基础篇007. 串行通信(二)--中断方式接收数据

news/2024/11/28 10:47:51/

目录

1. 实验任务

2. 硬件原理

3. 利用STM32CubeMX创建MDK工程

3.1 STM32CubeMX工程创建

3.2 配置调试方式

3.3 配置时钟电路

3.4 配置GPIO

3.5 配置串口参数

3.6 配置时钟

3.7 项目配置

4. 串行通信实验

4.1 UART串口printf,scanf函数串口重定向

4.2 开启中断

4.3 中断回调函数

4.4 main()函数修改

5.调试与验证

6.总结


1. 实验任务

利用STM32CubeMX,创建MDK工程,使用中断方式,实现串口接收数据,然后在转发到串口。

本实验是串行通信的第二部分,基础知识已在上一篇讲述:

基础篇007. 串行通信(一)--阻塞方式发送接收

2. 硬件原理

936338e4d96446048606373683a01f83.png

ef1ed9eb1de845e3930799677333f273.png

1) 指示灯 DS0、 DS1分别连接到PA8和PD2.

2) 3个按键: KEY0、 KEY1 和 KEY_UP,分别连接到PA13、PA15、PA0。

3. 利用STM32CubeMX创建MDK工程

3.1 STM32CubeMX工程创建

选择File下的New Project:

e8d98eaebc0b4e87a8a577bf4c4bf862.png

选择芯片类型(本文为stm32f103RBt6),选择下边的item,然后Start Project:

f21131b6caaa4a0bba1057749bd9621f.png

3.2 配置调试方式

点击左侧的System Core下的SYS,将Debug设置为Serial Wire:

729454ecff83437594cd7414d031818e.png

3.3 配置时钟电路

配置时钟:将RCC下的HSE设置为Crystal/Ceramic Resonator

338a4809a7814ea5a8836226db604b97.png

3.4 配置GPIO

结合开发版的硬件电路,进行GPIO设置

选择GPIO,依次将PA8、PD2设置为GPIO_Output,3个按键对应的IO口设置为输入,KEY0、 KEY1 和 KEY_UP,分别连接到PA13、PA15、PA0。

KEY0(PA13)是低电平有效的,需要将PA13设置为GPIO_Input,在STM32内部设置上拉:

bd50ece1db584f98bb977df4f6f5a7cf.png

各IO口设置后的参见见上图。

3.5 配置串口参数

USART1参数配置:

在 Connectivity 中选择 USART1 设置,并选择 Asynchronous 异步通信。

波特率为 115200 Bits/s。传输数据长度为 8 Bit。奇偶检验 None,停止位 1 ,接收和发送都使能。

d14697a9bed44e64972290bf996f0a3d.png

配置串口中断:

d2ab86f44ac540eb91cda7627ab7f8ae.png

检查NVIC

9383e24076ac4a2da3b20bbef402da3e.png

3.6 配置时钟

结合开发版的硬件电路,选择Clock Configuration,做如下配置:

结合开发版的硬件电路,选择Clock Configuration,做如下配置:

c52c6b97a903445da64f17d7be511234.png

3.7 项目配置

在Project Manager下的Project中设置工程名称和工程路径,并选择编译软件。取消勾选Use lastest available version,选择其他版本:

262df25baaa44fc69af085b653e8a094.png

代码生成设置:

e5905003116c432fa2bc50cfcb6ae9a0.png在Code Generate中选择第二个,然后Generate Code,即生成代码:a141a0cf0b8d403a9951f6bfb01455ad.png

可以打开MDK工程编辑了。

963438b0c0724baba65d3fa2c51e12b4.png

4. 串行通信实验

4.1 UART串口printf,scanf函数串口重定向

这部分内容与上一节相同。

在学习C语言时我们经常使用C语言标准函数库输入输出函数,比如printf、scanf、getchar等。为让开发板也支持这些函数需要把USART发送和接收函数添加到这些函数的内部函数内。

在C语言HAL库中,fputc函数是printf函数内部的一个函数,功能是将字符ch写入到文件指针f所指向文件的当前写指针位置,简单理解就是把字符写入到特定文件中。

fgetc函数与fputc函数非常相似,实现字符读取功能。在使用scanf函数时需要注意字符输入格式。

注意:

使用fput和fgetc函数达到重定向C语言HAL库输入输出函数必须在MDK的工程选项把“UseMicroLIB”勾选上,MicoroLIB是缺省C库的备选库,它对标准C库进行了高度优化使代码更少,占用更少资源。

为使用printf、scanf函数需要在文件中包含stdio.h头文件。

在usart.c文件的user code 0 区域内:

149afbaac7e24cd9a3bf011c62a640f9.png

输入如下内容:

548adcf871174ef78c160f520c96ae88.png

