[其他ST产品] OpenMv和STM32通信

[复制链接]
 楼主| 9dome猫 发表于 2022-1-24 17:04 | 显示全部楼层 |阅读模式
最近一段时间都在捣鼓OpenMV和Stm32的通信问题,刚开始不知道哪里出了问题,一直通信失败,明明使用TTL串口接收OpenMv发送的数据是可以在串口调试助手上显示的,但就是无法发给Stm32的USART串口。经过了差不多一周的时间,终于解决了。于是在这里记录学习记录。

一、OpenMv配置1.第一种发送方法

OpenMv代码如下

  1. # Untitled - By: 86188 - 周二 5月 25 2021

  2. import sensor, image, time,pyb
  3. from pyb import UART,LED
  4. import json
  5. import ustruct




  6. #white_threshold_01 = ((95, 100, -18, 3, -8, 4));  #白色阈值
  7. red_threshold_01 = ((2, 51, 11, 127, -128, 127))  #红色阈值

  8. LED_R = pyb.LED(1) # Red LED = 1, Green LED = 2, Blue LED = 3, IR LEDs = 4.
  9. LED_G = pyb.LED(2)
  10. LED_B = pyb.LED(3)

  11. LED_R.on()
  12. LED_G.on()
  13. LED_B.on()



  14. sensor.reset()
  15. sensor.set_pixformat(sensor.RGB565)
  16. sensor.set_framesize(sensor.QVGA)
  17. sensor.skip_frames(time = 2000)
  18. sensor.set_auto_gain(False) # must be turned off for color tracking
  19. sensor.set_auto_whitebal(False) # must be turned off for color tracking


  20. clock = time.clock()

  21. LED_R.off()
  22. LED_G.off()
  23. LED_B.off()

  24. uart = UART(3,115200)   #定义串口3变量
  25. uart.init(115200, bits=8, parity=None, stop=1) # init with given parameters



  26. def find_max(blobs):    #定义寻找色块面积最大的函数
  27.     max_size=0
  28.     for blob in blobs:
  29.         if blob.pixels() > max_size:
  30.             max_blob=blob
  31.             max_size = blob.pixels()
  32.     return max_blob


  33. def send_data_packet(x,y,z,w):
  34.     temp = ustruct.pack("<bbhhhh",                #格式为俩个字符俩个整型
  35.                    0x2C,                       #帧头1
  36.                    0x12,                       #帧头2
  37.                    int(x), # up sample by 2    #数据1
  38.                    int(y), # up sample by 2    #数据2
  39.                    int(z),
  40.                    int(w))
  41.                    #0x5B)
  42.     uart.write(temp);                           #串口发送





  43. while(True):
  44.     img = sensor.snapshot()
  45.     #time.sleep_ms(1000)
  46.     #send_data_packet(x,y)
  47.     blobs = img.find_blobs([red_threshold_01]);

  48.     cx=0;cy=0;
  49.     if blobs:
  50.                 #如果找到了目标颜色
  51.                 max_b = find_max(blobs);
  52.                 # Draw a rect around the blob.
  53.                 img.draw_rectangle(max_b[0:4]) # rect
  54.                 #用矩形标记出目标颜色区域
  55.                 img.draw_cross(max_b[5], max_b[6]) # cx, cy
  56.                 #img.draw_cross(160, 120) # 在中心点画标记
  57.                 #在目标颜色区域的中心画十字形标记
  58.                 cx=max_b[5];
  59.                 cy=max_b[6];
  60.                 cw=max_b[2];
  61.                 ch=max_b[3];

  62.     #data = bytearray([x,y])
  63.                 send_data_packet(cx,cy,cw,ch)
  64.     #time.sleep_ms(1000)









 楼主| 9dome猫 发表于 2022-1-24 17:05 | 显示全部楼层
代码作用:OpenMv使用的是python语言编写,而这段代码的主要目的就是在openmv视野种寻找红色色块,并将其中点坐标发送会Stm32,并在OLED屏幕上显示。
redone 发表于 2022-1-25 13:13 | 显示全部楼层
OpenMv是个什么高级东西
 楼主| 9dome猫 发表于 2022-1-25 15:15 | 显示全部楼层
