#include <p18f1320.h>
#pragma config WDT = OFF, LVP = OFF, OSC = INTIO2
#define ServoPin LATBbits.LATB3
#define ServoTris TRISBbits.TRISB3
void main(void){
int ServoPos;
OSCCON=0x70; //Osc=8MHz
ADCON0=0b00000101; //A2D on and select AN1
ADCON1=0x7d; //A1 = analogue
ADCON2=0b10110101; //Right justify - Fosc/16
ServoTris=0; //make servo pin output
ServoPin=0; //Servo output off
CCP1CON=0b00001011; //Special event trigger
T1CON=0b10010001; //Timer 1 on with Pre=2
ServoPos=1500; //set servo to mid position
CCPR1=ServoPos; //set CCP initial value
while(1){
while(!PIR1bits.CCP1IF); //wait for CCP interrupt bit
ServoPin=0; //end pulse
CCPR1=20000-ServoPos; //Off time = 20mS - Servo Time
PIR1bits.CCP1IF=0; //clear int flag
ADCON0bits.GO=1; //start conversion
while(ADCON0bits.GO); //Wait for it to complete
ServoPos=ADRES+1000; //Pos will be 1mS to 2.023mS
while(!PIR1bits.CCP1IF); //wait for int flag
ServoPin=1; //start pulse
CCPR1=ServoPos; //Servo time in uS
PIR1bits.CCP1IF=0; //clear int flag
}
}
blueroomelectronics said:I've noticed many C18 programs use
#include <p18Cxxxx.h>
#ifndef _P18CXXX_H
#define _P18CXXX_H
#if defined(__18C242)
#include <p18c242.h>
#elif defined(__18C252)
#include <p18c252.h>
#elif defined(__18C442)
#include <p18c442.h>
#elif defined(__18C452)
#include <p18c452.h>
Mike said:Mike,
May I suggest an interrupt version of that code for newcomers to study? The ISR vector setup isn't quite as intuitive as it is in some other languages.
Regards...
Odin said:I'm in the process of building a R/C helicopter, and needed something to center the servoes, in the absence of a radio system. A switch to make the circuit output exactly 1,5 ms for center position would be nice. A two position switch, to choose between center lock and normal operation. Would also be good if the pic outputs 1,5 ms until the pot reaches center position. That would avoid wrecking the servo gears if the switch is moved when the pot is at either end. (if the servo stalls because of mechanical limitis in the model)
#include <p18f1320.h>
#pragma config WDT = OFF, LVP = OFF, OSC = INTIO2
#define ServoPin LATBbits.LATB3
#define ServoTris TRISBbits.TRISB3
void ccp1_isr();
volatile int ServoPos; //used to hold the servo position
#pragma code low_vector=0x18 //setup the ISR vector
void low_interrupt (){
_asm GOTO ccp1_isr _endasm //jump to interrupt handler
}
#pragma code
#pragma interruptlow ccp1_isr //the ISR
void ccp1_isr(){
if(ServoPin==1){ //will be 1 if we are at end of pulse
ServoPin=0; //turn off servo output
CCPR1=20000-ServoPos; //Off time = 20mS - Servo Time
}
else{
ServoPin=1; //turn on servo output
CCPR1=ServoPos; //On time
}
PIR1bits.CCP1IF=0; //clear int flag
}
#pragma code
void main(){
OSCCON=0x70; //Osc=8MHz
ADCON0=0b00000101; //A2D on and select AN1
ADCON1=0x7d; //A1 = analogue
ADCON2=0b10110101; //Right justify - Fosc/16
ServoTris=0; //make bit 0 output
ServoPin=0; //Servo output off
CCP1CON=0b00001011; //Special event trigger
T1CON=0b10010001; //Timer 1 on with Pre=2
ServoPos=1500; //set servo to mid position
CCPR1=ServoPos; //set CCP initial value
PIE1bits.CCP1IE=1; //enable CCP1 interrupt
INTCONbits.PEIE=1; //enable peripheral interrupts
INTCONbits.GIE=1; //enable glogal interrupts
INTCON2bits.RBPU=0; //enable port b week pullups
while(1){ //loop forever
static char Mode=0; //0 = use ADC, 1=fixed pos
static char Keys; //holds previous key values
char OldKeys,Edges; //local variables
while(!ServoPin); //Wait for start of servo pulse
while(ServoPin); //wait for end - makes for good debounce
OldKeys=Keys; //make a copy of keys
Keys=PORTB&0b00100101; //get switch state
Keys^=0b00100101; //make pressed keys = 1
if(Keys==0b00100101) //all 3 pressed?
Mode=0; //yes, set to use ADC input
Edges=(Keys^OldKeys); //keep only keys that have changed
Edges&=Keys; //keep only new key presses - not key releases
if(Mode==0){ //are we using the pot?
ADCON0bits.GO=1; //yes, start conversion
while(ADCON0bits.GO); //Wait for it to complete
ServoPos=ADRES+1000; //Pos will be 1mS to 2.023mS
}
if(Edges!=0) //any key pressed
Mode=1; //switch to fixed mode
if(Edges==0b00000001) //Key 1 pressed
ServoPos=1000; //set servo fully left
if(Edges==0b00000100) //key 2?
ServoPos=1500; //set center
if(Edges==0b00100000) //key 3?
ServoPos=2000; //set fully right
}
}
void ccp1_isr()
{ if(ServoPin = !ServoPin) // if toggled ServoPin = 1
CCPR1 = ServoPos; // setup "on" time match value
else // else
CCPR1 = 20000 - ServoPos // setup "off" time match value
while(ADCON0bits.GO); // wait for ADC conversion
ServoPot=ADRES+1000; // <-- new variable
PIR1bits.CCP1IF=0; // clear CCP1 interrupt flag bit
}
Work has been hectic lately and I haven't had much time to play. Saw the post, but couldn't do anything with it till today.Is there really that few people experimenting with the Junebug that nobody found this post interesting?
list p=18F1320
include <p18F1320.inc>
CONFIG OSC=INTIO2,WDT=OFF,MCLRE=ON,LVP=OFF
cblock 0x00
ServoPosH,ServoPosL,src1,src2,dst1,dst2
endc
org 0x0000
init movlw 0x70
movwf OSCCON ;Osc=8MHz
movlw b'00000101' ;A2D on and select AN1
movwf ADCON0
movlw b'01111101' ;A1 = analog
movwf ADCON1
movlw b'10110101' ;Right justify - Fosc/16
movwf ADCON2
bcf TRISB,3 ;make servo pin output
bcf LATB,3 ;Servo output off
movlw b'00001011' ;Special event trigger
movwf CCP1CON
movlw b'10010001' ;Timer 1 on with Pre=2
movwf T1CON
movlw 0x05 ;set servo to mid position
movwf ServoPosH
movwf CCPR1H ;and set CCP initial value
movlw 0xdc
movwf ServoPosL
movwf CCPR1L
main btfss PIR1,CCP1IF ;wait for CCP interrupt bit
goto main
bcf LATB,3 ;end pulse
movlw 0x4e ;Off time = 20ms - Servo Time
movwf src1
movlw 0x20
movwf src2
movff ServoPosH,dst1
movff ServoPosL,dst2
call sub16
movff dst1,CCPR1H
movff dst2,CCPR1L
bcf PIR1,CCP1IF ;clear int flag
bsf ADCON0,GO ;start conversion
conv btfsc ADCON0,DONE ;Wait for it to complete
goto conv
movff ADRESH,src1 ;Pos will be 1ms to 2.023ms
movff ADRESL,src2
movlw 0x03
movwf dst1
movlw 0xe8
movwf dst2
call add16
movff dst1,ServoPosH
movff dst2,ServoPosL
wait btfss PIR1,CCP1IF ;wait for int flag
goto wait
bsf LATB,3 ;start pulse
movff ServoPosH,CCPR1H ;Servo time in uS
movff ServoPosL,CCPR1L
bcf PIR1,CCP1IF ;clear int flag
goto main
sub16 movf src2,W
subwf dst2,F
movf src1,W
btfss STATUS,C
incf src1,W
subwf dst1,F
return
add16 movf src2,W
addwf dst2,F
movf src1,W
btfsc STATUS,C
incf src1,W
addwf dst1,F
return
end
;so this
movlw 0x03
movwf dst1
movlw 0xe8
movwf dst2
call add16
;becomes
movlw low(.1000)
movwf dstLo
movlw high(.1000)
movwf dstHi
call add16
The port is done, but the buttons aren't working yet. I have to go through it (maybe tomorrow) and see what I did wrong. Most likely I got one of the bit tests backward and it's branching the wrong way. The potentiometer/servo part works fine though.Pommie said:Nicely done Futz. Are you going to do the interrupt version as well?
Those 1 & 2 things came from Chuck McMannis, the guy I stole those 16-bit add/subtract code snips from. I didn't change a thing. I prefer to use H and L suffixes. I'll change that in the second port.One little suggestion to make it more readable. Use word variables with Lo and Hi on the end instead of 1 & 2,
I used a decimal number?use the . with decimal numbers and make use of the low and high directives.
Mike.
Finally found the problem. Here's the asm port of Pommie's second program:Pommie said:Are you going to do the interrupt version as well?
list p=18F1320
include <p18F1320.inc>
CONFIG OSC=INTIO2,WDT=OFF,MCLRE=ON,LVP=OFF
cblock 0x00
Mode,Keys,OldKeys,Edges,ServoPosH,ServoPosL
srcH,srcL,dstH,dstL
endc
org 0x00
goto init
org 0x18
isr btfss PORTB,3 ;the ISR
goto else1
bcf LATB,3 ;turn off servo output
movlw high(.20000) ;Off time = 20ms - Servo Time
movwf srcH
movlw low(.20000)
movwf srcL
movff ServoPosH,dstH
movff ServoPosL,dstL
call sub16
movff dstH,CCPR1H
movff dstL,CCPR1L
goto isr_done
else1 bsf LATB,3 ;turn on servo output
movff ServoPosH,CCPR1H ;On time
movff ServoPosL,CCPR1L
isr_done
bcf PIR1,CCP1IF ;clear int flag
retfie FAST
init movlw 0x70
movwf OSCCON ;Osc=8MHz
movlw b'00000101' ;A2D on and select AN1
movwf ADCON0
movlw b'01111101' ;A1 = analog
movwf ADCON1
movlw b'10110101' ;Right justify - Fosc/16
movwf ADCON2
bcf TRISB,3 ;make servo pin output
bcf LATB,3 ;Servo output off
movlw b'00001011' ;Special event trigger
movwf CCP1CON
movlw b'10010001' ;Timer 1 on with Pre=2
movwf T1CON
movlw high(.1500) ;set servo to mid position
movwf ServoPosH
movwf CCPR1H ;and set CCP initial value
movlw low(.1500)
movwf ServoPosL
movwf CCPR1L
bsf PIE1,CCP1IE ;enable CCP1 interrupt
bsf INTCON,PEIE ;enable peripheral interrupts
bsf INTCON,GIE ;enable global interrupts
bcf INTCON2,RBPU ;enable PORTB weak pullups
main btfss PORTB,3 ;Wait for start of servo pulse
goto main
wait2 btfsc PORTB,3 ;wait for end - makes for good debounce
goto wait2
movff Keys,OldKeys ;make a copy of keys
movf PORTB,W ;get switch state
andlw b'00100101'
movwf Keys
movlw b'00100101' ;make pressed keys = 1
xorwf Keys,F
movlw b'00100101' ;all 3 pressed?
cpfseq Keys
goto not3
clrf Mode ;yes, set to use ADC input
not3 movf Keys,W ;keep only keys that have changed
xorwf OldKeys,W
movwf Edges
andwf Keys,W ;keep only new key presses - not key releases
movwf Edges
tstfsz Mode ;are we using the pot?
goto nomode
bsf ADCON0,GO ;yes, start conversion
waitcv btfsc ADCON0,DONE ;wait for it to complete
goto waitcv
movff ADRESH,srcH ;Pos will be 1ms to 2.023ms
movff ADRESL,srcL
movlw high(.1000)
movwf dstH
movlw low(.1000)
movwf dstL
call add16
movff dstH,ServoPosH
movff dstL,ServoPosL
nomode tstfsz Edges ;any key pressed
goto mode1 ;go switch to fixed mode
goto mode0
mode1 movlw 1 ;switch to fixed mode
movwf Mode
mode0 movlw 1
subwf Edges,W ;key 1 pressed
btfss STATUS,Z
goto key2
movlw high(.1000) ;set servo fully left
movwf ServoPosH
movlw low(.1000)
movwf ServoPosL
goto again
key2 movlw 0x04 ;key 2?
subwf Edges,W
btfss STATUS,Z
goto key3
movlw high(.1500) ;set center
movwf ServoPosH
movlw low(.1500)
movwf ServoPosL
goto again
key3 movlw 0x20 ;key 3?
subwf Edges,W
btfss STATUS,Z
goto again
movlw high(.2000) ;set fully right
movwf ServoPosH
movlw low(.2000)
movwf ServoPosL
again goto main
sub16 movf srcL,W
subwf dstL,F
movf srcH,W
btfss STATUS,C
incf srcH,W
subwf dstH,F
return
add16 movf srcL,W
addwf dstL,F
movf srcH,W
btfsc STATUS,C
incf srcH,W
addwf dstH,F
return
end
list p=18F1320
include <p18F1320.inc>
CONFIG OSC=INTIO2,WDT=OFF,MCLRE=ON,LVP=OFF
cblock 0x00
ServoPosH,ServoPosL,srcH,srcL,dstH,dstL
endc
org 0x0000
init movlw 0x70
movwf OSCCON ;Osc=8MHz
movlw b'00000101' ;A2D on and select AN1
movwf ADCON0
movlw b'01111101' ;A1 = analog
movwf ADCON1
movlw b'10110101' ;Right justify - Fosc/16
movwf ADCON2
bcf TRISB,3 ;make servo pin output
bcf LATB,3 ;Servo output off
movlw b'00001011' ;Special event trigger
movwf CCP1CON
movlw b'10010001' ;Timer 1 on with Pre=2
movwf T1CON
movlw high(.1500) ;set servo to mid position
movwf ServoPosH
movwf CCPR1H ;and set CCP initial value
movlw low(.1500)
movwf ServoPosL
movwf CCPR1L
main btfss PIR1,CCP1IF ;wait for CCP interrupt bit
goto main
bcf LATB,3 ;end pulse
movlw high(.20000) ;Off time = 20ms - Servo Time
movwf srcH
movlw low(.20000)
movwf srcL
movff ServoPosH,dstH
movff ServoPosL,dstL
call sub16
movff dstH,CCPR1H
movff dstL,CCPR1L
bcf PIR1,CCP1IF ;clear int flag
bsf ADCON0,GO ;start conversion
conv btfsc ADCON0,DONE ;Wait for it to complete
goto conv
movff ADRESH,srcH ;Pos will be 1ms to 2.023ms
movff ADRESL,srcL
movlw high(.1000)
movwf dstH
movlw low(.1000)
movwf dstL
call add16
movff dstH,ServoPosH
movff dstL,ServoPosL
wait btfss PIR1,CCP1IF ;wait for int flag
goto wait
bsf LATB,3 ;start pulse
movff ServoPosH,CCPR1H ;Servo time in uS
movff ServoPosL,CCPR1L
bcf PIR1,CCP1IF ;clear int flag
goto main
sub16 movf srcL,W
subwf dstL,F
movf srcH,W
btfss STATUS,C
incf srcH,W
subwf dstH,F
return
add16 movf srcL,W
addwf dstL,F
movf srcH,W
btfsc STATUS,C
incf srcH,W
addwf dstH,F
return
end
blueroomelectronics said:Watch out with powering the Servo with your USB port.
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?