//! 用户添加的代码--->>>#include "stdio.h"// 加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1                                                        // 方便调试,改为“#if 0”不要以下功能
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) // AC6编译器
// 加入以下代码,支持printf函数,而不需要选择use MicroLIB
__asm(".global __use_no_semihosting\n\t");
void _sys_exit(int x)
{ // 定义_sys_exit()以避免使用半主机模式x = x;
}
/* __use_no_semihosting was requested, but _ttywrch was */
void _ttywrch(int ch)
{ch = ch;
}
FILE __stdout;
#elif defined(__CC_ARM) // AC5编译器
// #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#pragma import(__use_no_semihosting)
// 标准库需要的支持函数
struct __FILE
{int handle;
};
FILE __stdout;
void _sys_exit(int x)
{x = x;
}
#endif
//重定义fputc函数
// int fputc(int ch, FILE *f)
//{
//	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
//	USART1->DR = (u8) ch;
//	return ch;
// }// 重定向 c 库函数 printf 到串口 USARTx,重定向后可使用 printf 函数
// 重定向 c 库函数 scanf 到串口 USARTx,重写向后可使用 scanf、 getchar 等函数
// 使用 printf、 scanf 函数需要在文件中包含 stdio.h 头文件。
#if defined(__GNUC__) && !defined(__clang__)
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#define GETCHAR_PROTOTYPE int __io_getchar(FILE *f)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#define GETCHAR_PROTOTYPE int fgetc(FILE *f)
#endif
// 改写fputc函数。【有多个串口是,需要修改下面的代码】
PUTCHAR_PROTOTYPE
{// 发送一个字节数据到串口USARTxHAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000); // 发送数据到串口return ch;
}GETCHAR_PROTOTYPE
{uint8_t ch = 0;// 等待串口输入数据// while (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) == RESET);HAL_UART_Receive(&huart1, &ch, 1, 0xffff);return ch;
}
#endif//! 用户添加的变量定义--->>>
uint8_t Rx1_Byte;      // 定义串口1接收字节寄存器
uint8_t Rx1_Buff[256]; // 定义串口1接收缓冲器,此处默认最大缓存为256字节。
uint16_t Rx1_Count;    // 定义串口1接收计数器

4.2 开启中断

在usart.c文件中的函数void MX_USART1_UART_Init(void)内:

0007208a95ba4e95a54502d1da9d1709.png

  //! 用户添加的代码--->>>HAL_UART_Receive_IT(&huart1, &Rx1_Byte, 1); // 开启接收中断:标志位UART_IT_RXNE,并设置接收缓冲以及接收缓冲接收最大数据量//__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);      //开启接收中断

4.3 中断回调函数

在usart.c文件中末尾的:

817ee95069bf4cb9864cf37962106418.png

输入如下内容:

8b588aee69214805bdaf8afef6866c8f.png

//! 用户添加的代码--->>>
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if (huart->Instance == USART1) // 如果是串口1{Rx1_Buff[Rx1_Count++] = Rx1_Byte; //接收到的数据存入缓存if (Rx1_Byte == 0x0a) // 要求发送数据到串口时,以\n结束【0x0a是"\n"换行符NewLine】{//转发接收到的数据到串口while(HAL_UART_Transmit(&huart1,Rx1_Buff,Rx1_Count-1,1000)!=HAL_OK);Rx1_Count = 0;  //计数器复位}if (Rx1_Count >= 254){Rx1_Count = 0;}while(HAL_UART_Receive_IT(&huart1,&Rx1_Byte,1)!=HAL_OK); // 一次处理完成之后,重新开中断}
}

注意:根据上述串口数据接收程序,发送数据时,需使用“\n”结束,否则会一直等待发送,看不到输出结果。

可以在主程序中使用printf("\n");发送数据,也可以使用串口调试助手。

4.4 main()函数修改

2ecc6ddc643a4e46a640d11842b05e8b.png

#include "stdio.h"

a812d56de7b0445c9c808623c28b1f58.png

  uint16_t times = 0;

a120046534b2471d9fe169c0b53ffad9.png

    if(times%500==0){if (__ARMCC_VERSION > 6000000)printf("您编译工程时选择的是ARMCLANG(AC6)编译器\n");elseprintf("您编译工程时选择的是ARMCC(AC5)编译器\n");printf("\n");printf("实验内容:串口采用中断方式接收数据,然后转发输出。\n");printf("请按下开发板中的Key0按键,或者用串口调试助手发送数据!\n");printf("重要提示:使用野人家园串口助手时,请在发送设置中选择自动发送附加位,校验算法需选择”无“,指令结束符处填写:”0A“\n\n");}if(!HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)){printf("您刚才按下了key0!\n");HAL_Delay(200);}times++;HAL_Delay(10);}

5.调试与验证

程序编译通过后,可将其下载到开发板进行验证

实验需要使用串口调试助手验证。

串口调试助手: 下载地址

打开串口调试助手,实验结果如下:

eb673db44503487c9071bbc16544f9f7.png

