0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何来编写一个串口收发程序

汽车电子技术 来源:物联网知识 作者: 跋扈洋 2023-01-20 16:43 次阅读

介绍

串口(UART通用异步收发器,TTL)通讯是一种设备间的串行全双工通讯方式。由于UART是异步传输,没有传输同步时钟,为了保证数据的正确性,UART采用16倍数据波特率的时钟进行采样。因为它简便捷,因此大部分电子设备都支持该通讯方式工程师在调试设备时也经常使用该方式输出调试信息

本文详细的介绍如何来编写一个串口收发程序,我们采用常用的收发逻辑,发送直接编写函数进行实现,而接收使用中断进行完成。接收中断使用接收到一个字节和一帧数据两种中断触发方式。

USART中断

USART 有多个中断请求事件。微信截图_20230105161930.png

之所以介绍这个USART中断请求,是因为很多人在初学阶段,对串口怎么判断串口中断的状态不太了解,所以我这里重点来介绍一下。

一般在我们开始和配置完串口中断后,进入串口中断处理程序的情况会有很多,我们也可以自己选择打开哪些串口中断情况。一般情况下,我们在接受时主要使用的中断事件标志是RXNE和IDLE。

RXNE是接收中断,每接收一个字节都会出发这个中断,也是我们用的最频繁的中断请求。

IDLE 是空闲中断,每接收完一帧数据,总线就会暂时空闲,就会触发这个中断。

串口状态

串口的状态可以通过状态寄存器 USART_SR 读取。USART_SR 的各位描述如下:微信截图_20230105161930.png

这里我们关注一下两个位,第 5、6 位 RXNE 和 TC。

RXNE(读数据寄存器非空),当该位被置 1 的时候,就是提示已经有数据被接收到了,且可以读出来了。这时候我们要做的就是尽快去读取 USART_DR,通过读 USART_DR 可以该位清零,也可以向该位写 0,直接清除。

TC(发送完成),当该位被置位的时候,表示 USART_DR 内的数据已经被发送完成了。果设置了这个位的中断,则会产生中断。该位也有两种清零方式:

  1. 读 USART_SR,USART_DR。
  2. 直接向该位写 0。

实例

需求分析

本项目主要编写一个串口收发的实例。使用STM32F103C8T6充当MCU,在PC上使用串口调试助手充当上位机。每次PC向MCU下发一帧数据, MCU每接收一个字节数据,检查一下数据中是否有指令0x23,当接收到指令0x23的时候,MCU向上位机发送“PC”。当一帧数据接收完毕后,MCU向上位机发送“Receive a frame data”.

串口初始化

串口初始化的一般步骤可以总结为如下几个步骤:

  1. 串口时钟使能,GPIO 时钟使能。
  2. 设置引脚复用器映射:调用 GPIO_PinAFConfig 函数。
  3. GPIO 初始化设置:要设置模式为复用功能。
  4. 串口参数初始化:设置波特率,字长,奇偶校验等参数。
  5. 开启中断并且初始化 NVIC,使能中断(如果需要开启中断才需要这个步骤)。
  6. 使能串口。
#include "usart.h"
#include 
#include "stm32f1xx_hal.h
UART_HandleTypeDef huart3
void MX_USART3_UART_Init(void)


  huart3.Instance = USART3;
  huart3.Init.BaudRate = 115200;
  huart3.Init.WordLength = UART_WORDLENGTH_8B;
  huart3.Init.StopBits = UART_STOPBITS_1;
  huart3.Init.Parity = UART_PARITY_NONE;
  huart3.Init.Mode = UART_MODE_TX_RX;
  huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart3.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart3) != HAL_OK)
  {
    Error_Handler()
  __HAL_UART_ENABLE_IT(&huart3,UART_IT_RXNE);//接收中断使能
  __HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);//空闲中断使能 
}


