Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Bit Banging

Status
Not open for further replies.

bhodder

New Member
Hi I am trying to use bit banging as well, to receive data and then send it back out on a hardware usart. However; when I send the received data back out it it does not send what I have sent to the pics software usart. What would cause this, as if i send it back out the bit banged port it works great.

Thanks,

Blake
 
bit bang

I am working with a UART and bit banging but what I need is to be able to detect an idle line on the serial port when there is 11 highs before a start bit. Can this be done via hardware usart or do I need to use Bit Banging?
 
Last edited by a moderator:
I am working with a UART and bit banging but what I need is to be able to detect an idle line on the serial port when there is 11 highs before a start bit. Can this be done via hardware usart or do I need to use Bit Banging?
"When there is 11 highs" is that eleven or three? Decimal or Binary?
 
hi,
For the software UART look at Nigels Tutorials, link near my signature.
 
We can do this with a hardware UART and an on chip timer easily.

J1708 uses RA-485 protocol @ 9600bps. One bit time = 104.2uS, which x11 is 1.14mS for 11 bit times (J1708 buss access time). A J1708 "message" consists of one message byte, up to 19 data bytes (known as "characters"), and one checksum byte for a total maximum of 21 characters per "message" (1 "character" = 1 "byte"). There cannot be more than two bit times between each character in the message (enough time for 1 stop bit and 1 start bit between bytes), and there must be at least 10 bit times between each message.

This means that when transmitting a message, you want to transmit all of the bytes within the message one right after the other (super easy to do), then after the last byte of the message is sent (the checksum byte), you must wait a minimum of 10 bit times before the next message is sent.

About that...each message also has a "priority" level, which is going to set the buss access time. The priority levels are 1-8 (with level 1 being the highest priority), and the buss access time for each message is 10 bit times + 2x the priority level of the message. So if the priority of the message is 1, we need 10 bit times + (2 x 1) = 12 bit times total. If the priority level of the message is 5, we need 10 bit times + (2 x 5) = 20 bit times total between messages.

Once the checksum byte has been received, we can use TMR0 to create a 1.14mS delay or we can construct a software delay for such to wait 11 bit times prior to transmitting the received bytes down the buss.

A couple of things we need to know -

1) What PIC are you using?

2) What oscillator config are you using and at what speed (i.e. internal oscillator, external crystal, etc etc)?

Setting the UART up is simple to do once you know your Fosc speed. But we need to know what Fosc speed is being used in order to know what value to write to the baud rate generator in the PIC (SPBRG).

Now...the difficult part...we're going to need a way to monitor the transmit buss for 10 bit times to ensure that the tx buss has been pulled high for that period of time. This is actually simple to implement if we tie a PIC I/O line to the tx buss and set that line as an input. We can use TMR0 to set up a 1.042mS delay. While TMR0 is running, the input line is monitoring the tx line and incrementing a counter that we initialize to 0 before running the sample loop. Each time the tx line goes low within that delay time, the counter gets incremented. Then once TMR0 overflows, we jump into an interrupt handler where we check the counter. If the counter value is anything other than 0, we know that something else accessed the tx buss in that time so we must reset the counter, reset TMR0, then wait again. However, if the counter still equals 0, then we know we can go ahead and transmit down the buss.

A little bit involved but definitely possible. Answer my above questions and we can proceed further with this.
 
Last edited:
We can do this with a hardware UART and an on chip timer easily.

J1708 uses RA-485 protocol @ 9600bps. One bit time = 104.2uS, which x11 is 1.14mS for 11 bit times (J1708 buss access time). A J1708 "message" consists of one message byte, up to 19 data bytes (known as "characters"), and one checksum byte for a total maximum of 21 characters per "message" (1 "character" = 1 "byte"). There cannot be more than two bit times between each character in the message (enough time for 1 stop bit and 1 start bit between bytes), and there must be at least 10 bit times between each message.

