目录

1.openmv端配置:

1.1  openmv代码:

1.2 openmv鱼眼镜头画面异常修正

2.STM32F103C8T6端配置



1.openmv端配置:

1.1  openmv代码:

         我使用的是将被识别的目标中心点坐标通过串口通讯发送给STM32,中心值感觉不是很准,后面还需要调整,但是基本的收发已经完成。

# Untitled - By: zzy - 周五 11月 25 2022

import sensor, image, time
from pyb import UART
import json

#output_str_green="[0,0]"
output_str_white="[0,0]"

#green_threshold  = (   0,   80,  -70,   -10,   -0,   30)
#使用的白色测试阈值
white_threshold  = (53, 100, -128, 127, -128, 127)
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_windowing((0,20,320,200))#QVGA find Region Of Interest
#sensor.set_windowing((5,10,160,95))#QQVGA find Region Of Interest
sensor.skip_frames(10)
sensor.set_auto_whitebal(False)#白平衡增益关闭
clock = time.clock()

uart = UART(3, 115200)
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 detect(max_blob):#输入的是寻找到色块中的最大色块
    #print(max_blob.solidity())
    shape=0
    if max_blob.solidity()>0.90 or max_blob.density()>0.84:
        img.draw_rectangle(max_blob.rect(),color=(255,255,255))
        shape=1

    elif max_blob.density()>0.6:
        img.draw_circle((max_blob.cx(), max_blob.cy(),int((max_blob.w()+max_blob.h())/4)))
        shape=2

    elif max_blob.density()>0.4:
        img.draw_rectangle(max_blob.rect(),color=(0,0,0))
        shape=3

    return shape

while(True):
    #clock.tick()
    img = sensor.snapshot() # Take a picture and return the image.
    blobs_white = img.find_blobs([white_threshold])

    if blobs_white:
        max_blob_white=find_max(blobs_white)
        shape_white=detect(max_blob_white)
        #img.draw_rectangle(max_blob_blue.rect(),color=(0,0,255))
        img.draw_cross(max_blob_white.cx(), max_blob_white.cy(),color=(0,0,255))
        output_str_white="[%d,%d]" % (max_blob_white.cx()-160,max_blob_white.cy()-100) #方式1
        img_data=bytearray([0x2C,7,4,max_blob_white.cx()-160,max_blob_white.cy()-100,1,0X5B]) # 数据倒数前三位可发送成功
        uart.write(img_data)
        print('white:',output_str_white)
    else:
        print('not found white !')


   # uart.write(output_str_green + output_str_red + output_str_blue + output_str_brown + output_str_yellow + '\r\n')

    #print(clock.fps())

上面代码中如果需要引用,最主要的是串口的配置和发送部分,串口配置就一句话,串口的发送是两句话,包括下面这两句:

其中0X2C是帧头,0X5B是帧尾。中间夹的就是数据。目前调用的是第三和第四位数据,STM32那边对应的是第二和第三位。

        img_data=bytearray([0x2C,7,4,max_blob_white.cx()-160,max_blob_white.cy()-100,1,0X5B]) # 数据倒数前三位可发送成功
        uart.write(img_data)

根据自己的需要完成OPENMV端的配置后就可跳转到STM32端的配置

1.2 openmv鱼眼镜头画面异常修正

       openmv鱼眼镜头呈现的画面存在曲面,需要在while中添加一个函数进行修正

    img.lens_corr(strength=1.8, zoom=1.0)

这是修正后的运行代码,与上面的原版代码不同,此代码是识别绿色物体,且识别的物体未发生移动时,不会发送新坐标,防止stm32持续接受信号,提高运行的稳定性。

import sensor, image, time
from pyb import UART
import json

#output_str_green="[0,0]"
output_str_white="[0,0]"

# 初始化上一次的坐标
last_cx = 0
last_cy = 0

