Clock Ticks per command - UART

Discussion in 'Programmer's Corner' started by AgentSmithers, Feb 23, 2015.

  1. AgentSmithers

    Thread Starter Active Member

    Jan 14, 2011
    Hi everyone!
    I'm almost wrapped up on getting this Soft UART down to a science, So I'll sound by laying down my foundation and see if I'm on the right track. I am currently hooked up to a GPS module and am receiving a 4800 BUAD communication from the unit. Right now I am sleeping in Microsecond's to help bitbang the incoming stream. However what is the best way to do this?

    1: 1Second / 4800Buad / = 0.00020833333
    2: A different forumla is required?

    Should I always have the UC sleep in US or should I sleep by Ticks?

    Inbetween bytes coming through the communication I need to check to see if the Char I received was a '$' and a LF on the end to mark the end of the communication. However It appears it effects the timing of the incoming message. What is the best way to resolve this issue by the book? Calculate how much time in UC the checks take and subtract it from the sleep in UC (Some what calibrate it to the code) or is there another alternative? If I do calculate the difference it appears my sending and recv timing will have to be a different value because this check won't exist when sending data?
    Thank you for your input!

    Code (Text):
    2. while(true)
    3.     {
    4.         while(PINA & (1<<UART_GPSRX_INTERRUPT))
    5.         {
    6.         }
    8.         _delay_us(SleepRX4800 * 1.5);
    9.         for(uint8_t i = 0; i < 8; i += 1)
    10.         {
    11.             if(PINA & (1<<UART_GPSRX_INTERRUPT)) //RX PIN IS HIGH
    12.             {
    13.                 uart_GPS_rx_buffer[uart_GPS_rx_buff_end] |= (1 << i); //RX PIN IS HIGH, try not to change any code here its timing sensitive
    14.             }
    15.             else
    16.             {
    17.                 uart_GPS_rx_buffer[uart_GPS_rx_buff_end] &= ~(1 << i); //RX PIN IS LO
    18.             }
    20.             if(i != (UART_RX_BUFFER_SIZE - 1))
    21.             {
    22.                 _delay_us(SleepRX4800);
    23.             }
    24.         }
    26.         if(uart_GPS_rx_buffer[0] == '$' && uart_GPS_rx_buffer[uart_GPS_rx_buff_end] == 0x0A)
    27.         {
    28.             break;
    29.         }
    31.         if(uart_GPS_rx_buffer[0] == '$')
    32.         {
    33.             uart_GPS_rx_buff_end++;
    34.         }
    35.     }
  2. Papabravo


    Feb 24, 2006
    If every transmitter and receiver operated at the exact same frequency then your method might work. In practice different ends of the cable will have different bit timing. I don't think there is much point in going to sleep between bits. Since the communications are asynchronous you can sleep between characters. That way if the talker on the other end has a fast crystal you won't miss anything.
  3. MrChips


    Oct 2, 2009
    With literally thousands of MCUs with UARTs to choose from, why are you using a software UART instead of a hardware solution?
  4. AgentSmithers

    Thread Starter Active Member

    Jan 14, 2011
    PapaBravo, Thanks for the input however I am not following. What is an alternative to sleeping when waiting for the next signal when bitBanging?

    I am choosing to use a Software UART because I want to learn and I want to understand how it work's. i am aware of plenty of ATMega's that have hardware UART but I rather educate myself and overcome this challenge rather then buying myself out of it.

    Thanks both for the reply.
  5. Papabravo


    Feb 24, 2006
    The alternative to sleeping is to monitor the time base to determine the next sample point or use a periodic interrupt to determine the next sample point. Waking up from sleep is not very precise from a timing point of view. This has to do with how long it takes to stabilize the oscillator and come out of sleep state.
  6. John P

    AAC Fanatic!

    Oct 14, 2008
    Use an initial edge-triggered interrupt to detect the start bit of each character, then a timer-based interrupt to read each data bit. I'd call it fairly challenging to do this however, if you haven't got an oscilloscope to check the timing as you go along.
  7. bzznxlad

    New Member

    Dec 29, 2014
    I definitely agree. It's nonsense to invent a wheel the second time.
  8. AgentSmithers

    Thread Starter Active Member

    Jan 14, 2011
    I do use the falling Edge to detect the start bit then after that use delay_us to delay inbetween bit sampling. Is this what you are saying is the correct way?
    I use The ATTiny84 with a 8MHZ oscillator accurate enough for 9600buad and in code using ISR(PCINT_vect) to detect these changes then find if its rising or falling then execute my code above.
    But is that the best way to implement it from a software point of view?

    Agreed, However education isn't nonsense and thus I find myself wanting to continue my way to figuring this out instead of buying my way through this.