Jump to content

Rs232 Receive From Hyperterminal --- Need Some Help


Recommended Posts

This is my first project dealing with serial communications of the PIC. I have not looked into the functions provided with Sourceboost, as I really want to understand more of the details.

 

I have my PIC16F913 connected to a MAX232 and to a 16x4 parallel LCD display. I do not care about sending data for now, this project purely receives data only.

 

This project is just for me to learn the UART. After I get this down I plan to use this on another project that I have going.

 

One problem that I have is the lack of an oscilloscope, so I cannot determine if my baud rate is 9600 like I have it programmed. I am using the internal oscillator for now.

 

I believe my problem exists in my interrupt handler when I try and buffer the data as it is coming in. If I only send one command from hyperterminal and I don't try to use my char array for the buffer, I can display the character perfect. Works every time. This makes me think that my hardware and baud are correct. The problem comes when I try and store the incoming data into my array and then read out of the array while writing to the LCD. I get the first 2 characters of my string to display correctly, but then the rest of the screen if filled with random junk. I initialize the array to all 0's so that is what I look for to end my print function.

 

Please check out the code below and tell me what you think.

 

#include <system.h>
#include "rx_test_initialize.h"
#include "rx_test_LCD.h"
#pragma CLOCK_FREQ 8000000;

void UART_Initialize(void);

#pragma DATA 0x2007, 0x30E4

unsigned char rx_buffer[33] = {0};
unsigned char *array_ptr;
unsigned char i = 0;
unsigned char error = 0;
unsigned char data_in, single_print;
bit message_received = 0;
bit STX_received = 0;
bit interrupt_flag = 0;

/*****************INTERRUPT HANDLER*****************
*******THIS INTERRUPT WILL STORE THE DATA FROM******
********THE UART RECEIVE BUFFER INTO AN ARRAY******/

void interrupt(void)
{
//unsigned char data_in;

pir1 &= 0xDF;//clear uart receive flag
data_in = rcreg;//save the data from uart buffer	 

if(STX_received)//if start bit has been received
{
	if(data_in == 0x0D)//if data is carriage return (ASCII)
	{
		STX_received = 0;//reset for next start bit
		message_received = 1;//message is ready to process in main()
	}
	else
	{
		if(array_ptr == 34)//data is about to overflow buffer
			error = 1;//error 1 occurs
		else
		{
			single_print = data_in;//FOR TESTING!!
			*array_ptr = data_in;//store data in buffer
			array_ptr++;//increment pointer				
		}
	}
}
else
{
	if(data_in == 0x02 && !message_received)//0x02 is ASCII STX (start bit)
	{
		STX_received = 1;//start bit has been received, now collect data
		array_ptr = &rx_buffer[0];//reset pointer to beginning of buffer					 
	}
}
}
//----------------------------------------------------------------------


void main()
{
initiate();//call initialization function
LCD_Initialize();//initialize the LCD	

char start_up[] = "POWERING UP...";	
char waiting[] = "WAITING...	";		

print_char(start_up);	
delay_s(1);	

UART_Initialize();

print_char(waiting);											  

while(1)
{		
	if(message_received)
	{		   	
	   //print_char(rx_buffer);//THIS WON'T WORK!!!
	   print_1char(single_print);//THIS WORKS GREAT!!!		   
	   message_received = 0;
	}				  
}	
}

void UART_Initialize()
{
txsta = 0;
spbrg = 0x0C;//9600 baud rate @ 8MHz
//spbrg = 0x19;//2400 baud rate @ 4MHz	
rcsta = 0x90;
intcon |= 0xC0;	
pir1.RCIF = 0;
pie1 = 0x20;
}

Edited by jwilson
Link to post
Share on other sites

My code for LCD operations and code for initializing the PIC hardware...

 

#include <stdio.h>

//--------latch the LCD instuction--------
void LCD_instruct()
{
porta |= 0x40;//sets E high
porta &= 0x7F;//sets RS low
delay_ms(1);//latch the instruction
porta &= 0x3F;//sets E and RS low
delay_ms(1);	
return;
}

