This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

8051 interrupts

I am trying to generate an interrupt when a byte is received via the serial port of an Atmel AT89C51. I am not having much luck. Here is my code:

#include <reg51.h>
#include <CTYPE.H>
#include <STDIO.H>
#include <INTRINS.H>

int big_d, count, dogg, i, j;

void rcv (void) interrupt 4 
{
	big_d = _getkey();
	count++;
	dogg = 1;
	RI = 0;
}

void main(void)
{
	SCON  = 0x50;		/* SCON: mode 1, 8-bit UART, enable rcvr */
    TMOD |= 0x20;       /* TMOD: timer 1, mode 2, 8-bit reload */   
    TH1   = 253;        /* TH1:  reload value for 9600 baud @ 11.0592MHz */
    TR1   = 1;          /* TR1:  timer 1 run */          
    TI    = 1;          /* TI:   set TI to send first char of UART */
	ES = 1;				/* enable serial interrupts */

	dogg = 0;
	count = 0x30;
do{
	putchar(count);
	for(j=0; j<255; j++)
	{
		for(i=0; i<255; i++)
		{
			_nop_();
			_nop_();
			_nop_();
			_nop_();
		}
	}
	if(dogg == 1)
	{
		putchar(count);
		printf("\n");
		putchar(big_d);
		printf("\n\n\n");
		dogg = 0;
	}
}while(1);
}

Any suggestions or corrections to my code would be great. Thanks

Parents
  • Depending on the application, you might just as well have saved all the timing overhead from filling the ring buffer.

    There's very little over head in having putchar check file scoped bit var called txRingFull. No more than checking if TI is set. I always write my own putchar/getchar.

    Polling requires a delay of 1 character time between writes into SBUF. So, at 2400 baud, when you write into SBUF you must wait for 1/240th seconds. This is FOREVER in a real-time program. Sending a 240-byte string eats up 1 second of processing time (including waiting for the TI bit).

    Circular buffers are FAST. Writes into the buffer execute in a few instruction cycles. Assuming the buffer is large enough, sending a 240-byte string is practically instantaneous.

    Using an RTOS, you can implement a DELAY to allow other tasks to run. With polling, the delay will always be 1 character time. However, with a buffered system, the delay will be the total character time represented by the buffer (which can be closer to 0.3-0.4 seconds).

    The argument that interrupt-driven/buffered serial I/O is complex is moot. If you implement the circular buffer for receive, just copy it and make a few changes for transmit. It's only 3-4 lines of code in and out.

    But, my primary point is...

    It's already been written. It's available for you to use. There's no royalty required. You get source code. It's commented.

    What more could a developer want? :-)

    Jon

    P.S. Andrew, I refuse to make a Windows-based configurator for the interrupt-driven serial port example--so don't even ask. :-p


Reply
  • Depending on the application, you might just as well have saved all the timing overhead from filling the ring buffer.

    There's very little over head in having putchar check file scoped bit var called txRingFull. No more than checking if TI is set. I always write my own putchar/getchar.

    Polling requires a delay of 1 character time between writes into SBUF. So, at 2400 baud, when you write into SBUF you must wait for 1/240th seconds. This is FOREVER in a real-time program. Sending a 240-byte string eats up 1 second of processing time (including waiting for the TI bit).

    Circular buffers are FAST. Writes into the buffer execute in a few instruction cycles. Assuming the buffer is large enough, sending a 240-byte string is practically instantaneous.

    Using an RTOS, you can implement a DELAY to allow other tasks to run. With polling, the delay will always be 1 character time. However, with a buffered system, the delay will be the total character time represented by the buffer (which can be closer to 0.3-0.4 seconds).

    The argument that interrupt-driven/buffered serial I/O is complex is moot. If you implement the circular buffer for receive, just copy it and make a few changes for transmit. It's only 3-4 lines of code in and out.

    But, my primary point is...

    It's already been written. It's available for you to use. There's no royalty required. You get source code. It's commented.

    What more could a developer want? :-)

    Jon

    P.S. Andrew, I refuse to make a Windows-based configurator for the interrupt-driven serial port example--so don't even ask. :-p


Children
  • "P.S. Andrew, I refuse to make a Windows-based configurator for the interrupt-driven serial port example--so don't even ask. :-p"

    I wasn't going to - FastChip does it for me! ;-)

  • A hybrid design in which characters are received via interrupts and sent using polling is common professional design.

    The 8051 has the complication that the transmit interrupt cannot be ignored. I've already shown that the polling loop needs only two instructions. Moving the character to SBUF requires one. That is three opcodes.

    The transmit interrupt can be as simple as:

    SERIAL_INTERRUPT:
       JBC TI, TINTERRUPT
    <receive interrupt processing>
    
    
    TINTERRUPT:
       SETB TRE
       RETI
    

    So the entire driver can be done with six opcodes and one memory bit.