#green_threshold  = (   0,   80,  -70,   -10,   -0,   30)
#使用的白色测试阈值
white_threshold  =(   0,   80,  -70,   -10,   -0,   30)
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_windowing((0,20,300,220))#QVGA find Region Of Interest
#sensor.set_windowing((5,10,160,95))#QQVGA find Region Of Interest
sensor.skip_frames(10)
sensor.set_auto_whitebal(False)#白平衡增益关闭
clock = time.clock()

uart = UART(3, 115200)
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 detect(max_blob):#输入的是寻找到色块中的最大色块
    #print(max_blob.solidity())
    shape=0
    if max_blob.solidity()>0.90 or max_blob.density()>0.84:
        img.draw_rectangle(max_blob.rect(),color=(255,255,255))
        shape=1

    elif max_blob.density()>0.6:
        img.draw_circle((max_blob.cx(), max_blob.cy(),int((max_blob.w()+max_blob.h())/4)))
        shape=2

    elif max_blob.density()>0.4:
        img.draw_rectangle(max_blob.rect(),color=(0,0,0))
        shape=3

    return shape

while(True):
    #clock.tick()
    img = sensor.snapshot() # Take a picture and return the image.
    img.lens_corr(strength=1.8, zoom=1.0)
    #img=img.rotation_corr(16)#旋转90度
    blobs_white = img.find_blobs([white_threshold])

    if blobs_white:
        max_blob_white=find_max(blobs_white)
        shape_white=detect(max_blob_white)
        #img.draw_rectangle(max_blob_blue.rect(),color=(0,0,255))
        img.draw_cross(max_blob_white.cx(), max_blob_white.cy(),color=(0,0,255))
        # 计算当前坐标
        # 获取当前坐标
        current_cx = int(max_blob_white.cx())
        current_cy = int(max_blob_white.cy())
        # 与上一次坐标进行比较
        # 新增条件判断,如果坐标超出指定范围,则不更新坐标,不输出
        if current_cx > 250 or current_cy > 170:
            print('坐标超出范围,不输出:', current_cx, current_cy)
        else:    
            if abs(current_cx - last_cx) < 4 and abs(current_cy - last_cy) < 4:
                   # 如果变化小于4,保持上一次的坐标
             current_cx, current_cy = last_cx, last_cy
            else:
                   # 更新坐标并输出
                last_cx, last_cy = current_cx, current_cy
                output_str_white = "[{0},{1}]".format(current_cx, current_cy)
                img_data = bytearray([0x2C, 7, 4, current_cx, current_cy, 1, 0X5B])
                uart.write(img_data)
                print('white:', output_str_white)
    else:
        print('not found white !')
    

2.STM32F103C8T6端配置

     system文件中应包含有sys,usart,delay三个基本文件才能进行后续运行。其中uart需要进行一定的修改。

     下面是相关的库文件代码:

    如果无法移植可直接使用百度网盘下载:链接:  https://pan.baidu.com/s/1PvGVYfdQrutwHfJiNS3TJQ 
提取码:fafu

麻烦大家给个关注

usart.c文件:

#include "sys.h"
#include "usart.h"	
#include "openmv.h"
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h"					//ucos 使用	  
#endif
	  
 
 
//
//加入以下代码,支持printf函数,而不需要选择use MicroLIB	  
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 
}; 
 
FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{ 	
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
	USART1->DR = (u8) ch;      
	return ch;
}
#endif
 
#if EN_USART1_RX   //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   	
u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
u16 USART_RX_STA=0;       //接收状态标记	
 
//初始化IO 串口1 
void uart_init(u32 bound){
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);	//使能USART1,GPIOA时钟以及复用功能时钟
     //USART1_TX   PA.9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);
   
    //USART1_RX	  PA.10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);  

   //Usart1 NVIC 配置

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
   //USART 初始化设置

	USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
	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); //初始化串口
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
    USART_Cmd(USART1, ENABLE);                    //使能串口 
		printf("usart1_init_success\r\n");
}

 
 