//-------write character to the LCD-------
void LCD_write()
{
porta |= 0xC0;//sets E and RS high
delay_ms(1);//latch the character
porta &= 0x3F;//sets E and RS low
delay_ms(1);	
return;
}

//-------Function to initialize the LCD--------
void LCD_Initialize()
{
delay_ms(20);//20ms delay for power on

portb = 0x38;//function set
LCD_instruct();	
delay_ms(5);	
portb = 0x38;//function set
LCD_instruct();	

portb = 0x38;//function set
LCD_instruct();

portb = 0x38;//function set (length, lines & font)
LCD_instruct();

portb = 0x08;//display off	
LCD_instruct();

portb = 0x01;//clear display
LCD_instruct();

portb = 0x06;//entry mode set (cursor direction)
LCD_instruct();	

portb = 0x0C;//display on, cursor off, blink off
LCD_instruct();
return;
}

//---------Prints unsigned char to LCD---------
void print_char(unsigned char char_2_print[])
{
int j=0;

portb = 0x80;//place cursor on the 1st row
LCD_instruct();	

for(j=0; char_2_print[j]!=0; j++)
{
	portb = char_2_print[j];
	LCD_write();
}
return;
}

//---------Prints unsigned char to LCD---------
void print_1char(unsigned char char_2_print)
{		
portb = 0x80;//place cursor on the 1st row
LCD_instruct();	

portb = char_2_print;
LCD_write();

return;
}

 

//----------------INITIATE-------------------
void initiate(void)
{
option_reg = 0x00;	// bit 7=0 enable pullups
					// bit 6-0=000000 don't care

cmcon0 |= 0x07;		//turn comparators off
lcdcon = 0x40; 		//turn off all LCD functions


osccon = 0x71; 		//bit 7=0 unimplemented (read as '0')
					//bits 6-4=111 Fosc = 8MHz
					//bit 3=0 status bit (don't care)
					//bit 2=0 status bit (don't care)
					//bit 1=0 stable bit (don't care)
					//bit 0=1 internal oscillator used for system clock																	


ansel = 0x00;		  //porta bits all set as digital I/O's	
wpub = 0xFF;		//enable all pullups on portb
iocb = 0x00;		//disable interrupt on change for portb		

trisa = 0x00;		  //bit 7 = output - LCD RS
					//bit 6 = output - LCD E
					//bit 5-0 = output - not used							

trisc = 0x80;		  //bit 7 = input - used for RX
					//bit 6-0 = output - not used						

trisb = 0x00;		  //bit 7 = output - LCD D7
					//bit 6 = output - LCD D6
					//bit 5 = output - LCD D5
					//bit 4 = output - LCD D4
					//bit 3 = output - LCD D3
					//bit 2 = output - LCD D2
					//bit 1 = output - LCD D1
					//bit 0 = output - LCD D0						

portb = 0x00;		  //outputs initially low
portc = 0x00;		//outputs initially low	
}

Edited by jwilson
Link to post
Share on other sites

I have made a couple of tweaks to your interrupt routine.

 

void interrupt(void)
{
//unsigned char data_in;

pir1.RCIF = 0;					//clear uart receive flag
data_in = rcreg;				//save the data from uart buffer	 

if (STX_received)				//if start bit has been received
{
	if (data_in == '\r')			//if data is carriage return (ASCII)
	{
		STX_received = 0;		//reset for next start bit
		message_received = 1;	//message is ready to process in main()
	}
	else
	{
//			if(array_ptr == 34)	//data is about to overflow buffer
		if (array_ptr == rx_buffer + sizeof(rx_buffer))	//data is about to overflow buffer
			error = 1;			//error 1 occurs
		else
		{
			single_print = data_in;//FOR TESTING!!
			*array_ptr = data_in;//store data in buffer
			array_ptr++;		//increment pointer				
		}
	}
}
else
{
	if (data_in == 0x02 && !message_received)//0x02 is ASCII STX (start bit)
	{
		STX_received = 1;		//start bit has been received, now collect data
		array_ptr = rx_buffer;	//reset pointer to beginning of buffer					 
	}
}
}

 

