当前位置:   article > 正文

OpenMV与STM32之间的通信(附源码)_openmv与stm32连接

openmv与stm32连接

本篇文章旨在记录我电赛期间使用openmv和stm32单片机之间进行串口通信,将openmv识别到的坐标传输给单片机。背景是基于2023年全国大学生电子设计大赛E题:舵机云台追踪识别。

单片机的串口通信原理我便不再详细讲解,下面直接上代码分析。

值得注意的是接线:RX——>TX

                                 TX——>RX

                                 单片机和OPENMV必须共地

非常重要!!!!

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

(一)、 OPENMV串口通信部分

  1. import sensor, image, time,math,pyb
  2. from pyb import UART,LED
  3. import json
  4. import ustruct
  5. sensor.reset()
  6. sensor.set_pixformat(sensor.RGB565)
  7. sensor.set_framesize(sensor.QVGA)
  8. sensor.skip_frames(time = 2000)
  9. sensor.set_auto_gain(False) # must be turned off for color tracking
  10. sensor.set_auto_whitebal(False) # must be turned off for color tracking
  11. red_threshold_01=(10, 100, 127, 32, -43, 67)
  12. clock = time.clock()
  13. uart = UART(3,115200) #定义串口3变量
  14. uart.init(115200, bits=8, parity=None, stop=1) # init with given parameters
  15. def find_max(blobs): #定义寻找色块面积最大的函数
  16. max_size=0
  17. for blob in blobs:
  18. if blob.pixels() > max_size:
  19. max_blob=blob
  20. max_size = blob.pixels()
  21. return max_blob
  22. def sending_data(cx,cy,cw,ch):
  23. global uart;
  24. #frame=[0x2C,18,cx%0xff,int(cx/0xff),cy%0xff,int(cy/0xff),0x5B];
  25. #data = bytearray(frame)
  26. data = ustruct.pack("<bbhhhhb", #格式为俩个字符俩个短整型(2字节)
  27. 0x2C, #帧头1
  28. 0x12, #帧头2
  29. int(cx), # up sample by 4 #数据1
  30. int(cy), # up sample by 4 #数据2
  31. int(cw), # up sample by 4 #数据1
  32. int(ch), # up sample by 4 #数据2
  33. 0x5B)
  34. uart.write(data); #必须要传入一个字节数组
  35. while(True):
  36. clock.tick()
  37. img = sensor.snapshot()
  38. blobs = img.find_blobs([red_threshold_01])
  39. max_b = find_max(blobs)
  40. cx=0;cy=0;
  41. if blobs:
  42. #如果找到了目标颜色
  43. cx=max_b[5]
  44. cy=max_b[6]
  45. cw=max_b[2]
  46. ch=max_b[3]
  47. img.draw_rectangle(max_b[0:4]) # rect
  48. img.draw_cross(max_b[5], max_b[6]) # cx, cy
  49. FH = bytearray([0x2C,0x12,cx,cy,cw,ch,0x5B])
  50. #sending_data(cx,cy,cw,ch)
  51. uart.write(FH)
  52. print(cx,cy,cw,ch)

