【嵌入式系统】STM32串口通信的四种方法(基于RTOS)

目录

  • 1、串行通信的基本参数
  • 2、轮询方式代码效果
  • 3、中断方式代码效果
  • 4、中断加上时间戳方式代码及效果
  • 5、DMA空闲中断方式接收数据

1、串行通信的基本参数

串行端口的通信方式是将字节拆分成一个接一个的位再传输出去,接收方再将此一个一个的位组合成原来的字符,如此形成一个字节的完整传输,在数据传输时,应在通信端口的初始化时设置几个通信参数。

1)波特率,即传送数据的速度。波特率的意思就是在一秒中可以传输的数据位数,单位是bps。如果采用波特率4800bps进行传输,那么每秒可以传输600个byte。
2)数据位,当接收设备收到起始位后,紧接着就会收到数据位,数据位的个数可以是5、6、7或者8位。在字符数据传输的过程中,数据位从最低有效位开始传输。
3)起始位,在串口线上,没有数据传输时处于逻辑"1"状态,当发送设备要发送一个字符数据时,首先发出一个逻辑“0"信号,这个逻辑低电平就是起始位。
4)停止位,是一个字符数据的结束标志,它可以是1位、1.5位或者2位。
5)奇偶校验位,数据位发送完之后,就可以发送奇偶校验位。奇偶校验用于有限差错校验,通信双方在通信时约定一致的奇偶校验方式。

在这里插入图片描述

2、轮询方式代码效果

在这里插入图片描述

char ch;
/* Infinite loop */
for(;;)
{
if(HAL_UART_Receive(&huart1,(uint8_t*)&ch,1,100) == HAL_OK)printf("%c",ch);//osDelay(1);
}

在这里插入图片描述
轮询方式不适合接收一大段的数据,否则会卡死,如上图。

3、中断方式代码效果

在这里插入图片描述

#define MAX_RECV_LEN 128							//定义的一次最多接收字节的位数
uint8_t rx1_buff[MAX_RECV_LEN] = {0};	//串口接收数据缓冲
uint8_t *pBuf;												//当前接收字节存放的位置指针
uint8_t line_flag = 0;								//一行数据接收结束标志

在这里插入图片描述

void StartTaskUsart(void *argument)
{/* USER CODE BEGIN StartTaskUsart */printf("HELLO WORLD\n");pBuf = rx1_buff;HAL_UART_Receive_IT(&huart1,pBuf, 1); /* Infinite loop */for(;;){if(line_flag){printf("%s",rx1_buff);line_flag=0;}osDelay(1);}/* USER CODE END StartTaskUsart */
}

