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);
}
中断设置函数,可以放在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)