注意观察下图标注的部分,我不做详细讲解,但是很容易理解: 

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

  1. #include "uart.h"
  2. #include "oled.h"
  3. #include "stdio.h"
  4. static u8 Cx=0,Cy=0,Cw=0,Ch=0;
  5. void USART1_Init(void)
  6. {
  7. //USART1_TX:PA 9
  8. //USART1_RX:PA10
  9. GPIO_InitTypeDef GPIO_InitStructure; //串口端口配置结构体变量
  10. USART_InitTypeDef USART_InitStructure; //串口参数配置结构体变量
  11. NVIC_InitTypeDef NVIC_InitStructure; //串口中断配置结构体变量
  12. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
  13. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //打开PA端口时钟
  14. //USART1_TX PA9
  15. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA9
  16. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设定IO口的输出速度为50MHz
  17. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  18. GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9
  19. //USART1_RX PA10
  20. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PA10
  21. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  22. GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA10
  23. //USART1 NVIC 配置
  24. NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  25. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ; //抢占优先级0
  26. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子优先级2
  27. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
  28. NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
  29. //USART 初始化设置
  30. USART_InitStructure.USART_BaudRate = 115200; //串口波特率为115200
  31. USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
  32. USART_InitStructure.USART_StopBits = USART_StopBits_1; //一个停止位
  33. USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位
  34. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
  35. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
  36. USART_Init(USART1, &USART_InitStructure); //初始化串口1
  37. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //使能中断
  38. USART_Cmd(USART1, ENABLE); //使能串口1
  39. //如下语句解决第1个字节无法正确发送出去的问题
  40. USART_ClearFlag(USART1, USART_FLAG_TC); //清串口1发送标志
  41. }
  42. //USART1 全局中断服务函数
  43. void USART1_IRQHandler(void)
  44. {
  45. u8 com_data;
  46. u8 i;
  47. static u8 RxCounter1=0;
  48. static u16 RxBuffer1[10]={0};
  49. static u8 RxState = 0;
  50. static u8 RxFlag1 = 0;
  51. if( USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) //接收中断
  52. {
  53. USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志
  54. com_data = USART_ReceiveData(USART1);
  55. if(RxState==0&&com_data==0x2C) //0x2c帧头
  56. {
  57. RxState=1;
  58. RxBuffer1[RxCounter1++]=com_data;OLED_Refresh();
  59. }
  60. else if(RxState==1&&com_data==0x12) //0x12帧头
  61. {
  62. RxState=2;
  63. RxBuffer1[RxCounter1++]=com_data;
  64. }
  65. else if(RxState==2)
  66. {
  67. RxBuffer1[RxCounter1++]=com_data;
  68. if(RxCounter1>=10||com_data == 0x5B) //RxBuffer1接受满了,接收数据结束
  69. {
  70. RxState=3;
  71. RxFlag1=1;
  72. Cx=RxBuffer1[RxCounter1-5];
  73. Cy=RxBuffer1[RxCounter1-4];
  74. Cw=RxBuffer1[RxCounter1-3];
  75. Ch=RxBuffer1[RxCounter1-2];
  76. }
  77. }
  78. else if(RxState==3) //检测是否接受到结束标志
  79. {
  80. if(RxBuffer1[RxCounter1-1] == 0x5B)
  81. {
  82. USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);//关闭DTSABLE中断
  83. if(RxFlag1)
  84. {
  85. OLED_Refresh();
  86. OLED_ShowNum(0, 0,Cx,3,16,1);
  87. OLED_ShowNum(0,17,Cy,3,16,1);
  88. OLED_ShowNum(0,33,Cw,3,16,1);
  89. OLED_ShowNum(0,49,Ch,3,16,1);
  90. }
  91. RxFlag1 = 0;
  92. RxCounter1 = 0;
  93. RxState = 0;
  94. USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
  95. }
  96. else //接收错误
  97. {
  98. RxState = 0;
  99. RxCounter1=0;
  100. for(i=0;i<10;i++)
  101. {
  102. RxBuffer1[i]=0x00; //将存放数据数组清零
  103. }
  104. }
  105. }
  106. else //接收异常
  107. {
  108. RxState = 0;
  109. RxCounter1=0;
  110. for(i=0;i<10;i++)
  111. {
  112. RxBuffer1[i]=0x00; //将存放数据数组清零
  113. }
  114. }
  115. }
  116. }

注意观察下面的图:

