Files
P4-USB-transfer/main/SC7U22/SC7U22.c
T
zhengxinandCursor 851e347cf5 初始提交卡包 USB 工程
纳入固件源码、屏幕组件、nand_xfer 工具和文档。忽略本机构建产物、sdkconfig,以及含本机路径的依赖锁。

Co-authored-by: Cursor <[email protected]>
2026-10-13 21:54:50 +08:00

989 lines
32 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <stdio.h>
#include <inttypes.h>
#include "../config.h"
#if !EXAMPLE_USE_TOUCH
#error "SC7U22 requires EXAMPLE_USE_TOUCH (IMU shares the touch I2C bus)."
#endif
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include <math.h>
#include "esp_timer.h"
#include "../ui/generated/gui_guider.h" // 包含GUI引导器头文件
#include "lvgl.h" // 包含LVGL头文件
#include "LVGL/lvgl_init.h"
#include "ui_cmd.h"
#include "main.h"
static bool event_cooldown_active = false; // 是否处于冷却屏蔽中
static int64_t cooldown_end_time = 0; // 冷却结束时间戳
static const char *TAG_IMU = "SCU722";
i2c_master_dev_handle_t SC7U22_handle;
/** 与触摸共用的 I2C 总线句柄(SC7U22_init 写入,供扫描/查询) */
i2c_master_bus_handle_t s_i2c_bus;
sensor_data_t data_buffer[DATA_BUFFER_SIZE];
SC7U22_DataType sensor_data = {0};
static int buffer_index = 0;
static int buffer_count = 0;
struct acc_offset offset_data = {0};
noise_datatype noise_data = {0};
float ax=0,ay=0,az=0,gx=0,gy=0,gz=0;
//float acc_pre_x=0,acc_pre_y=0,acc_pre_z=0;
float acc_sum = 0;
float acc_sign_sum = 0;
float acc_hp = 0;
uint32_t bum_energy = 0;
float iir_state = 0;
uint16_t start_stop_cnt = 0;
uint16_t stop_cnt = 0;
uint8_t sharp_turn_flag = 0,pre_st_flag = 0;
bool sharpturn_ret_L = false,sharpturn_ret_R = false;
uint8_t rapid_acc_flag = 0,pre_ra_flag = 0,rapid_acc_ret = 0;
uint8_t rapid_dec_flag = 0,pre_rd_flag = 0,rapid_dec_ret = 0;
bool brake_fir_flag = false, rapid_fir_flag = false;
const char* MYTAG = "SC7U22";
extern int lottie_id;
extern int current_page_idx;
extern lv_ui guider_ui; // 外部声明GUI引导器
/*
* @brief This function converts lsb to meter per second squared for 16 bit accelerometer at
* range 2G, 4G, 8G or 16G.
*/
float lsb_to_mps2(int16_t val, float g_range, uint8_t bit_width)
{
double power = 2;
float half_scale = (float)((pow((double)power, (double)bit_width) / 2.0f));
return (GRAVITY_EARTH * val * g_range) / half_scale;
}
/*
* @brief This function converts lsb to degree per second for 16 bit gyro at
* range 125, 250, 500, 1000 or 2000dps.
*/
float lsb_to_dps(int16_t val, float dps, uint8_t bit_width)
{
double power = 2;
float half_scale = (float)((pow((double)power, (double)bit_width) / 2.0f));
return (dps / (half_scale)) * (val);
}
void i2c_scan_devices(void)
{
if (s_i2c_bus == NULL) {
ESP_LOGW(MYTAG, "i2c_scan: bus not ready (call SC7U22_init first)");
return;
}
uint8_t address;
esp_err_t ret;
bool found = false;
ESP_LOGI(MYTAG, "Scanning I2C devices on shared bus...");
for (address = 1; address < 127; address++) {
ret = i2c_master_probe(s_i2c_bus, (uint16_t)address, 100);
if (ret == ESP_OK) {
ESP_LOGI(MYTAG, "Device found at address: 0x%02X", address);
found = true;
}
vTaskDelay(50 / portTICK_PERIOD_MS);
}
if (!found) {
ESP_LOGI(MYTAG, "No I2C devices found");
}
}
void SC7U22_init(i2c_master_bus_handle_t i2c_bus)
{
if (i2c_bus == NULL) {
ESP_LOGE(MYTAG, "SC7U22_init: I2C bus handle is NULL");
return;
}
s_i2c_bus = i2c_bus;
ESP_LOGI(MYTAG, "SC7U22 on shared I2C bus: %p", (void *)s_i2c_bus);
i2c_device_config_t dev_cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = SC7U22_I2C_ADDR,
.scl_speed_hz = I2C_MASTER_FREQ_HZ,
};
esp_err_t ret = i2c_master_bus_add_device(s_i2c_bus, &dev_cfg, &SC7U22_handle);
if (ret != ESP_OK) {
ESP_LOGE(MYTAG, "添加设备失败,错误码: %s", esp_err_to_name(ret));
return;
}
SC7U22_Sensor_enable();
ESP_LOGI(MYTAG, "SC7U22 初始化完成(硬件就绪,校准将在后台进行)");
}
esp_err_t SC7U22_Reg_W(uint8_t reg_addr, uint8_t data)
{
uint8_t write_buf[2] = {reg_addr, data};
return i2c_master_transmit(SC7U22_handle, write_buf, sizeof(write_buf), 1000 / portTICK_PERIOD_MS);
}
esp_err_t SC7U22_Reg_R(uint8_t reg_addr, uint8_t *data)
{
return i2c_master_transmit_receive(SC7U22_handle, &reg_addr, 1, data, 1, 1000 / portTICK_PERIOD_MS);
}
void SC7U22_Sensor_enable(void)
{
SC7U22_Reg_W(0x7F, 0x00); // Bank / page(如需要)
vTaskDelay(pdMS_TO_TICKS(2));
SC7U22_Reg_W(0x7D, 0x0E); // PWR_CTRL enable acc + gyro
vTaskDelay(pdMS_TO_TICKS(5));
// 加速度
SC7U22_Reg_W(0x40, 0xA8); // ACC_CONF(用缺省)
SC7U22_Reg_W(0x41, 0x02); // ±4g
// 陀螺仪(关键)
SC7U22_Reg_W(0x42, 0xA9); // GYR_CONF(缺省、安全)
SC7U22_Reg_W(0x43, 0x00); // ±2000 dps
}
void SC7U22_DaMYTAGet(SC7U22_DataType* SC7U22_DataStucture)
{
esp_err_t ret;
uint8_t raw_acc[6]; // 用于存放 AX_L, AX_H, AY_L, AY_H, AZ_L, AZ_H
uint8_t raw_gyr[6]; // 用于存放 GX_L, GX_H, GY_L, GY_H, GZ_L, GZ_H
// ================= 加速度计读取 (一次读6字节) =================
// 假设 XOUT_L 是起始地址。如果你的宏定义 XOUT_H 比 XOUT_L 小,请改用 XOUT_H
uint8_t acc_reg_addr = SC7U22_ACCEL_XOUT_H;
ret = i2c_master_transmit_receive(SC7U22_handle, &acc_reg_addr, 1, raw_acc, 6, 1000 / portTICK_PERIOD_MS);
if (ret == ESP_OK) {
// 拼接数据。注意:通常 I2C 传感器先发低位(L),后发高位(H)。
// 具体的 buffer 顺序取决于寄存器地址顺序。
// 假设地址顺序是: X_L(0), X_H(1), Y_L(2), Y_H(3), Z_L(4), Z_H(5)
SC7U22_DataStucture->Ax = (int16_t)((raw_acc[0] << 8) | raw_acc[1]);
SC7U22_DataStucture->Ay = (int16_t)((raw_acc[2] << 8) | raw_acc[3]);
SC7U22_DataStucture->Az = (int16_t)((raw_acc[4] << 8) | raw_acc[5]);
} else {
ESP_LOGE(MYTAG, "Accel read failed: %s", esp_err_to_name(ret));
}
// ================= 陀螺仪读取 (一次读6字节) =================
// 假设 XOUT_L 是起始地址
uint8_t gyr_reg_addr = SC7U22_GYRO_XOUT_H;
//暂时注释掉
ret = i2c_master_transmit_receive(SC7U22_handle, &gyr_reg_addr, 1, raw_gyr, 6, 1000 / portTICK_PERIOD_MS);
if (ret == ESP_OK) {
SC7U22_DataStucture->Gx = (int16_t)((raw_gyr[0] << 8) | raw_gyr[1]);
SC7U22_DataStucture->Gy = (int16_t)((raw_gyr[2] << 8) | raw_gyr[3]);
SC7U22_DataStucture->Gz = (int16_t)((raw_gyr[4] << 8) | raw_gyr[5]);
} else {
ESP_LOGE(MYTAG, "Gyro read failed");
}
}
void baseline_remove(void)
{
// 加速度计去偏
ax = lsb_to_mps2(sensor_data.Ax, (float)4, 16) - offset_data.acc_x_offset;
ay = lsb_to_mps2(sensor_data.Ay, (float)4, 16) - offset_data.acc_y_offset;
az = lsb_to_mps2(sensor_data.Az, (float)4, 16) - offset_data.acc_z_offset;
// 陀螺仪去偏 (新增)
gx = lsb_to_dps(sensor_data.Gx, (float)2000, 16) - offset_data.gyr_x_offset;
gy = lsb_to_dps(sensor_data.Gy, (float)2000, 16) - offset_data.gyr_y_offset;
gz = lsb_to_dps(sensor_data.Gz, (float)2000, 16) - offset_data.gyr_z_offset;
}
void noise_threshold_get(void)
{
uint8_t ax_cnt = 0,ay_cnt = 0,az_cnt = 0,gx_cnt = 0,gy_cnt = 0,gz_cnt = 0;
SC7U22_DaMYTAGet(&sensor_data);
baseline_remove();
for(int i = 0;i<50;i++)
{
if(ax!=0) {noise_data.accx_noise+=fabs(ax); ax_cnt++;}
if(ay!=0) {noise_data.accy_noise+=fabs(ay); ay_cnt++;}
if(az!=0) {noise_data.accz_noise+=fabs(az); az_cnt++;}
if(gx!=0) {noise_data.gyrx_noise+=fabs(gx); gx_cnt++;}
if(gy!=0) {noise_data.gyry_noise+=fabs(gy); gy_cnt++;}
if(gz!=0) {noise_data.gyrz_noise+=fabs(gz); gz_cnt++;}
vTaskDelay(pdMS_TO_TICKS(5));
}
noise_data.accx_noise/=(float)ax_cnt;
noise_data.accy_noise/=(float)ay_cnt;
noise_data.accz_noise/=(float)az_cnt;
noise_data.gyrx_noise/=(float)gx_cnt;
noise_data.gyry_noise/=(float)gy_cnt;
noise_data.gyrz_noise/=(float)gz_cnt;
}
void data_deal_with_noise(void)
{
if(fabs(ax)<fabs(noise_data.accx_noise)*1.5f+0.05) ax = 0;
if(fabs(ay)<fabs(noise_data.accy_noise)*1.5f+0.05) ay = 0;
if(fabs(az)<fabs(noise_data.accz_noise)*1.5f+0.05) az = 0;
if(fabs(gx)<fabs(noise_data.gyrx_noise)*1.5f+1) gx = 0;
if(fabs(gy)<fabs(noise_data.gyry_noise)*1.5f+1) gy = 0;
if(fabs(gz)<fabs(noise_data.gyrz_noise)*1.5f+1) gz = 0;
}
void mySC7_getdata(void)
{
SC7U22_DaMYTAGet(&sensor_data);
baseline_remove(); //去零偏处理
data_deal_with_noise();//去噪声处理
data_buffer[buffer_index].accel_x = ax;
data_buffer[buffer_index].accel_y = ay;
data_buffer[buffer_index].accel_z = az;
data_buffer[buffer_index].timestamp = esp_timer_get_time();
buffer_index = (buffer_index + 1) % DATA_BUFFER_SIZE;
if (buffer_count < DATA_BUFFER_SIZE) {
buffer_count++;
}
}
void accel_Getoffset(void)
{
float ax_sum=0, ay_sum=0, az_sum=0;
float gx_sum=0, gy_sum=0, gz_sum=0; // 新增
ESP_LOGI(MYTAG, "正在校准传感器,请保持静止...");
for(int i = 0; i < 100; i++) // 采样100次
{
SC7U22_DaMYTAGet(&sensor_data);
// 累加加速度
ax_sum += lsb_to_mps2(sensor_data.Ax, (float)4, 16);
ay_sum += lsb_to_mps2(sensor_data.Ay, (float)4, 16);
az_sum += lsb_to_mps2(sensor_data.Az, (float)4, 16);
// 累加陀螺仪 (注意:这里使用 2000dps 量程)
gx_sum += lsb_to_dps(sensor_data.Gx, (float)2000, 16);
gy_sum += lsb_to_dps(sensor_data.Gy, (float)2000, 16);
gz_sum += lsb_to_dps(sensor_data.Gz, (float)2000, 16);
vTaskDelay(pdMS_TO_TICKS(10));
}
// 计算平均值
offset_data.acc_x_offset = ax_sum / 100.0f;
offset_data.acc_y_offset = ay_sum / 100.0f;
offset_data.acc_z_offset = (az_sum / 100.0f) - GRAVITY_EARTH; // Z轴要扣除重力
// 计算陀螺仪偏移 (理论上静止时全是0,所以读数即为偏移)
offset_data.gyr_x_offset = gx_sum / 100.0f;
offset_data.gyr_y_offset = gy_sum / 100.0f;
offset_data.gyr_z_offset = gz_sum / 100.0f;
int gz_milli = (int)(offset_data.gyr_z_offset * 1000.0f);
ESP_LOGI(MYTAG, "校准完成! Gz Offset: %d.%03d", gz_milli / 1000, abs(gz_milli % 1000));
}
void bum_energy_get(void)
{
acc_sum += fabs(az);
acc_sign_sum += az;
iir_state = ALPHA * iir_state + (1 - ALPHA) * acc_sum;
acc_hp = acc_sum -iir_state; //高通滤波
bum_energy += (uint32_t)(acc_hp*acc_hp*1000); //处理颠簸能量
}
bool is_bump(void)
{
uint32_t temp = bum_energy;
static bool wasbump = false;
float variance = 0;
bum_energy = 0;
acc_sum = 0;
acc_sign_sum /= DATA_BUFFER_SIZE;
for(int i = 0;i<DATA_BUFFER_SIZE;i++)
{
variance += fabs(data_buffer[i].accel_z - acc_sign_sum); //平均绝对值误差
}
acc_sign_sum = 0;
bool isbump = (temp>=BUM_THRESHOLD&&variance>=400);
if(isbump&&!wasbump)
{
wasbump = isbump;
return true;
}
wasbump = isbump;
return false;
}
void sharp_turn_detect(void)
{
if(fabs(gz) > turn_gyro_threshold && fabs(ay) > turn_accel_threshold)
{
sharp_turn_flag++;
}
else
{
sharp_turn_flag = 0;
}
if(sharp_turn_flag == 0 && pre_st_flag >= 5) // 连续触发次数稍微减少一点,灵敏些
{
pre_st_flag = 0;
// 左转通常 gyrz > 0 (逆时针),右转 gyrz < 0 (顺时针)
// 具体正负取决于芯片安装面,你测试时如果不准,互换一下即可
if(gz > 0) sharpturn_ret_L = true;
else if(gz < 0) sharpturn_ret_R = true;
}
pre_st_flag = sharp_turn_flag;
}
driving_event_t is_sharp_turn(void)
{
if(sharpturn_ret_L)
{
sharpturn_ret_L = 0;
return EVENT_SHARP_LTURN;
}
else if(sharpturn_ret_R)
{
sharpturn_ret_R = 0;
return EVENT_SHARP_RTURN;
}
return EVENT_NONE;
}
static float calculate_acceleration_magnitude(void)
{
return sqrtf(ax * ax + ay * ay + az * az);
}
void start_stop_state(void)
{
static uint8_t st_cnt = 0;
static uint8_t sp_cnt = 0;
static bool stop_flag = false;
bool is_stop = calculate_acceleration_magnitude()<= is_stop_magnitude;
if(is_stop&&!stop_flag) sp_cnt++;
if(sp_cnt>=3)
{
stop_flag = true;
sp_cnt = 0;
}
if(is_stop&&stop_flag)
{
stop_cnt++;
}
if(stop_flag&&!is_stop)
{
st_cnt++;
}
else{
st_cnt = 0;
}
if(st_cnt>=3)
{
start_stop_cnt++;
st_cnt = 0;
stop_flag = false;
}
}
// 判断急停急加速
void detect_driving_events(void)
{
//获取数据
mySC7_getdata();
//颠簸能量累加
bum_energy_get();
//急转弯检测
sharp_turn_detect();
//急加速检测 急刹车检测
if (buffer_count < 2) return ;
int current_idx = (buffer_index - 1 + DATA_BUFFER_SIZE) % DATA_BUFFER_SIZE;
int prev_idx = (buffer_index - 2 + DATA_BUFFER_SIZE) % DATA_BUFFER_SIZE;
// 计算时间差(秒)
float time_diff = (data_buffer[current_idx].timestamp -
data_buffer[prev_idx].timestamp) / 1000000.0f;
if (time_diff <= 0) return ;
float accel_diff_x = data_buffer[current_idx].accel_x - data_buffer[prev_idx].accel_x;
float jerk_x = accel_diff_x / time_diff; // 急动度
// 急刹车/减速检测
// 逻辑:当前有一个很大的负向加速度(刹车),且变化率很大
// 注意:如果是“前倾 accx 变大”,说明 +X 是车头向下或向前。
// 假设 +X 是向前加速,那么 -X 就是刹车。
if ((jerk_x < -rapid_accel_threshold/0.02) && (data_buffer[current_idx].accel_x < -rapid_accel_threshold))
rapid_dec_flag = 1;
if ((data_buffer[current_idx].accel_x < -rapid_accel_threshold) && rapid_dec_flag)
rapid_dec_flag++;
else
rapid_dec_flag = 0;
if (rapid_dec_flag == 0 && pre_rd_flag >= 4) rapid_dec_ret = 1; // 阈值改小一点容易触发
pre_rd_flag = rapid_dec_flag;
// 急加速检测
// 逻辑:当前有一个很大的正向加速度
if ((jerk_x > rapid_accel_threshold/0.02) && (data_buffer[current_idx].accel_x > rapid_accel_threshold))
rapid_acc_flag = 1;
if ((data_buffer[current_idx].accel_x > rapid_accel_threshold) && rapid_acc_flag)
rapid_acc_flag++;
else
rapid_acc_flag = 0;
if (rapid_acc_flag == 0 && pre_ra_flag >= 4) rapid_acc_ret = 1;
pre_ra_flag = rapid_acc_flag;
}
driving_event_t is_rapid_acc_or_dec(void)
{
if(rapid_acc_ret)
{
rapid_acc_ret = 0;
return EVENT_SUDDEN_ACCEL;
}
if(rapid_dec_ret)
{
rapid_dec_ret = 0;
return EVENT_SUDDEN_BRAKE;
}
return EVENT_NONE;
}
bool is_jam(void)
{
float stop_proportion = (float)stop_cnt/600.0;
uint16_t temp_cnt = start_stop_cnt;
stop_cnt = 0;
start_stop_cnt = 0;
if((stop_proportion>=stop_proportion_threshold&&temp_cnt>=start_stop_threshold)||stop_proportion>=0.8f)
{
return true;
}
return false;
}
// 在IMU任务函数外定义(全局区),避免栈溢出,同时供回调函数访问
// 驾驶事件冷却检查:冷却中返回true,允许触发返回false
bool is_event_in_cooldown(void)
{
if (!event_cooldown_active) {
return false;
}
// 当前时间 < 结束时间 = 还在冷却
if (esp_timer_get_time() < cooldown_end_time) {
return true;
} else {
// 冷却结束,复位
event_cooldown_active = false;
ESP_LOGI(MYTAG, "冷却时间已结束,可以再次触发驾驶事件");
return false;
}
}
// 触发一次事件后,启动50秒冷却
void start_event_cooldown(void)
{
event_cooldown_active = true;
cooldown_end_time = esp_timer_get_time() + (EVENT_COOLDOWN_MS * 1000); // 转微秒
ESP_LOGI(MYTAG, "已启动冷却,%d 毫秒内不再触发", EVENT_COOLDOWN_MS);
}
/** 诊断:因 g_ble_play_sticker_active 抑制幸运表情时打印(节流,避免刷屏) */
#define BLE_GUARD_LOG_THROTTLE_MS 3000
static uint32_t s_ble_guard_last_log_tick;
static void ble_guard_log_lucky_suppressed(const char *reason)
{
uint32_t t = lv_tick_get();
if (s_ble_guard_last_log_tick != 0 && (t - s_ble_guard_last_log_tick) < BLE_GUARD_LOG_THROTTLE_MS)
return;
s_ble_guard_last_log_tick = t;
ESP_LOGW("BLE_STICKER_GUARD",
"Lucky suppressed: %s (g_ble_play_sticker_active still true)",
reason);
}
void imu_task(void *param)
{
ESP_LOGI(MYTAG, "Starting IMU task");
driving_event_t drive_even = EVENT_NONE;
uint16_t i = 0;
/* 保持原校准逻辑不变,只调整执行时机:由主初始化路径改为后台任务执行。 */
uint32_t calib_start_ms = (uint32_t)(esp_timer_get_time() / 1000ULL);
ESP_LOGI(MYTAG, "IMU 后台校准开始");
vTaskDelay(pdMS_TO_TICKS(20));
accel_Getoffset();
noise_threshold_get();
uint32_t calib_elapsed_ms = (uint32_t)(esp_timer_get_time() / 1000ULL) - calib_start_ms;
ESP_LOGI(MYTAG, "IMU 后台校准完成,耗时: %" PRIu32 " ms", calib_elapsed_ms);
while(1)
{
// ========== 原有逻辑保持不变 ==========
mySC7_getdata(); // 永远读取传感器数据
ESP_LOGW(MYTAG,"正在读取IMU数据...");
if (current_page_idx == 0)
{
detect_driving_events();
drive_even = is_sharp_turn();
if(drive_even == EVENT_SHARP_LTURN) //急转弯判断 结束一个急转弯后判定
{
if (is_event_in_cooldown()) continue; // 冷却中直接跳过
if (g_ble_play_sticker_active)
{
ble_guard_log_lucky_suppressed("left sharp turn");
continue; /* BLE 正在播表情时不插播 IMU 幸运 */
}
start_event_cooldown(); // 启动50秒冷却
/*左急转弯反馈入口*/
lottie_id = 29;
ESP_LOGE(MYTAG,"左急转!");
/*左急转弯反馈结束*/
}else if(drive_even == EVENT_SHARP_RTURN)
{
if (is_event_in_cooldown()) continue; // 冷却中直接跳过
if (g_ble_play_sticker_active)
{
ble_guard_log_lucky_suppressed("right sharp turn");
continue;
}
start_event_cooldown(); // 启动50秒冷却
/*右急转弯反馈入口*/
lottie_id = 29;
ESP_LOGE(MYTAG,"右急转!");
/*右急转弯反馈入口*/
}
drive_even = is_rapid_acc_or_dec();
if(drive_even==EVENT_SUDDEN_ACCEL)
{
if (is_event_in_cooldown()) continue; // 冷却中直接跳过
if (g_ble_play_sticker_active)
{
ble_guard_log_lucky_suppressed("sudden accel");
continue;
}
start_event_cooldown(); // 启动50秒冷却
/*急加速反馈入口*/
lottie_id = 29;
ESP_LOGE(MYTAG,"急加速!");
/*急加速反馈结束*/
}
else if(drive_even==EVENT_SUDDEN_BRAKE)
{
if (is_event_in_cooldown()) continue; // 冷却中直接跳过
if (g_ble_play_sticker_active)
{
ble_guard_log_lucky_suppressed("sudden brake");
continue;
}
start_event_cooldown(); // 启动50秒冷却
/*急刹车反馈入口*/
lottie_id = 29;
ESP_LOGE(MYTAG,"急刹车!");
/*急刹车反馈结束*/
}
}
// ========== 4. 通用逻辑(堵车/颠簸检测) ==========
vTaskDelay(pdMS_TO_TICKS(20));
i++;
if(i%25==0 && current_page_idx == 0)
{
//堵车数据检测
start_stop_state();
// printf("accx:%4.2f, accy:%4.2f, accz:%4.2f, gyrx:%4.2f, gyry:%4.2f, gyrz:%4.2f\n",
// ax,ay,az,gx,gy,gz);
}
if(i%200==0 && current_page_idx == 0) //2秒累加检测 反馈程序入口
{
if(is_bump()) //判断路面颠簸
{
ESP_LOGE(MYTAG,"路面颠簸!");
}
}
if(i>=15000 && current_page_idx == 0) //5分钟判定一次堵车
{
if(is_jam())
{
ESP_LOGE(MYTAG,"堵车!");
}
i = 0;
}
vTaskDelay(pdMS_TO_TICKS(30));
}
}
i2c_master_bus_handle_t get_i2c_master_bus_handle(void)
{
return s_i2c_bus;
}
i2c_master_bus_handle_t touch_bus_handle_BMI;
i2c_master_bus_handle_t touch_bus_handle_NST112;
i2c_master_bus_handle_t touch_bus_handle_MS523;
i2c_master_bus_handle_t n_i2c_bus;
//i2c_master_bus_config_t i2c_bus_config = {0};
esp_err_t BMI_init(void)
{
ESP_LOGI(TAG_IMU, "开始初始化 SC7U22...");
vTaskDelay(pdMS_TO_TICKS(100));
#if !EXAMPLE_USE_TOUCH
#error "BMI_init requires EXAMPLE_USE_TOUCH (SC7U22 shares touch I2C bus)."
#endif
//extern i2c_master_bus_handle_t touch_bus_handle; I2C主总线
i2c_master_bus_config_t i2c_bus_config = {0};
i2c_bus_config.clk_source = I2C_CLK_SRC_DEFAULT;
i2c_bus_config.i2c_port = 0;
i2c_bus_config.scl_io_num = TEST_BOARD_I2C_SCL_PIN;
i2c_bus_config.sda_io_num = TEST_BOARD_I2C_SDA_PIN;
i2c_bus_config.glitch_ignore_cnt = 7;
i2c_bus_config.flags.enable_internal_pullup = true;
//i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_config, &touch_bus_handle_BMI));
s_i2c_bus = touch_bus_handle_BMI;
i2c_scan_devices();
SC7U22_init(touch_bus_handle_BMI);
bmi_task_stack = heap_caps_malloc(BMI_TASK_STACK_SIZE, MALLOC_CAP_SPIRAM);
if (bmi_task_stack == NULL)
{
ESP_LOGE("LVGL", "Failed to allocate BMI task stack");
return ESP_FAIL;
}
TaskHandle_t task_handle = xTaskCreateStaticPinnedToCore(imu_task, "BMI", BMI_TASK_STACK_SIZE, NULL, BMI_TASK_PRIORITY, bmi_task_stack, &bmi_task_tcb, 0);
if (task_handle == NULL)
{
ESP_LOGE("LVGL", "Failed to create BMI task");
heap_caps_free(bmi_task_stack);
bmi_task_stack = NULL;
return ESP_FAIL;
}
ESP_LOGI("LVGL", "BMI task created successfully");
return ESP_OK;
}
i2c_master_dev_handle_t NST112_handle;
uint8_t temp_data[2] ={0};
uint8_t config_data[2] = {0};
uint8_t H_tmp_data[2] = {0};
uint8_t L_tmp_data[2] = {0};
esp_err_t NST112_Reg_W(uint8_t reg_addr, uint8_t data)
{
uint8_t write_buf[] = {reg_addr, data};
return i2c_master_transmit(NST112_handle, write_buf, sizeof(write_buf), 1000 / portTICK_PERIOD_MS);
}
esp_err_t NST112_Reg_R(uint8_t reg_addr)
{
esp_err_t ret = i2c_master_transmit_receive(NST112_handle,&reg_addr,1,temp_data,2,1000 / portTICK_PERIOD_MS);
if(ret != ESP_OK){
ESP_LOGE("NST112", "读取 NST112 寄存器失败,错误码: %s", esp_err_to_name(ret));
return ret;
}
else{
return ESP_OK;
}
}
extern StaticTask_t nst112_task_tcb;
extern StackType_t *nst112_task_stack;
void nst112_task(void *param)
{
ESP_LOGI("NST112", "Starting NST112 task");
uint8_t read_addr = 0x00;
float temp_c = 0;
while(1)
{
i2c_master_transmit_receive(NST112_handle, &read_addr, 1, temp_data, 2, 1000 / portTICK_PERIOD_MS);
int16_t raw = (int16_t)((temp_data[0] << 8) | temp_data[1]);
temp_c = raw / 256.0f;
ESP_LOGI("NST112", "TEMP: %02X %02X", temp_data[0], temp_data[1]);
ESP_LOGI("NST112", "TEMP (C): %f", temp_c);
if(temp_c > 70){
ESP_LOGI("NST112", "TEMP: WARNING");
}
if(temp_c < (-20)){
ESP_LOGI("NST112", "TEMP: WARNING");
}
vTaskDelay(pdMS_TO_TICKS(2000));
}
}
esp_err_t NST112_init(void)
{
//extern i2c_master_bus_handle_t touch_bus_handle_touch;
i2c_master_bus_config_t i2c_bus_config = {0};
i2c_bus_config.clk_source = I2C_CLK_SRC_DEFAULT;
i2c_bus_config.i2c_port = 1;
i2c_bus_config.scl_io_num = NST112_I2C_SCL_PIN;
i2c_bus_config.sda_io_num = NST112_I2C_SDA_PIN;
i2c_bus_config.glitch_ignore_cnt = 7;
i2c_bus_config.flags.enable_internal_pullup = true;
//i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_config, &touch_bus_handle_NST112)); //此处单传感器调试用,正式使用时改为传入共享总线句柄
n_i2c_bus = touch_bus_handle_NST112;//touch_bus_handle_touch
s_i2c_bus = touch_bus_handle_NST112;
i2c_scan_devices();
ESP_LOGI("NST112", "NST112 on shared I2C bus: %p", (void *)n_i2c_bus);
i2c_device_config_t dev_cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = NST112_I2C_ADDR,
.scl_speed_hz = I2C_MASTER_FREQ_HZ,
};
esp_err_t ret = i2c_master_bus_add_device(n_i2c_bus, &dev_cfg, &NST112_handle);
if (ret != ESP_OK) {
ESP_LOGE("NST112", "添加 NST112 设备失败");
return ret;
}
uint8_t write_buf[] = {0x01,0x60,0xA0}; // 0x01 寄存器地址,0x60 和 0xA0 是要写入的数据
uint8_t high_temp_config_reg[] = {0x03,0x05,0x50};
uint8_t low_temp_config_reg[] = {0x02,0x00,0xA0};
uint8_t read_config_addr = 0x01;
uint8_t read_H_TMP_addr = 0x02;
uint8_t read_L_TMP_addr = 0x03;
i2c_master_transmit(NST112_handle, write_buf, sizeof(write_buf), 1000 / portTICK_PERIOD_MS);
vTaskDelay(pdMS_TO_TICKS(1000));
ret = i2c_master_transmit_receive(NST112_handle,&read_config_addr,1 ,config_data,2,pdMS_TO_TICKS(100));
vTaskDelay(pdMS_TO_TICKS(1000));
ret = i2c_master_transmit_receive(NST112_handle,&read_L_TMP_addr,1 ,H_tmp_data,2,pdMS_TO_TICKS(100));
vTaskDelay(pdMS_TO_TICKS(1000));
ret = i2c_master_transmit_receive(NST112_handle,&read_H_TMP_addr,1 ,L_tmp_data,2,pdMS_TO_TICKS(100));
vTaskDelay(pdMS_TO_TICKS(1000));
ESP_LOGI("NST112", "TEMP: %02X %02X L:%02X %02X H:%02X %02X ", config_data[0], config_data[1],L_tmp_data[0],L_tmp_data[1],H_tmp_data[0],L_tmp_data[1]);
//i2c_master_transmit(NST112_handle, high_temp_config_reg, sizeof(high_temp_config_reg), 1000 / portTICK_PERIOD_MS);
//i2c_master_transmit(NST112_handle, low_temp_config_reg, sizeof(low_temp_config_reg), 1000 / portTICK_PERIOD_MS);
vTaskDelay(pdMS_TO_TICKS(100));
uint8_t read_addr = 0x00;
//i2c_master_transmit_receive(NST112_handle, &read_addr, 1, temp_data, 2, 1000 / portTICK_PERIOD_MS);
nst112_task_stack = heap_caps_malloc(NST112_TASK_STACK_SIZE, MALLOC_CAP_SPIRAM);
if (nst112_task_stack == NULL)
{
ESP_LOGE("LVGL", "Failed to allocate NST112 task stack");
return ESP_FAIL;
}
xTaskCreateStaticPinnedToCore(nst112_task, "NST112", NST112_TASK_STACK_SIZE, NULL, NST112_TASK_PRIORITY, nst112_task_stack, &nst112_task_tcb,0);
return ESP_OK;
}
#define MS523_CTRL_GPIO GPIO_NUM_48
i2c_master_dev_handle_t MS523_handle;
extern StaticTask_t MS523_task_tcb;
extern StackType_t *MS523_task_stack;
esp_err_t ms523_write_byte(uint8_t reg_addr, uint8_t data) {
uint8_t write_buf[2] = {reg_addr, data};
esp_err_t ret = i2c_master_transmit(MS523_handle, write_buf, sizeof(write_buf), pdMS_TO_TICKS(100));
if (ret != ESP_OK) {
ESP_LOGE("MS523", "Write reg 0x%02X failed: %s", reg_addr, esp_err_to_name(ret));
}
return ret;
}
esp_err_t ms523_read_byte(uint8_t reg_addr, uint8_t *data) {
esp_err_t ret = i2c_master_transmit_receive(MS523_handle, &reg_addr, 1, data, 1, pdMS_TO_TICKS(100));
if (ret == ESP_OK) {
ESP_LOGI("MS523", "Read reg 0x%02X = 0x%02X", reg_addr, *data);
} else {
ESP_LOGE("MS523", "Read reg 0x%02X failed: %s", reg_addr, esp_err_to_name(ret));
}
return ret;
}
#define GPIO_OUTPUT_PIN GPIO_NUM_48 // 以GPIO2为例
void MS523_ctrl_init(void){
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << GPIO_OUTPUT_PIN), // 选择要配置的引脚[reference:5]
.mode = GPIO_MODE_OUTPUT, // 设置为输出模式[reference:6]
.pull_up_en = GPIO_PULLUP_DISABLE, // 禁用内部上拉电阻[reference:7]
.pull_down_en = GPIO_PULLDOWN_DISABLE, // 禁用内部下拉电阻[reference:8]
.intr_type = GPIO_INTR_DISABLE // 禁用中断[reference:9]
};
gpio_config(&io_conf); // 应用配置[reference:10]
// 2. 设置GPIO输出高电平
gpio_set_level(GPIO_OUTPUT_PIN, 1);
vTaskDelay(pdMS_TO_TICKS(1000));
ESP_LOGI("MS523", "当前输出高电平");
}
void ms523_detect_card(void) {
// 1-4:发送寻卡指令
ms523_write_byte(0x0A, 0x80);
ms523_write_byte(0x09, 0x52);
ms523_write_byte(0x0D, 0x87);
ms523_write_byte(0x01, 0x0C);
// 5:轮询等待 RxIRq(超时 50ms)
uint8_t irq = 0;
int timeout_ms = 50;
TickType_t start = xTaskGetTickCount();
while ((xTaskGetTickCount() - start) < pdMS_TO_TICKS(timeout_ms)) {
ms523_read_byte(0x04, &irq);
if (irq & 0x20) {
ESP_LOGI("MS523", "✅ Card detected!");
return; // 检测到卡,退出函数
}
vTaskDelay(pdMS_TO_TICKS(1));
}
// 检查碰撞
uint8_t err;
ms523_read_byte(0x06, &err);
if (err & 0x08) {
ESP_LOGI("MS523", "✅ Card detected (Collision)!");
return;
}
// 无卡
ESP_LOGW("MS523", "No card detected.");
}
void MS523_task(void *param){
while (1)
{
ms523_detect_card();
ESP_LOGW("MS523", "运行中");
vTaskDelay(500);
}
}
esp_err_t MS523_init(void)
{
MS523_ctrl_init();
ESP_LOGI(TAG_IMU, "开始初始化 MS523");
vTaskDelay(pdMS_TO_TICKS(100));
#if !EXAMPLE_USE_TOUCH
#error "BMI_init requires EXAMPLE_USE_TOUCH (SC7U22 shares touch I2C bus)."
#endif
//extern i2c_master_bus_handle_t touch_bus_handle; I2C主总线
i2c_master_bus_config_t i2c_bus_config = {0};
i2c_bus_config.clk_source = I2C_CLK_SRC_DEFAULT;
i2c_bus_config.i2c_port = 0;
i2c_bus_config.scl_io_num = TEST_BOARD_I2C_SCL_PIN;
i2c_bus_config.sda_io_num = TEST_BOARD_I2C_SDA_PIN;
i2c_bus_config.glitch_ignore_cnt = 7;
i2c_bus_config.flags.enable_internal_pullup = true;
//i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_config, &touch_bus_handle_MS523));
s_i2c_bus = touch_bus_handle_MS523;
//i2c_scan_devices();
i2c_device_config_t dev_cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = MS523_I2C_ADDR,
.scl_speed_hz = I2C_MASTER_FREQ_HZ,
};
esp_err_t ret = i2c_master_bus_add_device(s_i2c_bus, &dev_cfg, &MS523_handle);
uint8_t reg_addr = 0x37;
uint8_t version = 0;
uint8_t data = 0;
ms523_read_byte(reg_addr,&version);
ms523_write_byte(0x14, 0x83); // 开启 TX1/TX2 天线驱动
ms523_write_byte(0x12, 0x00); // 发送速率 106k
ms523_write_byte(0x13, 0x08); // 接收速率 106k
ms523_write_byte(0x26, 0x48); // 接收增益 48dB
if (ret == ESP_OK) {
ESP_LOGI("MS523", "NFC version:0x%02X", version);
} else {
ESP_LOGE("MS523", "Read version failed: %s", esp_err_to_name(ret));
}
MS523_task_stack = heap_caps_malloc(MS523_TASK_STACK_SIZE, MALLOC_CAP_SPIRAM);
if (MS523_task_stack == NULL)
{
ESP_LOGE("LVGL", "Failed to allocate NST112 task stack");
return ESP_FAIL;
}
//ms523_write_byte(0x0A, 0x80);
//ms523_read_byte(0x0A,&data);
//ms523_write_byte(0x09, 0x52);
//ms523_read_byte(0x09,&data);
//ms523_write_byte(0x0D, 0x87);
//ms523_read_byte(0x0D,&data);
//ms523_write_byte(0x01, 0x0C);
//ms523_read_byte(0x01,&data);
xTaskCreateStaticPinnedToCore(MS523_task, "MS523", MS523_TASK_STACK_SIZE, NULL, MS523_TASK_PRIORITY, MS523_task_stack, &MS523_task_tcb,1);
return ESP_OK;
}