串口程序(1)-接收多个字节程序设计

数据寄存器

关键的标志位

通过该宏定义可以开启对应的串口中断,之前用该宏定义代替标准库函数USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);  //使能接收中断

HAL库程序

1.串口发送程序

HAL库串口发送一个/一组数据是很简单的,可以直接调用HAL_UART_Transmit(&g_uart1_handle,(uint8_t*)g_usart_rx_buf, len, 1000);    /* 发送一个/一组数据*/

第一个参数是对应的串口句柄地址,第二个参数是要发送的数据指针,第三个参数是发送的长度,最后一个参数是设置的超时时间。

2.串口接收程序

串口的接收一般不直接使用对应的库函数HAL_UART_Receive(&uartx_handle,Rxdata,3,1000);,而是自定义通过中断的方式接收一定数量的数据。经过测试hal库接收函数也可以接收相应数量的数据(如下图),但不知道为什么用的不普遍。

2.1 串口接收程序1

#define USART_REC_LEN               200         /* 定义最大接收字节数 200 */
#define USART_EN_RX                 1           /* 使能(1)/禁止(0)串口1接收 */
#define RXBUFFERSIZE   1                        /* 缓存大小 */
//可以看到 USART_REC_LEN 表示最大接收字节数,这里定义的是 200 个字节,后续如果
//有需求要发送更大的数据包,可以改大这个值,这里不改太大,是避免浪费太多内存。
#if USART_EN_RX /*如果使能了接收*/     //宏定义已经使能了/* 接收缓冲, 最大USART_REC_LEN个字节. */
uint8_t g_usart_rx_buf[USART_REC_LEN];/*  接收状态*  bit15,      接收完成标志*  bit14,      接收到0x0d*  bit13~0,    接收到的有效字节数目
*/
uint16_t g_usart_rx_sta = 0;uint8_t g_rx_buffer[RXBUFFERSIZE];  /* HAL库使用的串口接收缓冲 */UART_HandleTypeDef g_uart1_handle;  /* UART句柄 *//*** @brief       串口X初始化函数* @param       baudrate: 波特率, 根据自己需要设置波特率值* @note        注意: 必须设置正确的时钟源, 否则串口波特率就会设置异常.*              这里的USART的时钟源在sys_stm32_clock_init()函数中已经设置过了.* @retval      无*/
void usart_init(uint32_t baudrate)
{/*UART 初始化设置*/g_uart1_handle.Instance = USART_UX;                                       /* 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); 
}/*** @brief       UART底层初始化函数* @param       huart: UART句柄类型指针* @note        此函数会被HAL_UART_Init()调用*              完成时钟使能,引脚配置,中断配置* @retval      无*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{GPIO_InitTypeDef gpio_init_struct;if (huart->Instance == USART_UX)                            /* 如果是串口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;    HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct);   /* 串口RX脚 必须设置成输入模式 */#if USART_EN_RX                //宏定义中已经使能HAL_NVIC_EnableIRQ(USART_UX_IRQn);                      /* 使能USART1中断通道 */HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3);              /* 组2,最低优先级:抢占优先级3,子优先级3 */
#endif}
}/*** @brief       串口数据接收回调函数数据处理在这里进行* @param       huart:串口句柄* @retval      无*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if (huart->Instance == USART_UX)                    /* 如果是串口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);}
}/*** @brief       串口1中断服务函数* @param       无* @retval      无*/
void USART_UX_IRQHandler(void)
{
#if SYS_SUPPORT_OS                          /* 使用OS */OSIntEnter();    
#endifHAL_UART_IRQHandler(&g_uart1_handle);   /* 调用HAL库中断处理公用函数 */#if SYS_SUPPORT_OS                          /* 使用OS */OSIntExit();
#endif}#endif

注意点:

1.发送(TX)引脚模式:因为要输出高低电平,所以要设置为复用推挽输出模式。接收(RX)引脚模式:设置为复用浮空输入模式。

2.串口在初始化开启了接收中断,为什么在接收到一字节后再次开启中断(如下图)?

 答:因为此程序调用 HAL 库中断处理公用函数HAL_UART_IRQHandler(&g_uart1_handle),在该函数中调用了UART_Receive_IT(huart)函数,该函数的作用就是清除相关中断标志位并调用回调函数且失能数据寄存器非空中断,所以若用中断接收到一个数据后若不开启中断则接收数据后不能产生中断,故每次接收一个数据后都要再次调用HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE)函数。

在UART_Receive_IT(huart)函数中失能接收中断的具体程序如下:

 3.串口接收多个数据的设计。