二、串口通信传输多个数据(四个点的x、y坐标同时传输给STM32单片机

(一)OPENMV串口部分

  1. from machine import Pin
  2. import sensor, image, time, pyb
  3. #import seekfree
  4. from pyb import UART
  5. # 初始化TFT180屏幕
  6. #lcd = seekfree.LCD180(3)
  7. # 初始化摄像头
  8. sensor.reset()
  9. sensor.set_pixformat(sensor.RGB565) # 设置图像色彩格式为RGB565格式
  10. sensor.set_framesize(sensor.QQVGA) # 设置图像大小为160*120
  11. sensor.set_auto_whitebal(True) # 设置自动白平衡
  12. sensor.set_brightness(3000) # 设置亮度为3000
  13. sensor.skip_frames(time = 20) # 跳过帧
  14. uart = UART(3, 115200,timeout_char=3000) #配置串口
  15. clock = time.clock()
  16. def sending_data(cx,cy,cw,ch):
  17. global uart;
  18. data = ustruct.pack("<bbhhb", #格式为俩个字符俩个短整型(2字节)
  19. 0x2C, #帧头1
  20. 0x12, #帧头2
  21. int (cx1), # up sample by 4 #数据26
  22. int (cy1),
  23. int (cx2), # up sample by 4 #数据26
  24. int (cy2),
  25. int (cx3), # up sample by 4 #数据26
  26. int (cy3),
  27. int (cx4), # up sample by 4 #数据26
  28. int (cy4),
  29. 0x5B)
  30. uart.write(data); #必须要传入一个字节数组
  31. while(True):
  32. clock.tick()
  33. img = sensor.snapshot()
  34. # -----矩形框部分-----
  35. # 在图像中寻找矩形
  36. for r in img.find_rects(threshold = 10000):
  37. # 判断矩形边长是否符合要求
  38. if r.w() > 20 and r.h() > 20:
  39. # 在屏幕上框出矩形
  40. img.draw_rectangle(r.rect(), color = (255, 0, 0), scale = 4)
  41. # 获取矩形角点位置
  42. corner = r.corners()
  43. # 在屏幕上圈出矩形角点
  44. img.draw_circle(corner[0][0], corner[0][1], 5, color = (0, 0, 255), thickness = 2, fill = False)
  45. img.draw_circle(corner[1][0], corner[1][1], 5, color = (0, 0, 255), thickness = 2, fill = False)
  46. img.draw_circle(corner[2][0], corner[2][1], 5, color = (0, 0, 255), thickness = 2, fill = False)
  47. img.draw_circle(corner[3][0], corner[3][1], 5, color = (0, 0, 255), thickness = 2, fill = False)
  48. # 打印四个角点坐标, 角点1的数组是corner[0], 坐标就是(corner[0][0],corner[0][1])
  49. # 角点检测输出的角点排序每次不一定一致,矩形左上的角点有可能是corner0,1,2,3其中一个
  50. corner1_str = f"corner1 = ({corner[0][0]},{corner[0][1]})"
  51. corner2_str = f"corner2 = ({corner[1][0]},{corner[1][1]})"
  52. corner3_str = f"corner3 = ({corner[2][0]},{corner[2][1]})"
  53. corner4_str = f"corner4 = ({corner[3][0]},{corner[3][1]})"
  54. print(corner1_str + "\n" + corner2_str + "\n" + corner3_str + "\n" + corner4_str)
  55. # 显示到屏幕上,此部分会降低帧率
  56. #lcd.show_image(img, 160, 120, 0, 0, zoom=0) #屏幕显示
  57. #串口通信传输的数据
  58. cx1=(int)(corner[0][0]*10)
  59. cy1=(int)(corner[0][1]*10)
  60. cx2=(int)(corner[1][0]*10)
  61. cy2=(int)(corner[1][1]*10)
  62. cx3=(int)(corner[2][0]*10)
  63. cy3=(int)(corner[2][1]*10)
  64. cx4=(int)(corner[3][0]*10)
  65. cy4=(int)(corner[3][1]*10)
  66. FH=bytearray([0x2C,0x12,cx1,cy1,cx2,cy2,cx3,cy3,cx4,cy4,0x5B])
  67. uart.write(FH)
  68. cx1=0
  69. cy1=0
  70. cx2=0
  71. cy2=0
  72. cx3=0
  73. cy3=0
  74. cx4=0
  75. cy4=0
  76. # 打印帧率
  77. print(clock.fps())

下面请观察这幅代码截图:

(二)、STM32串口通信部分

  1. #include "stm32f10x.h" // Device header
  2. #include <stdio.h>
  3. #include <stdarg.h>
  4. #include "OLED.h"
  5. #include "LED.h"
  6. #include "Serial.h"
  7. uint8_t Serial_RxData;
  8. uint8_t Serial_RxFlag;
  9. static int16_t Cx1=0,Cy1=0,Cx2=0,Cy2=0,Cx3=0,Cy3=0,Cx4=0,Cy4=0;
  10. int Cx5[16];//用于存放分段求的坐标值
  11. int Cy5[16];
  12. //static u8 RxFlag1 = 0;//串口中断接收标志位
  13. extern float Ang1,Ang2,AngFlag;
  14. extern float Angle1,Angle2;
  15. int avel_X1 ;
  16. int avel_X2 ;
  17. int avel_X3 ;
  18. int avel_X4 ;
  19. int avel_Y1 ;
  20. int avel_Y2 ;
  21. int avel_Y3 ;
  22. int avel_Y4 ;
  23. void Serial_Init(void)
  24. {
  25. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
  26. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  27. //TX
  28. GPIO_InitTypeDef GPIO_InitStructure;
  29. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  30. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  31. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  32. GPIO_Init(GPIOB, &GPIO_InitStructure);
  33. //RX
  34. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  35. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  36. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  37. GPIO_Init(GPIOB, &GPIO_InitStructure);
  38. USART_InitTypeDef USART_InitStructure;
  39. USART_InitStructure.USART_BaudRate = 115200;
  40. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  41. USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
  42. USART_InitStructure.USART_Parity = USART_Parity_No;
  43. USART_InitStructure.USART_StopBits = USART_StopBits_1;
  44. USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  45. USART_Init(USART3, &USART_InitStructure);
  46. USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
  47. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  48. NVIC_InitTypeDef NVIC_InitStructure;
  49. NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
  50. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  51. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  52. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  53. NVIC_Init(&NVIC_InitStructure);
  54. USART_Cmd(USART3, ENABLE);
  55. }
  56. void Serial_SendByte(uint8_t Byte)
  57. {
  58. USART_SendData(USART3, Byte);
  59. while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
  60. }
  61. void Serial_SendArray(uint8_t *Array, uint16_t Length)
  62. {
  63. uint16_t i;
  64. for (i = 0; i < Length; i ++)
  65. {
  66. Serial_SendByte(Array[i]);
  67. }
  68. }
  69. void Serial_SendString(char *String)
  70. {
  71. uint8_t i;
  72. for (i = 0; String[i] != '\0'; i ++)
  73. {
  74. Serial_SendByte(String[i]);
  75. }
  76. }
  77. uint32_t Serial_Pow(uint32_t X, uint32_t Y)
  78. {
  79. uint32_t Result = 1;
  80. while (Y --)
  81. {
  82. Result *= X;
  83. }
  84. return Result;
  85. }
  86. void Serial_SendNumber(uint32_t Number, uint8_t Length)
  87. {
  88. uint8_t i;
  89. for (i = 0; i < Length; i ++)
  90. {
  91. Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
  92. }
  93. }
  94. int fputc(int ch, FILE *f)
  95. {
  96. Serial_SendByte(ch);
  97. return ch;
  98. }
  99. void Serial_Printf(char *format, ...)
  100. {
  101. char String[100];
  102. va_list arg;
  103. va_start(arg, format);
  104. vsprintf(String, format, arg);
  105. va_end(arg);
  106. Serial_SendString(String);
  107. }
  108. //USART3 全局中断服务函数
  109. void USART3_IRQHandler(void)
  110. {
  111. int com_data;
  112. u8 i;
  113. u8 Jieshou = 1;
  114. static u8 RxCounter1=0;
  115. static int RxBuffer1[16]={0};
  116. static u8 RxState = 0;
  117. static u8 RxFlag1 = 0;//串口中断接收标志位,已被移除至函数体外作为全局变量
  118. if( USART_GetITStatus(USART3,USART_IT_RXNE)!=RESET && Jieshou == 1) //接收中断
  119. {
  120. // OLED_ShowSignedNum(1,1,520,4);
  121. USART_ClearITPendingBit(USART3,USART_IT_RXNE); //清除中断标志
  122. com_data = USART_ReceiveData(USART3);
  123. if(Jieshou == 1)
  124. {
  125. if(RxState==0&&com_data==0x2C) //0x2c帧头
  126. {
  127. RxBuffer1[RxCounter1++]=com_data;
  128. RxState=1;
  129. }
  130. else if(RxState==1&&com_data==0x12) //0x12帧头
  131. {
  132. RxBuffer1[RxCounter1++]=com_data;
  133. RxState=2;
  134. }
  135. else if(RxState==2)
  136. {
  137. RxBuffer1[RxCounter1++]=com_data;
  138. if(RxCounter1>=14||com_data == 0x5B) //RxBuffer1接受满了,接收数据结束
  139. {
  140. RxState=3;
  141. RxFlag1=1;
  142. Jieshou = 2;
  143. Cx1=RxBuffer1[RxCounter1-9];
  144. Cy1=RxBuffer1[RxCounter1-8];
  145. Cx2=RxBuffer1[RxCounter1-7];
  146. Cy2=RxBuffer1[RxCounter1-6];
  147. Cx3=RxBuffer1[RxCounter1-5];
  148. Cy3=RxBuffer1[RxCounter1-4];
  149. Cx4=RxBuffer1[RxCounter1-3];
  150. Cy4=RxBuffer1[RxCounter1-2];
  151. OLED_ShowSignedNum(1,1,Cx1,4);
  152. OLED_ShowSignedNum(2,1,Cy1,4);
  153. OLED_ShowSignedNum(3,1,Cx2,4);
  154. OLED_ShowSignedNum(4,1,Cy2,4);
  155. OLED_ShowSignedNum(1,7,Cx3,4);
  156. OLED_ShowSignedNum(2,7,Cy3,4);
  157. OLED_ShowSignedNum(3,7,Cx4,4);
  158. OLED_ShowSignedNum(4,7,Cy4,4);
  159. }
  160. }
  161. }
  162. else if(RxState==3) //检测是否接受到结束标志
  163. {
  164. if(RxBuffer1[RxCounter1-1] == 0x5B)
  165. {
  166. USART_ITConfig(USART3,USART_IT_RXNE,DISABLE);//关闭DTSABLE中断
  167. if(RxFlag1)
  168. {
  169. AngFlag=0;
  170. HuanRaoZuoBiao();
  171. //
  172. // OLED_ShowSignedNum(1,1,Cx1,4);
  173. // OLED_ShowSignedNum(2,1,Cx2,4);
  174. // OLED_ShowSignedNum(3,1,avel_X1,4);
  175. // OLED_ShowSignedNum(4,1,Cx5[0],4);
  176. AngFlag=1;
  177. RxFlag1 = 0;
  178. RxCounter1 = 0;
  179. RxState = 0;
  180. }
  181. USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
  182. }
  183. else //接收错误
  184. {
  185. RxState = 0;
  186. RxCounter1=0;
  187. for(i=0;i<10;i++)
  188. {
  189. RxBuffer1[i]=0x00; //将存放数据数组清零
  190. }
  191. }
  192. }
  193. else //接收异常
  194. {
  195. RxState = 0;
  196. RxCounter1=0;
  197. for(i=0;i<10;i++)
  198. {
  199. RxBuffer1[i]=0x00; //将存放数据数组清零
  200. }
  201. }
  202. }
  203. }

 注意观察下面这副代码截图:

以上便是我对电赛期间OPENMV与单片机之间实现串口通信的代码实现。学者若有疑问或需要代码工程,可以私聊我。收到后我会及时回复。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/82861
推荐阅读
相关标签
  

闽ICP备14008679号