|
|
View previous topic :: View next topic |
Author |
Message |
xavier righetti Guest
|
RS-232 communication problem. Please help ! |
Posted: Fri Oct 13, 2006 5:36 am |
|
|
Hello,
I'm using a PIC18F6720 to drive 16 servos.
I developed a c++ interface on my pc to control the servos via the rs232 interface. I'm using two aerocomm transceivers for wireless communication.
Each time the PIC receives a message from the pc, it sends an acknowledgement message. But after approximately 35 messages, the pic stops communicating...
Did someone have the same kind of issues ? Could somebody point me to a solution ?
Here is the source code of the embedded software:
pic.c:
------
Code: |
#include "C:\Work\PIC_C_SERVO\pic.h"
#include "C:\Work\PIC_C_SERVO\com.h"
#int_TIMER1
TIMER1_isr()
{
//alert("timer1 has reset...\n");
}
#int_CCP1
CCP1_isr(){
if (PWMready) {
if (i >= length) {
set_timer1(0);
i = 0;
if(PWMupdated){
PWMupdated = FALSE;
swapStack();
//PWMack = TRUE;
}
}
output_d(PWMStack[i]);
CCP_1 = PWMStack[i+1];
i += 2;
}
}
#int_RDA2
void RDA2_isr() // interruption lorsque RS232 reçoit des données
{
//putc('x');
//putc(timed_getc());
RCtreatC(timed_getc());
}
void init() {
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_spi2(FALSE);
setup_wdt(WDT_ON);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
setup_timer_4(T4_DISABLED,0,1);
setup_ccp1(CCP_COMPARE_INT);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_RDA2);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);
setup_low_volt_detect(FALSE);
setup_oscillator(False);
chgSrvo = FALSE;
Verbose = TRUE;
high = TRUE;
PWMready = FALSE;
PWMupdate = FALSE;
PWMstack = PWMstack1;
PWMPasStack = PWMstack2;
SET_TRIS_D(0x00); //port D output
output_d(0);
servoValue = 2000; // 1.5 ms : Neutral
periodValue = 49997;
i = 0;
}
void main()
{
int deltaPrec;
init();
switch (restart_cause()) {
case WDT_TIMEOUT :
alert("Restarted due to Watchdog overflow\n");
break;
case MCLR_FROM_SLEEP :
alert("Restarted due to waking up from sleep\n");
break;
case NORMAL_POWER_UP :
alert("Microcontroller initialized\n");
break;
case BROWNOUT_RESTART :
alert("Restarted due to low voltage detected\n");
break;
default :
alert("Restarted due to abnormal error\n");
}
while(TRUE)
{
restart_wdt();
if(sendMsg){
//alert("Envoi des donnees\n");
sendMsg = FALSE;
}
if(getPrecision){
SendMessage(T_GET_PREC,2,(BYTE *)&newTimerVal);
//SendMessage(T_GET_TOTA,2,(BYTE *)&totalVal);
getPrecision = FALSE;
}
if (PWMcheck) {
SendMessage(T_PWM_CHK, RCmess.sizedata, RCmess.data);
PWMcheck = FALSE;
}
if(PWMupdate) {
for (j = 0; j < RCmess.sizedata/2; j++){
k = j * 2;
answer = make16(RCMess.data[k],RCMess.data[k+1]);
PWMPasStack[j] = answer;
}
lengthPas = RCmess.sizedata/2;
PWMack = TRUE;
PWMready = TRUE;
PWMupdate = FALSE;
//PWMupdated = TRUE;
}
if(PWMack){
sendMessage(T_PWM_ACK,0,NULL);
PWMack = FALSE;
}
if(GetPWMS){
sendMessage(T_GET_PWMS,length,PWMStack);
GetPWMS = FALSE;
}
if(GetPWMP){
sendMessage(T_GET_PWMS,lengthPas,PWMPasStack);
GetPWMP = FALSE;
}
}
}
|
pic.h
Code: |
#include <18F6720.h>
#device adc=8
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES HS //High speed Osc (> 4mhz)
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOOSCSEN //Oscillator switching is disabled, main oscillator is source
#FUSES BROWNOUT //Reset when brownout detected
#FUSES BORV25 //Brownout reset at 2.5V
#FUSES NOPUT //No Power Up Timer
#FUSES NOCPD //No EE protection
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NODEBUG //No Debug mode for ICD
#FUSES LVP //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOWRT //Program memory not write protected
#FUSES NOCPB //No Boot Block code protection
#FUSES NOEBTRB //Boot block not protected from table reads
#FUSES NOEBTR //Memory not protected from table reads
#FUSES NOWRTD //Data EEPROM not write protected
#FUSES NOWRTC //configuration not registers write protected
#FUSES NOWRTB //Boot block not write protected
#use delay(clock=20000000)
#use rs232(baud=57600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#use rs232(baud=57600,parity=N,xmit=PIN_G1,rcv=PIN_G2,bits=8)
#use fast_io(D)
void generatePWMstack(BYTE * source, BYTE * _message, int * length);
void swapStack();
//global variables
typedef struct {
BYTE type;
BYTE sizedata;
BYTE * data;
} message;
char ch;
BYTE RCi;
message RCmess;
BYTE PWMval[8];
unsigned int16 PWMstack1[64];
unsigned int16 PWMstack2[64];
unsigned int16 * PWMstack;
unsigned int16 * PWMPasStack;
BYTE length,lengthPas;
int i;
BOOLEAN PWMready;
BOOLEAN PWMupdate;
BOOLEAN PWMupdated;
BOOLEAN PWMack;
BOOLEAN PWMcheck;
BOOLEAN getprecision;
BOOLEAN GetPWMS;
BOOLEAN GetPWMP;
BOOLEAN sendMsg;
BOOLEAN chgSrvo;
BOOLEAN Verbose;
BOOLEAN high;
//global functions
void alert(char c);
void RCtreatC(char c);
void RCtreatMess();
void SendMessage(BYTE message_type, BYTE size_data, BYTE * data);
|
com.h:
Code: |
#include <stdlibm.h>
//Start_up Code
#define BOOT_RESET 0xC1
#define BOOT_START 0x90
//RC packet flag
#define RC_START 0x69
#define RC_STOP 0x96
//message type
#define T_TXT 0x05
#define T_GET_PWMS 0x07
#define T_GET_PWMP 0x77
#define T_CHG_SRVO 0x08
#define T_GET_PREC 0x09
#define T_GET_TOTA 0x10
#define T_CHG_PERI 0x11
#define T_PWM_ACK 0x12
#define T_PWM_STA 0x13
#define T_PWM_LST 0x14
#define T_PWM_CHK 0x15
#define PWM_period 16 // set the period of the PWM outputs
//custom data types
BYTE alerti;
char str[64];
unsigned int16 servoValue;
unsigned int16 periodValue;
unsigned int16 newTimerVal;
unsigned int16 totalVal;
int j;
int k;
unsigned int16 answer;
////////////////////////////////////////////////////////
// timed_getc() //
////////////////////////////////////////////////////////
char timed_getc() {
long time_out;
//mnt_error=NOERR;
time_out=0;
while(!kbhit()&&(++time_out<10000)) // 0.2 second
delay_us(20);
if(kbhit())
return(fgetc());
else {
//mnt_error=TIMEOUT;
alert("ERROR timeout reception bluetooth\n");
reset_cpu();
return(0);
}
}
////////////////////////////////////////////////////////
// RCtreatC //
////////////////////////////////////////////////////////
void RCtreatC(char c) {
//alert("RCtreatC");
//test header
if (RCi == 0) {
if (c == RC_START) {
RCi ++;
}
else {
// alert("ERROR : no Start byte\n");
RCi = 0;
}
return;
}
if (RCi == 1) {
RCmess.type = c;
RCi ++;
return;
}
if (RCi == 2) {
RCmess.sizedata = c;
RCmess.data = malloc(RCmess.sizedata);
RCi++;
return;
}
if ( (RCi-3) <RCmess>= 60) {
alerti = 0;
return;
}
if (c == '\n') {
str[alerti] = c;
alerti ++;
putc(RC_START); //0xA6; //start byte
putc(T_TXT);
putc(alerti);
//data
for(i=0;i<alerti;i++) {
putc(str[i]);
}
//ending
putc(RC_STOP);
alerti=0;
// delay_ms(300);
}
else {
str[alerti] = c;
alerti ++;
}
return;
}
////////////////////////////////////////////////////////
// SendMessage() //
////////////////////////////////////////////////////////
void SendMessage(BYTE message_type, BYTE size_data, BYTE * data) {
int i;
if ((data == NULL) && (size_data != 0)) {
alert("ERROR SendMessage: NULL pointer data\n");
return;
}
//header
putc(RC_START);
putc(message_type);
putc(size_data);
//data
for(i=0;i<size_data;i++) {
putc(data[i]);
}
//ending
putc(RC_STOP);
return;
}
////////////////////////////////////////////////////////
// swapStack() //
////////////////////////////////////////////////////////
void swapStack() {
BYTE * temp;
BYTE temp2;
temp = PWMPasStack;
temp2 = lengthPas;
PWMPasStack = PWMstack;
lengthPas = length;
PWMstack = temp;
length = temp2;
alert("swap!\n");
return;
}
|
Thank you very much in advance for your kind answers
xavier |
|
|
bsodmike
Joined: 05 Aug 2006 Posts: 52
|
|
Posted: Fri Oct 13, 2006 5:40 am |
|
|
Code: | #use rs232(baud=57600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#use rs232(baud=57600,parity=N,xmit=PIN_G1,rcv=PIN_G2,bits=8) |
Wouldn't you be better off defining a stream for each one and using fprintf() just to ensure your rs232 coms is taking to the correct UART?
Also, what's inside 'alert();'? |
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1635 Location: Perth, Australia
|
|
Posted: Fri Oct 13, 2006 6:05 am |
|
|
You are missing the errors directive on the #use rs232 line _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
xavier righetti Guest
|
|
Posted: Fri Oct 13, 2006 6:22 am |
|
|
bsodmike wrote: | Code: | #use rs232(baud=57600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#use rs232(baud=57600,parity=N,xmit=PIN_G1,rcv=PIN_G2,bits=8) |
Wouldn't you be better off defining a stream for each one and using fprintf() just to ensure your rs232 coms is taking to the correct UART?
Also, what's inside 'alert();'? |
Hi mike,
Thank you for your fast answer!
I don't use the first #use rs232 definition, always the second one.
Sorry I didn't copy the entire com.h file, here are the two missing methods:
[code]
////////////////////////////////////////////////////////
// RCtreatMess() //
////////////////////////////////////////////////////////
void RCtreatMess() {
if (RCmess.type == T_GET_PREC) {
getPrecision = TRUE;
return;
}
if (RCmess.type == T_PWM_ACK) {
PWMupdate = TRUE;
//PWMack = TRUE;
return;
}
if (RCmess.type == T_PWM_STA) {
PWMready = FALSE;
//check if size is ok
if (RCmess.sizedata == 0) {
alert("ERROR : No data for the PWM stack\n");
return;
}
//PWMupdate = TRUE;
PWMcheck = TRUE;
return;
}
alert("ERROR : Unknown message type\n");
return;
}
////////////////////////////////////////////////////////
// alert() //
////////////////////////////////////////////////////////
void alert(char c){
int i;
if (!Verbose)
return;
if (alerti >= 60) {
alerti = 0;
return;
}
if (c == '\n') {
str[alerti] = c;
alerti ++;
putc(RC_START); //0xA6; //start byte
putc(T_TXT);
putc(alerti);
//data
for(i=0;i<alerti;i++) {
putc(str[i]);
}
//ending
putc(RC_STOP);
alerti=0;
// delay_ms(300);
}
else {
str[alerti] = c;
alerti ++;
}
return;
}
As you can see, the alert method simply sends text messages (message must end with a \n).
I monitored the messages and everything seems, fine. The pic is talking to the correct UART... |
|
|
Guest
|
|
Posted: Fri Oct 13, 2006 6:31 am |
|
|
asmallri wrote: | You are missing the errors directive on the #use rs232 line |
Hi asmallri,
I added the ERRORS directive:
Code: |
#use rs232(baud=57600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8, ERRORS)
#use rs232(baud=57600,parity=N,xmit=PIN_G1,rcv=PIN_G2,bits=8, ERRORS)
|
Everything works fine, but still after 40 messages, The PIC stops answering.. Is there something I have to check using the RS232_ERRORS variable ?
Thank you very much...
xavier |
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1635 Location: Perth, Australia
|
|
Posted: Fri Oct 13, 2006 6:40 am |
|
|
The errors directive will tell the compiler to add code to deal with lockup of the UART. If you are still getting ewrrors then your bug is elsewhere (but don't delete the errors flag) _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
Ttelmah Guest
|
|
Posted: Fri Oct 13, 2006 6:47 am |
|
|
No.
ERRORS, is basically automatic. What it does, is if this is added to the define, then whenever the serial port is read, the compiler adds the small amount of extra code, to check for the OERR bit being set in particular, and clear this (done by disabling, then re-enabling the UART). This is'seperate' from the function of RS232_ERRORS, into which the value of the error bits will be written, so you can 'see' if an error has occurred. OERR, is the important error, since if this is set, the UART stops receiving...
Now some other comments apply. There is no point at all, in using a 'timed getc' function inside a serial interrupt. A timed getc function, is for use 'outside' the interrupt, where you don't want the system to hang if a character has not arrived. If you arrive in the interrupt, then a character _has_ been seen, and this is adding complexity to the interrupt handler. Then the real 'killer', is what you do in the character handler. In the event of seeing the line feed character, you are printing out three characters, plus a whole received string. Don't do this. It will _guarantee_ overrun errors, since as you are inside the interrupt, no character reception can take place fo the whole of this time. Also, you seem to malloc a new buffer for each message, but I then see no sign of you giving the buffer back. This is also a complex and potentially slow thing to do in an interrupt. Instead have a _single_ buffer large enough for the biggest expected message, and keep re-using this. If you must print the reply inside the interrupt, buffer the transmission, as well as reception. Much better though, buffer the incoming data, and do the interpretation in the main loop.
I suspect the actual fault is that malloc is running out of memory.
Best Wishes |
|
|
Guest
|
|
Posted: Fri Oct 13, 2006 7:21 am |
|
|
Ttelmah, YOU RULE !!!!!!!
Thank you very very very much !!
I changed the struct as you said to the max possible value:
Code: |
typedef struct {
BYTE type;
BYTE sizedata;
BYTE data [128];
} message;
|
and I removed the malloc directive:
Code: |
if (RCi == 2) {
RCmess.sizedata = c;
//RCmess.data = malloc(RCmess.sizedata);
RCi++;
return;
}
|
And now it works !!
I'm working on the other issues you pointed out...
Once again, thank you
xavier
p.s. somebody can change the subject to resolved! |
|
|
Ttelmah Guest
|
|
Posted: Fri Oct 13, 2006 2:29 pm |
|
|
This was actually raher a good illustration of how the problem can often not be what it seems.
The original 'comms stopping' fault, is 'classic' for not having the errors statement in the setup, since if more than two characters arrive at any time without handling,this leads to the UART locking up. Asmallri correctly pointed this out. This helped a fraction, but the problem then reappeared a few loops latter, so I found myself thinking 'for some reason, the interrupt code is getting slower (and hence the fault worse), the more it is called'. I found myself thinking 'oh dear far too much in the interrupt handler at times', but then saw one thing that would get slower and slower, which was the malloc. :-)
Glad it is working.
Best Wishes |
|
|
|
|
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
|