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.

Software UART driven - bit-banging in C (Keil)

Status
Not open for further replies.

Maverickmax

Advanced Member level 1
Joined
Dec 6, 2004
Messages
404
Helped
8
Reputation
16
Reaction score
3
Trophy points
1,298
Activity points
3,689
bit bang uart

Hi

I have been struggling to develop bit-banging in C to implement the UART at the receiver in my AT89C51 chip. My codes didn't work at the moment

If you have already UART software-driven code for receiver in C, please let me know asap. I need it for my wireless project.

Thank you

Maverick Max
 

bit banging

Philips has an application note for bit-banged serial port.

May I suggest that it would be much more accurate if you do it in ASM. In C, it is difficult to predict the timing of your code.
 

bit banging in c

techie said:
Philips has an application note for bit-banged serial port.

May I suggest that it would be much more accurate if you do it in ASM. In C, it is difficult to predict the timing of your code.

Do you have the link?

Maverick Max
 

uart bit banging

No I dont have the link but you can search semiconductor.philips.com for that. search for the term software UART . I think it was for their 87C751 controller. It also might help in searching.
 

bit banging uart

Here is two Application notes from philips for Software driven serial communication routines. it is for 751/752/753 devices but I hope it is applicable for 51 as well.

**broken link removed**

**broken link removed**

the source code which I have reffered earlier from programmers heaven is attached.

Cheers
 

unsigned char buffer_l = 0x00;

Hello again

As you know that I want to develop software UART (bit-banging) for my receiver. Since you could not give me any C code, I have been forced to develop my C code but I am not 100% sure that it would work. You are welcome to use it

I intend to use 4200 Baud therefore 1/baud which yields 416uS.

When the start bit occurs, the first delay will be generated bitwidth/2 (208uS). The Interrupt Service Routine activates which repeats at 8 times for every 416us in order to capture the data bits because i want to detect the data bit in the middle of data bit'speriod.


Finally the delay is generated at twice time (208us + 208us = 416us) to check if the stop bit is 1 then the data bits (buffer_G) is placed in the P1...

After reading various documents from internets, I was thinking of using external interrupt in my code but I am going to save it for later cuz I need to make this code right first.

Any feedback?

Maverick Max

Code:
#include <AT89X52.H>

#define INTERRUPT_Timer_2_Overflow 5
#define OUTPUT P1

void Timer_2_Init(void);
void hardware_delay_208us();

/* --------------------------------------------------------------- */

char buffer_G;
int i_G=0;
sbit DATA_RX = P3^2;

void main(void)
{
   Timer_2_Init();  // Set up Timer 2
   EA = 1;          // Globally enable interrupts
   
   while(1)
   {
   		// Wait for Start bit
		while(DATA_RX == 1)
		{
		}

		//Delay (208uS)
		hardware_delay_208us();
		
		// Is it logic zero
		if (DATA_RX == 0)
		{
		
			// Activate Interrupt Service Routine
			ET2=1;
			TR2=1;
		
			// Wait for Interrupt Service Routine completes 8 times

			while(i_G != 8)
			{

			}

			// set i_G to be zero
			i_G=0;
			

			// Hardware delay 208 (Repeat twice to get 416us)
			hardware_delay_208us();
			hardware_delay_208us();


			// Stop bit 
			if (DATA_RX != 1)
			{
				// Remove the content in buffer_G
		 		buffer_G = buffer_G & 0x00;
			}
			else
			{
			OUTPUT = OUTPUT & buffer_G;
			}
		}
		
   }
}

/* --------------------------------------------------------------- */

void Timer_2_Init(void)
   {
   
   T2CON   = 0x04;   // Load Timer 2 control register

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

   
   ET2     = 0;
   TR2   = 0;        
   }

/* --------------------------------------------------------------- */

void X(void) interrupt INTERRUPT_Timer_2_Overflow
{
 
   	
		
	i_G++;
	if ( DATA_RX ==1)
	{
		buffer_G=(buffer_G & 0x80);
	}
	else
	{
		buffer_G=(buffer_G & 0x00);				
	}
			
	// Shift the data to right at seven times
	if (i_G<7)
	{
		buffer_G=buffer_G>>1;				
	}

	if (i_G == 8)
	{
		//Disable Interrupt Service Routine
		ET2=0;
		TR2=0;
	}
}

/* --------------------------------------------------------------- */

void hardware_delay_208us()
{
	// Configure Timer 0 as a 16-bit timer
	TMOD &= 0xF0; // Clear all TO bits (T1 left unchanged)
	TMOD |= 0x01; // Set required TO bits(T1 left unchanged)

	ET0=0;

	// Value for 50ms delay
	TH0=0xFF; // Timer 0 initial value (High Byte)
	TL0=0x3F; // Timer 0 initial value (LOW Byte)

	TF0=0;	// Clear overflow flag 
	TR0=1;	// Start timer 0

	while (TF0==0);	//Loop until Timer 0 overflows (TF0==1)

	TR0=0;	// Stop Timer 0;
}
 

