串口的再认识

常用函数介绍

串口发送/接收函数

HAL_UART_Transmit(); 串口发送数据,使用超时管理机制即在发送成功前一直阻塞

HAL_UART_Receive(); 串口接收数据,使用超时管理机制

HAL_UART_Transmit_IT(); 串口中断模式发送  

HAL_UART_Receive_IT(); 串口中断模式接收

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

UART_HandleTypeDef *huart串口的编号(结构体类型指针变量)

uint8_t *pData指向要发送的数据地址

uint16_t Size要发送的数据大小,以字节为单位

uint32_t Timeout设置的超时时间,以ms为单位

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

UART_HandleTypeDef *huart串口的编号(结构体类型指针变量)

uint8_t *pData是指向接收数据缓冲区

uint16_t Size要接收的数据大小,以字节为单位

此函数执行完后将清除中断,需要再次调用以重新开启中断

串口中断回调函数

HAL_UART_IRQHandler(UART_HandleTypeDef *huart); //串口中断处理函数

HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); //发送中断回调函数

HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); //接收中断回调函数

状态标记变量

USART_RX_STA(可自命名)

从0开始,串口中断接收到一个数据(一个字节)就自增1。当数据读取全部OK时候(回车和换行 符号来的时候),那么 USART_RX_STA的最高位置1,表示串口数据接收全部完毕了,然后main 函数里面可以处理数据了。

串口接收中断流程 

非中断的串口实验

需求:接受串口工具发送的字符串,并将其发送回串口工具。

接线:使用之前用到的CH340接到STM32的1号串口:

1. 打开CubeMX:

1.0 惯例配置,不再展示

1.1 选择左侧的Connectivity--> USART1(共有三路口,随便选一路)

1.2 在右侧设置为 异步通信

1.3 在上图的下侧可以看到参数,暂时不做修改

1.4 惯例配置,生成项目

2. 打开Keil

2.1 实现方式1,直接用刚刚UART的接收和发送的函数

