搜索
bottom↓
回复: 2

Interrupt-drive software uart

[复制链接]

出0入0汤圆

发表于 2013-8-18 06:55:07 | 显示全部楼层 |阅读模式
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:

  1. //==============uartxisr.h========================
  2. #ifndef _UARTXISR_H
  3. #define _UARTXISR_H

  4. //#include "stm32f10x_rcc.h"                                //we use rcc
  5. //#include "stm32f10x_tim.h"                                //we use timer

  6. //hardware configuration
  7. //softuart pin definitions
  8. #define UART_PORT                PORTC
  9. #define UART_DDR                TRISC
  10. #define UART_TX                        (1<<2)                //tx pin

  11. #define UART_SET(tx)        IO_SET(UART_PORT, tx)
  12. #define UART_CLR(tx)        IO_CLR(UART_PORT, tx)

  13. //pick the timer to be used
  14. //#define UART_TIM                TIM3
  15. #define tmrx_init                tmr1_init
  16. #define tmrx_act                tmr1_act
  17. #include "tmr1.h"                                                //we use timer
  18. //end hardware configuration

  19. //insert into the isr
  20. #define UARTX_TX_ISR()                                \
  21.         if (TMR1IF) {                                        \
  22.                 TMR1H = tmr1_offset>>8;                \
  23.                 TMR1L = tmr1_offset/* & 0x00ff*/;        \
  24.                 TMR1IF = 0;                                        \
  25.                 _tmr1_isr_ptr();                        \
  26.         }       

  27. //uartx protocol
  28. //1 start bit
  29. //8 data bits
  30. //1 stop bit
  31. //lsb first
  32. #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

  33. //global defines
  34. //define baud rates
  35. #define UART_BR_300                        300ul                //baudrate=300 - it overflows under 24Mhz F_CPU
  36. #define UART_BR_600                        600ul                //baudrate=600
  37. #define UART_BR_1200                1200ul                //baudrate=1200
  38. #define UART_BR_2400                2400ul                //baudrate=2400
  39. #define UART_BR_4800                4800ul                //baudrate=4800
  40. #define UART_BR_9600                9600ul                //baudrate=9600
  41. #define UART_BR_19200                19200ul                //baudrate=19200
  42. #define UART_BR_38400                38400ul                //baudrate=38400
  43. #define UART_BR_57600                57600ul                //baudrate=57600 - upper limit for 24Mhz F_CPU
  44. #define UART_BR_115200                115200ul        //baudrate=115200


  45. //global variables
  46. //softuart_isr handler
  47. //install this in the timer
  48. void uartx_isr(void);

  49. //reset softuart_isr
  50. void uartx_init(unsigned long baud);

  51. //transmit a string
  52. void uartx_puts(unsigned char * str);

  53. //if uart is busy, return 1
  54. unsigned char uartx_busy(void);

  55. #endif
