;******************************************************************* ; Motordrehzahlsteuerung.ASM ; mit Pulsbreitenmodulation ; fr Elektrobuggy ; PIC16C84 Voggeneder Andreas ;******************************************************************* ; Oszillator Frequenz 4 MHz ; Hebel oben ... ca. 512 ; Hebel unten ... ca. 1024 ; PWM ... PA0 ; DIR ... PA1 ; FERN .. PB0 ; SAVE_O ... PB1 Obere Hebelstellung speichern ; SAVE_U ... PB2 Untere Hebelstellung speichern ; SAVE TZ .. PB3 Tote Zohne speichern ; RESTORE .. PB4 Defaultwerte spichern ; MODE ..... PB5 =1 -> 2 Richtungen include "picreg.equ" LIST p=16C84,w=1 ; PIC16C84 is the target processor __CONFIG _CP_OFF & _WDT_ON & _XT_OSC & _PWRTE_ON minimum equ .512 ; Impulsl„nge obere Hebelstellung maximum equ .1024 ; Impulsl„nge untere Hebelstellung min_d equ .250 ; Impulsmindestl„nge = 500 us max_d equ .1250 ; Impulsh”chstdauer = 1500 us Rcal equ .10000 ; Rcal = 100 kOhm Roff equ .600 ; Abschaltpunkt Rntc = 6 kOhm Ron equ .1200 ; Wiedereinschaltpunkt Rntc = 12 kOhm Mot equ 7 ; Motorausgang Motn equ 6 ; invertierter Motorausgang intcon equ 0Bh eeadr equ 9h eedata equ 8h speed equ 0ch ; errechnete Geschwindigkeit count equ 0dh ; Periodenz„hler fr PWM on equ 0eh ; Zyklenz„hler fr PWM flag equ 0fh ; diverse flags ACCaHI EQU 10h ; Akkumulamtoren fr Arithmetikroutinen ACCaLO EQU 11h ACCbHI EQU 12h ACCbLO EQU 13h ACCcHI EQU 14h ACCcLO EQU 15h ACCdHI EQU 16h ACCdLO EQU 17h rtch equ 18h ; High- Byte Timer imp_h equ 19h ; gemessene Impulsbreite high imp_l equ 1Ah ; gemessene Impulsbreite low save equ 1Bh ; Zwischenspeicher fr W un_h equ 1Ch ; untere Impulsbreite high un_l equ 1Dh ; - " - low ob_h equ 1Eh ; obere Impulsbreite high ob_l equ 1Fh ; - " - low tz equ 20h ; tote Zohne divisor_l equ 21h ; Umrechnungsfaktor save_s equ 22h ; Zwichenspeicher fr Status kal_lo equ 23h ; gemessene Ladezeit 100k Widerstand kal_hi equ 24h temp equ 25h ; Temor„res Arbeitsregister org 0 goto start ; RESET Vektor org 4 ; Interrupt Vektor int btfsc intcon,2 ; rtc ? goto int_rtc movwf save ; W sichern movlw 7 ; RTCC anhalten option swapf STATUS,w ; Swapf ver„ndert Status- Register nicht movwf save_s ; Status sichern exint btfss Port_B,0 ; Externer Interrupt goto h_l l_h clrf RTCC ; Low- High- Flanke clrf rtch ; Timer l”schen ; bcf Port_A,2 ; Testfunktion clrw option ; interrupt bei h-l goto exiend h_l movf RTCC,w ; High- Low- Flanke clrf RTCC movwf imp_l ; Z„hlerstand sichern movf rtch,w movwf imp_h btfsc intcon,2 ; Timer overflow ? incf imp_h ; ja, dann high- Byte incrementieren bsf flag,0 ; merken, daá neue Daten da ; bsf Port_A,2 ; Testfunktion movlw 40H option ; Interrupt bei l-h exiend bcf intcon,1 ; Interrupt Flags l”schen bcf intcon,2 ; swapf save_s,w ; Status wiederherstellen movwf STATUS swapf save swapf save,w ; W- Register wiederherstellen retfie ; und zurck zum Hauptprogramm ; int_rtc bcf intcon,2 ; Timer- Interrupt, Timer- high incrementieren incfsz rtch ; beeinflusst Z- Flag nicht (incf schon) retfie retfie ; **************************************************************************** ; division macro ; divMac MACRO LOCAL NOCHK LOCAL NOGO bcf STATUS,CARRY rlf ACCdLO rlf ACCdHI rlf ACCcLO rlf ACCcHI movf ACCaHI,w subwf ACCcHI,w ;check if a>c btfss STATUS,Z_bit goto NOCHK movf ACCaLO,w subwf ACCcLO,w ;if msb ecual then check lsb NOCHK btfss STATUS,CARRY ;carry set if c>a goto NOGO movf ACCaLO,w ; c-a into c subwf ACCcLO btfss STATUS,CARRY decf ACCcHI movf ACCaHI,w subwf ACCcHI bsf STATUS,CARRY ;shift a 1 into b (result) NOGO rlf ACCbLO rlf ACCbHI ; ENDM ; ;***************************************************************************** ; Double Precision Divide ( 16/16 -> 16 ) ; ( ACCb/ACCa -> ACCb with remainder in ACCc ): ~ 6 bit output ,with Quotiont in ; ACCb (ACCbHI,ACCbLO) and Remainder in ACCc (ACCcHI,ACCcLO) . ; NOTE: Before calling this routine, the user should make sure that the Numerator(ACCb) ; is greater than Denominator (ACCa) . If the case is not true, the user should ; scale either Numerator or Denominator or both such that Numerator is greater than ; the Denominator. setup movlw .16 ;for 16 shifts movwf temp movf ACCbHI,w ;move ACCb to ACCd movwf ACCdHI movf ACCbLO,w movwf ACCdLO clrf ACCbHI clrf ACCbLO return ; ********************************************************************** ; neg_A comf ACCaLO ;negate ACCa ( -ACCa -> AC( a ) incf ACCaLO btfsc STATUS,Z_bit decf ACCaHI comf ACCaHI retlw 0 D_divF ; 16 bit Division call setup clrf ACCcHI clrf ACCcLO ;use the Macro 16 times divMac divMac divMac divMac divMac divMac divMac divMac divMac divMac divMac divMac divMac divMac divMac divMac return ;************************************************; MADD movf ACCaLO,w ; 16 bit Addition addwf ACCbLO btfsc STATUS,CARRY incf ACCbHI movf ACCaHI,w addwf ACCbHI return MPY call setup ; 16 bit Multiplikation MLOOP rrf ACCdHI rrf ACCdLO SKPNC call MADD rrf ACCbHI rrf ACCbLO rrf ACCcHI rrf ACCcLO decfsz temp goto MLOOP return start clrf RTCC ; Reset movlw 40H ; Vorteiler auf Timer 1:2 option ; und Int bei l_h clrf speed clrf flag movlw 0CH ; tris Port_A movlw 03fH tris Port_B ; Port A.1 ... Ausgang DIR (1=Rckw„rts) bsf Port_B,Motn bcf Port_B,Mot ; Motor ausschalten bcf Port_A,1 ; Relais ausschalten btfss Port_B,4 ; EEProm mit standardwerten vorbelegen goto restore call crc ; Prfsumme berechnen movf ACCaHI bz m14 clrwdt movlw 6 ; Prfsumme lesen call ee_rd movf ACCaLO,w subwf ACCaLO,w ; gespeicherte und berechnete Prfsumme gleich bz m11 m14 movlw .16 ; nein, dann Standardkonfiguration movwf divisor_l movlw (minimum >> 8) movwf un_h movlw (minimum & 0FFH) movwf un_l movlw (maximum >> 8) movwf ob_h movlw (maximum & 0FFH) movwf ob_l movlw 2 ; tote zohne = 2 movwf tz goto m12 ; m11 movlw tz ; Konfigruation ist OK movwf FSR ; Pointer auf Speicherbereich movlw 5 ; 5 bytes zu lesen movwf count bcf STATUS,7 m13 movf count,w call ee_rd movf ACCaLO,w ; Byte aus EEProm lesen movwf 0 ; und im Konfigurationsspeicher ablegen decf FSR ; Pointer auf n„chste Speicherzelle decfsz count goto m13 ; m12 movf un_l,w subwf ob_l,0 movwf ACCbLO movf un_h,w btfss STATUS,CARRY incf un_h,0 ; Ergebnis in W subwf ob_h,0 movwf ACCbHI clrf ACCaHI movlw .31 movwf ACCaLO call D_divF movf ACCbLO,w ; (ob-un)/31 movwf divisor_l ; Divisionsfaktor berechen ; movlw 0b0H movwf intcon ; Interrupts zulassen m19 clrwdt movlw .135 movwf kal_lo ; Defaultwert clrf kal_hi bcf flag,0 movlw 04 tris Port_A bsf Port_A,3 ; Vergleichswid. messen bsf Port_A,4 ; Eingang freigeben, Kond. wird nun geladen clrf RTCC clrf rtch m18 movlw .5 ; Timeout 500H erreicht ? subwf rtch,w bc m18a btfss Port_A,4 ; warten bis C geladen goto m18 call get_mes ; Messwerte speichern btfsc flag,0 goto m19 btfsc Port_B,0 goto m19 movlw (Rcal & 0FFH) ; Widerstandswert nach ACCb movwf ACCbLO movlw (Rcal >> 8) movwf ACCbHI call D_divF movf ACCbLO,w movwf kal_lo ; RC/tc speichern movf ACCbHI,w movwf kal_hi m18a ; movlw .1 ; movwf coun movlw .25 movwf count wd1 clrwdt btfss flag,0 goto wd1 bcf flag,0 decfsz count goto wd1 movlw 08 tris Port_A ; Vergleichswid. abschalten, NTC freigeben bcf flag,2 ; Messung l„uft movlw 40H option ; Interrupt bei l-h bsf Port_A,2 ; NTC messen clrf RTCC clrf rtch clrf eeadr wait_d clrwdt btfsc Port_A,4 ; C geladen ? call get_mes ; Messwert speichern btfss flag,0 ; auf 1. Datensatz warten goto wait_d ; m7 bcf flag,0 ; merker rcksetzen btfss flag,2 ; Messung erfolgreich ? goto m15 ; nein, dann keine Berechnung movf kal_lo,w movwf ACCbLO movf kal_hi,w ; Rc/tc laden movwf ACCbHI call MPY ; und mit tx multiplizieren movf ACCcLO btfss Port_A,0 ; šbertemperatursicherung angesprochen ? goto m21 sublw (Ron & 0FF) movf ACCcHI,w btfss STATUS,CARRY incf ACCcHI,w sublw (Ron >> 8) ; Ron- Rx negativ bnc m15 ; ja, dann Motor freigeben clrw clrf speed goto m10 m21 sublw (Roff & 0FF) movf ACCcHI,w btfss STATUS,CARRY incf ACCcHI,w sublw (Roff >> 8) ; Roff- Rx negativ bnc m15 bsf Port_A,0 ; Alarm zu hohe Temp. bcf Port_A,1 ; Relais ausschalten clrw ; Speed = 0 clrf speed goto m10 ; Messung starten m15 bcf Port_A,0 ; Alarmausgang abschalten btfss Port_B,1 goto save_u btfss Port_B,2 goto save_o movf imp_l,w sublw (min_d & 0FF) movf imp_h,w btfss STATUS,CARRY incf imp_h,w sublw (min_d >> 8) ; Ist mindestdauer - impulsl„nge >0 ? bc m20 ; ja, dann Fehler movf imp_l,w sublw (max_d & 0FF) movf imp_h,w btfss STATUS,CARRY incf imp_h,w sublw (max_d >> 8) ; Ist h”chstdauer - impulsl„nge < 0 ? bnc m20 ; ja, dann Fehler movf un_l,w subwf imp_l,w ; Impulsdauer - untere Grenze movwf ACCbLO movf un_h,w btfss STATUS,CARRY incf un_h,w subwf imp_h,w movwf ACCbHI bc m5 clrf ACCbHI ; Ergebnis negativ clrf ACCbLO ; Signal am minimum goto m6 ; m5 movf imp_l,w subwf ob_l,w ; Obere Grenze - Impulsdauer movf imp_h,w btfss STATUS,CARRY incf imp_h,w subwf ob_h,w bc m6 movf un_l,w ; Ergebnis negativ, subwf ob_l,w ; d.h. Hebel am unteren Anschlag, movwf ACCbLO ; unteren Grenzwert- oberen Grenzwert movf un_h,w ; berechnen btfss STATUS,CARRY incf un_h,w subwf ob_h,w movwf ACCbHI ; m6 clrf ACCaHI ; Wert nun durch Schrittweite dividieren movf divisor_l,w movwf ACCaLO call D_divF ; movlw .31 subwf ACCbLO,w ; max. 32 Stufen zul„ssig bnc m17 movlw .31 movwf ACCbLO m17 btfss Port_B,5 ; Mode ? goto m16 btfsc ACCbLO,4 ; Zweirichtungsbetrieb, Bit 4 ist Richtung goto m9 bcf Port_A,1 ; Umpolrelais ausschalten btfsc flag,1 ; testen ob vorher umgepolt war call warte ; umschaltzeit abwarten bcf flag,1 ; Direction =0 comf ACCbLO ; Wert negieren goto m10a m9 bsf Port_A,1 ; Umpolrelais einschalten btfss flag,1 ; testen ob vorher umgepolt war call warte ; umschaltzeit abwarten bsf flag,1 ; Direction=1 m10a bcf STATUS,CARRY rlf ACCbLO,w andlw 1f movwf speed ; neue Geschwindigkeit sublw 1EH movlw 1FH btfsc STATUS,Z movwf speed movf speed,w goto m10 m16 ; bcf STATUS,CARRY ; rrf ACCbLO comf ACCbLO,w ; movwf speed ; bcf Port_A,1 ; Direction immer 0 andlw 1f movwf speed ; neue Geschwindigkeit m10 btfss Port_B,3 ; Soll tote Zohne kalibriert werden ? goto save_tz ; ja, dann Speichern subwf tz,w ; prfen ob Speed innerhalb Toter Zohne ist btfsc STATUS,CARRY clrf speed ; ja, dann Speed = 0 movlw 1f xorwf speed m20 bcf flag,2 ; neue Messung movlw 1f xorwf speed,w bnz m8 ; Speed <> 0, dann PWM xx bcf Port_B,Mot bsf Port_B,Motn btfss Port_B,5 ; Flugmodus ? bsf Port_A,1 ; ja, Bremse einschalten bsf Port_A,4 ; Eingang freigeben, Kond. wird nun geladen clrf RTCC clrf rtch goto wait_d ; Motor ausgeschaltet m8 btfss Port_B,5 ; Flugmodus ? bcf Port_A,1 ; Bremse ausschalten bsf Port_A,4 ; Eingang freigeben, Kond. wird nun geladen clrf RTCC clrf rtch m8a movlw .16 ; 16 Perioden ausgeben movwf count m3 movlw .32 ; pro Periode 32 Stufen movwf on bsf Port_B,Mot ; Ausgang einschalten bcf Port_B,Motn btfsc flag,0 ; neue Daten eingetroffen ? goto m7 ; ja, dann neue Berechnung ; cycle movf on,w subwf speed,w ; Speed = Zyklus movlw 0C0 btfsc STATUS,Z xorwf Port_B ; Ausgang ausschalten btfsc Port_A,4 call get_mes ; Messwerte lesen m4 decfsz on goto cycle clrwdt ; Watchdog rcksetzen decfsz count goto m3 goto m8a ; restore clrf intcon ; Konfigurationsspeicher mit Standardwerten movlw .16 ; belegen movwf divisor_l movlw 1 movwf eeadr movlw (minimum >> 8) ; OBERE Hebelstellung movwf un_h call ee_wr incf eeadr movlw (minimum & 0FFH) movwf un_l call ee_wr incf eeadr movlw (maximum >> 8) ; untere Hebelstellung movwf ob_h call ee_wr incf eeadr movlw (maximum & 0FFH) movwf ob_l call ee_wr incf eeadr movlw 1 ; tote zohne = 1 movwf tz call ee_wr call crc movlw 6 movwf eeadr movf ACCaLO,w call ee_wr rest1 clrwdt btfss Port_B,4 goto rest1 goto start ; ee_rd movwf eeadr bsf STATUS,5 bsf 8,0 ; EEprom lesezyklus starten bcf STATUS,5 movf eedata,w movwf ACCaLO return ee_wr movwf eedata ; Adresse muá schon in EEadr stehen bsf STATUS,5 bsf 8,2 ; WREN setzen movlw 55 movwf 9 movlw 0AA movwf 9 bsf 8,1 ; schreibzyklus starten wr1 clrwdt btfss 8,4 goto wr1 ; schreibzyklus abwarten clrf 8 bcf STATUS,5 return save_u bcf intcon,7 ; Obere Hebelstellung verewigen bcf Port_B,Mot bsf Port_B,Motn bcf Port_A,1 ; Relais ausschalten movlw 1 movwf eeadr movf imp_h,w call ee_wr incf eeadr movf imp_l,w call ee_wr call crc movlw 6 movwf eeadr movf ACCaLO,w call ee_wr su1 clrwdt btfss Port_B,1 goto su1 goto start ; save_o bcf intcon,7 ; Untere Hebelstellung verewigen bcf Port_B,Mot bsf Port_B,Motn bcf Port_A,1 ; Relais ausschalten movlw 3 movwf eeadr movf imp_h,w call ee_wr incf eeadr movf imp_l,w call ee_wr call crc movlw 6 movwf eeadr movf ACCaLO,w call ee_wr so1 clrwdt btfss Port_B,2 goto so1 goto start ; save_tz bcf intcon,7 ; Tote Zohne im EEProm verewigen bcf Port_B,Mot bsf Port_B,Motn bcf Port_A,1 ; Relais ausschalten movlw 5 movwf eeadr movf speed,w call ee_wr call crc movlw 6 movwf eeadr movf ACCaLO,w call ee_wr tz1 clrwdt btfss Port_B,3 goto tz1 goto start ; crc movlw 5 ; Prfsummenberechnung movwf count ; 5 Bytes zu lesen clrf ACCaLO clrf ACCaHI crc1 movf count,w call ee_rd ; Byte aus EEProm lesen iorwf ACCaHI addwf ACCaLO ; Aufaddieren decfsz count ; na„chstes goto crc1 return warte movlw .255 ; ca. 100ms Verz”gerung movwf count movlw .130 movwf on w1 decfsz count goto w1 clrwdt decfsz on goto w1 return get_mes movlw 47H ; Messwert abspeichern option bcf Port_A,4 ; C entladen movf RTCC,w movwf ACCaLO ; Messwert nach ACCa movf rtch,w movwf ACCaHI bsf flag,2 ; Flag Messwert eingelesen setzen return END