发个串口通信的程序

[复制链接]
3460|14
 楼主| dong_abc 发表于 2013-12-21 22:33 | 显示全部楼层 |阅读模式
本帖最后由 dong_abc 于 2013-12-23 04:35 编辑

很早的时候在keil网站下载了个串口通信的demo程序,写得还不错。工作几年了,看过不少人的串口程序,很少有比这个写的好的(也可能是我见识少吧)虽然只是个小小的串口通信。
一、关键字:软缓冲(前几年的单片机一般都没有串口fifo)、中断接收、中断发送、手动触发、全双工

  1. /*----------------------------------------------------------------------------
  2. * Name:    Usart.c
  3. * Purpose: USART usage for STM32
  4. * Version: V1.00
  5. *----------------------------------------------------------------------------
  6. * This file is part of the uVision/ARM development tools.
  7. * This software may only be used under the terms of a valid, current,
  8. * end user licence from KEIL for a compatible version of KEIL software
  9. * development tools. Nothing else gives you the right to use this software.
  10. *
  11. * Copyright (c) 2005-2007 Keil Software. All rights reserved.
  12. *----------------------------------------------------------------------------*/
  13. #include <stm32f10x_lib.h>                        // STM32F10x Library Definitions
  14. #include <stdio.h>
  15. #include "STM32_Init.h"                           // STM32 Initialization

  16. /*----------------------------------------------------------------------------
  17.   Notes:
  18.   The length of the receive and transmit buffers must be a power of 2.
  19.   Each buffer has a next_in and a next_out index.
  20.   If next_in = next_out, the buffer is empty.
  21.   (next_in - next_out) % buffer_size = the number of characters in the buffer.
  22. *----------------------------------------------------------------------------*/
  23. #define TBUF_SIZE   256      /*** Must be a power of 2 (2,4,8,16,32,64,128,256,512,...) ***/
  24. #define RBUF_SIZE   256      /*** Must be a power of 2 (2,4,8,16,32,64,128,256,512,...) ***/
  25. /*----------------------------------------------------------------------------
  26. *----------------------------------------------------------------------------*/
  27. #if TBUF_SIZE < 2
  28. #error TBUF_SIZE is too small.  It must be larger than 1.
  29. #elif ((TBUF_SIZE & (TBUF_SIZE-1)) != 0)
  30. #error TBUF_SIZE must be a power of 2.
  31. #endif
  32. #if RBUF_SIZE < 2
  33. #error RBUF_SIZE is too small.  It must be larger than 1.
  34. #elif ((RBUF_SIZE & (RBUF_SIZE-1)) != 0)
  35. #error RBUF_SIZE must be a power of 2.
  36. #endif
  37. /*----------------------------------------------------------------------------
  38. *----------------------------------------------------------------------------*/
  39. struct buf_st {
  40.   unsigned int in;                                // Next In Index
  41.   unsigned int out;                               // Next Out Index
  42.   char buf [RBUF_SIZE];                           // Buffer
  43. };
  44. static struct buf_st rbuf = { 0, 0, };
  45. #define SIO_RBUFLEN ((unsigned short)(rbuf.in - rbuf.out))
  46. static struct buf_st tbuf = { 0, 0, };
  47. #define SIO_TBUFLEN ((unsigned short)(tbuf.in - tbuf.out))
  48. static unsigned int tx_restart = 1;               // NZ if TX restart is required
  49. /*----------------------------------------------------------------------------
  50.   USART1_IRQHandler
  51.   Handles USART1 global interrupt request.
  52. *----------------------------------------------------------------------------*/
  53. void USART1_IRQHandler (void) {
  54.   volatile unsigned int IIR;
  55.   struct buf_st *p;
  56.     IIR = USART1->SR;
  57.     if (IIR & USART_FLAG_RXNE) {                  // read interrupt
  58.       USART1->SR &= ~USART_FLAG_RXNE;           // clear interrupt
  59.       p = &rbuf;
  60.       if (((p->in - p->out) & ~(RBUF_SIZE-1)) == 0) {
  61.         p->buf [p->in & (RBUF_SIZE-1)] = (USART1->DR & 0x1FF);
  62.         p->in++;
  63.       }
  64.     }
  65.     if (IIR & USART_FLAG_TXE) {
  66.       USART1->SR &= ~USART_FLAG_TXE;           // clear interrupt
  67.       p = &tbuf;
  68.       if (p->in != p->out) {
  69.         USART1->DR = (p->buf [p->out & (TBUF_SIZE-1)] & 0x1FF);
  70.         p->out++;
  71.         tx_restart = 0;
  72.       }
  73.       else {
  74.         tx_restart = 1;
  75.   USART1->CR1 &= ~USART_FLAG_TXE;        // disable TX interrupt if nothing to send
  76.       }
  77.     }
  78. }
  79. /*------------------------------------------------------------------------------
  80.   buffer_Init
  81.   initialize the buffers
  82. *------------------------------------------------------------------------------*/
  83. void buffer_Init (void) {
  84.   tbuf.in = 0;                                    // Clear com buffer indexes
  85.   tbuf.out = 0;
  86.   tx_restart = 1;
  87.   rbuf.in = 0;
  88.   rbuf.out = 0;
  89. }
  90. /*------------------------------------------------------------------------------
  91.   SenChar
  92.   transmit a character
  93. *------------------------------------------------------------------------------*/
  94. int SendChar (int c) {
  95.   struct buf_st *p = &tbuf;
  96.                                                   // If the buffer is full, return an error value
  97.   if (SIO_TBUFLEN >= TBUF_SIZE)
  98.     return (-1);
  99.                                                   
  100.   p->buf [p->in & (TBUF_SIZE - 1)] = c;           // Add data to the transmit buffer.
  101.   p->in++;
  102.   if (tx_restart) {                               // If transmit interrupt is disabled, enable it
  103.     tx_restart = 0;
  104. USART1->CR1 |= USART_FLAG_TXE;            // enable TX interrupt
  105.   }
  106.   return (0);
  107. }
  108. /*------------------------------------------------------------------------------
  109.   GetKey
  110.   receive a character
  111. *------------------------------------------------------------------------------*/
  112. int GetKey (void) {
  113.   struct buf_st *p = &rbuf;
  114.   if (SIO_RBUFLEN == 0)
  115.     return (-1);
  116.   return (p->buf [(p->out++) & (RBUF_SIZE - 1)]);
  117. }

  118. /*----------------------------------------------------------------------------
  119.   MAIN function
  120. *----------------------------------------------------------------------------*/
  121. int main (void) {
  122.   buffer_Init();                                  // init RX / TX buffers
  123.   stm32_Init ();                                  // STM32 setup
  124.   printf ("Interrupt driven Serial I/O Example\r\n\r\n");
  125.   while (1) {                                     // Loop forever
  126.     unsigned char c;
  127.     printf ("Press a key. ");
  128.     c = getchar ();
  129.     printf ("\r\n");
  130.     printf ("You pressed '%c'.\r\n\r\n", c);
  131.   } // end while
  132. } // end main
