Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Junebug Servo C18 code.

Status
Not open for further replies.
Pommie said:
Here is a version that will go fully left if button 1 pressed, center if button 2 pressed and fully right if button 3 pressed. If you press all 3 buttons together it will take up the position defined by the pot.

Tested, and it works! Thanks a lot for the code examples. I know 16F-series fairly well, but I'm new to 18Fs. Need some time to learn. I'm to lazy to connect other pic's, now that I have the 18F1320 on the Junebug :)
I have another wish also. Center position with middle button, small steps left/right with button 1 & 3. Could be used to test the resolution of the servos.
I'll have a go at it later. I don't expect you to write the code for me, but if you find it interresting, please do. I program pics partly for learning, partly for practical use. Like most, I guess.
 
The really nice thing about having a Junebug is that you can flip a couple of switches and instantly try a bit of code.

It's really easy to do. If you want to have a go yourself then stop reading now.

To do what you ask simply needs this change,
Code:
        if(Edges==0b00000001        //Key 1 pressed
         &&ServoPos>1000)           //and servo not fully left
            ServoPos-=100;          //move servo a bit left
        if(Edges==0b00000100)       //key 2?
            ServoPos=1500;          //set center
        if(Edges==0b00100000        //Key 3 pressed
         &&ServoPos<2000)           //and servo not fully right
            ServoPos+=100;          //move a bit right

If the steps are too bit change the 100 value.

Edit, you probably want to experiment with the endstop values (1000 and 2000) as I believe most servos go beyond the 1-2mS range. Just tried my Futaba S3003 and the endstops seem to be 600 and 2400.

That code is a little confusing, the lines are actaully,
Code:
    if(Edges==0b00000001 && ServoPos>600)
    {
        ServoPos-=100;
    }
I just split them so it looked tidy.

Mike.
 
Last edited:
I just googled for "junebug c18 servo example" and it took me to a forum I frequent anyway, how convienient is that? Thanks for the code Pommie. I'll be making use of this when i get home.

I've got a question already, where did you find out all the system variables your setting and what they do? such as "ADCON0bits.GO" I'm just starting on C18, and with 18F chips. I'm going to look through some of the microchip PDFs and see if I can find it.
 
Last edited:
I've got a question already, where did you find out all the system variables your setting and what they do? such as "ADCON0bits.GO" I'm just starting on C18, and with 18F chips. I'm going to look through some of the microchip PDFs and see if I can find it.

They're all listing in the data sheet. Here's the 18F1320 data sheet. If you mean the actual names, they pretty much follow the data sheet but if your unsure they're in the 18F1320.h file in C:\MCC18\h.

Mike.
 
Thanks, I see a lot of the variables you used, but with "bits" at the end, what does that do?
 
I'll have to give this a try with the junebug Looks good Mike. futz It's good to see you been a long time haven't seen you glad to see your still with us.I just tried it with a cheapo parallax servo works great Thanks Mike. good work.
 
Last edited:
Thanks, I see a lot of the variables you used, but with "bits" at the end, what does that do?

It's the way C18 accesses the individual bits in a variable. Other compilers use a syntax like adcon0.GO=1 (BoostC) but Microchip decided that typing practice was good for people and added bits into the middle of it and so in C18 it's ADCON0bits.GO=1. Another way to write it is ADCON0|=2; as the GO bit is bit 1 (I think).

Mike.
 
futz It's good to see you been a long time haven't seen you glad to see your still with us.

Haven't seen Futz for a long time, he seems to have stopped visiting. I guess that you didn't notice that this thread is over a year old.

Mike.
 
That why I didn't see it till today Triode stated it back up
I guess that you didn't notice that this thread is over a year old.
dope till I posted two times lol I looked at futz site to day he got into bigger toys
 
Last edited:
Well, like I said when I replied to it, I googled for exactly what this thread was about and ended up finding it here, where I already post, so why not bring it back.

