Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

how to build software UART ?

Status
Not open for further replies.

sanket.joshi

Member level 3
Joined
Jun 27, 2013
Messages
65
Helped
8
Reputation
16
Reaction score
8
Trophy points
8
Location
Mumbai,India
Activity points
386
I m doing one project in which i want to interface GSM Module and RF-ID Reader to 89C51..
but problem is there is only one UART for 89C51..
i want to interface them using software UART only..i googled this topic many times but i m not getting what i need...
please provide me code if anyone has for receiving data using software UART...Kindly help...
thanks...
 

Even if you configure the second UART, you cannot use it unless you have a peripheral connected !
 

i want to interface RF-ID reader using software UART.....I dont have second uart..thats why i want to do bit banging.
does anyone have code for this?
 

A softUART or an Analog Multiplexer/Demultiplexer are both possible options.

Although, I should mention both have their drawbacks.

The most softUART is not interrupt driven, therefore without proper planning, the microcontroller can burn may cycles wait for traffic from an attached device.

In the case of the Analog Mux/Demux, some serial devices do to react well when the state of the TX/RX lines are changed, some method of flow control is usually required.

The following is an example of using an Analog Mux/Demux and mentions its use with a UART:

Muxing Around With The CD74HC4067 + Arduino


BigDog
 
A softUART or an Analog Multiplexer/Demultiplexer are both possible options.

Although, I should mention both have their drawbacks.

The most softUART is not interrupt driven, therefore without proper planning, the microcontroller can burn may cycles wait for traffic from an attached device.

In the case of the Analog Mux/Demux, some serial devices do to react well when the state of the TX/RX lines are changed, some method of flow control is usually required.

The following is an example of using an Analog Mux/Demux and mentions its use with a UART:

Muxing Around With The CD74HC4067 + Arduino


BigDog

i saw link provided in the above...there is mentions regarding rf-id at the last...
but i hv doubt that if i interface rf-id with mux for receiving data i have to program uc as if softUART or not?
 

not, just you have to use an extra input output pin for selecting mux lines that which device you are going to connect with.

i have to use 4 i/o pins for select lines...
but will uc be able to receive all 12 byte transmitted by RF-ID?
if yes how?
 

i have to use 4 i/o pins for select lines...
but will uc be able to receive all 12 byte transmitted by RF-ID?
if yes how?
It is just only one pin to select the UART is going to interact with GSM or Rf id you can communicate with any number of bytes but before a data transfer with a device you have to select the device in mux. for two devices you need only one selecting line with two selecting lines you connect 4 devices with your single uart...
 
More than likely you will need to implement hardware flow control for both the serial devices.

Otherwise syncing to a freewheeling transmission would be another issue.

Essentially, the AVR would use the flow control to signal the currently transmitting device to stop transmission.

The AVR would then initiate the Mux channel switch to the other serial device and then using the flow control attached to the second serial device signal it to begin transmitting.

After the transmission is received, the process repeats itself.



BigDog
 
The following attachment is an appnote and generic source code for implementing a softUART:
 

Attachments

  • AN-G-001.zip
    185.3 KB · Views: 75
@bigdogguru
i m posting my code here...
Code:
#include<reg51f.h>
#include<stdio.h>
#include<string.h>
#define BAUD_RATE		9600.0
#define IN_BUF_SIZE		256

#define TRUE 1
#define FALSE 0

#define port P0            
#define lcdport P1 
sbit rs=port^0;        //Register select 
sbit rw=port^1;        //Read/Write 
sbit en=port^2;        //Enable pin

static unsigned char		inbuf[IN_BUF_SIZE];
static unsigned char		qin = 0;
static unsigned char		qout = 0;

static char 			flag_rx_waiting_for_stop_bit;
static char 			flag_rx_off;
static char 			rx_mask;
static char 			flag_rx_ready;
static char 			flag_tx_ready;
static char 			timer_rx_ctr;
static char 			timer_tx_ctr;
static char 			bits_left_in_rx;
static char 			bits_left_in_tx;
static char 			rx_num_of_bits;
static char 			tx_num_of_bits;
static char			internal_rx_buffer;
static char			internal_tx_buffer;
static char			user_tx_buffer;

sbit rx_pin=P2^0;
sbit tx_pin=P2^1;

char ch;

void delay(unsigned int count)    
{
    int i,j;
     for(i=0;i<count;i++)
     for(j=0;j<1100;j++);
}

void lcdcmd(char cmdout)
{
lcdport=cmdout;
rs=0;
rw=0;
en=1;
delay(10);
en=0;
}
 
void lcddata(char dataout)
{
	lcdport=dataout;
rs=1;
rw=0;
en=1;
delay(10);
en=0;
}