在这里插入图片描述

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) 
{ if (UartHandle->Instance == USART1) { ++ pBuf; // 已接收一个字节数据,当前存储位置指针后移 if(pBuf == rx1_buff + MAX_RECV_LEN) // 如果指针已移出数组边界 pBuf = rx1_buff; 									// 重新指向数组开头 else if(*(pBuf - 1) == '\n') // 如果之前接收到‘\n’换行符,则表示接收完成 {line_flag = 1;		// 行接收标志置1*pBuf = '\0';			// 添加字符串末尾结束符pBuf = rx1_buff;	// 重新指向数组开头}__HAL_UNLOCK(UartHandle); 								// 解锁串口HAL_UART_Receive_IT(UartHandle, pBuf, 1); // 重新开启接收中断} 
}

缺点:由于中断接收是以换行符为标准的,这里我们按下两次发送键才将4个数字全部发送。
在这里插入图片描述

4、中断加上时间戳方式代码及效果

利用时间戳来辅助判断接收空闲,实现了分段发送。

 for(;;){if(recv_tick>0 && (osKernelGetTickCount()-recv_tick)>=20){*pBuf = '\0';	//添加字符串末尾结束符printf("%s",rx1_buff);recv_tick=0;pBuf = rx1_buff;//重新指向数组开头}}
//加了时间戳的完善代码
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) 
{ if (UartHandle->Instance == USART1) { ++ pBuf; // 已接收一个字节数据,当前存储位置指针后移 if(pBuf == rx1_buff + MAX_RECV_LEN) // 如果指针已移出数组边界 pBuf = rx1_buff; 									// 重新指向数组开头 recv_tick = osKernelGetTickCount();__HAL_UNLOCK(UartHandle); 								// 解锁串口HAL_UART_Receive_IT(UartHandle, pBuf, 1); // 重新开启接收中断} 
}

在这里插入图片描述

5、DMA空闲中断方式接收数据

步骤总结:

1、开启串口DMA接收
2、串口收到数据,DMA不断传输数据到接收缓冲
3、一帧数据发送完毕,串口暂时空闲,触发串口空闲中断
4、在串口中断函数中,计算刚才收到的数据长度
5、复制接收缓冲数据,清除标志位,开始下一帧接收

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

//添加串口数据缓冲、DMA数据缓冲、接收标志
uint8_t data_buff[MAX_BUFF_LEN] = {0};	//串口接收数据缓冲
uint8_t dma_buff[MAX_BUFF_LEN] = {0};		//DMA数据缓冲
uint32_t recv_len = 0;			//接收数据长度

在这里插入图片描述

#define MAX_BUFF_LEN 512
extern uint8_t data_buff[MAX_BUFF_LEN];
extern uint8_t dma_buff[MAX_BUFF_LEN];
extern uint32_t recv_len;
extern void UART_IDLE_Callback(UART_HandleTypeDef *huart);

在这里插入图片描述

void UART_IDLE_Callback(UART_HandleTypeDef *huart)
{if (__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET &&huart->Instance == USART1){__HAL_UART_CLEAR_IDLEFLAG(huart);HAL_UART_DMAStop(huart);recv_len = MAX_BUFF_LEN - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);if (recv_len < MAX_BUFF_LEN - 1){memcpy(data_buff, dma_buff, recv_len);data_buff[recv_len] = '\0';}else{recv_len = 0;}__HAL_UNLOCK(huart);HAL_UART_Receive_DMA(huart, dma_buff, MAX_BUFF_LEN);}
}

在这里插入图片描述

void USART1_IRQHandler(void)
{/* USER CODE BEGIN USART1_IRQn 0 *//* USER CODE END USART1_IRQn 0 */HAL_UART_IRQHandler(&huart1);/* USER CODE BEGIN USART1_IRQn 1 */UART_IDLE_Callback(&huart1);/* USER CODE END USART1_IRQn 1 */
}

在这里插入图片描述

void StartTaskUsart(void *argument)
{/* USER CODE BEGIN StartTaskUsart */__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);		//使能idle中断HAL_UART_Receive_DMA(&huart1,dma_buff,MAX_BUFF_LEN);//打开DMA接收,数据存入dma_buff数组中/* Infinite loop */for(;;){if(recv_len>0){printf("%s",(char *)data_buff);recv_len=0;}}osDelay(1);/* USER CODE END StartTaskUsart */
}

这种方法效果极其有效:
使用串口调试助手软件,定时每隔20ms发送总共100个字节的多行字符串对STM32串口接收功能进行测试。
如图所示,发送数据个数超过50000字节后停止发送,接收到的STM32回送数据个数与发送数据个数相同。
在这里插入图片描述

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

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

相关文章

十五、聚类的评估

一、Given Label 均一性homogeneity&#xff1a;一个簇中只包含一个类别样本&#xff0c;Precision 完整性completeness&#xff1a;同类别样本被归到同一个簇中&#xff0c;Recall 将均一性h和完整性c进行结合(二者加权平均)得到V-Measure&#xff0c;&#xff0c;β为权重 …

SQL SERVER作业的Schedules浅析

SQL SERVER作业的计划&#xff08;Schedules&#xff09;&#xff0c;如果你没仔细研究过或没有应用一些复杂的计划&#xff08;Schedules&#xff09;&#xff0c;那么你觉得SQL SERVER作业的计划(Schedules)非常好用&#xff0c;也没啥问题&#xff0c;但是我要告诉你一个“残…

leetcode 51. N 皇后 思考分析

目录题目思考AC代码题目 n 皇后问题研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 思考 首先以N4为例&#xff0c;画出解空间树的一部分&#xff1a; 根据模板&#xff1a; void backtracking(参数) {if(终止条件){存放结果…

No module named ‘tensorflow.examples‘解决方案

想从tensorflow中导入mnist手写数字数据集&#xff0c;结果报错 from tensorflow.examples.tutorials.mnist import input_data import tensorflow.compat.v1 as tf tf.disable_v2_behavior()my_mnist input_data.read_data_sets("MNIST_data_bak/", one_hotTrue)&…

.NET通用基本权限系统

DEMO下载地址&#xff1a; http://download.csdn.net/detail/shecixiong/5372895 一、开发技术&#xff1a;B/S(.NET C# ) 1、Windows XP以上 (支援最新Win 8) 2、Microsoft Visual Studio 2010/2012 C#.NET 3、.NET Framework 4.0以上 (支援最新4.5版本) 4、SQL Server 2005以…

leetcode 37. 解数独 思考分析

目录题目核心思路的不断细化1、核心框架2、考虑到每个位置的工作3、考虑到到达最后一列、该位置的数已经预置的情况4、判断是否符合规则的函数5、确定递归终止条件确定函数返回值AC代码题目 编写一个程序&#xff0c;通过填充空格来解决数独问题。 一个数独的解法需遵循如下规…

快速完成兼职外包开发任务

做了很多年的开发相关的工作&#xff0c;做过兼职开发&#xff0c;也做过外包一些开发项目。 兼职人员角色时 正是经历这些事情时&#xff0c;每次就要提前很费经的跟公司沟通&#xff0c;让他们把公司内部的svn开发出去&#xff0c;但是就是很难&#xff0c;会涉及到安全各方的…

使用YOLOv5训练NEU-DET数据集

一、下载YOLOv5源码和NEU-DET(钢材表面缺陷)数据集 YOLOv5源码 NEU-DET(钢材表面缺陷)数据集 这里的数据集已经经过处理了&#xff0c;下载即可 若通过其他途径下载的原始数据集标签为xml格式&#xff0c;需要转化为txt格式XML转txt格式脚本 二、数据集准备 NEU-DET(钢材表…

带分页功能的SSH整合,DAO层经典封装

任何一个封装讲究的是&#xff0c;使用&#xff0c;多状态。Action&#xff1a;任何一个Action继承分页有关参数类PageManage&#xff0c;自然考虑的到分页效果&#xff0c;我们必须定义下几个分页的参数。并根据这个参数进行查值。然后在继承ServiceManage&#xff0c;Service…

leetcode 198. 打家劫舍 思考分析

目录1、题目2、求解思路3、代码1、题目 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动…

找不到Windows照片查看器解决方法

桌面创建一个txt文本 复制这些命令&#xff0c;之后将后缀改为.reg&#xff0c;右击管理员身份运行即可 Windows Registry Editor Version 5.00 ; Change Extensions File Type [HKEY_CURRENT_USER\Software\Classes\.jpg] "PhotoViewer.FileAssoc.Tiff" ; Change E…

伙伴分配器的一个极简实现

提起buddy system相信很多人不会陌生&#xff0c;它是一种经典的内存分配算法&#xff0c;大名鼎鼎的Linux底层的内存管理用的就是它。这里不探讨内核这么复杂实现&#xff0c;而仅仅是将该算法抽象提取出来&#xff0c;同时给出一份及其简洁的源码实现&#xff0c;以便定制扩展…

[USACO3.2.3 Spinning Wheels]

[关键字]&#xff1a;模拟 枚举 [题目大意]&#xff1a;有5个轮子&#xff0c;每个轮子优r个缺口并且会按一定速度不停转动&#xff0c;问什么时候可以使一条光线射过所有轮子。 // [分析]&#xff1a;从0到1000&#xff08;或其他的&#xff09;枚举分钟然后判断&#xff0c;当…

一、SQLServer2008安装(带密码)、创建数据库、C#窗体项目测试

一、下载和安装SQLServer2008 东西太大了&#xff0c;没法上传到资源里面&#xff0c;官网其他公众号都下载可以。 右击管理员身份 运行setup.exe 这个密钥不能用的话&#xff0c;也可以去百度其他密钥 JD8Y6-HQG69-P9H84-XDTPG-34MBB 建议改一下路径&#xff0c;我这边修…

【C++grammar】多态、联编、虚函数

目录1、多态概念1.多态性有两种表现的方式2、联编&#xff08;实现多态&#xff09;1.静态联编2.动态联编3、实现运行时多态1.为何要使用运行时多态&#xff1f;2.如何实现运行时多态3.多态的例子1.调用哪个同名虚函数&#xff1f;2. 用途&#xff1a;可以用父类指针访问子类对…

一 MVC - HtmlHelper

HtmlHelper类位于System.Web.Mvc.Html之中主要有七个静态类组成&#xff1a; FormExtensions - BeginForm, BeginRouteForm, EndForm InputExtensions - CheckBox, CheckBoxFor, Hidden, HiddenFor, Password, PasswordFor, RadioButton, RadioButtonFor, TextBox, TextBoxFor …

二、用户登录和注册

一、页面设计 一共四个页面 主页面Form1&#xff0c;登录页面login&#xff0c;注册页面resister&#xff0c;主菜单页面main_page 系统运行进入Form1&#xff0c;单击登录按钮跳转到login&#xff0c;数据库中得存在数据信息且输入正确才可登录成功&#xff0c;跳转到main_pa…

【C++grammar】访问控制与抽象类与纯虚函数

目录一、访问控制 (可见性控制)1.private、public、protected关键字2.关键字示例1、关键字对类数据成员访问的限制3. 公有继承4. 私有继承5. 保护继承6. 私有继承和保护继承的区别二、抽象类与纯虚函数1.什么是抽象类2.抽象函数/纯虚函数3.抽象类示例一、访问控制 (可见性控制)…

三、上传织物图片至SQL Server并提供name进行展示织物照片

一、数据库的建立 还是在fiber_yy数据库下创建images表 images表设计如下 二、页面完善设计 main_page页面进行功能完善 入库管理系统 warehousing页面 库存查询系统 query页面 登录注册页面前面几个博文已经实现过了&#xff0c;这里就再赘述了&#xff0c;仍是沿用前…

ARM MMU工作原理剖析[转]

一、MMU的产生 许多年以前&#xff0c;当人们还在使用DOS或是更古老的操作系统的时候&#xff0c;计算机的内存还非常小&#xff0c;一般都是以K为单位进行计算&#xff0c;相应的&#xff0c;当时的程序规模也不大&#xff0c;所以内存容量虽然小&#xff0c;但还是可以容纳当…