I need some code translated for me.

This code was posted 2 or 3 years ago from AVR freaks and the user is probably moved on. Therefore, I have been trying to understand what is going on line by line. I know that the user is pulsing the TX pin high and low for specific delay times but, I am having trouble understanding the lines that look like bit shifting and compounding. Basically, anywhere there are things that look like "bitwise" code, I get confused.

If someone would have time to do something like...///"this line he is compound x and y to get x(y)"
Or other wise say TX_PORT &= ~_BV(TX_BIT); ///"this line means this".

I would be grateful for any help or direction to help me understand what this code is doing.

Thanks,
Mark

Sure, here is the init function. I just send address 0x33 and 
my Accord's ECU responded correctly. I didn't bother using the UART
 for such a slow baud, just software bit toggling. 

Code:

void send_address(uint8_t addr) { 
   uint8_t i; 
   uint8_t temp; 
    
   /* idle high */ 
   TX_PORT |= _BV(TX_BIT); 
   TX_DDR  |= _BV(TX_BIT); 
    
   /* required idle delay w0 (2ms), be safe with 4ms */ 
   _delay_ms(4); 
    
   /* start bit */ 
   TX_PORT &= ~_BV(TX_BIT); 
   /* this is at 5bps */ 
   _delay_ms(200); 
    
   /* send byte */ 
   for (i = 0; i < 8; i++) { 
      temp = (addr >> i) & 0x01; 
      if (((TX_PORT & _BV(TX_BIT)) >> TX_BIT) == temp) { 
         /* already at the correct level, do nothing */ 
      } else { 
         if (0 != temp) { 
            TX_PORT |= _BV(TX_BIT); 
         } else { 
            TX_PORT &= ~_BV(TX_BIT); 
         } 
      } 
      _delay_ms(200); 
   } 
    
   TX_PORT |= _BV(TX_BIT); 
   _delay_ms(200); 
    
   /* already idling high on TX */ 
    
   return; 
}

From the avr-libc user manual (get it here):

11.6 What is all this _BV() stuff about?
When performing low-level output work, which is a very central point in microcontroller
programming, it is quite common that a particular bit needs to be set or cleared
in some IO register. While the device documentation provides mnemonic names for
the various bits in the IO registers, and the AVR device-specific IO definitions reflect
these names in definitions for numerical constants, a way is needed to convert a bit
number (usually within a byte register) into a byte value that can be assigned directly
to the register. However, sometimes the direct bit numbers are needed as well (e. g. in
an SBI() instruction), so the definitions cannot usefully be made as byte values in the
first place.

So in order to access a particular bit number as a byte value, use the _BV() macro.
Of course, the implementation of this macro is just the usual bit shift (which is done
by the compiler anyway, thus doesn’t impose any run-time penalty), so the following
applies:
_BV(3) => 1 << 3 => 0x08

However, using the macro often makes the program better readable.
"BV" stands for "bit value", in case someone might ask you. :slight_smile:

Example: clock timer 2 with full IO clock (CS2x = 0b001), toggle OC2 output on
compare match (COM2x = 0b01), and clear timer on compare match (CTC2 = 1). Make
OC2 (PD7) an output.
TCCR2 = _BV(COM20)|_BV(CTC2)|_BV(CS20);
DDRD = _BV(PD7);

So, the following statement clears the TX_BIT in the TX_PORT register. Refer to the datasheet to understand the register and bit mnemonics. Not sure which datasheet to refer you to, as TX_PORT and TX_BIT aren't in the few AVR datasheets that I'm familiar with.

TX_PORT &= ~_BV(TX_BIT)

TX_PORT could be any port register, I'm guessing, because it looks like the code is just, doing bit-banging.

Thank you Jack Christensen! You have solved the BV mystery that I was hung up in! I followed your link for the manual and found the quote for BV on page 77. I am that much wiser now.

@Awol, I think you are correct about the TX_PORT being a general define for a port register. I wasn't sure about it but, when it would not compile I suspected it as a variable that needed defined somewhere.

Thanks you guys have gotten me closer to understanding how to put this to use.

Glad to help. I was puzzled by the _BV thing at first too. Now I find I use it... :fearful:

void send_address(uint8_t addr) { 
   uint8_t i; 
   uint8_t temp; 
    
   /* idle high */ 
   TX_PORT |= _BV(TX_BIT); // digitalWrite(TX_BIT on TX_PORT, HIGH);
   TX_DDR  |= _BV(TX_BIT); // pinMode(TX_BIT on TX_PORT, OUTPUT);
    
   /* required idle delay w0 (2ms), be safe with 4ms */ 
   _delay_ms(4); //delay(4);
    
   /* start bit */ 
   TX_PORT &= ~_BV(TX_BIT); // digitalWrite(TX_BIT on TX_PORT, LOW);
   /* this is at 5bps */ 
   _delay_ms(200); // delay(200);
    
   /* send byte */ 
   for (i = 0; i < 8; i++) { // go 8 times
      temp = (addr >> i) & 0x01;  //temp is the i-th bit of addr
      if (((TX_PORT & _BV(TX_BIT)) >> TX_BIT) == temp) { // if (digitalRead(TX_BIT) == temp)
         /* already at the correct level, do nothing */ 
      } else { 
         if (0 != temp) { // if temp isn't 0
            TX_PORT |= _BV(TX_BIT); //digitalWrite(TX_BIT, HIGH);
         } else { 
            TX_PORT &= ~_BV(TX_BIT); //digitalWrite(TX_BIT, LOW);
         } 
      } 
      _delay_ms(200); //delay(200);
   } 
    
   TX_PORT |= _BV(TX_BIT); //digitalWrite(TX_BIT, HIGH);
   _delay_ms(200);  //delay(200);
    
   /* already idling high on TX */ 
    
   return; 
}

The entire thing is essentially a copy of shiftOut()

...but without the clock. :wink:

The start and stop bits are something of a give away.

AWOL:
...but without the clock. :wink:

The start and stop bits are something of a give away.

shiftOut(TX_BIT, -1, LSBFIRST, addr);

Thank you WizenedEE for taking the time to comment every part of that code! I looked up shiftOut() and I can see the similarity. :slight_smile:
I am going to take parts of the code and do some tests with an led and see if I can see it in action.

@Awol thanks for pointing out the "without the clock" part, I found what you mean in the shift() tutorial.

I will try to make good use of this new knowledge, thanks again!