STM32-08-串口

文章目录

  • STM32 串口
    • 1. 数据通信的基本概念
    • 2. 串口通信协议
    • 3. 串口
    • 4. 相关寄存器
    • 5. MSP回调机制
    • 6. HAL库中断回调机制
    • 7. USART/UART异步通信配置步骤
    • 8. IO引脚复用功能
    • 9. 代码实现

STM32 串口

1. 数据通信的基本概念

  1. 通信方式:
    在这里插入图片描述

  2. 数据传输方向:
    在这里插入图片描述

  3. 数据同步方式:
    在这里插入图片描述

  • 通信速率:

    在数字通信系统中,通信速率(传输速率)指数据在信道中传输的速度,分为传信率传码率

    传信率(比特率):每秒钟传输的信息量,即每秒钟传输的二进制位数,单位为bit/s;

    传码率(波特率):每秒钟传输的码元个数,单位为Band.

    比特率与波特率之间的关系:

    比特率 = 波特率 * log2M

    M表示码元承载的信息量,可以理解为码元的进制数,码元采用二进制编码时,数值上波特率与比特率相等。

  • 常见的串行通信接口

    通信接口接口引脚数据同步方式数据传输方向
    UART (通用异步收发器)TXD:发送端 RXD:接收端 GND:公共地异步通信全双工
    1-wireDQ:发送/接收端异步通信半双工
    IICSCL:同步时钟 SDA:数据输入/输出端同步通信半双工
    SPISCK:同步时钟 MISO:主机输入,从机输出 MOSI:主机输出,从机输入 CS:片选信号同步通信全双工

2. 串口通信协议

串行通信协议是指规定了数据包的内容,内容包含了起始位主体数据校验位停止位,双方需要约定一致的数据包格式才能正常收发数据的有关规范。
在这里插入图片描述

  1. 波特率:波特率表示每秒传送的码元符号的个数,决定数据帧里面一个位的时间长度,两个要通信的设备的波特率一定要设置相同,常见的波特率是4800,9600,115200.
  2. 数据帧格式:起始位、停止位、有效数据位、校验位。
    • 起始位和停止位:串行通信的一个数据帧是从起始位开始,直到停止位。数据帧中的起始位是由一个逻辑0的数据位表示,而数据帧的停止位可以是0.5、1、1.5、2个逻辑1的数据位表示,只要双方约定一致即可。
    • 有效数据位:数据帧的起始位之后,紧接着数据位,这是我们发送的有效数据,有效数据位是低位在前,高位在后。
    • 校验位:校验位可以认为是一个特殊的数据位。一般用来判断接收的数据位有无错误,检验的方法有:奇校验、偶校验、0校验、1校验。奇校验代表的是数据位和校验位中1的个数为奇数;偶校验代表的是数据位和校验位中1的个数为偶数;0 校验是指不管有效数据中的内容是什么,校验位总为0,1 校验是校验位总为1。 无校验是指数据帧中不包含校验位。

3. 串口

  • 串口:串行通信接口,指按位发送和接收的接口。

  • RS232接口
    在这里插入图片描述

    通信示意图
    在这里插入图片描述

  • USB接口
    在这里插入图片描述

  • USART框图
    在这里插入图片描述

  • 简化版框图
    在这里插入图片描述

  • 设置波特率
    在这里插入图片描述
    - 波特率相关寄存器
    在这里插入图片描述

4. 相关寄存器

  • 控制寄存器1CR1
    在这里插入图片描述

在这里插入图片描述在这里插入图片描述

  • 控制寄存器2CR2
    在这里插入图片描述

  • 控制寄存器3CR3
    在这里插入图片描述

  • 数据寄存器DR
    在这里插入图片描述

  • 状态寄存器SR
    在这里插入图片描述

5. MSP回调机制

在这里插入图片描述

在这里插入图片描述

6. HAL库中断回调机制

在这里插入图片描述

在这里插入图片描述

