打印

发个串口通信的程序

[复制链接]
2821|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dong_abc|  楼主 | 2013-12-21 22:33 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 dong_abc 于 2013-12-23 04:35 编辑

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

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

/*----------------------------------------------------------------------------
  Notes:
  The length of the receive and transmit buffers must be a power of 2.
  Each buffer has a next_in and a next_out index.
  If next_in = next_out, the buffer is empty.
  (next_in - next_out) % buffer_size = the number of characters in the buffer.
*----------------------------------------------------------------------------*/
#define TBUF_SIZE   256      /*** Must be a power of 2 (2,4,8,16,32,64,128,256,512,...) ***/
#define RBUF_SIZE   256      /*** Must be a power of 2 (2,4,8,16,32,64,128,256,512,...) ***/
/*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/
#if TBUF_SIZE < 2
#error TBUF_SIZE is too small.  It must be larger than 1.
#elif ((TBUF_SIZE & (TBUF_SIZE-1)) != 0)
#error TBUF_SIZE must be a power of 2.
#endif
#if RBUF_SIZE < 2
#error RBUF_SIZE is too small.  It must be larger than 1.
#elif ((RBUF_SIZE & (RBUF_SIZE-1)) != 0)
#error RBUF_SIZE must be a power of 2.
#endif
/*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/
struct buf_st {
  unsigned int in;                                // Next In Index
  unsigned int out;                               // Next Out Index
  char buf [RBUF_SIZE];                           // Buffer
};
static struct buf_st rbuf = { 0, 0, };
#define SIO_RBUFLEN ((unsigned short)(rbuf.in - rbuf.out))
static struct buf_st tbuf = { 0, 0, };
#define SIO_TBUFLEN ((unsigned short)(tbuf.in - tbuf.out))
static unsigned int tx_restart = 1;               // NZ if TX restart is required
/*----------------------------------------------------------------------------
  USART1_IRQHandler
  Handles USART1 global interrupt request.
*----------------------------------------------------------------------------*/
void USART1_IRQHandler (void) {
  volatile unsigned int IIR;
  struct buf_st *p;
    IIR = USART1->SR;
    if (IIR & USART_FLAG_RXNE) {                  // read interrupt
      USART1->SR &= ~USART_FLAG_RXNE;           // clear interrupt
      p = &rbuf;
      if (((p->in - p->out) & ~(RBUF_SIZE-1)) == 0) {
        p->buf [p->in & (RBUF_SIZE-1)] = (USART1->DR & 0x1FF);
        p->in++;
      }
    }
    if (IIR & USART_FLAG_TXE) {
      USART1->SR &= ~USART_FLAG_TXE;           // clear interrupt
      p = &tbuf;
      if (p->in != p->out) {
        USART1->DR = (p->buf [p->out & (TBUF_SIZE-1)] & 0x1FF);
        p->out++;
        tx_restart = 0;
      }
      else {
        tx_restart = 1;
  USART1->CR1 &= ~USART_FLAG_TXE;        // disable TX interrupt if nothing to send
      }
    }
}
/*------------------------------------------------------------------------------
  buffer_Init
  initialize the buffers
*------------------------------------------------------------------------------*/
void buffer_Init (void) {
  tbuf.in = 0;                                    // Clear com buffer indexes
  tbuf.out = 0;
  tx_restart = 1;
  rbuf.in = 0;
  rbuf.out = 0;
}
/*------------------------------------------------------------------------------
  SenChar
  transmit a character
*------------------------------------------------------------------------------*/
int SendChar (int c) {
  struct buf_st *p = &tbuf;
                                                  // If the buffer is full, return an error value
  if (SIO_TBUFLEN >= TBUF_SIZE)
    return (-1);
                                                  
  p->buf [p->in & (TBUF_SIZE - 1)] = c;           // Add data to the transmit buffer.
  p->in++;
  if (tx_restart) {                               // If transmit interrupt is disabled, enable it
    tx_restart = 0;
USART1->CR1 |= USART_FLAG_TXE;            // enable TX interrupt
  }
  return (0);
}
/*------------------------------------------------------------------------------
  GetKey
  receive a character
*------------------------------------------------------------------------------*/
int GetKey (void) {
  struct buf_st *p = &rbuf;
  if (SIO_RBUFLEN == 0)
    return (-1);
  return (p->buf [(p->out++) & (RBUF_SIZE - 1)]);
}

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

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

