前言
(1)继上一篇:2022年十月份电赛OpenMV巡线方案详细代码分析(1)
(2)这个代码适用于所有主控,只需要更改一下串口接收部分的API,别问我某某MCU能不能跑的这种废话!
(3)本文使用的协议与正点原子的串口通讯协议一致,看不懂的建议学一下正点原子的那个串口通讯协议。
(4)最后强调一边:本文的代码是伪代码!也就是说,不能够直接使用!需要灵活变更!
主控代码及讲解
main.c
(1)我们OpenMV的数据最终会存放在16bit_state.state和5bit_state.state。16bit_state.state存放横向16bit的数据,5bit_state.state存放右侧的5bit的数据。我们可以根据这个参数来判断不同的情况。
(2)需要注意的一点是,每次OpenMV_data_read()函数之后,16bit_state.state和5bit_state.state这两个数据才会更新。否则一直是一个数值。
(3)OpenMV_data_read()函数有一个返回值,如果有数据更新,那么就会返回1,没有数据更新就会返回0。你们可以根据自己的需求看要不要利用上这个返回值。
#include "bsp_OpenMV.h" void main() { while(1) { OpenMV_data_read(); //读取OpenMV的数据,有返回值,但是我没有进行处理 switch(16bit_state.state) //OpenMV横向16个数据的处理 { case 0x01: break; case 0x02: break; default: break; } switch(5bit_state.state) //OpenMV纵向5个数据的处理 { case 0x01: break; case 0x02: break; default: break; } } }
user_interrupt.c
(1)我一般喜欢用一个user_interrupt.c文件存放所有的中断程序。
(2)这里你只需要做一件事情,将获得到8bit数据传入OpenMV_agreement_receive()函数里面。
#include "bsp_OpenMV.h" void UARTx_IRQHandler(void) { //...是你这一款MCU的串口接收函数 uint8_t UARTx_recevie= ...; //将接收到的数据进行协议处理 OpenMV_agreement_receive(UARTx_recevie); }
bsp_OpenMV.h
#ifndef _bsp_openmv__H #define _bsp_openmv__H /***** 参数宏定义 *******/ #define USART_REC_LEN 5 //定义最大接收字节数 5 /***** 变量外部使用声明 *******/ extern _gray_state 16bit_state,5bit_state; //用于记录OpenMV传输过来的值 /***** 结构体声明 *******/ typedef struct { uint8_t bit1 :1; uint8_t bit2 :1; uint8_t bit3 :1; uint8_t bit4 :1; uint8_t bit5 :1; uint8_t bit6 :1; uint8_t bit7 :1; uint8_t bit8 :1; uint8_t bit9 :1; uint8_t bit10 :1; uint8_t bit11 :1; uint8_t bit12 :1; uint8_t bit13 :1; uint8_t bit14 :1; uint8_t bit15 :1; uint8_t bit16 :1; }gray_flags; //位域,将黑线信息都存放进一个16bit的数据中 typedef union //共用体,可以利用这两个值来判断巡线状态 { gray_flags gray; uint16_t state; }_gray_state; /***** 函数声明 *******/ void OpenMV_agreement_receive(uint8_t OpenMV_recevie); //OpenMV数据协议 int OpenMV_receive_if_finish(void); //判断是否与OpenMV通讯完成 int OpenMV_data_read(void); //读取OpenMV的值 #endif
bsp_OpenMV.c
(1)OpenMV_data_read()这个c文件,我们只需要关注这个函数。
<1>因为2022年十月份电赛OpenMV巡线方案详细代码分析(1)中设置了,OpenMV会给主控发送3个字节数据。所以我这里的OpenMV_receive_if_finish() == 3进行判断,看看是否接收到了3个字节数据。如果不是3个字节的数据,那么就说明数据传输未完成,或者是出现了问题。
<2> 因为上一篇文章里面,OpenMV是先传输高8位的数据,所以这里需要USART_RX_BUF[0] << 8,然后再‘|’。
<3>依旧是要根据上一篇文章,我们知道第三个数据才是右侧横向5bit数据,所以5bit.state = USART_RX_BUF[2];
<4>数据处理完之后,需要清空标志位USART_RX_STA。
(2)这里的OpenMV_receive_if_finish()函数和OpenMV_agreement_receive()不要进行更改!我已经给你们封装好了,如果看不懂的,请自己去看正点原子的串口通讯教程!
(3)USART_RX_STA是标志位,用于存放如下注释中的数据。因为我已经使用OpenMV_receive_if_finish()函数进行了封装,所以这个常量你不知道没有事情。
/* ============================================================================================================= USART_RX_STA ============================================================================================================= bit15 | bit14 | bit13--bit0 ============================================================================================================= 接收完成标志位(0x0A,换行键) | 接收到0x0d(回车键) | 接收到的有效数据个数 ============================================================================================================= */ uint16_t USART_RX_STA = 0; //接收状态标记 uint8_t USART_RX_BUF[USART_REC_LEN] = {0}; //存放接收到的OpenMV数据 /* 作用 : OpenMV数据协议 * 传入参数 : OpenMV_recevie : 将串口接受中断的uint8_t数据传入 * 返回参数 : 无 */ void OpenMV_agreement_receive(uint8_t OpenMV_recevie) { if((USART_RX_STA&0x8000)==0) //bit15没有被置为1,接收未完成 { if(USART_RX_STA&0x4000) //bit14被置为1,表示接收到了'\n'(0x0d) { if((OpenMV_recevie)!=0x0a)USART_RX_STA=0; //如果bit14被置1了,但是bit15并不是换行操作,表示接收错误,重新开始 else USART_RX_STA|=0x8000; //接收完成了 } else //还没收到'\n'(0x0d) { if((OpenMV_recevie)==0x0d)USART_RX_STA|=0x4000; //如果接收到了'\n'(0x0d),bit14被置为1 else { USART_RX_BUF[USART_RX_STA&0x3FFF]=OpenMV_recevie; //如果没有接收到结束标志,继续将数据写入USART_RX_BUF[] USART_RX_STA++; if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0; //如果接收到的数据大于定义最大接收字节数,表示接收数据错误,重新开始接收 } } } } /* 作用 : 判断是否与OpenMV通讯完成 * 传入参数 : 无 * 返回参数 : 如果与OpenMV通讯完成,返回接收到的字符数量。否则返回0 */ int OpenMV_receive_if_finish(void) { if(USART_RX_STA & 0x8000) //如果接收完成 { return USART_RX_STA&0x3fff; } return 0; //没有接收完成返回错误 } /* 作用 : 读取OpenMV的数据 * 传入参数 : 无 * 返回参数 : 如果成功读取到了数据,返回1。否则返回0。 */ _gray_state 16bit_state,5bit_state; //用于记录OpenMV传输过来的值 int OpenMV_data_read(void) { if(OpenMV_receive_if_finish() == 3)//如果串口接收到三个数据,表示OpenMV发送数据完成 { 16bit.state = (USART_RX_BUF[0] << 8 | (USART_RX_BUF[1])); //处理OpenMV的横线16路数据 5bit.state = USART_RX_BUF[2]; //处理OpenMV的纵线5路数据 USART_RX_STA=0; //标志位清零 return 1; } return 0; }
总结
(1)你需要变动的地方
<1>user_interrupt.c的串口中断里面,写入当前MCU的串口接收函数。
<2>OpenMV_data_read()根据需求进行调整。
<3>看看main.c,根据需求编写main.c