This means that when transmitting a message, you want to transmit all of the bytes within the message one right after the other (super easy to do), then after the last byte of the message is sent (the checksum byte), you must wait a minimum of 10 bit times before the next message is sent.

About that...each message also has a "priority" level, which is going to set the buss access time. The priority levels are 1-8 (with level 1 being the highest priority), and the buss access time for each message is 10 bit times + 2x the priority level of the message. So if the priority of the message is 1, we need 10 bit times + (2 x 1) = 12 bit times total. If the priority level of the message is 5, we need 10 bit times + (2 x 5) = 20 bit times total between messages.

Once the checksum byte has been received, we can use TMR0 to create a 1.14mS delay or we can construct a software delay for such to wait 11 bit times prior to transmitting the received bytes down the buss.

A couple of things we need to know -

1) What PIC are you using?

2) What oscillator config are you using and at what speed (i.e. internal oscillator, external crystal, etc etc)?

Setting the UART up is simple to do once you know your Fosc speed. But we need to know what Fosc speed is being used in order to know what value to write to the baud rate generator in the PIC (SPBRG).

Now...the difficult part...we're going to need a way to monitor the transmit buss for 10 bit times to ensure that the tx buss has been pulled high for that period of time. This is actually simple to implement if we tie a PIC I/O line to the tx buss and set that line as an input. We can use TMR0 to set up a 1.042mS delay. While TMR0 is running, the input line is monitoring the tx line and incrementing a counter that we initialize to 0 before running the sample loop. Each time the tx line goes low within that delay time, the counter gets incremented. Then once TMR0 overflows, we jump into an interrupt handler where we check the counter. If the counter value is anything other than 0, we know that something else accessed the tx buss in that time so we must reset the counter, reset TMR0, then wait again. However, if the counter still equals 0, then we know we can go ahead and transmit down the buss.

A little bit involved but definitely possible. Answer my above questions and we can proceed further with this.


Great, thanks for the response.

I am using the PIC18F25K80 using and external crystal at 3.686MHz. My FOSC setting is XT.

As to transmitting, I do not need to transmit down the same bus as I will be taking the received data and sending it out my second USART to an embedded PC tty level serial port. So once I have detected the new message I need to receive the incomming message and send it after I have sent a message to say this is a new message.

Thanks.
 
We can do this with a hardware UART and an on chip timer easily.

J1708 uses RA-485 protocol @ 9600bps. One bit time = 104.2uS, which x11 is 1.14mS for 11 bit times (J1708 buss access time). A J1708 "message" consists of one message byte, up to 19 data bytes (known as "characters"), and one checksum byte for a total maximum of 21 characters per "message" (1 "character" = 1 "byte"). There cannot be more than two bit times between each character in the message (enough time for 1 stop bit and 1 start bit between bytes), and there must be at least 10 bit times between each message.

This means that when transmitting a message, you want to transmit all of the bytes within the message one right after the other (super easy to do), then after the last byte of the message is sent (the checksum byte), you must wait a minimum of 10 bit times before the next message is sent.

About that...each message also has a "priority" level, which is going to set the buss access time. The priority levels are 1-8 (with level 1 being the highest priority), and the buss access time for each message is 10 bit times + 2x the priority level of the message. So if the priority of the message is 1, we need 10 bit times + (2 x 1) = 12 bit times total. If the priority level of the message is 5, we need 10 bit times + (2 x 5) = 20 bit times total between messages.

Once the checksum byte has been received, we can use TMR0 to create a 1.14mS delay or we can construct a software delay for such to wait 11 bit times prior to transmitting the received bytes down the buss.

A couple of things we need to know -

1) What PIC are you using?

2) What oscillator config are you using and at what speed (i.e. internal oscillator, external crystal, etc etc)?

Setting the UART up is simple to do once you know your Fosc speed. But we need to know what Fosc speed is being used in order to know what value to write to the baud rate generator in the PIC (SPBRG).

