STM32与openmv的串口通信

OpenMV与STM32的通信是嵌入式系统和物联网领域中的一项重要技术。OpenMV是一种开源的微型机器视觉模块,基于ARM Cortex-M7微控制器,支持多种图像处理功能,如颜色识别、形状检测等。而STM32是STMicroelectronics公司推出的基于ARM Cortex内核的32位微控制器系列,具有高性能、低功耗和丰富的外设接口。

在OpenMV与STM32之间建立通信,常用的方式包括UART(通用异步收发传输器)、SPI(串行外设接口)和I2C(两线式串行总线)等。这些通信协议各有特点,如UART适合长距离通信,SPI和I2C则更适合短距离通信。在选择通信协议时,需要考虑数据传输速率、硬件资源、通信距离以及复杂度等因素。

实现OpenMV与STM32的通信,需要在硬件上进行引脚连接,确保双方的工作电压一致,并正确连接TX(发送)和RX(接收)引脚。在软件方面,需要分别在OpenMV和STM32上配置相应的通信接口参数,如波特率、数据位、停止位等,以确保双方能够正确地进行数据传输。

通过OpenMV与STM32的通信,可以实现图像数据的实时传输和处理,为嵌入式系统和物联网应用提供了强大的机器视觉功能。这种通信方式在智能小车、机器人、无人机等领域具有广泛的应用前景。

OpenMV与STM32之间的通信通常通过串行通信接口(如UART、SPI或I2C)来实现。这些接口允许两个设备之间以数字信号的形式交换数据。以下是OpenMV与STM32通信的几种常见方法:

1. UART(通用异步收发传输器)

UART是最常用的串行通信接口之一,它不需要时钟同步信号,而是使用起始位、数据位、校验位和停止位来标记数据的开始和结束。

硬件连接:将OpenMV的TX(发送)引脚连接到STM32的RX(接收)引脚,同时将OpenMV的RX(接收)引脚连接到STM32的TX(发送)引脚。确保两个设备的GND(地线)也连接在一起。

软件配置:在OpenMV上,使用pyb.UART()函数来初始化串口。在STM32上,使用STM32CubeMX或手动配置USART外设,并编写代码来初始化串口。

数据通信:在OpenMV上,使用uart.send()或uart.write()函数发送数据。在STM32上,使用中断或轮询方式接收数据,并使用HAL_UART_Receive()等函数读取数据。

2. SPI(串行外设接口)

SPI是一种同步串行通信协议,它使用主从设备架构,其中一个设备作为主机(通常是STM32),其他设备作为从机(如OpenMV,但需要注意OpenMV的SPI支持情况)。

硬件连接:连接MOSI(主出从入)、MISO(主入从出)、SCK(时钟)和CS(片选)引脚。确保GND也连接在一起。

软件配置:在OpenMV上,如果支持SPI,则使用pyb.SPI()函数来初始化SPI接口。在STM32上,使用STM32CubeMX或手动配置SPI外设。

数据通信:在OpenMV上,使用spi.send()和spi.recv()等函数进行数据传输。在STM32上,使用HAL_SPI_Transmit()和HAL_SPI_Receive()等函数进行数据传输。

注意:OpenMV的SPI支持可能因版本和硬件配置而异,因此在使用前需要查阅OpenMV的官方文档以确认其SPI功能。

3. I2C(总线)

I2C也是一种同步串行通信协议,它使用两根线(SDA数据线和SCL时钟线)进行数据传输。与SPI相比,I2C支持多个从设备连接到一个主设备。

硬件连接:连接SDA和SCL引脚,以及GND。

软件配置:在OpenMV上,如果支持I2C,则使用pyb.I2C()函数来初始化I2C接口。在STM32上,使用STM32CubeMX或手动配置I2C外设。

数据通信:在OpenMV上,使用i2c.send()和i2c.recv()等函数进行数据传输。在STM32上,使用HAL_I2C_Master_Transmit()和HAL_I2C_Master_Receive()等函数进行数据传输。

