|
I wrote a software uart for STM32F10x chips here: http://www.amobbs.com/thread-5542383-1-1.html. On a 24Mhz CM3, it is good up to about 50Kbps, without any optimization.
I mentioned that porting it to the code to other mcus should be fairly easy. Here are two examples of porting that piece of code to a PIC (16F684) and a 89C51.
First, porting it to a 16F684. 16F chips don't have vectored interrupts so it is more involved. But here it is:
- //==============uartxisr.h========================
- #ifndef _UARTXISR_H
- #define _UARTXISR_H
- //#include "stm32f10x_rcc.h" //we use rcc
- //#include "stm32f10x_tim.h" //we use timer
- //hardware configuration
- //softuart pin definitions
- #define UART_PORT PORTC
- #define UART_DDR TRISC
- #define UART_TX (1<<2) //tx pin
- #define UART_SET(tx) IO_SET(UART_PORT, tx)
- #define UART_CLR(tx) IO_CLR(UART_PORT, tx)
- //pick the timer to be used
- //#define UART_TIM TIM3
- #define tmrx_init tmr1_init
- #define tmrx_act tmr1_act
- #include "tmr1.h" //we use timer
- //end hardware configuration
- //insert into the isr
- #define UARTX_TX_ISR() \
- if (TMR1IF) { \
- TMR1H = tmr1_offset>>8; \
- TMR1L = tmr1_offset/* & 0x00ff*/; \
- TMR1IF = 0; \
- _tmr1_isr_ptr(); \
- }
- //uartx protocol
- //1 start bit
- //8 data bits
- //1 stop bit
- //lsb first
- #define UART_SR(dat) (0x0200 | ((dat) << 1) | 0x0000) //form the uart shift register. 1 start bit (low), 8 data bits, 1 stop bit (high), lsb first
- //global defines
- //define baud rates
- #define UART_BR_300 300ul //baudrate=300 - it overflows under 24Mhz F_CPU
- #define UART_BR_600 600ul //baudrate=600
- #define UART_BR_1200 1200ul //baudrate=1200
- #define UART_BR_2400 2400ul //baudrate=2400
- #define UART_BR_4800 4800ul //baudrate=4800
- #define UART_BR_9600 9600ul //baudrate=9600
- #define UART_BR_19200 19200ul //baudrate=19200
- #define UART_BR_38400 38400ul //baudrate=38400
- #define UART_BR_57600 57600ul //baudrate=57600 - upper limit for 24Mhz F_CPU
- #define UART_BR_115200 115200ul //baudrate=115200
- //global variables
- //softuart_isr handler
- //install this in the timer
- void uartx_isr(void);
- //reset softuart_isr
- void uartx_init(unsigned long baud);
- //transmit a string
- void uartx_puts(unsigned char * str);
- //if uart is busy, return 1
- unsigned char uartx_busy(void);
- #endif
复制代码 We are using timer1 to generate the baud rate and PORTC.2 as the tx pin.
- //================uartxisr.c==========================
- #include <htc.h> //we use picc
- //#include <stm32f10x.h>
- //#include "stm32f10x_gpio.h"
- //#include "stm32f10x_tim.h" //we use timer
- #include "gpio.h" //we use own macros
- #include "tmr1.h" //we use tmr1 as baud rate generator
- #include "uartxisr.h" //we use software uart
- //hardware configuration
- //end hardware configuration
- //global defines
- //global variables
- static unsigned char *_UxTX_ptr;
- static unsigned char _UxTX_BUSY=0; //0=u1 transmission done, 1=u1 transmission in process
- static unsigned short _UxTX_MASK=0; //current bit being transmitted. 0=end of transmission for the current char
- static unsigned short _UxTX_buffer; //software shift register for the transmiter
- unsigned short _Ux_OFFSET; //timer offset for uart baud rate
- //softuart_isr handler
- //install this in the timer
- void uartx_isr(void) {
- //IO_FLP(UART_PORT, UART_TX); //flip the pin - for debugging
- if (_UxTX_MASK!=0x0400) { //current char isn't fully transmitted
- if (_UxTX_MASK & _UxTX_buffer) UART_SET(UART_TX); //send '1'
- else UART_CLR(UART_TX); //send '0'
- _UxTX_MASK = _UxTX_MASK << 1; //shift to the next bit
- } else { //current char has been fully transmitted
- if (*_UxTX_ptr) { //current char is not a null char
- _UxTX_ptr+=1; //increment to the next character
- _UxTX_MASK = 0x0001; //1 start bit, 8 data bits, 1 stop bits = 10 bits
- _UxTX_buffer = UART_SR(*_UxTX_ptr); //form the buffer to be transmitted
- } else { //current char is a null char -> end of transmission
- _UxTX_BUSY = 0; //uartx no longer busy
- /* TIM IT enable */
- //TIM_ITConfig(UART_TIM, TIM_IT_Update, DISABLE); //don't start the isr yet
- TMR1IE = 0; //disable tmr1 interrupt
- }
- }
- }
- //reset softuart_isr
- void uartx_init(unsigned long baud) {
- //set up the pin
- IO_SET(UART_PORT, UART_TX); //tx idles high
- IO_OUT(UART_DDR, UART_TX); //tx as output
- //set up the baud rate generator
- tmrx_init(0, F_CPU / baud); //set up timer
- tmrx_act(uartx_isr); //install the handler
- //clear the bits
- //TIM_ClearITPendingBit(UART_TIM, TIM_IT_Update);
- TMR1IF = 0;
- /* TIM IT enable */
- //TIM_ITConfig(UART_TIM, TIM_IT_Update, DISABLE); //don't start the isr yet
- TMR1IE = 1;
- _UxTX_BUSY = 0; //uartx not busy
- }
- //transmit a string
- void uartx_puts(unsigned char * str) {
- _UxTX_BUSY = 1; //uartx is busy
- _UxTX_ptr = str;
- _UxTX_MASK = 0x0001; //1 start bit, 8 data bits, 1 stop bits = 10 bits
- _UxTX_buffer = UART_SR(*_UxTX_ptr); //form the buffer to be transmitted
- //clear the bits
- //TIM_ClearITPendingBit(UART_TIM, TIM_IT_Update);
- TMR1IF = 1; //force loading of offsets in the isr
- /* TIM IT enable */
- //TIM_ITConfig(UART_TIM, TIM_IT_Update, ENABLE); //enable the transmission
- TMR1IE = 1;
- }
- //if uart is busy, return 1
- unsigned char uartx_busy(void) {
- return _UxTX_BUSY;
- }
复制代码 Three routines are involved: uartx_init() initialize the module and sets the baud rate; uartx_puts() sends a string, and uartx_busy() tests if the uartx module is busy.
You can see great similarity between this code base and the one for STM32F.
here is the application code:
- //==============main.c===================
- #include <htc.h> //we use picc
- #include "config.h" //configuration words
- #include "gpio.h"
- #include "delay.h" //we use software delays
- #include "tmr1.h" //we use timer1 for uartxisr
- #include "uartxisr.h" //we use software uart isr
- //hardware configuration
- #define LED_PORT PORTC
- #define LED_DDR TRISC
- #define LED (1<<0)
- #define LED_DLY 100 //delay, in ms
- //end hardware configuration
- //global defines
- //global variables
- unsigned char uRAM[]="16F684 UARTXISR...\n\r"; //test string to be sent
- //isr
- void interrupt isr(void) {
- UARTX_TX_ISR(); //uartx transmitter isr
- }
- //reset the mcu
- void mcu_init(void) {
- ANSEL = 0x00; //all pins digital
- CMCON0= 0x07; //comparators off
-
- IO_CLR(LED_PORT, LED); //clear led
- IO_OUT(LED_DDR, LED); //led as output
- }
- int main(void) {
-
- mcu_init(); //initialize the mcu
- uartx_init(UART_BR_1200); //set the baud rate
- ei(); //enable interrupt
- while (1) {
- if (!uartx_busy()) { //uart is not busy
- uartx_puts(uRAM); //send the string
- }
- IO_FLP(LED_PORT, LED); //flip led
- //delay_ms(LED_DLY); //waste some time
- }
- }
复制代码 It is fairly simple: sets up the uart to send a string at 1200bps, and then flip a pin (PORTC.0).
Here is the output:
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
|