Now...the difficult part...we're going to need a way to monitor the transmit buss for 10 bit times to ensure that the tx buss has been pulled high for that period of time. This is actually simple to implement if we tie a PIC I/O line to the tx buss and set that line as an input. We can use TMR0 to set up a 1.042mS delay. While TMR0 is running, the input line is monitoring the tx line and incrementing a counter that we initialize to 0 before running the sample loop. Each time the tx line goes low within that delay time, the counter gets incremented. Then once TMR0 overflows, we jump into an interrupt handler where we check the counter. If the counter value is anything other than 0, we know that something else accessed the tx buss in that time so we must reset the counter, reset TMR0, then wait again. However, if the counter still equals 0, then we know we can go ahead and transmit down the buss.

A little bit involved but definitely possible. Answer my above questions and we can proceed further with this.
Hi,

I understand what you are saying, my question now is how would I setup timer0 to the count of 1.14ms?
 
There is C code on this page for very simple sending and receiving bit-banged serial with a PIC;
https://www.romanblack.com/bitbangserial.htm

It is free from any hardware requirements (other than a timer) so you can send multiple serial streams out multiple PIC pins (no limit on number of devices) although only one pin can transmit at once.
 
Hi,

I understand what you are saying, my question now is how would I setup timer0 to the count of 1.14ms?

Not sure why you're using an "off" crystal speed instead of going with something like an even 4MHz but -

The instruction clock speed = Fosc / 4 so @ 3.686MHz, our instruction clock runs at 921.5kHz, or 0.9215MHz. This means that in 1 second the PIC can execute 921,500 instructions per second, which translates to 1 instruction every 1.09uS.

With TMR0 set up as an 8 bit timer, the TMR0 register will start counting from 0 once every instruction cycle (once every 1.09uS), and will count up to 255. Once at 255, it overflows from 255 to 0 for a total of 256 counts, and sets the TMR0 interrupt flag. Well, 1.09uS x 256 counts = 279uS. This means that the TMR0 interrupt flag will go high once every 279uS.

So...we COULD set up a counter that gets preloaded with a set value to count how many times the flag goes high to know when 1.14mS has passed. However, fortunately TMR0 has a built in hardware prescaler just for this purpose. The prescaler allows us to slow the timer down so that instead of counting up by 1 once every 1.09uS, we can set a ratio so that it will count up once every 2 cycles, or once every 4 cycles (1:4), every 8 (1:8), so on and so forth all the way up to once every 256 cycles (1:256).

With an "off" crystal speed like 3.686MHz, the closest we can get is 1.12mS, which would be right between 10 and 11 bit times. According to the J1708 specification, this should work as the minimum hold time is 10 bit times so this is slightly longer. With a 1:4 prescale, TMR0 will increment its value every 4 instruction cycles, or once every 4.36uS. This will make TMR0 overflow once every 1.12mS (4.36uS x 256 = 1.12mS). This also means that the TMR0 interrupt flag will get set high once every 1.12mS.

Now the question I have is when your PIC receives data, is it just relaying this data to a PC so that you can read it? Or does it have to also send it down the transmit buss once it's been received and "mirror" the data to the receiving PC?
 
Last edited:
I'd just like to add something to Jon's comprehensive timer advice!

The bit banging code I linked to in post #10 uses the timer (like Jon's example) but adds a value to it each bit, this enables finer adjustment of the timed period for each bit. It also retains the last bit "time error" within the timer so it is compensated on the very next bit, giving excellent bit banging frequency stability.
 
Not sure why you're using an "off" crystal speed instead of going with something like an even 4MHz but -

The instruction clock speed = Fosc / 4 so @ 3.686MHz, our instruction clock runs at 921.5kHz, or 0.9215MHz. This means that in 1 second the PIC can execute 921,500 instructions per second, which translates to 1 instruction every 1.09uS.

