树莓派与STM32通信全程详解:一步步带你走完全过程
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
笔者之前发过关于stm32与openmv通信的教程,在学习了几天opencv后,想实现树莓派4B与stm32进行通信。于是上网查询资料,最后实现了两者之间的通信,相信这对大多数电赛人都很有帮助,opencv的识别效果是远高于openmv以及K210的。在此我参考了以下资料辅助我学习,大家可以参考。
基于树莓派4B与STM32的UART串口通信实验(代码开源)_树莓派4b串口波特率-CSDN博客
这位大佬的接发方式我觉得可能对于新手朋友来说比较难懂,于是我换了一种收发方式,与我之前openmv与opencv通信的方式极为类似,如果那个可以搞懂,相信这个也不是问题,甚至超容易上手。
在此默认树莓派已经配置好环境烧录好系统。如果不会烧录系统以及配置opencv的可以私聊我获取镜像。
先上效果图以及视频
一、两者如何进行通信?
与我们之前openmv与stm32的通信方式类似,打开双方的串口然后互相连接,就可以进行通信,具体笔者不多描述,参考我给的链接就可以实现通信,笔者主要讲解我的数据传输方法。
具有以下两个特点:
1.以数据包格式打包发送,32端的代码不用过多改变,接收方式基本相同
data = bytearray([0x2C, 0x12, temp_xh, temp_xl, temp_yh, temp_yl, temp_wh, temp_wl,temp_hh,temp_hl ,0x5B])
ser.write(data)
2.可以发送16位数据,笔者起初一直发送8位数据,但是bytearray数据包只能发送8位的数据即最高只能发送小于256的数字。这对我们刚入手openmv和32通信的人极不友好。但是根据2023年e题有的坐标点大于256,我们将如何发送?我的解决方法我将数据拆分为高8位和低8位,发送到32后再让32进行解析。为此也是思考了一段时间,我认为还是很有帮助的也能很好的帮助大家。也自认为这个方法很不赖。在此我直接附上树莓派的代码。
import serial
import time
import struct
cx=300
cy=400
cw=500
ch=600
# 初始化串口,修改串口号和波特率
ser = serial.Serial('/dev/ttyAMA0', 115200)
def sending_data(cx, cy, cw, ch):
# 取 cx 的高 8 位
temp_xh = (cx & 0xff00) >> 8
# 取 cx 的低 8 位
temp_xl = cx & 0x00ff
# 取 cy 的高 8 位
temp_yh = (cy & 0xff00) >> 8
# 取 cy 的低 8 位
temp_yl = cy & 0x00ff
# 取 cw 的高 8 位
temp_wh = (cw & 0xff00) >> 8
# 取 cw 的低 8 位
temp_wl = cw & 0x00ff
# 取 ch 的高 8 位
temp_hh = (ch & 0xff00) >> 8
# 取 ch 的低 8 位
temp_hl = ch & 0x00ff
data = bytearray([0x2C, 0x12, temp_xh, temp_xl, temp_yh, temp_yl, temp_wh, temp_wl,temp_hh,temp_hl ,0x5B])
ser.write(data)
print(data)
while True:
# 模拟获取数据
cx += 100
cy += 100
cw += 100
ch += 100
sending_data(cx, cy, cw, ch)
time.sleep(0.2)
可以发现这种数据传输方式与openmv与stm32通信的方式极为类似,如果理解了这种传输方式,那么我写的这个树莓派传输数据的方式就超容易上手以及理解。只不过openmv没有加16位数据发送的格式而已。
二、stm32如何解析树莓派发送的数据
1.解析8位数据(0-256)
代码如下(示例):
8位数据比较简单直接从python发送的数据解析低8位就可以
bytearray([0x2C, 0x12, temp_xh, temp_xl, temp_yh, temp_yl, temp_wh, temp_wl,temp_hh,temp_hl ,0x5B])
这里temp_xh为高8位数据,temp_xl为低8位数据,stm32对应数组的位置C1为高8位,Cx为低8位,我们只用处理Cx就可以了。
Cx=RxBuffer1[RxCounter1-8];
C1=RxBuffer1[RxCounter1-9];
2.16位数据(0-65536)
与8位数据类似,我们只需将Cx和C1都读出来,让C1*256加上Cx就是大于256即16位的数据。
我直接附上总处理代码。(stm32端)
uint16_t Cx,Cy,Cw,Ch;
uint16_t C1,C2,C3,C4;
uint16_t X,Y,W,H;
uint8_t display_buf[20];
uint8_t Flag=0;
void Receive_Data(int16_t Com_Data)
{
uint8_t i;
static uint8_t RxCounter1=0;//
static uint16_t RxBuffer1[20]={0};
static uint8_t RxState = 0;
static uint8_t RxFlag1 = 0;
if(RxState==0&&Com_Data==0x2C) //0x2c
{
RxState=1;
RxBuffer1[RxCounter1++]=Com_Data;
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
}
else if(RxState==1&&Com_Data==0x12) //0x12
{
RxState=2;
RxBuffer1[RxCounter1++]=Com_Data;
}
else if(RxState==2)
{
RxBuffer1[RxCounter1++]=Com_Data;
if(RxCounter1>=20||Com_Data == 0x5B)
{
RxState=3;
Cx=RxBuffer1[RxCounter1-8];
C1=RxBuffer1[RxCounter1-9];
Cy=RxBuffer1[RxCounter1-6];
C2=RxBuffer1[RxCounter1-7];
Cw=RxBuffer1[RxCounter1-4];
C3=RxBuffer1[RxCounter1-5];
Ch=RxBuffer1[RxCounter1-2];
C4=RxBuffer1[RxCounter1-3];
X=C1*256+Cx;
Y=C2*256+Cy;
W=C3*256+Cw;
H=C4*256+Ch;
}
}
else if(RxState==3)//
{
if(RxBuffer1[RxCounter1-1] == 0x5B)
{
if(RxFlag1==0)
{
OLED_Clear();
}
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
RxFlag1++;
RxCounter1 = 0;
RxState = 0;
OLED_ShowNum(0,0,X,6,16);
OLED_ShowNum(0,2,Y,6,16);
OLED_ShowNum(0,4,W,6,16);
OLED_ShowNum(0,6,H,6,16);
}
else
{
RxState = 0;
RxCounter1=0;
for(i=0;i<10;i++)
{
RxBuffer1[i]=0x00; //
}
}
}
else
{
RxState = 0;
RxCounter1=0;
for(i=0;i<10;i++)
{
RxBuffer1[i]=0x00; //
}
}
}
XYWH分别对应处理过的cx,cy,cw,ch。我们直接用oled就可以显示我们从树莓派接收到的数据了。
3.stm32端开启中断
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
uint16_t tempt /*定义临时变量存放接受的数据*/;
if(huart->Instance==USART1)
{
tempt=USART1_RXbuff;
Receive_Data(tempt);
HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET);
}
HAL_UART_Receive_IT(&huart1,(void *)&USART1_RXbuff,1);/*再次开启接收中断*/
}
总结
具体的可以参考我openmv与stm32通信的文章,有详细的stm32端接收讲解。
https://blog.csdn.net/Halcyon0804/article/details/139890266?spm=1001.2014.3001.5502
到这里基本就实现两者的数据互传了。并且数据范围特别大,我相信已经很够用了,希望这篇文章可以帮到大家。
如果树莓派不会配置的可以私聊我获取树莓派配置好的镜像,已经配置好opencv以及2023年运动目标跟踪控制系统的图像处理代码。
作者:Blaze my Future