usartcar.h

```c
#ifndef __USARTCAR_H
#define __USARTCAR_H
#include "sys.h"
void uart2_init(u32 baudratetemp);
void uart3_init(u32 baudratetemp);
void sendByte(USART_TypeDef *USARTx,u16 byte);
void sendString(USART_TypeDef *USARTx,char *str);

#endif```
```c

usartcar.c

#include "usartcar.h"
#include "openmv.h"

#include "stdlib.h"
#include "stdarg.h"	 
#include "stdio.h"
#include "string.h"

//D5  D6
void uart2_init(u32 baudratetemp)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure; 

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);  //需要修改

	GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_USART2); //需要修改
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_USART2); //需要修改 
	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_5|GPIO_Pin_6; //需要修改
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_Init(GPIOD, &GPIO_InitStructure);  //需要修改
	
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	USART_InitStructure.USART_BaudRate =baudratetemp; 
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  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(USART2, &USART_InitStructure); 	
	
	USART_ClearITPendingBit(USART2,USART_IT_TC);
	USART_ClearITPendingBit(USART2,USART_IT_RXNE);
	USART_ClearFlag(USART2,USART_FLAG_ORE);  //溢出中断,注意这个中断的问题。
	USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
  USART_Cmd(USART2, ENABLE);	
	
}
	
//***********          PD8,PD9
void uart3_init(u32 baudratetemp)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure; 

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); //需要修改
	GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_USART3); //需要修改
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_USART3);//需要修改
	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_8|GPIO_Pin_9;  //需要修改
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	
	GPIO_Init(GPIOD, &GPIO_InitStructure);  //需要修改
		
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);	

	USART_ClearITPendingBit(USART3,USART_IT_TC);
	USART_ClearITPendingBit(USART3,USART_IT_RXNE);
	USART_ClearFlag(USART3,USART_FLAG_ORE); 
	USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);	
	USART_Cmd(USART3, ENABLE);
	
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
	USART_InitStructure.USART_BaudRate =baudratetemp; 
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  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(USART3, &USART_InitStructure); 	
	
	USART_ClearITPendingBit(USART3,USART_IT_TC);
	USART_ClearITPendingBit(USART3,USART_IT_RXNE);
	USART_ClearFlag(USART3,USART_FLAG_ORE);  //溢出中断,注意这个中断的问题。
	USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
  USART_Cmd(USART3, ENABLE);	
	
}

//查询发送,不用TC中断发送
void sendByte(USART_TypeDef *USARTx,u16 byte)
{
	USART_SendData(USARTx,byte);
	while(USART_GetFlagStatus(USARTx,USART_FLAG_TC) == RESET);//发送完成标志位
	USART_ClearFlag(USARTx,USART_FLAG_TC);	
}
//查询方式,发送字符串
void sendString(USART_TypeDef *USARTx,char *str)
{
	while(*str)
	{
			sendByte(USARTx,*str++);
	}	
}

//串口2的中断函数
void USART2_IRQHandler(void)         
{
	if(USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET)
	{
		USART_ClearITPendingBit(USART2,USART_IT_RXNE);
	  Openmv_Usart_Rx_Irq((u8)USART_ReceiveData(USART2));//将串口的数据和接收的绑定
	}	

	if(USART_GetFlagStatus(USART2,USART_FLAG_ORE)==SET) 
  { 
    USART_ClearFlag(USART2,USART_FLAG_ORE); 
  }

}

openmv.h

#ifndef __OPENMV_H
#define __OPENMV_H
#include "sys.h"
//结构体,材料物体属性,坐标,中心坐标,角度,等参数
typedef struct 
{
	float x;
	float y;
	float cx;
	float cy;
	float angle;
  int a;
}materials_blob;
extern materials_blob materials;   //材料定义成员

#define openmv_Rx_Length 		100     		//接收最长数据
#define openmv_UART 				USART2	     //绑定串口2
extern u8 openmv_rx_data[openmv_Rx_Length];  //接收缓冲区

void send_to_Openmv(char *str);  //发送字符串,通过串口2
void Openmv_Usart_Rx_Irq(u8 data);   //发送中断绑定函数
void Clear_Openmv_Rxbuff(void);      //清除串口接收缓冲区
u8 Judge_Openmv_Response(char* fmt,...);  //判断字符串接收,和约定的对比

u8 Get_Openmv_Materials_XY(materials_blob *blob);  //获取数据,按照指定格式分配
u8 Get_Openmv_Materials_Labels_Size(u8 *input_label,s32 *input_size);  //获取数据,按照指定格式分配
u8 Get_Openmv_Lighting(u8 *input_lighting); //获取数据,单个变量,按照指定格式分配
u8 Get_Openmv_Angle(u8 input_angle[]); //获取数据,数组,按照指定格式分配    
#endif

openmv.c

#include "openmv.h"
#include "usartcar.h"
#include "stdlib.h"
#include "stdarg.h"	 
#include "stdio.h"
#include "string.h"


materials_blob 	materials;    //声明一个材料的结构体成员

//0x0d和0x0a作为结束符
#define openmv_END_CODE_Before		0x0D   //OPENMV的接收结束前一个字节
#define openmv_END_CODE 					0x0a   //openmv的接收结束字节
u8 openmv_rx_data[openmv_Rx_Length];    //openmv接收缓冲区
u8 openmv_length_i=0;  //接收的长度,指针
u8 openmv_rx_flag=0;  //接收一帧的标记


//openmv接收中断绑定函数,,,串口2的中断函数绑定的
void Openmv_Usart_Rx_Irq(u8 recvdata)
{
	openmv_rx_data[openmv_length_i]=recvdata;  //将接收的数据,放到缓冲区中
	//以0x0D,0x0A作为结束符,如果接收的字符是最后一个字符,验证一下
	//再判断接收的上一个字符,是不是约定的字符,双层验证,确保OK。
	//两次验证都通过,那么认为接收到一帧数据,标记位等于1,同时清空接收长度指针
	if(openmv_rx_data[openmv_length_i]==openmv_END_CODE) 
	{
		if(openmv_rx_data[openmv_length_i-1]==openmv_END_CODE_Before) 
		{
			openmv_rx_flag=1;
			openmv_length_i=0;
		}
	}
	else    //如果接收的数据不是结束字符,那么接收指针加一,判断接收的长度,有没有超过
	{
		openmv_length_i++;
		if(openmv_length_i>openmv_Rx_Length-1) openmv_length_i=0;
	}
}


//清楚openmv接收缓冲区,让标记位全部清空,相当于接收复位。
void Clear_Openmv_Rxbuff(void)
{
	u8 i;
	for(i=0;i<openmv_Rx_Length;i++)
	{
		openmv_rx_data[i]=0;
	}
	openmv_length_i=0;
	openmv_rx_flag=0;
}
//判断openmv发送过来的数据;不定长接收的方法
//(Judge_Openmv_Response("OK"))
//返回1,判断成;回0,判断失败
u8 Judge_Openmv_Response(char* fmt,...)
{
	char p[100];   //定义一个缓冲区
	va_list ap;
	//如果接收到一帧数据,才进行后面的,否则,返回0,结束当前的函数
	if(!openmv_rx_flag) return 0; 
  
	va_start(ap,fmt);  //fmt指针和ap对应
	vsprintf((char*)p,fmt,ap); //将fmt指针对应的字符串,放到p指针对应的缓冲区中
	va_end(ap); //转换完成之后,结束va
	//字符串对比函数,将openmv接收缓冲区的字符串和p指针对应缓冲区,对比,
	//如果两者对比结果为null,那么就返回0,
	//否则,就返回1
	if(strstr((char*)openmv_rx_data,p)==NULL) return 0;
	else return 1;
}

/*

*/
u8 Get_Openmv_Materials_XY(materials_blob *blob)
{
	int x,y,a,cx,cy;
	if(!openmv_rx_flag) return 0;    //如果没有接收到一帧数据,那么返回0,结束当前函数;
	
	//将接收的字符串,按照指定的格式,赋值给对应的变量
	sscanf((char *)openmv_rx_data,"x:%d,y:%d,a:%d,cx:%d,cy:%d",&x,&y,&a,&cx,&cy);
	
	//将取得的变量数据,放到结构体中的内容中;
	blob->x=(float)(x-0);
	blob->y=(float)(y-0);
	blob->a=a;
	blob->cx=(float)(cx-0);
	blob->cy=(float)(cy-0);
	return 1;//同时返回一个判断结果1
}

u8 Get_Openmv_Materials_Labels_Size(u8 *input_label,s32 *input_size)
{
	s32 label_;
	s32 size_;
	if(!openmv_rx_flag) return 0;
	sscanf((const char *)openmv_rx_data,"l:%da:%d",&label_,&size_);
	*input_label=(u8)label_;
	*input_size=(u32)size_;
	return 1;
}

u8 Get_Openmv_Lighting(u8 *input_lighting)
{
	s32 lighting_;
	if(!openmv_rx_flag) 
	{
	  return 0;
	}
	sscanf((const char *)openmv_rx_data,"%d",&lighting_);
	*input_lighting=(u8)lighting_;
	return 1;
}


u8 Get_Openmv_Angle(u8 input_angle[])
{
	s32 angle_[3];
	if(!openmv_rx_flag) return 0;
	sscanf((const char *)openmv_rx_data,"lr:%d,ud:%d,an:%d",&angle_[0],&angle_[1],&angle_[2]);
	input_angle[0]=(u8)angle_[0];
	input_angle[1]=(u8)angle_[1];
	input_angle[2]=(u8)angle_[2];
	return 1;
}
	
void send_to_Openmv(char *str)
{
   sendString(openmv_UART,str);
}

407-串口2open...mv。。。。代码和stm代码_单片机

中断设置函数,可以放在sys中。

void Set_Nvic_Irq(u8 Channel,u8 PreemptionPriority,u8 SubPriority)
{
	NVIC_InitTypeDef NVIC_Structure;
	NVIC_Structure.NVIC_IRQChannel=Channel;
	NVIC_Structure.NVIC_IRQChannelPreemptionPriority=PreemptionPriority;
	NVIC_Structure.NVIC_IRQChannelSubPriority=SubPriority;
	NVIC_Structure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_Structure);
}

主函数main.c

#include "sys.h"

#include "usart.h"
#include "delay.h"
#include "led.h"
#include "beep.h"
#include "key.h"
#include "BaseTimX.h"
#include "usartcar.h"
#include "openmv.h"
# include <stdio.h>
# include <string.h>
int main(void)
{
	u8 angle[3];
  char temp[50];
	int back_count=0;
	u8 lighting=100;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//中断分组第四组 高优先打断低优先
	Set_Nvic_Irq(USART2_IRQn,0,0);
	Set_Nvic_Irq(USART3_IRQn,0,0);
	Set_Nvic_Irq(TIM6_DAC_IRQn,4,0);//一定注意,
	//delay_ms(500);这个最多延时500ms,切记
	Delay_Init(); 
	LED_Init();
	//包括串口2和串口3,串口2是OPENMV接口,PA2和PA3
	uart2_init(115200);
	uart3_init(115200);

	
	LED0 =0 ;delay_ms(300);
	LED0 =1 ;delay_ms(300);
	LED0 =0 ;delay_ms(300);
	LED0 =1 ;delay_ms(300);
	LED0 =0 ;delay_ms(300);
	LED0 =1 ;delay_ms(300);
	LED0 =0 ;delay_ms(300);
	LED0 =1 ;delay_ms(300);
	BaseTim6_Init();
	delay_ms(300);
  TIM_Cmd(BASIC_TIM6, ENABLE);
	while(1)
	{
		
		//************************************************第一段测试,测试接收
		/*
		stm32发送&light给openmv, 
		openmv发送一个整数和回车换行,比如0x35,0x0D,0x0a给stm32,记得有回车换行符号;
		stm32等待2.5s,等待应答信号,检测是不是接收成功。超时,就算了。在里面可以增加自己的逻辑。
		比如,如果没有应答,蜂鸣器响,然后不断检测,不断检测,死机在这一个步骤里面。
		*/
    //清空接收的缓冲区,等待接收
		Clear_Openmv_Rxbuff();
		//发送light命令
		send_to_Openmv("&light\r\n");
		//背后计数从0开始,等待应答,超时应答
		back_count=0;
		// 等待接收数据
		while(!Get_Openmv_Lighting(&lighting))
		{
			delay_ms(50);   //延时50ms
			back_count++;
			if(back_count>50) 
			{
				send_to_Openmv("NO light ack\r\n");
			  break;
			}
		}
		
    delay_ms(10);
		if(lighting == 2)
		{
			lighting=100;
		  send_to_Openmv("light ==2\r\n");
		}
		else if(lighting == 0)
		{
			lighting=100;
		  send_to_Openmv("light ==0\r\n");
		}
		delay_ms(300);
		
		//********************************************************第一步测试结束。
	

//*************************第二段测试,发送angle=1给openmv,等到openmv按照指定格式回传信息;	
/*
 	sscanf((const char *)openmv_rx_data,"lr:%d,ud:%d,an:%d",&angle_[0],&angle_[1],&angle_[2]);
  lr:%d,ud:%d,an:%d
*/		
  memset(temp, 0, sizeof(temp));   //清空命令缓冲区
	sprintf(temp,"angle=%d\r\n",1);  //填上命令
	//演示获取角度
	Clear_Openmv_Rxbuff();   //清空接收缓冲区
  send_to_Openmv(temp);    //将命令发送
	back_count=0;             //时间计数清0
	while(!Get_Openmv_Angle(angle))    //等待回传的字符串,超时等待,代码可以修改。
	{
		delay_ms(5);
		back_count++;
		if(back_count>300) break;
	}
	
	
//*********************第三段测试,延时获取三个角度
/*
   发送 angle0=%d,angle1=%d,angle2=%d\r\n给openmv;
	
*/	
  memset(temp, 0, sizeof(temp));    //清空发送缓冲区
	sprintf(temp,"angle0=%d,angle1=%d,angle2=%d\r\n",angle[0],angle[1],angle[2]);  //整理字符串
	send_to_Openmv(temp); //发送字符串给openmv
		
	delay_ms(500);   //等待两秒
	delay_ms(500);
	delay_ms(500);
	delay_ms(500);
	
//*********************第4段测试,  	//演示获取材料属性  
	
	//演示获取材料属性   x:127,y:72,a:67,cx:178,cy:200
	Clear_Openmv_Rxbuff();  //清空接收缓冲区
	back_count=0;           //超时次数清0
	send_to_Openmv("&material\r\n");  //给openmv发送命令字符串
	while(!Get_Openmv_Materials_XY(&materials))       //等待材料信息
	{
		delay_ms(5);
		back_count++;
		if(back_count>300) break;
	}
	//sscanf(( char *)openmv_rx_data,"x:%d,y:%d,a:%d,cx:%d,cy:%d",&x,&y,&a,&cx,&cy);

	//将接收的信息,发给openmv,也是个串口助手,显示信息。
  memset(temp, 0, sizeof(temp));
	sprintf(temp,"x=%0.2f,y=%0.2f,cx=%0.2f,cy=%0.2f\r\n",materials.x,materials.y,materials.cx,materials.cy);
	send_to_Openmv(temp);
	delay_ms(50);//必须要添加这个延时,不然不正常。
	
	//**********************************************第5段测试, 测试openmv有没有发送ok回来。
	 memset(temp, 0, sizeof(temp));
	//演示judge
  if(Judge_Openmv_Response("OK"))//判断
		{
			Clear_Openmv_Rxbuff();
			send_to_Openmv("OKK0\r\n");
		}
	delay_ms(300);			
	}
}

openmv代码

import sensor, image, time
from pyb import UART
from pyb import Pin, Timer, LED


import re

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)

uart=UART(1,115200)  #PA9 txd   PA10--rxd 微翻版OPENMV接口PA9和PA10就好。
#uart = UART(3, 9600)  #正式openmv的接口P4和P5
uart.init(115200, bits=8, parity=None, stop=1) # init with given parameters timeout_char=1000
clock = time.clock()


#def tick(timer):
    #Uart_recv()
##5ms读取一次检测一次串口,t=5ms f=1/t=200hz
#tim = Timer(3, freq=200)      # create a timer object using timer 2 - trigger at 1Hz
#tim.callback(tick)          # set the callback to our tick function

g_uart_cmdA_flag=0   # 将变量声明为全局变量,如此才可改变其数值
g_uart_cmdB_flag=0
#*********************************************************************************************
#串口接收函数的定义
def Uart_recv():  # 串口接收数据
    global g_uart_cmdA_flag
    global g_uart_cmdB_flag
    if (uart.any()):   # 更新串口接收数据
        recv_data = eval(str(uart.read()))  #接收读取的字符串
        print(recv_data)
        #uart.write(recv_data)
        if ("&" in recv_data) :  #如果接收的字符串中有&号。注意,这个不是第一个字符串,只要有&就行,可以修改下,检查帧头
            print("Openmv has recved CMD data.")
            if ("lightA" in recv_data): #如果接收字符串有light1,比如&light1
                print(len(recv_data))
                g_uart_cmdA_flag = 1
                print("Ready for light 1!")
## &lightA0 或者&lightA99 提取A后面的数据,必须是正数,后面不能加换行符号,否则长度改变
## 字符串的下标计数从0开始,它是一个标记特殊的list(数据结构会讲到)
                if len(recv_data)>8:
                    ddd=(int(recv_data[7])-48)*10
                    ddd=ddd+(int(recv_data[8])-48)
                    print(ddd)
                elif len(recv_data)==8:
                    ddd=(int(recv_data[7])-48)
                    print(ddd)


            if ("lightB1" in recv_data):#如果接收字符串有B,比如&B
                g_uart_cmdB_flag = 1
                print("Ready for B!")
#*********************************************************************************************
#定义两个数据,测试发送
adata =10.2
bdata =123
#定义两个数据,测试发送
cdata=88.65
ddata=896
while(True):
    clock.tick()
    img = sensor.snapshot()
    Uart_recv() #主函数中不断检测,可以在串口中断中进行接收,或者是开辟一个定时器,定时5ms-10ms检查一次这个函数(这方法好像有问题,定时器的),
    if g_uart_cmdA_flag ==1  :  #命令A的回应
       # uart.write("loc"+(str)adata+"num"+(str)bdata+"#")   # 串口发送
        uart.write("adata:%0.2f,bdata:%d\r\n"%(adata,bdata)) #发送字符串,字符串中包括了数据,数据可以根据检测得到,浮点数或者是整数
        g_uart_cmdA_flag = 0
    if g_uart_cmdB_flag ==1  : #命令B的回应
        uart.write("cdata:%0.2f,ddata:%d\r\n"%(cdata,ddata))#发送字符串,字符串中包括了数据,数据可以根据检测得到,浮点数或者是整数
        g_uart_cmdB_flag = 0
    time.sleep(100)