主要通信函数如下
  1. def send_data_packet(x,y,z,w):
  2.     temp = ustruct.pack("<bbhhhh",                #格式为俩个字符俩个整型
  3.                    0x2C,                       #帧头1
  4.                    0x12,                       #帧头2
  5.                    int(x), # up sample by 2    #数据1
  6.                    int(y), # up sample by 2    #数据2
  7.                    int(z),
  8.                    int(w))
  9.                    #0x5B)
  10.     uart.write(temp);                           #串口发送
 楼主| 9dome猫 发表于 2022-1-25 15:17 | 显示全部楼层
这里使用了数据包的形式发送数据,将一帧的数据包装,并发送给Stm32,此数据包中的包头非常重要,也就是0x2C以及0x12,这两个数据便与Stm32接收中断中进行判断,以确保数据的正确性。
 楼主| 9dome猫 发表于 2022-1-25 15:23 | 显示全部楼层
对于数据包格式,此等的使用规划:

  1. #pack各字母对应类型
  2. #x   pad byte        no value            1
  3. #c   char            string of length 1  1
  4. #b   signed char     integer             1
  5. #B   unsigned char   integer             1
  6. #?   _Bool           bool                1
  7. #h   short           integer             2
  8. #H   unsigned short  integer             2
  9. #i   int             integer             4
  10. #I   unsigned int    integer or long     4
  11. #l   long            integer             4
  12. #L   unsigned long   long                4
  13. #q   long long       long                8
  14. #Q   unsilong long   long                8
  15. #f   float           float               4
  16. #d   double          float               8
  17. #s   char[]          string              1
  18. #p   char[]          string              1
  19. #P   void *          long

 楼主| 9dome猫 发表于 2022-1-25 15:24 | 显示全部楼层
对于此处我所使用的"<bbhhhh",
第一个第二个数据为包头,便是b,字符串类型。而后面开始为数据格式,我选择的是h也就是短整型,传输给Stm32的时候,便是两个字节的数据格式。
 楼主| 9dome猫 发表于 2022-1-25 15:25 | 显示全部楼层
如图,一串完整的数据便是 2C 12 36 00 80 00 2E 00 9D 00。

9580261efa5d29e48a.png
 楼主| 9dome猫 发表于 2022-1-25 15:26 | 显示全部楼层
2.第二种发送方法
除了以上这种以包(pack)的方式发送给stm32外,还可以使用另外的一种方法发送:
  1. def send_data(cx,cy,w,h):
  2.     datalist = [ 0x2C,0x12,cx,cy,w,h]
  3.     datalist.append(sum_checkout(datalist))
  4.     data = bytearray(datalist)
  5.     return data

  6. #检验数据和  
  7. def sum_checkout(data_list):
  8.     data_sum = 0
  9.     for temp in data_list:
  10.         data_sum =  data_sum + temp
  11.     return data_sum

 楼主| 9dome猫 发表于 2022-1-25 15:29 | 显示全部楼层
这段代码和之前不同的是:我将0x5B 最后一位的数据校验位改成了用sum_checkout() 这段函数求和取余的方法作为该数据的数据校验位。
 楼主| 9dome猫 发表于 2022-1-25 15:30 | 显示全部楼层
但是使用这样不封包的方法发送,就必须加上data = bytearray(datalist),将数据转化,才可以进行通讯。
 楼主| 9dome猫 发表于 2022-1-25 15:30 | 显示全部楼层
