900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 【星曈科技】OpenMv笔记——利用OpenMV与STM32进行串口通信

【星曈科技】OpenMv笔记——利用OpenMV与STM32进行串口通信

时间:2023-02-19 12:41:10

相关推荐

【星曈科技】OpenMv笔记——利用OpenMV与STM32进行串口通信

利用OpenMV与STM32进行串口通信

OpenMV端的程序

# Untitled - By: dell - 周一 7月 19 # Blob Detection and uart transportimport sensor, image, time,pybimport ustructfrom 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 = (25, 79, 2, 39, 26, 69)# You may need to tweak the above settings for tracking green things...# Select an area in the Framebuffer to copy the color settings.led3 = pyb.LED(3) # Red LED = 1, Green LED = 2, Blue LED = 3, IR LEDs = 4.led1 = pyb.LED(1) # Red LED = 1, Green LED = 2, Blue LED = 3, IR LEDs = 4.sensor.reset() # Initialize the camera sensor.sensor.set_pixformat(sensor.RGB565) # use RGB565.sensor.set_framesize(sensor.QVGA) # 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 sending_data(cx,cy):global uart;#frame=[0x2C,18,cx%0xff,int(cx/0xff),cy%0xff,int(cy/0xff),0x5B];#data = bytearray(frame)data = ustruct.pack("<bbhhb",#格式为俩个字符俩个短整型(2字节)0x2C, #帧头10x12, #帧头2int(cx), # up sample by 4 #数据1int(cy), # up sample by 4 #数据20x5B)uart.write(data); #必须要传入一字节的数组,这个函数似乎不能发送单个字节,必须得一次发送多个字节#**************************************************************************while(True):img = sensor.snapshot() # Take a picture and return the image.led1.on()led3.on()#LED指示openmv正在工作blobs = img.find_blobs([yellow_threshold])#寻找符合条件的色块if len(blobs) == 1:#如果只找到一个符合条件的色块#print('sum :', len(blobs))img.draw_rectangle(blobs[0].rect())img.draw_cross(blobs[0].cx(), blobs[0].cy())output_str="[%d,%d]" % (blobs[0].cx(),blobs[0].cy())print('you send:',output_str)sending_data(blobs[0].cx(),blobs[0].cy())#发送色块框的中心点坐标#FH = bytearray([0x2C,0x12,blobs[0].cx(),blobs[0].cy(),0x5B])#uart.write(FH)else:print('not found!')sending_data(567,789)#如果没有找到符合条件的色块,那么发送一个不可能出现的坐标#FH = bytearray([0x2C,0x12,0x77,0x55,0x5B])#uart.write(FH)

由于我们图像大小设置成了QVGA,所以所有可能出现的坐标最大是(320,240),所以x或y最多只需要16bit,也就是两个Bit就可以完全发送出去。

由上图可知,格式为h,就可以表示2Bit,于是我们把数据的打包格式为h。

""bbhhb"就是要发送数据的声明,bbhhb共5个,代表发送5个数据。虽然只有5个数据,却需要发送7个字节,因为1个h就占用两个字节,openmv的发送顺序为:帧头1>帧头2>数据1的低八位>数据1的高八位>数据2的低八位>数据2的高八位。0x2c为数据帧的帧头,即检测到数据流的开始,但是一个帧头可能会出现偶然性,因此设置两个帧头0x2c与0x12以便在中断中检测是否检测到了帧头以便存放有用数据。0x5b为帧尾,即数据帧结束的标志。

下面,先让openmv与电脑通讯,通过串口调试助手看一下数据是否成功发送。

这里注意:openmv需要通过一个USB to TTL模块才能与电脑进行串口通信,openmv的RXD要连接模块的TXD,openmv的TXD要连接模块的RXD,然后再把模块与openmv共地即可。

通讯结果:

可以看到,由于摄像头没有检测到符合条件的色块,所以sending_data(567,789),通过串口助手明显发现数据传输成功,共有7个字节。

这样,我已经保证了openmv的串口发送程序是完全没有问题的,于是将程序烧录进openmv。

