树莓派与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年运动目标跟踪控制系统的图像处理代码。

### 树莓派STM32之间的通信方法 树莓派STM32可以通过多种方式进行通信,其中最常用的三种方式是串口UART、I2C以及SPI。每种通信方式都有其特点和适用场景。 #### 1. **串口UART通信** 串口UART是一种全双工通信协议,适合用于简单的数据交换应用。它不需要额外的同步信号线,因此硬件连接较为简单。以下是通过Python树莓派上配置UART的一个基本示例: ```python import serial # 配置串口参数 ser = serial.Serial('/dev/ttyS0', baudrate=9600, timeout=1) def send_data(data): ser.write(data.encode()) # 发送数据到STM32 def receive_data(): data = ser.readline().decode() # 接收来自STM32的数据 return data if __name__ == "__main__": while True: message = input("Enter a message to send: ") send_data(message) response = receive_data() print(f"Received from STM32: {response}") ``` 在STM32端可以使用HAL库来初始化USART外设并处理接收/发送操作[^1]。 --- #### 2. **I2C通信** I2C是一种半双工通信协议,适用于多设备共享总线的情况。它的优点在于只需要两根线(SDA和SCL),缺点是对速度有一定限制。以下是一个基于Python树莓派I2C通信示例: ```python import smbus # 初始化I2C总线 i2c_bus = smbus.SMBus(1) # 使用I2C-1接口 address = 0x48 # 假设STM32作为从机地址为0x48 def write_byte(value): i2c_bus.write_byte(address, value) # 向指定地址写入单字节数据 def read_byte(): byte = i2c_bus.read_byte(address) # 读取来自指定地址的单字节数据 return byte if __name__ == "__main__": while True: command = int(input("Enter an integer to send via I2C: ")) write_byte(command) result = read_byte() print(f"Read back from STM32: {result}") ``` 在STM32侧,需设置相应的I2C外设为主模式或从模式,并编写中断服务程序以响应事件。 --- #### 3. **SPI通信** SPI支持高速传输,通常采用四线制(MOSI/MISO/SCLK/SS)。相比I2C,SPI更适合高带宽需求的应用场合。下面展示了一个利用spidev模块实现树莓派STM32之间SPI交互的例子: ```python import spidev import time spi = spidev.SpiDev() spi.open(0, 0) # 打开SPI通道0上的CS0 spi.max_speed_hz = 1000000 # 设置最大频率为1 MHz def spi_transfer(byte_array): response = spi.xfer(byte_array) # 进行双向数据传输 return response if __name__ == "__main__": try: while True: tx_bytes = [int(x) for x in input("Enter bytes separated by space: ").split()] rx_bytes = spi_transfer(tx_bytes) print(f"Received bytes: {rx_bytes}") time.sleep(0.5) except KeyboardInterrupt: spi.close() ``` 同样,在STM32一侧需要启用SPI功能并通过DMA或者轮询机制完成数据帧的传递。 --- ### 总结 选择哪种通信方式取决于实际项目的需求。如果追求低延迟且有较高吞吐量的要求,则推荐选用SPI;而对于成本敏感型设计或是希望减少布线复杂度的情况下,可以选择I2C或UART。无论采取何种手段,都需要仔细考虑双方的工作电压差异及其电气兼容性问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值