注意:同样地,OpenMV的I2C支持也可能因版本和硬件配置而异。

总结

在选择通信接口时,需要考虑数据传输速率、设备数量、硬件资源和软件复杂度等因素。UART通常是最简单且最常用的选择,而SPI和I2C则适用于需要更高数据传输速率或需要连接多个从设备的场景。在编写代码时,务必确保两个设备的通信参数(如波特率、数据位、停止位、校验位等)一致,以避免通信错误。

通信原理:

1、通信基础

通信方式:OpenMV与STM32之间的通信主要通过串口(UART)实现,这是一种异步通信方式,不需要时钟同步信号,而是直接在数据信号中穿插一些用于同步的信号位,或者以数据帧的格式传输数据。
硬件连接:在硬件连接上,OpenMV的TX(发送)引脚连接到STM32的RX(接收)引脚,同时OpenMV的RX(接收)引脚连接到STM32的TX(发送)引脚。通常,OpenMV的UART引脚为P4(TX)和P5(RX),而STM32的UART引脚则根据具体型号有所不同,如STM32F103系列的USART1通常使用PA9(TX)和PA10(RX)。此外,还需要确保OpenMV和STM32的电源和地线正确连接,以保证稳定的电源供应和信号传输。

2、通信过程

初始化:在通信开始前,需要在OpenMV和STM32上分别进行初始化设置。在OpenMV端,需要编写Python代码来配置串口,包括设置波特率、数据位、停止位和校验位等参数。在STM32端,则需要使用STM32CubeMX或手动配置时钟和GPIO引脚,并编写代码来初始化串口,确保与OpenMV的串口配置一致。
数据发送:在OpenMV端,可以通过串口发送数据。数据可以包括图像识别结果(如目标坐标、大小等)。发送数据前,需要编写函数来打包需要发送的数据,并通过串口发送。数据打包时,可以使用特定的字节作为帧头和帧尾,以确保数据传输的准确性和可靠性。
数据接收:在STM32端,需要编写接收中断服务函数来读取接收到的数据,并根据数据帧格式进行解析。接收数据时,STM32需要不断地检查串口接收缓冲区,当接收到完整的数据帧时,进行解析并提取出有效数据。如果数据帧不完整或格式错误,则需要丢弃当前数据帧并等待下一个数据帧的到来。

一、串口通信传输两个数据(x坐标和y坐标)

(一)、 OPENMV串口通信部分

import sensor, image, time,math,pyb
from pyb import UART,LED
import json
import ustruct
 
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False) # must be turned off for color tracking
sensor.set_auto_whitebal(False) # must be turned off for color tracking
red_threshold_01=(10, 100, 127, 32, -43, 67)
clock = time.clock()
 
uart = UART(3,115200)   #定义串口3变量
uart.init(115200, bits=8, parity=None, stop=1) # init with given parameters
 
def find_max(blobs):    #定义寻找色块面积最大的函数
    max_size=0
    for blob in blobs:
        if blob.pixels() > max_size:
            max_blob=blob
            max_size = blob.pixels()
    return max_blob
 
 
def sending_data(cx,cy,cw,ch):
    global uart;
    #frame=[0x2C,18,cx%0xff,int(cx/0xff),cy%0xff,int(cy/0xff),0x5B];
    #data = bytearray(frame)
    data = ustruct.pack("<bbhhhhb",      #格式为俩个字符俩个短整型(2字节)
                   0x2C,                      #帧头1
                   0x12,                      #帧头2
                   int(cx), # up sample by 4   #数据1
                   int(cy), # up sample by 4    #数据2
                   int(cw), # up sample by 4    #数据1
                   int(ch), # up sample by 4    #数据2
                   0x5B)
    uart.write(data);   #必须要传入一个字节数组
 
 