因为我们设置了串口句柄成员变量 RxXferSize 为 1,那么每当串口 1 接收到一个字符后触 发接收完成中断,便会在中断服务函数中引导执行该回调函数。当串口接受到一个字符后,它会保存在缓存 g_rx_buffer 中,由于我们设置了缓存大小为 1,而且 RxXferSize=1,所以每次接受一个字符,会直接保存到 RxXferSize[0]中,我们直接通过读取RxXferSize[0]的值就是本次接收到的字符。这里我们设计了一个小小的接收协议:通过这个函数,配合一个数组 g_usart_rx_buf, 一个接收状态寄存器 g_usart_rx_sta(此寄存器其实就是一个全局变量,由作者自行添加。由于 它起到类似寄存器的功能,这里暂且称之为寄存器)实现对串口数据的接收管理。数组 g_usart_rx_buf 的大小由 USART_REC_LEN 定义,也就是一次接收的数据最大不能超过 USART_REC_LEN 个字节。g_usart_rx_sta 是一个接收状态寄存器其各的定义如下表所示:

设计思路如下: 当接收到从电脑发过来的数据,把接收到的数据保存在数组 g_usart_rx_buf 中,同时在接 收状态寄存器(g_usart_rx_sta)中计数接收到的有效数据个数,当收到回车(回车的表示由 2 个 字节组成:0X0D 和 0X0A)的第一个字节 0X0D 时,计数器将不再增加,等待 0X0A 的到来, 而如果 0X0A 没有来到,则认为这次接收失败,重新开始下一次接收。如果顺利接收到 0X0A, 则标记 g_usart_rx_sta 的第 15 位,这样完成一次接收,并等待该位被其他程序清除,从而开始下一次的接收,而如果迟迟没有收到 0X0D,那么在接收数据超过 USART_REC_LEN 的时候, 则会丢弃前面的数据,重新接收。

可以看到,在回调函数后面调用了 UART_Receive_IT 函数。该函数在这里的主要作用是重新开启接收完成中断。 

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

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

相关文章

互联网Java工程师面试题·Spring Cloud篇

目录 1、什么是 Spring Cloud? 2、使用 Spring Cloud 有什么优势? 3、服务注册和发现是什么意思?Spring Cloud 如何实现? 4、负载平衡的意义什么? 5、什么是 Hystrix?它如何实现容错? 6、什么是…

【毕业设计】基于雷达与深度学习的摔倒检测——短时傅里叶变换

在雷达的探测过程中,雷达信号合成器产生一个高频的连续波信号,该信号的瞬时频率随时间线性增加。这种类型的信号也被称为线性调频脉冲信号。雷达回波信号包含人体动作的特征信息,由于雷达信号是非平稳信号,需要采用相应的处理方式,例如短时傅里叶变换,小波变换。 目录 1…

在Linux系统中更换yum源为阿里云

(꒪ꇴ꒪ ),Hello我是祐言QAQ我的博客主页:C/C语言,数据结构,Linux基础,ARM开发板,网络编程等领域UP🌍快上🚘,一起学习,让我们成为一个强大的攻城狮&#xff0…

vue v-for获取子组件$ref总是拿到最后一个元素

页面循环列表,把子组件放在循环里面,此处获取this.$refs返回的应该是个数组,但是不知道为什么,一直返回的是循环的最后一个的子组件实列,官网上已经说明v-for返回的就是数组,所以一直很困惑 代码如下&#…

DevOps搭建(一)-之swappiness安装详细步骤

1、安装swappiness yum install procps 修改配置 vim /etc/sysctl.conf 在配置文件中添加参数 vm.swappiness10 使生效 sysctl -p 如何确认swap分区是否开启 # free -mtotal used free shared buff/cache available Mem: 971 …

Ubuntu-rsyslog和systemd-journald日志服务

rsyslog日志服务 rsyslog作为传统的系统日志服务,把所有收集到的日志都记录到/var/log/目录下的各个日志文件中。 常见的日志文件如下: /var/log/messages 绝大多数的系统日志都记录到该文件 /var/log/secure 所有跟安全和认证授权等日志…

基于Java SSM框架实现弹幕视频网站系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现弹幕视频网站系统演示 摘要 随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,弹幕视频网站当然也不能排除在外。弹幕视频网站是以实际运用为开发背景&…

DBSCAN聚类算法学习笔记