接下来,写一下stm32的接受程序

以下代码引用 乌拉~~~~ 博主的 超详细OpenMV与STM32单片机通信 (有完整版源码) 这一篇文章里的源码。感谢此博主的文章!!!!

// 串口中断服务函数//USART2 全局中断服务函数void DEBUG_USART_IRQHandler(void){uint8_t com_data; //接收一个字节数据的临时变量uint8_t i;static uint8_t RxCounter1=0;//数据缓冲区的索引static uint8_t RxBuffer1[10]={0};//存放数据的接收缓存区static uint8_t RxState = 0;//接收标志位//static uint8_t RxFlag1 = 0;if( USART_GetITStatus(DEBUG_USARTx ,USART_IT_RXNE)!=RESET)//接收中断 {USART_ClearITPendingBit(DEBUG_USARTx ,USART_IT_RXNE); //清除中断标志com_data = USART_ReceiveData(DEBUG_USARTx );if(RxState==0&&com_data==0x2C) //0x2c帧头{RxState=1;RxBuffer1[RxCounter1++]=com_data;//RxBuffer1[0]==0x2c RxCounter1==1}else if(RxState==1&&com_data==0x12) //0x12帧头{RxState=2;RxBuffer1[RxCounter1++]=com_data;RxBuffer1[0]==0x12 RxCounter1==2}else if(RxState==2)//开始接收有效数据{RxBuffer1[RxCounter1++]=com_data;//全部接收完,RxCounter1==7if(RxCounter1>=10||com_data == 0x5B) //RxBuffer1接受满了,接收数据结束{RxState=3;//RxFlag1=1;Cx=(RxBuffer1[RxCounter1-4]<<8)+(RxBuffer1[RxCounter1-5]);//RxBuffer1[2]是openmv发送的第一个数据的低八位,RxBuffer1[3]是openmv发送的第一个数据的高八位Cy=(RxBuffer1[RxCounter1-2]<<8)+(RxBuffer1[RxCounter1-3]);RxBuffer1[4]是openmv发送的第二个数据的低八位,RxBuffer1[5]是openmv发送的第二个数据的高八位}}else if(RxState==3)//检测是否接受到结束标志{if(RxBuffer1[RxCounter1-1] == 0x5B){USART_ITConfig(DEBUG_USARTx,USART_IT_RXNE,DISABLE);//关闭DTSABLE中断//if(RxFlag1)//{//OLED_ShowNum(0,0,Cx,3,1,2);OLED_ShowNum(0,2,Cy,3,1,2);//}//RxFlag1 = 0;RxCounter1 = 0;RxState = 0;USART_ITConfig(DEBUG_USARTx,USART_IT_RXNE,ENABLE);}else //接收错误{RxState = 0;RxCounter1=0;for(i=0;i<10;i++){RxBuffer1[i]=0xff;//将存放数据数组清零}}} else //接收异常{RxState = 0;RxCounter1=0;for(i=0;i<10;i++){RxBuffer1[i]=0xff;//将存放数据数组清零}}}}

将openmv的TXD、RXD分别和单片机的RXD、和TXD相连,然后两者共地,再在单片机上连接oled显示一下收到的数据,再把openmv连接电脑,通过IDE观测其发送的数据和oled接收的是否一致。

结果:

可以看到,我成功了。

将OLED显示的两行代码改进一下:

OLED_ShowChar(0,0,'(',2);OLED_ShowNum(8,0,Cx,3,1,2);OLED_ShowChar(56,0,',',2);OLED_ShowNum(64,0,Cy,3,1,2);OLED_ShowChar(112,0,')',2);

就成了这个效果:

这里有个疑问

openmv一共发送了7个数据,所以我就把RxBuffer1[10]={0};//存放数据的接收缓存区改为了RxBuffer1[7]={0};改完之后,oled就不能正常显示数据。(下标最小得是9)

想不出来这到底是因为什么??????????????????

解决(最新代码)

