写在前面
备战2024电赛,使用到了TI开发板,型号MSPM0G3507,该开发板除文档外,网上资料稀少。
现在为大家提供uart通信openmv视觉模块的代码,以促共同进步。
该代码由本人编写,转载请标明来源。
代码亲测成功,如有bug欢迎评论区指正。
头文件
openmv.h
#ifndef OPENMV_H
#define OPENMV_H
#include "../COMMON.h"
#define SELF_CHECK_CMD 0x1A
#define STOP_CMD 0x1C
#define TIME_OUT 0xFF
#define END1 0x01
#define END2 0xFE
#define END3 0xFF
uint8_t openmv_init();
void openmv_cmd(uint8_t cmd , uint8_t (*func)(uint8_t*));
float openmv_parse_float(uint8_t* data,uint8_t* index);
int openmv_parse_int(uint8_t* data, uint8_t* index);
const char* openmv_parse_string(uint8_t* data, uint8_t* index);
uint8_t openmv_parse_byte(uint8_t* data, uint8_t* index);
#define OMB(d,i) openmv_parse_byte((data),&(i))
#define OMF(d,i) openmv_parse_float((data),&(i))
#define OMI(d,i) openmv_parse_int((data),&(i))
#define OMS(d,i) openmv_parse_string((data),&(i))
#endif
源文件
#include "OpenMv.h"
uint8_t openmv_init(){
DL_UART_transmitData(OPENMV_INST,SELF_CHECK_CMD);
while (DL_UART_isBusy(OPENMV_INST));
system_delay_ms(100);
uint8_t data = 0;
uint8_t time = 0;
while (data != 0x1B) {
if(time++ >= TIME_OUT)return 0;
data = DL_UART_receiveDataBlocking(OPENMV_INST);
}
return 1;
}
void openmv_cmd(uint8_t cmd , uint8_t (*func)(uint8_t*)){
DL_UART_transmitData(OPENMV_INST,cmd);
while (DL_UART_isBusy(OPENMV_INST));
system_delay_ms(100);
uint8_t loop_flag = 1;
uint8_t data[128];
while (loop_flag){
DL_UART_receiveDataBlocking(OPENMV_INST);
uint8_t temp = DL_UART_receiveDataBlocking(OPENMV_INST);
uint8_t last_temp = 0;
uint8_t last_last_temp = 0;
uint8_t i = 0;
while (!(temp==END3&&last_temp==END2&&last_last_temp==END1)){
data[i++] = temp;
last_last_temp = last_temp;
last_temp = temp;
temp = DL_UART_receiveDataBlocking(OPENMV_INST);
}
loop_flag = func(data);
system_delay_ms(50);
}
DL_UART_transmitData(OPENMV_INST,STOP_CMD);
while (DL_UART_isBusy(OPENMV_INST));
system_delay_ms(100);
}
int openmv_parse_int(uint8_t* data, uint8_t* index) {
int i = (int)(
((int32_t)data[*index]) |
((int32_t)data[*index + 1] << 8) |
((int32_t)data[*index + 2] << 16) |
((int32_t)data[*index + 3] << 24)
);
*index +=4;
return i;
}
float openmv_parse_float(uint8_t* data,uint8_t* index){
union {
uint32_t i;
float f;
} u;
u.i = ((uint32_t)data[*index]) |
((uint32_t)data[*index + 1] << 8) |
((uint32_t)data[*index + 2] << 16) |
((uint32_t)data[*index + 3] << 24);
*index +=4;
return u.f;
}
const char* openmv_parse_string(uint8_t* data, uint8_t* index) {
const char* str = (const char*)(data + *index);
uint8_t length = 0;
while (data[*index + length] != '\0') {
length++;
}
*index += length + 1;
return str;
}
uint8_t openmv_parse_byte(uint8_t* data, uint8_t* index){
*index+=1;
return data[*index];
}
测试代码
1.ti-mspmg3507
#include "Library/COMMON.h"
uint8_t openmv_func_tftchar(uint8_t* data){
static uint8_t num = 0;
uint8_t ptr = 0;
num++;
tft180_show_int(0, 20, OMI(data,ptr),3);
tft180_show_string(0, 40, OMS(data, ptr));
tft180_show_float(0, 60, OMF(data,ptr),3,3);
tft180_show_int(0, 80, OMB(data,ptr),3);
system_delay_ms(3000);
tft180_clear();
if(num==5){
num = 0;
return 0;
}
else return 1;
}
int main(void)
{
SYSCFG_DL_init();
tft180_init();
tft180_show_int(0, 0, openmv_init(),3);
openmv_cmd(0xe0, openmv_func_tftchar);
while (1) {
system_delay_ms(500);
}
}
2.openmv
import time,random,struct
from pyb import UART,LED
uart = UART(3, 19200, timeout_char=1000)
def blink(i,n,t):
for _ in range(0,n):
LED(i).on();
time.sleep_ms(t);
LED(i).off();
time.sleep_ms(t);
def send_float(f):
uart.write(struct.pack('f', f))
def send_int(i):
uart.write(struct.pack('i', i))
def send_string(s):
uart.write(s+'\0')
def send_byte(b):
uart.write(bytes([b]))
def send_end():
uart.write(b'\x01\xfe\xff')
tft_flag = 0
while(True):
a = uart.readchar()
if a == 28:
tft_flag = 0
blink(1, 1, 200)
elif a == 224 or tft_flag:
tft_flag = 1
send_int(-255)
send_string("Hello,World!")
send_float(255.51)
send_end()
elif a == 26:
blink(2, 3, 200)
uart.write(bytes([0x1b]))
time.sleep_ms(50)
配置与使用说明
配置
一个UART,命名为OPENMV
注意波特率要与openmv端的一致,上述例子中为19200
如何使用?
1.连接验证
如果你的openmv端与示例代码一致
连接好openmv与ti单片机后启动ti,若openmv端绿灯闪烁3次并且ti单片机屏幕第一行显示1说明连接成功
2.命令注册
void openmv_cmd(uint8_t cmd , uint8_t (*func)(uint8_t*))
通过此函数进行命令的注册,其作用是当openmv接收到cmd命令时,执行相应的逻辑并返回数据,func回调函数将对数据进行处理。正如定义中的参数类型所示,func将接收到数据数组,并返回一个是否应该令openmv结束当前逻辑的标志
如示例中openmv_func_tftchar便是一个func
uint8_t openmv_func_tftchar(uint8_t* data)
和
openmv_cmd(0xe0, openmv_func_tftchar);
以及
if(num==5){
num = 0;
return 0;
}
else return 1;
很显然使用者只需关注命令值,对数据执行的逻辑以及何时结束即可,而不需要关注数据传输具体的细节
3.数据发送与解析
在openmv端使用以下四个函数即可完成大部分常用数据的发送,发送后一定要发送调用send_end
帧尾标记结束
def send_float(f):
uart.write(struct.pack('f', f))
def send_int(i):
uart.write(struct.pack('i', i))
def send_string(s):
uart.write(s+'\0')
def send_byte(b):
uart.write(bytes([b]))
def send_end():
uart.write(b'\x01\xfe\xff')
而在ti单片机端func函数内的数据解析则可以由以下三个函数进行 (注意data不包括帧尾只包括数据)
float openmv_parse_float(uint8_t* data,uint8_t* index);
int openmv_parse_int(uint8_t* data, uint8_t* index);
const char* openmv_parse_string(uint8_t* data, uint8_t* index);
uint8_t openmv_parse_byte(uint8_t* data, uint8_t* index);
只需要关注数据发送的顺序就可以完成相应的解析,index
用于获取不同类型数据块解析的起始,每次解析后将指向data
数组当前数据后面的位置。
index指向的值初始为0,比如说数据类型是"string–>int–>float"
先调用openmv_parse_string,那么index指向的值就会变为字符串结束后的下一位,即int的开始,此时又可以直接调用openmv_parse_int,紧接着是openmv_parse_float,完成所有数据的接收。