串口的再认识

news2024/11/24 22:57:50

常用函数介绍

串口发送/接收函数

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 位置为1
					UART1_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.coloradmin.cn/o/747036.html

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

相关文章

DAY45:动态规划(六)背包问题优化:一维DP解决01背包问题

文章目录 一维DP数组的解法二维DP递推思路滚动数组优化思路(重要)一维DP数组的含义一维DP递推公式一维DP的初始化遍历顺序(重要)举例推导DP数组 一维DP数组完整版写法面试问题为什么一维DP背包的for循环一定要倒序遍历为什么一维D…

Qt + QR-Code-generator 生成二维码

0.前言 之前使用 libgrencode 生成二维码,LGPL 协议实在不方便,所以需要找一个 github 星星多的,代码简单最好 header-only,协议最好是 MIT 或者兼容协议而不是 GPL 或者 LPGL。 QR-Code-generator 正好符合这个要求&#xff0c…

JMeter 如何模拟不同的网络速度

目录 前言: 限制输出带宽以模拟不同的网络速度 将这两行添加到user.properties文件中(可以在JMeter安装的bin文件夹中找到此行) 通过-J 命令行参数传递属性的值,如下所示: 前言: JMeter可以通过使用不同…

【网络安全带你练爬虫-100练】第12练:pyquery解析库提取指定数据

目录 一、目标1、基础/环境的准备工作 二、目标2:开始使用pyquery 三、目标3:提取到指定的数据 四、目标3:通过列表的形式获取指定数据 五、扩展:其他方法 六、网络安全O 一、目标1、基础/环境的准备工作 1、文档&#xff1…

wordpress的wp_trim_words摘要没有截取到指定的字符长度的问题解决

一、问题描述 在imqd.cn文章列表中&#xff0c;用于将正文内容截取保留前75个字的方法突然没效果了。 <p class"post-desc text-black-50 d-none d-md-block"><?phpecho wp_trim_words( get_the_content(), 75, ...);?> </p>直接展示了所有的正…

计算机网络实验(1)--Windows网络测试工具

&#x1f4cd;实验目的 理解知识点&#xff08;ping&#xff0c;netstat&#xff0c;ipconfig&#xff0c;arp&#xff0c;tracert&#xff0c;route&#xff0c;nbtstat&#xff0c;net&#xff09;所涉及的基本概念&#xff0c;并学会使用这些工具测试网络的状态及从网上获取…

java后端开发环境搭建 mac

在mac pro上搭建一套java 后端开发环境&#xff0c;主要安装的内容有&#xff1a;jdk、maven、git、tomcat、mysql、navicat、IntelliJ、redis。 本人mac pro的系统为mac OS Monterey 12.6.7&#xff0c;主机的硬件架构为x86_64。 左上角关于本机查看系统版本&#xff1b;终端…

LLM - Baichuan7B Lora 训练详解

目录 一.引言 二.环境准备 三.模型训练 1.依赖引入与 tokenizer 加载 2.加载 DataSet 与 Model 3.Model 参数配置 4.获取 peft Model 5.构造 Trainer 训练 6.训练完整代码 四.Shell 执行 1.脚本构建 2.训练流程 3.训练结果 五.总结 一.引言 LLM - Baichuan7B Tok…

Ubuntu18.04 docker kafka 本地测试环境搭建

文章目录 一、kafka 介绍二、Ubuntu docker kafka 本地测试环境搭建2.1 docker kafka 启动2.1.1 下载镜像2.1.2 启动 wurstmeister/zookeeper2.1.3 启动 wurstmeister/kafka 2.2 docker kafka 测试数据收发2.2.1 docker kafka 测试数据收发2.2.2 windows验证 三、嵌入式集成四、…

加密劫持者攻击教育机构

我们的专家分析了2023年第一季度的当前网络威胁。研究表明&#xff0c;独特事件的数量增加&#xff0c;勒索软件活动激增&#xff0c;特别是针对学术和教育机构。我们记录了大量与就业有关的网络钓鱼邮件&#xff0c;出现了QR网络钓鱼和恶意广告的增加。 我们的研究表明&#…