void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)


  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART3)
  {
    __HAL_RCC_USART3_CLK_ENABLE()
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**USART3 GPIO Configuration
    PB10     ------> USART3_TX
    PB11     ------> USART3_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct)
    GPIO_InitStruct.Pin = GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    HAL_NVIC_SetPriority(USART3_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(USART3_IRQn);

我们平时需要改的其实就是串口的一些参数配置。

  • BaudRate:波特率
  • WordLength;:字长
  • StopBits:停止位
  • Parity:奇偶校验
  • Mode:收/发模式设置
  • HwFlowCtl:硬件流设置
  • OverSampling:过采样设置

串口发送

串口发送这里使用的非中断发送方式。

/*******************************************************************************
  * @函数名称  USART_Send
  * @函数说明   发送信息
  * @输入参数   _UART:串口号
      data:要发送的信息的首地址
      len:发送的长度
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
void USART_Send(USART_TypeDef *_UART,uint8_t *data,uint8_t len)
{
  for(int i;i

主要使用的是HAL_UART_Transmit(&huart3,&Res,1,0Xffff);

这是一个阻塞的发送函数,无需重复判断串口是否发送完成。发送每个字符,直到遇空字符才停止发送。其中第一个参数是串口号,第二个参数是要发送的数据起始地址,第三个是要发送的数据长度,第四个超时时间(超过此长度仍未发送成功则阻塞完毕,停止发送,函数执行完毕)。

串口接收

这里串口接收使用的是中断的方式。

中断的类别在文章的最上边已经介绍过。我们在初始化时设定触发中断的类型。本文中设置的

__HAL_UART_ENABLE_IT(&huart3,UART_IT_RXNE);//接收中断使能
__HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);//空闲中断使能

代表只有接收数据和空闲中断会触发。

在stm32f1xx_it.c中有我们的串口中断处理函数。我们将这个函数进行重构。

void USART3_IRQHandler(void)
{
  uint8_t Res;
if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_RXNE)!=RESET
{
  HAL_UART_Receive(&huart3,&Res,1,0Xffff); 
 if(Res==0x23)  
  printf("PC");
}
else if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE)!=RESET)//空闲中断(代表这一帧数据传输完了)
{
  printf("Receive a frame data.");
  __HAL_UART_CLEAR_IDLEFLAG(&huart3);
}

这里面的几个重点,我们来一一介绍。

首先是判断标志位,我们使用HAL库中的__HAL_UART_GET_FLAG()函数,里面有两个参数,前者是串口句柄,后者是具体哪个标志位。

if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_RXNE)!=RESET)用来检测是否检测到有单个字节的中断。

if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE)!=RESET)用来检测是否有空闲中断(代表这一帧数据传输完了)。

重定向printf和scanf

还有一点需要注意的,使用 fput 和 fgetc 函数达到重定向 C 语言标准库输入输出函数必须在 MDK 的工程选项把“Use MicroLIB”勾选上, MicoroLIB 是缺省 C 库的备选库,它对标准 C 库进行了高度优化使代码更少,占用更少资源

为使用 printf、 scanf 函数需要在文件中包含 stdio.h 头文件。

/**
  * 函数功能: 重定向c库函数printf
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}

/**
  * 函数功能: 重定向c库函数getchar,scanf
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fgetc(FILE *f)
{
  uint8_t ch = 0;
  HAL_UART_Receive(&huart3, &ch, 1, 0xffff);
  return ch;
}

效果

  1. PC下发:11 22 33 44

    微信截图_20230105161930.png

  2. PC下发:12 23 34 45

    微信截图_20230105161930.png

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

    关注

    10

    文章

    3424

    浏览量

    105952
  • 串口
    +关注

    关注

    14

    文章

    1551

    浏览量

    76406
  • uart
    +关注

    关注

    22

    文章

    1235

    浏览量

    101343
收藏 人收藏

    评论

    相关推荐

    【紫光同创国产FPGA教程】【第五章】串口收发实验

    本文主要讲解如何编写FPGA串口通信的收发程序,在程序中使用了状态机,是学习状态机的重要实验。
    的头像 发表于 02-04 13:23 6717次阅读
    【紫光同创国产FPGA教程】【第五章】<b class='flag-5'>串口</b><b class='flag-5'>收发</b>实验

    编写一个QT程序

    学习种编程语言或编程环境,通常会先编写“Hello World”程序。我们也用 Qt Creator
    发表于 11-21 10:41 1017次阅读

    如何去编写种基于Atmega8单片机的串口收发程序

    如何去编写种基于Atmega8单片机的串口收发程序?有大神遇到过这个问题吗
    发表于 07-08 06:06

    如何利用AVR编写简单的串口通信的程序

    如何利用AVR编写简单的串口通信的程序
    发表于 11-02 08:06

    STM32的串口收发程序如何编写

    STM32的串口收发程序如何编写
    发表于 12-16 07:34

    怎样去编写串口数据接收程序

    【嵌入式】串口数据接收程序1.题目详情2.代码详解1.题目详情编写串口数据接收
    发表于 12-21 06:12

    分享串口收发的小程序功能

    串口收发的小程序功能就是串口数据的收发;设置标题
    发表于 01-18 07:53

    求大佬分享stm32自收发串口通信程序

    求大佬分享stm32自收发串口通信程序
    发表于 02-18 07:40

    VHDL设计的串口通信程序

    本模块的功能是验证实现和PC机进行基本的串口通信的功能。需要在PC机上安装串口调试工具来验证程序的功能。
    发表于 06-05 12:03 2849次阅读

    labview串口编写中可能用到的程序

    串口编写中可能用到的程序
    发表于 01-03 16:49 10次下载

    如何使用Python编写简单的程序

    按照软件行业传统习惯,当你学习种新的编程语言如Python时,首先编写“Hello World! ”程序。请执行以下步骤,以创造你的“
    的头像 发表于 01-16 15:21 2.2w次阅读

    verilog编写UART串口程序下载

    收发程序写在.v文件中,已经在板子上实验过,收发正常
    发表于 12-21 18:08 0次下载
    verilog<b class='flag-5'>编写</b>UART<b class='flag-5'>串口</b><b class='flag-5'>程序</b>下载

    如何编写一个hello world程序

    本文简单介绍如何编写一个hello world程序,以及程序是如何被执行的
    的头像 发表于 03-02 17:31 8372次阅读
    如何<b class='flag-5'>编写</b>第<b class='flag-5'>一个</b>hello world<b class='flag-5'>程序</b>

    串口工具监听多路串口收发方案

    当我们仅有串口工具时,如何通过简单的方式,来做到串口工具,监听
    的头像 发表于 03-22 15:46 3409次阅读
    <b class='flag-5'>一</b><b class='flag-5'>个</b><b class='flag-5'>串口</b>工具监听多路<b class='flag-5'>串口</b><b class='flag-5'>收发</b>方案

    vim编写程序后怎么运行

    当你用 Vim 编写程序后,你需要执行系列步骤来运行程序。下面是详尽的说明: 保存文件:
    的头像 发表于 11-28 15:27 3636次阅读