View previous topic :: View next topic |
Author |
Message |
harlequin2
Joined: 11 Jun 2011 Posts: 21
|
RS232 interrupt not working (Solved) |
Posted: Sat Jun 11, 2011 8:29 pm |
|
|
I am trying to use interrupt driven comms on a 12F1822 with no success so far. The thing sends and receives OK without using interrupts, but doesn't seem to recognise the rcv int. What am I missing? (V 4.12)
#include <12lf1822.h>
#device ADC=10
#fuses INTRC_IO, NOWDT, NOPROTECT, NOLVP
#use delay(internal=4000000)
#use rs232(baud=9600, xmit= PIN_A4, rcv=PIN_A5)
#define ShntDrv PIN_A2 //balancing shunt driver
//Globals
volatile unsigned int8 StoredVal;
void init(){
port_a_pullups(0b00100000); //internal pullup on rcv pin (RA5)
setup_adc_ports(sAN1, VSS_VDD); //
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(1);
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA); //serial rcv
}
#int_rda
void serial_isr(){
unsigned int8 buffer, Msg=FALSE;
buffer = getc();
putc(buffer); //test - not working!!!!
if (buffer==0xFF) Msg=FALSE; //done rcving message
if (Msg) putc(buffer);
if (buffer==01){ //01 is command to add cell voltage to the string
Msg=TRUE; //receiving message
putc(buffer);
putc(StoredVal);
}
}
void main() {
unsigned int8 i;
unsigned int16 value ;
init();
do{
value=0;
for(i=1;i<=10;i++){
delay_ms(20);
value+=Read_ADC();
}
value/=10 ; //is now average of 10 readings
value-=316;
if(value>=0xFF) value = 0xFE; //is now 0 - 254
StoredVal=(int)value; //
// putc(getc()+1); // test comms - this works OK!!!!!!
}while(TRUE);
}
Last edited by harlequin2 on Sun Jun 12, 2011 6:07 pm; edited 1 time in total |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Sat Jun 11, 2011 8:45 pm |
|
|
you've got...
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA); //serial rcv
...maybe reverse the order to
enable_interrupts(INT_RDA); //serial rcv
enable_interrupts(GLOBAL);
??? |
|
|
harlequin2
Joined: 11 Jun 2011 Posts: 21
|
|
Posted: Sat Jun 11, 2011 8:58 pm |
|
|
temtronic wrote: | you've got...
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA); //serial rcv
...maybe reverse the order to
enable_interrupts(INT_RDA); //serial rcv
enable_interrupts(GLOBAL);
??? |
Thanks, tried that, makes no difference.
Sorry I didn't notice the "Code" button in my original post! |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Sat Jun 11, 2011 11:16 pm |
|
|
We all know the RDA interrupt only works with the hardware UART.
It is never a good idea to put a putc in a RDA interrupt. Sure it will work but it takes time to send chars and you can guess it is about the same time as it takes to receive them, RS232 is asynchronous so an inbound char can and will arrive at any time (unless you have a handshake with the transmitter). The RDA needs to be called when the inbound char arrives but if the RDA is busy doing things like outputting a char or two it will not be able to respond. The hardware has a small 2 char receive buffer so you may get one putc char out and have the hardware capture the inbound char. It's still not a good idea. The rule with interrupts is that you should put as little code in them as you can. |
|
|
harlequin2
Joined: 11 Jun 2011 Posts: 21
|
|
Posted: Sat Jun 11, 2011 11:26 pm |
|
|
Douglas Kennedy wrote: | We all know the RDA interrupt only works with the hardware UART.
It is never a good idea to put a putc in a RDA interrupt. Sure it will work but it takes time to send chars and you can guess it is about the same time as it takes to receive them, RS232 is asynchronous so an inbound char can and will arrive at any time (unless you have a handshake with the transmitter). The RDA needs to be called when the inbound char arrives but if the RDA is busy doing things like outputting a char or two it will not be able to respond. The hardware has a small 2 char receive buffer so you may get one putc char out and have the hardware capture the inbound char. It's still not a good idea. The rule with interrupts is that you should put as little code in them as you can. |
Yah, we know all that. The way this works is that all of the characters received are supposed to be transmitted as they come in. If the first one is $01 then an extra character is added to the stream. The 2 char buffer will allow this. But, the interrupt is still not being triggered by the first incoming character - why not is the question.
The following still does not send out a character:
Code: | #int_rda
void serial_isr(){
unsigned int8 buffer, Msg=FALSE;
buffer = getc();
putc(buffer); //test
/* if (buffer==0xFF) Msg=FALSE; //done rcving message
if (Msg) putc(buffer);
if (buffer==01){ //01 is command to add cell voltage to the string
Msg=TRUE; //receiving message
putc(buffer);
putc(StoredVal);
}*/
}
|
It should, shouldn't it? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Jun 11, 2011 11:43 pm |
|
|
I'm not at a location where I can test this, but I think it might have a
chance to work: Give the compiler what it wants, to make it generate
code for a hardware UART. Then use APFCON to switch the pins.
That's what I've done below. Try it. See if it works.
Code: |
#include <12lf1822.h>
#fuses INTRC_IO, NOWDT, NOPROTECT, NOLVP
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)
#int_rda
void serial_isr()
{
char c;
c = getc();
putc(c); // Echo back all incoming characters
}
//------------------------------------
// Put the UART on pins A4, A5 for Tx, Rx.
void select_alt_uart_pins(void)
{
#byte APFCON = getenv("SFR:APFCON")
APFCON |= 0x84; // Select alternate pins for Tx, Rx
}
//================================
void main()
{
select_alt_uart_pins();
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
while(1);
} |
|
|
|
harlequin2
Joined: 11 Jun 2011 Posts: 21
|
|
Posted: Sun Jun 12, 2011 12:22 am |
|
|
PCM programmer wrote: | I'm not at a location where I can test this, but I think it might have a
chance to work: Give the compiler what it wants, to make it generate
code for a hardware UART. ] |
That is exactly what I have done, if you read the code carefully. The XMIT and RCV pins are what they have to be. And they work fine for non-interrupt comms.
I would assume that the compiler would use the hardware UART if it is present, if it doesn't then it is more useless than I thought! But I stuck UART1 into the use RS232 directive just in case, and it makes no difference.
I've read the CCS C compiler stuff back and forth, looked at their sample programs and I cannot see why this doesn't work.
Thanks for your suggestions so far.
I've started looking at the .lst file, but the reason I used this CCS thing was to get away from assembler. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jun 12, 2011 12:28 am |
|
|
Post your exact compiler version and I'll look at it tomorrow.
(Version numbers have three digits after the decimal point). |
|
|
harlequin2
Joined: 11 Jun 2011 Posts: 21
|
|
Posted: Sun Jun 12, 2011 12:55 am |
|
|
PCM programmer wrote: |
Post your exact compiler version and I'll look at it tomorrow.
(Version numbers have three digits after the decimal point). |
4.120 |
|
|
harlequin2
Joined: 11 Jun 2011 Posts: 21
|
|
Posted: Sun Jun 12, 2011 3:40 pm |
|
|
I have reduced the code down to the following and it still doesn't work. Because I initialise buf as true, it transmits a single byte (01) but does not respond to characters sent to it ie no interrupt. I know the thing can receive because if I put "putc(getc())" in main, it sends and receives fine.
Code: | #include <12lf1822.h>
#device ADC=10
#fuses INTRC_IO, NOWDT, NOPROTECT, NOLVP
#use delay(internal=4000000)
#use rs232(baud=9600, UART1,xmit= PIN_A4, rcv=PIN_A5, ERRORS)
volatile char buf=TRUE;
#int_rda
void serial_isr(){
buf=getc();
}
void main(){
enable_interrupts(INT_RDA);
enable_interrupts(global);
do{
if(buf){
putc(buf);
buf = FALSE;
}
}while(TRUE);
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jun 12, 2011 3:46 pm |
|
|
That's right, because you're not setting the APFCON register bits to
select the alternate UART pins. The compiler won't do that for you
automatically just because you specified the alternate pins in the
#use rs232() statement.
And also, putting 'UART1' in the #use rs232() while still keeping the
pin declarations, does not work. The pin declarations override
the 'UART1' directive. The compiler does not know that the alternate
pins can work with the hardware UART. It will generate code for a
software UART if you specify those pins.
You have to do it the way I showed in my post. |
|
|
harlequin2
Joined: 11 Jun 2011 Posts: 21
|
|
Posted: Sun Jun 12, 2011 4:19 pm |
|
|
PCM programmer wrote: | That's right, because you're not setting the APFCON register bits to
select the alternate UART pins. The compiler won't do that for you
automatically just because you specified the alternate pins in the
#use rs232() statement.
And also, putting 'UART1' in the #use rs232() while still keeping the
pin declarations, does not work. The pin declarations override
the 'UART1' directive. The compiler does not know that the alternate
pins can work with the hardware UART. It will generate code for a
software UART if you specify those pins.
You have to do it the way I showed in my post. |
OK, what you have said makes sense so I added the code you gave for setting the APFCON register bits but sadly the result is still the same. The 1822 has only one uart so you'd think you wouldn't need to specify "uart1". I am at a bit of a loss now. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jun 12, 2011 4:21 pm |
|
|
Post your latest test program. |
|
|
harlequin2
Joined: 11 Jun 2011 Posts: 21
|
|
Posted: Sun Jun 12, 2011 4:45 pm |
|
|
PCM programmer wrote: | Post your latest test program. |
Here it is: Note that it sends one char when I power it up, as it should since buffer is true (usually 0xFF)
Code: | #include <12lf1822.h>
#device ADC=10
#fuses INTRC_IO, NOWDT, NOPROTECT, NOLVP
#use delay(internal=4000000)
#use rs232(baud=9600, UART1,xmit= PIN_A4, rcv=PIN_A5, ERRORS)
#define ShntDrv PIN_A2 //balancing shunt driver
//Globals
volatile char StoredVal, buffer;
// Put the UART on pins A4, A5 for Tx, Rx.
void select_alt_uart_pins(void){
#byte APFCON = getenv("SFR:APFCON")
APFCON |= 0x84; // Select alternate pins for Tx, Rx
}
void init(){
port_a_pullups(0b00100000); //internal pullup on rcv pin (RA5)
setup_adc_ports(sAN1, VSS_VDD); //
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(1);
select_alt_uart_pins();
enable_interrupts(PERIPH);
enable_interrupts(INT_RDA); //serial rcv
enable_interrupts(GLOBAL);
}
#int_rda
void serial_isr(){
// unsigned int8 buffer, Msg=FALSE;
buffer = getc();
// putc(buffer); //test
/* if (buffer==0xFF) Msg=FALSE; //done rcving message
if (Msg) putc(buffer);
if (buffer==01){ //01 is command to add cell voltage to the string
Msg=TRUE; //receiving message
putc(buffer);
putc(StoredVal);
}*/
}
void main() {
unsigned int8 i;
unsigned int16 value ;
init();
do{
value=0;
for(i=1;i<=10;i++){
delay_ms(20);
value+=Read_ADC();
}
value/=10 ; //is now average of 10 readings
value-=316;
if(value>=0xFF) value = 0xFE; //is now 0 - 254
StoredVal=(int)value; //
if(buffer){
putc(buffer); // test comms
buffer=FALSE;
}
}while(TRUE);
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jun 12, 2011 5:18 pm |
|
|
Quote: | #include <12lf1822.h>
#device ADC=10
#fuses INTRC_IO, NOWDT, NOPROTECT, NOLVP
#use delay(internal=4000000)
#use rs232(baud=9600, UART1,xmit= PIN_A4, rcv=PIN_A5, ERRORS) |
One last time. From my previous post:
Quote: |
And also, putting 'UART1' in the #use rs232() while still keeping the
pin declarations, does not work. The pin declarations override
the 'UART1' directive. The compiler does not know that the alternate
pins can work with the hardware UART. It will generate code for a
software UART if you specify those pins.
You have to do it the way I showed in my post.
|
I did not put the 'xmit= PIN_A4' and 'rcv=PIN_A5' statements in the code in my post !
You should NOT do it. You should use 'UART1' ONLY ! (After this I give up). |
|
|
|