-
2021-11-29 19:48:12
已经在研一度过快3个月了,研究生学习跟本科学习还是有很大区别的,要善于自己找资料善于自己总结,因此我也决定从现在开始时不时的写写博客总结后面每段时间遇到的各种困难以及解决方法,为以后工作积累经验也方便以后查阅。
这是我第一篇博客,之前都是在做关于树莓派和opencv的项目,前段时间老师也是给了我一个新项目的思路,也是要基于视觉处理的,但因为21年电赛刚过有些学弟在比赛时都用到了openmv,所以我也想试试用openmv来处理处理手上这个项目,也顺便重新认识认识老朋友stm32。
言归正传,基于openmv的图像处理可以说是非常简单的,官方给了各种库,但凡好好看看例子都能会用,但是openmv的引脚太少了以至于能实现的功能太单一,所以这时候openmv也就只能作为传感器,大多数功能还得靠stm32,既然openmv作为传感器,所以openmv与stm32之间必须实现通信,方式很多很多,我选择了最基础的串口通信。
虽然本科也干了不少STM32与各类传感器的通信,但这次依碰到一些小麻烦,在网上查了不少资料,但怎么说了要么就是给的代码不全不知道上下的联系,要么就是单纯在那讲STM32的串口通信跟题目根本不搭噶。
废话少说,直接边上代码边总结。(之前记得将openmv的P4接到stm32的PA10,P5接到PA9)
关于openmv的代码:
# Blob Detection and uart transport import sensor, image, time,math from pyb import UART import json # For color tracking to work really well you should ideally be in a very, very, # very, controlled enviroment where the lighting is constant... yellow_threshold = (65, 100, -10, 6, 24, 51) # You may need to tweak the above settings for tracking green things... # Select an area in the Framebuffer to copy the color settings. 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) 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 while(True): img = sensor.snapshot() # Take a picture and return the image. blobs = img.find_blobs([yellow_threshold]) img_data=bytearray([0x2C,7,1,2,3,4,0X5B]) uart.write(img_data)
这段代码原型是官方的寻找最大色块的代码,只是拿来简单做一下串口传输数据,因此删掉很多,核心成分在最后两行,其中要注意的是,用到了bytearry(),所以在开头要import math,其中第0位为开始标志,最后一位为结束标志,第1位为总位数7,其他为要传输的数据。
关于stm32的代码:
(1)usart.c
#include "sys.h" #include "usart.h" #include "openmv.h" #include "lcd.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 //bound:波特率 void uart_init(u32 bound){ //GPIO端口设置 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟 //串口1对应引脚复用映射 GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9复用为USART1 GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1 //USART1端口配置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉 GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10 //USART1 初始化设置 USART_InitStructure.USART_BaudRate = bound;//波特率设置 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_Cmd(USART1, ENABLE); //使能串口1 //USART_ClearFlag(USART1, USART_FLAG_TC); #if EN_USART1_RX USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断 //Usart1 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、 #endif } 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
(2)usart.h
#ifndef __USART_H #define __USART_H #include "stdio.h" #include "stm32f4xx_conf.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
采用的是官方已经包含的串口代码,但凡用过stm32的都有这段代码,只是在Res =USART_ReceiveData(USART1)后面增加了两行关于openmv的函数。
(3)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]; }
(4)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);
(5)main.c
#include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "lcd.h" #include "openmv.h" int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2 delay_init(168); //初始化延时函数 uart_init(115200); //初始化串口波特率为115200 LED_Init(); //初始化LED LCD_Init(); //初始化LCD FSMC接口 POINT_COLOR=RED; //画笔颜色:红色 while(1) { LCD_ShowNum(0,20,200,10,24); LCD_ShowNum(0,40,data1,10,24); } }
其中openmv[7]中的7与openmv代码中的bytearry()的总位数相同。
然后下载代码,可以在lcd显示屏上看到结果(lcd显示屏代码就不贴了,官方资料很详细)。
更多相关内容 -
Openmv与STM32通信.zip
2020-05-09 10:28:53该文件包括三部分,一个是openmv的官方云台三维模型,可直接打印,一个是openmv的程序,该程序可同时识别三个颜色,本程序中同时识别了红绿蓝,识别后返回颜色顺序,通过串口通信给stm32主控,并在LCD屏幕上显示识别... -
openmv与stm32通信,openmv与stm32通信传输数据卡顿,C,C++源码.zip
2021-10-15 00:59:17openmv与stm32通信,openmv与stm32通信传输数据卡顿,C,C++源码 -
超详细OpenMV与STM32单片机通信 (有完整版源码)
2021-05-04 01:56:49最近在做电磁炮,发现题目需要用到颜色跟踪,于是花了一点时间学了一下OpenMV,只学习OpenMV是远远不够的,还需要实现与单片机的通信,本以为很简单,在CSDN上找了一些代码,直接拿来修改粘贴,把代码看明白了,这些...目录标题
1.前言(闲话)
最近在做电磁炮,发现题目需要用到颜色跟踪,于是花了一点时间学了一下OpenMV,只学习OpenMV是远远不够的,还需要实现与单片机的通信,本以为很简单,在CSDN上找了一些代码,直接拿来修改粘贴,把代码看明白了,这些只花了几个小时,本以为自己已经弄明白了二者之间的通信,但是在后期把OpenMV端数据传输到单片机的时候却犯了难。我选择使用OLED显示传输的数据,在这里调试了许久,中间遇到了许多之前的学习漏洞,特在此写下博客记录学习经历。*
2.硬件连接
我所用到的材料如下: 四针IIC OLED,OpenMV(OV7725),STM32F103C8T6最小系统板,数据线N条(OpenMV的数据线只能用官方自带的,其他的基本都用不了),杜邦线若干。
1.OpenMV端:由图知UART_RX—P5 ------ UART_TX—P4
2.STM32端:USART_TX—PA9 -----USART_RX—PA10
3.四针OLED IIC连接:SDA—PA2-----SCL—PA1 由于使用的是模拟IIC而不是硬件IIC,可以根据个人需要修改IO口来控制SDA线和SCL线,只需要简单修改一下代码即可。
4.STM32的TX(RX)接OpenMV的RX(TX),OLED连接到STM32即可。
3.软件代码———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]) cx=0;cy=0; if blobs: max_b = find_max(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)
bytearray([, , ,])组合uart.write()的作用与直接调用sending_data(cx,cy,cw,ch)作用是一样的
4.软件代码———STM32端
工程总共包含如下文件:main.c、iic.c、iic.h、oled.c、oled.h、uart.c、uart.h。由于OLED的代码存在版权问题,需要的可以邮箱私发。
/***** oled.h *****/
#ifndef __USART_H #define __USART_H #include "sys.h" void USART1_Init(void);//串口1初始化并启动 #endif
/***** oled.c *****/
#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 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发送数据包给STM32,STM32利用中断接收数据并把数据存放在RxBuffer1这个数组里,并且在中断中利用OLED显示cx,cy,cw,ch四个坐标。在中断中,有如下函数:
else if(RxState==2) { RxBuffer1[RxCounter1++]=com_data; if(RxCounter1>=10||com_data == 0x5B) //RxBuffer1接受满了,接收数据结束 { RxState=3; RxFlag1=1; Cx=RxBuffer1[RxCounter-5]; Cy=RxBuffer1[RxCounter-4]; Cw=RxBuffer1[RxCounter-3]; Ch=RxBuffer1[RxCounter1-2]; } }
RxBuffer1是一个装有接收OpenMV数据的数组,RxCounter1起着一个计数器的作用,当RxBuffer[RxCounter1-1]存放的数据为数据包的帧位时,说明已经接收成功整个数据包,此时RxBuffer[RxCounter1-2]存放ch坐标值,RxBuffer[RxCounter1-3]存放cw坐标值,RxBuffer[RxCounter1-4]存放cy坐标值,RxBuffer[RxCounter1-5]存放cx坐标值,此后在RxState=3过程中将这四个坐标显示出来即可。
特别注意的是:STM32中断每发生一次,只会接收到一字节的数据,因此,进行七次才会接收完一整帧的数据包,这一点需要读者仔细揣摩,结合上文中说的静态变量关键字static,定义了:u8 com_data; u8 i; static u8 RxCounter1=0; static u8 RxBuffer1[10]={0}; static u8 RxState = 0; static u8 RxFlag1 = 0;
请读者仔细揣摩为什么com_data(端口接收到的数据)、i定义的是动态的(auto),而RxBuffer1(装接收到数据的静态全局数组)、RxState(状态标志变量)、RxFlag1(接受结束标志变量)定义的确实静态的,这一点并不难理解。
5.利用PC端测试数据数据是否发送接收正常
在进行OpenMV与STM32的通信测试过程中,我使用了USB转TTL模块,将OpenMV(或STM32单片机)与PC端进行通信确保数据发出或者接收正常。
OpenMV&&PC
OpenMV_RX接模块TX
OpenMV_TX接模块RX
OpenMV_GND接模块GND
然后打开OpenMV,在大循环while(True)中使用语句:DATA=bytearray[(1,2,3,4,5)] uart.write(DATA)
打开PC端串口助手,注意设置一样的波特率、停止位、发送字节数等,查看串口助手是否接受到了数据。
STM32&&PC
STM32_RX接模块TX
STM32_TX接模块RX
STM32_GND接模块GND
注意:不管是STM32与PC还是OpenMV与PC还是STM32与OpenMV通信,都要将二者的GND连接在一起。
在main.c中先调用stdio头文件,大循环中使用如下语句:while(1) { printf("HelloWorld!"); }
打开串口助手查看是否接收到了数据。
6.学习补充 (代码看不懂的时候可以来看一下)
补充1:static关键字(静态变量)的使用
static 修饰全局函数和全局变量,只能在本源文件使用。举个例子,比如用以下语句
static u8 RxBuffer[10]
定义了一个名为RxBuffer的静态数组,数组元素类型为unsigned char型。在包含Rxbuffer的源文件中,Rxbuffer相当于一个全局变量,任意地方修改RxBuffer的值,RxBuffer都会随之改变。而且包含RxBuffer的函数在多次运行后RxBuffer的值会一直保存(除非重新赋值)。在C语言学习中,利用static关键字求阶乘是一个很好的例子:#include“stdio.h” long fun(int n); void main() { int i,n; printf("input the value of n:"); scanf("%d",&n); for(i=1;i<=n;i++) { printf("%d! = %1d\n",i,fun(i)); } } >long fun(int n) { static long p=1; p=p*n; return p; }
效果为依次输出n!(n=1,2,3…n)
这个例子中,第一次p的值为1,第二次p的值变成了p x n=1 x 2=2,这个值会一直保存,如果p没有定义为静态类型,那么在第一次运算过后p的值会重新被赋值为1,这就是auto型(不声明默认为auto型)与static型的最大区别。总结:static关键字定义的变量是全局变量,在static所包含的函数多次运行时,该变量不会被多次初始化,只会初始化一次。
补充2:extern关键字(外部变量)的使用
程序的编译单位是源程序文件,一个源文件可以包含一个或若干个函数。在函数内定义的变量是局部变量,而在函数之外定义的变量则称为外部变量,外部变量也就是我们所讲的全局变量。它的存储方式为静态存储,其生存周期为整个程序的生存周期。全局变量可以为本文件中的其他函数所共用,它的有效范围为从定义变量的位置开始到本源文件结束。
如果整个工程由多个源文件组成,在一个源文件中想引用另外一个源文件中已经定义的外部变量,同样只需在引用变量的文件中用 extern 关键字加以声明即可。下面就来看一个多文件的示例:/****max.c****/ #include <stdio.h> /*外部变量声明*/ extern int g_X ; extern int g_Y ; int max() { return (g_X > g_Y ? g_X : g_Y); } /***main.c****/ #include <stdio.h> /*定义两个全局变量*/ int g_X=10; int g_Y=20; int max(); int main(void) { int result; result = max(); printf("the max value is %d\n",result); return 0; } 运行结果为: the max value is 20
对于多个文件的工程,都可以采用上面这种方法来操作。对于模块化的程序文件,可在其文件中预先留好外部变量的接口,也就是只采用 extern 声明变量,而不定义变量,max.c 文件中的 g_X 与 g_Y 就是如此操作的。比如想要在主函数中调用usart.c中的变量x,usart.c中有着这样的定义:
static u8 x=0
在usart.h中可以这样写:extern u8 x
在main.c中包含usart.h头文件,这样在编译的时候就会在main.c中调用x外部变量。总结:extern关键字是外部变量,静态类型的全局变量,可以在源文件中调用其他文件中的变量,在多文件工程中配合头文件使用。
补充3:MicroPython一些库函数的解释
1.ustruct.pack函数:
import ustruct,在ustruct中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)
""bbhhhhb"简单来说就是要发送数据的声明,bbhhhhb共七个,代表发送七个数据,对照下面的表,可以知道七个数据按时序发送为unsigner char、unsigned char、short、short、short、short、unsigned char。0x2c为数据帧的帧头,即检测到数据流的开始,但是一个帧头可能会出现偶然性,因此设置两个帧头0x2c与0x12以便在中断中检测是否检测到了帧头以便存放有用数据。0x5b为帧尾,即数据帧结束的标志。
2.bytearray([ , , , ])函数:
用于把十六进制数据以字节形式存放到字节数组中,以便以数据帧的形式发送出去进行通信。FH = bytearray([0x2C,0x12,cx,cy,cw,ch,0x5B]) uart,write(FH)
7.效果展示(可以先来看效果)
从上到下依次为CX,CY,CW,CH
8.博客更新
1.有朋友反馈OpenMv端找不到色块就会报错,解决方案如下:
while(True): clock.tick() img = sensor.snapshot() blobs = img.find_blobs([red_threshold_01]) cx=0;cy=0; if blobs: max_b = find_max(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)
在以上代码中,将max_b = find_max(blobs) 移到if blobs外即可。
2.有朋友反馈OpenMV发送数据只能发送一个字节,也就是说大于255的数据无法直接通过代码完成,现在提供以下解决方案:在STM32端代码中依次保存大于255数字的高八位和低八位最后在组合在一起即可。
2021/9/15更新 4字节与浮点数之间的转换(参考)#if 1 int main() { #if 0 //字符型数据分成四个字节存放在数组中 float m = 23.25; unsigned char *a; a = (unsigned char *)&m; printf("0x%x \n0x%x \n0x%x \n0x%x \n",a[0],a[1],a[2],a[3]); #endif #if 1 //四个字节数据合成存放在数组中 unsigned char a[]={0x00,0x00,0xba,0x41}; float BYTE; BYTE = *(float *)&a; printf("%f\n",BYTE); #endif } #endif
上述代码实现了将四个字节转换为一个浮点数的功能,同时也实现了将一个浮点数拆分为四个字节功能。在Openmv传数据时,只能传输一个字节,大于255的数无法以一字节形式发送,因此可以在Openmv端将该数据拆分成两个字节,分别发送给Stm32端,同时Stm32端对传来的数据进行合成,合成并解析为对应的数据。
另一种解决方案:python传数据的1/2,单片机在乘2即可。
9.参考链接
[1]extern外部变量参考链接
[2]星瞳科技OpenMV中文参考手册官方
[3]MicroPython函数库
10.完整版代码链接
最新博客:《陀螺仪MPU6050模块输出姿态角》
最新博客:《HC-SR04超声波测距模块》
欢迎大家浏览支持!
-
使用openMV3与stm32进行通讯
2019-04-21 22:56:44使用openMV3与stm32进行通讯,想用openMV与stm32通讯,在网上找了一大圈,最后决定使用串口,参照这篇文章https://blog.csdn.net/qq_43243338/article/details/89441756 -
OpenMv和STM32通信
2021-06-07 11:33:33OpenMv和STM32通信问题OpenMv和STM32通信前言一、OpenMv配置二、Stm32配置总结 前言 最近一段时间都在捣鼓OpenMV和Stm32的通信问题,刚开始不知道哪里出了问题,一直通信失败,明明使用TTL串口接收OpenMv发送的数据...OpenMv和STM32通信
OpenMv和STM32通信问题
前言
最近一段时间都在捣鼓OpenMV和Stm32的通信问题,刚开始不知道哪里出了问题,一直通信失败,明明使用TTL串口接收OpenMv发送的数据是可以在串口调试助手上显示的,但就是无法发给Stm32的USART串口。经过了差不多一周的时间,终于解决了。于是在这里记录学习记录。
一、OpenMv配置
1.第一种发送方法
OpenMv代码如下
# Untitled - By: 86188 - 周二 5月 25 2021 import sensor, image, time,pyb from pyb import UART,LED import json import ustruct #white_threshold_01 = ((95, 100, -18, 3, -8, 4)); #白色阈值 red_threshold_01 = ((2, 51, 11, 127, -128, 127)) #红色阈值 LED_R = pyb.LED(1) # Red LED = 1, Green LED = 2, Blue LED = 3, IR LEDs = 4. LED_G = pyb.LED(2) LED_B = pyb.LED(3) LED_R.on() LED_G.on() LED_B.on() 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 clock = time.clock() LED_R.off() LED_G.off() LED_B.off() 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 send_data_packet(x,y,z,w): temp = ustruct.pack("<bbhhhh", #格式为俩个字符俩个整型 0x2C, #帧头1 0x12, #帧头2 int(x), # up sample by 2 #数据1 int(y), # up sample by 2 #数据2 int(z), int(w)) #0x5B) uart.write(temp); #串口发送 while(True): img = sensor.snapshot() #time.sleep_ms(1000) #send_data_packet(x,y) blobs = img.find_blobs([red_threshold_01]); cx=0;cy=0; if blobs: #如果找到了目标颜色 max_b = find_max(blobs); # Draw a rect around the blob. img.draw_rectangle(max_b[0:4]) # rect #用矩形标记出目标颜色区域 img.draw_cross(max_b[5], max_b[6]) # cx, cy #img.draw_cross(160, 120) # 在中心点画标记 #在目标颜色区域的中心画十字形标记 cx=max_b[5]; cy=max_b[6]; cw=max_b[2]; ch=max_b[3]; #data = bytearray([x,y]) send_data_packet(cx,cy,cw,ch) #time.sleep_ms(1000)
代码作用:OpenMv使用的是python语言编写,而这段代码的主要目的就是在openmv视野种寻找红色色块,并将其中点坐标发送会Stm32,并在OLED屏幕上显示。
主要通信函数如下
def send_data_packet(x,y,z,w): temp = ustruct.pack("<bbhhhh", #格式为俩个字符俩个整型 0x2C, #帧头1 0x12, #帧头2 int(x), # up sample by 2 #数据1 int(y), # up sample by 2 #数据2 int(z), int(w)) #0x5B) uart.write(temp); #串口发送
这里使用了数据包的形式发送数据,将一帧的数据包装,并发送给Stm32,此数据包中的包头非常重要,也就是0x2C以及0x12,这两个数据便与Stm32接收中断中进行判断,以确保数据的正确性。
对于数据包格式,此等的使用规划:#pack各字母对应类型 #x pad byte no value 1 #c char string of length 1 1 #b signed char integer 1 #B unsigned char integer 1 #? _Bool bool 1 #h short integer 2 #H unsigned short integer 2 #i int integer 4 #I unsigned int integer or long 4 #l long integer 4 #L unsigned long long 4 #q long long long 8 #Q unsilong long long 8 #f float float 4 #d double float 8 #s char[] string 1 #p char[] string 1 #P void * long
对于此处我所使用的"<bbhhhh",
第一个第二个数据为包头,便是b,字符串类型。而后面开始为数据格式,我选择的是h也就是短整型,传输给Stm32的时候,便是两个字节的数据格式。
如图,一串完整的数据便是 2C 12 36 00 80 00 2E 00 9D 00。
2.第二种发送方法
除了以上这种以包(pack)的方式发送给stm32外,还可以使用另外的一种方法发送:
def send_data(cx,cy,w,h): datalist = [ 0x2C,0x12,cx,cy,w,h] datalist.append(sum_checkout(datalist)) data = bytearray(datalist) return data #检验数据和 def sum_checkout(data_list): data_sum = 0 for temp in data_list: data_sum = data_sum + temp return data_sum
这段代码和之前不同的是:我将0x5B 最后一位的数据校验位改成了用sum_checkout() 这段函数求和取余的方法作为该数据的数据校验位。
但是使用这样不封包的方法发送,就必须加上data = bytearray(datalist),将数据转化,才可以进行通讯。二、Stm32配置
Stm32的USART1配置如下:
u16 USART_RX_STA=0; //接收状态标记 void uart1_init(u32 bound){ //GPIO端口设置 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟 //USART1_TX GPIOA.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);//初始化GPIOA.9 //USART1_RX GPIOA.10初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10 //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;//串口波特率 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 }
相比于平常配置并未存在较大差别,而实现通信的重要步骤是在USART1的串口接收中断中。
void USART1_IRQHandler(void) { u8 Res; static u8 Rebuf[20]={0}; static u8 i = 0; if( USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET ) { Rebuf[i++] = USART_ReceiveData(USART1); if(Rebuf[0] != 0x2c) i = 0; if((i==2)&&Rebuf[1] != 0x12) i = 0; if(i>=10) { memcpy(OpenMV_Rx_BUF,Rebuf,i); i = 0; } USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除中断标志 } }
其中定义了一个OpenMV_Rx_BUF[20]的数组来接收openmv发送过来的数据,需要使用extern修饰这个变量,以便于事项后续操作。
同时memcpy()函数也是十分重要的一个内置函数,可以实现两个数组的拷贝任务。主函数的代码如下:
int main(void) { delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart1_init(115200); //串口初始化为115200 LED_Init(); //LED端口初始化 OLED_Init(); while(1) { LED0=!LED0; delay_ms(200); OLED_Refresh_Gram(); OLED_ShowNumber(0,20,OpenMV_Rx_BUF[2],3,12); OLED_ShowNumber(20,20,OpenMV_Rx_BUF[4],3,12); OLED_ShowNumber(40,20,OpenMV_Rx_BUF[6],3,12); OLED_ShowNumber(60,20,OpenMV_Rx_BUF[8],3,12); } }
前面就提到了,由于我数据包的格式设置问题,存入OpenMV_Rx_BUF[] 数组中的数据,真正有效的是第3、5、7、9位(因为选择了h类型数据格式,一个数据占2位)。
总结
博主我之前数据一直发送失败的原因是,博主使用了 uart.write() 这个函数,企图通过 uart.write() 这个函数实现数据发送。
这个函数在实现OpenMv和PC端的通信上没有问题,可以将数据打在串口调试助手上,但在其与Stm32的通信问题上就存在问题。
若要使用 uart.write() 实现与stm32的通信,便要使用bytearray()函数将其转化,才可以进行通信。FH = bytearray([0x2C,0x12]) uart.write(FH)
-
USART_OpenMV_STM32F407双向通信.zip
2021-11-11 16:52:091.OpenMV-H7 通过uart3 发送一帧数据到stm32f407usart1中 数据buf=[0xaa,0xaa,0x20,0x65,0x88,0x5d,0x6d] {0xaa,0xaa帧头} 2.stm32F407 串口1收到数据 点亮LED1并发送应答信号 Buf1[7]={0xaa,0xaa,0x20,0x01,0x01,... -
【stm32程序】stm32f103与OpenMV通信
2020-05-17 22:04:03基于stm32f103的于openmv的通信程序。 -
STM32与OpenMV串口通信实现
2022-02-06 15:31:351. STM32调用OpenMV_Send()、OpenMV_Recv()函数即可实现收发。 2. OpenMV程序中, 1)buff[0]==0表明STM32调用的OpenMV_Send()函数,1表明STM32调用的OpenMV_Recv()函数。 2)buff[1]为STM32下发的命令,可根据... -
2021-07-29 Openmv与stm32 的串口通信(HAL库)
2021-07-29 13:56:45Openmv与stm32 的串口通信 前言 假期准备参加电赛,学习了openmv,openmv识别到的数据传到STM32,然后进行下一步的处理,为了实现来着之间的通信,花了很长时间,终于实现了,现在想想好像也挺简单的,哈哈哈哈,...Openmv与stm32 的串口通信
前言
假期准备参加电赛,学习了openmv,openmv识别到的数据传到STM32,然后进行下一步的处理,为了实现来着之间的通信,花了很长时间,终于实现了,现在想想好像也挺简单的,哈哈哈哈,但是对于我这种小白还是有点难,大佬就不用看啦!!
防止以后忘记,来CSDN做一个笔记吧!!openmv端
在openmv端主要的工作是对目标物体进行识别,然后将需要的数据通过打包,再使用串口发送个单片机。这里有几个关键的地方:
数据打包的格式:
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); #必须要传入一个字节数组
打包的方式如上图所示,为了防止数据错误,需要加入两个数据帧头和一个 数据帧尾。openmv传输的数据的形式
openmv只能传输十六进制的数据给STM32,否则STM32将收不到数据,结果就是单片机和openmv都能正常和电脑通信,但是两者结合就不能正常通信
十六进制数据的实现主要通过 bytearray ()这个函数,具体的格式如下:OUT_DATA =bytearray([0x2C,0x12,cx,cy,cw,ch,0x5B])
在openmv段主要的问题就是这两个地方,区域的串口的配置,以及数据发送数都是常规的,openmv还有一种数据格式,就是json字符串,都是我还没试过,以后再补上。openmv端完整的源代码
from pyb import UART,LED import json,ustruct,sensor,time red_threshold = (2, 12, -56, 2, -75, 14)#测试所用,白色,懒得该名称 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) img.draw_rectangle(max_blob.rect()) # rect img.draw_cross(max_blob.cx(), max_blob.cy()) # cx, cy cx=max_blob[5] cy=max_blob[6] cw=max_blob[2] ch=max_blob[3] OUT_DATA =bytearray([0x2C,0x12,cx,cy,cw,ch,0x5B]) uart.write(OUT_DATA) print(OUT_DATA)
STM32 端
说到STM32 端真的是让我走了很多的弯路,就因为printf()重定向,刚开始用的方式有点问题,让我花了很多很多时间,导致串口调试助手一直收不到消息,还以为是板子坏了,最后发现是重定向的问题,这是两种方式:
经过验证后的正确方式:
# include "stdio.h" int fputc(int ch ,FILE *f) { //轮询方式发送一个字节数据 HAL_UART_Transmit (&huart1 ,(uint8_t *)&ch , 1,HAL_MAX_DELAY ); return ch ; }
关键点:
串口接收中断 回调函数:
/*串口接收中断回调函数*/ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { uint16_t tempt /*定义临时变量存放接受的数据*/; if(huart->Instance==USART2) { tempt=USART2_RXbuff; Openmv_Receive_Data(tempt); /*调运数据接收处理函数,每次进入中断都对数据进行理处 ,由于需要接收器个数据,因此要进入七次断理*/ } HAL_UART_Receive_IT(&huart2,(void *)&USART2_RXbuff,1);/*再次开启接收中断*/ }
最后的重新开启中断接收一定不能忘记;
数据读取的函数
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; /*对数据进行校准,判断是否为有效数据*/ 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帧头 { HAL_GPIO_WritePin(LED_GPIO_Port, LED_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; 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); } } 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; //将存放数据数组清零 } } }
openmv.h
#ifndef __OpenMV_H #define __OpenMV_H #include "stm32f1xx.h" void Openmv_Receive_Data(int16_t data); #endif
主函数里面没什么太多的内容,主要是开启中断接收,以及一些变量的定义
/* USER CODE BEGIN 2 */ HAL_UART_Receive_IT(&huart2,(void *)&USART2_RXbuff,1); HAL_UART_Receive_IT(&huart1,(void *)&USART1_RXbuff,1); /* USER CODE END 2 */
/* USER CODE BEGIN PV */ uint8_t USART1_RXbuff; // 接收缓冲区; uint8_t USART2_RXbuff; uint8_t ch = 0;
cubemx 配置很简单
最后就是接线的问题啦!!
完成,收工,有问题就私聊吧!!! -
OPENMV和STM32通信
2019-12-28 19:05:50OPENMV端 import sensor, image, time, math from pyb import UART uart = UART(3,38400) sensor.reset() sensor.set_pixformat(sensor.GRAYSCALE) sensor.set_framesize(sensor.VGA) sensor.set_windowing((640, 50... -
openmv与stm32串口通信数据传输
2022-03-28 10:16:35openmv与stm32串口数据传输,遇到棘手问题,疑似stm32无法进入中断。 -
openmv与stm32通信
2021-06-29 19:22:14import serial as ser se = ser.Serial('/dev/ttyTHS1',9600,timeout=0.5) def send_data_packet(x,y): temp = struct.pack("<bbii", #格式为俩个字符俩个整型 0xAA, #帧头1 0xAE, -
OpenMV&&stm32通信
2020-02-19 01:53:17stm32通信 目录: 1.开篇之言 2.简单介绍 3.主要代码 4.结篇之语 ------------------------------------------------------------------------------------------- 1.开篇之言 (不用看这,都是废话) ……由于新型... -
【嵌入式】openmv与stm32的串口通信
2022-03-13 19:00:47PYTHON串口数据打包发送STM32接收数据解析 openmv中文文档 这里以openmv循迹代码为例 main.py THRESHOLD = (74, 100, -128, 127, -128, 127) # 识别白线 import sensor, image, time from pyb import LED,UART ... -
OpenMv与stm32简单串口通信
2021-10-13 19:57:59刚开始学openmv与32串口通信,我是用的stm32f103的板子。开始想简单发送字符或者16位数试验一下,然后就遇到了个小问题,即openmv和单片机可以分别和电脑通信,但是让他俩通信的话就不行,随后解决在此记录下来。 ... -
OpenMV与STM32单片机串口通信,如何使用openmv连续发送多帧数据给单片机
2019-04-24 10:24:48首先,我使用STM 32单片机有2 年左右的时间了,但是openmv却不足一个月的时间,由于近几天问我关于两者之间如何进行通讯问题的人比较多,所以特地写这样一篇文章进行讲解。如果有什么讲的不对的地方,还请各位读者... -
openmv与stm32之间的通信学习(数字识别)
2021-11-11 09:23:02前提:软件安装与学习视频讲解 在我们使用openmv中的神经网络时,在新的版本里是没有nn的库给你调用的,需要在老版本里才有,百度云链接:https://pan.baidu.com/s/1bgLiLMxyqqL9X3h5dN8cZA提取码:behn (光这个能... -
OPENMV识别色块与STM32F4通过串口通信
2021-08-26 23:24:13OPENMV识别色块与STM32F4通过串口通信 -
stm32F103与openmv结合代码.rar
2020-12-12 00:01:41stm32与open mv通信并配有PID算法控制小车车速,基于uart通信,PID控速。 stm32与open mv通信并配有PID算法控制小车车速,基于uart通信,PID控速。 stm32与open mv通信并配有PID算法控制小车车速,基于uart通信,PID... -
STM32单片机与Openmv的串口通信
2019-03-24 21:43:31openmv与stm32的串口通信简谈闲话Openmv主要代码STM32单片机的配置运行效果图片如下 简谈闲话 这两天本人利用周末时间粗略的学习一下openmv的使用,目的是用openmv图像处理数据并通过串口发送数据给STM32F103的... -
OPENMV-STM32串口通信
2021-10-08 11:27:50OPENMV-STM32串口通信 目录标题OPENMV-STM32串口通信前言硬件选择硬件的通信连接OPENMV软件分析效果展示图 前言 最近要准备工巡赛,突然要发现需要进行视觉传动,所以我最近几天又温顾了一下Openmv,以前学习Openmv都... -
Openmv 与 Stm32f407通信
2020-12-20 12:28:48Openmv 与 Stm32f407通信入门学习记录大概思路代码 入门学习记录 学习中接触到了openmv ,发现视觉也挺好玩的,openmv视觉处理的数据经常要传到另一个单片机,这里openmv用的是stm32h7,用的串口为串口3。控制板是stm... -
openmv和stm32串口通信完成二维码识别
2021-03-21 22:28:25openmv和stm32串口通信完成二维码...openmv4通过串口通信加json与stm32f103完成通信,结果由stm32所连的lcd屏显示 一、所用的硬件: openmv4、正点原子的mini板(stm32f103rct6)、正点原子配套的lcd屏。 示例:panda -
openmv与STM32之间怎样通过IIC通信协议通信
2019-12-04 10:42:47之前用openmv进行颜色识别然后与STM32通过串口通信,但是STM32接收到的图像中心坐标与openmv中的实际坐标有时候会不同。所以想尝试一下openmv与STM32之间到其他通信方式, -
【星曈科技】OpenMv笔记——利用OpenMV与STM32进行串口通信
2021-07-20 10:25:48利用OpenMV与STM32进行串口通信 OpenMV端的程序 # Untitled - By: dell - 周一 7月 19 2021 # Blob Detection and uart transport import sensor, image, time,pyb import ustruct from pyb import UART #import ... -
STM32与OpenMV通信的几点注意【小白级】
2019-04-17 09:25:50状况描述:STM32和OpenMV都能与PC通信,但STM32和OpenMV两者之间无法实现,甚至STM32未进入串口中断函数。 1.接线 STM32 OpenMV RXD TXD TXD RXD GND GND 注意:一定要共地 2.串口初始化的配置 1)... -
OPENMV和STM32的识别追踪小车(详细版)之OPENMV端
2020-02-22 16:01:57OPENMV和STM32的识别追踪小车(详细版) 实现:通过OPENMV识别Apriltags标签,STM32驱动小车追踪标签 博主通过一段时间的学习,做了这个比较简单的以OPENMV为摄像传感器STM32为控制器的寻物小车,不多说,直接进入...