void dis_cmd(char cmd_value)
{
	char cmd_value1;
	
		cmd_value1 = cmd_value & 0xF0;		
	lcdcmd(cmd_value1);			
 
	cmd_value1 = ((cmd_value<<4) & 0xF0);	
	lcdcmd(cmd_value1);			
}						
 
 
void dis_data(char data_value)
{
	char data_value1;
	
	data_value1=data_value&0xF0;
	lcddata(data_value1);
 
	data_value1=((data_value<<4)&0xF0);
	lcddata(data_value1);
}

void lcd_init()	// fuction for intialize 
{
	dis_cmd(0x02);		
	dis_cmd(0x28);		
	dis_cmd(0x0C);
	dis_cmd(0x06);
	dis_cmd(0x80);
}


char get_rx_pin_status(void)  //Returns 0 or 1 dependent on whether the receive pin is high or low.
{
if(rx_pin==1)
{
return 0;
}
else 
return 1;
}

void set_tx_pin_high(void)  //    Sets the transmit pin to the high state.
{
tx_pin=1;
}

void set_tx_pin_low(void)  //    Sets the transmit pin to the low state.
{
tx_pin=0;
}

void idle(void)        //    Background functions to execute while waiting for input.
{

unsigned char i=0,data0[]="idle";
dis_cmd(0xC1);
while(data0[i]!='\0')
   {
dis_data(data0[i]);
delay(20);
i++;
}
}

void timer_set(  )  //    Sets the timer to 3 times the baud rate.
{
T2CON   = 0x04;   
   TH2     = 0xFF;  
   RCAP2H  = 0xFF;  
   TL2     = 0xE0;
   RCAP2L  = 0xE0; 
  
   ET2     = 0;
   TR2   = 0;        
}

void timer_isr(void)
	{
	char			start_bit, flag_in;

// Receiver Section
	if ( flag_rx_off==FALSE )
		{
		if ( flag_rx_waiting_for_stop_bit )
			{
			if ( --timer_rx_ctr<=0 )
				{
				flag_rx_waiting_for_stop_bit = FALSE;
				flag_rx_ready = FALSE;
				internal_rx_buffer &= 0xFF;
				if ( internal_rx_buffer!=0xC2 )
					{
					inbuf[qin] = internal_rx_buffer;
                    qin++;
					
					if ( ++qin>=IN_BUF_SIZE )
						{
						qin = 0;
						}
					}
				}
			}
		else		// rx_test_busy
			{
			if ( flag_rx_ready==FALSE )
				{
				start_bit = get_rx_pin_status();
// Test for Start Bit
				if ( start_bit==0 )
					{
					flag_rx_ready = TRUE;
					internal_rx_buffer = 0;
					timer_rx_ctr = 4;
					bits_left_in_rx = rx_num_of_bits;
					rx_mask = 1;
					}
				}
			else	// rx_busy
				{
				if ( --timer_rx_ctr<=0 )
					{				// rcv
					timer_rx_ctr = 3;
					flag_in = get_rx_pin_status();
					if ( flag_in )
						{
						internal_rx_buffer |= rx_mask;
						}
					rx_mask <<= 1;
					if ( --bits_left_in_rx<=0 )
						{
						flag_rx_waiting_for_stop_bit = TRUE;
						}
					}
				}
			}
		}
	}

void set_timer_interrupt( timer_isr )  //    Enables the timer interrupt.
{
EA=1;
ET2 =1;
TR2 =1;

}

char _getchar( void )
	{
           do
		{
		while ( qout==qin )
			{
			idle();
			}
		ch = inbuf[qout] & 0xFF;
		dis_cmd(0xC1);
        dis_data(ch);
		if ( ++qout>=IN_BUF_SIZE )
			{
			qout = 0;
			}
		}
	while ( ch==0x0A || ch==0xC2 );
	return( ch );
	}

void flush_input_buffer( void )
	{
	qin = 0;
	qout = 0;
	}

char kbhit( void )
	{
	return( qin!=qout );
	}

void turn_rx_on( void )
	{
	flag_rx_off = FALSE;
	}

void turn_rx_off( void )
	{
	flag_rx_off = TRUE;
	}

void init_uart( void )
	{
	flag_tx_ready = FALSE;
	flag_rx_ready = FALSE;
	flag_rx_waiting_for_stop_bit = FALSE;
	flag_rx_off = FALSE;
	rx_num_of_bits = 10;
	tx_num_of_bits = 10;

	set_tx_pin_low();
        timer_set();
	set_timer_interrupt( timer_isr ); 	
	}