With TMR0 set up as an 8 bit timer, the TMR0 register will start counting from 0 once every instruction cycle (once every 1.09uS), and will count up to 255. Once at 255, it overflows from 255 to 0 for a total of 256 counts, and sets the TMR0 interrupt flag. Well, 1.09uS x 256 counts = 279uS. This means that the TMR0 interrupt flag will go high once every 279uS.

So...we COULD set up a counter that gets preloaded with a set value to count how many times the flag goes high to know when 1.14mS has passed. However, fortunately TMR0 has a built in hardware prescaler just for this purpose. The prescaler allows us to slow the timer down so that instead of counting up by 1 once every 1.09uS, we can set a ratio so that it will count up once every 2 cycles, or once every 4 cycles (1:4), every 8 (1:8), so on and so forth all the way up to once every 256 cycles (1:256).

With an "off" crystal speed like 3.686MHz, the closest we can get is 1.12mS, which would be right between 10 and 11 bit times. According to the J1708 specification, this should work as the minimum hold time is 10 bit times so this is slightly longer. With a 1:4 prescale, TMR0 will increment its value every 4 instruction cycles, or once every 4.36uS. This will make TMR0 overflow once every 1.12mS (4.36uS x 256 = 1.12mS). This also means that the TMR0 interrupt flag will get set high once every 1.12mS.

Now the question I have is when your PIC receives data, is it just relaying this data to a PC so that you can read it? Or does it have to also send it down the transmit buss once it's been received and "mirror" the data to the receiving PC?

Hi Jon,

Thanks for your help and sugestions. No the PIC does not have to send down the transmission line. It simply needs to detect when it is a new message and send a 0x01 to signify that it is a new message and then relay the J1708 data to the PC.

thanks,

Blake
 
Alright, After some time I have decided to use a 4MHz crystal. I am working on setting up TMR0 and it seems to work but what happens is that I get a framing error on the output of the usart on the PIC. what would cause the framing error?

Blake
 
With the 4MHz crystal and a 1:4 prescale, TMR0 should overflow/interrupt every 1024uS, which is exactly 10 bit times.

In regards to the framing error, a baud rate mismatch between the PIC and the receiving device you're transmitting from the PIC to. The PIC should be set to 19.2Kbps to meet the J1708 spec. This also means that the device that the PIC is transmitting to also needs to be set to 19.2Kbps.

The only other way around that would be to disable continuous receive on the PIC while it is transmitting to the receiving device. This will allow you to switch the baud rate on the PIC to match the receiving device's baud rate by altering the value in SPBRG. To do this, you would have to -

Upon receiving the data to be transmitted -

1) Disable continuous receive

2) Modify the SPBRG value to set the PIC to the baud rate of the receiving device that the PIC is transmitting to

3) Transmit the data

4) Re-modify the value in SPBRG to set the PIC's baud rate to 19.2Kbps

5) Enable continuous receive

The only down side to this is that the PIC cannot receive data while it is transmitting so you would be forced to run 1/2 duplex. Unfortunately there is no way to make the UART rx at one baud rate while transmitting on another since it only has 1 baud clock.
 
Last edited:
With the 4MHz crystal and a 1:4 prescale, TMR0 should overflow/interrupt every 1024uS, which is exactly 10 bit times.

In regards to the framing error, a baud rate mismatch between the PIC and the receiving device you're transmitting from the PIC to. The PIC should be set to 19.2Kbps to meet the J1708 spec. This also means that the device that the PIC is transmitting to also needs to be set to 19.2Kbps.

The only other way around that would be to disable continuous receive on the PIC while it is transmitting to the receiving device. This will allow you to switch the baud rate on the PIC to match the receiving device's baud rate by altering the value in SPBRG. To do this, you would have to -

Upon receiving the data to be transmitted -

1) Disable continuous receive

2) Modify the SPBRG value to set the PIC to the baud rate of the receiving device that the PIC is transmitting to

3) Transmit the data

4) Re-modify the value in SPBRG to set the PIC's baud rate to 19.2Kbps