Cheers

 

Reynard

Link to post
Share on other sites

Okay I just tested that and it most definitely helped things. I can understand now why also...thank you for catching that for me.

 

I still have the issue of my print statement not stopping at the end of the string. Do you mind checking that section out? Maybe you can suggest something other than checking for 0.

Link to post
Share on other sites

Can't say if this will cure your problem. Your end of buffer check was certainly not correct.

 

I would probably store a NULL in the buffer upon receiving the CR that was you know how many characters you have received by using strlen(), assuming you are not sending any NULLs that is.

 

Cheers

 

Reynard

Link to post
Share on other sites
Can't say if this will cure your problem. Your end of buffer check was certainly not correct.

 

I would probably store a NULL in the buffer upon receiving the CR that was you know how many characters you have received by using strlen(), assuming you are not sending any NULLs that is.

Great idea. I will do that now.

 

Man I love Sourceboost and this forum. You guys are so helpful.

 

Thanks yet again

Edited by jwilson
Link to post
Share on other sites

Try passing a pointer to the string array rather than the array itself.

 

 

	print_char("Hello World");
...
//---------Prints unsigned char to LCD---------
void print_char(unsigned char *char_2_print)
{
unsigned char j;

portb = 0x80;//place cursor on the 1st row
LCD_instruct();	

while ((j = *char_2_print++) != '\0')
{
	portb = j;
	LCD_write();
}
}

 

You could pass the char straight to portb instead of using j.

 

Cheers

 

Reynard

 

ps. We have 20 ounce pints over here so will cost you more.

Edited by Reynard
Link to post
Share on other sites

Evil HyperTerminal bugs:

 

Win 2K & XP: Freezes if the cursor blink is turned off.

HyperTerminal has a built in bug where the -1 setting (no blink) makes it think that it needs to constantly redraw the cursor (caret) in its message processing loop.

Workaround: Dont EVER turn of cursor blink in Terminal Setup. If you have done so, restart and create a new session file.

 

All: Incorrectly initializes serial port

If the same character is received 3 times consecutively at session startup, Hyperterminal can display garbage and will not recover till exited and restarted. Once it's past the first 3 characters continuous repeats are displayed correctly.

A PIC with a simplistic RS232 test program that just sends 'A' in a loop will trigger this bug - I've been there and wasted a day!

Workaround: Modify your PIC code to send a short 'sign-on' message without repeated characters before sending anything else.

 

All: Handshake:none may fail to transmit

On some PCs it has been known to fail to transmit with handshaking set to none.

Workaround: If building a 3 wire cable loop DTR and DSR and also RTS and CTS at the 9 pin plug. If all signals are available to your project board either implement handshaking or at least provide appropriate levels on the handshake lines.

 

All: Autodetect is buggy

Terminal Autodetect can detect an inappropriate terminal type, resulting in a mixed up screen.

Workaround: Set terminal type manually.

 

I have my suspicions that some settings changes may not 'take' unless you quit and restart the session or possibly the whole application.

 

There are also known to be bugs in its file transfer protocols, especially its Xmodem and Zmodem implementations.

Link to post
Share on other sites

I attempted to run this code on the device that I plan to talk to in the main design. This device is a weight indicator, it sends continuous streams (every 1 second) of data. I connected my computer to this indicator and I could view the data perfectly. This is a sample of the data that hyperterminal displayed (what does the smiley face mean?).

 

232screenshot.jpg

 

 

When I connected my breadboard instead of my computer it would not work.

 

I wrote the above code in order to obtain the data from the indicator. The data stream format for the indicator is:

 

stream_format.jpg

 

So the first character that is send should be the STX command, just like I have in my code and just like I have emulated. The last should be the CR command which also is just like I have emulated.

 