「2023 最新版」Java 工程师面试题总结 (1000 道题含答案解析)

作为一名优秀的程序员&#xff0c;技术面试都是不可避免的一个环节&#xff0c;一般技术面试官都会通过自己的方式去考察程序员的技术功底与基础理论知识。 如果你参加过一些大厂面试&#xff0c;肯定会遇到一些这样的问题&#xff1a; 1、看你项目都用的框架&#xff0c;熟悉…

AIGC:文生图stable-diffusion-webui部署及使用

1 stable-diffusion-webui介绍 Stable Diffusion Web UI 是一个基于 Stable Diffusion 的基础应用&#xff0c;利用 gradio 模块搭建出交互程序&#xff0c;可以在低代码 GUI 中立即访问 Stable Diffusion Stable Diffusion 是一个画像生成 AI&#xff0c;能够模拟和重建几乎…

Linux(centos7)下安装mariadb10详解

MariaDB 和 MySQL 之间存在紧密的关系。 起源&#xff1a;MariaDB 最初是作为 MySQL 的一个分支而创建的。它的初始目标是保持与 MySQL 的兼容性&#xff0c;并提供额外的功能和性能改进。 共同的代码基础&#xff1a;MariaDB 使用了 MySQL 的代码基础&#xff0c;并在此基础上…

PYTHON 解码 IP 层

PYTHON 解码 IP 层 引言1.编写流量嗅探器1.1 Windows 和 Linux 上的包嗅探2.解码 IP 层2.1 struct 库3.编写 IP 解码器4.解码 ICMP5.总结 作者&#xff1a;高玉涵 时间&#xff1a;2023.7.12 环境&#xff1a;Windows 10 专业版 22H2&#xff0c;Python 3.10.4 引言 IP 是 …

JWT的深入理解

1、JWT是什么 JWT&#xff08;JSON Web Token&#xff09;是一种开放标准&#xff08;RFC 7519&#xff09;&#xff0c;用于在不同实体之间安全地传输信息。它由三部分组成&#xff0c;即头部&#xff08;Header&#xff09;、载荷&#xff08;Payload&#xff09;和签名&…

获取QT界面坐标的各种方法

链接 ract() 获取rect所在部件的尺寸。 rect()返回的QRect对象可以用来做什么

openResty的Redis模块踩坑记录

OpenResty提供了操作Redis的模块&#xff0c;我们只要引入该模块就能直接使用。说是这样说&#xff0c;但是实践起来好像并不太顺利。 1.设置了密码的redis&#xff0c;lua业务逻辑中需要添加身份认证代码 网上很多资料、文章似乎都是没有设置redis密码&#xff0c;说来也奇怪…

JS区域滤镜

思路 简单一点的&#xff0c;像素点X坐标小于图宽1/3和大于2/3的点变灰&#xff0c;中间的点不变。 复杂的暂时不会搞。 原图 处理后 <html> <style> #canvas { width:100%; } </style> <body> <input id"file" type"file" …

python中的生成器(generator)

一、生成器 生成器是 Python 中非常有用的一种数据类型&#xff0c;它可以让你在 Python 中更加高效地处理大量数据。生成器可以让你一次生成一个值&#xff0c;而不是一次生成一个序列&#xff0c;这样可以节省内存并提高性能 二、实现generator的两种方式 python中的gener…

SAP从放弃到入门系列之WIP Batch(Work-in-Process ) -Part1

目录 一、 概述二、 系统配置三、 数据设置最后 ERP系统的复杂性并不单是架构设计和技术造成的&#xff0c;而是它所要支撑的业务场景&#xff0c;涉及行业越广泛越复杂软件功能越复杂&#xff0c;复杂的背后是业务实践沉淀和优化的流程。平时看着部分系统功能很复杂&#xff0…