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_RXHAL_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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

六西格玛培训证书攻略2024:一站式解决方案助你快速上手

目前,企业对于员工的专业能力和综合素质要求越来越高。六西格玛作为一种先进的质量管理方法,已经成为众多企业提升运营效率、降低成本的重要手段。张驰咨询针对2024年六西格玛培训证书考取,为广大学员制定了实用的攻略,帮助学员们…

网络故障快速定位的秘诀 - 基于 AnaTraf 全流量回溯分析

网络故障是每个 IT 从业者都深有体会的头疼问题。当网络出现异常时,如何快速定位故障原因,恢复网络正常运行,是考验运维能力的关键所在。借助 AnaTraf 网络流量分析仪的全流量回溯分析功能,您可以轻松应对各种复杂的网络问题,实现快速故障定位。 1. 网络故障分析的痛点 网络故…

C++自定义脚本文件执行

FunctionCall.h&#xff1a; #include <sstream> #include <string> #include <vector> // 函数调用 class FunctionCall { public: FunctionCall(); ~FunctionCall(); std::string call(const st…

失误删除也能救回,推荐前10款手机数据恢复软件!

在手机的日常使用中&#xff0c;不可避免的会误删数据&#xff0c;这些数据可能包括照片、视频、联系人、短信等重要信息。不过好在市面上有很多优秀的手机数据恢复软件&#xff0c;可以帮助我们从各种情况下恢复丢失的数据。 本文将为您推荐十大手机数据恢复软件&#xff0c;…

Xxl-job实现定时任务视频转码

搭建XXL-JOB 调度中心 首先下载xxl-job GitHub&#xff1a;GitHub - xuxueli/xxl-job: A distributed task scheduling framework.&#xff08;分布式任务调度平台XXL-JOB&#xff09; 码云&#xff1a;xxl-job: 一个分布式任务调度平台&#xff0c;其核心设计目标是开发迅速…

三大国密浏览器简单介绍-行云管家

国密浏览器是指支持国密算法SM2/SM3&#xff0c;支持基于国密算法的SSL协议&#xff0c;支持采用国密SSL证书实现HTTPS加密的网站正常访问的浏览器。今天我们行云管家小编就给大家简单介绍一下三大国密浏览器&#xff0c;以便大家了解。 三大国密浏览器简单介绍-行云管家 1、密…

快速上手六步教你如何进行跨境电商ERP开发

跨境电商平台开发是当前电商行业的热门话题&#xff0c;一套高效的ERP系统对跨境电商平台的发展至关重要。在本文中&#xff0c;我将为你介绍六个简单而关键的步骤&#xff0c;帮助你快速上手进行跨境电商ERP开发。 步骤一&#xff1a;需求分析 在跨境电商平台开发之初&#…

C++笔试强训day22

目录 1.添加字符 2.数组变换 3.装箱问题 常规一维优化&#xff1a; 1.添加字符 链接 因为lenA < lenB < 50&#xff0c;因此可以无脑暴力解题&#xff1a; 遍历所有符合条件的匹配方法&#xff0c;找出最小的不同的数量&#xff0c;即最大的相同的数量 #include &…

需要无广告、结构化信息的搜索引擎?秘塔AI搜索,你的新选择

工欲善其事&#xff0c;必先利其器。 随着AI技术与各个行业或细分场景的深度融合&#xff0c;日常工作可使用的AI工具呈现出井喷式发展的趋势&#xff0c;AI工具的类别也从最初的AI文本生成、AI绘画工具&#xff0c;逐渐扩展到AI思维导图工具、AI流程图工具、AI生成PPT工具、AI…

蓝桥杯备战22.k倍区间——前缀和

目录 题目 分析 暴力求解 优化思路 AC代码 题目链接&#xff1a; P8649 [蓝桥杯 2017 省 B] k 倍区间 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目 分析 很明显这题是一道前缀和的题 暴力求解 只得了28分 #include<iostream> using namespace std; co…

地平线旭日X3开发板编译USB网卡驱动 AX88772B

由于使用的激光雷达是网口输出的&#xff0c; 为了不占用X3派已有的网口&#xff0c;接上去了一个绿联的usb网卡&#xff0c; 发现系统没有驱动&#xff0c;所以动手看看能不能自己编译一个 首先lsusb查看一下网卡型号 发现型号是AX88772B&#xff0c;去官网看了一下&#x…

JVM运行时内存:程序计数器

文章目录 1. 程序计数器的作用2. 程序计数器的基本特征3. 程序计数器的问题 运行时内存整体结构如下图所示: 1. 程序计数器的作用 为了保证程序(在操作系统中理解为进程)能够连续地执行下去&#xff0c;CPU必须具有某些手段来确定下一条指令的地址。而程序计数器正是起到这种作…