复制代码
We are using timer1 to generate the baud rate and PORTC.2 as the tx pin.

  1. //================uartxisr.c==========================
  2. #include <htc.h>                                        //we use picc
  3. //#include <stm32f10x.h>
  4. //#include "stm32f10x_gpio.h"
  5. //#include "stm32f10x_tim.h"                        //we use timer
  6. #include "gpio.h"                                        //we use own macros
  7. #include "tmr1.h"                                        //we use tmr1 as baud rate generator
  8. #include "uartxisr.h"                                //we use software uart

  9. //hardware configuration
  10. //end hardware configuration

  11. //global defines

  12. //global variables
  13. static unsigned char *_UxTX_ptr;
  14. static unsigned char _UxTX_BUSY=0;                //0=u1 transmission done, 1=u1 transmission in process
  15. static unsigned short _UxTX_MASK=0;                //current bit being transmitted. 0=end of transmission for the current char
  16. static unsigned short _UxTX_buffer;                //software shift register for the transmiter
  17. unsigned short _Ux_OFFSET;                                //timer offset for uart baud rate


  18. //softuart_isr handler
  19. //install this in the timer
  20. void uartx_isr(void) {
  21.         //IO_FLP(UART_PORT, UART_TX);        //flip the pin - for debugging
  22.         if (_UxTX_MASK!=0x0400) {                                //current char isn't fully transmitted
  23.                 if (_UxTX_MASK & _UxTX_buffer) UART_SET(UART_TX);        //send '1'
  24.                 else UART_CLR(UART_TX);                //send '0'
  25.                 _UxTX_MASK = _UxTX_MASK << 1;        //shift to the next bit
  26.         } else {                                                //current char has been fully transmitted
  27.                 if (*_UxTX_ptr)        {                        //current char is not a null char
  28.                         _UxTX_ptr+=1;                        //increment to the next character
  29.                         _UxTX_MASK = 0x0001;        //1 start bit, 8 data bits, 1 stop bits = 10 bits
  30.                         _UxTX_buffer = UART_SR(*_UxTX_ptr);        //form the buffer to be transmitted
  31.                 } else {                                        //current char is a null char -> end of transmission
  32.                         _UxTX_BUSY = 0;                        //uartx no longer busy
  33.                         /* TIM IT enable */
  34.                         //TIM_ITConfig(UART_TIM, TIM_IT_Update, DISABLE);        //don't start the isr yet
  35.                         TMR1IE = 0;                                //disable tmr1 interrupt
  36.                 }
  37.         }
  38. }

  39. //reset softuart_isr
  40. void uartx_init(unsigned long baud) {
  41.         //set up the pin
  42.         IO_SET(UART_PORT, UART_TX);                //tx idles high
  43.         IO_OUT(UART_DDR, UART_TX);                //tx as output

  44.         //set up the baud rate generator
  45.         tmrx_init(0, F_CPU / baud);                //set up timer
  46.         tmrx_act(uartx_isr);                        //install the handler
  47.         //clear the bits
  48.         //TIM_ClearITPendingBit(UART_TIM, TIM_IT_Update);
  49.         TMR1IF = 0;
  50.         /* TIM IT enable */
  51.         //TIM_ITConfig(UART_TIM, TIM_IT_Update, DISABLE);        //don't start the isr yet
  52.         TMR1IE = 1;

  53.         _UxTX_BUSY = 0;                                        //uartx not busy
  54. }

  55. //transmit a string
  56. void uartx_puts(unsigned char * str) {
  57.         _UxTX_BUSY = 1;                                        //uartx is busy
  58.         _UxTX_ptr = str;
  59.         _UxTX_MASK = 0x0001;                        //1 start bit, 8 data bits, 1 stop bits = 10 bits
  60.         _UxTX_buffer = UART_SR(*_UxTX_ptr);        //form the buffer to be transmitted

  61.         //clear the bits
  62.         //TIM_ClearITPendingBit(UART_TIM, TIM_IT_Update);
  63.         TMR1IF = 1;                        //force loading of offsets in the isr
  64.         /* TIM IT enable */
  65.         //TIM_ITConfig(UART_TIM, TIM_IT_Update, ENABLE);        //enable the transmission
  66.         TMR1IE = 1;
  67. }

  68. //if uart is busy, return 1
  69. unsigned char uartx_busy(void) {
  70.         return _UxTX_BUSY;
  71. }

复制代码
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:

  1. //==============main.c===================
  2. #include <htc.h>                                                //we use picc
  3. #include "config.h"                                                //configuration words
  4. #include "gpio.h"
  5. #include "delay.h"                                                //we use software delays
  6. #include "tmr1.h"                                                //we use timer1 for uartxisr
  7. #include "uartxisr.h"                                        //we use software uart isr

  8. //hardware configuration
  9. #define LED_PORT                        PORTC
  10. #define LED_DDR                                TRISC
  11. #define LED                                        (1<<0)
  12. #define LED_DLY                                100                        //delay, in ms
  13. //end hardware configuration

  14. //global defines

  15. //global variables
  16. unsigned char uRAM[]="16F684 UARTXISR...\n\r";        //test string to be sent

  17. //isr
  18. void interrupt isr(void) {
  19.         UARTX_TX_ISR();                                                //uartx transmitter isr
  20. }

  21. //reset the mcu
  22. void mcu_init(void) {
  23.         ANSEL = 0x00;                                                //all pins digital
  24.         CMCON0= 0x07;                                                //comparators off
  25.        
  26.         IO_CLR(LED_PORT, LED);                                //clear led
  27.         IO_OUT(LED_DDR, LED);                                //led as output
  28. }

  29. int main(void) {
  30.        
  31.         mcu_init();                                                        //initialize the mcu
  32.         uartx_init(UART_BR_1200);                        //set the baud rate
  33.         ei();                                                                //enable interrupt
  34.         while (1) {
  35.                 if (!uartx_busy()) {                        //uart is not busy
  36.                         uartx_puts(uRAM);                        //send the string
  37.                 }
  38.                 IO_FLP(LED_PORT, LED);                        //flip led
  39.                 //delay_ms(LED_DLY);                                //waste some time
  40.         }
  41. }

复制代码
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

出0入4汤圆