5) Enable continuous receive

The only down side to this is that the PIC cannot receive data while it is transmitting so you would be forced to run 1/2 duplex. Unfortunately there is no way to make the UART rx at one baud rate while transmitting on another since it only has 1 baud clock.

Hi Jon,

I am acctually using two UARTs so one to receive the J1708 data and then one to send it out.

Also the framing error only happens once I use the timer. If I leave the timer off I have no problems.
 
Hi Jon,

I am acctually using two UARTs so one to receive the J1708 data and then one to send it out.

Also the framing error only happens once I use the timer. If I leave the timer off I have no problems.

OK...can you explain to me in detail the routine you're using to send the data to the receiving device step by step?
 
OK...can you explain to me in detail the routine you're using to send the data to the receiving device step by step?

Once I know that it is a new message I notify the receiving device that a new message is coming. To send the data I call a piece of code that takes the RCREG2 and sends it to TXREG1. Therefore sends directly as it comes in. I am now thinking that I probably need to place the received message into a buffer but not sure?
 
Once I know that it is a new message I notify the receiving device that a new message is coming. To send the data I call a piece of code that takes the RCREG2 and sends it to TXREG1. Therefore sends directly as it comes in. I am now thinking that I probably need to place the received message into a buffer but not sure?

Actually...I'm not sure what language you code in but if you're coding in C I think something like this should work -

Code:
unsigned char BUFFER;

void ClrSerErr(void)
{
	CREN = 0;
	DATA = RCREG;
	DATA = RCREG;
	CREN = 1;
}

unsigned char DataRdyUSART()
{
	if(OERR)
	{
		ClrSerErr();
	{
	if(FERR)
	{
		ClrSerErr();
	{
	while(!RCIF);
	return RCREG;
}

void DataSndUSART(unsigned char data)
{
	while(!TXREG);
	TXREG = data;
}

void main(void)
{
	//init code goes here
	while(1)
	{
		DataRdyUSART();
		BUFFER = DataRdyUSART();
		DataSendUSART(BUFFER);
	}
}
 
Last edited:
Actually...I'm not sure what language you code in but if you're coding in C I think something like this should work -

Code:
unsigned char BUFFER;

void ClrSerErr(void)
{
	CREN = 0;
	DATA = RCREG;
	DATA = RCREG;
	CREN = 1;
}

unsigned char DataRdyUSART()
{
	if(OERR)
	{
		ClrSerErr();
	{
	if(FERR)
	{
		ClrSerErr();
	{
	while(!RCIF);
	return RCREG;
}

void DataSndUSART(unsigned char data)
{
	while(!TXREG);
	TXREG = data;
}

void main(void)
{
	//init code goes here
	while(1)
	{
		DataRdyUSART();
		BUFFER = DataRdyUSART();
		DataSendUSART(BUFFER);
	}
}

Thanks, I am coding in C and I was just testing that out. It seems to work ok the only thing is, as I am testing it, I send from my laptop "80 6f c8 b6 b6 06 d7" in hex but receive this: "80 c8 b6 d7 6f b6 06". What would cause that. If I am going through that snippet of code correctly it should receive and send out exactly what it receives.

Also I do have it working with the timer without getting framing errors how ever it sends 2 maybe 3 messages then stops.

here is there portion that deals with the timer:

Code:
void SerRx(void)
	{
		index=0;
		char checksum=0x00;
		do
		{
			index++;
			while(!RC2IF);
				to[index]=RCREG2;
			while(!RC2IF);
			index2=index-1;
			checksum=checksum+to[index];
		}while(checksum!=0x00);
			
	}

void T0_ISR(void)
	{
	if(count>0)
	{
		SerTx(0x01);
		okToSend = 1;
		SerRx();	
		for(char x=1;x<=index;x++)
		{
			SerTx(to[x]);
		}
	}
	count=0;
	TMR0L=0x00;
	TMR0IF=0;
	}
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top