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