7. USART/UART异步通信配置步骤

  1. 配置串口工作参数

    HAL_UART_Init()
    
  2. 串口底层初始化

    HAL_UART_MspInit() 
    
  3. 开启串口异步接收中断

    HAL_UART_Receive_IT()
    
  4. 设置优先级,使能中断

    HAL_NVIC_SetPriority()
    HAL_NVIC_EnableIRQ()
    
  5. 编写中断服务函数

    USARTx_IRQHandler()
    UARTx_IRQHandler()
    
  6. 串口数据发送

    HAL_UART_Transmit()
    

8. IO引脚复用功能

  • 通用与复用

    通用:IO端口的输入或输出是由GPIO外设控制

    复用:IO端口的输入或输出由其它非GPIO外设控制

  • IO复用功能冲突问题:同一时间IO只能用作一种复用功能,否则会发生冲突,当遇到冲突时,可以考虑重映射功能。

  • 实现:IO复用功能的实现是通过AFIO寄存器,STM32F103ZET6共有6个AFIO的寄存器,事件控制寄存器AFIO_EVCR,复用重映射和调试I/O配置寄存器AFIO_MAPR,外部中断配置寄存器AFIO_EXTICR1,外部中断配置寄存器AFIO_EXTICR2,外部中断配置寄存器AFIO_EXTICR3,外部中断配置寄存器AFIO_EXTICR4

    复用重映射和调试I/O配置寄存器AFIO_MAPR寄存器用来实现引脚的重映射功能。

    例如 AFIO_MAPR 寄存器位 2 是对 USART1 的重映射,置 0: 没有重映像(TX/PA9,RX/PA10); 置 1: 重映像(TX/PB6,RX/PB7)。默认情况下,PA9 和 PA10 是作为串口 1 的引脚使用,假如 PA9 和 PA10 被用作其它地方,但还是需要用到串口 1,那么就可以在 AFIO_MAPR 的位 2 置 1,把串口 1 的引脚重映射到 PB6和PB7。
    在这里插入图片描述

