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

DragonDad
Wed May 29 2019, 12:17 PM
Hi. Who is online?
Tue May 21 2019, 09:53 PM
Jayson Contreras
Hello
Xkalebar
Mon May 06 2019, 06:21 AM
Please provide me the code for gsm based sms controlled notice board
ExperimenterUK
Mon Apr 22 2019, 08:07 PM
@hassan malik post your problem in the "General help Guidance and Discussion" forum
Mon Apr 22 2019, 02:21 PM
RAJESH MAPARi
please send me code to interface atmega32 with 24c1024 serial eeprom
Mon Apr 22 2019, 10:48 AM
hassan malik
hello sir i installed proteus 7.8 professional on window 7 ultimate and window 10 but there would be same errors onn both windows. the error is bad license key.please any one help me
Mon Apr 22 2019, 10:47 AM
hassan malik
hello sir i installed proteus 7.8 professional on window 7 ultimate and window 10 but there would be same errors onn both windows. the error is bad license key.
ExperimenterUK
Sun Apr 14 2019, 03:14 PM
@deshrar. Please post your question in 8051 forum
Sun Apr 14 2019, 04:58 AM
deshraj
hallo mam.. i have downloded gsm notice board code its running fine on lcd but how so send msg to the module . i mean format of password and msg.. thank you
kevinharsha
Thu Apr 11 2019, 01:53 PM
Can i see the circuit diagram for the music tone library 8051 project?

Downloads

Comments

DragonDad
Tue May 21 2019, 02:50 PM
dhiyamtech
Thu May 09 2019, 10:20 AM
harsha.reddy
Fri May 03 2019, 09:02 AM
soumen1963
Fri May 03 2019, 06:01 AM
Vasily
Mon Apr 29 2019, 04:03 AM
Xkalebar
Sun Apr 28 2019, 08:59 AM
obibikwe
Fri Apr 19 2019, 05:55 PM
gigyani
Thu Apr 18 2019, 01:43 AM

Online

Guests: 42, Members: 0 ...

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

Members: 38066
Newest member: DragonDad
Forum Activity
Ansh12 Avatar
Posted By Ansh12
Sun Apr 28 2019, 02:15 PM
I made a minor change, it works in Proteus.Try the...
ExperimenterUK Avatar
Posted By ExperimenterUK
Thu Apr 25 2019, 08:20 PM
I made a minor change, it works in Proteus.Try the...
gigyani Avatar
Posted By gigyani
Thu Apr 25 2019, 01:17 AM
when i add cufirst.hex its not working.after 2-3 s...
ExperimenterUK Avatar
Posted By ExperimenterUK
Wed Apr 24 2019, 12:29 AM
http://www.8051projects.net/download-d205-electron...
gigyani Avatar
Posted By gigyani
Tue Apr 23 2019, 09:22 PM
How to enter the electronic voting machine into vo...
Ansh12 Avatar
Posted By Ansh12
Mon Apr 22 2019, 09:12 AM
Then flash the led when you get any input on B0.Le...
ExperimenterUK Avatar
Posted By ExperimenterUK
Fri Apr 19 2019, 05:35 PM
The full error is control_unit.asm(1294): error A4...
gigyani Avatar
Posted By gigyani
Thu Apr 18 2019, 10:09 PM
I'm using keil uvision5. attached is the rar file ...
ExperimenterUK Avatar
Posted By ExperimenterUK
Thu Apr 18 2019, 04:58 PM
Please zip your full code and post it.Which assemb...
gigyani Avatar
Posted By gigyani
Thu Apr 18 2019, 02:01 AM
STATREAD:MOV A, #WTCMD ;LOAD WRITE CO...