Important update: Arm Announces End of Life Timeline for Mbed. This site will be archived in July 2026. Read the full announcement.
Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
Software UART
Using the mbed.h I could figure out half of the functions I need:
DigitalOut TX(P12); DigitalIN RX(P13); Timer t; #define get_rx_pin_status() return RX; #define get_tx_pin_status() return TX #define set_tx_pin_low() TX = 0;
Still, for the timer, I have no Idea.
// 4. idle() // 5. timer_set( BAUD_RATE ) // 6. set_timer_interrupt( timer_isr )
Can I create a Timer with a specific baudrate?
<<quote RFID>>
<</quote>>
this is the same code i started out with, however i was only able to receive data and not send. i havent had time to debug it. you can set a timer to BAUD_RATE * 3.
Ticker ticker; ticker.attach_us(timer_isr, 1000000.0 / (BAUD_RATE * 3.0));
Thank you for your help. I used your code to implement set_timer_interrupt :
//Returns 0 or 1 dependent on whether the receive pin is high or low #define get_rx_pin_status() RX.read(); //Sets the transmit pin to the high state. #define set_tx_pin_high() TX = 1; //Sets the transmit pin to the low state. #define set_tx_pin_low() TX = 0; // #define idle() //Background functions to execute while waiting for input. #define timer_set( BAUD_RATE ) ( ticker.attach_us(timer_isr, 1000000.0 / (BAUD_RATE * 3.0)) ) //Enables the timer interrupt. #define set_timer_interrupt( timer_isr )
I am still trying to figure out what to do with the function :
set_timer_interrupt( timer_isr )
It seems like you did not implement this function in your code. Am I wrong? Is there a reason?
#define timer_set( BAUD_RATE ) (ticker.attach_us(timer_isr, 1000000.0 / (BAUD_RATE * 3.0)) )
The ticker.attach_us() is in fact setting the timer interrupt rate to 3x the BAUD_RATE as well as attaching the timer interrupt to the timer_isr. So you dont need to do anything anymore for the set_timer_interrupt().
//Enables the timer interrupt. #define set_timer_interrupt( timer_isr )
Regarding the idle() function: you can replace that by a short wait. That is the easy solution, more difficult to do anything useful rather than just wait.
#define idle() wait_us(1.0) //Background functions to execute while waiting for input.
Hermann Helmholz wrote:
I am still trying to figure out what to do with the function :
set_timer_interrupt( timer_isr )
It seems like you did not implement this function in your code. Am I wrong? Is there a reason?
since Ticker.attach_us() accepts both the function and the interval. you could have timer_set() store the calculated interval, and then have set_timer_interrupt() actually call .attach_us(), but i believe the calls where back to back thus making it unnecessary. in that case, leaving set_timer_interrupt defined as a NOOP is fine.
i dont have the experience to bypass MBED libraries and work with the timers on a closer level, but i'm pretty sure they would be separated.
Thanks for the hint. I decided to call (ticker.attach_us(timer_isr, 1000000.0 / (BAUD_RATE * 3.0)) ) inside the init function. So now, my code looks like this :
#include "mbed.h" // UART.C // // Generic software uart written in C, requiring a timer set to 3 times // the baud rate, and two software read/write pins for the receive and // transmit functions. // // * Received characters are buffered // * putchar(), getchar(), kbhit() and flush_input_buffer() are available // * There is a facility for background processing while waiting for input // // Colin Gittins, Software Engineer, Halliburton Energy Services // // The baud rate can be configured by changing the BAUD_RATE macro as // follows: // // #define BAUD_RATE 19200.0 // // The function init_uart() must be called before any comms can take place // // Interface routines required: // 1. get_rx_pin_status() // Returns 0 or 1 dependent on whether the receive pin is high or low. // 2. set_tx_pin_high() // Sets the transmit pin to the high state. // 3. set_tx_pin_low() // Sets the transmit pin to the low state. // 4. idle() // Background functions to execute while waiting for input. // 5. timer_set( BAUD_RATE ) // Sets the timer to 3 times the baud rate. // 6. set_timer_interrupt( timer_isr ) // Enables the timer interrupt. // // Functions provided: // 1. void flush_input_buffer( void ) // Clears the contents of the input buffer. // 2. char kbhit( void ) // Tests whether an input character has been received. // 3. char getchar( void ) // Reads a character from the input buffer, waiting if necessary. // 4. void turn_rx_on( void ) // Turns on the receive function. // 5. void turn_rx_off( void ) // Turns off the receive function. // 6. void putchar( char ) // Writes a character to the serial port. #include <stdio.h> #define BAUD_RATE 9600 #define IN_BUF_SIZE 256 #define TRUE 1 #define FALSE 0 static unsigned char inbuf[IN_BUF_SIZE]; static unsigned char qin = 0; static unsigned char qout = 0; static char flag_rx_waiting_for_stop_bit; static char flag_rx_off; static char rx_mask; static char flag_rx_ready; static char flag_tx_ready; static char timer_rx_ctr; static char timer_tx_ctr; static char bits_left_in_rx; static char bits_left_in_tx; static char rx_num_of_bits; static char tx_num_of_bits; static char internal_rx_buffer; static char internal_tx_buffer; static char user_tx_buffer; DigitalOut TX(p25); DigitalIn RX(p26); Ticker ticker; Serial pc(USBTX, USBRX); //Background functions to execute while waiting for input. void idle(){ wait_us(1.0); } //Sets the transmit pin to the high state. void set_tx_pin_high() { TX = 1; } //Sets the transmit pin to the low state. void set_tx_pin_low() { TX = 0; } //Returns 0 or 1 dependent on whether the receive pin is high or low int get_rx_pin_status() { return RX.read(); } void timer_isr(void) { char mask, start_bit, flag_in; // Transmitter Section // pc.printf("Transmission:\n\r" ); if ( flag_tx_ready ) { if ( --timer_tx_ctr<=0 ) { mask = internal_tx_buffer&1; internal_tx_buffer >>= 1; if ( mask ) { set_tx_pin_high(); pc.printf("TX:"); pc.printf("%d \n\r",TX.read()); } else { set_tx_pin_low(); pc.printf("TX:"); pc.printf("%d \n\r",TX.read()); } timer_tx_ctr = 3; if ( --bits_left_in_tx<=0 ) { flag_tx_ready = FALSE; pc.printf("flag_tx_ready = FALSE\r\n"); } } } // Receiver Section if ( flag_rx_off==FALSE ) { if ( flag_rx_waiting_for_stop_bit ) { if ( --timer_rx_ctr<=0 ) { flag_rx_waiting_for_stop_bit = FALSE; flag_rx_ready = FALSE; internal_rx_buffer &= 0xFF; if ( internal_rx_buffer!=0xC2 ) { inbuf[qin] = internal_rx_buffer; if ( ++qin>=IN_BUF_SIZE ) { qin = 0; } } } } else // rx_test_busy { if ( flag_rx_ready==FALSE ) { start_bit = get_rx_pin_status(); // Test for Start Bit if ( start_bit==0 ) { flag_rx_ready = TRUE; internal_rx_buffer = 0; timer_rx_ctr = 4; bits_left_in_rx = rx_num_of_bits; rx_mask = 1; } } else // rx_busy { if ( --timer_rx_ctr<=0 ) { // rcv timer_rx_ctr = 3; flag_in = get_rx_pin_status(); if ( flag_in ) { internal_rx_buffer |= rx_mask; } rx_mask <<= 1; if ( --bits_left_in_rx<=0 ) { flag_rx_waiting_for_stop_bit = TRUE; } } } } } } void init_uart( void ) { flag_tx_ready = FALSE; flag_rx_ready = FALSE; flag_rx_waiting_for_stop_bit = FALSE; flag_rx_off = FALSE; rx_num_of_bits = 10; tx_num_of_bits = 10; set_tx_pin_low(); pc.printf("ticker.attach_us\r\n"); ticker.attach_us(&timer_isr, 1000000.0 / (BAUD_RATE * 3.0)); } char _getchar( void ) { char ch; do { while ( qout==qin ) { idle(); } ch = inbuf[qout] & 0xFF; if ( ++qout>=IN_BUF_SIZE ) { qout = 0; } } while ( ch==0x0A || ch==0xC2 ); return( ch ); } void _putchar( char ch ) { while ( flag_tx_ready ); user_tx_buffer = ch; // invoke_UART_transmit timer_tx_ctr = 3; bits_left_in_tx = tx_num_of_bits; internal_tx_buffer = (user_tx_buffer<<1) | 0x200; pc.printf( "%x \n\r",internal_tx_buffer ); flag_tx_ready = TRUE; } void flush_input_buffer( void ) { qin = 0; qout = 0; } char kbhit( void ) { return( qin!=qout ); } void turn_rx_on( void ) { flag_rx_off = FALSE; } void turn_rx_off( void ) { flag_rx_off = TRUE; } int main() { pc.baud(9600); init_uart(); while(1){ _putchar('k'); wait(1); } }
I inserted printf statements to debug the code. The code seems to be ok, the TX are set properly and so on. I also check if the signal is outputed on pin 25 with a led. Everything is ok.
Still, I dont see anything on my PuTTY terminal connected on the right COM at 9600 baudrate.
The problem with the TX part is probably in the declaration of 'internal_tx_buffer' This should be an int or short since is must have room for at least 10 bits: an 8 bits char and the startbit and stopbit, see this code:
internal_tx_buffer = (user_tx_buffer<<1) | 0x200;
With this code you would lose the msb of the char and the stopbit when internal_tx_buffer is defined as char. See also http://mbed.org/users/mbed714/notebook/integer-types-int-long-and-long-long/
The declaration should be
static int internal_tx_buffer;
Obviously you need to remove the pc.printf("TX:") in your code or the timing will be all wrong.
you are right!!!
thanks a lot Wim and chag, you were of a great help (you praticly wrote the code form me). There are still some bugs related to types (when I write putchar('k'), I get a 'i' on screen)... I am working on it.
thanks again.
For some reason, I had to put some wait() between the _putchar. Now the code works for reading and writting. :
#include "mbed.h" // UART.C // // Generic software uart written in C, requiring a timer set to 3 times // the baud rate, and two software read/write pins for the receive and // transmit functions. // // * Received characters are buffered // * putchar(), getchar(), kbhit() and flush_input_buffer() are available // * There is a facility for background processing while waiting for input // // Colin Gittins, Software Engineer, Halliburton Energy Services // // The baud rate can be configured by changing the BAUD_RATE macro as // follows: // // #define BAUD_RATE 19200.0 // // The function init_uart() must be called before any comms can take place // // Interface routines required: // 1. get_rx_pin_status() // Returns 0 or 1 dependent on whether the receive pin is high or low. // 2. set_tx_pin_high() // Sets the transmit pin to the high state. // 3. set_tx_pin_low() // Sets the transmit pin to the low state. // 4. idle() // Background functions to execute while waiting for input. // 5. timer_set( BAUD_RATE ) // Sets the timer to 3 times the baud rate. // 6. set_timer_interrupt( timer_isr ) // Enables the timer interrupt. // // Functions provided: // 1. void flush_input_buffer( void ) // Clears the contents of the input buffer. // 2. char kbhit( void ) // Tests whether an input character has been received. // 3. char getchar( void ) // Reads a character from the input buffer, waiting if necessary. // 4. void turn_rx_on( void ) // Turns on the receive function. // 5. void turn_rx_off( void ) // Turns off the receive function. // 6. void putchar( char ) // Writes a character to the serial port. #include <stdio.h> #define BAUD_RATE 9600 #define IN_BUF_SIZE 256 #define TRUE 1 #define FALSE 0 static unsigned char inbuf[IN_BUF_SIZE]; static unsigned char qin = 0; static unsigned char qout = 0; static char flag_rx_waiting_for_stop_bit; static char flag_rx_off; static char rx_mask; static char flag_rx_ready; static char flag_tx_ready; static char timer_rx_ctr; static char timer_tx_ctr; static char bits_left_in_rx; static char bits_left_in_tx; static char rx_num_of_bits; static char tx_num_of_bits; static int internal_rx_buffer; static int internal_tx_buffer; static int user_tx_buffer; DigitalOut TX(p25); DigitalIn RX(p26); Ticker ticker; Serial pc(USBTX, USBRX); //Background functions to execute while waiting for input. void idle(){ wait_us(1.0); } //Sets the transmit pin to the high state. void set_tx_pin_high() { TX = 1; } //Sets the transmit pin to the low state. void set_tx_pin_low() { TX = 0; } //Returns 0 or 1 dependent on whether the receive pin is high or low int get_rx_pin_status() { return RX.read(); } void timer_isr(void) { char mask, start_bit, flag_in; // Transmitter Section if ( flag_tx_ready ) { if ( --timer_tx_ctr<=0 ) { mask = internal_tx_buffer&1; internal_tx_buffer >>= 1; if ( mask ) { set_tx_pin_high(); } else { set_tx_pin_low(); } timer_tx_ctr = 3; if ( --bits_left_in_tx<=0 ) { flag_tx_ready = FALSE; } } } // Receiver Section if ( flag_rx_off==FALSE ) { if ( flag_rx_waiting_for_stop_bit ) { if ( --timer_rx_ctr<=0 ) { flag_rx_waiting_for_stop_bit = FALSE; flag_rx_ready = FALSE; internal_rx_buffer &= 0xFF; if ( internal_rx_buffer!=0xC2 ) { inbuf[qin] = internal_rx_buffer; if ( ++qin>=IN_BUF_SIZE ) { qin = 0; } } } } else // rx_test_busy { if ( flag_rx_ready==FALSE ) { start_bit = get_rx_pin_status(); // Test for Start Bit if ( start_bit==0 ) { flag_rx_ready = TRUE; internal_rx_buffer = 0; timer_rx_ctr = 4; bits_left_in_rx = rx_num_of_bits; rx_mask = 1; } } else // rx_busy { if ( --timer_rx_ctr<=0 ) { // rcv timer_rx_ctr = 3; flag_in = get_rx_pin_status(); if ( flag_in ) { internal_rx_buffer |= rx_mask; } rx_mask <<= 1; if ( --bits_left_in_rx<=0 ) { flag_rx_waiting_for_stop_bit = TRUE; } } } } } } void init_uart( void ) { flag_tx_ready = FALSE; flag_rx_ready = FALSE; flag_rx_waiting_for_stop_bit = FALSE; flag_rx_off = FALSE; rx_num_of_bits = 10; tx_num_of_bits = 10; set_tx_pin_low(); ticker.attach_us(&timer_isr, 1000000.0 / (BAUD_RATE * 3.0)); } char _getchar( void ) { char ch; do { while ( qout==qin ) { idle(); } ch = inbuf[qout] & 0xFF; if ( ++qout>=IN_BUF_SIZE ) { qout = 0; } } while ( ch==0x0A || ch==0xC2 ); return( ch ); } void _putchar( int ch ) { while ( flag_tx_ready ); user_tx_buffer = ch; // invoke_UART_transmit timer_tx_ctr = 3; bits_left_in_tx = tx_num_of_bits; internal_tx_buffer = (user_tx_buffer<<1) | 0x200;; flag_tx_ready = TRUE; } void flush_input_buffer( void ) { qin = 0; qout = 0; } char kbhit( void ) { return( qin!=qout ); } void turn_rx_on( void ) { flag_rx_off = FALSE; } void turn_rx_off( void ) { flag_rx_off = TRUE; } void printStr(char* str){ int i = 0; int len = strlen(str); for(i = 0; i<len; i++){ wait(0.01); _putchar(str[i]); } } int main() { pc.baud(9600); pc.printf("test"); init_uart(); printStr("d\n\r"); wait(0.01); printStr("Voila!\n\r"); printStr("Voila!\n\r"); while(1){ pc.putc( _getchar() ); } }
I am working on a class to make the code more useable.
I am having some trouble with this code. I am only able to get some of the characters to transmit correctly but the start and end do not seem to do it correctly.
I turned the baud down(2400) and extended your delay of "wait(0.01)" to "wait(0.02)". I send a test string of "test" and when I use a logic analyzer I get "÷esÿ" which... is close. I am new to coding with UARTS so I wanted to talk to this group first before putting a large amount of effort into it. Any help would be appreciated.
Chag, I tried you code but it had compile errors and this dropped right in. I would be happy to help with debugging, but need help with the code aspect.
Thanks
Just in case I am using this on a 1769 MBED.
Hi,
I would like to implement a Software UART for mbed (lpc11u24) because there is only one UART. There is already a project about this but it is, I think, under construction.
After googleing, I found an interessting piece of software :
http://supp.iar.com/Support/?note=88469
and here is the code:
Now I have to implemente a few functions by myself (as written in the code)
So I need some help / link on programming the LCP11U24 directly I think (without mbed.h). Is it realystic? Do you know of a good tutorial / starting point?
thanks