9. 代码实现

  • 主要实现功能:通过串口接收或发送一个字符。

  • 硬件原理图
    电脑的USB引脚CH340 D+CH340 D-通过CH340C芯片与串口的TXD与RXD相连接,然后通过一个端子连接到单片机的USART1 RX PA10USART1 TX PA9引脚,从而完成单片机的串口与电脑的USB口的连接。
    在这里插入图片描述

  • 代码实现

    1. 配置串口工作参数

      void usart_init(uint32_t baudrate)
      {
          /*UART 初始化设置*/
          g_uart1_handle.Instance = USART1;                                     /* USART_UX */
          g_uart1_handle.Init.BaudRate = baudrate;                              /* 波特率 */
          g_uart1_handle.Init.WordLength = UART_WORDLENGTH_8B;                  /* 字长为8位数据格式 */
          g_uart1_handle.Init.StopBits = UART_STOPBITS_1;                       /* 一个停止位 */
          g_uart1_handle.Init.Parity = UART_PARITY_NONE;                        /* 无奇偶校验位 */
          g_uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;                  /* 无硬件流控 */
          g_uart1_handle.Init.Mode = UART_MODE_TX_RX;                           /* 收发模式 */
          HAL_UART_Init(&g_uart1_handle);                                       /* HAL_UART_Init()会使能UART1 */
      
          /* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */
          HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE); 
      }
      
    2. 串口底层初始化

      void HAL_UART_MspInit(UART_HandleTypeDef *huart)
      {
          GPIO_InitTypeDef gpio_init_struct;
      
          if (huart->Instance == USART1)                             /* 如果是串口1,进行串口1 MSP初始化 */
          {
              USART_TX_GPIO_CLK_ENABLE();                            /* 使能串口TX脚时钟 */
              USART_RX_GPIO_CLK_ENABLE();                            /* 使能串口RX脚时钟 */
              USART_UX_CLK_ENABLE();                                 /* 使能串口时钟 */
      
              gpio_init_struct.Pin = USART_TX_GPIO_PIN;              /* 串口发送引脚号 */
              gpio_init_struct.Mode = GPIO_MODE_AF_PP;               /* 复用推挽输出 */
              gpio_init_struct.Pull = GPIO_PULLUP;                   /* 上拉 */
              gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;         /* IO速度设置为高速 */
              HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct);
                      
              gpio_init_struct.Pin = USART_RX_GPIO_PIN;              /* 串口RX脚 模式设置 */
              gpio_init_struct.Mode = GPIO_MODE_AF_INPUT;            /* 串口RX脚 必须设置成输入模式 */
              gpio_init_struct.Pull = GPIO_PULLUP;                   //设置上拉输入
              HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct);   
              
      #if USART_EN_RX
              HAL_NVIC_EnableIRQ(USART_UX_IRQn);                     /* 使能USART1中断通道 */
              HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3);             /* 组2,最低优先级:抢占优先级3,子优先级3 */
      #endif
          }
      }
      
    3. 开启串口异步接收中断

      1.中实现
      
    4. 设置中断优先级

      2.中实现
      
    5. 编写中断服务函数

      void USART1_IRQHandler(void)
      {
          HAL_UART_IRQHandler(&g_uart1_handle);   /* 调用HAL库中断处理公用函数 */
      }
      
    6. 编写接收完成回调函数

      void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
      {
          if (huart->Instance == USART1)                    /* 如果是串口1 */
          {
              if ((g_usart_rx_sta & 0x8000) == 0)             /* 接收未完成 */
              {
                  if (g_usart_rx_sta & 0x4000)                /* 接收到了0x0d(即回车键) */
                  {
                      if (g_rx_buffer[0] != 0x0a)             /* 接收到的不是0x0a(即不是换行键) */
                      {
                          g_usart_rx_sta = 0;                 /* 接收错误,重新开始 */
                      }
                      else                                    /* 接收到的是0x0a(即换行键) */
                      {
                          g_usart_rx_sta |= 0x8000;           /* 接收完成了 */
                      }
                  }
                  else                                        /* 还没收到0X0d(即回车键) */
                  {
                      if (g_rx_buffer[0] == 0x0d)
                          g_usart_rx_sta |= 0x4000;
                      else
                      {
                          g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = g_rx_buffer[0];
                          g_usart_rx_sta++;
      
                          if (g_usart_rx_sta > (USART_REC_LEN - 1))
                          {
                              g_usart_rx_sta = 0;             /* 接收数据错误,重新开始接收 */
                          }
                      }
                  }
              }
      
              HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);
          }
      }
      

      在接收完成回调函数中,首先判断串口的类型,然后按照接收的数据格式进行判断,以回车符(0x0d)和换行符(0x0a)为结尾,如果未接收到回车符和换行符,表示数据未接收完成,g_usart_rx_sta为串口接收标志,用于判断是否接收完成;g_rx_buffer数据接收缓冲区,串口发送过来的数据会存放在该缓冲区,然后把接收到的数据放在g_usart_rx_buf数组里面。在接收完成后,开启串口异步接收中断,等待下一次数据的接收。

    7. 主函数的编写

      // 1. 定义串口接收数据长度的变量和超时时间变量
          uint8_t len;
          uint16_t times = 0;
      
      //2. 进行各种外设的初始化操作,打开相关外设的时钟
          HAL_Init();                         /* 初始化HAL库 */
          sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
          delay_init(72);                     /* 延时初始化 */
          led_init();                         /* LED初始化 */
          key_init();            //按键初始化
          beep_init();           //蜂鸣器初始化
          exti_init();           //外部中断初始化
          usart_init(115200);    //串口初始化 
      
      //3. 循环主体
           while (1)
          {
              
              if (g_usart_rx_sta & 0x8000)        /* 接收到了数据 */
              {
                  len = g_usart_rx_sta & 0x3fff;  /* 得到此次接收到的数据长度 */
                  printf("\r\n您发送的消息为:\r\n");
      
                  HAL_UART_Transmit(&g_uart1_handle,(uint8_t*)g_usart_rx_buf, len, 1000);  /* 发送接收到的数据 */
                  while(__HAL_UART_GET_FLAG(&g_uart1_handle, UART_FLAG_TC) != SET);        /* 等待发送结束 */
                  printf("\r\n\r\n");             /* 插入换行 */
                  g_usart_rx_sta = 0;
              }
              else
              {
                  times++;
        
                  if (times % 30  == 0)
                      LED_toggle(); /* 闪烁LED,提示系统正在运行. */
                                           
                  delay_ms(10);
              }
          }
      

      主函数的循环里面主要是判断是否接收到数据,然后把接收到的数据发送出去,通过SR寄存器的TC位判断数据是否发送完成;同时使用LED灯代表系统在正常运行。

