View previous topic :: View next topic |
Author |
Message |
dDelage
Joined: 10 Sep 2022 Posts: 20
|
RS-232 interrupt fails |
Posted: Sun Oct 16, 2022 12:01 am |
|
|
This is code (simplified) that has worked previously with PIC16F876A, now being used with PIC16F18855. I know that the WIN11 and Prolific USB/Serial adapter work because they work with the previous revision. Here's the code with two choices, neither of them work. Ideas?
Code: | /*RS-232 Test*/
// PICK ONE
#define SerIntr //uses serial interrupt
//#define SerPoll //uses kbhit()
//////////// CHIP SETUP
#include <16F18855.H> //includes #device spec rev5
#id CHECKSUM //stores the checksum, doesn't affect program
#use delay (INTERNAL=4MHZ) //Says INTERNAL OSCILLATOR is 4MHz rev5
#use rs232 (baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8)
// PORTB ASSIGNMENTS
#define StatusLed PIN_B1
#define ReadyLed PIN_B2
//other
void serial_in();
void initialize();
void main();
#INT_RDA // interrupt on serial data receive
void serial_in()
{
INT iSerCnt;
CHAR cSerialParam;
CHAR cSerialValue;
CHAR sSerialData[10]; //upto 10 characters from race manager, max is 8
gets (sSerialData); //get the incoming data
output_toggle (ReadyLed);
iSerCnt = 0;
WHILE ((sSerialData[iSerCnt] != 13)&& (iSerCnt < 10) )
{
//get this param and value until out of data
cSerialParam = sSerialData[iSerCnt]; //get first CHAR that identifies param
iSerCnt++;
cSerialValue = sSerialData[iSerCnt] - 64; //get second CHAR value, 64 got us out of lf, cr, bksp
iSerCnt++; //increment to next
SWITCH (cSerialParam)
{
// decide what to DO
CASE 'U' : // UUUUc
IF (cSerialValue == 21)
{
puts ("UUUUt"); //tell RM we are here
iSerCnt += 3; //skip past rest of characters in sSerialData
}
BREAK;
CASE '0' : //report values bck to RM
putc (5 + 64);
putc (10 + 64);
putc (0x1f + 64);
putc (3 + 64);
putc (65);
putc (66);
putc (67);
BREAK;
} //SWITCH
} // WHILE iSerialCntr[x] > 0
} //end serial interrupt handler
VOID initialize ()
{
// set up initial interrupt conditions
#ifdef SerIntr
enable_interrupts (INT_RDA); //SERIAL ReceiveDataAvailable
#endif
enable_interrupts (GLOBAL); //interrupt
} // end initialize
// MAIN
VOID main()
{
initialize (); //initialize the hardware
WHILE (1)
{
#ifdef SerPoll
IF (kbhit () )
{
serial_in ();
output_toggle (StatusLed);
}
#endif
delay_ms (10);
output_toggle (StatusLed);
}
} //end main ()
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Sun Oct 16, 2022 1:02 am |
|
|
The problem is you are not using the UART!......
Hence no INT_RDA....
Look at the sticky at the top of the forum about PIN_SELECT.
The new chip is a PPS chip. The peripherals are relocatable to different
pins.
The syntax you need to use is:
Code: |
#PIN_SELECT U1RX=PIN_C7
#PIN_SELECT U1TX=PIN_C6
#USE RS232 (UART1, BAUD=9600, parity=N, bits=8, ERRORS)
//You should always use 'ERRORS' unless you are adding code to
//handle hardware ERRORS yourself
|
|
|
|
dDelage
Joined: 10 Sep 2022 Posts: 20
|
RS-232 interrupt fails |
Posted: Sun Oct 16, 2022 6:22 am |
|
|
Thank you, thank you. I woke up this morning to a message that makes me feel so dumb, but happy! You made my day. On to the next! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Sun Oct 16, 2022 8:17 am |
|
|
It is one of those things that until you have 'met it', is not immediately
obvious. So don't feel too bad.
Just add it to your internal knowledge-base, to check if a chip has
PPS.
Have a great day. |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1934 Location: Norman, OK
|
|
Posted: Sun Oct 16, 2022 3:33 pm |
|
|
I find it interesting it is working previously using gets() for a single char input
unless it spends a loooong time in the ISR and has the potential to hang..... _________________ Google and Forum Search are some of your best tools!!!! |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Sun Oct 16, 2022 5:52 pm |
|
|
Quote: |
unless it spends a loooong time in the ISR and has the potential to hang.....
|
Well, I hate to spend any significant time in any ISR. As for the UART, there are so far only two ways I approach it. Either fill a buffer starting from some known start sequence till an "end_of_data" sequence and than raising a flag for main to handle the data or by directly decoding the incoming message via a state machine inside the ISR. In latter case, if the task that needs to be done after receiving the message is simple (like a LED on or off), it is done inside the ISR. Otherwise, flag for the main. Since messages usually don't come directly one after another, I've never encountered a situation where main wasn't able to handle the data before the next arrived. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Mon Oct 17, 2022 5:38 am |
|
|
Yes.
Using gets in an RDA interrupt, will 'work', but completely wastes the
actual point of the interrupt. It means that nothing else happens in the
code all the time serial is being received. The whole 'point' of having
interrupt driven serial is so that other things can be done while serial data
is being handled....
Generally, except when working with very fast serials, as PrinceNai says
it is really worth getting your head round just how slow normal serial 'is'
in processor terms, and so how easy it is to handle data between packets. |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Mon Oct 17, 2022 1:53 pm |
|
|
To illustrate the point of Mr. Ttelmah. With a clock of 32MHz each machine instruction cycle takes 0,000125ms. With a serial set to 19.200 each byte (10 bits) comes in every 0,52083ms. That means you have 4.177 (4177, not four point 177) instruction cycles available for each byte received. Messages are seldom (never) 1byte long. + Carriage return and Newline take the same time. An eternity.
Last edited by PrinceNai on Mon Oct 17, 2022 7:47 pm; edited 1 time in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Oct 17, 2022 5:23 pm |
|
|
Note that you are using a decimal point as a thousands separator, and a
comma as a decimal point. Some countries do this, some do the opposite.
So you mean 4177 instruction cycles. |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Mon Oct 17, 2022 7:16 pm |
|
|
Dear PCM, 4177 cycles it is. Please don't hold it against me for using European way of writing numbers, since I'm from there. It has already caused me no end of grief with SQL. But the point is well taken. How could people know? I edited the response, leaving the original there. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Oct 17, 2022 11:27 pm |
|
|
My intention was to indicate it to others if they weren't aware of it,
not to chastise you. |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Tue Oct 18, 2022 6:03 am |
|
|
It was never ever taken that way :-). You pointed out how numbers can be interpreted in a totally different way, based on how one is trained to see them. A very good point, in fact, that can save someone a lot of time scratching his head and wondering about the result.
As I mentioned, I already had problems with precisely the same thing and lost days with an SQL database where the same client program spitted out different results on different computers. Different locale, different way of interpreting the numbers and dates. So once again, your comment was very well taken and I hope I'll remember it next time. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Wed Oct 19, 2022 1:09 am |
|
|
Yes.
I must admit when I read the original post, it took me perhaps half a
second to suddenly reaiise that the decimal here was the thousands
separator. However I've dealt with so many variants of this over the years
that it is very much second nature (the apostrophe in Switzerland was one
that drove me mad!). Remembering when programming to make sure that
you have the 'national' options selected to deal with this has become
standard practice in databases, spreadsheets etc., that remembering
standard text does not deal with this, is important. I think PriceNai's
change to point it out in his post was the brilliant way to handle this. |
|
|
dDelage
Joined: 10 Sep 2022 Posts: 20
|
|
Posted: Wed Feb 14, 2024 9:45 pm |
|
|
Greetings, all. I am resurrecting this thread from a year and a half ago. I am the son of the OP. I'm picking this project up where he left off.
I see that after Dad got his answer and left the conversation, that a lot of good points were brought up.
Regarding the serial interrupt: in this particular application, when we get serial messages, there isn't a lot of other stuff going on, so waiting for the full string seems to work.
However, I have taken the advice about not wasting CPU cycles to heart, and am looking to improve the serial interrupt handler. Unfortunately, in this case, our serial messages do not have a specific end character, so we can't wait for, say, a CRLF and then signal main() to process the serial data buffer.
I'm considering using one of the 8-bit timers on the PIC to do a timer-based serial capture. Serial strings into the PIC are never more than 10 characters long and are always sent in one stream from the computer. We're running at 9600 baud, which tells me that each character arrives in just under 1mS, putting us at ~10mS for the worst-case string.
The plan is to start the timer when we receive the first serial character, and then signal main() to process the serial data buffer 15mS or so later, giving plenty of time for the remainder of the characters to arrive.
So now here's the question: has anyone here done anything like this before, and if so, does this approach make sense? I'm leaving lots of details out--like incrementing indices and clearing out the serial buffer--in the interest of brevity. When I get this coded, I'll be sure to post the source, but in the meantime, I'm hoping to see if anyone has any tips.
And the best solution is probably to put a message terminator at the end of the serial messages, but we have thousands of devices in the wild that can't be updated, so we'll probably have to deal with this issue for the foreseeable future.
Thanks! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Thu Feb 15, 2024 1:46 am |
|
|
Whoa a second.
gets, waits for a carriage return.
If gets works, then you can simply have the ISR set a flag when the
carriage return arrives.
The original approach, won't work unless there _is_ a carriage return... |
|
|
|