🚀write in front🚀
🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝💬本系列哔哩哔哩江科大STM32的视频为主以及自己的总结梳理📚
🚀Projeet source code🚀
💾工程代码放在了本人的Gitee仓库:iPickCan (iPickCan) - Gitee.com
引用:
STM32入门教程-2023版 细致讲解 中文字幕_哔哩哔哩_bilibili
Keil5 MDK版 下载与安装教程(STM32单片机编程软件)_mdk528-CSDN博客
STM32之Keil5 MDK的安装与下载_keil5下载程序到单片机stm32-CSDN博客
0. 江协科技/江科大-STM32入门教程-各章节详细笔记-查阅传送门-STM32标准库开发_江协科技stm32笔记-CSDN博客
【STM32】江科大STM32学习笔记汇总(已完结)_stm32江科大笔记-CSDN博客
江科大STM32学习笔记(上)_stm32博客-CSDN博客
STM32学习笔记一(基于标准库学习)_电平输出推免-CSDN博客
STM32 MCU学习资源-CSDN博客
stm32学习笔记-作者: Vera工程师养成记
stem32江科大自学笔记-CSDN博客
术语:
英文缩写 | 描述 |
GPIO:General Purpose Input Onuput | 通用输入输出 |
AFIO:Alternate Function Input Output | 复用输入输出 |
AO:Analog Output | 模拟输出 |
DO:Digital Output | 数字输出 |
内部时钟源 CK_INT:Clock Internal | 内部时钟源 |
外部时钟源 ETR:External Trigger | 时钟源 External 触发 |
外部时钟源 ETR:External Trigger mode 1 | 外部时钟源 External 触发 时钟模式1 |
外部时钟源 ETR:External Trigger mode 2 | 外部时钟源 External 触发 时钟模式2 |
外部时钟源 ITRx:Internal Trigger inputs | 外部时钟源,ITRx (Internal trigger inputs)内部触发输入 |
外部时钟源 TIx:exTernal Input pin | 外部时钟源 TIx (external input pin)外部输入引脚 |
CCR:Capture/Comapre Register | 捕获/比较寄存器 |
OC:Output Compare | 输出比较 |
IC:Input Capture | 输入捕获 |
TI1FP1:TI1 Filter Polarity 1 | Extern Input 1 Filter Polarity 1,外部输入1滤波极性1 |
TI1FP2:TI1 Filter Polarity 2 | Extern Input 1 Filter Polarity 2,外部输入1滤波极性2 |
DMA:Direct Memory Access | 直接存储器存取 |
正文:
0. 概述
从 2024/06/12 定下计划开始学习下江协科技STM32课程,接下来将会按照哔站上江协科技STM32的教学视频来学习入门STM32 开发,本文是视频教程 P2 STM32简介一讲的笔记。
本节我们来写一下串口收发数据包的代码
1.🚚第一个代码:串口收发HEX数据包
接线图
和上节的接线基本一样,只是在PB1口接了一个按键,用于控制。
我们在上节的Serial.c文件里加上HEX收发数据包的部分,定义的格式就和上一篇博客中说的HEX数据包接收固定包长,含包头包尾的这个思路一样,就按这个写状态机的思路写。
为了收发数据包,我们先定义两个缓冲区的数组。
这四个数据只存储发送或接收的载荷数据,包头包尾就不存了。
初始化的代码都不需要更改,把上节的这个函数删掉
然后我们先写一个send packet的函数。我们想要的效果是调用一下这个函数,Tx packet数组的四个数据就会自动加上包头报尾发送出去。
接下来我们就来写一下接收数据包的代码
首先在接收中断函数里,我们就需要用状态机来执行接收逻辑了,这就按上面那个状态转移图来写。
首先我们要定义一个标志当前状态的变量s,在中断这里,我们可以在函数里面定义一个静态变量RxState当成这个状态变量s
然后根RxState的不同,需要进入不同的处理程序。
📤️📤️注意:这里一定是要用else if,如果只用3个并列的If,可能在状态转移的时候会出现问题,比如在状态0,你想转移的状态1就置RxState等于1,结果就会造成下面状态1的条件就立马满足了,这样会出现连续两个if都同时成立的情况,这个情况我们不希望出现。
🎵🎵🎵
所以这里使用else if,保证每次进来之后,只能选择执行其中一个状态的代码,或者你用switch case语句,也可以保证只有一个条件满足。
这就是状态选择的部分。然后就依次写每个状态执行的操作和状态转移条件就行了。
🔊🔊🔊这个程序还隐藏有一个问题,就是这个Serial_RxPacket数组,它是一个同时被写入,又同时被读出的数组。
🔊🔊🔊在中断函数里,我们会依次写入它,在主函数里,我们又会依次读出它。这会造成数据包之间可能会混在一起。比如读出的过程太慢了,前面两个数据刚读出来,等了一会儿才继续往后读取。这时后面的数据就有可能会刷新为下一个数据包的数据,也就是读出的数据可能一部分属于上一个数据包,另一部分属于下一个数据包。
🔋🔋解决方法可以在接收部分加入判断,就是在每个数据包读取处理完毕后,再接收下一个数据包。当然,很多情况下其实还可以不进行处理,像这种hex数据包多是用于传输各种传感器的每个独立数据,比如陀螺仪的xyz轴数据,温湿度数据等等,它们相邻数据包之间的数据具有连续性,这样即使相邻数据包混在一起了,也没关系。所以这种情况下就不需要关心这个问题,具体到底怎么处理,还需要大家结合实际情况来操作了,这里就提一下这个可能存在的问题。大家了解一下就行了。
我们这个收发hex数据包的程序大概就讲完了。
接下来加上按键部分的代码,现象是按一下按键变换一下数据,发送到串口助手上。
定义一个变量
然后在主函数中实现按键的控制就行
2🚚.第二个程序:串口收发文本数据包
接线图:
在PA1口接了一个LED,用于指示。
我们在上一个工程的基础上改,按键部分的代码就不要了。
接下来就按上节讲过的文本数据包接收的思路来写,这里是可变包长,含包头包尾。
我们这里就只写接收的部分,因为发送的话不方便像hex数组一样一个个更改的。所以发送就直接在主函数里sendstring或者printf就行了,非常简单。
所以这个发送数据包的函数就不要了
接收部分我们来来实现一下。
数组的长度给多点,防止溢出,给个100,这要求单条指令最长不能超过一百个字符。
之后是中断的状态机部分,参考上面状态转移图写。
接下来就把LED部分的代码加进来就行
先是判断字符串是不是等于我们规定的指令再执行相应的操作。判断字符串要用到字符串处理函数,要包含头文件#include "string.h"。
在这里我们判断两个字符串是否相等,需要用到strcmp函数,如果不知道这个函数的用法可以去翻一下我的C语言复习专栏,在这篇博文中我详细介绍了字符串处理函数。
🔊🔊还有个问题需要说明,同样还是之前的个问题。如果连续发送数据包程序处理不及时,可能导致数据包错位。
🔊🔊在这里,文本数据包,每个数据包是独立的,不存在连续,这如果错位了问题就比较大。所以在程序这里我们可以修改一下,等每次处理完成之后,再开始接收下一个数据包。
我们可以这样在中断函数中等待包头的时候再加一个条件,如果数据等于包头并且Serial_RxFlag等于等于0才执行接收,否则就是发的太快了,还没处理完,就跳过这个数据包。
然后上面这个读取标志位之后立刻清零的函数先删掉。
运行结果
这就是我们第二个程序的现象。
本节的内容到这里就结束了,下节继续。