当前位置:   article > 正文

OpenMv和STM32通信_用xcom串口调试助手让openmv串口发送到32

用xcom串口调试助手让openmv串口发送到32

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)







  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97

代码作用: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);                           #串口发送
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

这里使用了数据包的形式发送数据,将一帧的数据包装,并发送给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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

对于此处我所使用的"<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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这段代码和之前不同的是:我将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 

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

相比于平常配置并未存在较大差别,而实现通信的重要步骤是在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);//清除中断标志
	}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

其中定义了一个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);
			

	} 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

前面就提到了,由于我数据包的格式设置问题,存入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)
  • 1
  • 2
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/474086
推荐阅读
相关标签
  

闽ICP备14008679号