while(True):
    clock.tick()
    img = sensor.snapshot()
    blobs = img.find_blobs([red_threshold_01])
    max_b = find_max(blobs)
    cx=0;cy=0;
    if blobs:
            #如果找到了目标颜色
            cx=max_b[5]
            cy=max_b[6]
            cw=max_b[2]
            ch=max_b[3]
            img.draw_rectangle(max_b[0:4]) # rect
            img.draw_cross(max_b[5], max_b[6]) # cx, cy
            FH = bytearray([0x2C,0x12,cx,cy,cw,ch,0x5B])
            #sending_data(cx,cy,cw,ch)
            uart.write(FH)
            print(cx,cy,cw,ch)在这里插入代码片

STM32端的代码相对复杂,涉及到硬件抽象层(HAL)或标准外设库(SPL)的使用,以及串口中断服务函数的编写。基本思路是初始化串口,编写接收中断服务函数来读取数据,并根据数据帧格式进行解析和处理。

接下来请看STM32串口通信部分的代码:

#include "uart.h"
#include "oled.h"
#include "stdio.h"
 
static u8 Cx=0,Cy=0,Cw=0,Ch=0;
 
void USART1_Init(void)
{
	//USART1_TX:PA 9   
	//USART1_RX:PA10
	GPIO_InitTypeDef GPIO_InitStructure;     //串口端口配置结构体变量
	USART_InitTypeDef USART_InitStructure;   //串口参数配置结构体变量
	NVIC_InitTypeDef NVIC_InitStructure;     //串口中断配置结构体变量
 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   //打开PA端口时钟
 
    //USART1_TX   PA9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;          		 //PA9
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  		 //设定IO口的输出速度为50MHz
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	   		 //复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);             	 	 //初始化PA9
    //USART1_RX	  PA10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;             //PA10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  //浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);                 //初始化PA10 
 
    //USART1 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;  //抢占优先级0
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;		  //子优先级2
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			  //IRQ通道使能
		NVIC_Init(&NVIC_InitStructure);	                          //根据指定的参数初始化VIC寄存器
 
    //USART 初始化设置
		USART_InitStructure.USART_BaudRate = 115200;                  //串口波特率为115200
		USART_InitStructure.USART_WordLength = USART_WordLength_8b;   //字长为8位数据格式
		USART_InitStructure.USART_StopBits = USART_StopBits_1;        //一个停止位
		USART_InitStructure.USART_Parity = USART_Parity_No;           //无奇偶校验位
		USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;   //无硬件数据流控制
		USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	                  //收发模式
    USART_Init(USART1, &USART_InitStructure);                     //初始化串口1
 
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //使能中断
    USART_Cmd(USART1, ENABLE);                     //使能串口1
 
  	//如下语句解决第1个字节无法正确发送出去的问题
	  USART_ClearFlag(USART1, USART_FLAG_TC);        //清串口1发送标志
		
}
 
//USART1 全局中断服务函数
void USART1_IRQHandler(void)			 
{
		u8 com_data; 
		u8 i;
		static u8 RxCounter1=0;
		static u16 RxBuffer1[10]={0};
		static u8 RxState = 0;	
		static u8 RxFlag1 = 0;
 
 
		if( USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)  	   //接收中断  
		{
				USART_ClearITPendingBit(USART1,USART_IT_RXNE);   //清除中断标志
				com_data = USART_ReceiveData(USART1);
			
				if(RxState==0&&com_data==0x2C)  //0x2c帧头
				{
					RxState=1;
					RxBuffer1[RxCounter1++]=com_data;OLED_Refresh();
				}
		
				else if(RxState==1&&com_data==0x12)  //0x12帧头
				{
					RxState=2;
					RxBuffer1[RxCounter1++]=com_data;
				}
		
				else if(RxState==2)
				{
					RxBuffer1[RxCounter1++]=com_data;
 
					if(RxCounter1>=10||com_data == 0x5B)       //RxBuffer1接受满了,接收数据结束
					{
						RxState=3;
						RxFlag1=1;
						Cx=RxBuffer1[RxCounter1-5];
						Cy=RxBuffer1[RxCounter1-4];
						Cw=RxBuffer1[RxCounter1-3];
						Ch=RxBuffer1[RxCounter1-2];
					}
				}
		
				else if(RxState==3)		//检测是否接受到结束标志
				{
						if(RxBuffer1[RxCounter1-1] == 0x5B)
						{
									USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);//关闭DTSABLE中断
									if(RxFlag1)
									{
									OLED_Refresh();
									OLED_ShowNum(0, 0,Cx,3,16,1);
									OLED_ShowNum(0,17,Cy,3,16,1);
									OLED_ShowNum(0,33,Cw,3,16,1);
									OLED_ShowNum(0,49,Ch,3,16,1);
									}
									RxFlag1 = 0;
									RxCounter1 = 0;
									RxState = 0;
									USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
						}
						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;      //将存放数据数组清零
						}
				}
 
		}
		
}

