|
|
View previous topic :: View next topic |
Author |
Message |
soong2020
Joined: 13 Feb 2008 Posts: 25
|
Problem with serial transmit and receive... |
Posted: Thu Apr 24, 2008 12:32 pm |
|
|
Hi fellow forumers, i've got a problem here with my source code which some of you might have come across before in this forum. I've expanded it into quite a long one so for reading convenience, i've taken out some parts which are unrelated to the problem.
So here is the problem. My PIC16F877A is supposed to be programmed to generate PWM to drive servomotors and also in the meantime receive inputs from a GUI from PC to move accordingly. The GUI is programmed to send in characters like "a" or "b" for it to move. In the mean time, the PIC is also supposed to be sending feedback values from 2 potentiometers connected to channel AN0 and AN1.
When the whole thing is running, i've got no problem receiving values from the PIC on an interval of every 1 second. But i am not able to control it from the GUI, which means the PIC can't read the characters sent from the PC.
However, when i turn off the puts() function, which sends out the feedback values in a string to my PC, the PIC is able to receive chars again. Dear forumers, can anyone please help me out on this? I'm nearing my due date for my project.
Here is the code:
Code: |
#include <16F877A.h>
#device ADC=10
#include <string.h>
#include <stdlib.h>
#fuses HS, NOLVP
#use delay(clock = 20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS, PARITY=N)
#define BTN_CEN1 PIN_B7 // base
#define BTN_R1 PIN_B6
#define BTN_L1 PIN_B5
#define LOOPCNT1 400
#define LOOPCNT2 10
#define LOOPCNT3 100
int16 widthC, widthL, widthR;
int16 temp0,temp1,actual0,actual1,actual2,actual3;
int width01, width02, width03, width04, widthL2, widthR2,widthL3, widthR3,i;
int step=1;
int16 loop1 = LOOPCNT1, loop2 = LOOPCNT2, loop3 = LOOPCNT3;
int16 pulse1, pulse2, pulse3, pulse4;
char rec;
char string0[10];
char string1[10];
unsigned int fl_cen1, fl_right1, fl_left1, fl_pulse1;
unsigned int fl_cen2, fl_right2, fl_left2, fl_pulse2;
unsigned int fl_cen3, fl_right3, fl_left3, fl_pulse3;
unsigned int fl_cen4, fl_right4, fl_left4, fl_pulse4;
//============================================================================
void init_main()
{
set_tris_c(0x00); // servo port
output_c(0x00);
set_tris_b(0b1111111); //button port set to all input
output_b(0x00);
fl_cen1 = FALSE;
fl_right1 = FALSE;
fl_left1 = FALSE;
fl_pulse1 = 0;
// Some flag initialisations....
fl_elbow = FALSE;
fl_shoulder = FALSE;
}
//***************************************************************************
void Initialize_RTC(void)//////////*********************************************
{
setup_timer_1( T1_INTERNAL | T1_DIV_BY_1);
enable_interrupts(INT_TIMER1);
setup_timer_2(T2_DIV_BY_1,255,1);
enable_interrupts(INT_TIMER2);
setup_adc_ports( RA0_RA1_RA3_ANALOG );
setup_adc( ADC_CLOCK_INTERNAL );
enable_interrupts(INT_RDA);
//enable_interrupts(INT_TBE);
enable_interrupts(GLOBAL);
}
//==================================================================================================
void btn1_check()
{
if(fl_left1 == TRUE)
{
width01=width01-step;
delay_ms(50);
if(width01<widthL)
{
width01=width01+step;
delay_ms(50);
}
fl_left1 = FALSE;
}
if(fl_right1 == TRUE)
{
width01=width01+step;
delay_ms(50);
if(width01>widthR)
{
width01=width01-step;
delay_ms(50);
}
fl_right1 = FALSE;
}
if(fl_cen1 == TRUE)
{
if(width01<widthC)
{
for(i = width01; i < widthC; i++)
{
width01=width01+1;
delay_ms(50);
fl_cen1 = FALSE;
}
}
else if(width01>widthC)
{
for(i = width01; i > widthC; i--)
{
width01=width01-1;
delay_ms(50);
fl_cen1 = FALSE;
}
}
else if(width01 == widthC)
{
width01 = widthC;
delay_ms(50);
}
}
}
}
//--------------------------------------------------------------------
void btn2_check()
{
// Tasks for button2
}
//-------------------------------------------------------
void btn3_check()
{
// Tasks for button3
}
//-----------------------------------------------------------
void btn4_check()
{
// Tasks for button4
}
//========================================================
void adc_shoulder()
{
if(fl_shoulder==TRUE)
{
set_adc_channel( 0 );
delay_us(10);
temp0=read_adc() ;
temp0=temp0+1;
actual0=((float)temp0/1024)*270;
itoa(actual0,10,string0);
puts(string0);
fl_shoulder = FALSE;
}
}
//--------------------------------------------
void adc_elbow()
{
if(fl_elbow==TRUE)
{
set_adc_channel( 1 );
delay_us(10);
temp1=read_adc() ;
temp1=temp1+1;
actual1=((float)temp1/1024)*270;
itoa(actual1,10,string1);
puts(string1);
fl_elbow = FALSE;
}
}
//===========================================================
//=========================================================================================
void main()
{
init_main();
Initialize_RTC();
// Some initial values..........
while(1)
{
btn1_check();
btn2_check();
btn3_check();
btn4_check();
adc_shoulder();
adc_elbow();
}
}
//====================================================================================
//******************************************************************************
#INT_TIMER2 //////*************************************************************
void TIMER2_isr(void)
{
// To feed PWM values to servomotors continuously....
}
//****************************************************************************
#INT_TIMER1 //////*************************************************************
void TIMER1_isr(void)
{
if(--loop3 == 0)
{
loop3 = LOOPCNT3;
fl_shoulder = TRUE;
fl_elbow = TRUE;
}
// Codes removed are to check button states....
}
//==================================================
#INT_RDA
void serial_isr()
{
rec=getc();
switch(rec)
{
case 'h': //base centre
fl_cen1 = TRUE;
fl_cen2 = TRUE;
fl_cen3 = TRUE;
fl_cen4 = TRUE;
rec = NULL;
break;
case 'q':
fl_right1 = TRUE;
rec = NULL;
break;
case 'a':
fl_left1 = TRUE;
rec = NULL;
break;
default:
break;
}
}
//**********************************************************************
|
Sincerely appreciates it for assistance offered. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Apr 24, 2008 1:38 pm |
|
|
Please cut the program down to 1/4 of that size. Test it and verify
that it still shows the problem. Then post the short program.
It would make it easier for us to look at it. |
|
|
RLScott
Joined: 10 Jul 2007 Posts: 465
|
Re: Problem with serial transmit and receive... |
Posted: Thu Apr 24, 2008 2:04 pm |
|
|
This is not going to address your problem directly, but it may clear away some underbrush that will help see the situation more clearly.
1. Why are you bothering to set rec=NULL in your INT_RDA? No other code looks at rec, and INT_RDA always sets it upon entry. It is just confusing. Get rid of it.
2. Since your reported problem is with receiving serial data, do you have a more primitive way to check if INT_RDA is being called? I suggest toggling an unused output every time you enter INT_RDA and the watching it on a scope.
3. One effect of calling puts() is to take up some time. This will lengthen the round-trip time in your main() loop. Is it possible that INT_RDA is working just fine, but the delay caused by calling puts() is preventing you from recognizing the results of that serial receive properly? That is why I suggested a more primitive check on what is being received in order to remove that issue from the table.
4. Have you simplified the data stream from the PC as much as possible? For example, just send a single 'q' and nothing more, then see if the PIC gets it and furthermore if it responds correctly.
Robert Scott
Real-Time Specialties |
|
|
soong2020
Joined: 13 Feb 2008 Posts: 25
|
|
Posted: Fri Apr 25, 2008 1:33 am |
|
|
Thanks for the suggestions, Scott and i have simplified the codes into a short one here. I ran it and my PC could receive the datas from PIC but i cant get thru the commands from PC to PIC.
Code: | #include <16F877A.h>
#device ADC=10
#include <string.h>
#include <stdlib.h>
#fuses HS, NOLVP
#use delay(clock = 20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS, PARITY=N)
#define LOOPCNT3 100
int16 temp0,temp1,actual0,actual1,actual2,actual3;
int16 loop3 = LOOPCNT3;
char rec;
char string0[10];
char string1[10];
char string2[10];
unsigned int fl_cen1, fl_right1, fl_left1, fl_shoulder;
//============================================================================
void init_main()
{
fl_cen1 = FALSE;
fl_right1 = FALSE;
fl_left1 = FALSE;
fl_shoulder = FALSE;
}
//***************************************************************************
void Initialize_INT(void)//////////*********************************************
{
setup_timer_1( T1_INTERNAL | T1_DIV_BY_1);
enable_interrupts(INT_TIMER1);
setup_adc_ports( RA0_RA1_RA3_ANALOG );
setup_adc( ADC_CLOCK_INTERNAL );
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
}
//=================================================================================================
void adc_shoulder()
{
if(fl_shoulder==TRUE)
{
set_adc_channel( 0 );
delay_us(10);
temp0=read_adc() ;
temp0=temp0+1;
actual0=((float)temp0/1024)*270;
itoa(actual0,10,string0);
puts(string0);
fl_shoulder = FALSE;
}
}
//=========================================================================================
void main()
{
init_main();
Initialize_INT();
while(1)
{
adc_shoulder();
if(fl_cen1 == TRUE)
{
output_high(PIN_C0);
strcpy(string0,"h");
puts(string0);
fl_cen1 = FALSE;
}
else
output_low(PIN_C0);
}
}
#INT_TIMER1 //////*************************************************************
void TIMER1_isr(void)
{
if(--loop3 == 0)
{
loop3 = LOOPCNT3;
fl_shoulder = TRUE;
}
}
//==================================================
#INT_RDA
void serial_isr()
{
rec=getc();
switch(rec)
{
case 'h':
fl_cen1 = TRUE;
break;
default:
break;
}
}
//**********************************************************************
|
|
|
|
Matro Guest
|
|
Posted: Fri Apr 25, 2008 1:48 am |
|
|
Can you certify that your hardware is fully OK (especially wiring)?
How is made the level shifting between PIC and PC?
Matro |
|
|
soong2020
Joined: 13 Feb 2008 Posts: 25
|
|
Posted: Fri Apr 25, 2008 2:17 am |
|
|
Oh yes it is certainly working. I have been testing it for numerous times and it is able to transmit and receive separately but not when both ways are running together. The chip i am using is a Maxim MAX232ACPE chip.
My compiler version is 4.017. |
|
|
Matro Guest
|
|
Posted: Fri Apr 25, 2008 2:26 am |
|
|
Try this code that is simply "echoing" the received data :
Code: |
#include <16F877A.h>
#device ADC=10
#fuses HS, NOLVP
#use delay(clock = 20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS, PARITY=N)
char rec_char = 0x00;
void main()
{
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
while(1)
{
if(rec_char != 0x00)
{
putc(rec_char);
rec_char = 0x00;
}
}
}
#INT_RDA
void serial_isr()
{
rec_char = getc();
}
|
Matro |
|
|
soong2020
Joined: 13 Feb 2008 Posts: 25
|
|
Posted: Fri Apr 25, 2008 5:16 am |
|
|
Thanks Matro. The echo-ing code worked perfectly. But how do i write it in a way that allows me to constantly check for the char input from PC while the PIC sends data to the PC in a certain interval?
Thanks |
|
|
RLScott
Joined: 10 Jul 2007 Posts: 465
|
|
Posted: Fri Apr 25, 2008 5:28 am |
|
|
soong2020 wrote: | ...I ran it and my PC could receive the datas from PIC but i cant get thru the commands from PC to PIC. |
Did you try the test I suggested above, sending a single 'q' from the PC and nothing more, to see if the PIC can receive just one command?
Robert Scott
Real-Time Specialties |
|
|
soong2020
Joined: 13 Feb 2008 Posts: 25
|
|
Posted: Fri Apr 25, 2008 5:55 am |
|
|
RLScott wrote: |
Did you try the test I suggested above, sending a single 'q' from the PC and nothing more, to see if the PIC can receive just one command?
Robert Scott
Real-Time Specialties |
Yeah i have done the following and it is working fine too.
Code: |
#include <16F877A.h>
#device ADC=10
#fuses HS, NOLVP
#use delay(clock = 20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS, PARITY=N)
char rec_char = 0x00;
char string[10];
void main()
{
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
while(1)
{
if(rec_char == 'q' && rec_char!=0x00)
{
strcpy(string,"Hello");
puts(string);
rec_char = 0x00;
}
}
}
#INT_RDA
void serial_isr()
{
rec_char = getc();
}
|
|
|
|
Matro Guest
|
|
Posted: Fri Apr 25, 2008 6:04 am |
|
|
I think the best way is to start from the echo-ing code and to add progressively each feature and to test each time the modifications to see what could trigger a problem.
Some remarks about your code (in comments):
Code: |
...
#define LOOPCNT3 100 //should be replaced by 12-15 (see after)
...
void Initialize_INT(void)//////////*********************************************
{
setup_timer_1( T1_INTERNAL | T1_DIV_BY_1); //if "T1_DIV_BY_1" is replaced by "T1_DIV_BY_8" it will generate 8 times less interrupts
// It should be still better to use another timer that is able to generate interrupts directly at the expected frequency (for example timer_0)
enable_interrupts(INT_TIMER1);
setup_adc_ports( RA0_RA1_RA3_ANALOG );
setup_adc( ADC_CLOCK_INTERNAL );
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
}
...
void adc_shoulder()
{
if(fl_shoulder==TRUE) // This statement would be better placed in the main() before calling the function
{
set_adc_channel( 0 );
delay_us(10); //this delay is not needed
temp0=read_adc() ; //it should be better to use "read_adc(START_ONLY)" and to use #INT_AD to read the result
temp0=temp0+1;
actual0=((float)temp0/1024)*270; //Can be simplified in "= temp0 * 135 / 512"
itoa(actual0,10,string0); //this lines are complicated
puts(string0); //should be replaced by printf("%Ld",temp0);
fl_shoulder = FALSE;
}
}
void main()
{
init_main();
Initialize_INT();
while(1)
{
adc_shoulder();
if(fl_cen1 == TRUE)
{
output_high(PIN_C0);
strcpy(string0,"h"); //here also very complicated
puts(string0); //should be replaced by putc('h');
fl_cen1 = FALSE;
}
else
output_low(PIN_C0);
}
}
...
|
Matro |
|
|
RLScott
Joined: 10 Jul 2007 Posts: 465
|
|
Posted: Fri Apr 25, 2008 6:47 am |
|
|
soong2020 wrote: | RLScott wrote: |
Did you try the test I suggested above, sending a single 'q' from the PC and nothing more, to see if the PIC can receive just one command?
Robert Scott
Real-Time Specialties |
Yeah i have done the following and it is working fine too...
|
That is not what I suggested. You were complaining that your full PIC program was unable to both send and receive serial data at the same time. So I suggested using your full PIC program, but changing only what comes from the PC so that only one 'q' command is sent. This would remove receiving timing from the picture.
Robert Scott
Real-Time Specialties |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Apr 25, 2008 8:10 am |
|
|
Quote: | My compiler version is 4.017. | This is a highly unstable compiler version. The v4.0xx compilers became more or less usable at release v4.030. Using any older v4 release is going to give problems sooner or later and as such is a waste of time (yours and ours). At the time you bought your compiler there was also the stable v3.249 available for download, please use that version or do an upgrade. |
|
|
soong2020
Joined: 13 Feb 2008 Posts: 25
|
|
Posted: Fri Apr 25, 2008 8:20 am |
|
|
RLScott wrote: |
That is not what I suggested. You were complaining that your full PIC program was unable to both send and receive serial data at the same time. So I suggested using your full PIC program, but changing only what comes from the PC so that only one 'q' command is sent. This would remove receiving timing from the picture.
Robert Scott
Real-Time Specialties |
Hi Scott, I have tried removing the other char inputs except for one and it still behaves the same. Still I'm getting values displayed on PC but can't send in command from PC.
What could the problem be? I have improvised my code as suggested by Matro by the way and it is still the same. |
|
|
RLScott
Joined: 10 Jul 2007 Posts: 465
|
|
Posted: Fri Apr 25, 2008 11:08 am |
|
|
soong2020 wrote: |
Hi Scott, I have tried removing the other char inputs except for one and it still behaves the same. Still I'm getting values displayed on PC but can't send in command from PC. |
OK, so you have a failure when sending a single character from the PC. The next step is to find out where that failure is taking place. Here is how you do it:
1. Add code to serial_isr so that an unused output is toggled every time you enter serial_isr. Watch that output on a scope to see if that output toggles when the PC sends the 'q' character.
2. Assuming the previous step went OK, next change serial_isr so that the unused output is toggled only if the received character is a 'q'. Put the code after case 'q': Then see if that output is toggled when the PC sends a 'q'.
3. Assuming the previous step went OK, then we know that fl_right1 must be getting set. So now see if fl_right1 is getting recognized by btn1_check(). Add code to bn1_check() so that it toggles an unused output every time it detects fl_right1 == TRUE. See if that output toggles when the PC sends a 'q'.
4. Assuming the previous step went OK, then I have to ask why you think the PIC is not receiving commands from the PC? Your answer will determine where to go from here.
Robert Scott
Real-Time Specialties |
|
|
|
|
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
|