Can someone explain what might be going on? I am using the internal oscillator, is there a chance that while connected to a computer the baud is okay but connected to this weight scale the baud is not okay? I don't have an oscope so I can't check how bad off I may be. I plan to use a crystal in the final project, but I don't have one to test at the moment.

 

BTW this weight indicator is about 40 miles from me. I will not be able to try anything else until next weekend. I do plan to work on it during my free time this week so I can hopefully have something working when I go there next.

 

I forgot my project files or I would have tried to troubleshoot a little better.

Link to post
Share on other sites

Can I make a suggestion?

 

When dealing with serial communications over RS232/RS485, etc, I have found it far better to use some program other than Hyperterminal.

 

When using something like Advanced Serial Port Terminal, etc., you can see the actual hex values received (as well as ASCII characters)

and more easily debug funny serial UART problems.

 

Also you can send whole messages or files via the TX output.

Link to post
Share on other sites
Can I make a suggestion?

 

When dealing with serial communications over RS232/RS485, etc, I have found it far better to use some program other than Hyperterminal.

 

When using something like Advanced Serial Port Terminal, etc., you can see the actual hex values received (as well as ASCII characters)

and more easily debug funny serial UART problems.

 

Also you can send whole messages or files via the TX output.

Thank you for the tip. Seeing the values will be much nicer than what hyperterminal provides. I downloaded the program, looks to have a 14 day trial and then it is $40. That will give me enough time to see how much I like it.

Link to post
Share on other sites
Can someone verify or not whether the internal oscillator could make my baud rate work while connected to a PC but not to another embedded device?

 

I don't believe it could change, IF YOU KEEP TEMPERATURE AND SUPPLY VOLTAGE FAIRLY CONSTANT but the other device may itself be out of tolerance.

 

Verify your baud rate *WITHOUT* a scope by setting up your port for 8,N,1 operation and writing a tight loop to output 0xF0 continuously with interrupts disabled, polling to see if another byte will fit in the TX buffer. This gives a square wave at exactly baud_rate/10 which can be easily verified with a DFM to 0.01% accuracy or a frequency equipped DMM to 1%. In your case you are looking for 960 Hz which would be a good indicator your RX will be correct.

 

With the possibility of an 'off spec' device at the other end of the cable, I'd add a diagnostics mode that is activated by a pin held low at power up, outputs 0xF0 continuously (keep that buffer *FULL*) and displays the raw received data on the LCD with the status on the bottom line.

 

With 40 miles each way to drive, if the PIC supports ADC and OSCTUNE, you may want to add a pot to tune the oscillator in the diagnostics mode till the frequency is correct displaying it on the LCD status line and activating the tune function if you take the diags pin high in diagnostics mode, storing the value when you take it low again. The whole implementation could be a test clip or 4 pin jumper to pick up ground, TX data, a spare port pin and a spare ADC pin, a lowish value pull-up resistor on the port pin (you NEVER want to accidentally enter diags mode) and small box with a couple of test lead sockets, a pot with a nice big knob and a toggle switch to control it.)

 

Remember, as members of our Army say (in public) 'P.P.P.P.P.P' (Perfect Planning Prevents P*ss Poor Performance). What they say in private is likely to cause offence but 'Fu***"£E$R%^&*()(*&^%$£"£$%^&*. . .

<NO CARRIER>

:-)

Link to post
Share on other sites
I don't believe it could change, IF YOU KEEP TEMPERATURE AND SUPPLY VOLTAGE FAIRLY CONSTANT but the other device may itself be out of tolerance.

 

Verify your baud rate *WITHOUT* a scope by setting up your port for 8,N,1 operation and writing a tight loop to output 0xF0 continuously with interrupts disabled, polling to see if another byte will fit in the TX buffer. This gives a square wave at exactly baud_rate/10 which can be easily verified with a DFM to 0.01% accuracy or a frequency equipped DMM to 1%. In your case you are looking for 960 Hz which would be a good indicator your RX will be correct.

 

