; Max Heise, 25.02.2002, 1202 - Created ; Max Heise, 26.02.2002, 0900 - Inits of the single modules finished ; Max Heise, 27.02.2002, 1900 - bughunting, now ready to run ; Max Heise, 28.02.2002, 0930 - code beautyfying, minor enhancements ;----------------------------------------- ; Description of functionality: ; Microcontroller is reading analog input ; on ports RA0/AN0 and RA1/AN1 and ; creates independant PWM signals with a ; frequency of 15KHz on ports RC2/CCP1 and ; RC1/CCP2 with a duty cycle corresponding ; to the voltage on the analog inputs. ; In addition to that, there are two press- ; buttons attached to port RB7 and RB6 which ; make two leds connected to RB5 and RB4 ; light up when pressed ;----------------------------------------- ; IDE Configuration: LIST P=16F877, R=DEC __CONFIG H'3FF1' ; XT,WDOG OFF ; 0011 1111 1111 0001, p. 122 __IDLOCS H'F055' ;----------------------------------------- ; Includes for symbolic names include "p16f877.inc" ;----------------------------------------- ; Jump to main org 0x00 goto Main ;----------------------------------------- ; Interrupt Service Routine org 0x04 Isr retfie ;----------------------------------------- ; RAM ; p. 13, GPR files from 0x20 to 0x7F on ; bank 0 org 0x20 ; one byte for loop in WaitRAT CMPT1 RES 1 ;----------------------------------------- ; Init for PWM mode of Capcom module, p. 61 ; PR2's value is calculated like that: ; We need a frequency of at least 15kHz, to ; avoid hearing the motors. That gives us a ; period Tpwm of 6,67,e-5, the formula is on ; p. 61 of the PIC16F877 documentation. ; With TMR2 prescaler set to 1 it is necessary ; to set PR2 to decimal 65=0x41. ; Duty cycle, 10 bits: ; 00 0000 0000b = 0d ; 00 1111 1111b = 255d = 1/4 = default ; 01 1111 1111b = 511d = 1/2 ; 10 1111 1111b = 767d = 3/4 ; 11 1111 1111b = 1023d ; 8 MSB Bits in CCPR1L or CCPR2L: ; 0011 1111 = 0x3F ; 1011 1111 = 0xBF ; PWM Mode for Capcom module is initialised ; by setting CCP1CON and CCP2CON file bits ; 3:0 to binary 11XX. ; Location of files, p. 14: ; PR2 bank 1 ; CCP1CON, CCP2CON bank 0 ; CCPR1L, CCPR1H, CCPR2L, CCPR2H bank 0 ; TRISC bank 1 ; PORTC bank 0 ; T2CON InitPWM ; Setup PR2 banksel PR2 movlw 0x41 movwf PR2 ; Set duty cycle 8 MSB Bits to 0, do not ; forget the 2 LSB later ! movlw 0x01 banksel CCPR1L movwf CCPR1L banksel CCPR2L movwf CCPR2L ; make RC2/CCP1 and RC1/CCP2 pins an output, p. 29 banksel PORTC clrf PORTC banksel TRISC bcf TRISC, 1 ; CCP2 bcf TRISC, 2 ; CCP1 ; set Timer 2 TMR2 prescale value to 1 by clearing bits 1:0, p. 55 ; and start the timer by setting bit 2 ; 0000 0100=0x04 banksel T2CON movlw 0x04 movwf T2CON ; setup CCP1,CCP2 for PWM operation ; clear 2 LSB bits 5:4, set bits 3:0 ; to 1100 for PWM mode ; 0000 1100=0x0C ; 0x00 to clear the two LSB bits of the PWM duty cycle ; 0x03 to set the two LSB bits of the PWM duty cycle ; 0x0C to set PWM operation of CCP1, CCP2 module ; banksel CCP1CON movlw 0x0C movwf CCP1CON banksel CCP2CON movlw 0x0C movwf CCP2CON ; Both CCP1 and CCP2 should now be configured for ; PWM operation, but the duty cycle is still set ; to 0, so no signal should appear. ; return and switch back to bank 0 for sure bcf STATUS, RP0 bcf STATUS, RP1 return ;----------------------------------------- ; Init of A/D converter module, p. 111 ; We are using RA0/AN0 and RA1/AN1 as ; analog inputs beware that AN7, AN6 and ; AN5 are *not* available on 28pin devices ; such as 873, 874 ; Unfortunately there is no mode for ADCON1, ; p. 112 with CHAN/REFS 2/0, so we have to ; sacrify one pin, RA3/AN3, and leave it as an ; unused analog input. Mode 3/0 is choosen ; by setting bits 3:0 of ADCON1 to 0x04, ; binary 0100. ; Location of files: ; ADCON0 bank 0 ; ADCON1 bank 1 InitAD ; set TRISA bits for analog inputs banksel TRISA bsf TRISA, 0 bsf TRISA, 1 bsf TRISA, 3 ; ADCON1, format left justified, clear bit 7 ; mode 3/0 bits 3:0 binary 0100 banksel ADCON1 movlw 0x04 movwf ADCON1 ; at the beginning select input channel AN0, bits 5:3 ; set to 000, later toggle between channel 0 and channel 1. ; Setting for channel 1 is 001 ; We are using a 4MHz clock, so regarding table 11-1, p. 116 ; we should use a operation time of 8Tosc for a conversion ; that is bits 7:6 of ADCON0 set to binary 01 ; thus we get a binary value of 01 000 0 0 1 or 0100 0001 or 0x41 ; for channel 0. For channel 1 the ADCON0 value is ; 01 001 0 0 1 equal 0x49 banksel ADCON0 movlw 0x41 movwf ADCON0 ; init is now complete, to use the A/D module ; follow with step 3., p. 113 ; return and switch back to bank 0 for sure bcf STATUS, RP0 bcf STATUS, RP1 return ;----------------------------------------- ; Toggle the A/D channel used for sampling ; an analog value from the the potentiometers ; see comment in function above ; For channel 0 the ADCON0 value is 0x41 ; For channel 1 the ADCON0 value is 0x49 ; ADCON1 does not change ; Location of files: ; ADCON0 bank 0, 0x1F toggleADChannel banksel ADCON0 ; move value for channel 0 in W movlw 0x41 ; and substract it from ADCON0 ; result in W subwf ADCON0,0 ; Bit 2 of STATUS is Z flag btfsc STATUS,2 ; jump if set goto ADChannel1 ; Z is set goto ADChannel0 ; Z is not set ADChannel1 movlw 0x49 movwf ADCON0 goto ADEnd ADChannel0 movlw 0x41 movwf ADCON0 ADEnd return ;----------------------------------------- ; Init INDF and FSR for indirect adressing ; of files CCPR1L and CCPR2L ; Location of files: ; CCPR1L bank 0, 0x15 ; CCPR2L bank 0, 0x1B ; Init with CCPR1L InitINDF movlw 0x15 movwf FSR return ;----------------------------------------- ; Toggles the PWM Channel. ; If FSR points to CCPR1L/0x15 we must point it ; to CCPR2L/0x1B and vice versa. togglePWMChannel ; move value for CCPR1L into W file movlw 0x15 ; and substract it from FSR, ; the result is placed in W subwf FSR,0 ; Bit 2 of STATUS is Z flag btfsc STATUS, 2 ; jump if set goto PWMChannel1 ; Z is set goto PWMChannel0 ; Z is not set PWMChannel1 movlw 0x1B movwf FSR goto PWMEnd PWMChannel0 movlw 0x15 movwf FSR PWMEnd return ;----------------------------------------- ; Init of PortB ; RB7, RB6 inputs, pressbuttons ; RB5, RB4 leds ; Location of files: ; TRISB bank 1 ; PORTB bank 0 ; Setup of Port B p. 31 InitPortB banksel TRISB ; 1. led bcf TRISB, 5 ; 2. led bcf TRISB, 4 banksel PORTB clrf PORTB ; And back to bank 0 for sure bcf STATUS, RP0 bcf STATUS, RP1 return ;----------------------------------------- ; Function for LED1 on portb,5 and press- ; button on portb, 7 LED1 goto LED1Loop LED1Else bcf PORTB, 5 return LED1Loop btfsc PORTB, 7 goto LED1Else bsf PORTB, 5 return ;----------------------------------------- ; dito except for portb,4 output and input ; portb,6 LED2 goto LED2Loop LED2Else bcf PORTB, 4 return LED2Loop btfsc PORTB, 6 goto LED2Else bsf PORTB, 4 return ;----------------------------------------- ; Init of Microproc. ; Select bank 0 first by clearing RP0 and RP1 Init bcf STATUS, RP0 bcf STATUS, RP1 call InitPWM call InitAD call InitINDF call InitPortB return ;----------------------------------------- ; Required acquisition time for A/D module WaitRAT ; p. 115 equation 11-1 Tacq=19,72,e-6 ; seconds, approx. 2,e-5 seconds. ; One instruction is executed in one ; cycle, one cycle at 4MHz takes 2,5,e-7 ; seconds. Thus we must idle for 80 ; instructions ; Formula for this loop ; Inst(I)=1+1+( (I-1)*(1+2) )+2+2=6+3N-3=3I+3 ; +2 Inst.Cycles for the call of this function ; => Inst(I)=3I+5 ; Inst(I) must be 80 ; 80=3I+5 ; => I=25 ; Used files : CMPT1 I EQU 25 movlw I ; 1 Inst.Cycle movwf CMPT1 ; 1 Inst.Cycle WaitRAT_Loop decfsz CMPT1,1 ; 1 Inst.Cycle if I!=0, 2 Inst.Cycles if I==0 goto WaitRAT_Loop ; 2 Inst.Cycles return ; 2 Inst.Cycles ;----------------------------------------- InfinitivLoop ; Location of files: ; ADCON0 bank 0 ; ADRESH bank 0 ; ADRESL bank 1 ; INDF is not physical file ; Wait required A/D acquisition time call WaitRAT ; One should wait at least 2 Tad, ; p. 115 Note 4 before the next A/D ; conversion. 2 Tad is, table 11-1, ; p. 116 16Tosc is equal 4,e-6 seconds which ; is equal 16 Inst.Cycles. ; Start conversion by setting bit 2 in ADCON0 banksel ADCON0 bsf ADCON0,2 ; Wait for result, A/D conversion is complete ; when bit ADCON0,2 is cleared by hardware. ; We only have to wait .... WaitGo_Cleared btfss ADCON0, 2 goto Go_Is_Cleared goto WaitGo_Cleared ; Read result and compute duty cycle Go_Is_Cleared banksel ADRESH movfw ADRESH ; write duty cycle, INDF is pointing to either ; CCPR1L or CCPR2L ; FIXME debugging, write a know value ; to the duty cycle register ; movlw 0x7F movwf INDF ; toggle pair of analog input channel ; and toggle pwm channel, files CCPR1L and ; CCPR2L call toggleADChannel call togglePWMChannel ; Any still take care of the leds and the ; pressbuttons call LED1 call LED2 ; and over and over again goto InfinitivLoop ;----------------------------------------- ; Main Main call Init goto InfinitivLoop ;----------------------------------------- ; End of the program end