(一)OPENMV串口部分

from machine import Pin
import sensor, image, time, pyb
#import seekfree
from pyb import UART
 
# 初始化TFT180屏幕
#lcd = seekfree.LCD180(3)
 
# 初始化摄像头
sensor.reset()
sensor.set_pixformat(sensor.RGB565) # 设置图像色彩格式为RGB565格式
sensor.set_framesize(sensor.QQVGA)  # 设置图像大小为160*120
sensor.set_auto_whitebal(True)      # 设置自动白平衡
sensor.set_brightness(3000)         # 设置亮度为3000
sensor.skip_frames(time = 20)       # 跳过帧
uart = UART(3, 115200,timeout_char=3000) #配置串口
clock = time.clock()
 
def sending_data(cx,cy,cw,ch):
    global uart;
    data = ustruct.pack("<bbhhb",      #格式为俩个字符俩个短整型(2字节)
                   0x2C,                      #帧头1
                   0x12,                      #帧头2
                   int (cx1), # up sample by 4    #数据26
                   int (cy1),
                   int (cx2), # up sample by 4    #数据26
                   int (cy2),
                   int (cx3), # up sample by 4    #数据26
                   int (cy3),
                   int (cx4), # up sample by 4    #数据26
                   int (cy4),
                   0x5B)
    uart.write(data);   #必须要传入一个字节数组
 
while(True):
    clock.tick()
    img = sensor.snapshot()
 
# -----矩形框部分-----
    # 在图像中寻找矩形
    for r in img.find_rects(threshold = 10000):
        # 判断矩形边长是否符合要求
        if r.w() > 20 and r.h() > 20:
            # 在屏幕上框出矩形
            img.draw_rectangle(r.rect(), color = (255, 0, 0), scale = 4)
            # 获取矩形角点位置
            corner = r.corners()
            # 在屏幕上圈出矩形角点
            img.draw_circle(corner[0][0], corner[0][1], 5, color = (0, 0, 255), thickness = 2, fill = False)
            img.draw_circle(corner[1][0], corner[1][1], 5, color = (0, 0, 255), thickness = 2, fill = False)
            img.draw_circle(corner[2][0], corner[2][1], 5, color = (0, 0, 255), thickness = 2, fill = False)
            img.draw_circle(corner[3][0], corner[3][1], 5, color = (0, 0, 255), thickness = 2, fill = False)
 
        # 打印四个角点坐标, 角点1的数组是corner[0], 坐标就是(corner[0][0],corner[0][1])
        # 角点检测输出的角点排序每次不一定一致,矩形左上的角点有可能是corner0,1,2,3其中一个
            corner1_str = f"corner1 = ({corner[0][0]},{corner[0][1]})"
            corner2_str = f"corner2 = ({corner[1][0]},{corner[1][1]})"
            corner3_str = f"corner3 = ({corner[2][0]},{corner[2][1]})"
            corner4_str = f"corner4 = ({corner[3][0]},{corner[3][1]})"
        print(corner1_str + "\n" + corner2_str + "\n" + corner3_str + "\n" + corner4_str)
    # 显示到屏幕上,此部分会降低帧率
    #lcd.show_image(img, 160, 120, 0, 0, zoom=0)  #屏幕显示
 
    #串口通信传输的数据
        cx1=(int)(corner[0][0]*10)
        cy1=(int)(corner[0][1]*10)
 
        cx2=(int)(corner[1][0]*10)
        cy2=(int)(corner[1][1]*10)
 
        cx3=(int)(corner[2][0]*10)
        cy3=(int)(corner[2][1]*10)
 
        cx4=(int)(corner[3][0]*10)
        cy4=(int)(corner[3][1]*10)
 
        FH=bytearray([0x2C,0x12,cx1,cy1,cx2,cy2,cx3,cy3,cx4,cy4,0x5B])
 
        uart.write(FH)
 
        cx1=0
        cy1=0
 
        cx2=0
        cy2=0
 
        cx3=0
        cy3=0
 
        cx4=0
        cy4=0
 
    # 打印帧率
    print(clock.fps())