声明:资料来源(战舰STM32F103ZET6开发板资源包)

  1. Cortex-M3权威指南(中文).pdf
  2. STM32F10xxx参考手册_V10(中文版).pdf
  3. STM32F103 战舰开发指南V1.3.pdf
  4. STM32F103ZET6(中文版).pdf
  5. 战舰V4 硬件参考手册_V1.0.pdf

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/631459.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

革命性GPT-4o:重塑人机交互体验

OpenAI 发布的 GPT-4o 模型无疑是一个巨大的突破,特别是在其能够处理多种输入媒介(文本、音频、图像)并生成相应输出方面。这种能力使得人机交互更加自然和直观,极大地提升了 AI 的实用性和可用性。GPT-4o 的几个关键亮点包括&…

Springboot+Vue项目-基于Java+MySQL的火锅店管理系统(附源码+演示视频+LW)

大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:Java毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计 &…

【Linux:环境变量】

环境变量一般是指在操作系统中用来指定操作系统环境的一些参数 常见的环境变量: PATH 指定可执行程序的搜索路径 系统级的文件:/etc/bashrc 用户级文件:~/.bashrc ~/.bash_profile HOME 指定用户的主要工作目录(当前用…

如何下载小米壁纸到本地分享给他人

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 操作方法 📒🚥 注意事项⚓️ 相关链接 ⚓️📖 介绍 📖 你是否曾被小米主题壁纸软件中的精美壁纸所吸引,却苦于无法将其下载到本地或与朋友分享?本文将为你揭晓如何将小米壁纸下载到本地分享给他人! 🏡 演示环境 �…

UVM寄存器模型——手写Ralf问题debug

寄存器模型是UVM中至关重要的一部分,如果没有寄存器模型,那么验证平台对于DUT内寄存器的访问方式将十分有限,对DUT运行状态的把控也会变得更为复杂。 在验证过程中,scoreboard或者其他验证组件经常需要了解当前时间某个寄存器的值…

【Python】图像批量合成视频,并以文件夹名称命名合成的视频

一个文件夹中有多个子文件夹,子文件夹中有多张图像。如何把批量把子文件夹中的图像合成视频,视频名称是子文件夹的名称,生成的视频保存到指定文件夹,效果记录。 代码 import os import cv2def create_video_from_images(image_f…

位运算概述

首先 位运算这个东西在考试中十分容易考,所以要多多看一看位运算的相关知识,多刷一刷题之类的。 位运算的概念 位运算就是二进制数据进行运算的运算符。 注意:通常我们用二进制补码来表示,补码的符号位也是要参与运算的。 通常的…

番外篇 | 一文读懂卷积神经网络(CNN)的基础概念及原理

前言:Hello大家好,我是小哥谈。卷积神经网络(Convolutional Neural Network,CNN)是一种深度学习模型,主要用于图像识别和计算机视觉任务。本文旨在对卷积神经网络进行详细的讲解,从基本原理到实际应用,帮助读者全面了解CNN的工作原理、优势和基本组成等,以及其在现实生…

HNU-算法设计与分析-作业3

第三次作业【动态规划】 文章目录 第三次作业【动态规划】<1>算法实现题 3-1 独立任务最优解问题<2>算法实现题 3-4 数字三角形问题<3>算法实现题 3-8 最小m段和问题<4>算法实现题 3-25 m处理器问题 <1>算法实现题 3-1 独立任务最优解问题 ▲问…

巴伦电路的原理及设计

本文档是针对Appcad帮助文档及si4468等电路设计内容的整合&#xff0c;参考了其中的内容。 1.巴伦的传输线与集总电路转换简述 巴伦是一种在平衡和非平衡电路连接之间进行转换的电路。balun 一词是由 BALanced 和UNbalanced 两个词的缩写衍生而来的首字母缩写词。不平衡连接也…

svn如何远程访问?

svn&#xff08;Subversion&#xff09;是一种版本控制系统&#xff0c;广泛应用于软件开发领域。它能够追踪文件和目录的变化&#xff0c;记录每个版本的修改内容&#xff0c;并允许多人协同开发。svn的远程访问功能允许开发人员可以在不同的地点访问和管理代码&#xff0c;提…

AIGC时代已至,你准备好抓住机遇了吗?

一、行业前景 AIGC&#xff0c;即人工智能生成内容&#xff0c;是近年来人工智能领域中发展迅猛的一个分支。随着大数据、云计算、机器学习等技术的不断进步&#xff0c;AIGC已经取得了显著的成果&#xff0c;并且在广告、游戏、自媒体、教育、电商等多个领域实现了广泛应用。…

24年湖南三支一扶报名流程图及报名照片要求

24湖南三支一扶报名流程图&#xff0c;照片要求☑️ ✔️报名时间&#xff1a;5月15日9:00至5月23日17:00 ✔️报名方式 报考人员登录市州人力资源社会保障局官网、市州人事考试网等查看各地公告&#xff0c;按要求报名。 ✔️报名流程&#xff08;湖南各地市单独报名&…

EtherCAT通信特点_7

一个 EtherCAT 数据帧足以完成所有节点控制数据的发送和接收。 question&#xff1a;数据会不会超过限制&#xff1f; 一个 EtherCAT 数据帧足以完成所有节点控制数据的发送和接收&#xff0c;这种高性能的运行模式克服了前面章节描述的各种问题&#xff01; EtherCAT 主站发送…

分布式计算、并行计算、网格计算、边缘计算

分布式计算 分布式计算是一种计算方法&#xff0c;它将一个大型的计算任务分解成多个子任务&#xff0c;并将这些子任务分布在网络上的多台计算机&#xff08;节点&#xff09;上同时执行。这些节点通过通信网络协同工作&#xff0c;共同完成任务。每个节点可以独立处理自己的…

VS2022如何添加现有项

以 想在队列里&#xff0c;使用堆栈的.c&#xff0c;.h文件 为例 目录 1.复制堆栈的.c&#xff0c;.h文件 ​编辑 2.打开队列所在项目的文件夹 3.粘贴堆栈的.c&#xff0c;.h文件 4.在头文件和源文件添加相应的堆栈的.c&#xff0c;.h文件 1.复制堆栈的.c&#xff0c;.h文件…

【Python探索之旅】元组

元组的作用 遍历 修改 元组运算符 索引和切片 加法运算符 重复运算符 比较运算符 完结撒花 前言 元组(tuple)是一种静态的(immutable)或者说是不可变(unchangeable)的数据结构&#xff0c;里面的元素按照一定的顺序排列。它是静态的&#xff0c;所以元组里的元素不能被…

Nginx企业级负载均衡:技术详解系列(1)

你好呀&#xff0c;我是赵兴晨&#xff0c;文科程序员。 最近&#xff0c;我注意到关于Nginx的文章总是能吸引到异常多的流量。这让我意识到&#xff0c;或许大家对这个话题有着浓厚的兴趣。既然如此&#xff0c;我决定将更多关于Nginx的深度内容与大家分享。 在接下来的时间…

[数据集][目标检测]肺结节检测数据集VOC+YOLO格式1186张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1186 标注数量(xml文件个数)&#xff1a;1186 标注数量(txt文件个数)&#xff1a;1186 标注…

【LAMMPS学习】十、LAMMPS辅助工具(1)

10. 辅助工具 LAMMPS 被设计为用于执行分子动力学计算的计算内核。设置和分析模拟通常需要额外的预处理和后处理步骤。此类工具的列表可以在 LAMMPS 网页上的以下链接中找到&#xff1a; 前/后处理 外部 LAMMPS 软件包和工具 Pizza.py 工具包 Pizza.py 的最后一个链接是桑迪…