STM32与openmv通信(HAL库)

最近需要用到openmv进行追踪物体,所以在此做个小结,其中这些文章给我很大的帮助,建议可以去看超详细OpenMV与STM32单片机通信
以及星瞳科技官网

实验目的:openmv追踪物体颜色,将物体坐标发给32(为了 调试,顺便将32收到的数据传给上位机)
实验所需:openmv,STM32F103ZET6(正点原子)

一、openmv程序编写

# Untitled - By:阿布  - 周日 7月 19 2021

import sensor, image, time

from pid import PID
from pyb import Servo
from pyb import UART,LED
import json
import ustruct

pan_servo=Servo(1)
tilt_servo=Servo(2)

pan_servo.calibration(500,2500,500)
tilt_servo.calibration(500,2500,500)

#red_threshold  = (13, 49, 18, 61, 6, 47)
red_threshold  = (2, 12, -56, 2, -75, 14)#测试所用,白色,懒得该名称
pan_pid = PID(p=0.08, i=0, imax=90) #脱机运行或者禁用图像传输,使用这个PID
tilt_pid = PID(p=0.05, i=0, imax=90) #脱机运行或者禁用图像传输,使用这个PID
#pan_pid = PID(p=1, i=0, imax=90)#在线调试使用这个PID
#tilt_pid = PID(p=1, i=0, imax=90)#在线调试使用这个PID

sensor.reset() # Initialize the camera sensor.
sensor.set_pixformat(sensor.RGB565) # use RGB565.
sensor.set_framesize(sensor.QQVGA) # use QQVGA for speed.
sensor.skip_frames(10) # Let new settings take affect.
sensor.set_auto_whitebal(False) # turn this off.
clock = time.clock() # Tracks FPS.

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[2]*blob[3] > max_size:
            max_blob=blob
            max_size = blob[2]*blob[3]
    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() # Track elapsed milliseconds between snapshots().
    img = sensor.snapshot() # Take a picture and return the image.

    blobs = img.find_blobs([red_threshold])
    if blobs:
        max_blob = find_max(blobs)
        pan_error = max_blob.cx()-img.width()/2
        tilt_error = max_blob.cy()-img.height()/2

        #print("pan_error: ", pan_error)

        img.draw_rectangle(max_blob.rect()) # rect
        img.draw_cross(max_blob.cx(), max_blob.cy()) # cx, cy

        pan_output=pan_pid.get_pid(pan_error,1)/2
        tilt_output=tilt_pid.get_pid(tilt_error,1)
        #print("pan_output",pan_output)
        pan_servo.angle(pan_servo.angle()+pan_output)
        tilt_servo.angle(tilt_servo.angle()-tilt_output)
        cx=max_blob[5]
        cy=max_blob[6]
        cw=max_blob[2]
        ch=max_blob[3]
        FH = bytearray([0x2C,0x12,cx,cy,cw,ch,0x5B])
        uart.write(FH)
        print(cx,cy,cw,ch)

二、stm32

1、cubeMX配置
时钟树这些基本配置掠过,然后需要配置串口4,串口1,以及两个led灯(方便调试),配置串口记得开中断,以及配置优先级
在这里插入图片描述
串口4
串口1
2、源码
(1).openmv.h

#ifndef __OpenMV_H
#define	__OpenMV_H

#include "stm32f1xx.h"

void  Openmv_Receive_Data(int16_t data);
 
 
 
#endif

(2).openmv.c

#include "OpenMV.h"
#include "stdio.h"
#include "usart.h"


static uint8_t  Cx=0,Cy=0,Cw=0,Ch=0;



void   Openmv_Receive_Data(int16_t com_data)
{
  
    uint8_t i;
		static uint8_t RxCounter1=0;//计数
		static uint16_t RxBuffer1[10]={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(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET);
				}

				else if(RxState==1&&com_data==0x12)  //0x12帧头
				{
          HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
					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];
            printf("%d\r   ",Cx);
            printf("%d\r   ",Cy);
            printf("%d\r   ",Cw);
            printf("%d\r\n",Ch); 
//               if(RxState==1)
//          {
//            HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
//          }
//          else if(RxState!=1&&RxState!=0)
//          {
//            HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET);
//          }
					}
			}
		
				else if(RxState==3)		//检测是否接受到结束标志
				{
						if(RxBuffer1[RxCounter1-1] == 0x5B)
						{
									
									RxFlag1 = 0;
									RxCounter1 = 0;
									RxState = 0;
								
						}
						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;      //将存放数据数组清零
						}
				}
      }

/**
  * 函数功能: 重定向c库函数printf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}
 
/**
  * 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fgetc(FILE *f)
{
  uint8_t ch = 0;
  HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
  return ch;
}

(3).主函数
先定义两个全局变量

/* USER CODE BEGIN PV */
uint8_t usart1_rxbuff;
uint8_t uart4_rxbuff;

/* USER CODE END PV */

主函数里面加上串口接受中断开启

HAL_UART_Receive_IT(&huart4,(void *)&uart4_rxbuff,1);
HAL_UART_Receive_IT(&huart1,(void *)&usart1_rxbuff,1);

