View previous topic :: View next topic |
Author |
Message |
BOB_SANTANA
Joined: 16 Oct 2006 Posts: 110 Location: HOVE, EAST SUSSEX
|
rs232 missed characters |
Posted: Mon Dec 04, 2006 11:03 am |
|
|
Hello Everyone
I have being pulling my hair (Whats left of it for 2 days now) trying to fine the problem with my program.
All i am trying to do is to use my pc to control 16 relays connected to my pic.
The address of my Pic is AD1 then the next 4 characters form a 16bits
number that i then convert to hex then binary before it outputed to my relays
those seems to got ok but its the communition part that plays up some time
The pic receives the messages ok but sometimes WHEN I TYPE A MESSAGE ON HYPERTHERM it justs sits there until i type the same message again.
the fomats of my messages are AD1FFFF , AD1F023
sometimes 4 times before it decides to work.
i thinks its something to do with the buffer ,but my c is still in baby stage
Here is my code below
Code: |
#if defined(__PCM__)
#include <16F877.h>
#ORG 0x1F00,0x1FFF {} // use boot loader for the 8k 16F877
#fuses XT,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,ERRORS) // Jumpers: 8 to 11, 7 to 1
#include <LCD_File.c>
///////////////////////////////////////////////
// We want to be able to write a byte value to the following spare pins.
// RA0,RA1,RA2,RA3,RD0,RD1,RD2,RD3
#byte PortA = 0x05 // For 16F877
#byte PortB = 0x06 // For 16F877
#byte PortD = 0x08 // For 16F877
#bit RD4 = 8.4//LSB
#bit RD5 = 8.5
#bit RD6 = 8.6
#bit RD7 = 8.7
#bit RA3 = 5.3
#bit RA2 = 5.2
#bit RA1 = 5.1
#bit RA0 = 5.0
#bit RB0 = 6.0
#bit RB1 = 6.1
#bit RB2 = 6.2
#bit RB3 = 6.3
#bit RB4 = 6.4
#bit RB5 = 6.5
#bit RB6 = 6.6
#bit RB7 = 6.7 //MSB
// The following macro defines the "setPorts()" function.
// This will be implemented by the compiler as 16 sequential
// BSF or BCF instructions.
#define SetPorts(x) \
RD4 = x & 1; \
RD5 = (x >> 1) & 1; \
RD6 = (x >> 2) & 1; \
RD7 = (x >> 3) & 1; \
RA3 = (x >> 4) & 1; \
RA2 = (x >> 5) & 1; \
RA1 = (x >> 6) & 1; \
RA0 = (x >> 7) & 1; \
RB0 = (x >> 8) & 1; \
RB1 = (x >> 9) & 1; \
RB2 = (x >> 10) & 1; \
RB3 = (x >> 11) & 1; \
RB4 = (x >> 12) & 1; \
RB5 = (x >> 13) & 1; \
RB6 = (x >> 14) & 1; \
RB7 = (x >> 15) & 1;\
///////////////////////////////////////////////
///////////////////////////////////////////////
#define BUFFER_SIZE 32
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;
BYTE Flag = 0;
char data[8];
int Rxdata[4];
/// This Function loads the Received Characters to the Circular buffer //
#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)
#define pointer (next_out-8)
/* Defines */
#define LENGTH_OF_SHORT 16u
/////////////////////////////////////////////////////////////////////////
/// This Function gets the Received Characters from buffer //
/// Its pointer to the received chars is Next_Out
/////////////////////////////////////////////////////////////////////////
BYTE bgetc()
{
BYTE c;
while(!bkbhit) ;
c=buffer[next_out];
next_out=(next_out+1) % BUFFER_SIZE;
flag = 1;
return(c);
}
/////////////////////////////////////////////////////////////////////////
BYTE MyFunction()
{ BYTE r=0;
int i;
int j=0;
for (i=pointer ;i<next_out;i++) // pointer has-8 offset to pointer
{
data[j]=buffer[i]; // copy from buffer the data array
j++;
}
if (data[0]=='A')
{ r++;
if (data[1]=='D')
r++;
if (data[2]=='1')
r++;
}
if ((data[0]=='A')&& (data[1]=='D')&& (data[2]=='1')&& (r==3)&&(data[7]==13))
{
r=100;
flag = 0; // Clear flag
return (r); // tell main data is ok
}
else
{
r++;
return (r);
}
}
///////////////////////////////////////////////////////
/// This Function checks the 4 character locations Data[3]to Data[6]
/// Has the values 0 - F
int CheckData ()
{
int i,Checker,Result;
Result = 0;
for (i=3; i<7; i++)
{
Checker = Data[i];
if (( Checker >=48 && Checker <= 57 )||( Checker >=65 && Checker <= 70 ))
{
Result++;
}
else
{
Result--;
}
}
return(Result);
}
///////////////////////////////////////////////////////
// This converts the ascii to hex
int ConvertData(int Rxd )
{
if((Rxd>=48)&&(Rxd<= 57 ))
{
Rxd=Rxd-48;
}
else
if((Rxd>=65) &&(Rxd<= 70 ))
{
Rxd=Rxd-55;
}
return (Rxd);
}
///////////////////////////////////////////////////////
/// coverts the final value to binary 16bits
void PrintAsBinary ( int16 value )
{ char display[16];
int i;
int binaryValue;
for ( i = 0; i < LENGTH_OF_SHORT; i++ )
{
/* Check MSB against 1 */
if ( 0x8000 == ( value & 0x8000 ) )
{
binaryValue = 1;
display[i]='1';
}
else
{
binaryValue = 0;
display[i]='x';
}
/* Print the binary value */
lcd_gotoxy(5+i, 2); // Go to end of first line.
printf(lcd_putc,"%c",display[i] );
/* Shift next bit into mask position */
value = value << 1;
}
}
///////////////////////////////////////////////////////////
void main()
{
int16 updateLcd;
int8 test,counter,D,i,result[4];
set_tris_a(0b00000000);
set_tris_b(0b00000000);
set_tris_d(0b00000000);
setup_adc_ports(NO_ANALOGS);
enable_interrupts(global);
enable_interrupts(int_rda);
lcd_init();
printf(lcd_putc, "\f"); // Clear the LCD.
delay_ms(500);
//Display 1st Default Startup Lcd Message
//-----------------------------------------
printf(lcd_putc, "\f Start Up Test "); // Clear Screen & Write To Line 1.
printf(lcd_putc, "\n 16 Port HV Switch"); // Write to "Line 2.
delay_ms(3000);
lcd_gotoxy(20, 2); // Go to End of 2nd Line
for(i = 0; i < 20; i++) // Backspace over 2nd line.
{
printf(lcd_putc," \b\b");
delay_ms(150);
}
lcd_gotoxy(20, 1); // Go to end of first line.
for(i = 0; i < 20; i++) // Backspace over first line.
{
printf(lcd_putc," \b\b");
delay_ms(150);
}
//Display 2nd Default Startup Lcd Message
//----------------------------------------
printf(lcd_putc, "\fPT: 0123456789ABCDEF"); // Clear Screen & Write To Line 1.
printf(lcd_putc, "\nAD1:0000000000000000"); // Write to "Line 2.
delay_ms(1000); // 1 Seconds Delay in mSeconds
do {
delay_ms(5000);
while(bkbhit)
{
bgetc();
if (flag !=0)
{
test = myFunction();
}
if (test==100) // test for valid for valid Address
{
D = CheckData (); // test for valid for valid Data Range 0- F
if ( D ==4)
{
counter=0;
lcd_gotoxy(20, 2); // Go to 2nd digit of 2nd line.
for(i = 1; i < 20; i++) // Backspace over 2nd line.
{
printf(lcd_putc," \b\b"); // clears msg on line 2
delay_ms(5);
}
printf(lcd_putc,"AD1:"); //new msg on line 2
for(counter=3;counter < 7;counter++)
{
lcd_gotoxy(6+counter, 2);
printf(lcd_putc,"%c",data[counter] );
/////////////////////////////////////////////////////////////////////////////////////////////////////
/// copy positions data[3]-data[6]
Rxdata[0]=data[3];
Rxdata[1]=data[4];
Rxdata[2]=data[5];
Rxdata[3]=data[6];
for (i = 0; i < 4; i++)
{ // Converts ASCII Range 0-F
result[i] = ConvertData(Rxdata[i]);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
updateLcd = ((int16)result[0]<<12) + ((int16)result[1]<<8) + (result[2]<<4) + (result[3]);
SetPorts(updateLcd); // Sets 16 Bits output port
PrintAsBinary (updateLcd); //Update LCD Display with binary value
test=false; // reset data test
}
printf("\r\nOk\n "); // Ack for saved msg
}
else
{
printf("\r\nAddr or Data Error\n ");
test=false;
}
}
}
D=0;
} while (TRUE);
}
|
Regards _________________ BOB_Santana
Last edited by BOB_SANTANA on Tue Dec 05, 2006 3:46 am; edited 3 times in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Dec 04, 2006 11:12 am |
|
|
You have to disable HTML when posting code. It's essential.
Look at this line in your post. It's messed up:
Quote: | for (i=3; i<7>=48 && Checker <57>=65 && Checker <70>=48)&&(Rxd<57>=65) &&(Rxd<= 70 )) |
Please EDIT your post, delete the existing code and paste in a fresh
copy of the code. And then, this time, select the box below the posting
window to disable HTML. It looks like this:
Quote: | x Disable HTML in this post |
|
|
|
BOB_SANTANA
Joined: 16 Oct 2006 Posts: 110 Location: HOVE, EAST SUSSEX
|
|
Posted: Tue Dec 05, 2006 3:47 am |
|
|
Thanks PCM Pro
I have just managed to edit the post
i know now next time
Best Regards _________________ BOB_Santana |
|
|
Ttelmah Guest
|
|
Posted: Tue Dec 05, 2006 5:29 am |
|
|
The code you have posted, is so complex, that I haven't bothered to try to understand it!.
However let me suggest a totally different way of doing this type of scan on data:
Code: |
#define hextoval(x) (x<='9')?(x-'0'):((toupper(x)-'A')+10)
int16 find_message(void) {
int8 state=0;
int16 ctr=20000;
int8 chr;
int16 val=0;
int16 dig=0;
while (true) {
while (!bkbhit) {
//timeout if a command is not completed in perhaps 10 seconds
if (--ctr)==0)) return 0;
delay_ms(5);
}
//Here I have a character
chr=bgetc();
switch (state) {
case 0:
if (chr=='A') {
//legitimate first char
state=1;
//Reset timeout
ctr=20000;
}
//go back to waiting
break;
case 1:
if (chr=='D') {
//legitimate second char
state=2;
//Reset timeout
ctr=20000;
}
//Otherwise start looking for the first character again
else if (chr!='A') state=0;
//go back to waiting
break;
case 2:
if (chr=='1') {
//legitimate third char
state=3;
//Reset timeout
ctr=20000;
}
//Otherwise start looking for the first character again
else if (chr!='A') state=0;
else state=1;
//go back to waiting
break;
case 3:
//Now you have seen 'AD1'
//Decode the digits
val=(val*16)+hextoval(x);
if (++dig >=4) return val;
break;
}
}
}
|
Now this is completely untested, but shows how to use a 'state machine', to walk through the arriving characters. It doesn't test everything (it should test that the digits are legitimate), but also shows how to implement a crude 'timeout', if there is a long gap in the incoming data (which would reflect a possible error). It does handle certain types of data error (so for instance, AAD1FFFF will be correctly handled). It returns '0' in the event of a timeout.
I'd suspect your problem, is actually quite simple. My 'guess' would be that you are not handling the extra characters present in the hyperterminal output it will normally send both line feed, and carriage return for an 'enter'), so the code gets out of sync from the incoming data.
Best Wishes |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Dec 05, 2006 5:40 am |
|
|
You said you're missing commands that are typed in. Your main loop
has got large delays in it. There's one delay of 5 seconds and there
are other delays in for(;;) loops. While those delays are executing,
the PIC can't check the buffer to see if chars are available. I don't
know if the delays are really the problem, because the code is
formatted so poorly that it's just too painful to read it.
I noticed that you took some of the demo code from the 20x4 LCD
driver that I posted in the Code Library. You're using it to clear
lines. It was never intended for that purpose. You're using code
that was intended to demonstrate the Backspace command. It runs
slowly, on purpose, so the user can see that the demo is working.
If you want to clear a line, use the lcd_gotoxy() function to set the
cursor to the start of a line, and then just printf 20 spaces to it
(using the redirection feature to send it to lcd_putc ).
Or do a for(;;) loop and send 20 spaces to it that way. But get
rid of that demo code. |
|
|
BOB_SANTANA
Joined: 16 Oct 2006 Posts: 110 Location: HOVE, EAST SUSSEX
|
|
Posted: Tue Dec 05, 2006 7:13 am |
|
|
Thanks guys
I am taking this all on board and learning the hard way
which is good for me.
I did removed the delays before posting and it didn't make much difference .
As for the formatting i would only learn as i go and with all your help
i would also try everything that you suggested
Thanks for All Your Help _________________ BOB_Santana |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Tue Dec 05, 2006 9:25 am |
|
|
Does your serial data come in "word" and then a little idle time. If so I would
say you should try an irq reception read into a buffer. set a timmer when start rx of serial(reset it on every char rx)
then when timer is 0 you are in the idle time.
Then check the data in the buffer.
This allows you to do other things without missing a RX char.
If you describe a little about how your project works, people will try to help you make programming decisions, and why, and still at your
learning curve level. |
|
|
BOB_SANTANA
Joined: 16 Oct 2006 Posts: 110 Location: HOVE, EAST SUSSEX
|
|
Posted: Tue Dec 05, 2006 10:19 am |
|
|
treitmey
Sorry for not describing the project in details and ( of cause the programming layout)
All i am trying to do is capture 7 characters example AD1FFFF using the
the serial interupt (int_rda).
the first 3 characters is the address of my Pic (Like a header) while the
next 4 characters are converter from ascii to hex limiting if to the range
0000 - FFFF .
Anything out of that range would be and error.
i then use the accepted range and send it to the out output of my pic
which is made up as follows
(This is an old piece of harware so i cant change it .if it were a new design i would have used 2 shift regs)
RB7 = MSB
RB6
RB5
RB4
RB3
RB2
RB1
RB0
RA0
RA1
RA2
RA3
RD0
RD1
RD2
RD3 = LSB
The rest of the time the pic is just running in a loop until the outputs need to be update through the pc
Its a simple project but its me that make it dificult
Regards _________________ BOB_Santana |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Tue Dec 05, 2006 10:42 am |
|
|
Is there idle time after the 7 char but before the next 7??
a few ms would do. |
|
|
BOB_SANTANA
Joined: 16 Oct 2006 Posts: 110 Location: HOVE, EAST SUSSEX
|
|
Posted: Tue Dec 05, 2006 1:06 pm |
|
|
yes i suppose
i am typing in on hyperterm and i also created text files with some different combination and send it to my pic as text file via hypertem
Now just to ask and please don't take it the wrong way i just want your professional opinion
When using the curly brackets with C which way is better
Code: |
Type A Type B
if (condition) { if (condition)
do this; {
} do this;
}
|
_________________ BOB_Santana |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Tue Dec 05, 2006 1:13 pm |
|
|
I flip/flop. Right now I use option A. I like to see as much code as possible.
and I've gotten use to it
But... I've also done option B as it lines up the curlies nice and its the way c# does it by default.
I'd say do it the way ttelma or pcm programmer does it. : ) |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Dec 05, 2006 1:15 pm |
|
|
The complaints about formatting are not really about the braces.
It's about your indentation. Look at your code above. There's a
section where almost every line is indented more than the previous line.
It makes the code hard to read. |
|
|
BOB_SANTANA
Joined: 16 Oct 2006 Posts: 110 Location: HOVE, EAST SUSSEX
|
|
Posted: Tue Dec 05, 2006 3:26 pm |
|
|
Thats Ok
Its back to the drawing board for me.
I have to get it right and i am in the right company
learning from you guys
Thank you for being honest no matter what, it can only help me.
Best Regards _________________ BOB_Santana |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
|
davekelly
Joined: 04 Oct 2006 Posts: 53 Location: Berkshire, England
|
|
Posted: Wed Dec 06, 2006 1:56 am |
|
|
For the formatting problem, get yourself a decent code editor.
The one I use for the CCS code is Notepad++ http://notepad-plus.sourceforge.net/uk/site.htm
This has a plugin (automatically installed) which can reformat your code (Plugins, TextFx Edit, Reindent C++ code). |
|
|
|