工程文件,初始化有点乱,不过这个是脚本配置的,不需要我们手动配置寄存器。

二、关键字:硬缓冲(带串口fifo)、中断接收、中断发送、手动触发、全双工。
这个程序时新塘mini51的demo,网上也有固件包可以下载。跟上面的程序基本雷同。

  1. /*---------------------------------------------------------------------------------------------------------*/
  2. /* Copyright(c) 2011 Nuvoton Technology Corp. All rights reserved.                                         */
  3. /*---------------------------------------------------------------------------------------------------------*/
  4. /*-----------------------------------------------------------------------------
  5.   Nuvoton Technoledge Corp creadted by CA11  
  6.   XTAL = 12MHz, BPS = 115200
  7. *-----------------------------------------------------------------------------*/
  8. #include "Common.h"
  9. #define RXBUFSIZE 64
  10. //全局变量   
  11. volatile uint8_t comRbuf[RXBUFSIZE];
  12. volatile uint16_t comRbytes = 0;                  
  13. volatile uint16_t comRhead  = 0;
  14. volatile uint16_t comRtail  = 0;
  15. volatile int32_t g_bWait  = 1;
  16. /****************************************************************************************
  17. 描述 :  UART0中断代码
  18. ****************************************************************************************/
  19. void UART0_IRQHandler(void)
  20. {
  21.     uint8_t bInChar[1]={0xFF};

  22.     if(UA_ISR & RDA_INT)                               //检查是否接收中断   
  23.     {
  24.         printf("\nInput:");
  25.   

  26.         while(UA_ISR & RDA_IF)                         //检查接收到底数据是否有效   
  27.         {
  28.             while (UA_FSR & RX_EMPTY);                 //等字符   
  29.             bInChar[0] = UA_RBR;                       //读取字符   
  30.             printf("%c ", bInChar[0]);
  31.    
  32.             if(bInChar[0] == '0')
  33.             {
  34.                 g_bWait = 0;
  35.             }
  36.   
  37.             if(comRbytes < RXBUFSIZE)                  //测缓冲区满否?   
  38.             {
  39.                 comRbuf[comRtail] = bInChar[0];        //字符队列   
  40.                 comRtail = (comRtail == (RXBUFSIZE-1)) ? 0 : (comRtail+1);
  41.                 comRbytes++;
  42.             }   
  43.         }
  44.         printf("\nTransmission Test:");
  45.     }
  46.     else if(UA_ISR & THRE_INT)                         //检查是否发送中断   
  47.     {        
  48.         uint16_t tmp;
  49.         tmp = comRtail;
  50.         if(comRhead != tmp)
  51.         {
  52.             bInChar[0] = comRbuf[comRhead];
  53.    
  54.             while((UA_FSR&TX_FULL) != 0);              //发送FIFO满时等待   
  55.             UA_THR = bInChar[0];                       //发送一个字符   
  56.             comRhead = (comRhead == (RXBUFSIZE-1)) ? 0 : (comRhead+1);
  57.             comRbytes--;
  58.         }
  59.     }
  60. }
  61. int32_t main()
  62. {      
  63.     Un_Lock_Reg();                                     //解锁被保护的寄存器位,以便用户访问   
  64.     PWRCON = PWRCON & (~XTLCLK_EN) | XTAL12M_EN;       //使能外晶振   
  65.     while((CLKSTATUS & XTL_STB) == 0);                 //等12M时钟稳定   
  66.     CLKSEL0 = (CLKSEL0 & (~HCLK)) | HCLK_12M_32K;      //选12M为系统时钟   
  67.     Lock_Reg();                                        //重新锁被保护的寄存器位   
  68.     UART_Init();
  69.     printf("\nUART Sample Demo. (Press '0' to exit)\n");

  70.     UA_IER |= (RDA_IEN | THRE_IEN | RLS_IEN);         //使能中断   
  71.     NVIC_ISER = UART_INT;                              //使能NVIC UART中断   
  72.     while(g_bWait);
  73.     UA_IER &= ~(RDA_IEN | THRE_IEN | RLS_IEN);        //禁中断   
  74.     NVIC_ICER = UART_INT;                              //禁止NVIC UART中断   
  75.     printf("\nUART Sample Demo End.\n");

  76.     return 0;
  77. }
