串口通讯(Serial Communication) 简介4

电子说

1.3w人已加入

描述

软件设计

代码如下:

//初始化 IO 串口 1 
//bound:波特率
void uart_init(u32 bound)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;


    //①串口时钟使能,GPIO 时钟使能,复用时钟使能
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|
    RCC_APB2Periph_GPIOA, ENABLE); //使能 USART1,GPIOA 时钟


    //②串口复位
    USART_DeInit(USART1); //复位串口 1
    //③GPIO 端口模式设置
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //ISART1_TX PA.9
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.9


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //USART1_RX PA.10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.10


    //④串口参数初始化
    USART_InitStructure.USART_BaudRate = bound; //波特率设置
    USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为 8 位
    USART_InitStructure.USART_StopBits = USART_StopBits_1; //一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = 
    USART_HardwareFlowControl_None; //无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
    USART_Init(USART1, &USART_InitStructure); //初始化串口


    #if EN_USART1_RX //如果使能了接收
    //⑤初始化 NVIC
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ; //抢占优先级 3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级 3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
    NVIC_Init(&NVIC_InitStructure); //中断优先级初始化


    //⑤开启中断
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启中断
    #endif


    //⑥使能串口
    USART_Cmd(USART1, ENABLE); //使能串口
}

此代码的编写顺序即USART的配置顺序:

我们用标号①~⑥标 示了顺序:

① 串口时钟使能,GPIO 时钟使能

② 串口复位

    ③ GPIO 端口模式设置

    ④ 串口参数初始化

    ⑤ 初始化 NVIC 并且开启中断

    ⑥ 使能串口

配置全双工的串口 1,那么 TX(PA9) 管脚需要配置为推挽复用输出,RX(PA10)管脚配置为浮空输入或者带上拉输入。

模式配置参考下面表格:

串行通讯

使用了串口的中断接收,必须在 usart.h 里面设置 EN_USART1_RX 为 1(默认设置就是 1 的) 。该函数才会配置中断使能,以及开启串口 1 的 NVIC 中断。这里我们把串口 1 中断放在组 2,优先级设置为组 2 里面的最低。

接下来,根据之前讲解的步骤 7,还要编写中断服务函数。串口 1 的中断服务函数 USART1_IRQHandler。

USART1_IRQHandler 函数

void USART1_IRQHandler(void)函数是串口 1 的中断响应函数,当串口 1 发生了相应的中断后,就会跳到该函数执行。中断相应函数的名字是不能随便定义的,一般我们都遵循 MDK定义的函数名。这些函数名字在启动文件 startup_stm32f10x_hd.s 文件中可以找到。

函数体里面通过函数:

if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)

判断是否接受中断,如果是串口接受中断,则读取串口接受到的数据:

Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据

读到数据后接下来就对数据进行分析。

这里我们设计了一个小小的接收协议:通过这个函数,配合一个数组 USART_RX_BUF[],一个接收状态寄存器 USART_RX_STA(此寄存器其实就是一个全局变量,由作者自行添加。由于它起到类似寄存器的功能,这里暂且称之为寄存器)实现对串口数据的接收管理。

USART_RX_BUF 的大小由 USART_REC_LEN 定义,也就是一次接收的数据最大不能超过USART_REC_LEN 个字节。USART_RX_STA 是一个接收状态寄存器其各的定义如表 5.3.1.1 所示:

串行通讯

设计思路如下:

当接收到从电脑发过来的数据,把接收到的数据保存在 USART_RX_BUF 中,同时在接收状态寄存器(USART_RX_STA)中计数接收到的有效数据个数,当收到回车(回车的表示由 2个字节组成:0X0D 和 0X0A)的第一个字节 0X0D 时,计数器将不再增加,等待 0X0A 的到来,而如果 0X0A 没有来到,则认为这次接收失败,重新开始下一次接收。

如果顺利接收到 0X0A,则标记 USART_RX_STA 的第 15 位,这样完成一次接收,并等待该位被其他程序清除,从而开始下一次的接收,而如果迟迟没有收到 0X0D,那么在接收数据超过 USART_REC_LEN 的时候,则会丢弃前面的数据,重新接收。

中断相应函数代码如下:

void USART1_IRQHandler(void)                  //串口1中断服务程序
  {
  u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    {
    Res =USART_ReceiveData(USART1);  //读取接收到的数据


    if((USART_RX_STA&0x8000)==0)//接收未完成
      {
      if(USART_RX_STA&0x4000)//接收到了0x0d
        {
        if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
        else USART_RX_STA|=0x8000;  //接收完成了 
        }
      else //还没收到0X0D
        {  
        if(Res==0x0d)USART_RX_STA|=0x4000;
        else
          {
          USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
          USART_RX_STA++;
          if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收    
          }     
        }
      }        
     }
}

main.c中的代码

int main(void)
{    
   u16 t;  
  u16 len;  
  u16 times=0;
  delay_init();         //延时函数初始化    
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
  uart_init(115200);   //串口初始化为115200
   LED_Init();           //LED端口初始化
  KEY_Init();          //初始化与按键连接的硬件接口
   while(1)
  {
    if(USART_RX_STA&0x8000)
    {             
      len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
      printf("\\r\\n您发送的消息为:\\r\\n\\r\\n");
      for(t=0;t<len;t++)
      {
        USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据
        while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
      }
      printf("\\r\\n\\r\\n");//插入换行
      USART_RX_STA=0;
    }else
    {
      times++;
      if(times%5000==0)
      {
        printf("\\r\\n精英STM32开发板 串口实验\\r\\n");
        printf("正点原子@ALIENTEK\\r\\n\\r\\n");
      }
      if(times%200==0)printf("请输入数据,以回车键结束\\n");  
      if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
      delay_ms(10);   
    }
  }   
 }
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2)函数, 该函数是设置中断分组号为 2,也就是 2 位抢占优先级和 2 位子优先级。
USART_SendData(USART1, USART_RX_BUF[t]); //向串口 1 发送数据
 while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);

第一句,其实就是发送一个字节到串口。

第二句,就是我们在我们发送一个数据到串口之后,要检测这个数据是否已经被发送完成了。USART_FLAG_TC 是宏定义的数据发送完成标识符。

下载验证

首先打开串口调试助手。任何一个串口调试助手都是可以的。正点原子中使用的是旧版本的XCOM2.0。

串行通讯

我们在程序上 面设置了必须输入回车,串口才认可接收到的数据,所以必须在发送数据后再发送一个回车符, 这里 XCOM 提供的发送方法是通过勾选发送新行实现。

串行通讯

只要勾选了这个选项,每次发送数据后,XCOM 都会自动多发一个回车(0X0D+0X0A)。设置好了发送新行,我们再在发送区输入你想要发送的文字,然后单击发送,就能实现发送数据。

串行通讯

发送的数据被打印出来了,说明实验成功。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分