Avr Software Uart In C

I've recently started work on a small project to provide visual notifications from a PC over a Bluetooth connection. I mentioned it on G+ a little while ago, it's essentially a minimalist version of this product.

  1. Avr-tinyuart provides a simple yet highly optimized uart tx function. It can be used to print any information to a terminal or to correlate the data with analog signals on an oscilloscope. The tiny footprint makes it suitable for almost any project. Software only: no UART, timer or interrupt required.
  2. Serial UART Interface with AVR An embedded project/product without a Universal Asynchrounous Receiver Transmiter (UART) interface is unimaginable. Even if the MCU is not talking to another serial device, you'll need it at-least during the development work to speak to your computer.
Uart

Software UART Hi, I'm doing a project who needs to use software UART but I don't know how I could do that. My hardware uart is busy to send information to bluetooth module and I need software uart to send information to rs-232 serial port. The information that i'm sending is not the same, so I can't send by the same channel. AVR serial communication UART tutorial using Embedded C language code program built AVR studio software AVR microcontroller tutorials embedded design system.

I started working on a post describing the work I was doing but it quickly expanded into something much larger than I expected as I started to describe aspects of my ATtiny85 template library which is being used as the basis of the project.

I decided to split the post into a number of smaller ones so I can cover the various topics in detail without swamping you with information. This post, the first in the series, provides an overview of the software UART implementation in the library - how it's implemented and how it's used. The upcoming posts will cover:

  1. Using a HC-05 breakout module with the library. This will include using AT commands to configure the module and basic connections to the ATtiny.
  2. PWM output on the ATtiny and the template libraries equivalent to the analogOut() function in the Arduino library.
  3. Finally the full project including schematics and code. This uses RGB LEDs to provide colour coded notifications under control of a remote PC through Bluetooth. Use it to provide information in a glance - you can control the colour based on whatever data you choose, stock information, website analytics or Bitcoin exchange rate.

For now, a brief introduction to the library and how to use the software UART.

I've mentioned my ATtiny Breakout Board and the associated template library in previous posts but only on a very superficial level. Although this post will concentrate on the software UART implementation it's worth running over it again.

The library is available on GitHub at the link above and the documentation for it can be found here. I've done my best to provide enough information in the project documentation to make it easy to get started. I'd appreciate any feedback you might have on how to improve it.

To use the library as a basis for your own projects simply fork the GitHub project (or clone your own local copy) and start modifying the code in the firmware directory. To get started you only need to start modifying the file hardware.h (which contains the pin assignments and is used to enable or disable various parts of the library) and main.c.

To keep up to date with newer version of the library simply merge the master branch of the original GitHub library into your project every now and then. The majority of updates will be in the firmware/shared and firmware/include directories which contain the implementations and definitions of the library components respectively.

Before I get into the implementation details of the UART functions it's probably best to run through how serial communication appears on the wire. Because we are generating these signals in software it's a good idea to know what is expected and what sort of issues to look out for.

The diagram above shows the voltage levels on the Tx pin when the ASCII character sequence 'AVR' is being sent. Obviously this is what will be seen on the Rx pin as well on the receiver end of the connection. In this case the connection is running at 3.3V levels (not RS232 levels) and the connection is configured for 57.6 KBaud, 8 data bits, 1 stop bit and no parity (57600 8N1). I've marked each character on the diagram along with the values for the individual bits.

The diagram above shows the detail for a single character (in this case the ASCII character 'A'). Even though we are only sending 8 bits of data per character additional bits are required for framing (to allow the receiver to detect the start of a character and to determine it has reached the end). In every case there is a single start bit - this causes the communications line to transition from it's idle state (high) to low for at least the duration of a single bit. The data bits come next starting from the least significant bit (bit 0) to the most (bit 7) and finally, the stop bit. The stop bit ensures the line comes back up to it's idle state for at least one bit.

The width, or duration, of each bit is a function of the baud rate - for the speed we are running at that is 1/57600 seconds per bit (about 17 microseconds) - and each bit must be exactly the same width. For our configuration it takes 10 bits to transmit a single byte (1 start bit, 8 data bits and a stop bit) so it takes 170 microseconds per byte of data giving a peak transfer rate of 5.6Kb per second assuming there are no gaps between the bytes. In reality it will be lower).

From the first diagram you can see that there are no restrictions on the gaps between the characters (the inter-character delay). The line must remain at an idle state for this period (logic high) but the duration doesn't have to be a multiple of whole bits and can be as long as is needed.

