|
|
View previous topic :: View next topic |
Author |
Message |
on7nh
Joined: 05 Jun 2006 Posts: 41 Location: Belgium
|
problem with interrupt and rs232 |
Posted: Sat May 21, 2011 11:06 am |
|
|
hello,
I have a problem with serial communication and fast interrupt.
The fast interrupt is comming from 2 encoders.
Serial communication from a pc, who is polling the pic.
When encoder is not moving, communication is running a long time, but when encoder is moving, after a few seconds, the serial communications stucks...it sounds as a serial buffer overrun.
Have anybody a idea how to solve this ?
I send the complete code...
Thanks,
Carl
Code: |
#include <30f4013.h>
#device adc=12
#Device icd=true
#FUSES WDT // Watch Dog Timer
#FUSES HS
#FUSES NOCKSFSM //Clock Switching is disabled, fail Safe clock monitor is disabled
#fuses HS2_pll8 // div by 3 and multiply the ext. clock of 40mhz by 8x
#FUSES BROWNOUT //Reset when brownout detected
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOWRT //Program memory not write protected
#FUSES NODEBUG //No Debug mode for ICD
#include <stdlib.h>
#include <string.h>
#define XTAL_FREQUENCY 120000000,RESTART_WDT
#use delay(clock=XTAL_FREQUENCY)
#use rs232(baud=115200,parity=N,uart2,bits=8)
/////////////////// Variabelen /////////////////
int32 EL_actu_position,AZ_actu_position;
int32 EL_calc_position,AZ_calc_position;
int32 EL_dest_position,AZ_dest_position;
int EL_init_ok, AZ_init_ok;
int32 EL_offset, AZ_Offset,AZ_u1;
int EL_stapteller=0,AZ_stapteller;
int EL_PID_OVER, AZ_PID_OVER;
int EL_STILL, AZ_STILL;
int el_brake_state, AZ_brake_state;
/////of the PID-controller azimuth ///////////////////////
int32 AZ_x0=0.0, AZ_y0=0.0, AZ_z0=0.0, AZ_u=0.0;
int32 AZ_y1, AZ_z1 ;
int32 AZ_Kr=15000.0, AZ_Ti=5000.0, AZ_Td=1000.0; // parameters of the PID-controller
int32 AZ_u0, AZ_dt=0.667;
/////of the PID-controller elevatie ///////////////////////
int32 EL_x0=0, EL_y0=0, EL_z0=0, EL_u=0;
int32 EL_y1, EL_z1, EL_u1;
int32 EL_Kr=15000, EL_Ti=5000, EL_Td=10000; // parameters of the PID-controller
int32 EL_u0, EL_dt=0.667;
///// variabelen voor rs232 ///////////////////////
#define COMBUFFSIZE 40
static int packet_ready = false;
static int8 buff[COMBUFFSIZE] = {0};
static int8 commNotActive = 0;
#define BUFFER_SIZE 100
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;
/////////////////// UIT-gangan /////////////////
#define AZ_CCW_Lswitsh PIN_B0 // input pen 2
#define AZ_CW_Lswitsh PIN_B1 // input pen 3
#define EL_CCW_Lswitsh PIN_B2 // input pen 4
#define EL_CW_Lswitsh PIN_B3 // input pen 5
#define AZ_enc_A PIN_A11 // input pen 17
#define AZ_enc_B PIN_B4 // input pen 6
#define AZ_enc_Z PIN_B11 // input pen 36
#define EL_enc_A PIN_D8 // input pen 23
#define EL_enc_B PIN_B5 // input pen 7
#define EL_enc_Z PIN_B12 // input pen 35
#define AZ_Enbl_Drive PIN_F1 // output pen 29
#define EL_Enbl_Drive PIN_F0 // output pen 30
#define AZ_pwm_CCW PIN_D3 // output pen 19
#define AZ_pwm_CW PIN_D2 // output pen 22
#define EL_pwm_CCW PIN_D1 // output pen 33
#define EL_pwm_CW PIN_D0 // output pen 34
#define AZ_Brake PIN_B9 // output pen 38
#define EL_Brake PIN_B10 // output pen 37
/////////////////////////////////////////////////////////////////////////////////////
void EXT_Encoder_AZ();
void EXT_Encoder_EL();
void RS232();
void AZ_TrajectBerekening();
void EL_TrajectBerekening();
/////////////////////////////////////////////////////////////////////////////////////
#int_rda2
void serial_isr() {
int t;
buffer[next_in]=getc();
t=next_in;
next_in=(next_in+1) % BUFFER_SIZE;
if(next_in==next_out)
next_in=t; // Buffer full !!
}
#define bkbhit (next_in!=next_out)
BYTE bgetc() {
BYTE c;
while(!bkbhit) ;
c=buffer[next_out];
next_out=(next_out+1) % BUFFER_SIZE;
return(c);
}
////////////////////////////////////////////////////////////////////////////////////
/****************** encoder Azimuth inlezen *******************/
#int_ext0
void EXT_Encoder_AZ()
{
if (input(AZ_enc_B) == 1)
{
AZ_actu_position = AZ_actu_position + 1.0;
}
else
{
AZ_actu_position = AZ_actu_position - 1.0;
}
}
/////////////////////////////////////////////////////////////////////////////////////
/****************** encoder elevatie inlezen *******************/
#int_ext1
void EXT_Encoder_EL()
{
if (input(EL_enc_B) == 1)
{
EL_actu_position = EL_actu_position +1.0;
}
else
{
EL_actu_position = EL_actu_position- 1.0;
}
}
/////////////////////////////////////////////////////////////////////////////////////
#INT_TIMER4
void TIMER4_isr()
{
// AZ_TrajectBerekening();
// EL_TrajectBerekening();
}
/////////////////////////////////////////////////////////////////////////////////////
void AZ_CalcError (void)
{
// AZ_actu_position is de positie waarde encoder is
// AZ_calc_position is de berekende positie
// AZ_u0 is de foutwaarde die in de PID gaat
AZ_u0 = AZ_actu_position - AZ_calc_position;
}
/////////////////////////////////////////////////////////////////////////////////////
void EL_CalcError (void)
{
// EL_actu_position is de positie waarde encoder is
// EL_calc_position is de berekende positie
// EL_u0 is de foutwaarde die in de PID gaat
EL_u0 = EL_actu_position - EL_calc_position;
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
void AZ_CalcPID ()
{
AZ_x0 = (AZ_Kr*AZ_u0)/1000; // P-action with Kr=100
AZ_y1 = AZ_y0 + AZ_x0/AZ_Ti*AZ_dt;
AZ_z1 = AZ_y0 + AZ_x0; // I-action with timeconstant Ti= 10
AZ_u1 = AZ_z0 + AZ_Td*(AZ_z1-AZ_z0)/AZ_dt; // D-action with timeconstant Td= 1
AZ_y0=AZ_y1;
AZ_z0=AZ_z1;
AZ_u=AZ_u1;
// hier word de ondergrens begrensd , dus hier tot -500
if(AZ_u1 < -500) //limit the calculated new dutycycle to zero to prevent strange behaviour
{
// indien kleiner als -500 deze waarde doorgeven
AZ_u1 = -500; // limit u1
}
//
// hier word de bovengrens begrensd , dus hier tot 500
if(AZ_u1 > 500) //limit the calculated new dutycycle to 1023 to prevent strange behaviour
{
// indien groter als 500 deze waarde doorgeven
AZ_u1 = 500; // limit u1
}
}
/////////////////////////////////////////////////////////////////////////////////////
void EL_CalcPID ()
{
EL_x0 = (EL_Kr*EL_u0)/1000; // P-action with Kr=100
EL_y1 = EL_y0 + EL_x0/EL_Ti*EL_dt;
EL_z1 = EL_y0 + EL_x0; // I-action with timeconstant Ti= 10
EL_u1 = EL_z0 + EL_Td*(EL_z1-EL_z0)/EL_dt; // D-action with timeconstant Td= 1
EL_y0=EL_y1;
EL_z0=EL_z1;
EL_u=EL_u1;
//hier word de ondergrens begrensd , dus hier tot -500
if(EL_u1 < -500) //limit the calculated new dutycycle to zero to prevent strange behaviour
{
//indien kleiner als -500 deze waarde doorgeve
EL_u1 = -500; // limit u1
}
//
//hier word de bovengrens begrensd , dus hier tot 500
if(EL_u1 > 500) //limit the calculated new dutycycle to 1023 to prevent strange behaviour
{
//indien groter als 500 deze waarde doorgeven
EL_u1 = 500; // limit u1
}
}
/////////////////////////////////////////////////////////////////////////////////////
void AZ_PWM(int AZ_speed,AZ_driv_enb)
{
// Drive enabelen en pwm instellen //
// De waarde kan negatief of positief zijn, dus CW of CCW //
// De waarde mag tussen -500 en +500 zijn, 0 is stilstaan //
if (AZ_speed > 1 && !input(AZ_CCW_Lswitsh))
{
AZ_brake_state=1;
set_pwm_duty(3,0); // --> fsw = 78.12 kHz
set_pwm_duty(4,AZ_speed); // --> fsw = 78.12 kHz
AZ_STILL = 1;
}
if (AZ_speed == 0)
{
set_pwm_duty(3,0); // --> fsw = 78.12 kHz
set_pwm_duty(4,0); // --> fsw = 78.12 kHz
AZ_STILL = 0;
AZ_brake_state = 0;
}
if (AZ_speed < -1 && !input(AZ_CW_Lswitsh))
{
AZ_brake_state = 1;
set_pwm_duty(3,(AZ_speed * -1)); // --> fsw = 78.12 kHz
set_pwm_duty(4,0); // --> fsw = 78.12 kHz
AZ_STILL = 1;
}
if ( AZ_brake_state == 1)
{
output_high(AZ_brake);
output_high(AZ_Enbl_Drive);
}
else
{
output_low(AZ_brake);
output_low(AZ_Enbl_Drive);
}
}
/////////////////////////////////////////////////////////////////////////////////////
void EL_PWM(int EL_speed,EL_driv_enb)
{
// Drive enabelen en pwm instellen //
// De waarde kan negatief of positief zijn, dus CW of CCW //
// De waarde mag tussen -500 en +500 zijn, 0 is stilstaan //
if (EL_speed > 1 && !input(EL_CCW_Lswitsh))
{
EL_brake_state=1;
set_pwm_duty(1,0); // --> fsw = 78.12 kHz
set_pwm_duty(2,EL_speed); // --> fsw = 78.12 kHz
EL_STILL = 1;
}
if (EL_speed ==0)
{
set_pwm_duty(1,0); // --> fsw = 78.12 kHz
set_pwm_duty(2,0); // --> fsw = 78.12 kHz
EL_STILL = 0;
EL_brake_state=0;
}
if (EL_speed < -1 && !input(EL_CW_Lswitsh))
{
EL_brake_state=1;
set_pwm_duty(1,(EL_speed * -1)); // --> fsw = 78.12 kHz
set_pwm_duty(2,0); // --> fsw = 78.12 kHz
EL_STILL = 1;
}
if ( EL_brake_state == 1)
{
output_high(EL_brake);
output_high(EL_Enbl_Drive);
}
else
{
output_low(EL_brake);
output_low(EL_Enbl_Drive);
}
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
void Init_AZ()
{
// nulpunt zoeken van de encoder //
if ((!input(AZ_CW_Lswitsh)& AZ_stapteller==0))
{
AZ_PWM(-80,1);
AZ_stapteller=1;
}
if ((input(AZ_CW_Lswitsh)& AZ_stapteller==1))
{
AZ_PWM(0,0);
delay_ms(100);
AZ_PWM(50,1);
AZ_stapteller=2;
}
if ((!input(AZ_CW_Lswitsh)& AZ_stapteller==2))
{
AZ_PWM(50,1);
AZ_stapteller=3;
}
if ((!input(AZ_enc_Z)& AZ_stapteller==3))
{
AZ_PWM(0,0);
AZ_stapteller=4;
AZ_actu_position=10000;
AZ_calc_position = AZ_actu_position;
AZ_init_ok=1;
}
}
/////////////////////////////////////////////////////////////////////////////////////
void Init_EL()
{
// nulpunt zoeken van de encoder //
if ((!input(EL_CW_Lswitsh)& EL_stapteller==0))
{
EL_pwm(-100,1);
EL_stapteller=1;
}
if ((input(EL_CW_Lswitsh)& EL_stapteller==1))
{
EL_pwm(0,0);
delay_ms(100);
EL_pwm(100,1);
EL_stapteller=2;
}
if ((!input(EL_CW_Lswitsh)& EL_stapteller==2))
{
EL_pwm(50,1);
EL_stapteller=3;
}
if ((!input(EL_enc_Z)& EL_stapteller==3))
{
EL_PWM(0,0);
EL_stapteller=4;
EL_actu_position=10000;
EL_calc_position = EL_actu_position;
EL_init_ok=1;
}
}
/////////////////////////////////////////////////////////////////////////////////////
void AZ_TrajectBerekening()
{
if (AZ_calc_position < AZ_dest_position)
{
AZ_calc_position = AZ_calc_position + 1.0;
}
if (AZ_calc_position > AZ_dest_position)
{
AZ_calc_position = AZ_calc_position - 1.0;
}
}
/////////////////////////////////////////////////////////////////////////////////////
void EL_TrajectBerekening()
{
if (EL_calc_position < EL_dest_position)
{
EL_calc_position = EL_calc_position + 1.0;
}
if (EL_calc_position < EL_dest_position)
{
EL_calc_position = EL_calc_position - 1.0;
}
}
/////////////////////////////////////////////////////////////////////////////////////
void main() {
setup_timer2(TMR_INTERNAL | TMR_DIV_BY_64,500); // prescale=64, PR2=255
setup_compare(1, COMPARE_PWM | COMPARE_TIMER2); // Configre for PWM mode
setup_compare(2, COMPARE_PWM | COMPARE_TIMER2); // Configre for PWM mode
setup_compare(3, COMPARE_PWM | COMPARE_TIMER2); // Configre for PWM mode
setup_compare(4, COMPARE_PWM | COMPARE_TIMER2); // Configre for PWM mode
AZ_PWM(0,0);
EL_PWM(0,0);
EXT_INT_EDGE(L_TO_H);
enable_interrupts(INT_timer4);
enable_interrupts(INT_EXT1);
enable_interrupts(INT_EXT0);
enable_interrupts(int_rda2);
enable_interrupts(intr_global);
output_low(AZ_Enbl_Drive);
AZ_actu_position = 0;
AZ_init_ok = 0;
AZ_stapteller=0;
AZ_dest_position=12000;
AZ_calc_position=2000;
// initialisatie Elevatie Drive
output_high(EL_Enbl_Drive);
EL_actu_position = 0;
EL_init_ok = 0;
EL_stapteller=0;
EL_dest_position=2000;
EL_calc_position=2000;
printf("Boot");
do {
// if (Packet_ready == true)
// Processcommand();
// output_high(AZ_brake);
// output_high(EL_brake);
if ((AZ_init_ok != 1))//||(EL_init_ok != 1))
{
if (AZ_init_ok != 1)
Init_AZ(); // eerst initialisatie uitvoeren
//if ((AZ_init_ok == 1)&(EL_init_ok != 1))
// Init_El(); // eerst initialisatie uitvoeren
}
else
{
/////// de regellus doorlopen
// AZ_TrajectBerekening();
AZ_CalcError();
AZ_CalcPID();
AZ_PWM((AZ_U1),1);
// EL_TrajectBerekening();
EL_CalcError();
EL_CalcPID();
EL_PWM((EL_U1*-1),1);
}
while(bkbhit)
putc( bgetc() );
} while (TRUE);
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Sat May 21, 2011 2:34 pm |
|
|
_Always_, when using the hardware UART, have the keyword 'ERRORS' in the RS232 setup. This adds error recovery code to the getc routine. Only time not to do this, is if _you_ are doing this recovery yourself.
Without this, if 2 characters arrive without the RS232 interrupt being serviced, you _will_ hang the UART.
Big reason for problems, is your UART buffer size. Using '%' in the ISR, only works safely, if you use a binary buffer size (32, 64 etc.). It really should be documented in the examples. For a non binary buffer size as you have, replace the line in the ISR with:
Code: |
//next_in=(next_in+1) % BUFFER_SIZE;
if (++next_in)==BUFFER_SIZE next_in=0;
|
Using a non binary buffer size forces the modulus operation to use a division, and makes it very slow. It also means that interrupts will be disabled in any eight bit divisions in the main code. The test and replace, is about 40* faster, and avoids this problem....
Best Wishes |
|
|
on7nh
Joined: 05 Jun 2006 Posts: 41 Location: Belgium
|
|
Posted: Sat May 21, 2011 3:27 pm |
|
|
@ Ttelmah
hmmm. I did read this post..re-read because it is almost midnight....
changing the buffer size make sense...change to 64 : check
test and communication hangs still after +-20 seconds.
I did also a test with slower communication, ...the same problem.
Changed also the code you mention, but I received a error on this...
greeting,
Carl |
|
|
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Sat May 21, 2011 10:18 pm |
|
|
Your code should look like: Code: | #use rs232(baud=115200,parity=N,uart2,bits=8,errors) | If you get an error, post back the message.
Also, when coding circular buffers I prefer to use code like: Code: | if (++ptr == BUFFER_SIZE) ptr = 0; | That precise code may change slightly depending on if I'm adding or removing to/from the buffer, or if I want it to be a LRU or MRU (least/most-recently used). The concept remains the same. No division, no power-of-2 worries, and I can use any size buffer. _________________ Andrew |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Sun May 22, 2011 2:02 am |
|
|
I'd suspect you get a warning, not an error.
When you add the keyword 'errors', error handling code is added. The compiler also adds a variable 'rs232_errors', _containing_ details of the errors it has seen/fixed. Since your code does not use this, you get a compiler warning. However a _warning_, _not_ and 'error'.
You can:
1) Just ignore it. It is only saying there is an unused variable - this is what most people do.
2) Prevent the error, by reading this variable. Typically just add the line:
val=rs232_errors;
somewhere in your code, where 'val' is a variable you use for something else. Then just clear val, and carry on as normal.
3) Add your own code to unlock the UART (pointless in general).
4) Carry on having the locks.....
Best Wishes |
|
|
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Mon May 23, 2011 1:04 am |
|
|
I forgot about that warning message!
I just add the following function to my code: Code: | void use_rs232_errors(void)
{
rs232_errors = 0;
} | This uses the variable and gets rid of the warning. The trick is that I don't call it anywhere, so the compiler optimises it away so it doesn't take up any space. _________________ Andrew |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|