发表于 2013-8-18 08:52:46 来自手机 | 显示全部楼层
good, i raise you

出0入0汤圆

 楼主| 发表于 2013-8-18 08:52:49 | 显示全部楼层
本帖最后由 millwood0 于 2013-8-18 08:53 编辑

Now, on to 89C51. It is actually a lot easier as the chip has a vectored interrupt controller.

  1. #ifndef _UARTXISR_H
  2. #define _UARTXISR_H

  3. //#include "stm32f10x_rcc.h"                                //we use rcc
  4. //#include "stm32f10x_tim.h"                                //we use timer

  5. //hardware configuration
  6. //softuart pin definitions
  7. #define UART_PORT                P2
  8. #define UART_DDR                P2
  9. #define UART_TX                        (1<<2)                //tx pin

  10. #define UART_SET(tx)        IO_SET(UART_PORT, tx)
  11. #define UART_CLR(tx)        IO_CLR(UART_PORT, tx)

  12. //pick the timer to be used
  13. //#define UART_TIM                TIM3
  14. #define tmrx_init                tmr1_init
  15. #define tmrx_act                tmr1_act
  16. #include "tmr1.h"                                                //we use timer
  17. //end hardware configuration

  18. //insert into the isr
  19. #define UARTX_TX_ISR()                                \
  20.         //if (TMR1IF) {                                        \
  21.                 TMR1H = tmr1_offset>>8;                \
  22.                 TMR1L = tmr1_offset/* & 0x00ff*/;        \
  23.         //        TMR1IF = 0;                                        \
  24.         //        _tmr1_isr_ptr();                        \
  25.         //}       

  26. //uartx protocol
  27. //1 start bit
  28. //8 data bits
  29. //1 stop bit
  30. //lsb first
  31. #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

  32. //global defines
  33. //define baud rates
  34. #define UART_BR_300                        300ul                //baudrate=300 - it overflows under 24Mhz F_CPU
  35. #define UART_BR_600                        600ul                //baudrate=600
  36. #define UART_BR_1200                1200ul                //baudrate=1200
  37. #define UART_BR_2400                2400ul                //baudrate=2400
  38. #define UART_BR_4800                4800ul                //baudrate=4800
  39. #define UART_BR_9600                9600ul                //baudrate=9600
  40. #define UART_BR_19200                19200ul                //baudrate=19200
  41. #define UART_BR_38400                38400ul                //baudrate=38400
  42. #define UART_BR_57600                57600ul                //baudrate=57600 - upper limit for 24Mhz F_CPU
  43. #define UART_BR_115200                115200ul        //baudrate=115200


  44. //global variables
  45. //softuart_isr handler
  46. //install this in the timer
  47. void uartx_isr(void);

  48. //reset softuart_isr
  49. void uartx_init(unsigned long baud);

  50. //transmit a string
  51. void uartx_puts(unsigned char * str);

  52. //if uart is busy, return 1
  53. unsigned char uartx_busy(void);

  54. #endif