DBSCAN聚类算法学习笔记 一些概念名词 MinPts:聚类在一起的点的最小数目,超过这一阈值才算是一个族群 核心点:邻域内数据点超过MinPts的点 边界点:落在核心点邻域内的点称为边界点 噪声点:既不是核心点也不是边界点的…

CGAL的泊松曲面重构

1、介绍 该CGAL组件实现了一种曲面重建方法,该方法将具有定向法线的点集作为输入,并计算隐式函数。我们假设输入点不包含异常值和少量噪声。通过使用CGAL曲面网格生成器[4]或可能使用任何其他曲面轮廓算法提取该函数的等值面来生成输出曲面网格。 更具体…

如何在业务中体现 TCC 事务模型?

在分布式系统设计中,随着微服务的流行,通常一个业务操作被拆分为多个子任务,比如电商系统的下单和支付操作,就涉及到了创建和更新订单、扣减账户余额、扣减库存、发送物流消息等,那么在复杂业务开发中,如何…

Linux驱动开发学习笔记2《LED驱动开发试验》

目录 一、Linux下LED灯驱动原理 1.地址映射 二、硬件原理图分析 三、实验程序编写 1.LED 灯驱动程序编写 2.编写测试APP 四、运行测试 1.编译驱动程序和测试APP (1)编译驱动程序 (2)编译测试APP 2.运行测试 一、Linux下…

探究Spring Boot 中实现跨域的几种方式

文章目录 前言1. 使用CrossOrigin注解2. 使用WebMvcConfigurer配置3. 使用Filter配置4. 使用全局配置结束语 前言 在现代Web应用中,由于安全性和隐私的考虑,浏览器限制了从一个域向另一个域发起的跨域HTTP请求。解决这个问题的一种常见方式是实现跨域资…

编程实战:类C语法的编译型脚本解释器(九)编译语句

系列入口:编程实战:类C语法的编译型脚本解释器(系列)-CSDN博客 前文已经介绍了编译入口,核心就是语句,本文介绍语句的编译。 目录 一、代码概览 二、辅助函数 2.1 tokens.IsPosNotToken(pos) 2.2 toke…

LT8668SXC DP转VBO/HDMI2.1/EDP 最高可支持到8k60hz

DP1.4a/eDP1.4b Receiver ▪ Compliant with DisplayPort specification 1.4a for 1.62Gbps, 2.7Gbps, 5.4Gbps and 8.1Gbps ▪ Compliant with Embedded DisplayPort specification version 1.4b ▪ Support DisplayPort 1/2/4 lanes ▪ Support HDCP 1.3/2.3 ▪ …

JVM 执行引擎篇

机器码、指令、汇编语言 机器码 各种用二进制编码方式表示的指令,叫做机器指令码。开始,人们就用它采编写程序,这就是机器语言。机器语言虽然能够被计算机理解和接受,但和人们的语言差别太大,不易被人们理解和记忆&a…

德迅抗D盾是如何防护攻击的

德迅抗D盾是针对游戏行业面对的DDoS、CC攻击推出的针对性的网络安全解决方案,相比高防IP,除了能针对大型DDoS攻击(T级别)进行有效防御外,还具备彻底解决游戏行业特有的TCP协议的CC攻击问题能力,防护成本更低…

基于Java SSM框架实现超市管理系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现超市管理系统演示 摘要 21世纪的今天,随着社会的不断发展与进步,人们对于信息科学化的认识,已由低层次向高层次发展,由原来的感性认识向理性认识提高,管理工作的重要性已逐渐被人们所认识&#…

多人聊天作业

服务端 import java.io.*; import java.net.*; import java.util.ArrayList; public class Server{public static ServerSocket server_socket;public static ArrayList<Socket> socketListnew ArrayList<Socket>(); public static void main(String []args){try{…

如何评估数据资产的价值?哪种方法更容易实现?

今年可以称之为数据年&#xff0c;从去年年底党中央发布《数据20条》&#xff0c;对数据领域的一系列的制度建设做了提纲起领的作用。在财经领域今年的下半年&#xff0c;密集出台一系列跟数据资产相关的政策&#xff0c;包括8月21日发布的《企业数据资源会计处理的暂行规定》以…

最小生成树算法与二分图算法

文章目录 概述 P r i m Prim Prim 算法 - 稠密图 - O ( n 2 ) O(n^2) O(n2)思路概述时间复杂度分析AcWing 858. Prim算法求最小生成树CODE K r u s k a l Kruskal Kruskal 算法 - 稀疏图 - O ( m l o g m ) O(mlogm) O(mlogm)思路解析时间复杂度分析AcWing 859. Kruskal算法求…