bit banging c

There seems to be one slight problem. When you detect the first bit, chances are that you will detect it a little time after the actual occuance of the start bit. It depends on your detection methood and software latency. Then if you start your algorithm of waiting half a bit for the center of the start bit, you will probably be somewhere near the end of the start bit, not in the middle.

I suggest that you wait 1/4 bit to start the first bit.
 

bitbang uart

Considering interrupt latencies etc, the point of sampling goes on towards the end. By reducing some count for the timer which is approximately equals interrupt latency and code execution will give proper results.

Any how the function is completely polling for eight bits, interrupt may not be necessary. you can sample eight bits in a while loop for eight times. Again small adjustments in timer count by considering the execution delay will correct the sampling point.

Check the following sample code
Code:
void get_char(void)
{
   unsigned char buffer_l = 0x00, mask_l = 0x01;

   // Wait for Start bit 
   while(DATA_RX == 1) 
   { 
   } 
   
   //Delay (208uS) 
   hardware_delay_208us(); 

   while(mask_l != 0)
   {
      hardware_delay_208us(); 
      hardware_delay_208us(); 
      if(DATA_RX == 1) 
      {
          buffer_l |= mask_l;
      }
      mask_l = mask_l << 1;
   }
   hardware_delay_208us(); 
   hardware_delay_208us();

   if (DATA_RX != 1) 
   { 
      // Remove the content in buffer_G 
      buffer_G = 0x00; 
   } 
   else
   {
      buffer_G =  buffer_l; 
   }
}
 

    Maverickmax

    Points: 2
    Helpful Answer Positive Rating
c code to receive 20 bits from uart

Hi idlebrain

Wow, Your code is far more simple than my familing code.

idlebrain said:
Any how the function is completely polling for eight bits, interrupt may not be necessary. you can sample eight bits in a while loop for eight times. Again small adjustments in timer count by considering the execution delay will correct the sampling point.

Are you saying that I need to reduce the time delay due to execution lantency?

Maverick Max
 

software uart driven - bit-banging in c (keil)

Maverickmax said:
Are you saying that I need to reduce the time delay due to execution lantency?

In the code I have posted,

Some time involved for
1)checking for mask & shifting of mask
2)two functiona calls (call to hardware_delay_208us)
3)sampling RX pin and updating the byte buffer

let us take the amount of delay is T
The problem here is this delay is added for every sample. So sample point moves towards the end by T for each sample, and so it can fall in to the next bit.

So you need to reduce the delay so that T + delay equals to Bit time. Then it will work 100%.

In your interrupt this problem should not be existing because timer is not stopped and reloaded automatically. The interrupt latency of 6 machine cycles 6us (as I remember) is consistent, so sampling will hapen midpoint of bit time + 6us always.

The following code looks not correct, please check
Code:
if(DATA_RX == 1)
{
   buffer_G=(buffer_G | 0x80);             
}
else
{
   buffer_G=(buffer_G & 0x00);             
}

If you AND with 0x00, the last received 1 bits will become zero, if you receive a 0 after some 1 bits. So in else you need to AND with 0x7F.

Code:
if(DATA_RX == 1)
{
   buffer_G=(buffer_G | 0x80);             
}
else
{
   buffer_G=(buffer_G & 0x7F);             
}

I did not obeserve it yesterday. sorry.


Cheers
 

Re: bitbang uart

Considering interrupt latencies etc, the point of sampling goes on towards the end. By reducing some count for the timer which is approximately equals interrupt latency and code execution will give proper results.

Any how the function is completely polling for eight bits, interrupt may not be necessary. you can sample eight bits in a while loop for eight times. Again small adjustments in timer count by considering the execution delay will correct the sampling point.

Check the following sample code
Code:
void get_char(void)
{
   unsigned char buffer_l = 0x00, mask_l = 0x01;

   // Wait for Start bit 
   while(DATA_RX == 1) 
   { 
   } 
   
   //Delay (208uS) 
   hardware_delay_208us(); 

   while(mask_l != 0)
   {
      hardware_delay_208us(); 
      hardware_delay_208us(); 
      if(DATA_RX == 1) 
      {
          buffer_l |= mask_l;
      }
      mask_l = mask_l << 1;
   }
   hardware_delay_208us(); 
   hardware_delay_208us();

   if (DATA_RX != 1) 
   { 
      // Remove the content in buffer_G 
      buffer_G = 0x00; 
   } 
   else
   {
      buffer_G =  buffer_l; 
   }
}

hi idlebrain,
if we use above function there is no need of using timer2 right?
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top