Well, your slowly convincing me, and unless anyone disagrees, I'll accept it.The chip can execute 8,000,000 (assuming 32MHz) instructions per second. The ISRs just take it in turn to do their thing. They've got 1mS (8000 instructions) between each byte arriving from the GPS. Same for each servo and the timer interrupt takes just a few instructions every 8,000 instructions. Oodles of time.
Had a busy day here and now late at night but I'll write some code tomorrow that will hopefully make it clearer.
Mike.
This was discussed in 2018 at AAC.Well, your slowly convincing me, and unless anyone disagrees, I'll accept it.
Good, so I'll go back to commenting your CODE from the program at #290 with comments from #307, which I'll post.
P.S. mind that radioactive capsule!
C
Hi J,This was discussed in 2018 at AAC.
It is good you are finally convinced
I made in 2018 a test in Oshonsoft simulator and servo interrupt using TIMER1 loaded with servo on time.
The main program ran with 99% speed.
Hi J,If 250ms is enough for parsing a 70 byte msg , then no problem.
Hi M,Whoops, my bad. CCP1 output is on RC2. Change TRISC.2 to be output and you should see pulses on RC2. Or if committed to RC1 then change to CCP2.
Mike.
if(RCIE & RCIF){
uint8_t chr=RCREG; //get the received character
if(OERR || FERR){ //neither of these should ever occur.
CREN=0; //this is kinda wishful thinking
CREN=1; //as any data received is corrupt
strCount=0; //however, reset everything
done=0; //and hope for the best
chr=0; //ensure this character isn't used
}else{ //no errors so use the data
if(strCount==0 && done==0){ //are we already receiving
//waiting for $ //no so wait
if(chr=='$'){ //for $ to appear
buff[strCount]=chr; //start receiving
strCount++;
}else if(done==0){ //have we collected a full string?
buff[strCount]=chr; //no so carry on storing
strCount++;
if(chr=='W'){ //have we got the "endOfString" character
done=1; //yes, so set done true
}
}
}
}
}
Hi M,Here's how I would write the UART interrupt,
It will wait for a '$' sign then start filling the buffer (buff) until a 'W' is received.Code:if(RCIE & RCIF){ uint8_t chr=RCREG; //get the received character if(OERR || FERR){ //neither of these should ever occur. CREN=0; //this is kinda wishful thinking CREN=1; //as any data received is corrupt strCount=0; //however, reset everything done=0; //and hope for the best chr=0; //ensure this character isn't used }else{ //no errors so use the data if(strCount==0 && done==0){ //are we already receiving //waiting for $ //no so wait if(chr=='$'){ //for $ to appear buff[strCount]=chr; //start receiving strCount++; }else if(done==0){ //have we collected a full string? buff[strCount]=chr; //no so carry on storing strCount++; if(chr=='W'){ //have we got the "endOfString" character done=1; //yes, so set done true } } } } }
The main code should monitor done, when done is not zero, process the buffer. No more bytes will go into buffer whilst this is happening.
Once the buffer has been processed, set done=0 and buffCount=0 and wait for done to be non zero again.
Mike.
Edit, changed if(!done) to if(done==0) so less confusing.
Hi M,Whoops, my bad. CCP1 output is on RC2. Change TRISC.2 to be output and you should see pulses on RC2. Or if committed to RC1 then change to CCP2.
Mike.
Yay, going in the right direction.Hi M,
Just got RC0 and RC2 to flash :0
Cheers,
C
Hi M,To clarify post #330,
The main loop should do,
Note, processing the buffer can also set servo positions if appropriate.Code:while(1) if(done) 'process buffer here done=0 strCount=0 endif wend
Mike.
servoPos(0) = 1.5 * 900 'SERVO pulse times allowing for Clock speed
servoPos(1) = 1.5 * 900
servoPos(2) = 1.5 * 1000
servoPos(0) = 8000 + 900 'SERVO pulse times allowing for Clock speed
servoPos(1) = 8000 + 900
servoPos(2) = 8000 + 1000
Hi M,You can do that however, you've got it wrong,
Should be,Code:servoPos(0) = 1.5 * 900 'SERVO pulse times allowing for Clock speed servoPos(1) = 1.5 * 900 servoPos(2) = 1.5 * 1000
etc.Code:servoPos(0) = 8000 + 900 'SERVO pulse times allowing for Clock speed servoPos(1) = 8000 + 900 servoPos(2) = 8000 + 1000
Also note you need a value for servoPos(8) so it outputs the last value. Just make it 8000 and all should be good.
Note, 8000 is 1mS in clock cycles at 32MHz.
ServoPos can go from 8,000 to 16,000 or from 0 to 7999 plus 8000.
Mike.
#include <xc.h>
#include "config.c"
#include <stdint.h>
#define _XTAL_FREQ 32000000
#define NUM_SERVOS 10
#define BUFFER 80
uint8_t buff[BUFFER],strCount=0,done=0;
uint16_t wordTemp;
uint32_t ms;
uint8_t count=0,servoCount,i;
uint16_t servoPos[NUM_SERVOS];
void main(void) {
OSCCON=0b01110000; //8MHz
PLLEN=1; //x4=32MHz
//setup 1mS interrupt = 8,000,000/16 = 500,000/10 = 50,000 set PR2=49 = 50,000/50 = 1000 = 1mS
T2CON=0b01001110; //pre=16 post=10
PR2=49;
TMR2IE=1; //timer 2 interrupts enable
T1CON=0; //timer 1 stopped
for(i=0;i<NUM_SERVOS;i++){
servoPos[i]=i*1000+8000; //1ms(8000) to 1.875(7/8ths - 15000)ms in 1/8th mS steps
}
TRISC=0b11111100; //CCP0 & 1 output
PEIE=1;
GIE=1;
while(1){
//adjust servo positions here
}
}
void __interrupt() inter(void){
if(TMR2IE && TMR2IF){
ms++;
count++;
if(count>=20){ //start every 20mS
TMR1=0; //zero timer 1
T1CON=1; //start timer 1
count=0;
CCP1CON=0b1000; //CCP1 pin low and high on match - will be first pulse
CCPR1L=0x0d;
CCPR2H=0x07;
CCP1IE=1; //enable CCP1 interrupts
CCP1IF=0; //ensure interrupt flag is clear
servoCount=0; //reset servoCount
LATC0=1; //connected to data in of shift register will clock in a high when CCP1 goes high
}
TMR2IF=0;
}
if(CCP1IE && CCP1IF){
LATC0=0; //clear the data in pin
if(servoCount==9) //have we done all servos?
CCP1IE=0; //yes so no more CCP1 interrupts
if(CCP1CON==0b1000){ //have we started the 4000 cycle pulse
CCP1CON=0b1001; //yes so end the pulse after 0.5mS
//CCPR1=CCPR1+4000; //4000 cycles=0.5mS
wordTemp=CCPR1H*256+CCPR1L;
wordTemp=wordTemp+4000;
CCPR1L=wordTemp & 255;
CCPR1H=wordTemp/256;
}else{
CCP1CON=0b1000; //No so output the timed gap
//CCPR1=CCPR1+servoPos[servoCount++]-4000; //will generate an interrupt when servo time is up
wordTemp=CCPR1H*256+CCPR1L;
wordTemp=wordTemp-4000+servoPos[servoCount];
CCPR1L=wordTemp&255;
CCPR1H=wordTemp/256;
servoCount=servoCount+1;
}
CCP1IF=0;
}
if(RCIE & RCIF){
uint8_t chr=RCREG; //get the received character
if(OERR || FERR){ //neither of these should ever occur.
CREN=0; //this is kinda wishful thinking
CREN=1; //as any data received is corrupt
strCount=0; //however, reset everything
done=0; //and hope for the best
}else{ //no errors so use the data
if(strCount==0 && done==0){ //are we already receiving
//waiting for $ //no so wait
if(chr=='$'){ //for $ to appear
buff[strCount]=chr; //start receiving
strCount++;
}else if(done==0){ //have we collected a full string?
buff[strCount]=chr; //no so carry on storing
strCount++;
if(chr=='W'){ //have we got the "endOfString" character
done=1; //yes, so set done true
}
}
}
}
}
}
Hi M,The .w bit was to mimic the oshonsoft .HB and .LB. .w is not legal in oshonsoft (I think) it's only in C as a union. The later version uses a word variable instead and loads CCPR1L and H into it, does some maths and moves it back.
The use of 2000 and 4000 are just constants that represent 0.25mS and 0.5mS and are definitely required. They can easily be split up into two 8 bit variables to load into the registers - or in the 4000 case added to the word variable.
Why doesn't 'Define num_servos = 10 'not compile?? compile?
You have constants defined above I.E. Define CLOCK_FREQUENCY = 32
What is the difference?
Why does one compile and not the other?
Here's a version that does not use a union and writes the two 8 bit values and makes i a global variable,
Code:#include <xc.h> #include "config.c" #include <stdint.h> #define _XTAL_FREQ 32000000 #define NUM_SERVOS 10 #define BUFFER 80 uint8_t buff[BUFFER],strCount=0,done=0; uint16_t wordTemp; uint32_t ms; uint8_t count=0,servoCount,i; void main(void) { OSCCON=0b01110000; //8MHz PLLEN=1; //x4=32MHz //setup 1mS interrupt = 8,000,000/16 = 500,000/10 = 50,000 set PR2=49 = 50,000/50 = 1000 = 1mS T2CON=0b01001110; //pre=16 post=10 PR2=49; TMR2IE=1; //timer 2 interrupts enable T1CON=0; //timer 1 stopped for(i=0;i<NUM_SERVOS;i++){ servoPos[i]=i*1000+8000; //1ms(8000) to 1.875(7/8ths - 15000)ms in 1/8th mS steps } TRISC=0b11111100; //CCP0 & 1 output PEIE=1; GIE=1; while(1){ //adjust servo positions here } } void __interrupt() inter(void){ if(TMR2IE && TMR2IF){ ms++; count++; if(count>=20){ //start every 20mS TMR1=0; //zero timer 1 T1CON=1; //start timer 1 count=0; CCP1CON=0b1000; //CCP1 pin low and high on match - will be first pulse CCPR1L=0x0d; CCPR2H=0x07; CCP1IE=1; //enable CCP1 interrupts CCP1IF=0; //ensure interrupt flag is clear servoCount=0; //reset servoCount LATC0=1; //connected to data in of shift register will clock in a high when CCP1 goes high } TMR2IF=0; } if(CCP1IE && CCP1IF){ LATC0=0; //clear the data in pin if(servoCount==9) //have we done all servos? CCP1IE=0; //yes so no more CCP1 interrupts if(CCP1CON==0b1000){ //have we started the 4000 cycle pulse CCP1CON=0b1001; //yes so end the pulse after 0.5mS //CCPR1=CCPR1+4000; //4000 cycles=0.5mS wordTemp=CCPR1H*256+CCPR1L; wordTemp=wordTemp+4000; CCPR1L=wordTemp & 255; CCPR1H=wordTemp/256; }else{ CCP1CON=0b1000; //No so output the timed gap //CCPR1=CCPR1+servoPos[servoCount++]-4000; //will generate an interrupt when servo time is up wordTemp=CCPR1H*256+CCPR1L; wordTemp=wordTemp-4000+servoPos[servoCount]; CCPR1L=wordTemp&255; CCPR1H=wordTemp/256; servoCount=servoCount+1; } CCP1IF=0; } if(RCIE & RCIF){ uint8_t chr=RCREG; //get the received character if(OERR || FERR){ //neither of these should ever occur. CREN=0; //this is kinda wishful thinking CREN=1; //as any data received is corrupt strCount=0; //however, reset everything done=0; //and hope for the best }else{ //no errors so use the data if(strCount==0 && done==0){ //are we already receiving //waiting for $ //no so wait if(chr=='$'){ //for $ to appear buff[strCount]=chr; //start receiving strCount++; }else if(done==0){ //have we collected a full string? buff[strCount]=chr; //no so carry on storing strCount++; if(chr=='W'){ //have we got the "endOfString" character done=1; //yes, so set done true } } } } } }
Mike.
Edit, you can of course replace,
CCPR1L=wordTemp&255;
CCPR1H=wordTemp/256;
with
CCPR1L=wordTemp.LB
CCPR1H=wordTemp.HB
Edit2, seems constants aren't defined with Define but Const so
Const NUM_SERVOS=10
and
Const BUFFER=80
should be fine.
Edit3, looks like multiple definition on one line are not allowed so
uint8_t buff[BUFFER],strCount=0,done=0;
will become
Dim buff(BUFFER) as byte
Dim strCount as byte
Dim done as byte
and initialise them prior to enabling interrupts,
strCount=0
done=0
before the line
PEIE=1
Edit4, TRISC will also need to be changed
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?