树莓派4B与STM32串口通信实验教程(附开源代码)- 串口波特率设置
(1)、UART,(2)、SPI,(3)、I2C(该项目使用Serial)
1.2 树莓派4B安装Serial与使用
引脚连接:
根据上图树莓派4B的 Pin 引脚图中 GPIO14(TXD) 和 GPIO15(RXD) 的两个引脚分别与 STM32F103C8T6 的 PA10(RXD) 和 PA10(RXD) 的引脚相连(交叉连接)
1.2.1 安装serial
在终端输入:sudo apt-get install serial
1.2.2 打开树莓派4B串口
在终端输入:sudo raspi-config 打开界面设置
Interfacing Options→serial→否→是
在终端输入:ls -al /dev/查看设备
1.2.3 修改串口映射关系
在终端输入:sudo nano /boot/config.txt
末行添加 dtoverlay=pi3-miniuart-bit
重启树莓派4B,之后终端输入:ls -la /dev/查看设备
1.2.4 修改配置文件
在终端输入:sudo nano /boot/cmdline.txt
修改cmdline.txt文件的内容,内容如下:
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait
二、安装minicom与树莓派4B测试
2.1 minicom安装
minicom 是 Linux/树莓派4B 平台串口调试工具,相当于 windows 上的串口调试助手,此时需要先安装 minicom;
sudo apt-get install minicom
在终端输入:minicom -D /dev/ttyAMA0
如果要退出这个minicom软件的话,先按CTRL+A再按Z就会弹出菜单,按下0回车就退出了,然后就能直接关闭了。
2.2 树莓派4B通信测试
我们使用 XCOM 串口调试助手来测试树莓派4B能否正常进行 UART 通信!
使用USB-TTL模块交叉连接树莓派4B的 UART 的引脚;
**★特殊说明:**USB-TTL 模块的 VCC 和 GND 一定都要与树莓派4B的相应 Pin 相连,不然可能因为电流的不平衡导致端口疯狂输出乱码!
我们在下图 minicom 红框区域输入 **Hi IKUN!**字样之后,可以在 XCOM 的端口处看到字符串成功发送到了 PC 端;
同理,在 XCOM 端口发送 Hi My Brother 字样之后,可以在树莓派4B的 minicom 红框区域成功接收到该信息!
当成功完成上述的操作之后,说明我们已经成功的配置好树莓派4B的UART功能!之后就可以尝试与 STM32 进行通信了(发送数据给XCOM不仅可以通过 minicom,也可以通过python等代码)!
三、树莓派4B与STM32通信
STM32 的代码其实就是简单的UART串口通讯代码,但实质上是有很多坑!!!作者发现大部分博主并没有说明出坑所在,这部分作者将会为读者朋友把可能出现的坑给解决掉!
3.1 树莓派4B代码
我们利用 Python 代码写一个循环发送数字的代码程序,具体代码如下:
import serial
import time
ser = serial.Serial('/dev/ttyAMA0',115200) # 串口初始化,根据实际情况修改串口号和波特率
# 定义要输出的数字
num = 196
while True:
ser.write(str(int(num)).encode()) # 发送数字到串口
num += 1
if num > 205:
num = 196
time.sleep(0.2) # 等待1秒钟
可以看出代码是非常简单的,但是这里读者朋友需要注意的是树莓派4B的端口发送至STM32的其实都是字符串流!在STM32端我们对发送过来的字符串流进行解码(很多博主其实都没有说明该点,导致很多朋友解码失败)!
3.2 CubeMX配置
1、RCC配置外部高速晶振(精度更高)——HSE;
2、SYS配置:Debug设置成Serial Wire(否则可能导致芯片自锁);
3、I2C配置:
4、USART1配置:设置UART1串口;波特率:115200;开启UART串口中断;
5、时钟树配置
6、工程配置
3.3 STM32代码
3.3.1 OLED代码
OLED模块主要是方便显示树莓派4B发送给STM32的数据信息!考虑到实际情况,我们一般需要根据树莓派4B发送过来的数字信息,所以,我们这里利用OLED进行数字显示!
小数显示API函数:
//z_len为整数显示位数,f_len为小数显示位数,size2为字体大小
void OLED_Showdecimal(u8 x,u8 y,float num,u8 z_len,u8 f_len,u8 size2)
{
u8 t,temp;
u8 enshow;
int z_temp,f_temp;
z_temp=(int)num;
//整数部分
for(t=0;t<z_len;t++)
{
temp=(z_temp/oled_pow(10,z_len-t-1))%10;
if(enshow==0 && t<(z_len-1))
{
if(temp==0)
{
OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
continue;
}
else
enshow=1;
}
OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2);
}
//小数点
OLED_ShowChar(x+(size2/2)*(z_len),y,'.',size2);
f_temp=(int)((num-z_temp)*(oled_pow(10,f_len)));
//小数部分
for(t=0;t<f_len;t++)
{
temp=(f_temp/oled_pow(10,f_len-t-1))%10;
OLED_ShowChar(x+(size2/2)*(t+z_len)+5,y,temp+'0',size2);
}
}
篇幅有限,OLED参考博客:http://t.csdn.cn/kydg4
3.3.2 UART代码
这部分代码是比较核心的,上述博客作者已经说明了,其实树莓派4B发送给STM32的数据都是以字符串流的格式发送来得。所以,即使发送过来的是数字数据也会变成字符,这就需要我们进行解码!
uart.h:
#ifndef __UART_H
#define __UART_H
#include "stm32f1xx_hal.h"
extern UART_HandleTypeDef huart1;
#define USART1_REC_LEN 600
extern int USART1_RX_BUF[USART1_REC_LEN];
extern uint16_t USART1_RX_STA;
extern int USART1_NewData;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
#endif
uart.c:
#include "uart.h"
#include "oled.h"
int USART1_RX_BUF[USART1_REC_LEN]; //目标数据
uint16_t USART1_RX_STA=2;
int USART1_NewData;
extern int num; //百位
extern int num2; //十位
extern int num3; //个位
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart ==&huart1)
{
USART1_RX_BUF[USART1_RX_STA&0X7FFF]=USART1_NewData;
USART1_RX_STA++;
if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;
//num = USART1_RX_BUF[USART1_RX_STA];
HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1);
num = USART1_RX_BUF[USART1_RX_STA-1];
num2 = USART1_RX_BUF[USART1_RX_STA-2];
num3 = USART1_RX_BUF[USART1_RX_STA-3];
}
}
上述UART代码,利用 UART 中断函数进行读取 USART1_NewData 的数值,因为我们最大传输的数字为3位数,所以我们分别读取缓存数组中最近的 3 个字节数据(树莓派4B发送过来的是字符串,也就是被转换成了对应数字的ASCII数值,例如:发送过来100,则STM32端接收到的为49 49 48 这3个字节)。
3.3.3 数据解码代码
control.c:
#include "control.h"
#include "uart.h"
#include "tim.h"
#include "oled.h"
int num;
int num2;
int num3;
int value;
int flag;
int last;
void TargetTracking()
{
flag = USART1_RX_STA - last;
last = USART1_RX_STA;
value = (num3-48) * 100 + (num2-48) * 10 + (num-48) * 1;
OLED_ShowStr(10,2,"Object Center",2);
OLED_Showdecimal(45,4,value,3,1,16);
if(flag == 2)
{
value = (num2-48) * 10 + (num-48) * 1;
OLED_Showdecimal(40,4,value,3,1,16);
}
}
这里默认都是 3 位数,所以之间按照 UART 数据传输高低位的数据将数据-48变为实际的数字,在×对应的比例即可得到实际值!flag 则是通过 USART1_RX_STA 变量的变化值判断一次传输过来几个字节的数据,可以判断是几位数!
读者朋友可以根据自己实际情况更改上述代码为己所用!
代码运行之后:
四、高级应用
智能小车的目标追踪
树莓派4B通常会出现在基于视觉技术进行规定目标的追踪,这个时候往往需要树莓派4B读取到目标框数据,然后发送给STM32下位机,之后STM32根据这些目标框信息来进行逻辑上的控制。
作者这里以上一篇博客的网络模型检测结果为例,代码如下:
import cv2
import numpy as np
import onnxruntime as ort
import serial
import time
## 最后
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
**深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**
**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**







**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!
7Kifn-1715710950517)]
[外链图片转存中...(img-db6x3o9v-1715710950519)]
[外链图片转存中...(img-2mIFnw8q-1715710950519)]
[外链图片转存中...(img-unSgX7yr-1715710950520)]
[外链图片转存中...(img-VIN91DyE-1715710950520)]
[外链图片转存中...(img-g0ed0vBj-1715710950521)]
[外链图片转存中...(img-vdPAVZ8y-1715710950521)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!
作者:普通网友