#include "string.h"int main()
{unsigned char buff[20] = {0};while (1){	HAL_UART_Receive(&huart1, buff, 19, 100);//19是因为我定义了20位字节的缓冲区,但实际字符串的发送结束会有\0,所以要预留一位,也就是说最多接收19个字符HAL_UART_Transmit(&huart1, buff, strlen(buff), 100);memset(buff,0,strlen(buff));}
}

2.2 实现方式2,通过重写printf 

2.2.1 首先要打开MicroLIB的库

 

2.2.2 

#include "stdio.h"
#include "string.h"int fputc(int a, FILE *f) //一个字符一个字符发送
{unsigned char temp[1] = {a};HAL_UART_Transmit(&huart1, temp, 1, 0xffff);return a;
}int main(void)
{unsigned char buff[20] = {0};while (1){	HAL_UART_Receive(&huart1, buff, 19, 100);//19是因为我定义了20位字节的缓冲区,但实际字符串的发送结束会有\0,所以要预留一位,也就是说最多接收19个字符printf(buff);memset(buff,0,strlen(buff));}}

3. 打开之前使用到的串口助手

 3.1 设置和Cube中相同的波特率,并打开串口

3.2 发送一个20个字节内的字符串

3.3 观察接收

可见,单片机发回了刚刚接收到的字符串:

 

如果点击“发送新行” ,发送的字符串就会带换行;反之如果不点,回传的数据就会始终在一行

 

使用中断的串口实验

需求:通过中断的方法接受串口工具发送的字符串,并将其发送回串口工具。

接线:同上。

1. CubeMX配置,同上,在之前的基础上打开中断:

2. 打开Keil 

通过stm32f1xx_it.c --> USART1_IRQHandler() --> HAL_UART_IRQHandler() --> UART_Receive_IT() / UART_Transmit_IT()

UART_Receive_IT()UART_Transmit_IT()就是本节开篇提到的“ 串口中断模式 接收发送 ”,这也是本节提到的串口接收中断流程的第三步,下一步就是回调函数:

HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); //发送中断回调函数

HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); //接收中断回调函数

 而其中的“接收中断回调函数”,就是要在main函数中需要重写的函数了:

#include "stdio.h"#define UART1_REC_LEN 200 //定义最大接收字节数 200,可根据需求调整uint8_t buf=0; //串口接收缓存(1字节)
uint8_t UART1_RX_Buffer[UART1_REC_LEN];//接收缓冲, 串口接收到的数据放在这个数组里,最大UART1_REC_LEN个字节uint16_t UART1_RX_STA=0; //bit15,接收完成标志 //bit14,接收到0x0d //bit13~0,接收到的有效字节数目void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) // 接收完成回调函数,每收到一个字符(字节)后,就会在这里处理
{if(huart->Instance == USART1){ // 判断中断是由哪个串口触发的if((UART1_RX_STA & 0x8000) == 0){ // 判断接收是否完成(UART1_RX_STA bit15 位是否为1)if(UART1_RX_STA & 0x4000){ // 如果已经收到了 0x0d (回车)// 则接着判断是否收到 0x0a (换行)if(buf == 0x0a){ // 如果 0x0a 和 0x0d 都收到,UART1_RX_STA |= 0x8000; //则将 bit15 位 置为1}else{ // 否则认为接收错误,重新开始UART1_RX_STA = 0;}}else{ // 如果没有收到 0x0d (回车)//则先判断收到的这个字符是否是 0x0d (回车)if(buf == 0x0d){ // 是的话则将 bit14 位置为1UART1_RX_STA |= 0x4000;}else{ // 否则将接收到的数据保存在缓存数组里UART1_RX_Buffer[UART1_RX_STA & 0X3FFF] = buf; //因为UART1_RX_STA只有前14位为有效数据,所以缓存数组UART1_RX_Buffer[X]中的X作为16位的二进制数,最高两位的判断应该写在前面代码的判断中,在此处不用UART1_RX_STA++;if(UART1_RX_STA > UART1_REC_LEN - 1){ //如果接收数据大于UART1_REC_LEN(200字节),则重新开始接收UART1_RX_STA = 0;}}}}HAL_UART_Receive_IT(&huart1, &buf, 1); // 重新开启中断}
}int fputc(int a, FILE *f) //一个字符一个字符发送
{unsigned char temp[1] = {a};HAL_UART_Transmit(&huart1, temp, 1, 0xffff);return a;
}int main(void)
{HAL_UART_Receive_IT(&huart1, &buf, 1);//开启中断,并把数据存到buf里while (1){if(UART1_RX_STA & 0x8000){//不断的判断串口是否接收完成printf("收到数据:"); HAL_UART_Transmit(&huart1, UART1_RX_Buffer, UART1_RX_STA & 0x3fff, 0xffff);// 将收到的数据发送到串口(此处也可以使用printf)while(huart1.gState != HAL_UART_STATE_READY);// 等待发送完成printf("\r\n");UART1_RX_STA = 0;// 重新开始下一次接收}printf("hello mjm\r\n");HAL_Delay(1000);}}

3. 打开之前使用到的串口助手

按照刚刚的设置,调整波特率,打开串口,可以看到每秒从单片机发来的心跳包:

并且如果此时发送字符串给单片机,也会立刻收到单片机回传的这个字符串:

 

注意,此时必须勾选上“发送新行”,原因是在单片机的函数中,判断字符串是否传输完毕的方法就是检测最后的换行!

 

 

 

 

 

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

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

相关文章

C++ 变量类型

C 变量类型 变量其实只不过是程序可操作的存储区的名称。 在 C 中,有多种变量类型可用于存储不同种类的数据。 C 中每个变量都有指定的类型,类型决定了变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用于变量…

Pytorch实现warm up和consine decay

在深度学习领域,模型训练过程中的不稳定性是一个常见的问题。为了解决这个问题,在Resnet这篇论文也提及了Warm Up的方法,通过逐渐增加学习率,引导模型在训练初期更稳定地收敛。同时在warm up之后结合consine decay的方法让训练变得…

辅助驾驶功能开发-功能规范篇(22)-3-L2级辅助驾驶方案功能规范

1.3.3 TLA系统功能定义 1.3.3.1 状态机 1.3.3.2 状态迁移图 1.3.3.3 功能定义 1.3.3.3.1 信号需求列表 1.3.3.3.2 系统开启关闭 1)初始化 车辆上电后,交通灯辅助系统(TLA)进行初始化,控制器需在 220ms 内发出第一帧…

Spring-Interceptor拦截器

使用步骤 申明拦截器bean,并实现HandlerInterceptor接口 true为放行,false为拦截 2.定义配置类,继承WebMvcConfigurationSupport,实现addInterceptors方法,该方法调用具体的拦截器进行拦截 也可以在配子类通过实现W…

JMeter进行WebSocket压力测试

背景 之前两篇内容介绍了一下 WebSocket 和 SocketIO 的基础内容。之后用 Netty-SocketIO 开发了一个简单的服务端,支持服务端主动向客户端发送消息,同时也支持客户端请求,服务端响应方式。本文主要想了解一下服务端的性能怎么样,…

一百二十九、Kettle——从MySQL增量导入到GreenPlum

一、目标 用Kettle从MySQL增量导入数据到GreePlum 二、前提准备 (一)kettle已连上MySQL (二)kettle已连上GreenPlum 三、实施步骤 (一)打开kettle,新建转换任务。拖拽2个表输入、替换NULL…

Spring 如何解决 Bean 的循环依赖(循环引用)

Component public class A {Autowiredprivate B b;}Component public class B {Autowiredprivate A a;}上面的情况就是 循环依赖 Bean的创建初始化过程如下 如果不采取措施,那么循环依赖就会进入死循环 但 Spring 已经帮我们解决了大部分循环依赖问题 具体是如何解…

prompt:有需求就有价值,prompt案例

prompt:有需求就有价值 此文章来自于小七姐 首先来看需求: 客户需要生成1000条俏皮灵动,趣味盎然,比喻精妙的和美食有关的短句子,要求文风优美,句子让人充满食欲。 客户使用这些句子的场景比较奇妙&…

路径规划算法:基于食肉植物优化的路径规划算法- 附代码

路径规划算法:基于食肉植物优化的路径规划算法- 附代码 文章目录 路径规划算法:基于食肉植物优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要:本文主要介绍利用智能优化…

2023年Q2空调行业品牌数据榜单(京东商品数据)

随着夏季的来临,高温天气也带动部分家电行业的销售,以空调为代表的家电市场正逐步恢复活力。结合鲸参谋电商数据分析平台的相关数据,我们来分析一下2023年Q2空调市场的具体销售表现。 根据鲸参谋平台的数据显示,2023年4-6月份&am…

数据库备份恢复和索引视图

样例表如下: /***************************样例表***************************/CREATE DATABASE booksDB;use booksDB;CREATE TABLE books(bk_id INT NOT NULL PRIMARY KEY,bk_title VARCHAR(50) NOT NULL,copyright YEAR NOT NULL);INSERT INTO booksVALUES (1107…

ICEFlow VPN敏感信息泄露

一个新的历史时期开始了,而眼下又是一个艰难的转折阶段:既要除旧,又要布新;这需要魄力,需要耐力,需要能力,需要精力,当然也需要体力——尽管这一切他都不够,但他自信他的…