Discussion in "8051 Discussion Forum" started by    DavesGarage    Dec 4, 2009.
Fri Dec 04 2009, 05:18 PM
#1
A serial interface to the outside world is a fantastic way to speed development in your 8052 project. If you know your serial interface is working, you can use it to debug your code when other methods for debugging aren't available (like an ICE, or JTAG, etc... ).

Getting your first piece of code running on a new target system is always a challenge, and even the simplest program (Hello World) requires an output device.

The goal of this thread is to help you get your first program up and running, and get your microcontroller talking to your PC through the Hyperterminal emulator.

I'd like to personally thank Rickey's World member Abhinav.Chaurey for taking the time to verify/validate the software in this thread.

 Abhinav.Chaurey like this.
Fri Dec 04 2009, 05:34 PM
#2
So, where to start?

Firstly, we make a couple of assumptions about our target system:

The crystal frequency will be 11.0592Mhz, and the processor will be a 12-clock/instruction processor.

so, here is the first part of the software:

//=====================================================================
// simple example software for testing serial interface...             
//=====================================================================
#include "AT89X51.H"            
#include <stdio.h>


We include a header that has our special function registers defined for us. I'm using the Keil development environment, and this header came with it... We also include the stdio.h header, since that's where our printf(...) function is declared...

Next, we make a few definitions:
#define BUF_SIZE           16          // buffer size for both Rx   
                                       // and Tx buffers            
#define MICRO_FREQUENCY    11059200.0  // frequency of micro...     

typedef unsigned char BYTE;
typedef unsigned long ULONG;
typedef unsigned int WORD;

#define UART0_VECTOR       4           //0x23 Serial Port 0         

volatile BYTE TxBuffer[ BUF_SIZE ];   
volatile BYTE RxBuffer[ BUF_SIZE ];   
volatile BYTE RxInChar;
volatile BYTE RxOutChar;
volatile BYTE TxInChar;
volatile BYTE TxOutChar;
volatile BYTE TxEnabled;


The first thing declared is the size of our buffer - this is an 8-bit value, so it should be somewhere between 1 and 255 - I chose 16 bytes as an example, but you can increase this depending on your memory size.

Next, we define the crystal frequency we're using - 11.059Mhz on an 8052 can get you up to 56k baud - a 22.059Mhz crystal can get you 115.2k baud - for this example, I'm using 11.059Mhz as an example.

Next, we define the vector number for the UART - this is pretty much the same for all basic 8052 micros.

And finally, we define our variables:

TxBuffer and RxBuffer are the transmit and receive buffers.
RxInChar and RxOutChar are pointers into the receive buffer.
TxInChar and TxOutChar are pointers into the transmit buffer.
TxEnabled is a flag for transmitting characters that are waiting in the transmit buffer...



[ Edited Fri Dec 04 2009, 06:16 PM ]
Fri Dec 04 2009, 05:39 PM
#3
Next, we define a function to initialize our serial interface interrupt:

//=====================================================================
// init routine for ISR handler...                                     
//=====================================================================
void SER_init()
   {
   /* disable interrupts...       */
   EA          = 0;
   
   /* clear com buffer indexes... */
   TxInChar    = 0;
   TxOutChar   = 0;
   TxEnabled   = 0;
   RxInChar    = 0;
   RxOutChar   = 0;
   
   /* Setup serial port registers */
   SM0         = 0; 
   SM1         = 1;           // serial port MODE 1 
   SM2         = 0;
   REN         = 1;           // enable serial receiver 
   TI          = 0;           // clear transmit interrupt 
   RI          = 0;           // clear receiver interrupt 
   ES          = 1;           // enable serial interrupts 
   PS          = 0;           // set to low priority 
   EA          = 1;           // Enable Interrupts 
   }



The process is outlined in the comments above. When your comments are complete, there is no need to expound on what you are trying to accomplish.

Fri Dec 04 2009, 05:52 PM
#4
Now we need to define the actual interrupt service routine...

//=====================================================================
//=====================================================================
void SER_ISR() interrupt UART0_VECTOR using 2
   {
   /* Received value interrupt    */
   if( RI )
      {
      RI = 0;

      /* get byte if there's room in the buffer */
      if( ((RxInChar + 1)%BUF_SIZE) != RxOutChar )
         {
         RxBuffer[ RxInChar++ ] = SBUF;
         RxInChar %= BUF_SIZE;
         }
      }

   /* Transmitted value interrupt */
   if( TxEnabled )
      {
      /* if previous byte is finished transmitting */
      if( TI )
         {
         TI = 0;

         /* adjust queue and transmit character... */
         if (TxOutChar != TxInChar)
            {
            SBUF = TxBuffer [TxOutChar++];
            TxOutChar %= BUF_SIZE;
            }
         else
            /* nothing else to transmit, so disable function... */
            TxEnabled = 0;
         }
      }
   }