void USART1_IRQHandler(void)                	//串口1中断服务程序
{
	u8 Res;
#if SYSTEM_SUPPORT_OS 		//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntEnter();    
#endif
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
	{
		Res =USART_ReceiveData(USART1);//(USART1->DR);	//读取接收到的数据
		Openmv_Receive_Data(Res);
		Openmv_Data();
		if((USART_RX_STA&0x8000)==0)//接收未完成
		{
			if(USART_RX_STA&0x4000)//接收到了0x0d
			{
				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
				else USART_RX_STA|=0x8000;	//接收完成了 
			}
			else //还没收到0X0D
			{	
				if(Res==0x0d)USART_RX_STA|=0x4000;
				else
				{
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
					USART_RX_STA++;
					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
				}		 
			}
		}   		 
  } 
#if SYSTEM_SUPPORT_OS 	//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntExit();  											 
#endif
} 
#endif	
 
 
 
 
 

usart.h

#ifndef __USART_H
#define __USART_H
#include "stdio.h"	
#include "stm32f10x.h"
#include "sys.h" 
#define USART_REC_LEN  			200  	//定义最大接收字节数 200
#define EN_USART1_RX 			1		//使能(1)/禁止(0)串口1接收
	  	
extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART_RX_STA;         		//接收状态标记	
//如果想串口中断接收,请不要注释以下宏定义
void uart_init(u32 bound);
#endif

openmv.c

#include "openmv.h"
#include "usart.h"
int openmv[7];//stm32接收数据数组
int16_t data1;
int16_t data2;
int16_t data3;
int16_t data4;
 
 
int i=0;
 
void Openmv_Receive_Data(int16_t data)//接收Openmv传过来的数据
{
	static u8 state = 0;
	if(state==0&&data==0x2C)
	{
		state=1;
		openmv[0]=data;
	}
	else if(state==1&&data==7)
	{
		state=2;
		openmv[1]=data;
	}
	else if(state==2)
	{
		state=3;
		openmv[2]=data;
	}
	else if(state==3)
	{
		state = 4;
		openmv[3]=data;
	}
	else if(state==4)
	{
        state = 5;
        openmv[4]=data;
	}
	else if(state==5)
	{
        state = 6;
        openmv[5]=data;
	}
	else if(state==6)		//检测是否接受到结束标志
	{
        if(data == 0x5B)
        {
            state = 0;
            openmv[6]=data;
            Openmv_Data();
        }
        else if(data != 0x5B)
        {
            state = 0;
            for(i=0;i<7;i++)
            {
                openmv[i]=0x00;
            }           
        }
	}    
	else
		{
			state = 0;
            for(i=0;i<7;i++)
            {
                openmv[i]=0x00;
            }
		}
}
 
void Openmv_Data(void)
{
    data1=openmv[0];
    data2=openmv[3];
    data3=openmv[4];
    data4=openmv[5];
 
}
 

openmv.h
 

#ifndef  __OPENMV_H
#define  __OPENMV_H
#include "sys.h"
extern int openmv[7];//stm32接收数据数组
extern int16_t data1;
extern int16_t data2;
extern int16_t data3;
extern int16_t data4;
 
void Openmv_Receive_Data(int16_t data);
void Openmv_Data(void);
#endif

最后是main.c

#include "stm32f10x.h"
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "oled.h"
#include "openmv.h"
 
extern int openmv[7];//stm32接收数据数组
extern int16_t data1;
extern int16_t data2;
extern int16_t data3;
extern int16_t data4;
int16_t data;
int main(void)
{ 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	delay_init();      //初始化延时函数
	uart_init(115200);		//初始化串口波特率为115200
	LED_Init();					  //初始化LED
 	OLED_Init();           //初始化LCD FSMC接口		 	
  while(1) 
	{	

		OLED_ShowString(1,1,"CX:");
     	OLED_ShowNum(1, 5, data2, 3);
		OLED_ShowString(2,1,"CY:");
	 	OLED_ShowNum(2, 5, data3, 3);
		delay_ms(150);
	} 
}

将上述库文件和主函数配置完成后,按照下面的接线方式进行接线即可完成串口通讯。

 STM32 PA9--P5 OPENMV
 STM32 PA10-P4 OPENMV 
 STM32 GND-GND OPENMV
 OLED SCL-PB8
 OLED SDA-PB9

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