Beim Testen eines neuen PICs Typ 16F688 habe ich arge Probleme.
Dann habe ich die Software abgespeckt und habe den erzeugten Assembler Code mir angesehen
und ehrlich gesagt überhaupt nicht verstanden, obwohl ich quasi mit dem aufgewachsen bin....
Code:
!void Delay_ms(U16 ms)
!{
! GIE = 0;
0x60: BCF INTCON, 0x7
! TimeOut = ms;
0x61: BCF STATUS, 0x5
0x62: BCF STATUS, 0x6
0x63: MOVF 0x2F, W
0x64: MOVWF 0x78
0x65: MOVF __pcstackBANK0, W
0x66: MOVWF TimeOut
! while(TimeOut)
0x67: MOVF TimeOut, W
0x68: IORWF 0x78, W
0x69: BTFSC STATUS, 0x2
0x6A: GOTO 0x6E
0x6D: GOTO 0x67
! {
! GIE = 1;
0x6B: BSF INTCON, 0x7
!// NOP();
! GIE = 0;
0x6C: BCF INTCON, 0x7
! }
! GIE = 1;
0x6E: BSF INTCON, 0x7
!}
0x6F: RETURN
Zuerst dachte ich der C-Compiler erzeugt falschen Code,
nach einigem rumprobieren und schließlich durch Simulation mit dem
integrierten Simulator der IDE ging mir mehr und mehr ein Licht auf.
Der angezeigte ASM Code stimmt nicht:
Dreh und Angelpunkt ist die Abfrage
0x69: BTFSC STATUS, 0x2
0x6A: GOTO 0x6E
0x6D: GOTO 0x67 // Dieser Goto ist "hier" an falscher Stelle, es fehlen die Adresszeilen 0x6B und 0x6C
Die kommen dann erst viel später im Listing
Hier ist also etwas durcheinander geraten.
Normalerweise springt der BTFSC entweder in die nächste oder übernächste Zeile vom Code.
Da die Abfrage an der Adresse 0x69 im Speicher steht
muss er entweder auf die nächste Adresse0x6A oder auf die übernächste Adresse 0x6B springen.
Die übernächste Zeile ist aber 0x6D ?????
Die Adresse 0x6B steht aber erst viel weiter hinten im Listing.
Witzigerweise macht der Simulator das sogar richtig.
Er überspringt tatsächlich mehrere Zeilen um an die richtige Adresse 0x6B zu gelangen.
MPLAB-X 5.15
XC8 V2.05
Mein eigentliches Problem konnte ich nun auch lösen,
und ist auch interessant, daher rührt nämlich der obige Code.
Bei einer direkten Folge von
GIE=1;
GIE=0;
wenn voher die Interrupts schon gesperrt waren, werden keine neuen anstehenden Interrupts ausgelöst.
Es ist zwingend erforderlich zumindest ein NOP dazwischen zu setzen, also
GIE=1;
NOP(); // Zeit schaffen um Interrupt auszulösen
GIE=0;
Siro
Lesezeichen