STM32串口通信部分

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>
#include "OLED.h"
#include "LED.h"
#include "Serial.h"
 
uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
static int16_t Cx1=0,Cy1=0,Cx2=0,Cy2=0,Cx3=0,Cy3=0,Cx4=0,Cy4=0; 
 
int Cx5[16];//用于存放分段求的坐标值
int Cy5[16];
//static u8 RxFlag1 = 0;//串口中断接收标志位
 
extern float Ang1,Ang2,AngFlag;
extern float Angle1,Angle2;
 
int avel_X1 ;
int avel_X2 ;
int avel_X3 ;
int avel_X4 ;
 
int avel_Y1 ;
int avel_Y2 ;
int avel_Y3 ;
int avel_Y4 ;
 
void Serial_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	//TX
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	//RX
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = 115200;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART3, &USART_InitStructure);
	
	USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	USART_Cmd(USART3, ENABLE);
}
 
void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART3, Byte);
	while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
}
 
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
	uint16_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Array[i]);
	}
}
 
void Serial_SendString(char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i ++)
	{
		Serial_SendByte(String[i]);
	}
}
 
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y --)
	{
		Result *= X;
	}
	return Result;
}
 
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
	}
}
 
int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);
	return ch;
}
 
void Serial_Printf(char *format, ...)
{
	char String[100];
	va_list arg;
	va_start(arg, format);
	vsprintf(String, format, arg);
	va_end(arg);
	Serial_SendString(String);
}
//USART3 全局中断服务函数
void USART3_IRQHandler(void)			 
{
		int com_data; 
		u8 i;
		u8 Jieshou = 1;
		
		static u8 RxCounter1=0;
		static int RxBuffer1[16]={0};
		static u8 RxState = 0;	
		static u8 RxFlag1 = 0;//串口中断接收标志位,已被移除至函数体外作为全局变量
 
		if( USART_GetITStatus(USART3,USART_IT_RXNE)!=RESET && Jieshou == 1)  	   //接收中断  
		{
//			OLED_ShowSignedNum(1,1,520,4);
				USART_ClearITPendingBit(USART3,USART_IT_RXNE);   //清除中断标志
				com_data = USART_ReceiveData(USART3);
			if(Jieshou == 1)
			{
		
				if(RxState==0&&com_data==0x2C)  //0x2c帧头
				{
					RxBuffer1[RxCounter1++]=com_data;
					RxState=1;
				}
		
				else if(RxState==1&&com_data==0x12)  //0x12帧头
				{
					RxBuffer1[RxCounter1++]=com_data;
					RxState=2;
				}			
				else if(RxState==2)
				{
					RxBuffer1[RxCounter1++]=com_data;
 
					if(RxCounter1>=14||com_data == 0x5B)       //RxBuffer1接受满了,接收数据结束
					{
						RxState=3;
						RxFlag1=1;
						Jieshou = 2;
						
						Cx1=RxBuffer1[RxCounter1-9];
						Cy1=RxBuffer1[RxCounter1-8];
						
						Cx2=RxBuffer1[RxCounter1-7];
						Cy2=RxBuffer1[RxCounter1-6];
						
						Cx3=RxBuffer1[RxCounter1-5];
						Cy3=RxBuffer1[RxCounter1-4];
						
						Cx4=RxBuffer1[RxCounter1-3];
						Cy4=RxBuffer1[RxCounter1-2];
						
						OLED_ShowSignedNum(1,1,Cx1,4);
						OLED_ShowSignedNum(2,1,Cy1,4);
						OLED_ShowSignedNum(3,1,Cx2,4);
						OLED_ShowSignedNum(4,1,Cy2,4);
						
						OLED_ShowSignedNum(1,7,Cx3,4);
						OLED_ShowSignedNum(2,7,Cy3,4);
						OLED_ShowSignedNum(3,7,Cx4,4);
						OLED_ShowSignedNum(4,7,Cy4,4);
						
					}
				}
			}
				else if(RxState==3)		//检测是否接受到结束标志
				{
					if(RxBuffer1[RxCounter1-1] == 0x5B)
					{
						USART_ITConfig(USART3,USART_IT_RXNE,DISABLE);//关闭DTSABLE中断
						if(RxFlag1)
						{	
							
							AngFlag=0;
							HuanRaoZuoBiao();
//										
//							OLED_ShowSignedNum(1,1,Cx1,4);
 
//							OLED_ShowSignedNum(2,1,Cx2,4);
//							OLED_ShowSignedNum(3,1,avel_X1,4);
//							OLED_ShowSignedNum(4,1,Cx5[0],4);
 
							AngFlag=1;
							RxFlag1 = 0;
							RxCounter1 = 0;
							RxState = 0;									
						}
						USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);									
					}
					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;      //将存放数据数组清零
							
						}
				}
			
		}
	}

