打印
[其他ST产品]

OpenMv和STM32通信

[复制链接]
1965|40
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
最近一段时间都在捣鼓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)









使用特权

评论回复
沙发
9dome猫|  楼主 | 2022-1-24 17:05 | 只看该作者
代码作用:OpenMv使用的是python语言编写,而这段代码的主要目的就是在openmv视野种寻找红色色块,并将其中点坐标发送会Stm32,并在OLED屏幕上显示。

使用特权

评论回复
板凳
redone| | 2022-1-25 13:13 | 只看该作者
OpenMv是个什么高级东西

使用特权

评论回复
地板
9dome猫|  楼主 | 2022-1-25 15:15 | 只看该作者
主要通信函数如下
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);                           #串口发送

使用特权

评论回复
5
9dome猫|  楼主 | 2022-1-25 15:17 | 只看该作者
这里使用了数据包的形式发送数据,将一帧的数据包装,并发送给Stm32,此数据包中的包头非常重要,也就是0x2C以及0x12,这两个数据便与Stm32接收中断中进行判断,以确保数据的正确性。

使用特权

评论回复
6
9dome猫|  楼主 | 2022-1-25 15:23 | 只看该作者
对于数据包格式,此等的使用规划:

#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

使用特权

评论回复
7
9dome猫|  楼主 | 2022-1-25 15:24 | 只看该作者
对于此处我所使用的"<bbhhhh",
第一个第二个数据为包头,便是b,字符串类型。而后面开始为数据格式,我选择的是h也就是短整型,传输给Stm32的时候,便是两个字节的数据格式。

使用特权

评论回复
8
9dome猫|  楼主 | 2022-1-25 15:25 | 只看该作者
如图,一串完整的数据便是 2C 12 36 00 80 00 2E 00 9D 00。

使用特权

评论回复
9
9dome猫|  楼主 | 2022-1-25 15:26 | 只看该作者
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

使用特权

评论回复
10
9dome猫|  楼主 | 2022-1-25 15:29 | 只看该作者
这段代码和之前不同的是:我将0x5B 最后一位的数据校验位改成了用sum_checkout() 这段函数求和取余的方法作为该数据的数据校验位。

使用特权

评论回复
11
9dome猫|  楼主 | 2022-1-25 15:30 | 只看该作者
但是使用这样不封包的方法发送,就必须加上data = bytearray(datalist),将数据转化,才可以进行通讯。

使用特权

评论回复
12
9dome猫|  楼主 | 2022-1-25 15:30 | 只看该作者
二、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

}

使用特权

评论回复
13
9dome猫|  楼主 | 2022-1-25 16:15 | 只看该作者
相比于平常配置并未存在较大差别,而实现通信的重要步骤是在USART1的串口接收中断中。

使用特权

评论回复
14
9dome猫|  楼主 | 2022-1-25 16:30 | 只看该作者
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);//清除中断标志
        }

}

使用特权

评论回复
15
9dome猫|  楼主 | 2022-1-25 16:32 | 只看该作者
其中定义了一个OpenMV_Rx_BUF[20]的数组来接收openmv发送过来的数据,需要使用extern修饰这个变量,以便于事项后续操作。

使用特权

评论回复
16
9dome猫|  楼主 | 2022-1-25 16:33 | 只看该作者
同时memcpy()函数也是十分重要的一个内置函数,可以实现两个数组的拷贝任务。

使用特权

评论回复
17
9dome猫|  楼主 | 2022-1-25 16:34 | 只看该作者
主函数的代码如下:

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);
                       

        }
}

使用特权

评论回复
18
9dome猫|  楼主 | 2022-1-25 16:38 | 只看该作者
前面就提到了,由于我数据包的格式设置问题,存入OpenMV_Rx_BUF[] 数组中的数据,真正有效的是第3、5、7、9位(因为选择了h类型数据格式,一个数据占2位)。

使用特权

评论回复
19
9dome猫|  楼主 | 2022-1-25 16:39 | 只看该作者
总结
博主我之前数据一直发送失败的原因是,博主使用了 uart.write() 这个函数,企图通过 uart.write() 这个函数实现数据发送。

使用特权

评论回复
20
9dome猫|  楼主 | 2022-1-25 16:40 | 只看该作者
这个函数在实现OpenMv和PC端的通信上没有问题,可以将数据打在串口调试助手上,但在其与Stm32的通信问题上就存在问题。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

135

主题

1427

帖子

2

粉丝