// 串口中断服务函数//USART1 全局中断服务函数void DEBUG_USART_IRQHandler(void){uint8_t com_data; //接收一个字节数据的临时变量uint8_t i;static uint8_t RxCounter1=0;//数据缓冲区的索引static uint8_t RxBuffer1[7]={0};//存放数据的接收缓存区static uint8_t RxState = 0;//接收标志位//static uint8_t RxFlag1 = 0;if( USART_GetITStatus(DEBUG_USARTx ,USART_IT_RXNE)!=RESET)//接收中断 {USART_ClearITPendingBit(DEBUG_USARTx ,USART_IT_RXNE); //清除中断标志com_data = USART_ReceiveData(DEBUG_USARTx );if(RxState==0&&com_data==0x2C) //0x2c帧头{RxState=1;RxBuffer1[RxCounter1++]=com_data;//RxBuffer1[0]==0x2c RxCounter1==1}else if(RxState==1&&com_data==0x12) //0x12帧头{RxState=2;RxBuffer1[RxCounter1++]=com_data;RxBuffer1[0]==0x12 RxCounter1==2}else if(RxState==2)//开始接收有效数据{RxBuffer1[RxCounter1++]=com_data;//全部接收完,RxCounter1==7if(RxCounter1>=7||com_data == 0x5B) //RxBuffer1接受满了,接收数据结束{RxState=3;//RxFlag1=1;Cx=(RxBuffer1[RxCounter1-4]<<8)+(RxBuffer1[RxCounter1-5]);//RxBuffer1[2]是openmv发送的第一个数据的低八位,RxBuffer1[3]是openmv发送的第一个数据的高八位Cy=(RxBuffer1[RxCounter1-2]<<8)+(RxBuffer1[RxCounter1-3]);RxBuffer1[4]是openmv发送的第二个数据的低八位,RxBuffer1[5]是openmv发送的第二个数据的高八位}}else if(RxState==3)//检测是否接受到结束标志{if(RxBuffer1[RxCounter1-1] == 0x5B){USART_ITConfig(DEBUG_USARTx,USART_IT_RXNE,DISABLE);//关闭DTSABLE中断//if(RxFlag1)//{OLED_ShowChar(0,0,'(',2);OLED_ShowNum(8,0,Cx,3,1,2);OLED_ShowChar(56,0,',',2);OLED_ShowNum(64,0,Cy,3,1,2);OLED_ShowChar(112,0,')',2);//}//RxFlag1 = 0;RxCounter1 = 0;RxState = 0;USART_ITConfig(DEBUG_USARTx,USART_IT_RXNE,ENABLE);}else //接收错误{RxState = 0;RxCounter1=0;for(i=0;i<7;i++){RxBuffer1[i]=0x00;//将存放数据数组清零}}} else //接收异常{RxState = 0;RxCounter1=0;for(i=0;i<7;i++){RxBuffer1[i]=0x00;//将存放数据数组清零}}}}

疑惑存在是因为我只改了RxBuffer1的角标,而没有改动接收异常(else)里面for循环的i<10,这是要改成i<7的。

openmv脱机运行

将openmv脱机,用单片机的5v给他供电,其余连线保持不变:

同样可以把openmv的结果通过串口打印到电脑

只需要在while循环里加上:

while(1){printf("(%d,%d)",Cx,Cy);}

注意

1.想要单片机与电脑通信,要另外设置特定的串口,我的开发板上单片机通过USART1和电脑通信,所以要另外设置USART1。

2.同一个串口的RXD不可以连接多个设备的TXD。比如,我的开发板的USART1如果连接到openmv的TXD,那么可能就造成程序下载不到单片机,因为电脑的TXD也连接的是USART1的RXD。

///重定向c库函数printf到串口,重定向后可使用printf函数int fputc(int ch, FILE *f){/* 发送一个字节数据到串口 */USART_SendData(DEBUG_USARTx, (uint8_t) ch);/* 等待发送完毕 */while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);return (ch);}

我这个代码的重定向是写的USART1(DEBUG_USARTx),是不是就说明,我只要使用printf函数就是向USART1的TXR端发送数据???

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。