• 物联网ARM开发-4STM32串口通信USART应用


    一、串口通信基本概念

    1、同步通信和异步通信

    通信,最少要有两个对象,一个收,一个发。根据数据通信是否同步,可分为同步通信和异步通信。

    同步通信:
    一般情况下同步通信指的是通信双方根据同步信号进行通信的方式。
    比如通信双方有一个共同的时钟信号,通讯中通常双方会统一规定在时钟信号的上升沿或下降沿对数据线进行采样。

    异步通信:
    是指数据传输速度匹配依赖于通信双方有自己独立的系统时钟,大家约定好通信的速度。
    异步通信不需要同步信号,但是并不是说通信的过程不同步。

    2、串行通信和并行通信的区别

    串行通信:指的是同一时刻只能收或发一个bit位信息。因此只用1根信号线即可。
    -串行传输:数据按位顺序传输。  
    -优点:占用引脚资源少   
    -缺点:速度相对较慢

    并行通信:指的是同一时刻可以收或发多个bit位的信息,因此需要多根信号线才行
    -并行传输:数据各个位同时传输。   
    -优点:速度快   
    -缺点:占用引脚资源多

    3、单工、半双工、全双工

    单工:要么收,要么发,只能做接收设备或者发送设备。比如收音机

    半双工:可以收,可以发,但是不能同时收发, 比如对讲机

    全双工:可以在同一时刻既接收,又发送。 比如手机

    4、常见通信总结

     USART:    Universal Synchronous  Asynchronous Receiver and Transmitter的缩写,
    即通用同步异步收发器可以灵活地与外部设备进行全双工数据交换。

    UART 外设(Universal Asynchronous Receiver and Transmitter),
    它是在 USART基础上裁剪掉了同步通信功能,只有异步通信。简单区分同
    步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是 UART。

    USART 在 STM32应用最多莫过于“打印”程序信息,一般在硬件设计时都会预留一个 USART通信接口连接电脑,用于在调试程序是可以把一些调试信息“打印”在电脑端的串口调试助手工具上,从而了解程序运行是否正确、指出运行出错位置等等。

     STM32F407有四个 USART 和两个 UART,其中 USART1和 USART6 的时钟来源于 APB2 总线时钟,其最大频率为 84MHz,其他四个的时钟来源于 APB1总线时钟,其最大频率为 42MHz。
    中文参考手册2.1章、数据手册2.2 table4

     

    串口通信接口种类很多,下面几种都是串口

     

     

    5、传统通信协议

    一般不设置默认是下面这种数据类型,可以配置8-9位的数据位,可选奇偶校验位和1个停止位。

     6、波特率

    • -在串行通信中,用“波特率”来描述数据的传输速率。所谓波特率,既每秒传送的二进制位数,其单位为bps(bits per second)。它是衡量串行数据速度快慢的重要指标。
    • -国际上规定一个标准的波特率系列: 110、300、600、1200、1800、2400、4800、9600、115200、14.4Kbps、19.2Kbps、……例如:115200bps、指每秒传送115200位。通信双方必须设置同样的同学速率才能正常通信
    • 注意:实际的数据没这么多,还包括起始位,结束位,校验位

    二、串口寄存器介绍

     中文参考手册26

    1、控制寄存器USART_CR(截取来自中文参考手册说明)

    控制寄存器 1 (USART_CR1),这里截取了一部分常用位得说明

     

    位 7 TXEIE:TXE 中断使能 (TXE interrupt enable)
    此位由软件置 1 和清零。
    0:禁止中断
    1:当 USART_SR 寄存器中 TXE=1 时,生成 USART 中断。

    位 6 TCIE:传送完成中断使能 (Transmission complete interrupt enable)
    此位由软件置 1 和清零。
    0:禁止中断
    1:当 USART_SR 寄存器中 TC=1 时,生成 USART 中断

    位 5 RXNEIE:RXNE 中断使能 (RXNE interrupt enable)
    此位由软件置 1 和清零。
    0:禁止中断
    1:当 USART_SR 寄存器中 ORE=1 或 RXNE=1 时,生成 USART 中断

    位 3 TE:发送器使能 (Transmitter enable)
    该位使能发送器。该位由软件置 1 和清零。
    0:禁止发送器
    1:使能发送器
    注意:1:除了在智能卡模式下以外,传送期间 TE 位上的“0”脉冲(“0”后紧跟的是“1”) 
    会在当前字的后面发送一个报头(空闲线路)。
    2:当 TE 置 1 时,在发送开始前存在 1 位的时间延迟。

    位 2 RE:接收器使能 (Receiver enable)
    该位使能接收器。该位由软件置 1 和清零。
    0:禁止接收器
    1:使能接收器并开始搜索起始位

    控制寄存器 2 (USART_CR2) 略

    控制寄存器 3 (USART_CR3) 略

    2、波特率寄存器——USART_BRR(截取来自中文参考手册说明)

     

    31:16 保留,必须保持复位值

    15:4 DIV_Mantissa[11:0]USARTDIV 的尾数 这 12 个位用于定义 USART 除数 (USARTDIV) 的尾数

    3:0 DIV_Fraction[3:0]USARTDIV 的小数 这 4 个位用于定义 USART 除数 (USARTDIV) 的小数。当 OVER8 = 1 时,不考虑 DIV_Fraction3 位,且必须将该位保持清零。

    3、状态寄存器——USART_SR(截取来自中文参考手册说明)

     

    位 7 TXE:发送数据寄存器为空 (Transmit data register empty)
    当 TDR 寄存器的内容已传输到移位寄存器时,该位由硬件置 1。如果 USART_CR1 寄存器 
    中 TXEIE 位 = 1,则会生成中断。通过对 USART_DR 寄存器执行写入操作将该位清零。
    0:数据未传输到移位寄存器
    1:数据传输到移位寄存器
    注意:单缓冲区发送期间使用该位。
    位 6 TC:发送完成 (Transmission complete)
    如果已完成对包含数据的帧的发送并且 TXE 置 1,则该位由硬件置 1。如果 USART_CR1 寄存 
    器中 TCIE = 1,则会生成中断。该位由软件序列清零(读取 USART_SR 寄存器,然后写入 
    USART_DR 寄存器)。TC 位也可以通过向该位写入‘0’来清零。建议仅在多缓冲区通信 
    时使用此清零序列。
    0:传送未完成
    1:传送已完成
    位 5 RXNE:读取数据寄存器不为空 (Read data register not empty)
    当 RDR 移位寄存器的内容已传输到 USART_DR 寄存器时,该位由硬件置 1。如果 
    USART_CR1 寄存器中 RXNEIE = 1,则会生成中断。通过对 USART_DR 寄存器执行读入 
    操作将该位清零。RXNE 标志也可以通过向该位写入零来清零。建议仅在多缓冲区通信时使 
    用此清零序列。
    0:未接收到数据
    1:已准备好读取接收到的数据

    4、数据寄存器——USART_DR(截取来自中文参考手册说明)

    Data register
    偏移地址:0x04
    复位值:0xXXXX XXXX
    位 31:9 保留,必须保持复位值
    位 8:0 DR[8:0]:数据值
    包含接收到数据字符或已发送的数据字符,具体取决于所执行的操作是“读取”操作还是
    “写入”操作。
    因为数据寄存器包含两个寄存器,一个用于发送 (TDR),一个用于接收 (RDR),因此它具有 
    双重功能(读和写)。
    TDR 寄存器在内部总线和输出移位寄存器之间提供了并行接口(参见图 1)。
    RDR 寄存器在输入移位寄存器和内部总线之间提供了并行接口。
    在使能奇偶校验位的情况下(USART_CR1 寄存器中的 PCE 位被置 1)进行发送时,由于 
    MSB 的写入值(位 7 或位 8,具体取决于数据长度)会被奇偶校验位所取代,因此该值不 
    起任何作用。
    在使能奇偶校验位的情况下进行接收时,从 MSB 位中读取的值为接收到的奇偶校验位。

    三、实现串口数据收发的寄存器版开发

    1、硬件原理图分析 

    ALIENTEK 探索者 STM32F4 开发板板载了一个 USB 串口。USB 转串口,我们选择的是CH340G,是国内芯片公司南京沁恒的产品,稳定性经测试还不错,所以还是多支持下国产。 这样设计的好处就是使用上非常灵活。比如需要用到外部TTL 串口和 STM32通信的时候只需要拔了跳线帽,通过杜邦线连接外部 TTL 串口,就可以实现和外部设备的串口通信了;又比如我有个板子需要和电脑通信,但是电脑没有串口,那么你就可以使用开发板的 RXD 和 TXD来连接你的设备,把我们的开发板当成 USB 转串口用了。

    2、cubMX配置

    这里还是开启串口异步通信,让cubmx帮我们初始化默认参数。

     

     3、实验要求keil开发

    (1)定义一个串口接收的函数,用来接收电脑给开发板发送得数据
    (2)定义一个串口发送的函数,用来把接收到的数据发给开发板,通过串口工具显示
    (3)在主函数中循环这两个功能。
    1. void USART1_PutChar(uint8_t ch)
    2. {
    3. while(!(USART1->SR & (1<<7))); //1代表移位寄存器里数据已经发送完成,新数据可以发送了
    4. USART1->DR = ch; //把需要发送的数据传到数据寄存器
    5. }
    6. uint8_t USART1_GetChar(void)
    7. {
    8. while(!(USART1->SR & (1<<5))); //移位寄存器已准备好读取接收的数据
    9. return USART1->DR; //读取DR数据寄存器
    10. }
    11. int main(void)
    12. {
    13. /* USER CODE BEGIN 1 */
    14. /* USER CODE END 1 */
    15. /* MCU Configuration----------------------------------------------------------*/
    16. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    17. HAL_Init();
    18. /* USER CODE BEGIN Init */
    19. /* USER CODE END Init */
    20. /* Configure the system clock */
    21. SystemClock_Config();
    22. /* USER CODE BEGIN SysInit */
    23. /* USER CODE END SysInit */
    24. /* Initialize all configured peripherals */
    25. MX_GPIO_Init();
    26. MX_USART1_UART_Init();
    27. /* USER CODE BEGIN 2 */
    28. uint8_t ch;
    29. /* USER CODE END 2 */
    30. /* Infinite loop */
    31. /* USER CODE BEGIN WHILE */
    32. while (1)
    33. {
    34. ch = USART1_GetChar(); //等待串口的数据接收
    35. USART1_PutChar(ch); //收到数据发送到串口
    36. /* USER CODE END WHILE */
    37. /* USER CODE BEGIN 3 */
    38. }
    39. /* USER CODE END 3 */
    40. }

    四、实现串口数据收发的库函数版开发

    1、原理图略

    2、Cubmx配置(和之前一样)

    3 、实验开发思路

    (1)实验1:利用串口的收发函数(HAL_UART_Transmit)和(HAL_UART_Receive)代替寄存器写法

    1. int main(void)
    2. {
    3. /* USER CODE BEGIN 1 */
    4. /* USER CODE END 1 */
    5. /* MCU Configuration----------------------------------------------------------*/
    6. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    7. HAL_Init();
    8. /* USER CODE BEGIN Init */
    9. /* USER CODE END Init */
    10. /* Configure the system clock */
    11. SystemClock_Config();
    12. /* USER CODE BEGIN SysInit */
    13. /* USER CODE END SysInit */
    14. /* Initialize all configured peripherals */
    15. MX_GPIO_Init();
    16. MX_USART1_UART_Init();
    17. /* USER CODE BEGIN 2 */
    18. uint8_t buf[10];
    19. //HAL_UART_Transmit(&huart1,(uint8_t *)"UART SEND\r\n",10,1000);
    20. //printf("this is fpuc\r\n");
    21. /* USER CODE END 2 */
    22. /* Infinite loop */
    23. /* USER CODE BEGIN WHILE */
    24. while (1)
    25. {
    26. HAL_UART_Receive(&huart1,buf,5,1000);
    27. HAL_UART_Transmit(&huart1,buf,5,1000);
    28. /* USER CODE END WHILE */
    29. /* USER CODE BEGIN 3 */
    30. }
    31. /* USER CODE END 3 */
    32. }

    五、printf重定向实验

    思路:printf重定向,printf函数调用的是c库中的fputc函数(放在main函数之前)。因此我们如果重新写了fputc函数,就可以改变printf函数的功能,可以向串口打印输出。

    1. int fputc(int ch,FILE *f)
    2. {
    3. while(!(USART1->SR & (1<<7)));
    4. USART1->DR = (uint8_t) ch;
    5. return ch;
    6. }

    六、实验结果和总结

     总结上面讲述得都是应用层的开发,最常用得就是printf重定向了,方便我们打印调试。对于底层的UART协议栈,帧结构这里不详细讲了,先参考链接UART协议栈分析

  • 相关阅读:
    天文信号处理 Lightkurve 安装教程 报错处理
    Baichuan2:Open large-scale language models
    正则表达式匹配html中的图片地址
    不用Swagger,那我用啥?
    Scala 的学习笔记
    Maven
    【Vue入门】语法 —— 事件处理器、自定义组件、组件通信
    十、贪心算法相关题目
    分布式存储系统之Ceph集群部署
    【系统分析师之路】第六章 复盘需求工程(综合知识概念)
  • 原文地址:https://blog.csdn.net/m0_60718520/article/details/127325051