复制代码
the corresponding .c file

  1. //===============uartxisr.c===================
  2. //#include <htc.h>                                        //we use picc
  3. #include <regx51.h>                                        //we use keil c51
  4. //#include <stm32f10x.h>
  5. //#include "stm32f10x_gpio.h"
  6. //#include "stm32f10x_tim.h"                        //we use timer
  7. #include "gpio.h"                                        //we use own macros
  8. #include "tmr1.h"                                        //we use tmr1 as baud rate generator
  9. #include "uartxisr.h"                                //we use software uart

  10. //hardware configuration
  11. //end hardware configuration

  12. //global defines

  13. //global variables
  14. static unsigned char *_UxTX_ptr;
  15. static unsigned char _UxTX_BUSY=0;                //0=u1 transmission done, 1=u1 transmission in process
  16. static unsigned short _UxTX_MASK=0;                //current bit being transmitted. 0=end of transmission for the current char
  17. static unsigned short _UxTX_buffer;                //software shift register for the transmiter
  18. unsigned short _Ux_OFFSET;                                //timer offset for uart baud rate


  19. //softuart_isr handler
  20. //install this in the timer
  21. void uartx_isr(void) {
  22.         //IO_FLP(UART_PORT, UART_TX);        //flip the pin - for debugging
  23.         //load the offset
  24.         UARTX_TX_ISR();                                        //realod the offset
  25.         if (_UxTX_MASK!=0x0400) {                                //current char isn't fully transmitted
  26.                 if (_UxTX_MASK & _UxTX_buffer) UART_SET(UART_TX);        //send '1'
  27.                 else UART_CLR(UART_TX);                //send '0'
  28.                 _UxTX_MASK = _UxTX_MASK << 1;        //shift to the next bit
  29.         } else {                                                //current char has been fully transmitted
  30.                 if (*_UxTX_ptr)        {                        //current char is not a null char
  31.                         _UxTX_ptr+=1;                        //increment to the next character
  32.                         _UxTX_MASK = 0x0001;        //1 start bit, 8 data bits, 1 stop bits = 10 bits
  33.                         _UxTX_buffer = UART_SR(*_UxTX_ptr);        //form the buffer to be transmitted
  34.                 } else {                                        //current char is a null char -> end of transmission
  35.                         _UxTX_BUSY = 0;                        //uartx no longer busy
  36.                         /* TIM IT enable */
  37.                         //TIM_ITConfig(UART_TIM, TIM_IT_Update, DISABLE);        //don't start the isr yet
  38.                         //TMR1IE = 0;                                //disable tmr1 interrupt
  39.                         ET1 = 0;                                //turn off tmr1 interrupt
  40.                 }
  41.         }
  42. }

  43. //reset softuart_isr
  44. void uartx_init(unsigned long baud) {
  45.         //set up the pin
  46.         IO_SET(UART_PORT, UART_TX);                //tx idles high
  47.         IO_OUT(UART_DDR, UART_TX);                //tx as output

  48.         //set up the baud rate generator
  49.         tmrx_init(0, F_CPU / baud);                //set up timer
  50.         tmrx_act(uartx_isr);                        //install the handler
  51.         //clear the bits
  52.         //TIM_ClearITPendingBit(UART_TIM, TIM_IT_Update);
  53.         //TMR1IF = 0;
  54.         TF1 = 0;
  55.         /* TIM IT enable */
  56.         //TIM_ITConfig(UART_TIM, TIM_IT_Update, DISABLE);        //don't start the isr yet
  57.         //TMR1IE = 1;
  58.         ET1 = 1;

  59.         _UxTX_BUSY = 0;                                        //uartx not busy
  60. }

  61. //transmit a string
  62. void uartx_puts(unsigned char * str) {
  63.         _UxTX_BUSY = 1;                                        //uartx is busy
  64.         _UxTX_ptr = str;
  65.         _UxTX_MASK = 0x0001;                        //1 start bit, 8 data bits, 1 stop bits = 10 bits
  66.         _UxTX_buffer = UART_SR(*_UxTX_ptr);        //form the buffer to be transmitted

  67.         //clear the bits
  68.         //TIM_ClearITPendingBit(UART_TIM, TIM_IT_Update);
  69.         //TMR1IF = 1;                        //force loading of offsets in the isr
  70.         TF1 = 1;
  71.         /* TIM IT enable */
  72.         //TIM_ITConfig(UART_TIM, TIM_IT_Update, ENABLE);        //enable the transmission
  73.         //TMR1IE = 1;
  74.         ET1 = 1;
  75. }

  76. //if uart is busy, return 1
  77. unsigned char uartx_busy(void) {
  78.         return _UxTX_BUSY;
  79. }
复制代码
The calling convention is the same:

  1. //==============main.c=================
  2. #include <regx51.h>                                                        //we use keil c51
  3. #include "gpio.h"
  4. #include "delay.h"                                                        //we use software delay
  5. #include "tmr1.h"                                                        //we use timer
  6. #include "uartxisr.h"                                                //we use software uartx

  7. //hardware configuration
  8. #define LED_PORT                P2
  9. #define LED_DDR                        P2
  10. #define LED                                (1<<0)
  11. #define LED_DLY                        100
  12. //end hardware configuration

  13. //global defines

  14. //global variables
  15. unsigned char uRAM[]="89C51 UARTX_ISR...\n\r";

  16. void mcu_init(void) {
  17.         IO_CLR(LED_PORT, LED);                                        //clear led
  18.         IO_OUT(LED_DDR, LED);                                        //led as output
  19. }

  20. int main(void) {
  21.         mcu_init();                                                                //reset the mcu
  22.         uartx_init(UART_BR_1200);                                //set the baud rate
  23.         ei();                                                                        //enable interrupt
  24.         while (1) {
  25.                 if (!uartx_busy()) {                                //uartx is not busy
  26.                         uartx_puts(uRAM);                                //send the string
  27.                 }
  28.                 IO_FLP(LED_PORT, LED);                                //flip led
  29.                 //delay_ms(LED_DLY);                                //waste some time
  30.         }
  31. }
复制代码
The output:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-4 20:27

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表