/*---------------------------------------------------------------------------------------------------------*/
/* Copyright(c) 2011 Nuvoton Technology Corp. All rights reserved.                                         */
/*---------------------------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
  Nuvoton Technoledge Corp creadted by CA11  
  XTAL = 12MHz, BPS = 115200
*-----------------------------------------------------------------------------*/
#include "Common.h"
#define RXBUFSIZE 64
//全局变量   
volatile uint8_t comRbuf[RXBUFSIZE];
volatile uint16_t comRbytes = 0;                  
volatile uint16_t comRhead  = 0;
volatile uint16_t comRtail  = 0;
volatile int32_t g_bWait  = 1;
/****************************************************************************************
描述 :  UART0中断代码
****************************************************************************************/
void UART0_IRQHandler(void)
{
    uint8_t bInChar[1]={0xFF};

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

        while(UA_ISR & RDA_IF)                         //检查接收到底数据是否有效   
        {
            while (UA_FSR & RX_EMPTY);                 //等字符   
            bInChar[0] = UA_RBR;                       //读取字符   
            printf("%c ", bInChar[0]);
   
            if(bInChar[0] == '0')
            {
                g_bWait = 0;
            }
  
            if(comRbytes < RXBUFSIZE)                  //测缓冲区满否?   
            {
                comRbuf[comRtail] = bInChar[0];        //字符队列   
                comRtail = (comRtail == (RXBUFSIZE-1)) ? 0 : (comRtail+1);
                comRbytes++;
            }   
        }
        printf("\nTransmission Test:");
    }
    else if(UA_ISR & THRE_INT)                         //检查是否发送中断   
    {        
        uint16_t tmp;
        tmp = comRtail;
        if(comRhead != tmp)
        {
            bInChar[0] = comRbuf[comRhead];
   
            while((UA_FSR&TX_FULL) != 0);              //发送FIFO满时等待   
            UA_THR = bInChar[0];                       //发送一个字符   
            comRhead = (comRhead == (RXBUFSIZE-1)) ? 0 : (comRhead+1);
            comRbytes--;
        }
    }
}
int32_t main()
{      
    Un_Lock_Reg();                                     //解锁被保护的寄存器位,以便用户访问   
    PWRCON = PWRCON & (~XTLCLK_EN) | XTAL12M_EN;       //使能外晶振   
    while((CLKSTATUS & XTL_STB) == 0);                 //等12M时钟稳定   
    CLKSEL0 = (CLKSEL0 & (~HCLK)) | HCLK_12M_32K;      //选12M为系统时钟   
    Lock_Reg();                                        //重新锁被保护的寄存器位   
    UART_Init();
    printf("\nUART Sample Demo. (Press '0' to exit)\n");

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

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

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

相关帖子

沙发
max_v| | 2013-12-21 23:17 | 只看该作者
先收藏了  

使用特权

评论回复
板凳
as564335sa| | 2013-12-21 23:42 | 只看该作者

使用特权

评论回复
地板
dirtwillfly| | 2013-12-22 10:56 | 只看该作者
谢谢楼主分享

使用特权

评论回复
5
限量_个性。| | 2013-12-22 16:31 | 只看该作者
学习学习。

使用特权

评论回复
6
dong_abc|  楼主 | 2013-12-23 00:15 | 只看该作者
本帖最后由 dong_abc 于 2013-12-23 00:42 编辑

本想抛个砖看能否引点玉出来,有点小失望,顶一下。

使用特权

评论回复
7
john_lee| | 2013-12-23 00:28 | 只看该作者
dong_abc 发表于 2013-12-23 00:15
本想抛个砖看能否引点玉出来,有点小失望,顶一下。

“老鸟不用看了”,小草的意思是让菜鸟把玉拿出来?:lol

使用特权

评论回复
8
hk461073025| | 2013-12-23 00:36 | 只看该作者
先收下,留着参看一下

使用特权

评论回复
9
dong_abc|  楼主 | 2013-12-23 00:38 | 只看该作者
本帖最后由 dong_abc 于 2013-12-23 00:46 编辑
john_lee 发表于 2013-12-23 00:28
“老鸟不用看了”,小草的意思是让菜鸟把玉拿出来?


老鸟都是不喜欢回帖。有些菜鸟程序写的还可以呀。  看来要把标题改一下,把老鸟的玉引出来.哈哈

使用特权

评论回复
10
ayb_ice| | 2013-12-23 08:12 | 只看该作者
这有啥嘛

很多人都这么用的

使用特权

评论回复
11
dong_abc|  楼主 | 2013-12-23 10:03 | 只看该作者
ayb_ice 发表于 2013-12-23 08:12
这有啥嘛

很多人都这么用的

我看见好几个人还在用查询的模式啊,全是阻塞,我说他程序效率太差他还觉得很好。

使用特权

评论回复
12
ayb_ice| | 2013-12-23 11:43 | 只看该作者
dong_abc 发表于 2013-12-23 10:03
我看见好几个人还在用查询的模式啊,全是阻塞,我说他程序效率太差他还觉得很好。 ...

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

使用特权

评论回复
评论
dong_abc 2013-12-23 19:06 回复TA
自从打通了中断,就没用过查询了。貌视查询还能省几个全局变量呢。 
13
booker211| | 2013-12-23 17:29 | 只看该作者
楼主给力

使用特权

评论回复
14
dengxingling8| | 2013-12-23 22:37 | 只看该作者
看看

使用特权

评论回复
15
hnkf118| | 2014-12-23 15:39 | 只看该作者
我基本上都是这么写。搞成模块 方便



















使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

43

主题

5074

帖子

22

粉丝