Thanks for clairifying that pommie, I had found the list of what each bit did in the variables, but I had never seen "bits" written in like that.
 
If anyone is having problems with the interrupt driven version it is because I used the wrong interrupt vector.

The line,
Code:
#pragma code low_vector=0x18    //setup the ISR vector
Should be,
Code:
#pragma code low_vector=0x[COLOR="Red"]0[/COLOR]8    //setup the ISR vector

The old version of the C18 compiler put NOPs between the vectors and so the code worked. The new version of the compiler puts code there and so it crashes.

I noticed this as I needed the code to align a servo that had stripped its gears.

Mike.
 
Last edited:
Here is a version that will go fully left if button 1 pressed, center if button 2 pressed and fully right if button 3 pressed. If you press all 3 buttons together it will take up the position defined by the pot.

I also changed it to use interrupts because, as Mike said, it isn't as intuitive as one would imagine.

Mike.
Code:
#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
    }
}

hi mike,

thanks for putting this code up. my application basically uses a PIC18 with a 10Mhx crystal connected to it. Will i have to make any modifications to this code, especially with regards to the delays?or is it the same regardless of the clock speed?
 
With a 10MHz clock a 1mS pulse will be 1250 cycles. So multiply all time by 1.25 to get the new times. The line ServoPos=ADRES+1000; will need to be ServoPos=ADRES*5/4+1250;

Note also the interrupt vector is wrong. See the post above yours.

Mike.
 
how did you do the maths for it?im a bit confused :S

no mike, ur interrupt vector is correct..low priority interrupts are a 0x0018 and high priority is at 0x0008...
 
The maths is simple, at 8MHz the timer would be clocked at 2MHz if the prescaler wasn't used. I set the prescaler to 2 and so the timer is clocked once every microsecond. With a 10MHz clock it is 10/8 (=1.25) times faster.

The interrupt vector would be correct if I used interrupt priorities but I chose to use compatibility mode and so all interrupts go to the vector at 0x08.

Mike.
 
Code:
#include <p18f452.h>

#define ServoPin PORTAbits.RA2

int ServoPosition;

void CCP2_ISR();

#pragma code high_pri_vec = 0x0008
void high_pri_vec()
{
	_asm
	GOTO CCP2_ISR
	_endasm
}

#pragma interrupt CCP2_ISR
void CCP2_ISR()
{	
	if(ServoPin==1)
	{
		ServoPin = 0;
		CCPR2 = 25000 - ServoPosition;
	}
	else
	{
		ServoPin = 1;
		CCPR2 = ServoPosition;
	}
	PIR2bits.CCP2IF = 0;
	
}

#pragma code
void main()
{
	ServoPin = 0;
	TRISAbits.TRISA2 = 0; //Set Pin A2 as an output for the Servo
	CCP2CON = 0b00001011; //Setup CCP2 to generate special event
	CCPR2 = ServoPosition;
	T3CON = 0b10011001; //Setup timer3, prescaler=2
	ServoPosition = 1875; //Mid point position for Servo
	TMR3H = 0;
	TMR3L = 0;
	PIE2bits.CCP2IE = 1; //Enable CCP2 interrupt
	INTCONbits.PEIE = 1; //Enable peripheral interrupts
	INTCONbits.GIE = 1; //Enable all interrupts
	while(1);
}

i modified the code, since i needed a program which enabled the servo position to be controlled outside of the main servo control program. basically this is a servo control program....i was testing it in the MPLAB SIM, and it seems like it is stuck in an endless loop. the timer goes up to a value above 200, but never above 300, and then simply restarts. as a result, the compare never occurs. what's wrong here?

ok.so it seems like timer3 isnt accessing the high byte and counting up only to 256. what am i doing wrong?
 
Last edited:
You are still using Timer1 for the CCP module. Try T3CON = 0b11011001;

Mike.
 
You need to make A2 digital with ADCON1=0x07;

Analogue pins always read back as zero.

Mike.
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top