目录
本篇文章介绍超声波模块和esp32cam模块。
一、超声波模块
使用的超声波模块为HC-SR04。
1.1 HC-SR04避障原理
知识点:
HC-SR04超声波模块。探测距离为0.010m-3.5m一共有四个引脚VCC(DC5V)、Triger(发射端)、Echo(接收端)、GND(地)
MCU给Trig脚一个大于10us的高电平脉冲;然后读取Echo脚的高电平信号时间,通过公式:距离 = T* 声速/2 就可以算出来距离。
原理:
1)采用IO触发测距,给至少10us的高电平信号。
2)模块自动发送8个40KHz的方波,自动检测是否有信号返回。
3)有信号返回,通过IO输出一高电平,高电平持续时间就是超声波从发射到返回的时间声波从发射到返回的时间
1.2 代码部分
1.2.1 计算障碍物距离
定时器:配置定时tim7。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 1 */
if (htim->Instance == TIM7){
time_cnt ++;
}
/* USER CODE END Callback 1 */
}
回调函数:判断引脚的状态,计算持续时间。
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
int time = 0;
if (GPIO_Pin == GPIO_PIN_1)
{
if (ECHO_IRQ_FLAG == 0) // 上升沿中断
{
ECHO_IRQ_FLAG = 1;
time_cnt = 0;
TIM7->CNT = 0;
HAL_TIM_Base_Start_IT(&htim7); // 启动定时器,开始计时
}
else // 下降沿中断
{
ECHO_IRQ_FLAG = 0;
HAL_TIM_Base_Stop_IT(&htim7); // 关闭定时器,计时完毕
time = (time_cnt * 1000 + TIM7->CNT) / 2; // 统计声音单次传播的时间
Distance = 34000 * time / 1000000; // 计算距离
// 过滤掉可能出现0这种错误情况
if (Distance == 0)
Distance = last_Distance;
else
last_Distance = Distance;
}
}
}
1.2.2 数据处理
#include "myTask_HC_SR04.h"
#include "usart.h"
#include "stdio.h"
#include "tim.h"
#include "myTask_ESP32.h"
int Distance ; //前方障碍物之间的距离
int flag = 0; //距离传输标志位 1开启 0关闭
void myTask_HC_SR04(void){
HC_SRC04_Start();
if (flag == 1){
char DistanceBuf[20];
sprintf(DistanceBuf, "Distance = %d", Distance);
HAL_UART_Transmit_DMA(&huart3, (uint8_t *)DistanceBuf, strlen(DistanceBuf));
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)DistanceBuf, strlen(DistanceBuf));
esp32cam_flag = 1;
delay_ms(100);
//printf("%s",DistanceBuf);
}
}
//启动超声波检测
void HC_SRC04_Start(void){
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET);
delay_ms(20);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);
}
二、esp32cam模块
ESP32-Cam 是一款视觉传感器, 它可以进行视频传输、 人脸识别、 颜色识别三种功能。该模块通过IIC接口与STM32通信。软件IIC实现代码见:【GL03】IIC协议。
esp32cam.c
/*
文件名:esp32S3CAM.c
内容:规定了STM32F407VET6单片机与esp32S3-CAM模块交互的上层函数与数据信息格式
注意:
1.本例程默认使用IIC2与模块通信,得到数据后,默认通过串口3发出(HEX格式),用户可根据实际情况修改&hi2c3,&huart3,
将功能重定向到别的外设中,此外相关的硬件功能初始化函数也需要一并更新(建议在本例程的stm32cubemx文件内直接修改配置,
然后自动生成新IIC、USART外设初始化代码,在main文件中调用即可)
2.本例程默认使用了freertos系统,冰箱对模块的具体调用放在app_task任务中实现,用户如无相关需求,可以将app_task_entry
函数内的内容(osDelay延时函数需更换成自己使用的延时函数)移植到到main函数或者自己设计的函数中
*/
#include <stdio.h>
#include <string.h>
#include "esp32cam.h"
#include "i2c.h"
#include "usart.h"
#define device_addr 0x53 // (设备地址) ESP32-Cam的通讯地址
// 当ESP32-Cam为人脸识别功能时:
#define face_data_reg_addr 0xB0 // (人脸识别寄存器起始地址,一直到0xB5,顺序:检测框中心--左眼--右眼--鼻子--左嘴角--右嘴角)
/*每个寄存器内元素排布如下:
data[1]:检测点x轴坐标
data[2]:检测点y轴坐标*/
// 当ESP32-Cam为颜色识别功能时:
#define color_data_reg_addr 0xC0 // (颜色寄存器起始地址,一直到0xC5,颜色顺序:红黄绿蓝黑)
/*前5个元素,每个元素的信息排布如下: 最后一个元素内,信息排布如下:
data[0]:颜色ID号 data[0]:红色ID号
data[1]:检测框左上角x轴坐标 data[1]:黄色ID号
data[2]:检测框左上角y轴坐标 data[2]:绿色ID号
data[3]:检测框右下角x轴坐标 data[3]:蓝色ID号
data[4]:检测框右下角y轴坐标 data[4]:黑色ID号
data[5]:检测框中心x轴坐标 data[5]:NULL
data[6]:检测框中心y轴坐标 data[5]:NULL
*/
#define line_patrol_reg_addr 0XA0 // (视觉巡线寄存器起始地址,一直到0xA9,颜色顺序:红黄绿蓝黑)
/*data[0]:屏幕从上往下第一个区域色块的颜色ID号
data[1]:屏幕从上往下第一个区域色块检测框的中心x轴坐标
data[2]:屏幕从上往下第一个区域色块检测框的中心y轴坐标
data[3]:屏幕从上往下第一个区域色块检测框左上角x轴坐标
data[4]:屏幕从上往下第一个区域色块检测框左上角y轴坐标
data[5]:屏幕从上往下第一个区域色块检测框右下角x轴坐标
data[6]:屏幕从上往下第一个区域色块检测框右下角y轴坐标
*/
struct esp32S3CAMobject
{
uint8_t face_detection[6][2]; // 人脸识别
// 6--6个检测区域(具体内容见上) 2--x轴、y轴坐标
uint8_t color_detection[6][7]; // 颜色识别
// 6个寄存器(五个各颜色专属寄存器和一个综合信息寄存器) 7--每个寄存器有7个元素(具体内容见上)
uint8_t line_patrol[10][7]; // 视觉巡线
// 5*2=10--五种颜色,屏幕从上到下两块区域 7--某一区块某一颜色的颜色信息(具体内容见上)
};
struct esp32S3CAMobject cam1; // 全局变量,可在各处调用
// 功能:初始化esp32S3CAMobject结构体变量各个成员初始值,统一设为0(数据初始化)
void esp32cam_init()
{
memset((void *)cam1.face_detection, 0, 12 * sizeof(uint8_t));
memset((void *)cam1.color_detection, 0, 42 * sizeof(uint8_t));
memset((void *)cam1.line_patrol, 0, 70 * sizeof(uint8_t));
}
void esp32cam_face_data_get()
{
for (unsigned char i = 0x00; i < 0x06; i++)
{
HAL_I2C_Mem_Read(&hi2c3, device_addr << 1, (face_data_reg_addr + i), I2C_MEMADD_SIZE_8BIT, &cam1.face_detection[(int)i][0], 2 * sizeof(uint8_t), 0xFFFF);
/*IIC8位地址中,高7位为设备地址位,最低位为读写指示位(1为读,0为写),这就是使用device_addr << 1将设备地址左移一位的意义,具体读写位的填写由HAL_I2C_Mem_Read、HAL_I2C_Mem_Write内部实现*/
}
HAL_UART_Transmit_DMA(&huart1, &cam1.face_detection[0][0], 2); /* 触发 DMA 发送*/
HAL_UART_Transmit_DMA(&huart3, &cam1.face_detection[0][0], 2); // 发送给上位机
}
// 功能:获取模块人脸识别数据,并串口打印
// void esp32cam_face_data_get(void){
// HAL_I2C_Mem_Read(&hi2c3, device_addr << 1, face_data_reg_addr, I2C_MEMADD_SIZE_8BIT, &can_ret,2, 0xFFFF);
// /*IIC8位地址中,高7位为设备地址位,最低位为读写指示位(1为读,0为写),这就是使用device_addr << 1将设备地址左移一位的意义,
// 具体读写位的填写由HAL_I2C_Mem_Read、HAL_I2C_Mem_Write内部实现*/
// HAL_UART_Transmit_DMA(&huart1, (uint8_t *)cam1.face_detection, 12); /* 触发 DMA 发送*/
// }
// 功能:获取模块颜色识别数据,并串口打印(烧录对应的颜色识别固件(bin文件))
void esp32cam_color_data_get()
{
for (unsigned char i = 0x00; i < 0x06; i++)
{
HAL_I2C_Mem_Read(&hi2c3, device_addr << 1, (face_data_reg_addr + i), I2C_MEMADD_SIZE_8BIT, &cam1.color_detection[(int)i][0], 7 * sizeof(uint8_t), 0xFFFF);
}
HAL_UART_Transmit_DMA(&huart3, &cam1.color_detection[0][0], 42); /* 触发 DMA 发送*/
}
// 功能:获取模块视觉巡线数据,并串口打印(烧录对应的视觉巡线固件(bin文件))
void esp32cam_line_patrol_data_get(unsigned char value)
{
for (unsigned char i = 0x00; i < 0x10; i++)
{
HAL_I2C_Mem_Read(&hi2c3, device_addr << 1, (face_data_reg_addr + i), I2C_MEMADD_SIZE_8BIT, &cam1.line_patrol[(int)i][0], 7 * sizeof(uint8_t), 0xFFFF);
}
HAL_UART_Transmit_DMA(&huart3, &cam1.line_patrol[0][0], 70); /* 触发 DMA 发送*/
}
esp32cam.h
#ifndef __ESP32CAM_H_
#define __ESP32CAM_H_
#include <stdio.h>
void esp32cam_init(void);
void esp32cam_face_data_get(void);
void esp32cam_color_data_get(void);
void esp32cam_line_patrol_data_get(unsigned char value);
#endif
myTask_ESP32.c
#include "myTask_ESP32.h"
#include "usart.h"
#include "stdio.h"
#include "tim.h"
#include "esp32cam.h"
#include "i2c.h"
#define device_addr 0x53 // (设备地址) ESP32-Cam的通讯地址
#define face_data_reg_addr 0xB0 // (人脸识别寄存器起始地址,一直到0xB5,顺序:检测框中心--左眼--右眼--鼻子--左嘴角--右嘴角)
int esp32cam_flag = 0; //传输坐标标志位
void myTask_ESP32(void)
{
printf("人脸识别坐标:\r\n");
//uint8_t can_ret[6][2]= {0};
while (1)
{
if(esp32cam_flag == 1){
esp32cam_face_data_get();
delay_ms(500);
}
// if(HAL_I2C_Mem_Read(&hi2c3, device_addr, face_data_reg_addr, I2C_MEMADD_SIZE_8BIT, can_ret[0], 2, HAL_MAX_DELAY)==HAL_ERROR)
// HAL_UART_Transmit(&huart1, (uint8_t *)can_ret, 10,0xff); /* 触发 DMA 发送*/
}
}