Writing data out the serial port is fairly straight forward - we know the width of each bit so we simply toggle an output pin as needed and ensure it stays in the right state for the full duration of a bit. All we need to do is pull the output pin low for one bit width for the start bit, send out the individual bits from LSB to MSB and then bring the output high for one bit width as the stop bit. The output is then left high to represent the idle state.

The current implementation does just that in a small loop of assembly code. Because the timing is critical interrupts are disabled while this is happening - you will need to keep this in mind if you are depending on interrupts in your code.

NOTE: The serial send and receive code in the library makes heavy use of the assembly routines developed by Ralph Doncaster and described here. I said that generating the output is straight forward and, as a concept, it is. The actual implementation to get the timing right based purely on the number of instruction cycles needed to execute each op-code is another matter. The code developed by Ralph is a really nice piece of work - I highly recommend visiting his site for more examples.

Reading the serial data is the reverse operation. We simply watch the input pin and wait for it to transition from high (idle state) to low which will be our start bit. We then wait for 1.5 bit periods and then start sampling for the input pin once every bit period to get the value for the appropriate bit. We need 9 samples in all - 8 for the data and 1 for the stop bit.

The reason for the 1.5 bit delay at the start is to ensure that we are sampling the bit value in the middle of it's transmission period. If we are slightly off in our timing we will still get the right value for the bit.

Uart

The full implementation of the receiver can be found here. Initially this only provided a blocking implementation - if you called the uartRecv() function it would wait indefinitely until a start bit was detected before it would read and return a character. In cases where nothing happens until it is requested over the serial port (like a bootloader for example) it doesn't matter that the processor is locked in an endless loop with interrupts turned off.

If you want to be able to do work and only respond to serial input when it was available it was not the perfect solution. I've now added an option to have the start bit trigger a pin change interrupt which will cause the incoming byte to be read and buffered for later processing. There is also a uartAvail() function that tells you how many characters are currently buffered.

Pin Change Interrupts

The AVR allows for an interrupt to be triggered when the value of an input pin changes state (in either direction). On the ATtiny85 all of the inputs can be used to trigger this interrupt (which uses the vector PCINT0) but, if you enable multiple pins as triggers, you can't tell which one actually caused the interrupt. You can figure out what the transition was though - if the current reading on the input is 0 you can assume a high to low transition for example.

Avr Software Uart In Color

Uart

Avr Software Uart In China

When the interrupt handler is invoked interrupts will be disabled until they are explicitly enabled by the handler code or the interrupt handler returns. The interrupts don't queue so if another triggering event occurs while the current interrupt is being handled it won't be immediately triggered again when it is done.

Handling the Interrupt

Supporting the interrupt is actually straight forward - what was the original code for the uartRecv() function has been moved to an ISR handler. The code to wait for the start bit is no longer necessary as it has already been detected to trigger the interrupt.

The microcontroller PIC16F84A has no hardware UART module, but we can use software UART to send/receive data to/from the PC via RS232 cable (COM port). This topic shows a simple example for the use of the UART protocol with the PIC16F84A MCU.

Hardware Required:

  • PIC16F84A microcontroller
  • 8MHz crystal
  • 2 x 22pF ceramic capacitors
  • 10K ohm resistor
  • MAX232 — datasheet
  • 4 x 10uF polarized capacitor
  • Female RS232 connector
  • Breadboard
  • 5V power source
  • Jumper wires

UART Example for PIC16F84A microcontroller circuit:

To interface the PIC16F84A MCU with the PC we need MAX232 signal level converter as shown in the circuit diagram. There are 2 lines between the PIC16F84A and the MAX232 and also two lines between the MAX232 and the female COM connector. One line for data transmit and the other one for data receive.
The female COM connector is connected to the PC using RS232 cable, this cable has to be male-female because the PC RS232 port type is male.
In this example the PIC16F84A MCU runs with 8MHz crystal oscillator.

UART Example for PIC16F84A microcontroller C code:
The function #use rs232(xmit = PIN_B4, rcv = PIN_B5, baud = 2400) is used to configure the UART protocol. Here software UART is used.
where:
xmit is the transmit pin (RB4)
rcv is the receive pin (RB5)
2400 is the baud rate.
The functions used in the C code are:
printf: sends a string of characters over RS232 transmission pin (TX).
putc: send a character over RS232 transmission pin (TX).
getc(): read character if available.
Complete C code for CCS C compiler is below.

Avr Software Uart In C Code