这个工程文件就不上传了,要有固件库才能运行。mini51固件库新塘网站有下载。

以上程序是keil公司和新塘公司的demo,所以粗糙了点,将就着看吧。
如果你有更好的,可以贴上来晒晒。毕竟一个模块写过一次之后就尽量不再做重复劳动了。

本帖子中包含更多资源

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

×
max_v 发表于 2013-12-21 23:17 | 显示全部楼层
先收藏了  
as564335sa 发表于 2013-12-21 23:42 | 显示全部楼层
dirtwillfly 发表于 2013-12-22 10:56 | 显示全部楼层
谢谢楼主分享
限量_个性。 发表于 2013-12-22 16:31 | 显示全部楼层
学习学习。
 楼主| dong_abc 发表于 2013-12-23 00:15 | 显示全部楼层
本帖最后由 dong_abc 于 2013-12-23 00:42 编辑

本想抛个砖看能否引点玉出来,有点小失望,顶一下。
john_lee 发表于 2013-12-23 00:28 | 显示全部楼层
dong_abc 发表于 2013-12-23 00:15
本想抛个砖看能否引点玉出来,有点小失望,顶一下。

“老鸟不用看了”,小草的意思是让菜鸟把玉拿出来?:lol
hk461073025 发表于 2013-12-23 00:36 | 显示全部楼层
先收下,留着参看一下
 楼主| dong_abc 发表于 2013-12-23 00:38 | 显示全部楼层
本帖最后由 dong_abc 于 2013-12-23 00:46 编辑
john_lee 发表于 2013-12-23 00:28
“老鸟不用看了”,小草的意思是让菜鸟把玉拿出来?


老鸟都是不喜欢回帖。有些菜鸟程序写的还可以呀。  看来要把标题改一下,把老鸟的玉引出来.哈哈
ayb_ice 发表于 2013-12-23 08:12 | 显示全部楼层
这有啥嘛

很多人都这么用的
 楼主| dong_abc 发表于 2013-12-23 10:03 来自手机 | 显示全部楼层
ayb_ice 发表于 2013-12-23 08:12
这有啥嘛

很多人都这么用的

我看见好几个人还在用查询的模式啊,全是阻塞,我说他程序效率太差他还觉得很好。
ayb_ice 发表于 2013-12-23 11:43 | 显示全部楼层
dong_abc 发表于 2013-12-23 10:03
我看见好几个人还在用查询的模式啊,全是阻塞,我说他程序效率太差他还觉得很好。 ...

通信速率快的话,协议简单,查询是不错的方式

评论

自从打通了中断,就没用过查询了。貌视查询还能省几个全局变量呢。  发表于 2013-12-23 19:06
booker211 发表于 2013-12-23 17:29 | 显示全部楼层
楼主给力
dengxingling8 发表于 2013-12-23 22:37 | 显示全部楼层
hnkf118 发表于 2014-12-23 15:39 | 显示全部楼层
我基本上都是这么写。搞成模块 方便



















本帖子中包含更多资源

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

×
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:此id已冬眠...

43

主题

5073

帖子

22

粉丝
快速回复 在线客服 返回列表 返回顶部