Programmet är skrivet i assembler för en PIC16F886 (8Mhz intosc) och ska hantera en PWM (med CCP2) på 5kHz och skall parrallellt med det göra temperaur-avläsningar från en DS18b20 över 1-wire.
Koden är upp byggd på det här viset:
Varje gång som en stigande flank detekters på INT-pinnen (som är knuten till PWM-pinnen) så genereras ett interrupt. I interrupt-rutinen (ISR) så läses ADC-värdet från en pot in och den bestämmer DutyCycle på PWMen. Innan den lämnar ISR så sätter den en flagga för att indikera att ett interrupt har skett.
Denna flagga används av main-koden för det finns bara tid att skicka en bit över one-wirebusen per PWM/ISR-cykel. Man vill ju inte att mjukvaru-protokollet ska haverera pga att ett interrupt inträffar mitt i en bit-sändning så därför löste jag det så att main-koden helt enkelt sänder/tar emot en bit och går sedan in i en loop där den kollar statusen på ISR-flaggan och så fort den är satt till 1 så sätter loopen den tillbaks till noll och går vidare för att sända bit nummer två osv...
Problemet är att jag vill ha en min/maxvärdes limitering i ISRen. När jag implementerat detta så börjar koden bete sig väldigt underligt. Jag upptäckte det dock väldigt sent och kan inte garantera att det är det som är felet för programmet beter sig så (för mig) irrationellt så jag vet varken ut eller in men jag har i alla fall isolerat ett exempel som jag kan visa för er.
Jag har i exempelt implementerat en liten bit kod som kontrollerar om värdet från ADCn är högre än en viss nivå. I exemplet så är värdet 80 vilket motsvarar ungefär 80% DutyCycle.
Om värdet är under 80 så kör den en goto till där DutyCycle bestämms men om det är över 80 så hoppar den över goto:n och går in i en likadan goto raden efter.
Helt värdelös funktion men den utlöser det fel som jag brottas med.
I slutet på main loopen så säger jag åt PICen att skicka ut de två byte som den fått av DS18b20 innehållandes temperaturen seriellt ut på UARTen. Dessa är korrekta så länge jag håller ADC-värdet under den givna gränsen (80i det här exemplet) men går jag över den så blir det två stycken h'FF' ut till oscilloskopet.
Hårdkodar jag två värden precis innan det är dags att sända ut dem på UARTen så blir de precis som jag vill ha dem så jag kan bara dra den slutsatsen att det borde vara i inläsningen som det blir fel.
Jag kan dock inte för mitt liv begripa hur/var/varför det blir fel. Det ser helt perfekt ut på oscilloskopet och jag ser att DS18b20n sänder ut rätt data hela tiden och PICen samplar på exakt rätt ställen men ändå blir det bara ettor i registret. Men alltså bara när ADC-värdet är högre än 80, vilket naturligtvis inte ska ha med saken att göra.
Jag vill också tillägga att ingen tempavläsning görs i den här exempelkoden utan för debugning så använder jag bara de kända default-värdet i temp-registret i DS18b20.
Det är en ganska mastig kod så jag börjar med att posta mainloopen, ISRen och ReceiveByte-Loopen/funktionen eftersom det andra verkar funka som det ska. Vill ni ha mer så ska jag städa upp koden och lägga ut men det känns som att jag måste ha missat något elementärt som uppkallar det här beteendet och jag är fast besluten om att ta reda på VAD det är som är fel. Har slösat bort alldeles för mycket tid med den här koden för att jag inte ska få lära mig felet jag gjort och kunna se till att aldrig aldrig ALDRIG upprepas igen!

Kod: Markera allt
main
call NextStepWaitLoop
call Delay ;Delays for about 100ms. Gives the DS18b20 time to convert temp
call NextStepWaitLoop ;For correct timing of the resetPulse
call ResetPulse
movlw h'CC' ;The SkipROM-command
movwf OWbyte1
call SendByte
movlw h'BE' ;The ReadScratchpad-command
movwf OWbyte1
call SendByte
banksel PORTA
bsf PORTA, 0
call ReceiveByte
movfw OWbyte1 ;Copy LSB just received to OWbyte2
movwf OWbyte2
call ReceiveByte ;Gets the MSB and puts it in OWbyte1
banksel PORTA
bcf PORTA, 0
banksel TXREG
movfw OWbyte2
movwf TXREG
banksel PIR1
btfss PIR1, TXIF
goto $-2
banksel TXREG
movfw OWbyte1
movwf TXREG
goto main
;RECEIVE-BYTE****************************************************************
;This routine Recieves a byte from the OW-bus and stores it in OWByte1.
ReceiveByte
clrf OWByte1 ;Clear it out
movlw d'8' ;Eight bits in the byte
movwf OWcounter
bcf STATUS, C
ReceiveLoop
call NextStepWaitLoop
rrf OWbyte1, 1 ;Rotate byte for next bit, store result in OWbyte1
call LoZ ;bring OWpin low for 6µs
nop
nop
nop
nop
call HiZ ;bring it high and wait 4µs before sampling
nop
nop
nop
nop
nop
nop
nop
banksel PORTC
bcf PORTA, 0
btfsc PORTC, 0 ;Sample bus, If its high, write bit=1
bsf OWbyte1, 7
bsf PORTA, 0
decfsz OWcounter
goto ReceiveLoop
return ;When counter hits zero and all(8) bits has been received
;Så här ser loopen ut som väntar på att flaggan ska sättas i ISRen.
NextStepWaitLoop
btfss NextStep
goto NextStepWaitLoop
bcf NextStep
return
;;;;;;;;;;;;;;;;;;;;;;;;;;ISR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;***************************************************************
Interrupt
call DebugLEDon
banksel ADRESH
movfw ADRESH
movwf DutyCycle
HighLimitTest ;if RAMx < K
movfw HighLimit
subwf DutyCycle, 0 ;result in W
skpc
goto AssignDutyCycle ;LowLimitTest
goto AssignDutyCycle
AssignDutyCycle
movfw DutyCycle
banksel CCPR2L ;Put the 8 MSb in the Duty-cycle
movwf CCPR2L
banksel ADCON0 ;Order new A/D aquisition
bsf ADCON0, 1
banksel INTCON
bcf INTCON, INTF ;Clear the INT-pin Interrupt-flag
bsf NextStep ;(Tells the OW-guys that a new cycle has been initiated.
call DebugLEDoff
retfie
Jag är oändligt tacksam för all hjälp jag kan få här. Har kört fast som aldrig förr. Tyckte precis att jag hade fått så pass bra kläm på det här med Assembler att jag kan "klara mig själv" men det högmodet bestraffades å det grövsta.
Tack för ordet,
MVH
/En väldigt matt Tottish