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

ExperimenterUK
Thu Mar 14 2019, 08:44 PM
We don't send code,but you can ask for help in the 8051 forum
Thu Mar 14 2019, 11:00 AM
Jui Sanjay Kapare
Hello sir, I want code of interfacing DS18B20 with 8051.plz send the code as early as possible
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....

Downloads

Comments

tutu10
Tue Mar 12 2019, 07:11 AM
Raj243
Fri Mar 08 2019, 02:08 AM
bharatsb
Thu Mar 07 2019, 04:34 PM
Yass7
Thu Mar 07 2019, 03:55 PM
mashabed
Mon Mar 04 2019, 11:08 PM
AccelMotion
Tue Feb 26 2019, 06:06 PM
turbovps
Mon Feb 25 2019, 06:26 AM
the_Doker
Thu Feb 14 2019, 02:21 PM

Online

Guests: 31, Members: 0 ...

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

Members: 38052
Newest member: tutu10
Forum Activity
ExperimenterUK Avatar
Posted By ExperimenterUK
Fri Mar 22 2019, 09:10 PM
Using the external interrupt on pin B0 is the best...
Ansh12 Avatar
Posted By Ansh12
Fri Mar 22 2019, 03:45 PM
I have pic16f877a and MPLABX8 and I want to count ...
ExperimenterUK Avatar
Posted By ExperimenterUK
Wed Mar 13 2019, 02:32 AM
HiI looked at" Atmel AVR042: AVR Design Considera...
tutu10 Avatar
Posted By tutu10
Tue Mar 12 2019, 07:13 AM
Hi...My firmware upgradable code lock seems to be ...
Yass7 Avatar
Posted By Yass7
Sat Mar 09 2019, 12:52 AM
It's exactly that ! it's my teacher who asked me t...
ExperimenterUK Avatar
Posted By ExperimenterUK
Sat Mar 09 2019, 12:27 AM
As I understand it, you want to use a P89LPC952 /...
ExperimenterUK Avatar
Posted By ExperimenterUK
Sat Mar 09 2019, 12:21 AM
After you get the string what do you want to do wi...
bharatsb Avatar
Posted By bharatsb
Thu Mar 07 2019, 04:40 PM
help me to write code for 8051 to receive string ...
Yass7 Avatar
Posted By Yass7
Thu Mar 07 2019, 03:59 PM
Hello everyone,here I made a 3-axis CNC with 3 ste...
ExperimenterUK Avatar
Posted By ExperimenterUK
Sat Jan 26 2019, 07:19 PM
Yes that helps a lot.At first sight I can't see th...