With the possibility of an 'off spec' device at the other end of the cable, I'd add a diagnostics mode that is activated by a pin held low at power up, outputs 0xF0 continuously (keep that buffer *FULL*) and displays the raw received data on the LCD with the status on the bottom line.

 

With 40 miles each way to drive, if the PIC supports ADC and OSCTUNE, you may want to add a pot to tune the oscillator in the diagnostics mode till the frequency is correct displaying it on the LCD status line and activating the tune function if you take the diags pin high in diagnostics mode, storing the value when you take it low again. The whole implementation could be a test clip or 4 pin jumper to pick up ground, TX data, a spare port pin and a spare ADC pin, a lowish value pull-up resistor on the port pin (you NEVER want to accidentally enter diags mode) and small box with a couple of test lead sockets, a pot with a nice big knob and a toggle switch to control it.)

 

Remember, as members of our Army say (in public) 'P.P.P.P.P.P' (Perfect Planning Prevents P*ss Poor Performance). What they say in private is likely to cause offence but 'Fu***"£E$R%^&*()(*&^%$£"£$%^&*. . .

<NO CARRIER>

:-)

Thank you for the suggestions. I am talking with my work now about taking home an oscope for the weekend.

 

I was curious about the accuracy of the other device also, if it is a little off of 9600 then that could be my problem. I KNOW that I am off up to 5% using the internal oscillator. I have an 11.0592MHz crystal on the way, should be here tomorrow. That will give me precisely 9600 baud. I can at least eliminate that from my troubleshooting.

 