二、Stm32配置
Stm32的USART1配置如下:


  1. u16 USART_RX_STA=0;       //接收状态标记          
  2.   
  3. void uart1_init(u32 bound){
  4.   //GPIO端口设置
  5.   GPIO_InitTypeDef GPIO_InitStructure;
  6.         USART_InitTypeDef USART_InitStructure;
  7.         NVIC_InitTypeDef NVIC_InitStructure;
  8.          
  9.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);        //使能USART1,GPIOA时钟
  10.   
  11.         //USART1_TX   GPIOA.9
  12.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
  13.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  14.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出
  15.   GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
  16.    
  17.   //USART1_RX          GPIOA.10初始化
  18.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
  19.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  20.   GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  

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

  29.         USART_InitStructure.USART_BaudRate = bound;//串口波特率
  30.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
  31.         USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
  32.         USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
  33.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
  34.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //收发模式

  35.   USART_Init(USART1, &USART_InitStructure); //初始化串口1
  36.   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
  37.   USART_Cmd(USART1, ENABLE);                    //使能串口1

  38. }

 楼主| 9dome猫 发表于 2022-1-25 16:15 | 显示全部楼层
相比于平常配置并未存在较大差别,而实现通信的重要步骤是在USART1的串口接收中断中。
 楼主| 9dome猫 发表于 2022-1-25 16:30 | 显示全部楼层
  1. void USART1_IRQHandler(void)
  2. {
  3.                 u8 Res;

  4.                 static u8 Rebuf[20]={0};
  5.                 static u8 i = 0;

  6.                 if( USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET )
  7.         {
  8.                 Rebuf[i++] = USART_ReceiveData(USART1);
  9.                 if(Rebuf[0] != 0x2c)
  10.                                 i = 0;
  11.                 if((i==2)&&Rebuf[1] != 0x12)
  12.                           i = 0;
  13.                         if(i>=10)
  14.                         {
  15.                                 memcpy(OpenMV_Rx_BUF,Rebuf,i);
  16.                                 i = 0;
  17.                         }
  18.                         USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除中断标志
  19.         }

  20. }
 楼主| 9dome猫 发表于 2022-1-25 16:32 | 显示全部楼层
其中定义了一个OpenMV_Rx_BUF[20]的数组来接收openmv发送过来的数据,需要使用extern修饰这个变量,以便于事项后续操作。
 楼主| 9dome猫 发表于 2022-1-25 16:33 | 显示全部楼层
同时memcpy()函数也是十分重要的一个内置函数,可以实现两个数组的拷贝任务。

 楼主| 9dome猫 发表于 2022-1-25 16:34 | 显示全部楼层
主函数的代码如下:

  1. int main(void)
  2. {               
  3.          
  4.         delay_init();                     //延时函数初始化          
  5.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
  6.         uart1_init(115200);         //串口初始化为115200
  7.         LED_Init();                             //LED端口初始化
  8.         OLED_Init();
  9.        
  10.         while(1)
  11.         {
  12.                        
  13.                         LED0=!LED0;
  14.                         delay_ms(200);

  15.                     OLED_Refresh_Gram();
  16.            
  17.                         OLED_ShowNumber(0,20,OpenMV_Rx_BUF[2],3,12);
  18.                         OLED_ShowNumber(20,20,OpenMV_Rx_BUF[4],3,12);
  19.                         OLED_ShowNumber(40,20,OpenMV_Rx_BUF[6],3,12);
  20.                         OLED_ShowNumber(60,20,OpenMV_Rx_BUF[8],3,12);
  21.                        

  22.         }
  23. }
 楼主| 9dome猫 发表于 2022-1-25 16:38 | 显示全部楼层
前面就提到了,由于我数据包的格式设置问题,存入OpenMV_Rx_BUF[] 数组中的数据,真正有效的是第3、5、7、9位(因为选择了h类型数据格式,一个数据占2位)。
 楼主| 9dome猫 发表于 2022-1-25 16:39 | 显示全部楼层
总结
博主我之前数据一直发送失败的原因是,博主使用了 uart.write() 这个函数,企图通过 uart.write() 这个函数实现数据发送。
 楼主| 9dome猫 发表于 2022-1-25 16:40 | 显示全部楼层
这个函数在实现OpenMv和PC端的通信上没有问题,可以将数据打在串口调试助手上,但在其与Stm32的通信问题上就存在问题。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

138

主题

1574

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部