This routine gets executed every time the UART interrupt flags get set: either the RI or TI flag.

The routine is identified as "interrupt 4", which is the proper interrupt for the UART0, and is defined as using register set 2. For more information on register sets, you can read the "8052 bible" documents, listed at the end of this thread.

Here is the basic flow of the function:

1. if the receive flag was set, reset it, and if there's room in the receive buffer, get the byte and add it to the buffer, otherwise, ignore the byte - it will be lost
2. if the transmit flag was set, and our transmit process is enabled, reset the flag, and if there's another byte in the transmit buffer, grab it and send it. If there isn't another byte to send, the transmit process is over.


Fri Dec 04 2009, 05:57 PM
#5
We're almost done now...

We need a routine to set the baud rate:

//=====================================================================
//=====================================================================
void SER_setbaud( ULONG BaudRate )
   {
   /* disable interrupts */
   ES           = 0;
   
   /* Clear interrupt flag and buffer */
   TI           = 0;
   TxInChar     = 0;
   TxOutChar    = 0;

   /* transmitter is disabled */
   TxEnabled    = 0;
   
   /* Set timer 1 up as a baud rate generator.  */
   TR1         = 0;           // stop timer 1
   ET1         = 0;           // disable timer 1 interrupt
   PCON       |= 0x80;        // 0x40=SMOD1: set serial baudrate doubler
   TMOD       &= 0x0F;        // clear timer 1 mode bits
   TMOD       |= 0x20;        // put timer 1 into MODE 2 : 8-bit, auto-reload
   TH1         = (BYTE) (256.0 - (MICRO_FREQUENCY / (192.0 * (float)(BaudRate))));
   TR1         = 1;           // start timer 1
   
   /* enable interrupts */
   ES           = 1;
   }


Again, the comments speak for themselves, but the basic idea here is whenever we change the baud rate, we disable the interrupts, delete whatever is in the transmit buffer, reprogram the timer that generates the baud rate, and re-enable the interrupts.
Fri Dec 04 2009, 06:00 PM
#6
The last thing we'll need is a putchar(), getchar(), and kbhit() function to round out this example:

//=====================================================================
//=====================================================================
char putchar( char ThisChar )
   {
   /* wait if buffer is full... */
   while( ( (TxInChar+1) % BUF_SIZE) == TxOutChar );
   
   /* add this character to the transmit buffer */
   ES = 0;
   TxBuffer[ TxInChar++ ] = ThisChar;
   TxInChar %= BUF_SIZE;

   /* if transmitter is disabled enable it */
   if( !TxEnabled )           
      {
      TxEnabled = 1;
      TI = 1;
      }
   
   ES = 1;

   /* return character as default value */
   return( ThisChar );
   }

//=====================================================================
//=====================================================================
char getchar()
   {
   volatile char c;
   
   while(RxInChar == RxOutChar);
   ES = 0;                         /* Disable Interrupts */
   c = RxBuffer[ RxOutChar++ ];
   RxOutChar %= BUF_SIZE;
   ES = 1;                         /* Enable Interrupts */
   
   return( c );
   }

//=====================================================================
//=====================================================================
BYTE kbhit()
   {
   /* nothing to get? */
   if( RxInChar == RxOutChar )
      {   
      return (0);
      }

   /* something in buffer... */
   return( 1 );
   }


The putchar() function adds a byte to the transmit buffer (if there is room), the getchar() function grabs a byte from the receive buffer (if there is any), and the kbhit() function ( sounds like "keyboard hit?") checks the receive buffer to see if there is anything to grab. ac

Fri Dec 04 2009, 06:04 PM
#7
Finally, we need the main() function. I've written a simple main() that will utilize all of our functions, and echo characters back to Hyperterminal when you type.

//=====================================================================
//=====================================================================
void main()
   {
   char ThisChar;

   // initialize serial interface...
   SER_init();
   SER_setbaud( 19200 );

   printf("Keyboard Echo active\r\n");
   
   // loop forever...
   while(1)
      {
      // if the keyboard is hit, handle the incoming character...
      if( kbhit() )
         {
         ThisChar = getchar();
         putchar( ThisChar );
         
         // add line feed to all returns...
         if( ThisChar == 0x0D )
            putchar( 0x0A );
         }
      }
   }