If that doesn't solve my problem, I will try the OSCTUNE method that you explained above. I hope that is doesn't come to that, because it will be custom for each individual microcontroller (won't it?). I would like to make this PCB an easy replacement if something goes wrong.

Link to post
Share on other sites
Have you tried BRGH = 1 which will give you a much smaller error (0.16% at 4MHz).

 

Get a copy of the PIC Baud Rate Calculator from the site above.

 

Cheers

 

Reynard

Well currently I have an error rate of 0.16% at 8MHz. My problem is my 8MHz is not accurate either. Maybe I am wrong but I thought I read where the internal oscillator can be up to 5% off?

Link to post
Share on other sites

The 5% is over the temp range -40 to +85. They are calibrated at 25 and it is unlikely you will be operating very far from this temp. I think the factory freq will be 1% or better. I have not found an internal osc that far out of whack.

 

Cheers

 

Reynard

Link to post
Share on other sites
The 5% is over the temp range -40 to +85. They are calibrated at 25 and it is unlikely you will be operating very far from this temp. I think the factory freq will be 1% or better. I have not found an internal osc that far out of whack.

 

Cheers

 

Reynard

So do you think if I change to the crystal I will still see my problem?

Link to post
Share on other sites
Can I make a suggestion?

 

When dealing with serial communications over RS232/RS485, etc, I have found it far better to use some program other than Hyperterminal.

 

When using something like Advanced Serial Port Terminal, etc., you can see the actual hex values received (as well as ASCII characters)

and more easily debug funny serial UART problems.

 

Also you can send whole messages or files via the TX output.

BTW I have played with Advanced Serial Port Terminal and it is really great. Thank you for that tip.

 

 

Haven't tried the only Reynard suggested...will try it next.

Edited by jwilson
Link to post
Share on other sites

I must have speed read over the bit where you change from 4 to 8MHz.

 

At least with the 11.0592MHz you will know the baud is exact. I have half a dozen crystals here if you were not so far away.

 

We await the results.

 

Cheers

 

Reynard

Link to post
Share on other sites
I attempted to run this code on the device that I plan to talk to in the main design. This device is a weight indicator, it sends continuous streams (every 1 second) of data. I connected my computer to this indicator and I could view the data perfectly. This is a sample of the data that hyperterminal displayed (what does the smiley face mean?).

 

232screenshot.jpg

 

 

When I connected my breadboard instead of my computer it would not work.

 

I wrote the above code in order to obtain the data from the indicator. The data stream format for the indicator is:

 

stream_format.jpg

 

So the first character that is send should be the STX command, just like I have in my code and just like I have emulated. The last should be the CR command which also is just like I have emulated.

 

Can someone explain what might be going on? I am using the internal oscillator, is there a chance that while connected to a computer the baud is okay but connected to this weight scale the baud is not okay? I don't have an oscope so I can't check how bad off I may be. I plan to use a crystal in the final project, but I don't have one to test at the moment.

 

BTW this weight indicator is about 40 miles from me. I will not be able to try anything else until next weekend. I do plan to work on it during my free time this week so I can hopefully have something working when I go there next.

 

I forgot my project files or I would have tried to troubleshoot a little better.

Hi jwilson,

I can see that all the characters from the weight indicator is not printed on the hyperterminal. smiley is some special character( >127 <= 255).

why is the load digits not printed.

try to get some information regarding serial comm of the indicator. Like say if its got modbus protocol. does it have parity etc.

I have worked with similar project. In fact I have constructed a load indicator which sends out 6 digits using TI's adc chip & PIC16F876.

Apart from load it also outs encoder value(for displacement).

For all my testing I use hyperteminal with no problems.

I also have constucted a serial display pcb which receives the serial data & displays. The serial display also has keys to calibrate.

Regards

Raghunathan.

Link to post
Share on other sites
Hi jwilson,

I can see that all the characters from the weight indicator is not printed on the hyperterminal. smiley is some special character( >127 <= 255).

why is the load digits not printed.

try to get some information regarding serial comm of the indicator. Like say if its got modbus protocol. does it have parity etc.

I have worked with similar project. In fact I have constructed a load indicator which sends out 6 digits using TI's adc chip & PIC16F876.

Apart from load it also outs encoder value(for displacement).

For all my testing I use hyperteminal with no problems.

I also have constucted a serial display pcb which receives the serial data & displays. The serial display also has keys to calibrate.

Regards

Raghunathan.

 

Raghunathan,

 

Below is the setup for the serial port on the weight indicator. Some of this won't pertain to the protocol at all.

 

EDP = 9600/8NONE/CR/OFF

Print (not used though) = 9600/8NONE/CR

STREAM = EDP

STMDLY = 1SEC

PRNDES = EDP

PROTCT = DISABLE

 

serial_menu.jpg

Link to post
Share on other sites

Hi,

I suppose u can connect a load cell to your indicator. connect it & see if the count value changes on the hyper-term when you press the load-cell.

Right now what we see on the screen must be just raw counts. we need to config & calibrate the device. I probably would

require the whole data sheet to do that.

 

regards

Raghunathan.

Link to post
Share on other sites

hi,

for your serial receive program, u can use the space as the qualifier & start loading the other digits in an array. The size of the array depends on the data digits lenght. try placing full-load to the indicator determine the data length. I thought it should display 00001828 on the hyper.

Regards

Raghunathan.

Link to post
Share on other sites
Hi,

I suppose u can connect a load cell to your indicator. connect it & see if the count value changes on the hyper-term when you press the load-cell.

Right now what we see on the screen must be just raw counts. we need to config & calibrate the device. I probably would

require the whole data sheet to do that.

 

regards

Raghunathan.

 

The load cell is already connected and the entire system has been calibrated. The display that you see above is with my weight on it (182.8 lbs), it follows the data stream perfectly.

 

When I add more weight or less weight the value changes exactly like it is supposed to.

Edited by jwilson
Link to post
Share on other sites
hi,

for your serial receive program, u can use the space as the qualifier & start loading the other digits in an array. The size of the array depends on the data digits lenght. try placing full-load to the indicator determine the data length. I thought it should display 00001828 on the hyper.

Regards

Raghunathan.

Currently I am using the STX command as a qualifier, then placing the data into my array after that. I really don't think that part is my issue now, but I will note that and try it if the crystal doesn't provide any improvements.

 

Thank you for your suggestions.

Edited by jwilson
Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...