void main()
{
P2=0x00;
ch=0;
lcdport=0;


lcd_init();
dis_cmd(0x01);
turn_rx_on();
while(1)
{
dis_cmd(0x01);

init_uart();
flush_input_buffer();

_getchar();
}
}
i have modified code for receiving data only....my doubt is code not entering function timer_isr()..
thank you...
 

init_uart() cannot be in while(1) loop. It should be outside while(1) loop. If it is inside while(1) loop the UART is initialized on every loop of while(1).
 

@bigdogguru.....
please find the code...please suggest me any changes bcz m not getting any character through softUART...
Code:
#include<reg51f.h>
#include<stdio.h>
#include<string.h>

#define BAUD_RATE		9600.0

#define IN_BUF_SIZE		256

#define TRUE 1
#define FALSE 0

#define port P0            
#define lcdport P1  //14,13,12,11 pins of lcd and 1.7,1.6,1.5,1.4 of controller

sbit rs=port^0;        //Register select 
sbit rw=port^1;        //Read/Write 
sbit en=port^2;        //Enable pin



static unsigned char		inbuf[IN_BUF_SIZE];
static unsigned char		qin;
static unsigned char		qout;

static char 			flag_rx_waiting_for_stop_bit;
static char 			flag_rx_off;
static char 			rx_mask;
static char 			flag_rx_ready;
static char 			flag_tx_ready;
static char 			timer_rx_ctr;
static char 			timer_tx_ctr;
static char 			bits_left_in_rx;
static char 			bits_left_in_tx;
static char 			rx_num_of_bits;
static char 			tx_num_of_bits;
static char			internal_rx_buffer;
static char			internal_tx_buffer;
static char			user_tx_buffer;

sbit rx_pin=P2^0;
sbit tx_pin=P2^1;

char ch=0;




void delay(unsigned int count)    //Function to provide delay
{
    int i,j;
     for(i=0;i<count;i++)
     for(j=0;j<1100;j++);
}


/**************************** START OF LCD FUNCTIONS ***********************/
void lcdcmd(char cmdout)
{
lcdport=cmdout;
rs=0;
rw=0;
en=1;
delay(10);
en=0;
}
 
void lcddata(char dataout)
{
	lcdport=dataout;
rs=1;
rw=0;
en=1;
delay(10);
en=0;
}

void dis_cmd(char cmd_value)
{
	char cmd_value1;
	
		cmd_value1 = cmd_value & 0xF0;		//mask lower nibble because PA4-PA7 pins are used. 
	lcdcmd(cmd_value1);			// send to LCD
 
	cmd_value1 = ((cmd_value<<4) & 0xF0);	//shift 4-bit and mask
	lcdcmd(cmd_value1);			// send to LCD
}						
 
 
void dis_data(char data_value)
{
	char data_value1;
	
	data_value1=data_value&0xF0;
	lcddata(data_value1);
 
	data_value1=((data_value<<4)&0xF0);
	lcddata(data_value1);
}

void lcd_init()	// fuction for intialize 
{
	dis_cmd(0x02);		// to initialize LCD in 4-bit mode.
	dis_cmd(0x28);		//to initialize LCD in 2 lines, 5X7 dots and 4bit mode.
	dis_cmd(0x0C);
	dis_cmd(0x06);
	dis_cmd(0x80);
}
/************************ END OF LCD FUNCTIONS **************************/



char get_rx_pin_status(void)  //Returns 0 or 1 dependent on whether the receive pin is high or low.
{
if(rx_pin==1)
{
return 0;
}
else 
return 1;
}

void set_tx_pin_high(void)  //    Sets the transmit pin to the high state.
{
tx_pin=1;
}

void set_tx_pin_low(void)  //    Sets the transmit pin to the low state.
{
tx_pin=0;
}

void idle(void)        //    Background functions to execute while waiting for input.
{

unsigned char i=0,data0[]="idle";
dis_cmd(0xC1);
while(data0[i]!='\0')
   {
dis_data(data0[i]);
delay(20);
i++;
}
}

void timer_set(  )  //    Sets the timer to 3 times the baud rate.
{
T2CON   = 0x04;   // Load Timer 2 control register

   TH2     = 0xFF;  // Load Timer 2 high byte
   RCAP2H  = 0xFF;  // Load Timer 2 reload capt. reg. high byte
   TL2     = 0xE0; // Load Timer 2 low byte
   RCAP2L  = 0xE0; // Load Timer 2 reload capt. reg. low byte

   //Disable Interrupt Service Routine
   //ET2     = 0;
   //TR2   = 0;        
}