注意事项

波特率匹配:确保OpenMV和STM32的波特率设置一致,否则会导致数据传输错误。
数据帧格式:定义清晰的数据帧格式,避免数据冲突和解析错误。数据帧通常包括帧头、数据部分和帧尾。
电源稳定性:确保电源供应稳定,避免因电压波动导致的通信中断。
逐步测试:逐步测试每个功能模块,确保OpenMV和STM32之间的通信正常,数据解析正确。
相关推荐
yutian06067 小时前
Keil MDK下载程序后MCU自动重启设置
单片机·嵌入式硬件·keil
析木不会编程10 小时前
【小白51单片机专用教程】protues仿真独立按键控制LED
单片机·嵌入式硬件·51单片机
枯无穷肉14 小时前
stm32制作CAN适配器4--WinUsb的使用
stm32·单片机·嵌入式硬件
不过四级不改名67714 小时前
基于HAL库的stm32的can收发实验
stm32·单片机·嵌入式硬件
嵌入式科普15 小时前
十一、从0开始卷出一个新项目之瑞萨RA6M5串口DTC接收不定长
c语言·stm32·cubeide·e2studio·ra6m5·dma接收不定长
嵌入式大圣15 小时前
单片机UDP数据透传
单片机·嵌入式硬件·udp
云山工作室15 小时前
基于单片机的视力保护及身姿矫正器设计(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·毕设
嵌入式-老费15 小时前
基于海思soc的智能产品开发(mcu读保护的设置)
单片机·嵌入式硬件
qq_3975623117 小时前
MPU6050 , 设置内部低通滤波器,对于输出数据的影响。(简单实验)
单片机
liyinuo201717 小时前
嵌入式(单片机方向)面试题总结
嵌入式硬件·设计模式·面试·设计规范