重要提醒:串口调试助手必须按如下方法配置,才能接收上述代码发送的数据!!!

发送“\n”字符作为结束符的设置方法:

提示:“\n”的ASCII为“0xa”。

5fe40f0c764440a896fef398d29cf2e3.png

按下发送按钮后,显示如下:

5296a7c4fa7b4ea58539e8d59e277339.png

按下开发板的Key0按键后,显示如下:

d77f352441c14fe39dd89ccc10674c03.png

 5a51e007d8ee433fa2abd0e4a0531785.png

6.总结

暂无

----------------------------------------------------------------------------

 如果你需要AC5编译器,请参考如下博文安装设置:

Keil MDK5.37以上版本自行添加AC5(ARMCC)编译器的方法_armcc下载:

Keil MDK5.37以上版本自行添加AC5(ARMCC)编译器的方法_armcc下载_笑春风oO的博客-CSDN博客​【对安装AC5后,编译时提示找不到序列号的错误,文中有提示的解决方法】从MDK5.37开始,AC5(ARMCC)编译器不再默认安装,需要独立安装。路径、字符等安装问题,都可能引起AC5的编译错误。下面给出不用爬坑的方法。下面是安装步骤:下载AC5(ARMCC)编译器:1. 官方页面(可能下载不成功)2.网盘下载百度网盘:链接:https://pan.baidu.com/s/1ND3vKLzqxanWVP304txRtQ ,提取码:idvc...........................https://blog.csdn.net/qcmyqcmy/article/details/125814461

---------------------------------------------------------------------------

本实验是串行通信的第二部分,基础知识已在上一篇讲述:

基础篇007. 串行通信(一)--阻塞方式发送接收https://blog.csdn.net/qcmyqcmy/article/details/130674914


http://www.ppmy.cn/news/81555.html

相关文章

NetApp EF 系列全闪存阵列——性能极佳,性价比优势突出

NetApp EF 系列全闪存阵列——性能极佳,性价比优势突出 如果您需要为实时分析、HPC 和数据库等性能敏感型工作负载提供强劲动力,NetApp EF 系列全闪存阵列的性价比优势不言自明。其可为要求最苛刻的应用程序提供微秒级响应,最大限度地延长正…

使用Python复制某文件夹下子文件夹名为数据文件夹下的所有以DD开头的文件夹到桌面...

点击上方“Python爬虫与数据挖掘”,进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 楼阁玲珑五云起,其中绰约多仙子。 大家好,我是皮皮。 一、前言 前几天在Python最强王者群【魏哥】问了一个Python自动化办公处理…

[MAUI]在.NET MAUI中复刻苹果Cover Flow

文章目录 原理3D旋转平行变换 创建3D变换控件绘制封面图片应用3D旋转应用平行变换绘制倒影创建绑定属性 创建绑定数据创建布局计算位置计算3D旋转 创建动效项目地址 Cover Flow是iTunes和Finder中的一个视图选项,允许用户使用水平滚动的图像查看他们的音乐库或文件。…

微服务学习——Docker

初识Docker 项目部署的问题 大型项目组件较多,运行环境也较为复杂,部署时会碰到一些问题: 依赖关系复杂,容易出现兼容性问题开发、测试、生产环境有差异 Docker Docker如何解决依赖的兼容问题的? 将应用的Libs(函数库)、 Deps&#xf…

报名仅剩十天!又一开发者公布高分方案源代码,助力软件杯选手高效解题

‍‍ 本文作者:艾宏峰 算法工程师 M6 Global赛道总排名4th KDD Cup 2022风电功率预测飞桨赛道5th “中国软件杯”大学生软件设计大赛——龙源风电赛道,5月31日预选赛截止,80%选手将晋级区域赛,欢迎大家抓紧报名! 赛题背…

课程11:仓储层Repository实现、AutoMapper自动映射

课程简介目录 🚀前言一、Repository项目1.1创建Repository项目1.2 添加类1.2.1、添加类 RolePermissionRepositiory1.2.2、添加项目引用1.2.3、注入数据库上下文1.3 RolePermissionRepositiory接口的实现二、Repository注入2.1 提取接口2.2 添加项目依赖2.3 项目入口添加依赖…

二分查找问题(中间的target,和最左最右target求法)

本文涉及leetcode以下题目: leetcode704. 二分查找 leetcode 34. 在排序数组中查找元素的第一个和最后一个位置 要想做好二分查找的题目,我觉得应该首先知道二分查找的前提条件:二分查找也称为折半查找,它只适用于有序数组。然后就…

Padstack editor 绘制SMD Pin,Thru Pin和Via

一,椭圆形状的SMD PIN 的创建(例如:0.55/0.23 补偿后 0.95/0.28) 1,在select padstack usage 中选择 SMD Pin ;select pad geometry中选择 Oblong; 2,先将左下角 decimal places中的值设置为2&…