void timer_isr(void) interrupt 5
	{
	char mask,start_bit, flag_in;

// Transmitter Section
	if ( flag_tx_ready )
		{
		if ( --timer_tx_ctr<=0 )
			{
			mask = internal_tx_buffer&1;
			internal_tx_buffer >>= 1;
			if ( mask )
				{
				set_tx_pin_high();
				}
			else
				{
				set_tx_pin_low();
				dis_cmd(0x80);
					dis_data(48);
				}
			
			timer_tx_ctr = 3;
			if ( --bits_left_in_tx<=0 )
				{
				flag_tx_ready = FALSE;
				}
			}
		}
// Receiver Section
	if ( flag_rx_off==FALSE )
		{
		if ( flag_rx_waiting_for_stop_bit )
			{
			if ( --timer_rx_ctr<=0 )
				{
				flag_rx_waiting_for_stop_bit = FALSE;
				flag_rx_ready = FALSE;
				internal_rx_buffer &= 0xFF;
				if ( internal_rx_buffer!=0xC2 )
					{
					inbuf[qin] = internal_rx_buffer;
                    qin++;
					dis_cmd(0x80);
					dis_data(53);
					if ( ++qin>=IN_BUF_SIZE )
						{
						qin = 0;
						}
					}
				}
			}
		else		// rx_test_busy
			{
			if ( flag_rx_ready==FALSE )
				{
				start_bit = get_rx_pin_status();
// Test for Start Bit
				if ( start_bit==0 )
					{
					flag_rx_ready = TRUE;
					internal_rx_buffer = 0;
					timer_rx_ctr = 4;
					bits_left_in_rx = rx_num_of_bits;
					rx_mask = 1;
					}
				}
			else	// rx_busy
				{
				if ( --timer_rx_ctr<=0 )
					{				// rcv
					timer_rx_ctr = 3;
					flag_in = get_rx_pin_status();
					if ( flag_in )
						{
						internal_rx_buffer |= rx_mask;
						}
					rx_mask <<= 1;
					if ( --bits_left_in_rx<=0 )
						{
						flag_rx_waiting_for_stop_bit = TRUE;
						}
					}
				}
			}
		}
	}




void set_timer_interrupt(timer_isr)  //    Enables the timer interrupt.
{

EA=1;
ET2 =1;
TR2 =1;

}



char _getchar( void )
	{
	do
		{
		while ( qout==qin )
			{
			idle();
			}
		ch = inbuf[qout]& 0xFF;
		dis_cmd(0xC1);
        dis_data(ch);
		if ( ++qout>=IN_BUF_SIZE )
			{
			qout = 0;
			}
		}
	while ( ch==0x0A || ch==0xC2 );
	return( ch );
	}


/*void _putchar(char ch )
	{
	while ( flag_tx_ready );
	user_tx_buffer = ch;

// invoke_UART_transmit
	timer_tx_ctr = 3;
	bits_left_in_tx = tx_num_of_bits;
	internal_tx_buffer = (user_tx_buffer<<1) | 0x200;
	flag_tx_ready = TRUE;
    }*/

	void send(char ch)
	{
	while ( flag_tx_ready );
	user_tx_buffer = ch;

// invoke_UART_transmit
	timer_tx_ctr = 3;
	bits_left_in_tx = tx_num_of_bits;
	internal_tx_buffer = (user_tx_buffer<<1) | 0x200;
	flag_tx_ready = TRUE;
    }

void flush_input_buffer( void )
	{
	inbuf[IN_BUF_SIZE]=0;
	//qin = 0;
	//qout = 0;
	}


char kbhit( void )
	{
	return( qin!=qout );
	}


void turn_rx_on( void )
	{
	flag_rx_off = FALSE;
	}


void turn_rx_off( void )
	{
	flag_rx_off = TRUE;
	}




void init_uart( void )
	{
	flag_tx_ready = FALSE;
	flag_rx_ready = FALSE;
	flag_rx_waiting_for_stop_bit = FALSE;
	flag_rx_off = FALSE;
	rx_num_of_bits = 10;
	tx_num_of_bits = 10;

	set_tx_pin_low();

	timer_set();
	set_timer_interrupt(timer_isr); 	// Enable timer interrupt
	}


void main()
{
char a,l=0;
P2=0x00;
//ch=0;
lcdport=0;
lcd_init();
dis_cmd(0x01);

init_uart();
turn_rx_on();
while(1)
{
a=kbhit();
if(a==1)
{
_getchar();
}

}
}

ITS URGENT...please reply fast....thnks
 

I do not have an AT89C51 available, however I do have a few AT89S52 lying around.

So, I'll test you code on an AT89S52 and see if I can get it to function as expected.

What crystal frequency are you currently using?



BigDog
 
ok...my crystal frequency is 11.0592MHz....

Okay.

So you are not get any traffic either direction?

Of course the problem with the AT89 families of 8051s, is you can debug in-circuit unless you have an ICE.


BigDog
 
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top