Just make sure Hyperterminal is set to the same baud rate that your software is set for - in this example, I chose 19200, but you can choose whatever best fits (up to the limitations of your processor crystal, of course).

Have fun with this, and feel free to comment on your experiences...
Thu Mar 29 2012, 02:35 PM
#8
Thank you sir,

It is very informative article. I have used this code in my design & is working very well. Can you please describe how can I get a string instead of a single character from the serial port? The characters should get accumulated in the receive buffer until a carriage return is detected. In my main routine I will check for the string.

Thanks.

Thu Mar 29 2012, 07:08 PM
#9


Thank you sir,

It is very informative article. I have used this code in my design & is working very well. Can you please describe how can I get a string instead of a single character from the serial port? The characters should get accumulated in the receive buffer until a carriage return is detected. In my main routine I will check for the string.

Thanks.

vbdev


Dave's been busy recently so may not visit anytime soon.
Have a look through 8051 forum threads for examples of serial buffering.
Create a new thread if you can't find an answer.

Get Social

Information

Powered by e107 Forum System

Conversation

Tue Jan 22 2019, 06:51 AM
chnlovelyo
writing
ExperimenterUK
Mon Jan 07 2019, 03:31 AM
@REVOCATUS please post in the AVR forum
Mon Dec 24 2018, 09:25 AM
REVOCATUS MATEMU
sorry I mean referee boards for player substitution
Mon Dec 24 2018, 09:24 AM
REVOCATUS MATEMU
hi am.looking how to build referee by using Atmega 328 and its codes
Sat Dec 15 2018, 01:45 PM
Arslan ayoub
Hii ,, can I get the simulation of numeric keypad lock on proteus
ExperimenterUK
Mon Dec 03 2018, 05:17 PM
Please post questions in the forum. The chat box is for chat
Mon Dec 03 2018, 06:43 AM
help!me!
help! I don't understand busy flag!
Sun Dec 02 2018, 08:01 PM
ile
hello
Mon Nov 12 2018, 05:58 AM
Pavan_user
i have seen your replica of I2C programming using AT89C51 but i am unable to understand the "ack_bit" variable usage ...looks like it is always 1...can you elaborate how acknowledgment is working....
bgk3678
Tue Nov 06 2018, 02:36 PM
kindly any one give solution for my problem

Downloads

Comments

garfield0929
Sun Jan 20 2019, 12:48 AM
servprov
Thu Jan 17 2019, 06:44 AM
marcomilazzo
Wed Jan 16 2019, 04:21 PM
sandhyashree
Wed Jan 16 2019, 04:04 PM
SONACHAI1234
Sun Jan 06 2019, 08:14 AM
manan.gulyaani
Tue Jan 01 2019, 07:58 AM
etech
Sun Dec 30 2018, 07:44 PM
NeilC
Sun Dec 23 2018, 07:39 PM

Online

Guests: 58, Members: 0 ...

most ever online: 182184
(Members: , Guests: 182184) on 06 Aug 2010: 05:37 AM

Members: 38039
Newest member: garfield0929
Forum Activity
ExperimenterUK Avatar
Posted By ExperimenterUK
Sun Jan 06 2019, 10:37 PM
Which 8051 chip are you using ?
SONACHAI1234 Avatar
Posted By SONACHAI1234
Sun Jan 06 2019, 08:21 AM
Hi,By mistakenly i burn rx program in my 8051 micr...
ExperimenterUK Avatar
Posted By ExperimenterUK
Wed Dec 19 2018, 06:27 PM
Nobody knows?sifirsekizThe problem is that you are...
sifirsekiz Avatar
Posted By sifirsekiz
Wed Dec 19 2018, 12:15 PM
sifirsekiz Avatar
Posted By sifirsekiz
Sun Dec 16 2018, 11:13 PM
Guys pleaseeeee :((
sifirsekiz Avatar
Posted By sifirsekiz
Sat Dec 15 2018, 07:09 PM
HiThe pulse-sensor-amped has an analogue output.Th...
ExperimenterUK Avatar
Posted By ExperimenterUK
Sat Dec 15 2018, 07:01 PM
HiThe pulse-sensor-amped has an analogue output.Th...
sifirsekiz Avatar
Posted By sifirsekiz
Sat Dec 15 2018, 09:02 AM
and ı have pulse sensor one out but anolog use 805...
sifirsekiz Avatar
Posted By sifirsekiz
Sat Dec 15 2018, 08:56 AM
HiMembers can supply code and diagrams if they wan...
ExperimenterUK Avatar
Posted By ExperimenterUK
Fri Dec 14 2018, 11:54 PM
HiMembers can supply code and diagrams if they wan...