本文主要是介绍第四章(先学习第五章)-openmv和arduino和stm32的通信,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
4.1-openmv与arduino通信
https://www.bilibili.com/video/BV1VK411j733/?vd_source=16940ba3adbc66f0fb14e0c1d87db878
json
通信 控制一个lED. 0:关,1:开
控制两个LED灯 LED1 0 LED2 1 LED3 0
X:1 Y:8 (1,8)
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,以易于阅读和编写的文本格式表示结构化数据。它由键值对组成,其中键是字符串,值可以是字符串、数字、布尔值、对象、数组或者 null。
JSON 数据格式由以下几个基本规则组成:
- 键值对:键值对由键和值组成,用冒号
:
分隔。键是字符串,值可以是字符串、数字、布尔值、对象、数组或 null。示例:"key": "value"
- 对象(Object):对象由一系列键值对组成,用花括号
{}
包围。示例:{"key1": "value1", "key2": "value2"}
- 数组(Array):数组是一个有序的值列表,用方括号
[]
包围。示例:["value1", "value2", "value3"]
- 值可以是嵌套的对象或数组。示例:
{"key": ["value1", {"nested_key": "nested_value"}]}
- JSON 数据必须使用双引号
"
来包围字符串值。示例:{"key": "value"}
- JSON 文件的 MIME 类型是
application/json
。
arduino-需要再次确定 效果一般
这里我们使用arduino进行通信。
下面是arduino的代码,代码中使用了json 所以我们要安装一下json 的库。
上传到板子
带注释的代码
#include <ArduinoJson.h>
#include <SoftwareSerial.h>SoftwareSerial softSerial(10, 11); // 创建一个软串口对象,用于与其他设备通信(传输数据)10是Arduino板子的RX 11是Arduino板子上午TX 记得还需要连接GND引脚。
volatile int left; // 定义一个全局变量,用于存储左边的值
volatile int right; // 定义一个全局变量,用于存储右边的值
volatile char c; // 定义一个全局变量,用于存储接收到的字符
String json; // 定义一个字符串变量,用于存储接收到的JSON数据void setup(){left = 0; // 初始化左边的值为0right = 0; // 初始化右边的值为0c = 0; // 初始化接收到的字符为0json = ""; // 初始化接收到的JSON数据为空字符串Serial.begin(115200); // 初始化串口通信,波特率为115200softSerial.begin(115200); // 初始化软串口通信,波特率为115200
}void loop(){if (softSerial.available() > 0) { // 如果软串口中有数据可读取c = char(softSerial.read()); // 读取一个字符json = String(json) + String(c); // 将读取的字符添加到接收到的JSON数据字符串中if (c == '}') { // 判断是否接收到了完整的JSON数据DynamicJsonDocument doc(200); // 创建一个大小为200的JsonDocument对象deserializeJson(doc, json); // 解析接收到的JSON数据JsonObject obj = doc.as<JsonObject>(); // 将解析后的JSON数据转换为JsonObject对象int left = doc["left"]; // 从JsonObject对象中获取左边的值int right = doc["right"]; // 从JsonObject对象中获取右边的值if (left!=0 && right!=0) { // 判断左右的值是否都不为0Serial.print("left = "); // 打印左边的值Serial.print(left);Serial.print("right = "); // 打印右边的值Serial.println(right);}json = ""; // 清空接收到的JSON数据字符串,为下一次接收做准备}}
}
我们把上述文件烧录到Arduino 板子
我们调试Arduino 看Arduino收到数据是否可以正确解析
Arduino 连接如下图:
使用串口软件模拟openmv 发送给Arduino JSON字符串
然后在Arduino IDE 串口监视器中查看解析的数据是否正确。
{"left":1,"right":28}
然后Arduino IDE中打开 串口监视器
openmv-需要再次确定 效果一般
下面我们用电脑接受openmv 执行的时候,openmv通过串口发送出的数据。
使用openmv H7 plus 执行一下代码
注意 openmv 和arduino 串口通信速率有限 所以我们需要加入一个延时。
import sensor, image, time # 导入sensor、image和time模块
import json # 导入json模块
import time
from pyb import Servo # 从pyb模块中导入Servo类
from pyb import UART # 从pyb模块中导入UART类
left = 1
right = 2sensor.reset() # 初始化摄像头传感器
sensor.set_pixformat(sensor.RGB565) # 设置像素格式为RGB565
sensor.set_framesize(sensor.QQVGA) # 设置帧大小为QQVGA以加快处理速度
sensor.skip_frames(10) # 跳过一些帧,让新设置生效
sensor.set_auto_whitebal(False) # 关闭自动白平衡功能
clock = time.clock() # 创建一个时钟对象,用于跟踪FPS(每秒帧数)
uart = UART(3, 115200) # 创建一个UART对象,用于串口通信 始化串口三、波特率115200 TXD:P4\PB10 RXD:P5\PB11while True:data = {"left": left,"right": right}right = right+1data_out = json.dumps(data) # 将数据转换为JSON字符串uart.write(data_out + '') # 通过串口发送数据print(data)time. sleep_ms(8) #延时8毫秒 串口通信速率有限,测试后发现这里需要延时8ms
然后我们执行代码,并将openmv连接到电脑连接TTL 模块到电脑
串口软件显示接受的数据
检查数据 格式是JSON 格式
openmv和arduino连接调试
4.2-openmv与STM32通信
openmv
openmv和STM32通信我们使用自己构造数据帧进行通信
连接方法按照下图
import pyb, sensor, image, math, time
from pyb import UART
import ustruct
from image import SEARCH_EX, SEARCH_DS
import time
import sensor, lcd
#导入需要的库和模块
#2.注意是否有下面两句根据自己摄像头调整#sensor.set_vflip(True)#sensor.set_hmirror(True)uart = UART(3,115200,bits=8, parity=None, stop=1, timeout_char = 1000)#初始化串口三、波特率115200 TXD:P4\PB10 RXD:P5\PB11sensor.reset()#初始化相机传感器。
sensor.set_pixformat(sensor.RGB565)#设置相机模块的像素模式:sensor.RGB565: 16 bits/像素。
sensor.set_framesize(sensor.QQVGA)#设置图像分辨率、如果改变分辨率也要调整ROI区域。摄像头不同、应用场景不同可以选择不同分辨率。这里使用QQVGA可能画质很胡,但是为了兼容不同型号摄像头我们先使用QQVGA 不影响循迹效果
sensor.skip_frames(time=2000)#跳过指定数目的帧。在这里,设置为跳过2000毫秒(即2秒)的帧。这样可以给传感器一些时间进行初始化和自适应调整。
sensor.set_auto_whitebal(True)#设置为自动白平衡模式。这使得摄像头可以根据场景中的光照条件自动调整图像的白平衡,从而保持图像色彩更加准确和自然。
sensor.set_auto_gain(False)#关闭自动增益模式。通常情况下,开启自动增益会帮助摄像头自动调整亮度,并在低亮度环境下提高图像清晰度。通过设置为False,禁用了这个功能,使用固定增益值。# 注意是否有下面两句根据自己摄像头调整
sensor.set_vflip(True) #垂直方向翻转 根据自己摄像头和模块安装位置调整 !!!重要不同摄像头是否需要镜像根据实际情况定,如果不需要镜像需要注释掉
sensor.set_hmirror(True) #水平方向反转 根据自己摄像头和模块安装位置调整 !!!重要不同摄像头是否需要镜像根据实际情况定,如果不需要镜像需要注释掉def send_five_uchar(c1,c2,c3,c4,c5):#功能发送五个整形global uart;data = ustruct.pack("<BBiiiiiB",#使用了 ustruct.pack() 函数将这些数据打包为二进制格式。使用 "<BBiiiiiB" 作为格式字符串来指定要打包的数据的类型和顺序:0xA5,0xA6,int(c1),int(c2),int(c3),int(c4),int(c5),0x5B)uart.write(data);#uart.write(data) 将打包好的二进制数据帧写入 UART 发送缓冲区,从而将数据通过串口发送出去print(data)#通过 print(data) 打印发送的数据到串行终端,方便调试和确认发送的内容。while(True):data=0flag = [0,0,0,0,0]flag[0] = 0flag[1] = 1flag[2] = -1flag[3] = 500flag[4] = -99print(flag[0],flag[1],flag[2],flag[3],flag[4])#把数据打印在串行终端方便调试send_five_uchar(flag[0],flag[1],flag[2],flag[3],flag[4])#把五个数据通过串口发送出去、发送五个无符号字符。time. sleep_ms(8) #延时8毫秒 串口通信速率有限,测试后发现这里需要延时8ms
STM32
这里延时如何使用STM32F103接收数据
我们使用HAL库新建工程
我们先新建一个工程(工程不能中午目录和中午名字)
设置调试下载接口
设置晶振
输入 72然后回车
初始化串口一
串口二是用于和摄像头通信的!!!!
另外初始化一下PC13
起一个名字
生成代码
先编写串口一 映射printf
#include "stdio.h"
/**
* @brief 重定向printf (重定向fputc),使用时候记得勾选上魔法棒->Target->UseMicro LIB 可能需要在C文件加typedef struct __FILE FILE;包含这个文件#include "stdio.h"
* @param
* @return
*/
int fputc(int ch,FILE *stream)
{HAL_UART_Transmit(&huart1,( uint8_t *)&ch,1,0xFFFF);return ch;
}
然后我们要继续编写STM32串口二接收数据,然后把解析的数据值通过串口一发送出去
我们先定义一个串口二接收数据变量
uint8_t g_ucUsart2ReceiveData; //保存串口二接收的数据
开启接收中断
HAL_UART_Receive_IT(&huart2,&g_ucUsart2ReceiveData,1); //串口二接收数据
声明一下变量
extern uint8_t g_ucUsart2ReceiveData; //保存串口二接收的数据
我们需要在串口中断回调函数中加入我们对接收到数据的解析
在usart.c文件中定义一个函数
/*******************
* @brief 摄像头串口协议解析函数 可以连接K210或openmv等
* @param data:串口接收到的每个字节
* @return
*
*******************/
void usartCamera_Receive_Data(uint8_t data)
{static uint8_t state = 0;//定义静态static 变量if(state==0&&data==0xA5) //判断第一个是不是帧头0xA5{state=1;//是帧头0xA5 赋值state=1 表示接收下一个数据//数据存储在数组中 "g_ucUsart2ReceivCounter++",这里是先用后加,比如g_ucUsart2ReceivCounter 初值为0,执行这个是先g_ucaUsart2ReceiveBuffer[0]=data,然后g_ucUsart2ReceivCounter++,即后g_ucUsart2ReceivCounter = 1的g_ucaUsart2ReceiveBuffer[g_ucUsart2ReceivCounter++] = data;}else if(state==1&&data==0xA6) //第二个是不是帧头0xA6{state=2;//如果第二个是帧头0xA6 赋值state=2 表示接收下一个数据g_ucaUsart2ReceiveBuffer[g_ucUsart2ReceivCounter++] = data;//保存数据}else if(state==2)//然后确定开头是0XA5 0XA6 就开始接收{g_ucaUsart2ReceiveBuffer[g_ucUsart2ReceivCounter++]=data;if(g_ucUsart2ReceivCounter>25||data==0x5B) state=3; //接收大于25个或者接收到帧尾0X5B 就置位状态三}else if(state==3) //状态三{if(g_ucaUsart2ReceiveBuffer[g_ucUsart2ReceivCounter-1] == 0x5B) //确定 最后一个是不是0x5B帧尾 是帧尾0x5B 就认为通信正确 处理数据{state = 0;//这里就可以处理数据了、处理完记得清空数组和重置标志位与计数值g_ucUsart2ReceivCounter = 0;//清零计数值g_iUsart2_Data1 = int(g_ucaUsart2ReceiveBuffer[2]<<0) | int(g_ucaUsart2ReceiveBuffer[3]<<8) | int(g_ucaUsart2ReceiveBuffer[4]<<16)| int(g_ucaUsart2ReceiveBuffer[5]<<24);g_iUsart2_Data2 = int(g_ucaUsart2ReceiveBuffer[6]<<0) | int(g_ucaUsart2ReceiveBuffer[7]<<8) | int(g_ucaUsart2ReceiveBuffer[8]<<16)| int(g_ucaUsart2ReceiveBuffer[9]<<24); g_iUsart2_Data3 = int(g_ucaUsart2ReceiveBuffer[10]<<0) | int(g_ucaUsart2ReceiveBuffer[11]<<8) | int(g_ucaUsart2ReceiveBuffer[12]<<16)| int(g_ucaUsart2ReceiveBuffer[13]<<24); g_iUsart2_Data4 = int(g_ucaUsart2ReceiveBuffer[14]<<0) | int(g_ucaUsart2ReceiveBuffer[15]<<8) | int(g_ucaUsart2ReceiveBuffer[16]<<16)| int(g_ucaUsart2ReceiveBuffer[17]<<24); g_iUsart2_Data5 = int(g_ucaUsart2ReceiveBuffer[18]<<0) | int(g_ucaUsart2ReceiveBuffer[19]<<8) | int(g_ucaUsart2ReceiveBuffer[20]<<16)| int(g_ucaUsart2ReceiveBuffer[21]<<24); //2.然后清空数组for(int i=0;i<25;i++) g_ucaUsart2ReceiveBuffer[i]=0x00;//清空数组}else //不是帧尾说明通信错误重新开始接收{state=0;g_ucUsart2ReceivCounter =0;for(int i=0;i<25;i++) g_ucaUsart2ReceiveBuffer[i]=0x00;//清空数组}}else{ //其他异常清空state=0;g_ucUsart2ReceivCounter =0;for(int i=0;i<25;i++) g_ucaUsart2ReceiveBuffer[i]=0x00;//清空数组}
}
增加一些变量的定义
uint8_t g_ucaUsart2ReceiveBuffer[25];//保存串口接收有效数据的数组
uint8_t g_ucUsart2ReceivCounter=0;//串口接收计数值
增加串口帧数据解析
usartCamera_Receive_Data(g_ucUsart2ReceiveData);
然后增加一个声明
extern void usartCamera_Receive_Data(uint8_t data);
然后我们main中定义保存接收值的变量
int g_iUsart2_Data1 = 0; //保存最后转化的值
int g_iUsart2_Data2 = 0;
int g_iUsart2_Data3 = 0;
int g_iUsart2_Data4 = 0;
int g_iUsart2_Data5 = 0;
然后声明一下
extern int g_iUsart2_Data1 ; //保存最后转化的值
extern int g_iUsart2_Data2 ;
extern int g_iUsart2_Data3 ;
extern int g_iUsart2_Data4 ;
extern int g_iUsart2_Data5 ;
增加串口一输出代码
printf(“g_iUsart2_Data:%d %d %d %d %d\r\n”,g_iUsart2_Data1,g_iUsart2_Data2,g_iUsart2_Data3,g_iUsart2_Data4,g_iUsart2_Data5);
HAL_Delay(15);
HAL_GPIO_TogglePin(PC13_LED_GPIO_Port,PC13_LED_Pin);
如果爆警告记得包含头文件
#include “stdio.h”
编译之后没有报错我们就可以烧录测试了
把程序烧录到单片机中 可以使用DAP 、STlink等烧录均可
openmv与STM32连接 调试
这篇关于第四章(先学习第五章)-openmv和arduino和stm32的通信的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!