中断回调函数(切记要加上接收中断开启)

/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  uint16_t tem;
  if(huart->Instance==UART4)
  {
    tem=uart4_rxbuff;
    Openmv_Receive_Data(tem);
  }	
HAL_UART_Receive_IT(&huart4,(void *)&uart4_rxbuff,1);
}


/* USER CODE END 4 */

**

三、实验现象

**
在这里插入图片描述
四、总结
其中出现了一个好蠢的问题,就是我一直检测不到0x2c之后的数据,以为是接受解码程序的问题。后来发现只是忘记在中断回调函数里面加接收中断,真的是大无语事件。

### 回答1: 可以使用HAL来实现OpenMVSTM32之间的通信。具体而言,您可以使用UART通信协议来实现两个设备之间的数据传输。在STM32中,您可以使用HAL中的UART函数来发送和接收数据。而在OpenMV中,您可以使用UART通信协议来发送和接收数据。通过在两个设备之间建立UART通信协议,您可以实现可靠的数据传输。OpenMV是一款基于MicroPython的图像处理平台,主要用于嵌入式设备的视觉应用开发。而STM32是一系列由STMicroelectronics公司生产的微控制器,具有高性能、低功耗、可靠性高等优点。 HAL(Hardware Abstraction Layer)是ST公司提供的一套硬件抽象层,用于简化STM32芯片的底层开发,包括时钟、中断、GPIO、DMA等硬件模块的配置控制。 在使用OpenMV进行嵌入式视觉应用开发时,可以使用STM32芯片作为硬件平台,并且使用HAL作为硬件抽象层,简化底层硬件操作的复杂度。具体使用方法可以参考OpenMV官方文档和ST官方文档中有关HAL的章节。 ### 回答2: OpenMV是一款运行在MicroPython上的开源摄像头,可以用来实现机器视觉应用。而STM32则是一款功能强大的微控制器,广泛应用于各种嵌入式系统。若要实现OpenMVSTM32通信,需要使用HALHAL(Hardware Abstraction Layer)是针对硬件的底层驱动,对硬件进行抽象和封装,为上层应用提供一致的接口。通过HAL,可以方便地实现OpenMVSTM32通信。 一般情况下,OpenMV通过UART串口STM32通信。首先,在OpenMV的MicroPython环境中,需要使用UART对象来进行串口通信的配置。例如,可以设置串口通信的波特率、数据位、停止位、奇偶校验等参数,以及打开或关闭串口中断。最终,通过向串口发送数据和从串口接收数据,就可以实现OpenMVSTM32之间的通信。 在STM32方面,需要使用HAL中的UART驱动程序来对串口进行设置,包括设置串口通信的波特率、数据位、停止位、奇偶校验等参数,以及配置中断。通过调用HAL提供的函数,可以方便地发送和接收数据,实现OpenMV之间的通信。例如,可以使用HAL_UART_Transmit()函数发送数据,使用HAL_UART_Receive()函数接收数据。 需要注意的是,串口通信需要双方使用相同的波特率、数据位、停止位和奇偶校验等参数,否则将无法正确地接收和解析数据。此外,在编写代码时,还需要对串口通信进行错误处理,防止出现数据丢失或数据错误等情况。 总之,使用HAL可以方便地实现OpenMVSTM32之间的串口通信。通过充分利用底层驱动和通信协议,可以快速地完成机器视觉应用的开发和调试。 ### 回答3: OpenMVSTM32是两种非常常用的嵌入式设备,它们都有很多使用场景。在一些项目中,需要将OpenMVSTM32进行通信,这时候我们就可以使用HAL来实现。 HAL(Hardware Abstraction Layer)是为STM32微控制器编写的抽象层,它提供了一套统一的接口,方便开发人员在不同的STM32系列之间进行移植。在OpenMVSTM32之间通信的过程中,我们可以利用HAL提供的接口函数来实现数据传输。 在实际的操作中,我们需要对OpenMVSTM32进行硬件连接,通常会采用串口进行通信。我们可以利用HAL的UART(Universal Asynchronous Receiver/Transmitter)接口来实现串口通信。具体流程如下: 1. 在STM32的CubeMX中配置对应的GPIO口为UART口,设置波特率、数据位数、校验位等参数。 2. 在STM32代码中使用HAL的相关函数,开启和配置UART口。 3. 在OpenMV的代码中,使用pyb的UART接口,开启对应的串口。 4. 通过串口进行数据传输。 在具体的实现中,我们需要根据具体的应用场景进行数据处理。如果需要传输的数据较多,可以考虑对数据进行分包或压缩。如果需要实现实时控制,我们可以通过OpenMV传输图像数据,通过STM32进行处理和反馈。 总之,利用HAL实现OpenMVSTM32之间的通信是一种有效的方法。通过串口进行数据传输,可以实现较稳定、可靠的数据传输。在实际的项目中,我们需要充分利用HAL的功能,并结合具体的应用场景进行数据处理和控制。
评论 40
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值