View previous topic :: View next topic |
Author |
Message |
wordizlife
Joined: 08 Mar 2012 Posts: 38 Location: Canada
|
ex_sisr sample code problem |
Posted: Thu Apr 19, 2012 5:19 pm |
|
|
Hey guys,
I am using the CCS ex_sisr example file as a model to receive serial data through my RX port and display it on an LCD.
My code works fine and the data is displayed as expected on the LCD.
My problem is that my program seems to freeze as soon as the data is received and displayed on the LCD, it will not continue through to the next function.
How would I have to modify my function to exit the do loop once the data has been received?
Here is my main function:
Code: |
void main()
{
enable_interrupts(int_rda);
#if defined(__PCD__)
enable_interrupts(intr_global);
#else
enable_interrupts(global);
#endif
LCD_init(); // Initialize LCD
lcd_putc("\f*****\n");
lcd_putc("Project 2 - 2012");
delay_ms(5000); // wait 5 seconds
/********** Turn ELM327 On **********/
TRISA = 0x00; // Set Pot D as outputs
A5 = 1; // Turns on ELM327
/********** Display ELM Version **********/
lcd_init();
lcd_putc("\fOBD Reader\n");
read_buffer(); // THIS IS WHERE THECODE STAYS STUCK!
delay_ms(2000);
reset_elm();
}
void read_buffer(void)
{
do {
while(bkbhit)
lcd_putc( bgetc() );
}while(1);
}
void reset_elm(void)
{
lcd_init();
delay_ms(1000);
printf("ATZ");
lcd_putc("\fReset OBD\n");
delay_ms(1000);
read_buffer();
}
|
Thanks!
EDIT:
I just realised that the while(1) at the end of the do loop is the end condition. I'm guessing I will have do modify this to have the loop end when I want it to..?
Last edited by wordizlife on Thu Apr 19, 2012 5:28 pm; edited 1 time in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Apr 19, 2012 5:26 pm |
|
|
Quote: | void read_buffer(void)
{
do {
while(bkbhit)
lcd_putc( bgetc() );
}while(1);
} |
How do you propose to exit the do-while loop when you're done ?
Your while(test) at the end is a "forever" loop. And you don't
have any test inside the loop that will execute a "break".
So, you're stuck in it forever. |
|
|
wordizlife
Joined: 08 Mar 2012 Posts: 38 Location: Canada
|
|
Posted: Thu Apr 19, 2012 5:39 pm |
|
|
Ok so I just have to figure out how to write this function so that it stops when all the data has been received.
Question is how am I supposed to know when all the data has been received?
EDIT:
My concern is that all the data might be received but the buffer might not be full, so I cannot set my condition to next_in != next_out... Perhaps some sort of count function would work?
For example:
Code: |
void read_buffer(void)
{
count = 0;
do {
while(bkbhit)
lcd_putc( bgetc() );
count = count++;
}while(count<=32);
}
|
I tested this without any luck...
Here is my full code:
Code: |
/********** Included Files ***********/
#include <main.h>
#include "D:\Winter_2012\Project_2\flex_lcd.c"
/********** Required Registers **********/
#byte TRISA = 0x85
#byte PORTA = 0x05
#byte TRISB = 0x86
#byte PORTB = 0x06
/********** Required Bits **********/
#bit A5 = 0x5.5 // Used to power on ELM323
/********** Declared Functions **********/
void read_buffer(void);
void reset_elm(void);
#int_rda
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);
}
void main()
{
enable_interrupts(int_rda);
#if defined(__PCD__)
enable_interrupts(intr_global);
#else
enable_interrupts(global);
#endif
LCD_init(); // Initialize LCD
lcd_putc("\f*****\n");
lcd_putc("Project 2 - 2012");
delay_ms(5000); // wait 5 seconds
/********** Turn ELM327 On **********/
TRISA = 0x00; // Set Pot D as outputs
A5 = 1; // Turns on ELM327
/********** Display ELM Version **********/
lcd_init();
lcd_putc("\fOBD Reader\n");
read_buffer(); // THIS IS WHERE THECODE STAYS STUCK!
lcd_init();
delay_ms(2000);
reset_elm();
}
void read_buffer(void)
{
do {
while(bkbhit)
lcd_putc( bgetc() );
}while(1);
}
void reset_elm(void)
{
lcd_init();
delay_ms(1000);
printf("ATZ");
lcd_putc("\fReset OBD\n");
delay_ms(1000);
read_buffer();
}
| [/code] |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Apr 19, 2012 7:21 pm |
|
|
Quote: |
Question is how am I supposed to know when all the data has been received? |
If the data is in some specified protocol, then it probably has an
end-of-message marker byte, such as a CR, or maybe CR and LF bytes.
Look for those. But, also add some method of exiting the loop if you
don't receive a full message, so that you don't hang up in the loop
forever. Also have the read_buffer() routine return a status byte,
instead of declaring it as void. If it returns TRUE, then you got a
full message. If it returns FALSE, then it means you timed out in the loop,
while waiting for a message that didn't arrive. |
|
|
wordizlife
Joined: 08 Mar 2012 Posts: 38 Location: Canada
|
|
Posted: Thu Apr 19, 2012 7:45 pm |
|
|
Thanks for mentioning that. I am communicating between two pics. When my main pic receives this ">" (0x3e) it means that the device is in idle state and no more data will be transmitted.
So I modified my function to look like this:
Code: |
void read_buffer(void)
{
int c;
do {
while(bkbhit)
c = bgetc();
lcd_putc( c );
}while(c != 0x3e); //0x3e = >
}
|
Now the problem is the data being displayed is somewhat erratic, it repeats certain characters, for example instead of displaying Patrick, it displays PPPPATTTRRIICCCCKKKKK.
Why would it be doing this?
Should I modify the code to this?:
Code: |
void read_buffer(void)
{
do {
while(bkbhit)
lcd_putc( bgetc() );
}while(bgetc() != 0x3e); //0x3e = >
}
|
At least now it exits the loop correctly |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Apr 19, 2012 7:54 pm |
|
|
Post the main.h code. |
|
|
wordizlife
Joined: 08 Mar 2012 Posts: 38 Location: Canada
|
|
Posted: Thu Apr 19, 2012 9:17 pm |
|
|
Code: |
#if defined(__PCM__)
#include <16F877A.h>
#device adc=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOPROTECT
#use delay(clock=20000000)
#use rs232(baud=38400,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,ERRORS)
#endif
#define BUFFER_SIZE 32
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Apr 19, 2012 9:26 pm |
|
|
As an experiment, add the lines shown in bold below:
Quote: |
void read_buffer(void)
{
int c;
do {
while(bkbhit)
c = bgetc();
disable_interrupts(GLOBAL);
lcd_putc( c );
enable_interrupts(GLOBAL);
}while(c != 0x3e); //0x3e = >
} |
|
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Fri Apr 20, 2012 2:27 am |
|
|
It's possible the problem occurs whilst you're getting the next character, (the int routine and bgetc() both trying to manipulate next_in and next_out at the same time).
Try this variation on PCM's code.
Quote: |
void read_buffer(void)
{
int c;
do {
while(bkbhit)
disable_interrupts(GLOBAL);
c = bgetc();
enable_interrupts(GLOBAL);
lcd_putc( c );
}while(c != 0x3e); //0x3e = >
}
|
Mike |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1354
|
|
Posted: Fri Apr 20, 2012 6:49 am |
|
|
I was looking at that, but can't see a conflict. The ISR only changes next_in and can't be interrupted, so looking at bgetc(), it only affects next_out, and it does so in a single instruction, which should be atomic? Can interrupts stop a BYTE MOV instruction or does it finish the instruction and then jump? The "while(!bkbhit)" should be ok too since the ISR won't take values out of the buffer.
What part is weak to synchronization? I know I must be missing something simple. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Fri Apr 20, 2012 7:53 am |
|
|
Code: |
void read_buffer(void)
{
int c;
do {
while(bkbhit)
c = bgetc(); //This is the line that gets executed while 'bkbhit'....
lcd_putc( c );
}while(c != 0x3e); //0x3e = > //Keeps looping and redisplaying....
}
|
Code: |
void read_buffer(void) {
int tempc;
do {
if (bkbhit) {
c=bgetc();
lcd_putc(c);
if (c==0x3E)
return;
}
} while (TRUE);
}
|
This now loops, until a character is available.
When it is, it reads it, displays it, and then tests if it is the end of message marker. If so, it exits.
Best Wishes |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Fri Apr 20, 2012 8:02 am |
|
|
You're getting regular problems with the repeat characters.
That suggests that you've got a conflict during something which takes a fair time to execute.
For that reason it's the timing which make me dubious about your problem being in the bgetc() routine.
So little time is spent there, that there's little opportunity for a clash.
PCM's suggestion of the problem being with the lcd_putc() offers a much bigger time window for a clash to occur.
Mike |
|
|
wordizlife
Joined: 08 Mar 2012 Posts: 38 Location: Canada
|
|
Posted: Fri Apr 20, 2012 4:16 pm |
|
|
Ttelmah that configuration worked like a charm!
I can't thank you guys enough, you guys are great help!
Would anyone be aware if CCS also provides example files to send data through the TX pin of a PIC16F877A?
I am not sure if this is correct or not but I tried this:
I modified my read_buffer() function to return the tempc value so it can be used by other functions. I am not sure if this is correct or not. I also changed tempc to a global variable.
Code: |
read_buffer(void) {
do {
if (bkbhit) {
tempc=bgetc();
lcd_putc(tempc);
if (tempc==0x3E)
return tempc;
}
} while (TRUE);
}
|
I tried two different way's without any luck to send data through the TX pin:
Code: |
void reset_elm(void)
{
lcd_init();
delay_ms(500);
putc(0x41);//A
putc(0x54);//T
putc(0x5a);//Z
delay_ms(500);
lcd_putc("\fElm Reset\n");
if (tempc==0x3E);
read_buffer();
} |
Code: |
void reset_elm(void)
{
lcd_init();
delay_ms(500);
printf("ATZ")
delay_ms(500);
lcd_putc("\fElm Reset\n");
if (tempc==0x3E);
read_buffer();
} |
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Fri Apr 20, 2012 6:45 pm |
|
|
oopsy...
if (tempc==0x3E);
read_buffer();
...think you do NOT want the semicolon at the end of the if(tempc..line |
|
|
wordizlife
Joined: 08 Mar 2012 Posts: 38 Location: Canada
|
|
Posted: Sat Apr 21, 2012 9:52 am |
|
|
That was a stupid mistake... But even if I fix it I am getting no life from the TX pin.
I must be missing something simple here..?
Would I possibly have to set the TRIS to have TX as output and RX as input or is this done automatically with the #use RS232 ? |
|
|
|