Compare commits
39 Commits
8828f24549
...
skiing_tmp
| Author | SHA1 | Date | |
|---|---|---|---|
| 6c9ec6cec8 | |||
| ea610c24d3 | |||
| 45158aebcf | |||
| 138275a04b | |||
| 89f1c93f74 | |||
| 8c2db49083 | |||
| 627780ea20 | |||
| ade4b0a1f8 | |||
| 818e8c3778 | |||
| 892ed9267b | |||
| 4af4f13ac6 | |||
| 4c5da2298f | |||
| 5c7d9ab822 | |||
| 60a4e95386 | |||
| 845cc33fe8 | |||
| f3710fbb4b | |||
| 91b08dbe47 | |||
| 591e7632d2 | |||
| baa5979ee1 | |||
| bdadd5de1e | |||
| 9ccf1acda8 | |||
| 2bfdc81991 | |||
| 054ea8644a | |||
| ad3ab64b72 | |||
| ebca849be3 | |||
| d0d9c0a630 | |||
| b621ef7e44 | |||
| 046986c5c3 | |||
| 5e587e0527 | |||
| c88cb70bb1 | |||
| 58ad14691e | |||
| 23a71377a2 | |||
| d12252dfda | |||
| 289a6b780b | |||
| ae980789b6 | |||
| ac7299e7ad | |||
| 6be3cd1070 | |||
| 671730a351 | |||
| 97e85df2f8 |
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# 编译生成的目标文件
|
||||||
|
*.o
|
||||||
|
*.so
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# 编译生成的最终产物
|
||||||
|
*.elf
|
||||||
|
*.fw
|
||||||
|
*.ufw
|
||||||
|
*.map
|
||||||
|
*.lst
|
||||||
|
*.bc
|
||||||
|
|
||||||
|
|
||||||
|
# VSCode 用户个人设置
|
||||||
|
# 团队协作时,每个人的配置可能不同,通常不建议提交
|
||||||
|
.vscode/settings.json
|
||||||
24
.vscode/settings.json
vendored
24
.vscode/settings.json
vendored
@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"files.associations": {
|
|
||||||
"board_config.h": "c",
|
|
||||||
"board_jl701n_demo_cfg.h": "c",
|
|
||||||
"colorful_lights.h": "c",
|
|
||||||
"board_jl701n_anc_cfg.h": "c",
|
|
||||||
"update_loader_download.h": "c",
|
|
||||||
"iic_soft.h": "c",
|
|
||||||
"circle_buffer.h": "c",
|
|
||||||
"default_event_handler.h": "c",
|
|
||||||
"ui_manage.h": "c",
|
|
||||||
"charge.h": "c",
|
|
||||||
"app_main.h": "c",
|
|
||||||
"app_config.h": "c",
|
|
||||||
"app_action.h": "c",
|
|
||||||
"includes.h": "c",
|
|
||||||
"key_event_deal.h": "c",
|
|
||||||
"app_umidigi_chargestore.h": "c",
|
|
||||||
"hci_lmp.h": "c",
|
|
||||||
"bluetooth.h": "c",
|
|
||||||
"SCU722.C": "cpp",
|
|
||||||
"math.h": "c"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
12
Makefile
12
Makefile
@ -248,6 +248,11 @@ INCLUDES := \
|
|||||||
-Iapps/earphone/xtell_Sensor/buffer \
|
-Iapps/earphone/xtell_Sensor/buffer \
|
||||||
-Iapps/earphone/xtell_Sensor/sensor \
|
-Iapps/earphone/xtell_Sensor/sensor \
|
||||||
-Iapps/earphone/xtell_Sensor \
|
-Iapps/earphone/xtell_Sensor \
|
||||||
|
-Iapps/earphone/xtell_Sensor/calculate \
|
||||||
|
-Iapps/earphone/xtell_Sensor/ano \
|
||||||
|
-Iapps/earphone/xtell_Sensor/sensor/ \
|
||||||
|
-Iapps/earphone/xtell_Sensor/sensor/ \
|
||||||
|
-Iapps/earphone/xtell_Sensor/sensor/ \
|
||||||
-I$(SYS_INC_DIR) \
|
-I$(SYS_INC_DIR) \
|
||||||
|
|
||||||
|
|
||||||
@ -617,7 +622,12 @@ c_SRC_FILES := \
|
|||||||
apps/earphone/xtell_Sensor/send_data.c \
|
apps/earphone/xtell_Sensor/send_data.c \
|
||||||
apps/earphone/xtell_Sensor/buffer/circle_buffer.c \
|
apps/earphone/xtell_Sensor/buffer/circle_buffer.c \
|
||||||
apps/earphone/xtell_Sensor/sensor/LIS2DH12.c \
|
apps/earphone/xtell_Sensor/sensor/LIS2DH12.c \
|
||||||
apps/earphone/xtell_Sensor/sensor/SCU722.c \
|
apps/earphone/xtell_Sensor/sensor/SC7U22.c \
|
||||||
|
apps/earphone/xtell_Sensor/calculate/skiing_tracker.c \
|
||||||
|
apps/earphone/xtell_Sensor/ano/ano_protocol.c \
|
||||||
|
apps/earphone/xtell_Sensor/sensor/MMC56.c \
|
||||||
|
apps/earphone/xtell_Sensor/sensor/BMP280.c \
|
||||||
|
apps/earphone/xtell_Sensor/sensor/AK8963.c \
|
||||||
|
|
||||||
|
|
||||||
# 需要编译的 .S 文件
|
# 需要编译的 .S 文件
|
||||||
|
|||||||
@ -18,12 +18,24 @@
|
|||||||
#include "bt_tws.h"
|
#include "bt_tws.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define ENABLE_XLOG 1
|
||||||
|
#ifdef xlog
|
||||||
|
#undef xlog
|
||||||
|
#endif
|
||||||
|
#if ENABLE_XLOG
|
||||||
|
#define xlog(format, ...) printf("[XT:%s] " format, __func__, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define xlog(format, ...) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
spinlock_t iic_lock;
|
spinlock_t iic_lock;
|
||||||
|
|
||||||
#define LOG_TAG "[GSENSOR]"
|
#define LOG_TAG "[GSENSOR]"
|
||||||
#define LOG_ERROR_ENABLE
|
#define LOG_ERROR_ENABLE
|
||||||
#define LOG_DEBUG_ENABLE
|
#define LOG_DEBUG_ENABLE
|
||||||
#define LOG_INFO_ENABLE
|
#define xlog_ENABLE
|
||||||
/* #define LOG_DUMP_ENABLE */
|
/* #define LOG_DUMP_ENABLE */
|
||||||
#define LOG_CLI_ENABLE
|
#define LOG_CLI_ENABLE
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@ -82,20 +94,20 @@ void gSensor_int_io_detect(void *priv)
|
|||||||
u8 int_io_status = 0;
|
u8 int_io_status = 0;
|
||||||
u8 det_result = 0;
|
u8 det_result = 0;
|
||||||
int_io_status = gpio_read(platform_data->gSensor_int_io);
|
int_io_status = gpio_read(platform_data->gSensor_int_io);
|
||||||
//log_info("status %d\n",int_io_status);
|
//xlog("status %d\n",int_io_status);
|
||||||
gSensor_hdl->gravity_sensor_ctl(GSENSOR_INT_DET, &int_io_status);
|
gSensor_hdl->gravity_sensor_ctl(GSENSOR_INT_DET, &int_io_status);
|
||||||
if (gSensor_hdl->gravity_sensor_check == NULL) {
|
if (gSensor_hdl->gravity_sensor_check == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
det_result = gSensor_hdl->gravity_sensor_check();
|
det_result = gSensor_hdl->gravity_sensor_check();
|
||||||
if (det_result == 1) {
|
if (det_result == 1) {
|
||||||
log_info("GSENSOR_EVENT_CLICK\n");
|
xlog("GSENSOR_EVENT_CLICK\n");
|
||||||
gSensor_event_to_user(KEY_EVENT_CLICK);
|
gSensor_event_to_user(KEY_EVENT_CLICK);
|
||||||
} else if (det_result == 2) {
|
} else if (det_result == 2) {
|
||||||
log_info("GSENSOR_EVENT_DOUBLE_CLICK\n");
|
xlog("GSENSOR_EVENT_DOUBLE_CLICK\n");
|
||||||
gSensor_event_to_user(KEY_EVENT_DOUBLE_CLICK);
|
gSensor_event_to_user(KEY_EVENT_DOUBLE_CLICK);
|
||||||
} else if (det_result == 3) {
|
} else if (det_result == 3) {
|
||||||
log_info("GSENSOR_EVENT_THREE_CLICK\n");
|
xlog("GSENSOR_EVENT_THREE_CLICK\n");
|
||||||
gSensor_event_to_user(KEY_EVENT_TRIPLE_CLICK);
|
gSensor_event_to_user(KEY_EVENT_TRIPLE_CLICK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,7 +129,7 @@ int gSensor_read_data(u8 *buf, u8 buflen)
|
|||||||
//
|
//
|
||||||
int get_gSensor_data(short *buf)
|
int get_gSensor_data(short *buf)
|
||||||
{
|
{
|
||||||
// printf("%s",__func__);
|
// xlog("%s",__func__);
|
||||||
axis_info_t accel_data[32];
|
axis_info_t accel_data[32];
|
||||||
if (!gpio_read(platform_data->gSensor_int_io)) {
|
if (!gpio_read(platform_data->gSensor_int_io)) {
|
||||||
gSensor_hdl->gravity_sensor_ctl(READ_GSENSOR_DATA, accel_data);
|
gSensor_hdl->gravity_sensor_ctl(READ_GSENSOR_DATA, accel_data);
|
||||||
@ -126,7 +138,7 @@ int get_gSensor_data(short *buf)
|
|||||||
buf[i * 2] = accel_data[i].x;
|
buf[i * 2] = accel_data[i].x;
|
||||||
buf[i * 2 + 1] = accel_data[i].y;
|
buf[i * 2 + 1] = accel_data[i].y;
|
||||||
buf[i * 2 + 2] = accel_data[i].z;
|
buf[i * 2 + 2] = accel_data[i].z;
|
||||||
// printf("cnt:%1d x:%5d y:%5d z:%5d\n", i, accel_data[i].x, accel_data[i].y, accel_data[i].z);
|
// xlog("cnt:%1d x:%5d y:%5d z:%5d\n", i, accel_data[i].x, accel_data[i].y, accel_data[i].z);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +156,7 @@ int read_gsensor_buf(short *buf)
|
|||||||
static u8 wr_lock;
|
static u8 wr_lock;
|
||||||
int read_gsensor_nbuf(short *buf, short datalen)
|
int read_gsensor_nbuf(short *buf, short datalen)
|
||||||
{
|
{
|
||||||
// printf("%s",__func__);
|
// xlog("%s",__func__);
|
||||||
if (data_w_cbuf == NULL) {
|
if (data_w_cbuf == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -161,7 +173,7 @@ int read_gsensor_nbuf(short *buf, short datalen)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
printf("%s NOT ONLINE ", __func__);
|
xlog("%s NOT ONLINE ", __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,91 +187,156 @@ void write_gsensor_data_handle(void)
|
|||||||
if (gSensor_info->init_flag == 1) {
|
if (gSensor_info->init_flag == 1) {
|
||||||
|
|
||||||
// if (read_write_status == 0) {
|
// if (read_write_status == 0) {
|
||||||
// printf("%s ",__func__);
|
// xlog("%s ",__func__);
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (!gpio_read(platform_data->gSensor_int_io)) {
|
if (!gpio_read(platform_data->gSensor_int_io)) {
|
||||||
gSensor_hdl->gravity_sensor_ctl(READ_GSENSOR_DATA, accel_data);
|
gSensor_hdl->gravity_sensor_ctl(READ_GSENSOR_DATA, accel_data);
|
||||||
/*for(int i=0;i<29;i++){
|
/*for(int i=0;i<29;i++){
|
||||||
printf("cnt:%1d x:%5d y:%5d z:%5d\n", i, accel_data[i].x, accel_data[i].y, accel_data[i].z);
|
xlog("cnt:%1d x:%5d y:%5d z:%5d\n", i, accel_data[i].x, accel_data[i].y, accel_data[i].z);
|
||||||
|
|
||||||
}*/
|
}*/
|
||||||
u8 wlen;
|
u8 wlen;
|
||||||
wlen = cbuf_write(data_w_cbuf, accel_data, 2 * 3 * 29);
|
wlen = cbuf_write(data_w_cbuf, accel_data, 2 * 3 * 29);
|
||||||
/* for(int i=0;i<29;i++){ */
|
/* for(int i=0;i<29;i++){ */
|
||||||
/* printf("sour x=%06d y=%06d z=%06d",accel_data[i].x,accel_data[i].y,accel_data[i].z); */
|
/* xlog("sour x=%06d y=%06d z=%06d",accel_data[i].x,accel_data[i].y,accel_data[i].z); */
|
||||||
/* } */
|
/* } */
|
||||||
if (wlen == 0) {
|
if (wlen == 0) {
|
||||||
printf("data_w_cbuf_full");
|
xlog("data_w_cbuf_full");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// printf("%s ",__func__);
|
// xlog("%s ",__func__);
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 临时的设备扫描诊断函数
|
||||||
|
void i2c_scanner_probe(u8* device_addr, u8* found_number)
|
||||||
|
{
|
||||||
|
printf("Starting I2C bus scan...\n");
|
||||||
|
int devices_found = 0;
|
||||||
|
|
||||||
|
// I2C地址范围是 0x08 到 0x77
|
||||||
|
for (uint8_t addr_7bit = 0x00; addr_7bit < 0x7F; addr_7bit++)
|
||||||
|
{
|
||||||
|
// 构建8位的写地址
|
||||||
|
uint8_t write_addr_8bit = (addr_7bit << 1);
|
||||||
|
|
||||||
|
iic_start(gSensor_info->iic_hdl);
|
||||||
|
|
||||||
|
// 尝试发送写地址,并检查返回值
|
||||||
|
// iic_tx_byte 返回 1 表示收到了 ACK
|
||||||
|
if (iic_tx_byte(gSensor_info->iic_hdl, write_addr_8bit))
|
||||||
|
{
|
||||||
|
device_addr[devices_found] = addr_7bit;
|
||||||
|
printf("=====================================================================\n");
|
||||||
|
printf("I2C device found at 7-bit address: 0x%02X\n", addr_7bit);
|
||||||
|
printf("I2C device found at 8-bit address: 0x%02X\n", write_addr_8bit);
|
||||||
|
printf("=====================================================================\n");
|
||||||
|
devices_found++;
|
||||||
|
}
|
||||||
|
|
||||||
|
iic_stop(gSensor_info->iic_hdl);
|
||||||
|
delay(gSensor_info->iic_delay); // 短暂延时
|
||||||
|
}
|
||||||
|
*found_number = devices_found;
|
||||||
|
|
||||||
|
if (devices_found == 0) {
|
||||||
|
printf("Scan finished. No I2C devices found.\n");
|
||||||
|
} else {
|
||||||
|
printf("Scan finished. Found %d device(s).\n", devices_found);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char w_log_buffer_1[100];
|
||||||
|
char w_log_buffer_2[100];
|
||||||
|
char w_log_buffer_3[100];
|
||||||
|
char w_log_buffer_4[100];
|
||||||
|
char w_log_buffer_5[100];
|
||||||
u8 gravity_sensor_command(u8 w_chip_id, u8 register_address, u8 function_command)
|
u8 gravity_sensor_command(u8 w_chip_id, u8 register_address, u8 function_command)
|
||||||
{
|
{
|
||||||
// spin_lock(&sensor_iic);
|
// spin_lock(&sensor_iic);
|
||||||
/* os_mutex_pend(&SENSOR_IIC_MUTEX,0); */
|
/* os_mutex_pend(&SENSOR_IIC_MUTEX,0); */
|
||||||
u8 ret = 1;
|
u8 ret = 1;
|
||||||
|
// xlog("iic_start\n");
|
||||||
iic_start(gSensor_info->iic_hdl);
|
iic_start(gSensor_info->iic_hdl);
|
||||||
|
|
||||||
|
// xlog("iic_tx_byte id\n");
|
||||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, w_chip_id)) {
|
if (0 == iic_tx_byte(gSensor_info->iic_hdl, w_chip_id)) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
log_e("\n gsen iic wr err 0\n");
|
xlog("\n gsen iic wr err 0\n");
|
||||||
|
strcpy(&w_log_buffer_1, "gsen iic wr err 0\n");
|
||||||
goto __gcend;
|
goto __gcend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// xlog("iic delay\n");
|
||||||
delay(gSensor_info->iic_delay);
|
delay(gSensor_info->iic_delay);
|
||||||
|
|
||||||
|
// xlog("iic_tx_byte: address\n");
|
||||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, register_address)) {
|
if (0 == iic_tx_byte(gSensor_info->iic_hdl, register_address)) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
log_e("\n gsen iic wr err 1\n");
|
xlog("\n gsen iic wr err 1\n");
|
||||||
|
strcpy(&w_log_buffer_2, "gsen iic wr err 1\n");
|
||||||
goto __gcend;
|
goto __gcend;
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(gSensor_info->iic_delay);
|
delay(gSensor_info->iic_delay);
|
||||||
|
|
||||||
|
// xlog("iic_tx_byte: command\n");
|
||||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, function_command)) {
|
if (0 == iic_tx_byte(gSensor_info->iic_hdl, function_command)) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
log_e("\n gsen iic wr err 2\n");
|
xlog("\n gsen iic wr err 2\n");
|
||||||
|
strcpy(&w_log_buffer_3, "gsen iic wr err 3\n");
|
||||||
goto __gcend;
|
goto __gcend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strcpy(&w_log_buffer_4, "gsen iic wr sucess\n");
|
||||||
|
// xlog("\n gsen iic wr sucess\n");
|
||||||
|
|
||||||
__gcend:
|
__gcend:
|
||||||
iic_stop(gSensor_info->iic_hdl);
|
iic_stop(gSensor_info->iic_hdl);
|
||||||
// spin_unlock(&sensor_iic);
|
// spin_unlock(&sensor_iic);
|
||||||
/* os_mutex_post(&SENSOR_IIC_MUTEX); */
|
/* os_mutex_post(&SENSOR_IIC_MUTEX); */
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
char sen_log_buffer_1[100];
|
||||||
|
char sen_log_buffer_2[100];
|
||||||
|
char sen_log_buffer_3[100];
|
||||||
|
char sen_log_buffer_4[100];
|
||||||
|
char sen_log_buffer_5[100];
|
||||||
u8 _gravity_sensor_get_ndata(u8 r_chip_id, u8 register_address, u8 *buf, u8 data_len)
|
u8 _gravity_sensor_get_ndata(u8 r_chip_id, u8 register_address, u8 *buf, u8 data_len)
|
||||||
{
|
{
|
||||||
// printf("%s",__func__);
|
// xlog("%s",__func__);
|
||||||
// spin_lock(&sensor_iic);
|
// spin_lock(&sensor_iic);
|
||||||
/* os_mutex_pend(&SENSOR_IIC_MUTEX,0); */
|
/* os_mutex_pend(&SENSOR_IIC_MUTEX,0); */
|
||||||
u8 read_len = 0;
|
u8 read_len = 0;
|
||||||
|
|
||||||
iic_start(gSensor_info->iic_hdl);
|
iic_start(gSensor_info->iic_hdl);
|
||||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, r_chip_id - 1)) {
|
if (0 == iic_tx_byte(gSensor_info->iic_hdl, r_chip_id - 1)) {
|
||||||
log_e("\n gsen iic rd err 0\n");
|
xlog("I2C NACK on writing ADDR: 0x%X\n", r_chip_id - 1);
|
||||||
read_len = 0;
|
read_len = 0;
|
||||||
|
strcpy(&sen_log_buffer_1, "gsen iic rd err 0\n");
|
||||||
goto __gdend;
|
goto __gdend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
delay(gSensor_info->iic_delay);
|
delay(gSensor_info->iic_delay);
|
||||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, register_address)) {
|
if (0 == iic_tx_byte(gSensor_info->iic_hdl, register_address)) {
|
||||||
log_e("\n gsen iic rd err 1\n");
|
xlog("I2C NACK on register ADDR: 0x%X\n", register_address);
|
||||||
|
// xlog("\n gsen iic rd err 1\n");
|
||||||
read_len = 0;
|
read_len = 0;
|
||||||
|
strcpy(&sen_log_buffer_2, "gsen iic rd err 1\n");
|
||||||
goto __gdend;
|
goto __gdend;
|
||||||
}
|
}
|
||||||
|
|
||||||
iic_start(gSensor_info->iic_hdl);
|
iic_start(gSensor_info->iic_hdl);
|
||||||
if (0 == iic_tx_byte(gSensor_info->iic_hdl, r_chip_id)) {
|
if (0 == iic_tx_byte(gSensor_info->iic_hdl, r_chip_id)) {
|
||||||
log_e("\n gsen iic rd err 2\n");
|
xlog("\n gsen iic rd err 2\n");
|
||||||
read_len = 0;
|
read_len = 0;
|
||||||
|
strcpy(&sen_log_buffer_3, "gsen iic rd err 2\n" );
|
||||||
goto __gdend;
|
goto __gdend;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,14 +349,16 @@ u8 _gravity_sensor_get_ndata(u8 r_chip_id, u8 register_address, u8 *buf, u8 data
|
|||||||
|
|
||||||
*buf = iic_rx_byte(gSensor_info->iic_hdl, 0);
|
*buf = iic_rx_byte(gSensor_info->iic_hdl, 0);
|
||||||
read_len ++;
|
read_len ++;
|
||||||
|
strcpy(&sen_log_buffer_4, "gsen iic rd success\n");
|
||||||
|
// xlog("\n gsen iic rd success\n");
|
||||||
|
|
||||||
__gdend:
|
__gdend:
|
||||||
|
|
||||||
iic_stop(gSensor_info->iic_hdl);
|
iic_stop(gSensor_info->iic_hdl);
|
||||||
delay(gSensor_info->iic_delay);
|
delay(gSensor_info->iic_delay);
|
||||||
// spin_unlock(&sensor_iic);
|
// spin_unlock(&sensor_iic);
|
||||||
|
|
||||||
/* os_mutex_post(&SENSOR_IIC_MUTEX); */
|
/* os_mutex_post(&SENSOR_IIC_MUTEX); */
|
||||||
|
// strcpy(&sen_log_buffer_5, "gsen iic rd err\n");
|
||||||
return read_len;
|
return read_len;
|
||||||
}
|
}
|
||||||
void gsensor_io_ctl(u8 cmd, void *arg)
|
void gsensor_io_ctl(u8 cmd, void *arg)
|
||||||
@ -302,13 +381,13 @@ int gravity_sensor_init(void *_data)
|
|||||||
gSensor_info->iic_hdl = platform_data->iic;
|
gSensor_info->iic_hdl = platform_data->iic;
|
||||||
retval = iic_init(gSensor_info->iic_hdl);
|
retval = iic_init(gSensor_info->iic_hdl);
|
||||||
|
|
||||||
log_e("\n gravity_sensor_init\n");
|
xlog("\n gravity_sensor_init\n");
|
||||||
|
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
log_e("\n open iic for gsensor err\n");
|
xlog("\n open iic for gsensor err\n");
|
||||||
return retval;
|
return retval;
|
||||||
} else {
|
} else {
|
||||||
log_info("\n iic open succ\n");
|
xlog("\n iic open succ\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = -EINVAL;
|
retval = -EINVAL;
|
||||||
@ -320,14 +399,14 @@ int gravity_sensor_init(void *_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
log_e(">>>gSensor_hdl logo err\n");
|
xlog(">>>gSensor_hdl logo err\n");
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gSensor_hdl->gravity_sensor_init()) {
|
if (gSensor_hdl->gravity_sensor_init()) {
|
||||||
log_e(">>>>gSensor_Int ERROR\n");
|
xlog(">>>>gSensor_Int ERROR\n");
|
||||||
} else {
|
} else {
|
||||||
log_info(">>>>gSensor_Int SUCC\n");
|
xlog(">>>>gSensor_Int SUCC\n");
|
||||||
gSensor_info->init_flag = 1;
|
gSensor_info->init_flag = 1;
|
||||||
if (platform_data->gSensor_int_io != -1) {
|
if (platform_data->gSensor_int_io != -1) {
|
||||||
gpio_set_pull_up(platform_data->gSensor_int_io, 1);
|
gpio_set_pull_up(platform_data->gSensor_int_io, 1);
|
||||||
@ -336,7 +415,7 @@ int gravity_sensor_init(void *_data)
|
|||||||
gpio_set_die(platform_data->gSensor_int_io, 1);
|
gpio_set_die(platform_data->gSensor_int_io, 1);
|
||||||
data_buf = zalloc(BUF_SIZE);
|
data_buf = zalloc(BUF_SIZE);
|
||||||
if (data_buf == NULL) {
|
if (data_buf == NULL) {
|
||||||
printf("gsensor_cbuf_error!");
|
xlog("gsensor_cbuf_error!");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -347,7 +426,7 @@ int gravity_sensor_init(void *_data)
|
|||||||
cbuf_init(data_w_cbuf, data_buf, BUF_SIZE);
|
cbuf_init(data_w_cbuf, data_buf, BUF_SIZE);
|
||||||
/* port_edge_wkup_set_callback(write_gsensor_data_handle); */
|
/* port_edge_wkup_set_callback(write_gsensor_data_handle); */
|
||||||
/* 已改为使用port_edge_wkup_set_callback_by_index,使用时需要重新实现 */
|
/* 已改为使用port_edge_wkup_set_callback_by_index,使用时需要重新实现 */
|
||||||
printf("cbuf_init");
|
xlog("cbuf_init");
|
||||||
// spin_lock_init(&iic_lock);
|
// spin_lock_init(&iic_lock);
|
||||||
|
|
||||||
// sys_s_hi_timer_add(NULL, gSensor_int_io_detect, 10); //10ms
|
// sys_s_hi_timer_add(NULL, gSensor_int_io_detect, 10); //10ms
|
||||||
@ -388,7 +467,7 @@ int gsensor_enable(void)
|
|||||||
//工作空间
|
//工作空间
|
||||||
data_buf = zalloc(BUF_SIZE);
|
data_buf = zalloc(BUF_SIZE);
|
||||||
if (data_buf == NULL) {
|
if (data_buf == NULL) {
|
||||||
printf("gsensor_cbuf_error!");
|
xlog("gsensor_cbuf_error!");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
data_w_cbuf = zalloc(sizeof(cbuffer_t));
|
data_w_cbuf = zalloc(sizeof(cbuffer_t));
|
||||||
@ -396,7 +475,7 @@ int gsensor_enable(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
cbuf_init(data_w_cbuf, data_buf, BUF_SIZE);
|
cbuf_init(data_w_cbuf, data_buf, BUF_SIZE);
|
||||||
printf("cbuf_init");
|
xlog("cbuf_init");
|
||||||
//设置参数
|
//设置参数
|
||||||
valid = 0;
|
valid = 0;
|
||||||
gSensor_hdl->gravity_sensor_ctl(GSENSOR_RESET_INT, &valid);
|
gSensor_hdl->gravity_sensor_ctl(GSENSOR_RESET_INT, &valid);
|
||||||
@ -404,6 +483,6 @@ int gsensor_enable(void)
|
|||||||
if (valid == -1) {
|
if (valid == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
printf("gsensor_reset_succeed\n");
|
xlog("gsensor_reset_succeed\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,7 +49,7 @@
|
|||||||
#include "classic/tws_api.h"
|
#include "classic/tws_api.h"
|
||||||
#include "rcsp_adv_user_update.h"
|
#include "rcsp_adv_user_update.h"
|
||||||
#include "bt_tws.h"
|
#include "bt_tws.h"
|
||||||
|
// #include "le_trans_data.h"
|
||||||
#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV_RCSP)
|
#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_ADV_RCSP)
|
||||||
|
|
||||||
#if TCFG_CHARGE_BOX_ENABLE
|
#if TCFG_CHARGE_BOX_ENABLE
|
||||||
@ -86,8 +86,10 @@ static const char user_tag_string[] = {EIR_TAG_STRING};
|
|||||||
/* #include "debug.h" */
|
/* #include "debug.h" */
|
||||||
|
|
||||||
//------
|
//------
|
||||||
#define ATT_LOCAL_PAYLOAD_SIZE (200) //note: need >= 20
|
// #define ATT_LOCAL_PAYLOAD_SIZE (200*10) //note: need >= 20
|
||||||
#define ATT_SEND_CBUF_SIZE (512) //note: need >= 20,缓存大小,可修改
|
// #define ATT_SEND_CBUF_SIZE (1024 * 50) //note: need >= 20,缓存大小,可修改
|
||||||
|
#define ATT_LOCAL_PAYLOAD_SIZE (517) //note: need >= 20
|
||||||
|
#define ATT_SEND_CBUF_SIZE (1024 * 2) //note: need >= 20,缓存大小,可修改
|
||||||
#define ATT_RAM_BUFSIZE (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_PAYLOAD_SIZE + ATT_SEND_CBUF_SIZE) //note:
|
#define ATT_RAM_BUFSIZE (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_PAYLOAD_SIZE + ATT_SEND_CBUF_SIZE) //note:
|
||||||
static u8 att_ram_buffer[ATT_RAM_BUFSIZE] __attribute__((aligned(4)));
|
static u8 att_ram_buffer[ATT_RAM_BUFSIZE] __attribute__((aligned(4)));
|
||||||
//---------------
|
//---------------
|
||||||
@ -109,9 +111,10 @@ static const uint8_t sm_min_key_size = 7;
|
|||||||
static const uint8_t connection_update_enable = 1; ///0--disable, 1--enable
|
static const uint8_t connection_update_enable = 1; ///0--disable, 1--enable
|
||||||
static uint8_t connection_update_cnt = 0; //
|
static uint8_t connection_update_cnt = 0; //
|
||||||
static const struct conn_update_param_t connection_param_table[] = {
|
static const struct conn_update_param_t connection_param_table[] = {
|
||||||
{16, 24, 16, 600},
|
{6, 12, 0, 400},//3.7
|
||||||
{12, 28, 14, 600},//11
|
// {16, 24, 16, 600},
|
||||||
{8, 20, 20, 600},//3.7
|
// {12, 28, 14, 600},//11
|
||||||
|
// {8, 20, 20, 600},//3.7
|
||||||
/* {12, 28, 4, 600},//3.7 */
|
/* {12, 28, 4, 600},//3.7 */
|
||||||
/* {12, 24, 30, 600},//3.05 */
|
/* {12, 24, 30, 600},//3.05 */
|
||||||
};
|
};
|
||||||
@ -299,6 +302,17 @@ void test_data_send_packet(void)
|
|||||||
|
|
||||||
static void can_send_now_wakeup(void)
|
static void can_send_now_wakeup(void)
|
||||||
{
|
{
|
||||||
|
// static signed char acc_data_buf[60] = {
|
||||||
|
// 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22
|
||||||
|
// };
|
||||||
|
// extern void send_data_to_ble_client(const u8* data, u16 length);
|
||||||
|
// send_data_to_ble_client(&acc_data_buf, 60);
|
||||||
|
|
||||||
putchar('E');
|
putchar('E');
|
||||||
if (ble_resume_send_wakeup) {
|
if (ble_resume_send_wakeup) {
|
||||||
ble_resume_send_wakeup();
|
ble_resume_send_wakeup();
|
||||||
@ -315,6 +329,24 @@ u8 ble_update_get_ready_jump_flag(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加到 le_rcsp_adv_module.c
|
||||||
|
static void set_connection_data_length(u16 tx_octets, u16 tx_time) //xtell
|
||||||
|
{
|
||||||
|
if (con_handle) {
|
||||||
|
ble_user_cmd_prepare(BLE_CMD_SET_DATA_LENGTH, 3, con_handle, tx_octets, tx_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_connection_data_phy(u8 tx_phy, u8 rx_phy)//xtell
|
||||||
|
{
|
||||||
|
if (0 == con_handle) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
u8 all_phys = 0;
|
||||||
|
u16 phy_options = 0; // 根据你的 SDK 定义调整
|
||||||
|
ble_user_cmd_prepare(BLE_CMD_SET_PHY, 5, con_handle, all_phys, tx_phy, rx_phy, phy_options);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @section Packet Handler
|
* @section Packet Handler
|
||||||
*
|
*
|
||||||
@ -370,6 +402,16 @@ static void cbk_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *p
|
|||||||
connection_update_complete_success(packet);
|
connection_update_complete_success(packet);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE: //xtell
|
||||||
|
log_info("APP HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE\n");
|
||||||
|
set_connection_data_phy(2, 2); // 2 表示 2M PHY
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HCI_SUBEVENT_LE_PHY_UPDATE_COMPLETE://xtell
|
||||||
|
log_info("APP HCI_SUBEVENT_LE_PHY_UPDATE %s\n", packet[4] ? "Fail" : "Succ"); // packet[4] 是 status
|
||||||
|
log_info("Tx PHY: %d\n", packet[5]); // packet[5] 是 TX_PHY
|
||||||
|
log_info("Rx PHY: %d\n", packet[6]); // packet[6] 是 RX_PHY
|
||||||
|
break;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCI_EVENT_DISCONNECTION_COMPLETE:
|
case HCI_EVENT_DISCONNECTION_COMPLETE:
|
||||||
@ -410,6 +452,7 @@ static void cbk_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *p
|
|||||||
mtu = att_event_mtu_exchange_complete_get_MTU(packet) - 3;
|
mtu = att_event_mtu_exchange_complete_get_MTU(packet) - 3;
|
||||||
log_info("ATT MTU = %u\n", mtu);
|
log_info("ATT MTU = %u\n", mtu);
|
||||||
ble_user_cmd_prepare(BLE_CMD_ATT_MTU_SIZE, 1, mtu);
|
ble_user_cmd_prepare(BLE_CMD_ATT_MTU_SIZE, 1, mtu);
|
||||||
|
set_connection_data_length(251, 2120);//xtell
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCI_EVENT_VENDOR_REMOTE_TEST:
|
case HCI_EVENT_VENDOR_REMOTE_TEST:
|
||||||
@ -546,6 +589,8 @@ static int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_h
|
|||||||
app_recieve_callback(0, buffer, buffer_size);
|
app_recieve_callback(0, buffer, buffer_size);
|
||||||
}
|
}
|
||||||
// JL_rcsp_auth_recieve(data, len);
|
// JL_rcsp_auth_recieve(data, len);
|
||||||
|
extern void le_user_app_send_event(size_t command, unsigned char* data, size_t size);
|
||||||
|
le_user_app_send_event(ATT_CHARACTERISTIC_ae01_01_VALUE_HANDLE, buffer, buffer_size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
@ -569,6 +614,7 @@ static int app_send_user_data(u16 handle, u8 *data, u16 len, u8 handle_type)
|
|||||||
|
|
||||||
ret = ble_user_cmd_prepare(BLE_CMD_ATT_SEND_DATA, 4, handle, data, len, handle_type);
|
ret = ble_user_cmd_prepare(BLE_CMD_ATT_SEND_DATA, 4, handle, data, len, handle_type);
|
||||||
if (ret == BLE_BUFFER_FULL) {
|
if (ret == BLE_BUFFER_FULL) {
|
||||||
|
printf("app_send_user_data: buffer full\n");
|
||||||
ret = APP_BLE_BUFF_FULL;
|
ret = APP_BLE_BUFF_FULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -588,7 +634,7 @@ static const u8 dueros_dma_uuid_16bit[] = {0x04, 0xFE};
|
|||||||
extern u8 *get_chargebox_adv_addr(void);
|
extern u8 *get_chargebox_adv_addr(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void rcsp_adv_fill_mac_addr(u8 *mac_addr_buf)
|
void rcsp_adv_fill_mac_addr(u8 *mac_addr_buf)
|
||||||
{
|
{
|
||||||
#if (MUTIl_CHARGING_BOX_EN)
|
#if (MUTIl_CHARGING_BOX_EN)
|
||||||
u8 *mac_addr = get_chargebox_adv_addr();
|
u8 *mac_addr = get_chargebox_adv_addr();
|
||||||
@ -1423,9 +1469,25 @@ void ble_module_enable(u8 en)
|
|||||||
#if(TCFG_CHARGE_BOX_ENABLE)
|
#if(TCFG_CHARGE_BOX_ENABLE)
|
||||||
extern u8 get_chgbox_lid_status(void);
|
extern u8 get_chgbox_lid_status(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void user_ble_gap_device_set(char* name){ //xtell-set
|
||||||
|
|
||||||
|
if(strlen(name) < BT_NAME_LEN_MAX){
|
||||||
|
strcpy(gap_device_name,name);
|
||||||
|
|
||||||
|
//刷新广播
|
||||||
|
bt_ble_adv_enable(0);
|
||||||
|
make_set_adv_data();
|
||||||
|
make_set_rsp_data();
|
||||||
|
bt_ble_adv_enable(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
void bt_ble_init(void)
|
void bt_ble_init(void)
|
||||||
{
|
{
|
||||||
log_info("***** ble_init******\n");
|
log_info("***** ble_init******\n");
|
||||||
|
//xtell-set
|
||||||
|
// extern char xt_ble_new_name[9];
|
||||||
|
// user_ble_gap_device_set(xt_ble_new_name);
|
||||||
|
|
||||||
gap_device_name = bt_get_local_name();
|
gap_device_name = bt_get_local_name();
|
||||||
gap_device_name_len = strlen(gap_device_name);
|
gap_device_name_len = strlen(gap_device_name);
|
||||||
@ -1645,12 +1707,8 @@ void send_version_to_sibling(void)
|
|||||||
data[2] = ver >> 8;
|
data[2] = ver >> 8;
|
||||||
tws_api_send_data_to_sibling(data, sizeof(data), TWS_FUNC_ID_SEQ_RAND_SYNC);
|
tws_api_send_data_to_sibling(data, sizeof(data), TWS_FUNC_ID_SEQ_RAND_SYNC);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void send_data_to_ble_client(const u8* data, u16 length)
|
void send_data_to_ble_client(const u8* data, u16 length)
|
||||||
{
|
{
|
||||||
// 检查数据长度是否有效
|
// 检查数据长度是否有效
|
||||||
@ -1659,8 +1717,8 @@ void send_data_to_ble_client(const u8* data, u16 length)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查缓冲区空间
|
// // 检查缓冲区空间
|
||||||
if (app_send_user_data_check(length)) {
|
// if (app_send_user_data_check(length)) {
|
||||||
// 发送数据
|
// 发送数据
|
||||||
int ret = app_send_user_data(ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE, data, length, ATT_OP_NOTIFY);
|
int ret = app_send_user_data(ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE, data, length, ATT_OP_NOTIFY);
|
||||||
if (ret == 0) { // 假设 0 表示成功
|
if (ret == 0) { // 假设 0 表示成功
|
||||||
@ -1668,7 +1726,12 @@ void send_data_to_ble_client(const u8* data, u16 length)
|
|||||||
} else {
|
} else {
|
||||||
// printf("Failed to send data: Length %d, Error code: %d\n", length, ret);
|
// printf("Failed to send data: Length %d, Error code: %d\n", length, ret);
|
||||||
}
|
}
|
||||||
} else {
|
// } else {
|
||||||
// printf("Insufficient buffer space to send data: Length %d\n", length);
|
// printf("Insufficient buffer space to send data: Length %d\n", length);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -530,6 +530,7 @@ void JL_rcsp_msg_deal(void *hdl, u8 event, u8 *msg)
|
|||||||
|
|
||||||
case MSG_JL_ENTER_UPDATE_MODE:
|
case MSG_JL_ENTER_UPDATE_MODE:
|
||||||
rcsp_printf("MSG_JL_ENTER_UPDATE_MODE:%x %x\n", msg[0], msg[1]);
|
rcsp_printf("MSG_JL_ENTER_UPDATE_MODE:%x %x\n", msg[0], msg[1]);
|
||||||
|
clk_set("sys",96*1000000L);
|
||||||
bt_set_low_latency_mode(0);
|
bt_set_low_latency_mode(0);
|
||||||
if (support_dual_bank_update_en && !tws_api_get_role()) {
|
if (support_dual_bank_update_en && !tws_api_get_role()) {
|
||||||
u8 status = 0;
|
u8 status = 0;
|
||||||
|
|||||||
@ -81,9 +81,9 @@ extern void printf_buf(u8 *buf, u32 len);
|
|||||||
|
|
||||||
//------
|
//------
|
||||||
//ATT发送的包长, note: 20 <=need >= MTU
|
//ATT发送的包长, note: 20 <=need >= MTU
|
||||||
#define ATT_LOCAL_MTU_SIZE (200) //
|
#define ATT_LOCAL_MTU_SIZE (517) //200
|
||||||
//ATT缓存的buffer大小, note: need >= 20,可修改
|
//ATT缓存的buffer大小, note: need >= 20,可修改
|
||||||
#define ATT_SEND_CBUF_SIZE (512) //
|
#define ATT_SEND_CBUF_SIZE (512 * 20) //
|
||||||
|
|
||||||
//共配置的RAM
|
//共配置的RAM
|
||||||
#define ATT_RAM_BUFSIZE (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_MTU_SIZE + ATT_SEND_CBUF_SIZE) //note:
|
#define ATT_RAM_BUFSIZE (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_MTU_SIZE + ATT_SEND_CBUF_SIZE) //note:
|
||||||
@ -125,9 +125,10 @@ static uint8_t connection_update_cnt = 0; //
|
|||||||
|
|
||||||
//参数表
|
//参数表
|
||||||
static const struct conn_update_param_t connection_param_table[] = {
|
static const struct conn_update_param_t connection_param_table[] = {
|
||||||
{16, 24, 10, 600},//11
|
{6, 12, 0, 400},//11
|
||||||
{12, 28, 10, 600},//3.7
|
// {16, 24, 10, 600},//11
|
||||||
{8, 20, 10, 600},
|
// {12, 28, 10, 600},//3.7
|
||||||
|
// {8, 20, 10, 600},
|
||||||
/* {12, 28, 4, 600},//3.7 */
|
/* {12, 28, 4, 600},//3.7 */
|
||||||
/* {12, 24, 30, 600},//3.05 */
|
/* {12, 24, 30, 600},//3.05 */
|
||||||
};
|
};
|
||||||
@ -706,6 +707,8 @@ static int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_h
|
|||||||
u16 handle = att_handle;
|
u16 handle = att_handle;
|
||||||
|
|
||||||
log_info("write_callback, handle= 0x%04x,size = %d\n", handle, buffer_size);
|
log_info("write_callback, handle= 0x%04x,size = %d\n", handle, buffer_size);
|
||||||
|
extern void le_user_app_event(u8* buffer);
|
||||||
|
le_user_app_event(buffer);
|
||||||
|
|
||||||
switch (handle) {
|
switch (handle) {
|
||||||
|
|
||||||
@ -1389,6 +1392,44 @@ void hangup_ans_call_handle(u8 en)
|
|||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void send_data_to_ble_client(const u8* data, u16 length)
|
||||||
|
{
|
||||||
|
// 检查数据长度是否有效
|
||||||
|
if (length == 0 || length > 512) {
|
||||||
|
printf("Error: Data length %d is out of range (1-512)\n", length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 检查缓冲区空间
|
||||||
|
// if (app_send_user_data_check(length)) {
|
||||||
|
// 发送数据
|
||||||
|
int ret = app_send_user_data(ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE, data, length, ATT_OP_NOTIFY);
|
||||||
|
if (ret == 0) { // 假设 0 表示成功
|
||||||
|
// printf("Data sent successfully: Length %d\n", length);
|
||||||
|
} else {
|
||||||
|
printf("Failed to send data: Length %d, Error code: %d\n", length, ret);
|
||||||
|
}
|
||||||
|
// } else {
|
||||||
|
// printf("Insufficient buffer space to send data: Length %d\n", length);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void rcsp_adv_fill_mac_addr(u8 *mac_addr_buf)
|
||||||
|
{
|
||||||
|
#if (MUTIl_CHARGING_BOX_EN)
|
||||||
|
u8 *mac_addr = get_chargebox_adv_addr();
|
||||||
|
if (mac_addr) {
|
||||||
|
swapX(mac_addr, mac_addr_buf, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* printf("mac_addr:"); */
|
||||||
|
/* printf_buf(mac_addr_buf, 6); */
|
||||||
|
|
||||||
|
#else
|
||||||
|
swapX(bt_get_mac_addr(), mac_addr_buf, 6);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -37,7 +37,7 @@ extern void printf_buf(u8 *buf, u32 len);
|
|||||||
//------
|
//------
|
||||||
//ATT发送的包长, note: 20 <=need >= MTU
|
//ATT发送的包长, note: 20 <=need >= MTU
|
||||||
#define ATT_LOCAL_MTU_SIZE (517) //
|
#define ATT_LOCAL_MTU_SIZE (517) //
|
||||||
//ATT缓存的buffer大小, note: need >= 20,可修改
|
//ATT缓存的buffer大小, +: need >= 20,可修改
|
||||||
#if(APP_MAIN == APP_WIRELESS_MIC_2T1)
|
#if(APP_MAIN == APP_WIRELESS_MIC_2T1)
|
||||||
#define ATT_SEND_CBUF_SIZE (90)
|
#define ATT_SEND_CBUF_SIZE (90)
|
||||||
#else
|
#else
|
||||||
@ -92,7 +92,8 @@ static uint8_t connection_update_cnt = 0; //
|
|||||||
|
|
||||||
//参数表
|
//参数表
|
||||||
static const struct conn_update_param_t connection_param_table[] = {
|
static const struct conn_update_param_t connection_param_table[] = {
|
||||||
{WIRELESS_BLE_CONNECT_INTERVAL, WIRELESS_BLE_CONNECT_INTERVAL, 0, 100},//11
|
// {1, 5, 4, 600},//11
|
||||||
|
{12, 24, 0, 400}, // 建议修改为此值 (15ms - 30ms interval)
|
||||||
};
|
};
|
||||||
|
|
||||||
//共可用的参数组数
|
//共可用的参数组数
|
||||||
@ -421,7 +422,7 @@ static void cbk_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *p
|
|||||||
|
|
||||||
case HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE:
|
case HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE:
|
||||||
log_info("APP HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE\n");
|
log_info("APP HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE\n");
|
||||||
set_connection_data_phy(CONN_SET_2M_PHY, CONN_SET_2M_PHY);
|
// set_connection_data_phy(CONN_SET_2M_PHY, CONN_SET_2M_PHY);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCI_SUBEVENT_LE_PHY_UPDATE_COMPLETE:
|
case HCI_SUBEVENT_LE_PHY_UPDATE_COMPLETE:
|
||||||
@ -453,7 +454,7 @@ static void cbk_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *p
|
|||||||
mtu = att_event_mtu_exchange_complete_get_MTU(packet) - 3;
|
mtu = att_event_mtu_exchange_complete_get_MTU(packet) - 3;
|
||||||
log_info("ATT MTU = %u\n", mtu);
|
log_info("ATT MTU = %u\n", mtu);
|
||||||
ble_op_att_set_send_mtu(mtu);
|
ble_op_att_set_send_mtu(mtu);
|
||||||
set_connection_data_length(251, 2120);
|
// set_connection_data_length(251, 2120);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCI_EVENT_VENDOR_REMOTE_TEST:
|
case HCI_EVENT_VENDOR_REMOTE_TEST:
|
||||||
@ -1067,6 +1068,44 @@ void ble_server_send_test_key_num(u8 key_num)
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void send_data_to_ble_client(const u8* data, u16 length)
|
||||||
|
{
|
||||||
|
// 检查数据长度是否有效
|
||||||
|
if (length == 0 || length > 512) {
|
||||||
|
printf("Error: Data length %d is out of range (1-512)\n", length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 检查缓冲区空间
|
||||||
|
// if (app_send_user_data_check(length)) {
|
||||||
|
// 发送数据
|
||||||
|
int ret = app_send_user_data(ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE, data, length, ATT_OP_NOTIFY);
|
||||||
|
if (ret == 0) { // 假设 0 表示成功
|
||||||
|
printf("Data sent successfully: Length %d\n", length);
|
||||||
|
} else {
|
||||||
|
printf("Failed to send data: Length %d, Error code: %d\n", length, ret);
|
||||||
|
}
|
||||||
|
// } else {
|
||||||
|
// printf("Insufficient buffer space to send data: Length %d\n", length);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void rcsp_adv_fill_mac_addr(u8 *mac_addr_buf)
|
||||||
|
{
|
||||||
|
#if (MUTIl_CHARGING_BOX_EN)
|
||||||
|
u8 *mac_addr = get_chargebox_adv_addr();
|
||||||
|
if (mac_addr) {
|
||||||
|
swapX(mac_addr, mac_addr_buf, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* printf("mac_addr:"); */
|
||||||
|
/* printf_buf(mac_addr_buf, 6); */
|
||||||
|
|
||||||
|
#else
|
||||||
|
swapX(bt_get_mac_addr(), mac_addr_buf, 6);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -57,14 +57,14 @@ const struct task_info task_info_table[] = {
|
|||||||
#else
|
#else
|
||||||
{"btstack", 3, 0, 768, 256 },
|
{"btstack", 3, 0, 768, 256 },
|
||||||
#endif
|
#endif
|
||||||
{"audio_dec", 5, 0, 800, 128 },
|
// {"audio_dec", 5, 0, 800, 128 },
|
||||||
{"aud_effect", 5, 1, 800, 128 },
|
// {"aud_effect", 5, 1, 800, 128 },
|
||||||
/*
|
/*
|
||||||
*为了防止dac buf太大,通话一开始一直解码,
|
*为了防止dac buf太大,通话一开始一直解码,
|
||||||
*导致编码输入数据需要很大的缓存,这里提高编码的优先级
|
*导致编码输入数据需要很大的缓存,这里提高编码的优先级
|
||||||
*/
|
*/
|
||||||
{"audio_enc", 6, 0, 768, 128 },
|
// {"audio_enc", 6, 0, 768, 128 },
|
||||||
{"aec", 2, 1, 768, 128 },
|
// {"aec", 2, 1, 768, 128 },
|
||||||
#if TCFG_AUDIO_HEARING_AID_ENABLE
|
#if TCFG_AUDIO_HEARING_AID_ENABLE
|
||||||
{"HearingAid", 6, 0, 768, 128 },
|
{"HearingAid", 6, 0, 768, 128 },
|
||||||
#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
|
#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
|
||||||
@ -86,9 +86,9 @@ const struct task_info task_info_table[] = {
|
|||||||
{"tws_ota_msg", 2, 0, 256, 128 },
|
{"tws_ota_msg", 2, 0, 256, 128 },
|
||||||
{"dw_update", 2, 0, 256, 128 },
|
{"dw_update", 2, 0, 256, 128 },
|
||||||
{"rcsp_task", 2, 0, 640, 128 },
|
{"rcsp_task", 2, 0, 640, 128 },
|
||||||
{"aud_capture", 4, 0, 512, 256 },
|
// {"aud_capture", 4, 0, 512, 256 },
|
||||||
{"data_export", 5, 0, 512, 256 },
|
// {"data_export", 5, 0, 512, 256 },
|
||||||
{"anc", 3, 1, 512, 128 },
|
// {"anc", 3, 1, 512, 128 },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if TCFG_GX8002_NPU_ENABLE
|
#if TCFG_GX8002_NPU_ENABLE
|
||||||
@ -102,9 +102,9 @@ const struct task_info task_info_table[] = {
|
|||||||
#if TCFG_KWS_VOICE_RECOGNITION_ENABLE
|
#if TCFG_KWS_VOICE_RECOGNITION_ENABLE
|
||||||
{"kws", 2, 0, 256, 64 },
|
{"kws", 2, 0, 256, 64 },
|
||||||
#endif /* #if TCFG_KWS_VOICE_RECOGNITION_ENABLE */
|
#endif /* #if TCFG_KWS_VOICE_RECOGNITION_ENABLE */
|
||||||
{"usb_msd", 1, 0, 512, 128 },
|
// {"usb_msd", 1, 0, 512, 128 },
|
||||||
#if !TCFG_USB_MIC_CVP_ENABLE
|
#if !TCFG_USB_MIC_CVP_ENABLE
|
||||||
{"usbmic_write", 2, 0, 256, 128 },
|
// {"usbmic_write", 2, 0, 256, 128 },
|
||||||
#endif
|
#endif
|
||||||
#if AI_APP_PROTOCOL
|
#if AI_APP_PROTOCOL
|
||||||
{"app_proto", 2, 0, 768, 64 },
|
{"app_proto", 2, 0, 768, 64 },
|
||||||
@ -112,12 +112,12 @@ const struct task_info task_info_table[] = {
|
|||||||
#if (TCFG_SPI_LCD_ENABLE||TCFG_SIMPLE_LCD_ENABLE)
|
#if (TCFG_SPI_LCD_ENABLE||TCFG_SIMPLE_LCD_ENABLE)
|
||||||
{"ui", 2, 0, 768, 256 },
|
{"ui", 2, 0, 768, 256 },
|
||||||
#else
|
#else
|
||||||
{"ui", 3, 0, 384 - 64, 128 },
|
// {"ui", 3, 0, 384 - 64, 128 },
|
||||||
#endif
|
#endif
|
||||||
#if (TCFG_DEV_MANAGER_ENABLE)
|
#if (TCFG_DEV_MANAGER_ENABLE)
|
||||||
{"dev_mg", 3, 0, 512, 512 },
|
{"dev_mg", 3, 0, 512, 512 },
|
||||||
#endif
|
#endif
|
||||||
{"audio_vad", 1, 1, 512, 128 },
|
// {"audio_vad", 1, 1, 512, 128 },
|
||||||
#if TCFG_KEY_TONE_EN
|
#if TCFG_KEY_TONE_EN
|
||||||
{"key_tone", 5, 0, 256, 32 },
|
{"key_tone", 5, 0, 256, 32 },
|
||||||
#endif
|
#endif
|
||||||
@ -137,7 +137,7 @@ const struct task_info task_info_table[] = {
|
|||||||
{"icsd_src", 2, 1, 512, 128 },
|
{"icsd_src", 2, 1, 512, 128 },
|
||||||
#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
|
#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
|
||||||
{"pmu_task", 6, 0, 256, 128 },
|
{"pmu_task", 6, 0, 256, 128 },
|
||||||
{"WindDetect", 2, 0, 256, 128 },
|
// {"WindDetect", 2, 0, 256, 128 },
|
||||||
{0, 0},
|
{0, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -249,7 +249,7 @@ const struct vad_mic_platform_data vad_mic_data = {
|
|||||||
.mic_ldo2PAD_en = 1,
|
.mic_ldo2PAD_en = 1,
|
||||||
.mic_bias_en = 0,
|
.mic_bias_en = 0,
|
||||||
.mic_bias_res = 0,
|
.mic_bias_res = 0,
|
||||||
.mic_bias_inside = TCFG_AUDIO_MIC0_BIAS_EN,
|
// .mic_bias_inside = TCFG_AUDIO_MIC0_BIAS_EN,
|
||||||
/* ADC偏置电阻配置*/
|
/* ADC偏置电阻配置*/
|
||||||
.adc_rbs = 3,
|
.adc_rbs = 3,
|
||||||
/* ADC输入电阻配置*/
|
/* ADC输入电阻配置*/
|
||||||
@ -520,11 +520,13 @@ const struct hw_iic_config hw_iic_cfg[] = {
|
|||||||
{IO_PORTC_02, IO_PORTC_03}, //group c
|
{IO_PORTC_02, IO_PORTC_03}, //group c
|
||||||
{IO_PORTA_05, IO_PORTA_06}, //group d
|
{IO_PORTA_05, IO_PORTA_06}, //group d
|
||||||
*/
|
*/
|
||||||
.port = TCFG_HW_I2C0_PORTS,
|
// .port = TCFG_HW_I2C0_PORTS,
|
||||||
|
// .port = {IO_PORTC_04,IO_PORTC_05}, // portB: scl、sda
|
||||||
|
.port = {IO_PORTB_04,IO_PORTB_05}, // portA: scl、sda
|
||||||
.baudrate = TCFG_HW_I2C0_CLK, //IIC通讯波特率
|
.baudrate = TCFG_HW_I2C0_CLK, //IIC通讯波特率
|
||||||
.hdrive = 0, //是否打开IO口强驱
|
.hdrive = 0, //是否打开IO口强驱
|
||||||
.io_filter = 1, //是否打开滤波器(去纹波)
|
.io_filter = 1, //是否打开滤波器(去纹波)
|
||||||
.io_pu = 1, //是否打开上拉电阻,如果外部电路没有焊接上拉电阻需要置1
|
.io_pu = 0, //是否打开上拉电阻,如果外部电路没有焊接上拉电阻需要置1
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -715,7 +717,7 @@ struct port_wakeup port0 = {
|
|||||||
.pullup_down_enable = ENABLE, //配置I/O 内部上下拉是否使能
|
.pullup_down_enable = ENABLE, //配置I/O 内部上下拉是否使能
|
||||||
.edge = FALLING_EDGE, //唤醒方式选择,可选:上升沿\下降沿
|
.edge = FALLING_EDGE, //唤醒方式选择,可选:上升沿\下降沿
|
||||||
.filter = PORT_FLT_8ms,
|
.filter = PORT_FLT_8ms,
|
||||||
.iomap = IO_PORTB_01, //唤醒口选择
|
.iomap = IO_PORTA_04, //唤醒口选择
|
||||||
};
|
};
|
||||||
|
|
||||||
#if (TCFG_TEST_BOX_ENABLE || TCFG_CHARGESTORE_ENABLE || TCFG_ANC_BOX_ENABLE || TCFG_UMIDIGI_BOX_ENABLE)
|
#if (TCFG_TEST_BOX_ENABLE || TCFG_CHARGESTORE_ENABLE || TCFG_ANC_BOX_ENABLE || TCFG_UMIDIGI_BOX_ENABLE)
|
||||||
|
|||||||
@ -21,10 +21,12 @@
|
|||||||
//*********************************************************************************//
|
//*********************************************************************************//
|
||||||
// UART配置 //
|
// UART配置 //
|
||||||
//*********************************************************************************//
|
//*********************************************************************************//
|
||||||
#define TCFG_UART0_ENABLE ENABLE_THIS_MOUDLE //串口打印模块使能
|
// #define TCFG_UART0_ENABLE ENABLE_THIS_MOUDLE //串口打印模块使能
|
||||||
|
#define TCFG_UART0_ENABLE 0 //串口打印模块使能
|
||||||
#define TCFG_UART0_RX_PORT NO_CONFIG_PORT //串口接收脚配置(用于打印可以选择NO_CONFIG_PORT)
|
#define TCFG_UART0_RX_PORT NO_CONFIG_PORT //串口接收脚配置(用于打印可以选择NO_CONFIG_PORT)
|
||||||
#define TCFG_UART0_TX_PORT IO_PORT_DP //串口发送脚配置
|
#define TCFG_UART0_TX_PORT IO_PORT_DP //串口发送脚配置
|
||||||
#define TCFG_UART0_BAUDRATE 1000000 //串口波特率配置
|
#define TCFG_UART0_BAUDRATE 1000000 //串口波特率配置
|
||||||
|
// #define TCFG_UART0_BAUDRATE 115200 //串口波特率配置
|
||||||
|
|
||||||
//*********************************************************************************//
|
//*********************************************************************************//
|
||||||
// IIC配置 //
|
// IIC配置 //
|
||||||
@ -34,15 +36,18 @@
|
|||||||
#define TCFG_SW_I2C0_DAT_PORT IO_PORTA_06 //软件IIC DAT脚选择
|
#define TCFG_SW_I2C0_DAT_PORT IO_PORTA_06 //软件IIC DAT脚选择
|
||||||
#define TCFG_SW_I2C0_DELAY_CNT 10 //IIC延时参数,影响通讯时钟频率
|
#define TCFG_SW_I2C0_DELAY_CNT 10 //IIC延时参数,影响通讯时钟频率
|
||||||
|
|
||||||
/*硬件IIC端口选择
|
/*硬件IIC端口选择 -- 具体看手册,这里写的不准 -- lmx
|
||||||
SCL SDA
|
SCL SDA
|
||||||
'A': IO_PORT_DP IO_PORT_DM
|
'A': IO_PORT_DP IO_PORT_DM
|
||||||
'B': IO_PORTA_09 IO_PORTA_10
|
'B': IO_PORTA_09 IO_PORTA_10
|
||||||
'C': IO_PORTA_07 IO_PORTA_08
|
'C': IO_PORTA_07 IO_PORTA_08
|
||||||
'D': IO_PORTA_05 IO_PORTA_06
|
'D': IO_PORTA_05 IO_PORTA_06
|
||||||
|
|
||||||
|
具体要选择哪个iic口,去board_jl701n_demo.c中设置:hw_iic_cfg
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#define TCFG_HW_I2C0_PORTS 'B'
|
#define TCFG_HW_I2C0_PORTS 'B'
|
||||||
#define TCFG_HW_I2C0_CLK 100000 //硬件IIC波特率
|
#define TCFG_HW_I2C0_CLK 1000000 //硬件IIC波特率:400k
|
||||||
|
|
||||||
//*********************************************************************************//
|
//*********************************************************************************//
|
||||||
// 硬件SPI 配置 //
|
// 硬件SPI 配置 //
|
||||||
@ -82,7 +87,7 @@
|
|||||||
//*********************************************************************************//
|
//*********************************************************************************//
|
||||||
// USB 配置 //
|
// USB 配置 //
|
||||||
//*********************************************************************************//
|
//*********************************************************************************//
|
||||||
#define TCFG_PC_ENABLE 1//DISABLE_THIS_MOUDLE//PC模块使能
|
#define TCFG_PC_ENABLE 0//DISABLE_THIS_MOUDLE//PC模块使能
|
||||||
#define TCFG_UDISK_ENABLE 0//ENABLE_THIS_MOUDLE//U盘模块使能
|
#define TCFG_UDISK_ENABLE 0//ENABLE_THIS_MOUDLE//U盘模块使能
|
||||||
#define TCFG_OTG_USB_DEV_EN BIT(0)//USB0 = BIT(0) USB1 = BIT(1)
|
#define TCFG_OTG_USB_DEV_EN BIT(0)//USB0 = BIT(0) USB1 = BIT(1)
|
||||||
|
|
||||||
@ -101,7 +106,7 @@
|
|||||||
|
|
||||||
#define MULT_KEY_ENABLE 1//DISABLE //是否使能组合按键消息, 使能后需要配置组合按键映射表
|
#define MULT_KEY_ENABLE 1//DISABLE //是否使能组合按键消息, 使能后需要配置组合按键映射表
|
||||||
|
|
||||||
#define TCFG_KEY_TONE_EN ENABLE//DISABLE xtell // 按键提示音。
|
#define TCFG_KEY_TONE_EN DISABLE//DISABLE xtell // 按键提示音。
|
||||||
|
|
||||||
//*********************************************************************************//
|
//*********************************************************************************//
|
||||||
// iokey 配置 //
|
// iokey 配置 //
|
||||||
@ -724,9 +729,9 @@ DAC硬件上的连接方式,可选的配置:
|
|||||||
// 充电舱/蓝牙测试盒/ANC测试三者为同级关系,开启任一功能都会初始化PP0通信接口 //
|
// 充电舱/蓝牙测试盒/ANC测试三者为同级关系,开启任一功能都会初始化PP0通信接口 //
|
||||||
//*********************************************************************************//
|
//*********************************************************************************//
|
||||||
#define TCFG_CHARGESTORE_ENABLE DISABLE_THIS_MOUDLE //是否支持智能充电舱
|
#define TCFG_CHARGESTORE_ENABLE DISABLE_THIS_MOUDLE //是否支持智能充电舱
|
||||||
#define TCFG_TEST_BOX_ENABLE ENABLE_THIS_MOUDLE //是否支持蓝牙测试盒
|
#define TCFG_TEST_BOX_ENABLE DISABLE_THIS_MOUDLE//ENABLE_THIS_MOUDLE //是否支持蓝牙测试盒 //xtell
|
||||||
#define TCFG_ANC_BOX_ENABLE CONFIG_ANC_ENABLE //是否支持ANC测试盒
|
#define TCFG_ANC_BOX_ENABLE CONFIG_ANC_ENABLE //是否支持ANC测试盒
|
||||||
#define TCFG_UMIDIGI_BOX_ENABLE ENABLE_THIS_MOUDLE //是否支持UMIDIGI充电舱
|
#define TCFG_UMIDIGI_BOX_ENABLE DISABLE_THIS_MOUDLE //是否支持UMIDIGI充电舱 //xtell
|
||||||
#if TCFG_UMIDIGI_BOX_ENABLE
|
#if TCFG_UMIDIGI_BOX_ENABLE
|
||||||
#define _20MS_BIT 20 //传输20ms/Bit时使用
|
#define _20MS_BIT 20 //传输20ms/Bit时使用
|
||||||
#define _40MS_BIT 40 //传输40ms/Bit时使用
|
#define _40MS_BIT 40 //传输40ms/Bit时使用
|
||||||
@ -802,7 +807,7 @@ DAC硬件上的连接方式,可选的配置:
|
|||||||
// EQ配置 //
|
// EQ配置 //
|
||||||
//*********************************************************************************//
|
//*********************************************************************************//
|
||||||
//EQ配置,使用在线EQ时,EQ文件和EQ模式无效。有EQ文件时,使能TCFG_USE_EQ_FILE,默认不用EQ模式切换功能
|
//EQ配置,使用在线EQ时,EQ文件和EQ模式无效。有EQ文件时,使能TCFG_USE_EQ_FILE,默认不用EQ模式切换功能
|
||||||
#define TCFG_EQ_ENABLE 1 //支持EQ功能,EQ总使能
|
#define TCFG_EQ_ENABLE 0 //支持EQ功能,EQ总使能
|
||||||
// #if TCFG_EQ_ENABLE
|
// #if TCFG_EQ_ENABLE
|
||||||
#define TCFG_EQ_ONLINE_ENABLE 0 //支持在线EQ调试,如果使用蓝牙串口调试,需要打开宏 APP_ONLINE_DEBUG,否则,默认使用uart调试(二选一)
|
#define TCFG_EQ_ONLINE_ENABLE 0 //支持在线EQ调试,如果使用蓝牙串口调试,需要打开宏 APP_ONLINE_DEBUG,否则,默认使用uart调试(二选一)
|
||||||
#define TCFG_BT_MUSIC_EQ_ENABLE 1 //支持蓝牙音乐EQ
|
#define TCFG_BT_MUSIC_EQ_ENABLE 1 //支持蓝牙音乐EQ
|
||||||
@ -915,7 +920,7 @@ DAC硬件上的连接方式,可选的配置:
|
|||||||
#define TCFG_STK8321_EN 0
|
#define TCFG_STK8321_EN 0
|
||||||
#define TCFG_IRSENSOR_ENABLE 0
|
#define TCFG_IRSENSOR_ENABLE 0
|
||||||
#define TCFG_JSA1221_ENABLE 0
|
#define TCFG_JSA1221_ENABLE 0
|
||||||
#define TCFG_GSENOR_USER_IIC_TYPE 0 //0:软件IIC 1:硬件IIC
|
#define TCFG_GSENOR_USER_IIC_TYPE 1 //0:软件IIC 1:硬件IIC
|
||||||
|
|
||||||
//*********************************************************************************//
|
//*********************************************************************************//
|
||||||
// imu-sensor配置 //
|
// imu-sensor配置 //
|
||||||
@ -1005,7 +1010,7 @@ DAC硬件上的连接方式,可选的配置:
|
|||||||
//*********************************************************************************//
|
//*********************************************************************************//
|
||||||
#define TCFG_USER_TWS_ENABLE 0 //tws功能使能
|
#define TCFG_USER_TWS_ENABLE 0 //tws功能使能
|
||||||
#define TCFG_USER_BLE_ENABLE 1 //BLE功能使能
|
#define TCFG_USER_BLE_ENABLE 1 //BLE功能使能
|
||||||
#define TCFG_BT_SUPPORT_AAC 1 //AAC格式支持
|
#define TCFG_BT_SUPPORT_AAC 0 //AAC格式支持
|
||||||
#define TCFG_BT_SUPPORT_LDAC 0 //LDAC格式支持
|
#define TCFG_BT_SUPPORT_LDAC 0 //LDAC格式支持
|
||||||
|
|
||||||
#if TCFG_BT_SUPPORT_LDAC
|
#if TCFG_BT_SUPPORT_LDAC
|
||||||
@ -1079,7 +1084,7 @@ DAC硬件上的连接方式,可选的配置:
|
|||||||
// 编解码格式配置(CodecFormat) //
|
// 编解码格式配置(CodecFormat) //
|
||||||
//*********************************************************************************//
|
//*********************************************************************************//
|
||||||
/*解码格式使能*/
|
/*解码格式使能*/
|
||||||
#define TCFG_DEC_MP3_ENABLE ENABLE
|
#define TCFG_DEC_MP3_ENABLE DISABLE
|
||||||
#define TCFG_DEC_WTGV2_ENABLE ENABLE
|
#define TCFG_DEC_WTGV2_ENABLE ENABLE
|
||||||
#define TCFG_DEC_G729_ENABLE DISABLE
|
#define TCFG_DEC_G729_ENABLE DISABLE
|
||||||
#define TCFG_DEC_WMA_ENABLE DISABLE
|
#define TCFG_DEC_WMA_ENABLE DISABLE
|
||||||
@ -1125,7 +1130,7 @@ DAC硬件上的连接方式,可选的配置:
|
|||||||
//*********************************************************************************//
|
//*********************************************************************************//
|
||||||
#if TCFG_USER_BLE_ENABLE
|
#if TCFG_USER_BLE_ENABLE
|
||||||
#define DUEROS_DMA_EN 0
|
#define DUEROS_DMA_EN 0
|
||||||
#define TRANS_DATA_EN 0//1 //xtellota
|
// #define TRANS_DATA_EN 0//1 //xtellota
|
||||||
#define BLE_HID_EN 0
|
#define BLE_HID_EN 0
|
||||||
|
|
||||||
#if (DUEROS_DMA_EN)
|
#if (DUEROS_DMA_EN)
|
||||||
|
|||||||
@ -8,12 +8,12 @@
|
|||||||
|
|
||||||
/* Following Macros Affect Periods Of Both Code Compiling And Post-build */
|
/* Following Macros Affect Periods Of Both Code Compiling And Post-build */
|
||||||
|
|
||||||
#define CONFIG_DOUBLE_BANK_ENABLE 0 //单双备份选择(若打开了改宏,FLASH结构变为双备份结构,适用于接入第三方协议的OTA, PS: JL-OTA同样支持双备份升级, 需要根据实际FLASH大小同时配置CONFIG_FLASH_SIZE)
|
#define CONFIG_DOUBLE_BANK_ENABLE 1 //单双备份选择(若打开了改宏,FLASH结构变为双备份结构,适用于接入第三方协议的OTA, PS: JL-OTA同样支持双备份升级, 需要根据实际FLASH大小同时配置CONFIG_FLASH_SIZE)
|
||||||
#define CONFIG_APP_OTA_ENABLE 0 //是否支持RCSP升级(JL-OTA)
|
#define CONFIG_APP_OTA_ENABLE 1 //是否支持RCSP升级(JL-OTA)
|
||||||
|
|
||||||
#define CONFIG_UPDATE_JUMP_TO_MASK 0 //配置升级到loader的方式0为直接reset,1为跳转(适用于芯片电源由IO口KEEP住的方案,需要注意检查跳转前是否将使用DMA的硬件模块全部关闭)
|
#define CONFIG_UPDATE_JUMP_TO_MASK 0 //配置升级到loader的方式0为直接reset,1为跳转(适用于芯片电源由IO口KEEP住的方案,需要注意检查跳转前是否将使用DMA的硬件模块全部关闭)
|
||||||
|
|
||||||
#define CONFIG_IO_KEY_EN 0 //配置是否使用IO按键,配合RESET1
|
#define CONFIG_IO_KEY_EN 1 //配置是否使用IO按键,配合RESET1
|
||||||
#define CONFIG_UPDATE_WITH_MD5_CHECK_EN 0 //配置升级是否支持MD5校验
|
#define CONFIG_UPDATE_WITH_MD5_CHECK_EN 0 //配置升级是否支持MD5校验
|
||||||
|
|
||||||
#define CONFIG_ANC_ENABLE 0 //配置是否支持ANC
|
#define CONFIG_ANC_ENABLE 0 //配置是否支持ANC
|
||||||
@ -33,7 +33,7 @@
|
|||||||
/* Following Macros Only For Post Bulid Configuaration */
|
/* Following Macros Only For Post Bulid Configuaration */
|
||||||
|
|
||||||
#define CONFIG_DB_UPDATE_DATA_GENERATE_EN 0 //是否生成db_data.bin(用于第三方协议接入使用)
|
#define CONFIG_DB_UPDATE_DATA_GENERATE_EN 0 //是否生成db_data.bin(用于第三方协议接入使用)
|
||||||
#define CONFIG_ONLY_GRENERATE_ALIGN_4K_CODE 0 //ufw只生成1份4K对齐的代码
|
#define CONFIG_ONLY_GRENERATE_ALIGN_4K_CODE 1 //ufw只生成1份4K对齐的代码
|
||||||
|
|
||||||
//config for supported chip version
|
//config for supported chip version
|
||||||
#ifdef CONFIG_BR30_C_VERSION
|
#ifdef CONFIG_BR30_C_VERSION
|
||||||
@ -73,8 +73,8 @@
|
|||||||
|
|
||||||
#if CONFIG_IO_KEY_EN
|
#if CONFIG_IO_KEY_EN
|
||||||
#define CONFIG_SUPPORT_RESET1
|
#define CONFIG_SUPPORT_RESET1
|
||||||
#define CONFIG_RESET1_PIN PB01 //io pin
|
#define CONFIG_RESET1_PIN PA04 //io pin
|
||||||
#define CONFIG_RESET1_TIME 08 //unit:second
|
#define CONFIG_RESET1_TIME 01 //unit:second
|
||||||
#define CONFIG_RESET1_LEVEL 0 //tigger level(0/1)
|
#define CONFIG_RESET1_LEVEL 0 //tigger level(0/1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -21,9 +21,10 @@
|
|||||||
#define CONFIG_APP_BT_ENABLE
|
#define CONFIG_APP_BT_ENABLE
|
||||||
|
|
||||||
#ifdef CONFIG_APP_BT_ENABLE
|
#ifdef CONFIG_APP_BT_ENABLE
|
||||||
#define TRANS_DATA_EN 0
|
#define BLE_WIRELESS_SERVER_EN 0
|
||||||
|
#define TRANS_DATA_EN 1
|
||||||
#define RCSP_BTMATE_EN 0
|
#define RCSP_BTMATE_EN 0
|
||||||
#define RCSP_ADV_EN 1
|
#define RCSP_ADV_EN 0
|
||||||
#define AI_APP_PROTOCOL 0
|
#define AI_APP_PROTOCOL 0
|
||||||
#define LL_SYNC_EN 0
|
#define LL_SYNC_EN 0
|
||||||
#define TUYA_DEMO_EN 0
|
#define TUYA_DEMO_EN 0
|
||||||
@ -65,8 +66,8 @@
|
|||||||
#if CONFIG_APP_OTA_ENABLE
|
#if CONFIG_APP_OTA_ENABLE
|
||||||
#define RCSP_UPDATE_EN 1 //是否支持rcsp升级
|
#define RCSP_UPDATE_EN 1 //是否支持rcsp升级
|
||||||
#if CONFIG_DOUBLE_BANK_ENABLE //双备份才能打开同步升级流程
|
#if CONFIG_DOUBLE_BANK_ENABLE //双备份才能打开同步升级流程
|
||||||
#define OTA_TWS_SAME_TIME_ENABLE 1 //是否支持TWS同步升级
|
#define OTA_TWS_SAME_TIME_ENABLE 0 //是否支持TWS同步升级
|
||||||
#define OTA_TWS_SAME_TIME_NEW 1 //使用新的tws ota流程
|
#define OTA_TWS_SAME_TIME_NEW 0 //使用新的tws ota流程
|
||||||
#else
|
#else
|
||||||
#define OTA_TWS_SAME_TIME_ENABLE 1//0 xtellota //是否支持TWS同步升级
|
#define OTA_TWS_SAME_TIME_ENABLE 1//0 xtellota //是否支持TWS同步升级
|
||||||
#define OTA_TWS_SAME_TIME_NEW 1//0 //使用新的tws ota流程
|
#define OTA_TWS_SAME_TIME_NEW 1//0 //使用新的tws ota流程
|
||||||
|
|||||||
@ -204,6 +204,18 @@ int app_protocol_sys_event_handler(struct sys_event *event);
|
|||||||
#define EARPHONE_STATE_SNIFF(a)
|
#define EARPHONE_STATE_SNIFF(a)
|
||||||
#define EARPHONE_STATE_ROLE_SWITCH(a)
|
#define EARPHONE_STATE_ROLE_SWITCH(a)
|
||||||
|
|
||||||
|
#elif BLE_WIRELESS_SERVER_EN
|
||||||
|
#define EARPHONE_STATE_INIT() do { } while(0)
|
||||||
|
#define EARPHONE_STATE_SET_PAGE_SCAN_ENABLE() do { } while(0)
|
||||||
|
#define EARPHONE_STATE_GET_CONNECT_MAC_ADDR() do { } while(0)
|
||||||
|
#define EARPHONE_STATE_CANCEL_PAGE_SCAN() do { } while(0)
|
||||||
|
#define EARPHONE_STATE_ENTER_SOFT_POWEROFF() do { } while(0)
|
||||||
|
#define EARPHONE_STATE_TWS_INIT(a) do { } while(0)
|
||||||
|
#define EARPHONE_STATE_TWS_CONNECTED(a, b) do { } while(0)
|
||||||
|
#define SYS_EVENT_HANDLER_SPECIFIC(a) do { } while(0)
|
||||||
|
#define SYS_EVENT_REMAP(a) 0
|
||||||
|
#define EARPHONE_STATE_SNIFF(a)
|
||||||
|
#define EARPHONE_STATE_ROLE_SWITCH(a)
|
||||||
#else
|
#else
|
||||||
int adv_earphone_state_init();
|
int adv_earphone_state_init();
|
||||||
int adv_earphone_state_set_page_scan_enable();
|
int adv_earphone_state_set_page_scan_enable();
|
||||||
|
|||||||
@ -232,7 +232,8 @@ const uint64_t config_btctler_le_features = LE_ENCRYPTION;
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
const int config_btctler_le_roles = (LE_ADV | LE_SLAVE);
|
const int config_btctler_le_roles = (LE_ADV | LE_SLAVE);
|
||||||
const uint64_t config_btctler_le_features = 0;
|
// const uint64_t config_btctler_le_features = 0;
|
||||||
|
const uint64_t config_btctler_le_features = LE_ENCRYPTION | LE_DATA_PACKET_LENGTH_EXTENSION | LE_2M_PHY;
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
const int config_btctler_le_roles = 0;
|
const int config_btctler_le_roles = 0;
|
||||||
@ -280,9 +281,13 @@ const int config_btctler_le_acl_total_nums = 1;
|
|||||||
const int config_btctler_le_afh_en = 0;
|
const int config_btctler_le_afh_en = 0;
|
||||||
const u32 config_vendor_le_bb = 0;
|
const u32 config_vendor_le_bb = 0;
|
||||||
|
|
||||||
const int config_btctler_le_rx_nums = 5;
|
// const int config_btctler_le_rx_nums = 5;
|
||||||
const int config_btctler_le_acl_packet_length = 27;
|
// const int config_btctler_le_acl_packet_length = 27;
|
||||||
const int config_btctler_le_acl_total_nums = 5;
|
// const int config_btctler_le_acl_total_nums = 5;
|
||||||
|
|
||||||
|
const int config_btctler_le_rx_nums = 8;
|
||||||
|
const int config_btctler_le_acl_packet_length = 251;
|
||||||
|
const int config_btctler_le_acl_total_nums = 8;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|||||||
@ -202,7 +202,9 @@ void cfg_file_parse(u8 idx)
|
|||||||
log_info("read bt name err");
|
log_info("read bt name err");
|
||||||
} else if (ret >= LOCAL_NAME_LEN) {
|
} else if (ret >= LOCAL_NAME_LEN) {
|
||||||
memset(bt_cfg.edr_name, 0x00, LOCAL_NAME_LEN);
|
memset(bt_cfg.edr_name, 0x00, LOCAL_NAME_LEN);
|
||||||
memcpy(bt_cfg.edr_name, tmp, LOCAL_NAME_LEN);
|
// memcpy(bt_cfg.edr_name, tmp, LOCAL_NAME_LEN);
|
||||||
|
extern char xt_ble_new_name[9];
|
||||||
|
memcpy(bt_cfg.edr_name, xt_ble_new_name, LOCAL_NAME_LEN);
|
||||||
bt_cfg.edr_name[LOCAL_NAME_LEN - 1] = 0;
|
bt_cfg.edr_name[LOCAL_NAME_LEN - 1] = 0;
|
||||||
} else {
|
} else {
|
||||||
memset(bt_cfg.edr_name, 0x00, LOCAL_NAME_LEN);
|
memset(bt_cfg.edr_name, 0x00, LOCAL_NAME_LEN);
|
||||||
|
|||||||
219
apps/earphone/xtell_Sensor/A_hide/1/skiing_tracker.c
Normal file
219
apps/earphone/xtell_Sensor/A_hide/1/skiing_tracker.c
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
静态ZUPT+卡尔曼,效果貌似还行
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "skiing_tracker.h"
|
||||||
|
#include "../sensor/SC7U22.h" // 包含传感器驱动头文件以调用姿态解算函数
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define G_ACCELERATION 9.81f // 重力加速度 (m/s^2)
|
||||||
|
#define DEG_TO_RAD (3.14159265f / 180.0f)
|
||||||
|
|
||||||
|
// --- 状态检测阈值 ---
|
||||||
|
// 判断是否静止的加速度阈值 (m/s^2)。当加速度的模长减去重力后,小于此值,则认为可能静止。
|
||||||
|
#define STATIC_ACC_THRESHOLD 1.0f
|
||||||
|
// 连续多少帧满足静止条件才确认为静止状态
|
||||||
|
#define STATIC_FRAMES_REQUIRED 50 // 累加,超过这个数加速度仍变化不大,说明近似静止
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker)
|
||||||
|
{
|
||||||
|
if (!tracker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(tracker, 0, sizeof(skiing_tracker_t));
|
||||||
|
tracker->state = SKIING_STATE_STATIC; // 初始状态为静止
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 将设备坐标系下的加速度转换为世界坐标系
|
||||||
|
* @param acc_device 设备坐标系下的加速度 [x, y, z]
|
||||||
|
* @param angle 姿态角 [pitch, roll, yaw],单位: 度
|
||||||
|
* @param acc_world 输出:世界坐标系下的加速度 [x, y, z]
|
||||||
|
*/
|
||||||
|
static void transform_acc_to_world_frame(const float *acc_device, const float *angle, float *acc_world)
|
||||||
|
{
|
||||||
|
// 修正#1:驱动输出的角度与标准航空定义相反,需要取反才能用于标准旋转矩阵。
|
||||||
|
float pitch = -angle[0] * DEG_TO_RAD;
|
||||||
|
float roll = -angle[1] * DEG_TO_RAD;
|
||||||
|
|
||||||
|
float cp = cosf(pitch);
|
||||||
|
float sp = sinf(pitch);
|
||||||
|
float cr = cosf(roll);
|
||||||
|
float sr = sinf(roll);
|
||||||
|
|
||||||
|
float ax = acc_device[0];
|
||||||
|
float ay = acc_device[1];
|
||||||
|
float az = acc_device[2];
|
||||||
|
|
||||||
|
// 修正#2:使用经过验证的、正确的身体坐标系到世界坐标系的旋转矩阵 (基于 Y-X 旋转顺序)
|
||||||
|
// 这个矩阵将设备测量的加速度(ax, ay, az)正确地转换到世界坐标系(acc_world)。
|
||||||
|
acc_world[0] = cp * ax + sp * sr * ay + sp * cr * az;
|
||||||
|
acc_world[1] = 0 * ax + cr * ay - sr * az;
|
||||||
|
acc_world[2] = -sp * ax + cp * sr * ay + cp * cr * az;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 更新滑雪状态机
|
||||||
|
*/
|
||||||
|
static void update_state_machine(skiing_tracker_t *tracker, const float *acc_device)
|
||||||
|
{
|
||||||
|
// 计算当前加速度的模长
|
||||||
|
float acc_magnitude = sqrtf(acc_device[0] * acc_device[0] + acc_device[1] * acc_device[1] + acc_device[2] * acc_device[2]);
|
||||||
|
|
||||||
|
// 状态判断逻辑
|
||||||
|
switch (tracker->state) {
|
||||||
|
case SKIING_STATE_STATIC:
|
||||||
|
// 如果加速度变化较大,则切换到滑雪状态
|
||||||
|
if (fabsf(acc_magnitude - G_ACCELERATION) > STATIC_ACC_THRESHOLD * 2.0f) { // 使用一个更大的阈值来启动
|
||||||
|
tracker->state = SKIING_STATE_SKIING;
|
||||||
|
tracker->static_frames_count = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKIING_STATE_SKIING:
|
||||||
|
// 检测是否进入静止状态 (零速更新 ZUPT)
|
||||||
|
if (fabsf(acc_magnitude - G_ACCELERATION) < STATIC_ACC_THRESHOLD) {
|
||||||
|
tracker->static_frames_count++;
|
||||||
|
if (tracker->static_frames_count >= STATIC_FRAMES_REQUIRED) {
|
||||||
|
tracker->state = SKIING_STATE_STATIC;
|
||||||
|
// 进入静止状态,强制将速度清零以消除漂移
|
||||||
|
memset(tracker->velocity, 0, sizeof(tracker->velocity));
|
||||||
|
tracker->speed = 0.0f;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果在运动,则重置静止计数器
|
||||||
|
tracker->static_frames_count = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 可以在此添加摔倒等其他状态的判断
|
||||||
|
case SKIING_STATE_FALLEN:
|
||||||
|
// TODO: 添加从摔倒状态恢复的逻辑
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
tracker->state = SKIING_STATE_UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 主更新函数
|
||||||
|
*/
|
||||||
|
void skiing_tracker_update(skiing_tracker_t *tracker, float *acc, float *angle, float dt)
|
||||||
|
{
|
||||||
|
if (!tracker || !acc || !angle || dt <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将原始g单位的加速度转换为 m/s^2
|
||||||
|
float acc_device_ms2[3];
|
||||||
|
acc_device_ms2[0] = acc[0] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[1] = acc[1] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[2] = acc[2] * G_ACCELERATION;
|
||||||
|
|
||||||
|
// 更新状态机
|
||||||
|
update_state_machine(tracker, acc_device_ms2);
|
||||||
|
|
||||||
|
// 只有在滑雪状态下才进行计算
|
||||||
|
if (tracker->state == SKIING_STATE_SKIING) {
|
||||||
|
// 坐标系转换: 首先,利用姿态角(Pitch, Roll)将传感器测得的总加速度(运动加速度+重力)
|
||||||
|
// 从不断变化的“设备坐标系”转换到一个固定的“世界坐标系”。在这个世界坐标系里,Z轴永远垂直于地面指向上方。
|
||||||
|
// 执行坐标系转换
|
||||||
|
transform_acc_to_world_frame(acc_device_ms2, angle, tracker->acc_world);
|
||||||
|
// 转换完成后,重力就变成了一个恒定的、方向沿Z轴向下的矢量。
|
||||||
|
|
||||||
|
// 修正#3:经过正确的坐标转换后,静止时重力在世界坐标系Z轴上的分量精确为+g。
|
||||||
|
// 必须减去这个g,才能得到纯粹的运动加速度。
|
||||||
|
tracker->acc_world[2] -= G_ACCELERATION;
|
||||||
|
|
||||||
|
// 积分计算速度 (v = v0 + a*t)
|
||||||
|
tracker->velocity[0] += tracker->acc_world[0] * dt;
|
||||||
|
tracker->velocity[1] += tracker->acc_world[1] * dt;
|
||||||
|
tracker->velocity[2] += tracker->acc_world[2] * dt; // 垂直方向速度也计算在内
|
||||||
|
|
||||||
|
// 计算当前速率
|
||||||
|
tracker->speed = sqrtf(tracker->velocity[0] * tracker->velocity[0] +
|
||||||
|
tracker->velocity[1] * tracker->velocity[1] +
|
||||||
|
tracker->velocity[2] * tracker->velocity[2]);
|
||||||
|
|
||||||
|
// 积分计算距离 (d = d0 + v*t)
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 传感器数据采集与处理任务
|
||||||
|
void sensor_processing_task(signed short * acc_data_buf,signed short * gyr_data_buf) {
|
||||||
|
// --- 1. 定义静态变量 ---
|
||||||
|
static skiing_tracker_t my_skiing_tracker;
|
||||||
|
static int initialized = 0;
|
||||||
|
static int calibration_done = 0; // 新增:用于标记一次性静态校准是否完成
|
||||||
|
|
||||||
|
static signed short combined_raw_data[6];
|
||||||
|
static float final_angle_data[3];
|
||||||
|
static float calibrated_acc_g[3];
|
||||||
|
|
||||||
|
// sensor_processing_task的调用频率, dt = 0.001s
|
||||||
|
const float delta_time = 0.01f;
|
||||||
|
|
||||||
|
// --- 2. 初始化 ---
|
||||||
|
if (!initialized) {
|
||||||
|
skiing_tracker_init(&my_skiing_tracker);
|
||||||
|
initialized = 1;
|
||||||
|
printf("Skiing Tracker Initialized. Waiting for sensor calibration...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 3. 数据处理 ---
|
||||||
|
//合并加速度和陀螺仪数据
|
||||||
|
memcpy(&combined_raw_data[0], acc_data_buf, 3 * sizeof(signed short));
|
||||||
|
memcpy(&combined_raw_data[3], gyr_data_buf, 3 * sizeof(signed short));
|
||||||
|
|
||||||
|
unsigned char status;
|
||||||
|
if (get_calibration_state() == 0) { //正在校准
|
||||||
|
//领票校准
|
||||||
|
status = SL_SC7U22_Angle_Output(1, combined_raw_data, final_angle_data, 0);
|
||||||
|
if (status == 1) {
|
||||||
|
calibration_done = 1;
|
||||||
|
printf("Sensor calibration successful! Skiing mode is active.\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status = SL_SC7U22_Angle_Output(0, combined_raw_data, final_angle_data, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// c. 检查姿态解算是否成功
|
||||||
|
if (status == 1) {
|
||||||
|
// 将校准后的加速度数据从 LSB (原始值) 转换为 g (重力单位)
|
||||||
|
// ±8g量程下,8192 LSB 对应 1g
|
||||||
|
calibrated_acc_g[0] = (float)combined_raw_data[0] / 8192.0f;
|
||||||
|
calibrated_acc_g[1] = (float)combined_raw_data[1] / 8192.0f;
|
||||||
|
calibrated_acc_g[2] = (float)combined_raw_data[2] / 8192.0f;
|
||||||
|
|
||||||
|
skiing_tracker_update(&my_skiing_tracker, calibrated_acc_g, final_angle_data, delta_time);
|
||||||
|
|
||||||
|
static count = 0;
|
||||||
|
if(count < 10){
|
||||||
|
count++;
|
||||||
|
return;
|
||||||
|
}else{
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
printf("State: %d, Speed: %.2f m/s, Distance: %.2f m\n",
|
||||||
|
my_skiing_tracker.state,
|
||||||
|
my_skiing_tracker.speed,
|
||||||
|
my_skiing_tracker.distance);
|
||||||
|
|
||||||
|
} else if (status == 0) {
|
||||||
|
// 传感器正在进行静态校准
|
||||||
|
// printf("Sensor is calibrating...\n");
|
||||||
|
} else {
|
||||||
|
// status == 2, 表示校准失败或发生错误
|
||||||
|
// printf("Angle calculation error or calibration not finished.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
41
apps/earphone/xtell_Sensor/A_hide/1/skiing_tracker.h
Normal file
41
apps/earphone/xtell_Sensor/A_hide/1/skiing_tracker.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#ifndef SKIING_TRACKER_H
|
||||||
|
#define SKIING_TRACKER_H
|
||||||
|
|
||||||
|
// 定义滑雪者可能的状态
|
||||||
|
typedef enum {
|
||||||
|
SKIING_STATE_STATIC, // 静止
|
||||||
|
SKIING_STATE_SKIING, // 正在滑雪
|
||||||
|
SKIING_STATE_FALLEN, // 已摔倒
|
||||||
|
SKIING_STATE_UNKNOWN // 未知状态
|
||||||
|
} skiing_state_t;
|
||||||
|
|
||||||
|
// 追踪器数据结构体
|
||||||
|
typedef struct {
|
||||||
|
float velocity[3]; // 当前速度 (x, y, z),单位: m/s
|
||||||
|
float distance; // 总滑行距离,单位: m
|
||||||
|
float speed; // 当前速率 (标量),单位: m/s
|
||||||
|
skiing_state_t state; // 当前滑雪状态
|
||||||
|
|
||||||
|
// 私有成员,用于内部计算
|
||||||
|
int static_frames_count; // 用于判断静止状态的帧计数器
|
||||||
|
float acc_world[3]; // 在世界坐标系下的加速度
|
||||||
|
} skiing_tracker_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker 指向 skiing_tracker_t 结构体的指针
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 处理传感器数据并更新滑雪状态
|
||||||
|
*
|
||||||
|
* @param tracker 指向 skiing_tracker_t 结构体的指针
|
||||||
|
* @param acc 校准后的加速度数据 [x, y, z],单位: g (1g = 9.8m/s^2)
|
||||||
|
* @param angle 姿态角数据 [pitch, roll, yaw],单位: 度
|
||||||
|
* @param dt 采样时间间隔,单位: 秒 (s)
|
||||||
|
*/
|
||||||
|
void skiing_tracker_update(skiing_tracker_t *tracker, float *acc, float *angle, float dt);
|
||||||
|
|
||||||
|
#endif // SKIING_TRACKER_H
|
||||||
596
apps/earphone/xtell_Sensor/A_hide/10/skiing_tracker.c
Normal file
596
apps/earphone/xtell_Sensor/A_hide/10/skiing_tracker.c
Normal file
@ -0,0 +1,596 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "skiing_tracker.h"
|
||||||
|
#include "../sensor/SC7U22.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define G_ACCELERATION 9.81f
|
||||||
|
#define DEG_TO_RAD (3.14159265f / 180.0f)
|
||||||
|
|
||||||
|
// --- 静止检测 ---
|
||||||
|
//两个判断是否静止的必要条件:动态零速更新(ZUPT)阈值
|
||||||
|
// 加速方差阈值,提高阈值,让“刹车”更灵敏,以便在波浪式前进等慢速漂移时也能触发零速更新
|
||||||
|
#define STOP_ACC_VARIANCE_THRESHOLD 0.2f
|
||||||
|
// 陀螺仪方差阈值
|
||||||
|
#define STOP_GYR_VARIANCE_THRESHOLD 5.0f
|
||||||
|
// 静止时候的陀螺仪模长
|
||||||
|
#define STOP_GYR_MAG_THRESHOLD 15
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 启动滑雪阈值 ---
|
||||||
|
// 加速度模长与重力的差值大于此值,认为开始运动;降低阈值,让“油门”更灵敏,以便能捕捉到真实的慢速启动
|
||||||
|
#define START_ACC_MAG_THRESHOLD 1.0f //0.5、1
|
||||||
|
// 陀螺仪方差阈值,以允许启动瞬间的正常抖动,但仍能过滤掉混乱的、非滑雪的晃动。
|
||||||
|
#define START_GYR_VARIANCE_THRESHOLD 15.0f
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 滑雪过程 ---
|
||||||
|
//加速度 模长(不含重力),低于此值视为 在做匀速运动
|
||||||
|
#define SKIING_ACC_MAG_THRESHOLD 0.5f
|
||||||
|
//陀螺仪 模长,高于此值视为 摔倒了
|
||||||
|
#define FALLEN_GRY_MAG_THRESHOLD 2000.0f //未确定
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 原地旋转抖动 ---
|
||||||
|
// 加速度 方差 阈值。此值比 静止检测 阈值更宽松,
|
||||||
|
#define WOBBLE_ACC_VARIANCE_THRESHOLD 0.5f
|
||||||
|
// 加速度 模长 阈值
|
||||||
|
#define WOBBLE_ACC_MAG_THRESHOLD 1.0f
|
||||||
|
// 角速度 总模长 大于此值(度/秒),认为正在进行非滑雪的旋转或摆动
|
||||||
|
#define ROTATION_GYR_MAG_THRESHOLD 30.0f
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 滑雪转弯动 ---
|
||||||
|
// 加速度 方差 阈值,大于此值,滑雪过程可能发生了急转弯
|
||||||
|
#define WHEEL_ACC_VARIANCE_THRESHOLD 7.0f
|
||||||
|
// 角速度 总模长 大于此值(度/秒),认为滑雪过程中进行急转弯
|
||||||
|
#define WHEEL_GYR_MAG_THRESHOLD 500.0f //
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 跳跃 ---
|
||||||
|
// 加速度模长低于此值(g),认为进入失重状态(IN_AIR)
|
||||||
|
#define AIRBORNE_ACC_MAG_LOW_THRESHOLD 0.4f
|
||||||
|
// 加速度模长高于此值(g),认为发生落地冲击(LANDING)
|
||||||
|
#define LANDING_ACC_MAG_HIGH_THRESHOLD 3.5f
|
||||||
|
// 起跳加速度阈值(g),用于进入TAKING_OFF状态
|
||||||
|
#define TAKEOFF_ACC_MAG_HIGH_THRESHOLD 1.8f
|
||||||
|
// 进入空中状态确认计数:需要连续3个采样点加速度低于阈值才判断为起跳
|
||||||
|
#define AIRBORNE_CONFIRM_COUNT 3
|
||||||
|
// 落地状态确认计数:加速度恢复到1g附近并持续2个采样点(20ms)则认为已落地
|
||||||
|
#define GROUNDED_CONFIRM_COUNT 2
|
||||||
|
// 最大滞空时间(秒),超过此时间强制认为已落地,防止状态锁死
|
||||||
|
#define MAX_TIME_IN_AIR 12.5f
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 用于消除积分漂移的滤波器和阈值 ---
|
||||||
|
// 高通滤波器系数 (alpha)。alpha 越接近1,滤除低频(直流偏移)的效果越强,但可能滤掉真实的慢速运动。
|
||||||
|
// alpha = RC / (RC + dt),参考RC电路而来,fc ≈ (1 - alpha) / (2 * π * dt)
|
||||||
|
#define HPF_ALPHA 0.999f
|
||||||
|
//0.995f: 0.08 Hz 的信号
|
||||||
|
//0.999f: 0.0159 Hz
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 低通滤波器 ---
|
||||||
|
// 低通滤波器系数 (alpha)。alpha 越小,滤波效果越强(更平滑),但延迟越大。
|
||||||
|
// alpha 推荐范围 0.7 ~ 0.95。可以从 0.85 开始尝试。
|
||||||
|
#define LPF_ALPHA 0.7f
|
||||||
|
|
||||||
|
// 加速度死区阈值 (m/s^2)。低于此阈值的加速度被认为是噪声,不参与积分。
|
||||||
|
// 设得太高会忽略真实的慢速启动,设得太低则无法有效抑制噪声。
|
||||||
|
//参考:0.2f ~ 0.4f
|
||||||
|
#define ACC_DEAD_ZONE_THRESHOLD 0.05f
|
||||||
|
|
||||||
|
// --- 模拟摩擦力,进行速度衰减 ---
|
||||||
|
#define SPEED_ATTENUATION 1.0f //暂不模拟
|
||||||
|
BLE_KS_send_data_t KS_data;
|
||||||
|
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
|
||||||
|
debug_t debug1;
|
||||||
|
debug_t debug2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static skiing_tracker_t my_skiing_tracker;
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//实现
|
||||||
|
|
||||||
|
void clear_speed(void){
|
||||||
|
my_skiing_tracker.state = STATIC;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_detection(void){
|
||||||
|
my_skiing_tracker.state = STATIC;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.distance = 0;
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop_detection(void){
|
||||||
|
my_skiing_tracker.state = STOP_DETECTION;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker)
|
||||||
|
{
|
||||||
|
if (!tracker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 使用memset一次性清零整个结构体,包括新增的缓冲区
|
||||||
|
memset(tracker, 0, sizeof(skiing_tracker_t));
|
||||||
|
tracker->state = STATIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 当检测到落地时,计算空中的水平飞行距离并累加到总距离
|
||||||
|
*/
|
||||||
|
static void calculate_air_distance(skiing_tracker_t *tracker) {
|
||||||
|
float horizontal_speed_on_takeoff = sqrtf(
|
||||||
|
tracker->initial_velocity_on_takeoff[0] * tracker->initial_velocity_on_takeoff[0] +
|
||||||
|
tracker->initial_velocity_on_takeoff[1] * tracker->initial_velocity_on_takeoff[1]
|
||||||
|
);
|
||||||
|
float distance_in_air = horizontal_speed_on_takeoff * tracker->time_in_air;
|
||||||
|
tracker->distance += distance_in_air;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 在设备坐标系下,从原始加速度数据中移除重力分量
|
||||||
|
* @param acc_device 输入:设备坐标系下的原始加速度 [x, y, z], 单位 m/s^2
|
||||||
|
* @param angle 输入:姿态角 [pitch, roll, yaw],单位: 度
|
||||||
|
* @param acc_linear_device 输出:设备坐标系下移除重力后的线性加速度 [x, y, z]
|
||||||
|
*/
|
||||||
|
void remove_gravity_in_device_frame(const float *acc_device, const float *angle, float *acc_linear_device)
|
||||||
|
{
|
||||||
|
float pitch = angle[0] * DEG_TO_RAD; // 绕 Y 轴
|
||||||
|
float roll = angle[1] * DEG_TO_RAD; // 绕 X 轴
|
||||||
|
float yaw = angle[2] * DEG_TO_RAD; // 绕 Z 轴
|
||||||
|
|
||||||
|
float cp = cosf(pitch);
|
||||||
|
float sp = sinf(pitch);
|
||||||
|
float cr = cosf(roll);
|
||||||
|
float sr = sinf(roll);
|
||||||
|
float cy = cosf(yaw);
|
||||||
|
float sy = sinf(yaw);
|
||||||
|
|
||||||
|
// 世界坐标系下的重力矢量
|
||||||
|
const float g_world[3] = {0.0f, 0.0f, G_ACCELERATION};
|
||||||
|
|
||||||
|
// 计算旋转矩阵 R 的转置矩阵 R_transpose
|
||||||
|
// R (Z-Y-X) =
|
||||||
|
// [ cy*cp, cy*sp*sr - sy*cr, cy*sp*cr + sy*sr]
|
||||||
|
// [ sy*cp, sy*sp*sr + cy*cr, sy*sp*cr - cy*sr]
|
||||||
|
// [ -sp, cp*sr, cp*cr ]
|
||||||
|
//
|
||||||
|
// R_transpose =
|
||||||
|
// [ cy*cp, sy*cp, -sp ]
|
||||||
|
// [ cy*sp*sr - sy*cr, sy*sp*sr + cy*cr, cp*sr ]
|
||||||
|
// [ cy*sp*cr + sy*sr, sy*sp*cr - cy*sr, cp*cr ]
|
||||||
|
|
||||||
|
// 计算重力在设备坐标系下的投影 G_device = R_transpose * G_world
|
||||||
|
// 由于 G_world 只有 z 分量,计算可以简化
|
||||||
|
float g_device[3];
|
||||||
|
g_device[0] = (-sp) * g_world[2];
|
||||||
|
g_device[1] = (cp * sr) * g_world[2];
|
||||||
|
g_device[2] = (cp * cr) * g_world[2];
|
||||||
|
|
||||||
|
// 从原始设备加速度中减去重力投影
|
||||||
|
acc_linear_device[0] = acc_device[0] - g_device[0];
|
||||||
|
acc_linear_device[1] = acc_device[1] - g_device[1];
|
||||||
|
acc_linear_device[2] = acc_device[2] - g_device[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计算缓冲区内三轴数据的方差之和
|
||||||
|
*
|
||||||
|
* @param buffer 传进来的三轴数据:陀螺仪/加速度
|
||||||
|
* @return float 返回方差和
|
||||||
|
*/
|
||||||
|
static float calculate_variance(float buffer[VARIANCE_BUFFER_SIZE][3])
|
||||||
|
{
|
||||||
|
float mean[3] = {0};
|
||||||
|
float variance[3] = {0};
|
||||||
|
|
||||||
|
// 计算均值
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
mean[0] += buffer[i][0];
|
||||||
|
mean[1] += buffer[i][1];
|
||||||
|
mean[2] += buffer[i][2];
|
||||||
|
}
|
||||||
|
mean[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 计算方差
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
variance[0] += (buffer[i][0] - mean[0]) * (buffer[i][0] - mean[0]);
|
||||||
|
variance[1] += (buffer[i][1] - mean[1]) * (buffer[i][1] - mean[1]);
|
||||||
|
variance[2] += (buffer[i][2] - mean[2]) * (buffer[i][2] - mean[2]);
|
||||||
|
}
|
||||||
|
variance[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 返回三轴方差之和,作为一个综合的稳定度指标
|
||||||
|
return variance[0] + variance[1] + variance[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 摩擦力模拟,进行速度衰减
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
*/
|
||||||
|
void forece_of_friction(skiing_tracker_t *tracker){
|
||||||
|
// 增加速度衰减,模拟摩擦力
|
||||||
|
tracker->velocity[0] *= SPEED_ATTENUATION;
|
||||||
|
tracker->velocity[1] *= SPEED_ATTENUATION;
|
||||||
|
tracker->velocity[2] = 0; // 垂直速度强制归零
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 状态机更新
|
||||||
|
*
|
||||||
|
* @param tracker 传入同步修改后传出
|
||||||
|
* @param acc_device_ms2 三轴加速度,m/s^2
|
||||||
|
* @param gyr_dps 三轴陀螺仪,dps
|
||||||
|
*/
|
||||||
|
static void update_state_machine(skiing_tracker_t *tracker, const float *acc_device_ms2, const float *gyr_dps)
|
||||||
|
{
|
||||||
|
// 缓冲区未填满时,不进行状态判断,默认为静止
|
||||||
|
if (!tracker->buffer_filled) {
|
||||||
|
tracker->state = STATIC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 计算关键指标 ---
|
||||||
|
float acc_variance = calculate_variance(tracker->acc_buffer); // 计算加速度方差
|
||||||
|
float gyr_variance = calculate_variance(tracker->gyr_buffer); // 计算陀螺仪方差
|
||||||
|
float gyr_magnitude = sqrtf(gyr_dps[0]*gyr_dps[0] + gyr_dps[1]*gyr_dps[1] + gyr_dps[2]*gyr_dps[2]); //dps
|
||||||
|
float acc_magnitude = sqrtf(acc_device_ms2[0]*acc_device_ms2[0] + acc_device_ms2[1]*acc_device_ms2[1] + acc_device_ms2[2]*acc_device_ms2[2]); //m/s^s
|
||||||
|
float acc_magnitude_g = acc_magnitude / G_ACCELERATION; // 转换为g单位,用于跳跃判断
|
||||||
|
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
debug1.acc_variance =acc_variance;
|
||||||
|
debug1.gyr_variance =gyr_variance;
|
||||||
|
debug1.gyr_magnitude=gyr_magnitude;
|
||||||
|
debug1.acc_magnitude=fabsf(acc_magnitude - G_ACCELERATION);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// --- 状态机逻辑 (核心修改区域) ---
|
||||||
|
|
||||||
|
#if 0 //暂时不考虑空中
|
||||||
|
// 1. 空中/落地状态的后续处理
|
||||||
|
if (tracker->state == IN_AIR) {
|
||||||
|
// A. 检测巨大冲击 -> 落地
|
||||||
|
if (acc_magnitude_g > LANDING_ACC_MAG_HIGH_THRESHOLD) {
|
||||||
|
tracker->state = LANDING;
|
||||||
|
// B. 检测超时 -> 强制落地 (安全机制)
|
||||||
|
} else if (tracker->time_in_air > MAX_TIME_IN_AIR) {
|
||||||
|
tracker->state = LANDING;
|
||||||
|
// C. 检测恢复正常重力 (平缓落地)
|
||||||
|
} else if (acc_magnitude_g > 0.8f && acc_magnitude_g < 1.5f) {
|
||||||
|
tracker->grounded_entry_counter++;
|
||||||
|
if (tracker->grounded_entry_counter >= GROUNDED_CONFIRM_COUNT) {
|
||||||
|
tracker->state = LANDING;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tracker->grounded_entry_counter = 0;
|
||||||
|
}
|
||||||
|
return; // 在空中或刚切换到落地,结束本次状态判断
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 严格的 "起跳->空中" 状态转换逻辑
|
||||||
|
// 只有当处于滑行状态时,才去检测起跳意图
|
||||||
|
if (tracker->state == NO_CONSTANT_SPEED || tracker->state == CONSTANT_SPEED || tracker->state == WHEEL) {
|
||||||
|
if (acc_magnitude_g > TAKEOFF_ACC_MAG_HIGH_THRESHOLD) {
|
||||||
|
tracker->state = TAKING_OFF;
|
||||||
|
tracker->airborne_entry_counter = 0; // 准备检测失重
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 只有在TAKING_OFF状态下,才去检测是否进入失重
|
||||||
|
if (tracker->state == TAKING_OFF) {
|
||||||
|
if (acc_magnitude_g < AIRBORNE_ACC_MAG_LOW_THRESHOLD) {
|
||||||
|
tracker->airborne_entry_counter++;
|
||||||
|
if (tracker->airborne_entry_counter >= AIRBORNE_CONFIRM_COUNT) {
|
||||||
|
memcpy(tracker->initial_velocity_on_takeoff, tracker->velocity, sizeof(tracker->velocity));
|
||||||
|
tracker->time_in_air = 0;
|
||||||
|
tracker->state = IN_AIR;
|
||||||
|
tracker->airborne_entry_counter = 0;
|
||||||
|
tracker->grounded_entry_counter = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果在起跳冲击后一段时间内没有失重,说明只是一个颠簸,恢复滑行
|
||||||
|
// 可以加一个小的超时计数器,这里为了简单先直接恢复
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
return; // 无论是否切换,都结束本次判断
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// --- 静止判断 ---
|
||||||
|
if (acc_variance < STOP_ACC_VARIANCE_THRESHOLD && gyr_variance < STOP_GYR_VARIANCE_THRESHOLD && gyr_magnitude < STOP_GYR_MAG_THRESHOLD) {
|
||||||
|
tracker->state = STATIC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 地面状态切换逻辑 ---
|
||||||
|
switch (tracker->state) {
|
||||||
|
case LANDING:
|
||||||
|
tracker->state = STATIC;
|
||||||
|
break;
|
||||||
|
case STATIC:
|
||||||
|
// 优先判断是否进入 WOBBLE 状态
|
||||||
|
// 条件:陀螺仪活动剧烈,但整体加速度变化不大(说明是原地转或晃)
|
||||||
|
if (gyr_magnitude > ROTATION_GYR_MAG_THRESHOLD && fabsf(acc_magnitude - G_ACCELERATION) < WOBBLE_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = WOBBLE;
|
||||||
|
}
|
||||||
|
// 只有在陀螺仪和加速度都满足“前进”特征时,才启动
|
||||||
|
else if (gyr_variance > START_GYR_VARIANCE_THRESHOLD && fabsf(acc_magnitude - G_ACCELERATION) > START_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WOBBLE:
|
||||||
|
// 从 WOBBLE 状态启动的条件应该和从 STATIC 启动一样严格
|
||||||
|
if (gyr_variance > START_GYR_VARIANCE_THRESHOLD && fabsf(acc_magnitude - G_ACCELERATION) > START_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
// 如果陀螺仪活动减弱,则可能恢复静止
|
||||||
|
else if (gyr_magnitude < ROTATION_GYR_MAG_THRESHOLD * 0.8f) { // 增加迟滞,避免抖动
|
||||||
|
// 不直接跳回STATIC,而是依赖下一轮的全局静止判断
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NO_CONSTANT_SPEED: //非匀速状态
|
||||||
|
//暂时不考虑摔倒
|
||||||
|
// if (gyr_magnitude > FALLEN_GRY_MAG_THRESHOLD) {
|
||||||
|
// tracker->state = FALLEN; //摔倒
|
||||||
|
// } else
|
||||||
|
if (gyr_magnitude > WHEEL_GYR_MAG_THRESHOLD && acc_variance > WHEEL_ACC_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = WHEEL; //转弯
|
||||||
|
} else if (fabsf(acc_magnitude - G_ACCELERATION) < SKIING_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = CONSTANT_SPEED; //匀速
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONSTANT_SPEED: //匀速状态
|
||||||
|
if (fabsf(acc_magnitude - G_ACCELERATION) > START_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
//TODO:可以添加进入转弯或摔倒的判断
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WHEEL:
|
||||||
|
// 从转弯状态,检查转弯是否结束
|
||||||
|
// 如果角速度和加速度方差都降下来了,就回到普通滑行状态
|
||||||
|
if (gyr_magnitude < WHEEL_GYR_MAG_THRESHOLD * 0.8f && acc_variance < WHEEL_ACC_VARIANCE_THRESHOLD * 0.8f) { // 乘以一个滞后系数避免抖动
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FALLEN:
|
||||||
|
// TODO:回到 STATIC
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 主更新函数
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
* @param acc_g 三轴加速度,g
|
||||||
|
* @param gyr_dps 三轴陀螺仪,dps
|
||||||
|
* @param angle 欧若拉角
|
||||||
|
* @param dt 采样时间间隔,会用来积分求速度
|
||||||
|
*/
|
||||||
|
void skiing_tracker_update(skiing_tracker_t *tracker, float *acc_g, float *gyr_dps, float *angle, float dt)
|
||||||
|
{
|
||||||
|
if (!tracker || !acc_g || !gyr_dps || !angle || dt <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(my_skiing_tracker.state == STOP_DETECTION)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// --- 数据预处理和缓冲 ---
|
||||||
|
float acc_device_ms2[3];
|
||||||
|
acc_device_ms2[0] = acc_g[0] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[1] = acc_g[1] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[2] = acc_g[2] * G_ACCELERATION;
|
||||||
|
|
||||||
|
// 将最新数据存入缓冲区
|
||||||
|
memcpy(tracker->acc_buffer[tracker->buffer_index], acc_device_ms2, sizeof(acc_device_ms2));
|
||||||
|
memcpy(tracker->gyr_buffer[tracker->buffer_index], gyr_dps, 3 * sizeof(float));
|
||||||
|
|
||||||
|
tracker->buffer_index++;
|
||||||
|
if (tracker->buffer_index >= VARIANCE_BUFFER_SIZE) {
|
||||||
|
tracker->buffer_index = 0;
|
||||||
|
tracker->buffer_filled = 1; // 标记缓冲区已满
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 更新状态机 ---
|
||||||
|
update_state_machine(tracker, acc_device_ms2, gyr_dps);
|
||||||
|
|
||||||
|
// --- 根据状态执行不同的计算逻辑 ---
|
||||||
|
switch (tracker->state) {
|
||||||
|
case TAKING_OFF:
|
||||||
|
tracker->speed = 0.0f;
|
||||||
|
break;
|
||||||
|
case IN_AIR:
|
||||||
|
// 在空中时,只累加滞空时间
|
||||||
|
tracker->time_in_air += dt;
|
||||||
|
break;
|
||||||
|
case LANDING:
|
||||||
|
// 刚落地,计算空中距离
|
||||||
|
calculate_air_distance(tracker);
|
||||||
|
// 清理速度和滤波器状态,为恢复地面追踪做准备
|
||||||
|
memset(tracker->velocity, 0, sizeof(tracker->velocity));
|
||||||
|
tracker->speed = 0;
|
||||||
|
memset(tracker->acc_world_unfiltered_prev, 0, sizeof(tracker->acc_world_unfiltered_prev));
|
||||||
|
memset(tracker->acc_world_filtered, 0, sizeof(tracker->acc_world_filtered));
|
||||||
|
memset(tracker->acc_world_lpf, 0, sizeof(tracker->acc_world_lpf)); // 清理新增的LPF状态
|
||||||
|
break;
|
||||||
|
case WHEEL:
|
||||||
|
case NO_CONSTANT_SPEED:
|
||||||
|
remove_gravity_in_device_frame(acc_device_ms2, angle, tracker->acc_no_g);
|
||||||
|
|
||||||
|
|
||||||
|
float acc_world_temp[3]; // 临时变量存储当前周期的加速度
|
||||||
|
for (int i = 0; i < 2; i++) { // 只处理水平方向的 x 和 y 轴
|
||||||
|
|
||||||
|
// --- 核心修改:颠倒滤波器顺序为 HPF -> LPF ---
|
||||||
|
|
||||||
|
// 1. 高通滤波 (HPF) 先行: 消除因姿态误差导致的重力泄漏(直流偏置)
|
||||||
|
// HPF的瞬态响应会产生尖峰,这是正常的。
|
||||||
|
tracker->acc_world_filtered[i] = HPF_ALPHA * (tracker->acc_world_filtered[i] + tracker->acc_no_g[i] - tracker->acc_world_unfiltered_prev[i]);
|
||||||
|
tracker->acc_world_unfiltered_prev[i] = tracker->acc_no_g[i];
|
||||||
|
|
||||||
|
// 2. 低通滤波 (LPF) 殿后: 平滑掉HPF产生的尖峰和传感器自身的高频振动噪声。
|
||||||
|
// 这里使用 tracker->acc_world_filtered[i] 作为LPF的输入。
|
||||||
|
tracker->acc_world_lpf[i] = (1.0f - LPF_ALPHA) * tracker->acc_world_filtered[i] + LPF_ALPHA * tracker->acc_world_lpf[i];
|
||||||
|
|
||||||
|
// 将最终处理完的加速度值存入临时变量
|
||||||
|
acc_world_temp[i] = tracker->acc_world_lpf[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算处理后加速度的水平模长
|
||||||
|
float acc_horizontal_mag = sqrtf(acc_world_temp[0] * acc_world_temp[0] +
|
||||||
|
acc_world_temp[1] * acc_world_temp[1]);
|
||||||
|
#if XTELL_TEST
|
||||||
|
debug2.acc_magnitude = acc_horizontal_mag;
|
||||||
|
#endif
|
||||||
|
// 应用死区,并积分
|
||||||
|
if (acc_horizontal_mag > ACC_DEAD_ZONE_THRESHOLD) {
|
||||||
|
tracker->velocity[0] += acc_world_temp[0] * dt;
|
||||||
|
tracker->velocity[1] += acc_world_temp[1] * dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新速度和距离
|
||||||
|
tracker->speed = sqrtf(tracker->velocity[0] * tracker->velocity[0] +
|
||||||
|
tracker->velocity[1] * tracker->velocity[1]);
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
break;
|
||||||
|
case CONSTANT_SPEED:
|
||||||
|
//保持上次的速度不变。只更新距离
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
break;
|
||||||
|
case STATIC:
|
||||||
|
case WOBBLE:
|
||||||
|
// 速度清零,抑制漂移
|
||||||
|
memset(tracker->velocity, 0, sizeof(tracker->velocity));
|
||||||
|
tracker->speed = 0.0f;
|
||||||
|
memset(tracker->acc_world_unfiltered_prev, 0, sizeof(tracker->acc_world_unfiltered_prev));
|
||||||
|
memset(tracker->acc_world_filtered, 0, sizeof(tracker->acc_world_filtered));
|
||||||
|
memset(tracker->acc_world_lpf, 0, sizeof(tracker->acc_world_lpf)); // 清理新增的LPF状态
|
||||||
|
#if XTELL_TEST
|
||||||
|
debug2.acc_magnitude = 0;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case FALLEN:
|
||||||
|
// TODO
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 滑雪数据计算
|
||||||
|
*
|
||||||
|
* @param acc_data_buf 传入的三轴加速度数据
|
||||||
|
* @param gyr_data_buf 传入的三轴陀螺仪数据
|
||||||
|
* @param angle_data 传入的欧若拉角数据
|
||||||
|
* @return BLE_send_data_t 要发送给蓝牙的数据
|
||||||
|
*/
|
||||||
|
BLE_send_data_t sensor_processing_task(signed short* acc_data_buf, signed short* gyr_data_buf, float* angle_data) {
|
||||||
|
|
||||||
|
static int initialized = 0;
|
||||||
|
static float acc_data_g[3];
|
||||||
|
static float gyr_data_dps[3];
|
||||||
|
|
||||||
|
// const float delta_time = DELTA_TIME+0.01f;
|
||||||
|
// const float delta_time = DELTA_TIME + 0.005f;
|
||||||
|
const float delta_time = DELTA_TIME;
|
||||||
|
BLE_send_data_t BLE_send_data;
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
skiing_tracker_init(&my_skiing_tracker);
|
||||||
|
initialized = 1;
|
||||||
|
printf("Skiing Tracker Initialized. Waiting for sensor calibration...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if ACC_RANGE==2
|
||||||
|
// 加速度 LSB to g
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 16384.0f;
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 16384.0f;
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 16384.0f;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ACC_RANGE==4
|
||||||
|
// 加速度 LSB to g
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 8192.0f;
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 8192.0f;
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 8192.0f;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ACC_RANGE==8
|
||||||
|
//±8g 4096
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 4096.0f; //ax
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 4096.0f; //ay
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 4096.0f; //az
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ACC_RANGE==16
|
||||||
|
//±16g 2048
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 2048.0f; //ax
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 2048.0f; //ay
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 2048.0f; //az
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 陀螺仪 LSB to dps (度/秒)
|
||||||
|
// ±2000dps量程下,转换系数约为 0.061
|
||||||
|
gyr_data_dps[0] = (float)gyr_data_buf[0] * 0.061f;
|
||||||
|
gyr_data_dps[1] = (float)gyr_data_buf[1] * 0.061f;
|
||||||
|
gyr_data_dps[2] = (float)gyr_data_buf[2] * 0.061f;
|
||||||
|
|
||||||
|
skiing_tracker_update(&my_skiing_tracker, acc_data_g, gyr_data_dps, angle_data, delta_time);
|
||||||
|
|
||||||
|
BLE_send_data.skiing_state = my_skiing_tracker.state;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
BLE_send_data.acc_data[i] = (short)(acc_data_g[i] * 9.8f) * 100; //cm/^s2
|
||||||
|
BLE_send_data.gyr_data[i] = (short)gyr_data_dps[i]; //dps
|
||||||
|
BLE_send_data.angle_data[i] = angle_data[i];
|
||||||
|
#else
|
||||||
|
BLE_send_data.acc_data[i] = (short)acc_data_buf[i]; //原始adc数据
|
||||||
|
BLE_send_data.gyr_data[i] = (short)gyr_data_buf[i]; //原始adc数据
|
||||||
|
BLE_send_data.angle_data[i] = angle_data[i];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
BLE_send_data.speed_cms = (int)(my_skiing_tracker.speed * 100);
|
||||||
|
BLE_send_data.distance_cm = (int)(my_skiing_tracker.distance * 100);
|
||||||
|
// printf("Calculate the time interval =============== end\n");
|
||||||
|
|
||||||
|
return BLE_send_data;
|
||||||
|
}
|
||||||
|
|
||||||
88
apps/earphone/xtell_Sensor/A_hide/10/skiing_tracker.h
Normal file
88
apps/earphone/xtell_Sensor/A_hide/10/skiing_tracker.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#ifndef SKIING_TRACKER_H
|
||||||
|
#define SKIING_TRACKER_H
|
||||||
|
|
||||||
|
#include "../xtell.h"
|
||||||
|
// 定义滑雪者可能的状态
|
||||||
|
typedef enum {
|
||||||
|
STATIC, // 静止或动态稳定:0
|
||||||
|
NO_CONSTANT_SPEED, // 正在滑雪,非匀速:1
|
||||||
|
CONSTANT_SPEED, // 正在滑雪,匀速:2
|
||||||
|
WOBBLE, // 正在原地旋转:3
|
||||||
|
WHEEL, // 转弯:4
|
||||||
|
FALLEN, // 已摔倒:5
|
||||||
|
TAKING_OFF, // 起跳冲击阶段:6
|
||||||
|
IN_AIR, // 空中失重阶段:7
|
||||||
|
LANDING, // 落地冲击阶段:8
|
||||||
|
STOP_DETECTION, // 停止检测:9
|
||||||
|
UNKNOWN // 未知状态:10
|
||||||
|
} skiing_state_t;
|
||||||
|
|
||||||
|
#define VARIANCE_BUFFER_SIZE 5 // 用于计算方差的数据窗口大小 (5个样本 @ 100Hz = 50ms),减小延迟,提高实时性
|
||||||
|
#define DELTA_TIME 0.01f
|
||||||
|
|
||||||
|
|
||||||
|
// 追踪器数据结构体
|
||||||
|
typedef struct {
|
||||||
|
// 公开数据
|
||||||
|
float velocity[3]; // 当前速度 (x, y, z),单位: m/s
|
||||||
|
float distance; // 总滑行距离,单位: m
|
||||||
|
float speed; // 当前速率 (标量),单位: m/s
|
||||||
|
skiing_state_t state; // 当前滑雪状态
|
||||||
|
|
||||||
|
// 内部计算使用的私有成员
|
||||||
|
float acc_no_g[3]; // 去掉重力分量后的加速度
|
||||||
|
|
||||||
|
// 用于空中距离计算
|
||||||
|
float time_in_air; // 滞空时间计时器
|
||||||
|
float initial_velocity_on_takeoff[3]; // 起跳瞬间的速度向量
|
||||||
|
int airborne_entry_counter; // 进入空中状态的确认计数器
|
||||||
|
int grounded_entry_counter; // 落地确认计数器
|
||||||
|
|
||||||
|
// --- 内部计算使用的私有成员 ---
|
||||||
|
// 用于动态零速更新和旋转检测的缓冲区
|
||||||
|
float acc_buffer[VARIANCE_BUFFER_SIZE][3]; // 加速度数据窗口
|
||||||
|
float gyr_buffer[VARIANCE_BUFFER_SIZE][3]; // 角速度数据窗口
|
||||||
|
int buffer_index; // 缓冲区当前索引
|
||||||
|
int buffer_filled; // 缓冲区是否已填满的标志
|
||||||
|
|
||||||
|
// 用于高通滤波器(巴特沃斯一阶滤波器)的私有成员,以消除加速度的直流偏置
|
||||||
|
float acc_world_filtered[3]; //过滤过的
|
||||||
|
float acc_world_unfiltered_prev[3]; //上一次没过滤的
|
||||||
|
|
||||||
|
float acc_world_lpf[3]; // 经过低通滤波后的世界坐标系加速度
|
||||||
|
} skiing_tracker_t;
|
||||||
|
|
||||||
|
//ble发送的数据
|
||||||
|
typedef struct{ //__attribute__((packed)){ //该结构体取消内存对齐
|
||||||
|
char sensor_state;
|
||||||
|
char skiing_state;
|
||||||
|
int speed_cms; //求出的速度,cm/s
|
||||||
|
int distance_cm; //求出的距离,cm
|
||||||
|
short acc_data[3]; //三轴加速度, g
|
||||||
|
short gyr_data[3]; //三轴陀螺仪, dps
|
||||||
|
float angle_data[3]; //欧若拉角
|
||||||
|
}BLE_send_data_t;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
int acc_KS[3]; //卡尔曼后,LSB转换后的 三轴加速度数据(cm/s^2)
|
||||||
|
int gyr_KS_dps[3]; //卡尔曼后,LSB to dps 三轴陀螺仪数据
|
||||||
|
int angle_KS[3]; //卡尔曼后,计算得到的欧若拉角数据
|
||||||
|
}BLE_KS_send_data_t;
|
||||||
|
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
typedef struct{
|
||||||
|
float acc_variance; //三轴加速度方差之和
|
||||||
|
float gyr_variance; //三轴陀螺仪方差之和
|
||||||
|
float acc_magnitude; //三轴加速度模长
|
||||||
|
float gyr_magnitude; //三轴陀螺仪模长
|
||||||
|
}debug_t;
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker 指向 skiing_tracker_t 结构体的指针
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker);
|
||||||
|
|
||||||
|
BLE_send_data_t sensor_processing_task(signed short* acc_data_buf, signed short* gyr_data_buf, float* angle_data) ;
|
||||||
|
#endif // SKIING_TRACKER_H
|
||||||
377
apps/earphone/xtell_Sensor/A_hide/11_test/skiing_tracker.c
Normal file
377
apps/earphone/xtell_Sensor/A_hide/11_test/skiing_tracker.c
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
/*
|
||||||
|
使用四元数求角度和去掉重力分量
|
||||||
|
*/
|
||||||
|
#include "skiing_tracker.h"
|
||||||
|
#include "../sensor/SC7U22.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define ENABLE_XLOG 1
|
||||||
|
#ifdef xlog
|
||||||
|
#undef xlog
|
||||||
|
#endif
|
||||||
|
#if ENABLE_XLOG
|
||||||
|
#define xlog(format, ...) printf("[XT:%s] " format, __func__, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define xlog(format, ...) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define G_ACCELERATION 9.81f
|
||||||
|
#define DEG_TO_RAD (3.14159265f / 180.0f)
|
||||||
|
|
||||||
|
BLE_KS_send_data_t KS_data;
|
||||||
|
static float quaternion_data[4];
|
||||||
|
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
|
||||||
|
debug_t debug1;
|
||||||
|
debug_t debug2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static skiing_tracker_t my_skiing_tracker;
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//实现
|
||||||
|
|
||||||
|
void clear_speed(void){
|
||||||
|
my_skiing_tracker.state = STATIC;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_detection(void){
|
||||||
|
my_skiing_tracker.state = STATIC;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.distance = 0;
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop_detection(void){
|
||||||
|
my_skiing_tracker.state = STOP_DETECTION;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker)
|
||||||
|
{
|
||||||
|
if (!tracker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 使用memset一次性清零整个结构体,包括新增的缓冲区
|
||||||
|
memset(tracker, 0, sizeof(skiing_tracker_t));
|
||||||
|
tracker->state = STATIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 当检测到落地时,计算空中的水平飞行距离并累加到总距离
|
||||||
|
*/
|
||||||
|
static void calculate_air_distance(skiing_tracker_t *tracker) {
|
||||||
|
float horizontal_speed_on_takeoff = sqrtf(
|
||||||
|
tracker->initial_velocity_on_takeoff[0] * tracker->initial_velocity_on_takeoff[0] +
|
||||||
|
tracker->initial_velocity_on_takeoff[1] * tracker->initial_velocity_on_takeoff[1]
|
||||||
|
);
|
||||||
|
float distance_in_air = horizontal_speed_on_takeoff * tracker->time_in_air;
|
||||||
|
tracker->distance += distance_in_air;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 将设备坐标系下的加速度转换为世界坐标系,去掉重力分量
|
||||||
|
*
|
||||||
|
* @param acc_device
|
||||||
|
* @param angle
|
||||||
|
* @param acc_linear_world
|
||||||
|
*/
|
||||||
|
static void transform_acc_to_world_frame(const float *acc_device, const float *angle, float *acc_linear_world)
|
||||||
|
{
|
||||||
|
// 1. 将输入的角度从度转换为弧度
|
||||||
|
// angle[0] -> pitch, angle[1] -> roll, angle[2] -> yaw
|
||||||
|
float pitch_rad = -angle[0] * (M_PI / 180.0f);
|
||||||
|
float roll_rad = -angle[1] * (M_PI / 180.0f);
|
||||||
|
float yaw_rad = -angle[2] * (M_PI / 180.0f);
|
||||||
|
|
||||||
|
// 2. 预先计算三角函数值,以提高效率
|
||||||
|
float c_r = cosf(roll_rad);
|
||||||
|
float s_r = sinf(roll_rad);
|
||||||
|
float c_p = cosf(pitch_rad);
|
||||||
|
float s_p = sinf(pitch_rad);
|
||||||
|
float c_y = cosf(yaw_rad);
|
||||||
|
float s_y = sinf(yaw_rad);
|
||||||
|
|
||||||
|
// 3. 构建从设备坐标系到世界坐标系的旋转矩阵 R_device_to_world
|
||||||
|
// 该矩阵基于 Z-Y-X (Yaw-Pitch-Roll) 欧拉角顺序
|
||||||
|
// R = R_z(yaw) * R_y(pitch) * R_x(roll)
|
||||||
|
float R[3][3];
|
||||||
|
R[0][0] = c_y * c_p;
|
||||||
|
R[0][1] = c_y * s_p * s_r - s_y * c_r;
|
||||||
|
R[0][2] = c_y * s_p * c_r + s_y * s_r;
|
||||||
|
|
||||||
|
R[1][0] = s_y * c_p;
|
||||||
|
R[1][1] = s_y * s_p * s_r + c_y * c_r;
|
||||||
|
R[1][2] = s_y * s_p * c_r - c_y * s_r;
|
||||||
|
|
||||||
|
R[2][0] = -s_p;
|
||||||
|
R[2][1] = c_p * s_r;
|
||||||
|
R[2][2] = c_p * c_r;
|
||||||
|
|
||||||
|
// 4. 将设备坐标系的加速度计总读数旋转到世界坐标系
|
||||||
|
// a_raw_world = R * acc_device
|
||||||
|
float ax_raw_world = R[0][0] * acc_device[0] + R[0][1] * acc_device[1] + R[0][2] * acc_device[2];
|
||||||
|
float ay_raw_world = R[1][0] * acc_device[0] + R[1][1] * acc_device[1] + R[1][2] * acc_device[2];
|
||||||
|
float az_raw_world = R[2][0] * acc_device[0] + R[2][1] * acc_device[1] + R[2][2] * acc_device[2];
|
||||||
|
|
||||||
|
// 5. 在世界坐标系中减去重力分量,得到线性加速度
|
||||||
|
// 假设世界坐标系Z轴垂直向上,重力矢量为 [0, 0, -g]
|
||||||
|
// 线性加速度 = 总加速度 - 重力加速度
|
||||||
|
// az_linear = az_raw_world - (-g) = az_raw_world + g (如果Z轴向上)
|
||||||
|
// az_linear = az_raw_world - (+g) = az_raw_world - g (如果Z轴向下)
|
||||||
|
// 这里我们采用 Z 轴向上的标准惯性系 (ENU)
|
||||||
|
|
||||||
|
acc_linear_world[0] = ax_raw_world;
|
||||||
|
acc_linear_world[1] = ay_raw_world;
|
||||||
|
acc_linear_world[2] = az_raw_world - G_ACCELERATION; // Z轴向上,重力为正值,所以减去
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief 在设备坐标系下,从原始加速度数据中移除重力分量
|
||||||
|
* @param acc_device 输入:设备坐标系下的原始加速度 [x, y, z], 单位 m/s^2
|
||||||
|
* @param angle 输入:姿态角 [pitch, roll, yaw],单位: 度
|
||||||
|
* @param acc_linear_device 输出:设备坐标系下移除重力后的线性加速度 [x, y, z]
|
||||||
|
*/
|
||||||
|
void remove_gravity_in_device_frame(const float *acc_device, const float *angle, float *acc_linear_device)
|
||||||
|
{
|
||||||
|
float pitch = -angle[0] * DEG_TO_RAD; // 绕 Y 轴
|
||||||
|
float roll = -angle[1] * DEG_TO_RAD; // 绕 X 轴
|
||||||
|
float yaw = -angle[2] * DEG_TO_RAD; // 绕 Z 轴
|
||||||
|
|
||||||
|
float cp = cosf(pitch);
|
||||||
|
float sp = sinf(pitch);
|
||||||
|
float cr = cosf(roll);
|
||||||
|
float sr = sinf(roll);
|
||||||
|
float cy = cosf(yaw);
|
||||||
|
float sy = sinf(yaw);
|
||||||
|
|
||||||
|
// 世界坐标系下的重力矢量
|
||||||
|
const float g_world[3] = {0.0f, 0.0f, G_ACCELERATION};
|
||||||
|
|
||||||
|
// 计算旋转矩阵 R 的转置矩阵 R_transpose
|
||||||
|
// R (Z-Y-X) =
|
||||||
|
// [ cy*cp, cy*sp*sr - sy*cr, cy*sp*cr + sy*sr]
|
||||||
|
// [ sy*cp, sy*sp*sr + cy*cr, sy*sp*cr - cy*sr]
|
||||||
|
// [ -sp, cp*sr, cp*cr ]
|
||||||
|
//
|
||||||
|
// R_transpose =
|
||||||
|
// [ cy*cp, sy*cp, -sp ]
|
||||||
|
// [ cy*sp*sr - sy*cr, sy*sp*sr + cy*cr, cp*sr ]
|
||||||
|
// [ cy*sp*cr + sy*sr, sy*sp*cr - cy*sr, cp*cr ]
|
||||||
|
|
||||||
|
// 计算重力在设备坐标系下的投影 G_device = R_transpose * G_world
|
||||||
|
// 由于 G_world 只有 z 分量,计算可以简化
|
||||||
|
float g_device[3];
|
||||||
|
g_device[0] = (-sp) * g_world[2];
|
||||||
|
g_device[1] = (cp * sr) * g_world[2];
|
||||||
|
g_device[2] = (cp * cr) * g_world[2];
|
||||||
|
|
||||||
|
// 从原始设备加速度中减去重力投影
|
||||||
|
acc_linear_device[0] = acc_device[0] - g_device[0];
|
||||||
|
acc_linear_device[1] = acc_device[1] - g_device[1];
|
||||||
|
acc_linear_device[2] = acc_device[2] - g_device[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 使用四元数直接从设备坐标系的加速度中移除重力分量
|
||||||
|
* @details 这种方法比使用欧拉角更精确、更稳定,且避免了万向节死锁。
|
||||||
|
* @param acc_device 输入:设备坐标系下的原始加速度 [x, y, z], 单位 m/s^2
|
||||||
|
* @param q 输入:表示姿态的四元数 [w, x, y, z]
|
||||||
|
* @param acc_linear_device 输出:设备坐标系下移除重力后的线性加速度 [x, y, z]
|
||||||
|
*/
|
||||||
|
void q_remove_gravity_with_quaternion(const float *acc_device, const float *q, float *acc_linear_device)
|
||||||
|
{
|
||||||
|
// 从四元数计算重力在设备坐标系下的投影
|
||||||
|
// G_device = R_transpose * G_world
|
||||||
|
// G_world = [0, 0, g]
|
||||||
|
// R_transpose 的第三列即为重力投影方向
|
||||||
|
float gx = 2.0f * (q[1] * q[3] - q[0] * q[2]);
|
||||||
|
float gy = 2.0f * (q[0] * q[1] + q[2] * q[3]);
|
||||||
|
float gz = q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3];
|
||||||
|
|
||||||
|
// 从原始加速度中减去重力分量
|
||||||
|
acc_linear_device[0] = acc_device[0] - gx * G_ACCELERATION;
|
||||||
|
acc_linear_device[1] = acc_device[1] - gy * G_ACCELERATION;
|
||||||
|
acc_linear_device[2] = acc_device[2] - gz * G_ACCELERATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 使用四元数将设备坐标系的线性加速度转换到世界坐标系,并且移除重力分量
|
||||||
|
* @details 同样,此方法比使用欧拉角更优。
|
||||||
|
* @param acc_linear_device 输入:设备坐标系下的线性加速度 [x, y, z]
|
||||||
|
* @param q 输入:表示姿态的四元数 [w, x, y, z]
|
||||||
|
* @param acc_linear_world 输出:世界坐标系下的线性加速度 [x, y, z]
|
||||||
|
*/
|
||||||
|
void q_transform_to_world_with_quaternion(const float *acc_linear_device, const float *q, float *acc_linear_world)
|
||||||
|
{
|
||||||
|
// 这是 R_device_to_world * acc_linear_device 的展开形式
|
||||||
|
acc_linear_world[0] = (1.0f - 2.0f*q[2]*q[2] - 2.0f*q[3]*q[3]) * acc_linear_device[0] +
|
||||||
|
(2.0f*q[1]*q[2] - 2.0f*q[0]*q[3]) * acc_linear_device[1] +
|
||||||
|
(2.0f*q[1]*q[3] + 2.0f*q[0]*q[2]) * acc_linear_device[2];
|
||||||
|
|
||||||
|
acc_linear_world[1] = (2.0f*q[1]*q[2] + 2.0f*q[0]*q[3]) * acc_linear_device[0] +
|
||||||
|
(1.0f - 2.0f*q[1]*q[1] - 2.0f*q[3]*q[3]) * acc_linear_device[1] +
|
||||||
|
(2.0f*q[2]*q[3] - 2.0f*q[0]*q[1]) * acc_linear_device[2];
|
||||||
|
|
||||||
|
acc_linear_world[2] = (2.0f*q[1]*q[3] - 2.0f*q[0]*q[2]) * acc_linear_device[0] +
|
||||||
|
(2.0f*q[2]*q[3] + 2.0f*q[0]*q[1]) * acc_linear_device[1] +
|
||||||
|
(1.0f - 2.0f*q[1]*q[1] - 2.0f*q[2]*q[2]) * acc_linear_device[2];
|
||||||
|
acc_linear_world[2] -= G_ACCELERATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 主更新函数
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
* @param acc_g 三轴加速度,g
|
||||||
|
* @param gyr_dps 三轴陀螺仪,dps
|
||||||
|
* @param angle 欧若拉角
|
||||||
|
* @param dt 采样时间间隔,会用来积分求速度
|
||||||
|
*/
|
||||||
|
void skiing_tracker_update(skiing_tracker_t *tracker, float *acc_g, float *gyr_dps, float *angle, float dt)
|
||||||
|
{
|
||||||
|
if (!tracker || !acc_g || !gyr_dps || !angle || dt <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(my_skiing_tracker.state == STOP_DETECTION)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// --- 数据预处理和缓冲 ---
|
||||||
|
float acc_device_ms2[3];
|
||||||
|
acc_device_ms2[0] = acc_g[0] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[1] = acc_g[1] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[2] = acc_g[2] * G_ACCELERATION;
|
||||||
|
|
||||||
|
#if 1 //测试禁止状态下陀螺仪的三轴加速度,去掉重力分量后是否正常
|
||||||
|
float tmp_device_acc[3];
|
||||||
|
float tmp_world_acc[3];
|
||||||
|
// remove_gravity_in_device_frame(acc_device_ms2,angle,tmp_device_acc);
|
||||||
|
// transform_acc_to_world_frame(acc_device_ms2,angle,tmp_world_acc);
|
||||||
|
|
||||||
|
q_remove_gravity_with_quaternion(acc_device_ms2,quaternion_data,tmp_device_acc);
|
||||||
|
q_transform_to_world_with_quaternion(acc_device_ms2,quaternion_data,tmp_world_acc);
|
||||||
|
|
||||||
|
// 计算处理后加速度的水平模长
|
||||||
|
float all_device_mag = sqrtf(tmp_device_acc[0] * tmp_device_acc[0] +
|
||||||
|
tmp_device_acc[1] * tmp_device_acc[1] +
|
||||||
|
tmp_device_acc[2] * tmp_device_acc[2]);
|
||||||
|
|
||||||
|
float all_world_mag = sqrtf(tmp_world_acc[0] * tmp_world_acc[0] +
|
||||||
|
tmp_world_acc[1] * tmp_world_acc[1] +
|
||||||
|
tmp_world_acc[2] * tmp_world_acc[2]);
|
||||||
|
|
||||||
|
|
||||||
|
static int count = 0;
|
||||||
|
if(count > 100){
|
||||||
|
xlog("===original(g): x %.2f, y %.2f, z %.2f===\n",acc_g[0],acc_g[1],acc_g[2]);
|
||||||
|
xlog("===device(m/s^2) no g: x %.2f, y %.2f, z %.2f, all %.2f===\n",tmp_device_acc[0],tmp_device_acc[1],tmp_device_acc[2],all_device_mag); //去掉重力加速度
|
||||||
|
xlog("===world(m/s^2) no g: x %.2f, y %.2f, z %.2f, all %.2f===\n",tmp_world_acc[0],tmp_world_acc[1],tmp_world_acc[2],all_world_mag); //去掉重力加速度
|
||||||
|
xlog("===gyr(dps) : x %.2f, y %.2f, z %.2f, all %.2f===\n",gyr_dps[0],gyr_dps[1],gyr_dps[2]); //angle
|
||||||
|
xlog("===angle : x %.2f, y %.2f, z %.2f,===\n",angle[0],angle[1],angle[2]);
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 滑雪数据计算
|
||||||
|
*
|
||||||
|
* @param acc_data_buf 传入的三轴加速度数据
|
||||||
|
* @param gyr_data_buf 传入的三轴陀螺仪数据
|
||||||
|
* @param angle_data 传入的欧若拉角数据
|
||||||
|
* @return BLE_send_data_t 要发送给蓝牙的数据
|
||||||
|
*/
|
||||||
|
BLE_send_data_t sensor_processing_task(signed short* acc_data_buf, signed short* gyr_data_buf, float* angle_data, float* quaternion) {
|
||||||
|
|
||||||
|
static int initialized = 0;
|
||||||
|
static float acc_data_g[3];
|
||||||
|
static float gyr_data_dps[3];
|
||||||
|
if(quaternion != NULL){
|
||||||
|
memcpy(quaternion_data, quaternion, 4 * sizeof(float));
|
||||||
|
}
|
||||||
|
|
||||||
|
// const float delta_time = DELTA_TIME+0.01f;
|
||||||
|
// const float delta_time = DELTA_TIME + 0.005f;
|
||||||
|
const float delta_time = DELTA_TIME;
|
||||||
|
BLE_send_data_t BLE_send_data;
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
skiing_tracker_init(&my_skiing_tracker);
|
||||||
|
initialized = 1;
|
||||||
|
printf("Skiing Tracker Initialized. Waiting for sensor calibration...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if ACC_RANGE==2
|
||||||
|
// 加速度 LSB to g
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 16384.0f;
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 16384.0f;
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 16384.0f;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ACC_RANGE==4
|
||||||
|
// 加速度 LSB to g
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 8192.0f;
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 8192.0f;
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 8192.0f;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ACC_RANGE==8
|
||||||
|
//±8g 4096
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 4096.0f; //ax
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 4096.0f; //ay
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 4096.0f; //az
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ACC_RANGE==16
|
||||||
|
//±16g 2048
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 2048.0f; //ax
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 2048.0f; //ay
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 2048.0f; //az
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 陀螺仪 LSB to dps (度/秒)
|
||||||
|
// ±2000dps量程下,转换系数约为 0.061
|
||||||
|
gyr_data_dps[0] = (float)gyr_data_buf[0] * 0.061f;
|
||||||
|
gyr_data_dps[1] = (float)gyr_data_buf[1] * 0.061f;
|
||||||
|
gyr_data_dps[2] = (float)gyr_data_buf[2] * 0.061f;
|
||||||
|
|
||||||
|
skiing_tracker_update(&my_skiing_tracker, acc_data_g, gyr_data_dps, angle_data, delta_time);
|
||||||
|
|
||||||
|
// BLE_send_data.skiing_state = my_skiing_tracker.state;
|
||||||
|
// for (int i = 0; i < 3; i++) {
|
||||||
|
// #ifdef XTELL_TEST
|
||||||
|
// BLE_send_data.acc_data[i] = (short)(acc_data_g[i] * 9.8f) * 100; //cm/^s2
|
||||||
|
// BLE_send_data.gyr_data[i] = (short)gyr_data_dps[i]; //dps
|
||||||
|
// BLE_send_data.angle_data[i] = angle_data[i];
|
||||||
|
// #else
|
||||||
|
// BLE_send_data.acc_data[i] = (short)acc_data_buf[i]; //原始adc数据
|
||||||
|
// BLE_send_data.gyr_data[i] = (short)gyr_data_buf[i]; //原始adc数据
|
||||||
|
// BLE_send_data.angle_data[i] = angle_data[i];
|
||||||
|
// #endif
|
||||||
|
// }
|
||||||
|
// BLE_send_data.speed_cms = (int)(my_skiing_tracker.speed * 100);
|
||||||
|
// BLE_send_data.distance_cm = (int)(my_skiing_tracker.distance * 100);
|
||||||
|
// // printf("Calculate the time interval =============== end\n");
|
||||||
|
|
||||||
|
return BLE_send_data;
|
||||||
|
}
|
||||||
|
|
||||||
88
apps/earphone/xtell_Sensor/A_hide/11_test/skiing_tracker.h
Normal file
88
apps/earphone/xtell_Sensor/A_hide/11_test/skiing_tracker.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#ifndef SKIING_TRACKER_H
|
||||||
|
#define SKIING_TRACKER_H
|
||||||
|
|
||||||
|
#include "../xtell.h"
|
||||||
|
// 定义滑雪者可能的状态
|
||||||
|
typedef enum {
|
||||||
|
STATIC, // 静止或动态稳定:0
|
||||||
|
NO_CONSTANT_SPEED, // 正在滑雪,非匀速:1
|
||||||
|
CONSTANT_SPEED, // 正在滑雪,匀速:2
|
||||||
|
WOBBLE, // 正在原地旋转:3
|
||||||
|
WHEEL, // 转弯:4
|
||||||
|
FALLEN, // 已摔倒:5
|
||||||
|
TAKING_OFF, // 起跳冲击阶段:6
|
||||||
|
IN_AIR, // 空中失重阶段:7
|
||||||
|
LANDING, // 落地冲击阶段:8
|
||||||
|
STOP_DETECTION, // 停止检测:9
|
||||||
|
UNKNOWN // 未知状态:10
|
||||||
|
} skiing_state_t;
|
||||||
|
|
||||||
|
#define VARIANCE_BUFFER_SIZE 5 // 用于计算方差的数据窗口大小 (5个样本 @ 100Hz = 50ms),减小延迟,提高实时性
|
||||||
|
#define DELTA_TIME 0.01f
|
||||||
|
|
||||||
|
|
||||||
|
// 追踪器数据结构体
|
||||||
|
typedef struct {
|
||||||
|
// 公开数据
|
||||||
|
float velocity[3]; // 当前速度 (x, y, z),单位: m/s
|
||||||
|
float distance; // 总滑行距离,单位: m
|
||||||
|
float speed; // 当前速率 (标量),单位: m/s
|
||||||
|
skiing_state_t state; // 当前滑雪状态
|
||||||
|
|
||||||
|
// 内部计算使用的私有成员
|
||||||
|
float acc_world[3]; // 在世界坐标系下的加速度
|
||||||
|
|
||||||
|
// 用于空中距离计算
|
||||||
|
float time_in_air; // 滞空时间计时器
|
||||||
|
float initial_velocity_on_takeoff[3]; // 起跳瞬间的速度向量
|
||||||
|
int airborne_entry_counter; // 进入空中状态的确认计数器
|
||||||
|
int grounded_entry_counter; // 落地确认计数器
|
||||||
|
|
||||||
|
// --- 内部计算使用的私有成员 ---
|
||||||
|
// 用于动态零速更新和旋转检测的缓冲区
|
||||||
|
float acc_buffer[VARIANCE_BUFFER_SIZE][3]; // 加速度数据窗口
|
||||||
|
float gyr_buffer[VARIANCE_BUFFER_SIZE][3]; // 角速度数据窗口
|
||||||
|
int buffer_index; // 缓冲区当前索引
|
||||||
|
int buffer_filled; // 缓冲区是否已填满的标志
|
||||||
|
|
||||||
|
// 用于高通滤波器(巴特沃斯一阶滤波器)的私有成员,以消除加速度的直流偏置
|
||||||
|
float acc_world_filtered[3]; //过滤过的
|
||||||
|
float acc_world_unfiltered_prev[3]; //上一次没过滤的
|
||||||
|
|
||||||
|
float acc_world_lpf[3]; // 经过低通滤波后的世界坐标系加速度
|
||||||
|
} skiing_tracker_t;
|
||||||
|
|
||||||
|
//ble发送的数据
|
||||||
|
typedef struct{ //__attribute__((packed)){ //该结构体取消内存对齐
|
||||||
|
char sensor_state;
|
||||||
|
char skiing_state;
|
||||||
|
int speed_cms; //求出的速度,cm/s
|
||||||
|
int distance_cm; //求出的距离,cm
|
||||||
|
short acc_data[3]; //三轴加速度, g
|
||||||
|
short gyr_data[3]; //三轴陀螺仪, dps
|
||||||
|
float angle_data[3]; //欧若拉角
|
||||||
|
}BLE_send_data_t;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
int acc_KS[3]; //卡尔曼后,LSB转换后的 三轴加速度数据(cm/s^2)
|
||||||
|
int gyr_KS_dps[3]; //卡尔曼后,LSB to dps 三轴陀螺仪数据
|
||||||
|
int angle_KS[3]; //卡尔曼后,计算得到的欧若拉角数据
|
||||||
|
}BLE_KS_send_data_t;
|
||||||
|
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
typedef struct{
|
||||||
|
float acc_variance; //三轴加速度方差之和
|
||||||
|
float gyr_variance; //三轴陀螺仪方差之和
|
||||||
|
float acc_magnitude; //三轴加速度模长
|
||||||
|
float gyr_magnitude; //三轴陀螺仪模长
|
||||||
|
}debug_t;
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker 指向 skiing_tracker_t 结构体的指针
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker);
|
||||||
|
|
||||||
|
BLE_send_data_t sensor_processing_task(signed short* acc_data_buf, signed short* gyr_data_buf, float* angle_data, float* quaternion);
|
||||||
|
#endif // SKIING_TRACKER_H
|
||||||
259
apps/earphone/xtell_Sensor/A_hide/2/skiing_tracker.c
Normal file
259
apps/earphone/xtell_Sensor/A_hide/2/skiing_tracker.c
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
动态ZUPT+卡尔曼
|
||||||
|
*/
|
||||||
|
#include "skiing_tracker.h"
|
||||||
|
#include "../sensor/SC7U22.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define G_ACCELERATION 9.81f
|
||||||
|
#define DEG_TO_RAD (3.14159265f / 180.0f)
|
||||||
|
|
||||||
|
// --- 算法阈值定义 ---
|
||||||
|
// 动态零速更新(ZUPT)阈值:加速度方差小于此值,认为处于动态稳定状态
|
||||||
|
#define ZUPT_ACC_VARIANCE_THRESHOLD 0.05f
|
||||||
|
// 旋转检测阈值:Z轴角速度大于此值(度/秒),认为正在原地旋转
|
||||||
|
#define ROTATION_GYR_Z_THRESHOLD 60.0f
|
||||||
|
// 启动滑雪阈值:加速度模长与重力的差值大于此值,认为开始运动
|
||||||
|
#define START_SKIING_ACC_THRESHOLD 1.5f
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker)
|
||||||
|
{
|
||||||
|
if (!tracker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 使用memset一次性清零整个结构体,包括新增的缓冲区
|
||||||
|
memset(tracker, 0, sizeof(skiing_tracker_t));
|
||||||
|
tracker->state = SKIING_STATE_STATIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 将设备坐标系下的加速度转换为世界坐标系
|
||||||
|
* @param acc_device 设备坐标系下的加速度 [x, y, z]
|
||||||
|
* @param angle 姿态角 [pitch, roll, yaw],单位: 度
|
||||||
|
* @param acc_world 输出:世界坐标系下的加速度 [x, y, z]
|
||||||
|
*/
|
||||||
|
static void transform_acc_to_world_frame(const float *acc_device, const float *angle, float *acc_world)
|
||||||
|
{
|
||||||
|
// 驱动输出的角度与标准航空定义相反,需要取反才能用于标准旋转矩阵。
|
||||||
|
float pitch = -angle[0] * DEG_TO_RAD;
|
||||||
|
float roll = -angle[1] * DEG_TO_RAD;
|
||||||
|
|
||||||
|
float cp = cosf(pitch);
|
||||||
|
float sp = sinf(pitch);
|
||||||
|
float cr = cosf(roll);
|
||||||
|
float sr = sinf(roll);
|
||||||
|
|
||||||
|
float ax = acc_device[0];
|
||||||
|
float ay = acc_device[1];
|
||||||
|
float az = acc_device[2];
|
||||||
|
|
||||||
|
// 使用经过验证的、正确的身体坐标系到世界坐标系的旋转矩阵 (基于 Y-X 旋转顺序)
|
||||||
|
// 这个矩阵将设备测量的加速度(ax, ay, az)正确地转换到世界坐标系(acc_world)。
|
||||||
|
acc_world[0] = cp * ax + sp * sr * ay + sp * cr * az;
|
||||||
|
acc_world[1] = 0 * ax + cr * ay - sr * az;
|
||||||
|
acc_world[2] = -sp * ax + cp * sr * ay + cp * cr * az;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计算缓冲区内三轴数据的方差之和
|
||||||
|
*/
|
||||||
|
static float calculate_variance(float buffer[VARIANCE_BUFFER_SIZE][3])
|
||||||
|
{
|
||||||
|
float mean[3] = {0};
|
||||||
|
float variance[3] = {0};
|
||||||
|
|
||||||
|
// 1. 计算均值
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
mean[0] += buffer[i][0];
|
||||||
|
mean[1] += buffer[i][1];
|
||||||
|
mean[2] += buffer[i][2];
|
||||||
|
}
|
||||||
|
mean[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 2. 计算方差
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
variance[0] += (buffer[i][0] - mean[0]) * (buffer[i][0] - mean[0]);
|
||||||
|
variance[1] += (buffer[i][1] - mean[1]) * (buffer[i][1] - mean[1]);
|
||||||
|
variance[2] += (buffer[i][2] - mean[2]) * (buffer[i][2] - mean[2]);
|
||||||
|
}
|
||||||
|
variance[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 返回三轴方差之和,作为一个综合的稳定度指标
|
||||||
|
return variance[0] + variance[1] + variance[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 升级后的状态机,包含旋转检测和动态零速更新
|
||||||
|
*/
|
||||||
|
static void update_state_machine(skiing_tracker_t *tracker, const float *acc_device_ms2, const float *gyr_dps)
|
||||||
|
{
|
||||||
|
// 缓冲区未填满时,不进行状态判断,默认为静止
|
||||||
|
if (!tracker->buffer_filled) {
|
||||||
|
tracker->state = SKIING_STATE_STATIC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 计算关键指标 ---
|
||||||
|
float acc_variance = calculate_variance(tracker->acc_buffer);
|
||||||
|
float gyr_z_abs = fabsf(gyr_dps[2]);
|
||||||
|
float acc_magnitude = sqrtf(acc_device_ms2[0]*acc_device_ms2[0] + acc_device_ms2[1]*acc_device_ms2[1] + acc_device_ms2[2]*acc_device_ms2[2]);
|
||||||
|
|
||||||
|
// --- 状态切换逻辑 (按优先级) ---
|
||||||
|
|
||||||
|
// 旋转检测
|
||||||
|
// 如果Z轴角速度很大,则判断为原地旋转,暂停积分
|
||||||
|
if (gyr_z_abs > ROTATION_GYR_Z_THRESHOLD) {
|
||||||
|
tracker->state = SKIING_STATE_ROTATING;
|
||||||
|
return; // 直接返回,不执行后续判断
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态零速更新 (ZUPT)
|
||||||
|
// 如果加速度在窗口期内非常稳定(方差很小),则认为是动态稳定状态,进行零速校正
|
||||||
|
if (acc_variance < ZUPT_ACC_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = SKIING_STATE_STATIC;
|
||||||
|
// 速度清零,抑制漂移
|
||||||
|
memset(tracker->velocity, 0, sizeof(tracker->velocity));
|
||||||
|
tracker->speed = 0.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从静止/旋转状态启动
|
||||||
|
if (tracker->state == SKIING_STATE_STATIC || tracker->state == SKIING_STATE_ROTATING) {
|
||||||
|
if (fabsf(acc_magnitude - G_ACCELERATION) > START_SKIING_ACC_THRESHOLD) {
|
||||||
|
tracker->state = SKIING_STATE_SKIING;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 滑雪
|
||||||
|
if (tracker->state != SKIING_STATE_STATIC) {
|
||||||
|
tracker->state = SKIING_STATE_SKIING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 主更新函数
|
||||||
|
*/
|
||||||
|
void skiing_tracker_update(skiing_tracker_t *tracker, float *acc_g, float *gyr_dps, float *angle, float dt)
|
||||||
|
{
|
||||||
|
if (!tracker || !acc_g || !gyr_dps || !angle || dt <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 1. 数据预处理和缓冲 ---
|
||||||
|
float acc_device_ms2[3];
|
||||||
|
acc_device_ms2[0] = acc_g[0] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[1] = acc_g[1] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[2] = acc_g[2] * G_ACCELERATION;
|
||||||
|
|
||||||
|
// 将最新数据存入缓冲区
|
||||||
|
memcpy(tracker->acc_buffer[tracker->buffer_index], acc_device_ms2, sizeof(acc_device_ms2));
|
||||||
|
memcpy(tracker->gyr_buffer[tracker->buffer_index], gyr_dps, 3 * sizeof(float));
|
||||||
|
|
||||||
|
tracker->buffer_index++;
|
||||||
|
if (tracker->buffer_index >= VARIANCE_BUFFER_SIZE) {
|
||||||
|
tracker->buffer_index = 0;
|
||||||
|
tracker->buffer_filled = 1; // 标记缓冲区已满
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 2. 更新状态机 ---
|
||||||
|
update_state_machine(tracker, acc_device_ms2, gyr_dps);
|
||||||
|
|
||||||
|
// --- 3. 根据状态进行计算 ---
|
||||||
|
// 只有在明确的“滑雪”状态下才进行积分
|
||||||
|
if (tracker->state == SKIING_STATE_SKIING) {
|
||||||
|
transform_acc_to_world_frame(acc_device_ms2, angle, tracker->acc_world);
|
||||||
|
tracker->acc_world[2] -= G_ACCELERATION;
|
||||||
|
|
||||||
|
tracker->velocity[0] += tracker->acc_world[0] * dt;
|
||||||
|
tracker->velocity[1] += tracker->acc_world[1] * dt;
|
||||||
|
tracker->velocity[2] += tracker->acc_world[2] * dt;
|
||||||
|
}
|
||||||
|
// 在其他状态下(静止、旋转),速度已经在状态机内部被清零或保持不变
|
||||||
|
|
||||||
|
// --- 4. 更新速率和距离 ---
|
||||||
|
// 速率和距离总是在更新,但在非滑雪状态下,速度为0,所以它们不会增加
|
||||||
|
tracker->speed = sqrtf(tracker->velocity[0] * tracker->velocity[0] +
|
||||||
|
tracker->velocity[1] * tracker->velocity[1] +
|
||||||
|
tracker->velocity[2] * tracker->velocity[2]);
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 传感器数据采集与处理任务
|
||||||
|
void sensor_processing_task(signed short * acc_data_buf, signed short * gyr_data_buf) {
|
||||||
|
static skiing_tracker_t my_skiing_tracker;
|
||||||
|
static int initialized = 0;
|
||||||
|
static int calibration_done = 0;
|
||||||
|
|
||||||
|
static signed short combined_raw_data[6];
|
||||||
|
static float final_angle_data[3];
|
||||||
|
static float calibrated_acc_g[3];
|
||||||
|
static float calibrated_gyr_dps[3]; // 新增:用于存放转换后的陀螺仪数据
|
||||||
|
|
||||||
|
const float delta_time = 0.01f;
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
skiing_tracker_init(&my_skiing_tracker);
|
||||||
|
initialized = 1;
|
||||||
|
printf("Skiing Tracker Initialized. Waiting for sensor calibration...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&combined_raw_data[0], acc_data_buf, 3 * sizeof(signed short));
|
||||||
|
memcpy(&combined_raw_data[3], gyr_data_buf, 3 * sizeof(signed short));
|
||||||
|
|
||||||
|
unsigned char status;
|
||||||
|
if (!calibration_done) {
|
||||||
|
status = SL_SC7U22_Angle_Output(1, combined_raw_data, final_angle_data, 0);
|
||||||
|
if (status == 1) {
|
||||||
|
calibration_done = 1;
|
||||||
|
printf("Sensor calibration successful! Skiing mode is active.\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status = SL_SC7U22_Angle_Output(0, combined_raw_data, final_angle_data, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == 1) {
|
||||||
|
// 加速度 LSB to g
|
||||||
|
calibrated_acc_g[0] = (float)combined_raw_data[0] / 8192.0f;
|
||||||
|
calibrated_acc_g[1] = (float)combined_raw_data[1] / 8192.0f;
|
||||||
|
calibrated_acc_g[2] = (float)combined_raw_data[2] / 8192.0f;
|
||||||
|
|
||||||
|
// 陀螺仪 LSB to dps (度/秒)
|
||||||
|
// ±2000dps量程下,转换系数约为 0.061
|
||||||
|
calibrated_gyr_dps[0] = (float)combined_raw_data[3] * 0.061f;
|
||||||
|
calibrated_gyr_dps[1] = (float)combined_raw_data[4] * 0.061f;
|
||||||
|
calibrated_gyr_dps[2] = (float)combined_raw_data[5] * 0.061f;
|
||||||
|
|
||||||
|
skiing_tracker_update(&my_skiing_tracker, calibrated_acc_g, calibrated_gyr_dps, final_angle_data, delta_time);
|
||||||
|
|
||||||
|
// 打印逻辑保持不变
|
||||||
|
static int count = 0;
|
||||||
|
if(count < 10){
|
||||||
|
count++;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
printf("State: %d, Speed: %.2f m/s, Distance: %.2f m\n",
|
||||||
|
my_skiing_tracker.state,
|
||||||
|
my_skiing_tracker.speed,
|
||||||
|
my_skiing_tracker.distance);
|
||||||
|
|
||||||
|
} else if (status == 0) {
|
||||||
|
// printf("Sensor is calibrating...\n");
|
||||||
|
} else {
|
||||||
|
// printf("Angle calculation error or calibration not finished.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
50
apps/earphone/xtell_Sensor/A_hide/2/skiing_tracker.h
Normal file
50
apps/earphone/xtell_Sensor/A_hide/2/skiing_tracker.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#ifndef SKIING_TRACKER_H
|
||||||
|
#define SKIING_TRACKER_H
|
||||||
|
|
||||||
|
// 定义滑雪者可能的状态
|
||||||
|
typedef enum {
|
||||||
|
SKIING_STATE_STATIC, // 静止或动态稳定
|
||||||
|
SKIING_STATE_SKIING, // 正在滑雪
|
||||||
|
SKIING_STATE_ROTATING, // 正在原地旋转 (新增)
|
||||||
|
SKIING_STATE_FALLEN, // 已摔倒
|
||||||
|
SKIING_STATE_UNKNOWN // 未知状态
|
||||||
|
} skiing_state_t;
|
||||||
|
|
||||||
|
#define VARIANCE_BUFFER_SIZE 15 // 用于计算方差的数据窗口大小 (15个样本 @ 100Hz = 150ms)
|
||||||
|
|
||||||
|
// 追踪器数据结构体
|
||||||
|
typedef struct {
|
||||||
|
// 公开数据
|
||||||
|
float velocity[3]; // 当前速度 (x, y, z),单位: m/s
|
||||||
|
float distance; // 总滑行距离,单位: m
|
||||||
|
float speed; // 当前速率 (标量),单位: m/s
|
||||||
|
skiing_state_t state; // 当前滑雪状态
|
||||||
|
|
||||||
|
// 内部计算使用的私有成员
|
||||||
|
float acc_world[3]; // 在世界坐标系下的加速度
|
||||||
|
|
||||||
|
// 用于动态零速更新和旋转检测的缓冲区
|
||||||
|
float acc_buffer[VARIANCE_BUFFER_SIZE][3]; // 加速度数据窗口
|
||||||
|
float gyr_buffer[VARIANCE_BUFFER_SIZE][3]; // 角速度数据窗口
|
||||||
|
int buffer_index; // 缓冲区当前索引
|
||||||
|
int buffer_filled; // 缓冲区是否已填满的标志
|
||||||
|
} skiing_tracker_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker 指向 skiing_tracker_t 结构体的指针
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 处理传感器数据并更新滑雪状态
|
||||||
|
*
|
||||||
|
* @param tracker 指向 skiing_tracker_t 结构体的指针
|
||||||
|
* @param acc_g 校准后的加速度数据 [x, y, z],单位: g (1g = 9.8m/s^2)
|
||||||
|
* @param gyr_dps 角速度
|
||||||
|
* @param angle 姿态角数据 [pitch, roll, yaw],单位: 度
|
||||||
|
* @param dt 采样时间间隔,单位: 秒 (s)
|
||||||
|
*/
|
||||||
|
void skiing_tracker_update(skiing_tracker_t *tracker, float *acc_g, float *gyr_dps, float *angle, float dt);
|
||||||
|
#endif // SKIING_TRACKER_H
|
||||||
277
apps/earphone/xtell_Sensor/A_hide/3/skiing_tracker.c
Normal file
277
apps/earphone/xtell_Sensor/A_hide/3/skiing_tracker.c
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
/*
|
||||||
|
动态ZUPT+卡尔曼
|
||||||
|
*/
|
||||||
|
#include "skiing_tracker.h"
|
||||||
|
#include "../sensor/SC7U22.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define G_ACCELERATION 9.81f
|
||||||
|
#define DEG_TO_RAD (3.14159265f / 180.0f)
|
||||||
|
|
||||||
|
// --- 算法阈值定义 ---
|
||||||
|
//两个判断是否静止的必要条件
|
||||||
|
// 动态零速更新(ZUPT)阈值
|
||||||
|
// 提高阈值,让“刹车”更灵敏,以便在波浪式前进等慢速漂移时也能触发零速更新
|
||||||
|
#define ZUPT_ACC_VARIANCE_THRESHOLD 0.2f
|
||||||
|
// 陀螺仪方差阈值
|
||||||
|
#define ZUPT_GYR_VARIANCE_THRESHOLD 5.0f
|
||||||
|
|
||||||
|
// 旋转/摆动检测阈值:角速度总模长大于此值(度/秒),认为正在进行非滑雪的旋转或摆动
|
||||||
|
#define ROTATION_GYR_MAG_THRESHOLD 45.0f
|
||||||
|
// 启动滑雪阈值:加速度模长与重力的差值大于此值,认为开始运动
|
||||||
|
// 降低阈值,让“油门”更灵敏,以便能捕捉到真实的慢速启动
|
||||||
|
#define START_SKIING_ACC_THRESHOLD 0.5f
|
||||||
|
// 新增:速度阻尼系数,用于模拟摩擦力,抑制漂移
|
||||||
|
#define VELOCITY_DAMPING_FACTOR 0.98f
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker)
|
||||||
|
{
|
||||||
|
if (!tracker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 使用memset一次性清零整个结构体,包括新增的缓冲区
|
||||||
|
memset(tracker, 0, sizeof(skiing_tracker_t));
|
||||||
|
tracker->state = SKIING_STATE_STATIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 将设备坐标系下的加速度转换为世界坐标系
|
||||||
|
* @param acc_device 设备坐标系下的加速度 [x, y, z]
|
||||||
|
* @param angle 姿态角 [pitch, roll, yaw],单位: 度
|
||||||
|
* @param acc_world 输出:世界坐标系下的加速度 [x, y, z]
|
||||||
|
*/
|
||||||
|
static void transform_acc_to_world_frame(const float *acc_device, const float *angle, float *acc_world)
|
||||||
|
{
|
||||||
|
// 驱动输出的角度与标准航空定义相反,需要取反才能用于标准旋转矩阵。
|
||||||
|
float pitch = -angle[0] * DEG_TO_RAD;
|
||||||
|
float roll = -angle[1] * DEG_TO_RAD;
|
||||||
|
|
||||||
|
float cp = cosf(pitch);
|
||||||
|
float sp = sinf(pitch);
|
||||||
|
float cr = cosf(roll);
|
||||||
|
float sr = sinf(roll);
|
||||||
|
|
||||||
|
float ax = acc_device[0];
|
||||||
|
float ay = acc_device[1];
|
||||||
|
float az = acc_device[2];
|
||||||
|
|
||||||
|
// 使用经过验证的、正确的身体坐标系到世界坐标系的旋转矩阵 (基于 Y-X 旋转顺序)
|
||||||
|
// 这个矩阵将设备测量的加速度(ax, ay, az)正确地转换到世界坐标系(acc_world)。
|
||||||
|
acc_world[0] = cp * ax + sp * sr * ay + sp * cr * az;
|
||||||
|
acc_world[1] = 0 * ax + cr * ay - sr * az;
|
||||||
|
acc_world[2] = -sp * ax + cp * sr * ay + cp * cr * az;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计算缓冲区内三轴数据的方差之和
|
||||||
|
*/
|
||||||
|
static float calculate_variance(float buffer[VARIANCE_BUFFER_SIZE][3])
|
||||||
|
{
|
||||||
|
float mean[3] = {0};
|
||||||
|
float variance[3] = {0};
|
||||||
|
|
||||||
|
// 1. 计算均值
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
mean[0] += buffer[i][0];
|
||||||
|
mean[1] += buffer[i][1];
|
||||||
|
mean[2] += buffer[i][2];
|
||||||
|
}
|
||||||
|
mean[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 2. 计算方差
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
variance[0] += (buffer[i][0] - mean[0]) * (buffer[i][0] - mean[0]);
|
||||||
|
variance[1] += (buffer[i][1] - mean[1]) * (buffer[i][1] - mean[1]);
|
||||||
|
variance[2] += (buffer[i][2] - mean[2]) * (buffer[i][2] - mean[2]);
|
||||||
|
}
|
||||||
|
variance[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 返回三轴方差之和,作为一个综合的稳定度指标
|
||||||
|
return variance[0] + variance[1] + variance[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 升级后的状态机,包含旋转检测和动态零速更新
|
||||||
|
*/
|
||||||
|
static void update_state_machine(skiing_tracker_t *tracker, const float *acc_device_ms2, const float *gyr_dps)
|
||||||
|
{
|
||||||
|
// 缓冲区未填满时,不进行状态判断,默认为静止
|
||||||
|
if (!tracker->buffer_filled) {
|
||||||
|
tracker->state = SKIING_STATE_STATIC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 1. 计算关键指标 ---
|
||||||
|
float acc_variance = calculate_variance(tracker->acc_buffer); // 计算加速度方差
|
||||||
|
float gyr_variance = calculate_variance(tracker->gyr_buffer); // 计算陀螺仪方差
|
||||||
|
float gyr_magnitude = sqrtf(gyr_dps[0]*gyr_dps[0] + gyr_dps[1]*gyr_dps[1] + gyr_dps[2]*gyr_dps[2]);
|
||||||
|
float acc_magnitude = sqrtf(acc_device_ms2[0]*acc_device_ms2[0] + acc_device_ms2[1]*acc_device_ms2[1] + acc_device_ms2[2]*acc_device_ms2[2]);
|
||||||
|
|
||||||
|
// --- 2. 状态切换逻辑 (按优先级) ---
|
||||||
|
|
||||||
|
// 优先级1:原地旋转/摆动检测 (最终版)
|
||||||
|
// 增加一个关键前提:只在当前不处于滑雪状态时,才检测原地旋转。
|
||||||
|
// 这可以防止滑雪过程中的高速转弯被误判为原地旋转。
|
||||||
|
if (gyr_magnitude > ROTATION_GYR_MAG_THRESHOLD && tracker->state != SKIING_STATE_SKIING) {
|
||||||
|
tracker->state = SKIING_STATE_ROTATING;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态零速更新 (ZUPT)
|
||||||
|
// 必须同时满足加速度和角速度都稳定,才能判断为“真静止”,以区分匀速运动
|
||||||
|
if (acc_variance < ZUPT_ACC_VARIANCE_THRESHOLD && gyr_variance < ZUPT_GYR_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = SKIING_STATE_STATIC;
|
||||||
|
// 速度清零,抑制漂移
|
||||||
|
memset(tracker->velocity, 0, sizeof(tracker->velocity));
|
||||||
|
tracker->speed = 0.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从静止/旋转状态启动
|
||||||
|
if (tracker->state == SKIING_STATE_STATIC || tracker->state == SKIING_STATE_ROTATING) {
|
||||||
|
// 最终版启动逻辑:必须同时满足“有足够大的线性加速度”和“旋转稳定”两个条件
|
||||||
|
if (fabsf(acc_magnitude - G_ACCELERATION) > START_SKIING_ACC_THRESHOLD && gyr_variance < ZUPT_GYR_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = SKIING_STATE_SKIING;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 滑雪
|
||||||
|
if (tracker->state != SKIING_STATE_STATIC) {
|
||||||
|
tracker->state = SKIING_STATE_SKIING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 主更新函数
|
||||||
|
*/
|
||||||
|
void skiing_tracker_update(skiing_tracker_t *tracker, float *acc_g, float *gyr_dps, float *angle, float dt)
|
||||||
|
{
|
||||||
|
if (!tracker || !acc_g || !gyr_dps || !angle || dt <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 1. 数据预处理和缓冲 ---
|
||||||
|
float acc_device_ms2[3];
|
||||||
|
acc_device_ms2[0] = acc_g[0] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[1] = acc_g[1] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[2] = acc_g[2] * G_ACCELERATION;
|
||||||
|
|
||||||
|
// 将最新数据存入缓冲区
|
||||||
|
memcpy(tracker->acc_buffer[tracker->buffer_index], acc_device_ms2, sizeof(acc_device_ms2));
|
||||||
|
memcpy(tracker->gyr_buffer[tracker->buffer_index], gyr_dps, 3 * sizeof(float));
|
||||||
|
|
||||||
|
tracker->buffer_index++;
|
||||||
|
if (tracker->buffer_index >= VARIANCE_BUFFER_SIZE) {
|
||||||
|
tracker->buffer_index = 0;
|
||||||
|
tracker->buffer_filled = 1; // 标记缓冲区已满
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 2. 更新状态机 ---
|
||||||
|
update_state_machine(tracker, acc_device_ms2, gyr_dps);
|
||||||
|
|
||||||
|
// --- 3. 根据状态进行计算 ---
|
||||||
|
// 只有在明确的“滑雪”状态下才进行积分
|
||||||
|
if (tracker->state == SKIING_STATE_SKIING) {
|
||||||
|
transform_acc_to_world_frame(acc_device_ms2, angle, tracker->acc_world);
|
||||||
|
tracker->acc_world[2] -= G_ACCELERATION;
|
||||||
|
|
||||||
|
tracker->velocity[0] += tracker->acc_world[0] * dt;
|
||||||
|
tracker->velocity[1] += tracker->acc_world[1] * dt;
|
||||||
|
tracker->velocity[2] += tracker->acc_world[2] * dt;
|
||||||
|
}
|
||||||
|
// 在其他状态下(静止、旋转),速度已经在状态机内部被清零或保持不变
|
||||||
|
|
||||||
|
// --- 4. 引入速度阻尼(软件摩擦力) ---
|
||||||
|
// 只要不处于滑雪状态,就对速度进行衰减,以对抗漂移和抑制抖动产生的微小速度
|
||||||
|
if (tracker->state != SKIING_STATE_SKIING) {
|
||||||
|
tracker->velocity[0] *= VELOCITY_DAMPING_FACTOR;
|
||||||
|
tracker->velocity[1] *= VELOCITY_DAMPING_FACTOR;
|
||||||
|
tracker->velocity[2] *= VELOCITY_DAMPING_FACTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 5. 更新速率和距离 ---
|
||||||
|
tracker->speed = sqrtf(tracker->velocity[0] * tracker->velocity[0] +
|
||||||
|
tracker->velocity[1] * tracker->velocity[1] +
|
||||||
|
tracker->velocity[2] * tracker->velocity[2]);
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 传感器数据采集与处理任务
|
||||||
|
void sensor_processing_task(signed short * acc_data_buf, signed short * gyr_data_buf) {
|
||||||
|
static skiing_tracker_t my_skiing_tracker;
|
||||||
|
static int initialized = 0;
|
||||||
|
static int calibration_done = 0;
|
||||||
|
|
||||||
|
static signed short combined_raw_data[6];
|
||||||
|
static float final_angle_data[3]; // 计算得到的欧若拉角
|
||||||
|
static float calibrated_acc_g[3]; // 转换后的加速度计数据
|
||||||
|
static float calibrated_gyr_dps[3]; // 转换后的陀螺仪数据
|
||||||
|
|
||||||
|
const float delta_time = 0.01f;
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
skiing_tracker_init(&my_skiing_tracker);
|
||||||
|
initialized = 1;
|
||||||
|
printf("Skiing Tracker Initialized. Waiting for sensor calibration...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&combined_raw_data[0], acc_data_buf, 3 * sizeof(signed short));
|
||||||
|
memcpy(&combined_raw_data[3], gyr_data_buf, 3 * sizeof(signed short));
|
||||||
|
|
||||||
|
unsigned char status;
|
||||||
|
if (!calibration_done) { //第1次启动,开启零漂检测
|
||||||
|
status = SL_SC7U22_Angle_Output(1, combined_raw_data, final_angle_data, 0);
|
||||||
|
if (status == 1) {
|
||||||
|
calibration_done = 1;
|
||||||
|
printf("Sensor calibration successful! Skiing mode is active.\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status = SL_SC7U22_Angle_Output(0, combined_raw_data, final_angle_data, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == 1) {
|
||||||
|
// 加速度 LSB to g
|
||||||
|
calibrated_acc_g[0] = (float)combined_raw_data[0] / 8192.0f;
|
||||||
|
calibrated_acc_g[1] = (float)combined_raw_data[1] / 8192.0f;
|
||||||
|
calibrated_acc_g[2] = (float)combined_raw_data[2] / 8192.0f;
|
||||||
|
|
||||||
|
// 陀螺仪 LSB to dps (度/秒)
|
||||||
|
// ±2000dps量程下,转换系数约为 0.061
|
||||||
|
calibrated_gyr_dps[0] = (float)combined_raw_data[3] * 0.061f;
|
||||||
|
calibrated_gyr_dps[1] = (float)combined_raw_data[4] * 0.061f;
|
||||||
|
calibrated_gyr_dps[2] = (float)combined_raw_data[5] * 0.061f;
|
||||||
|
|
||||||
|
skiing_tracker_update(&my_skiing_tracker, calibrated_acc_g, calibrated_gyr_dps, final_angle_data, delta_time);
|
||||||
|
|
||||||
|
// 打印逻辑保持不变
|
||||||
|
static int count = 0;
|
||||||
|
if(count < 10){
|
||||||
|
count++;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
printf("State: %d, Speed: %.2f m/s, Distance: %.2f m\n",
|
||||||
|
my_skiing_tracker.state,
|
||||||
|
my_skiing_tracker.speed,
|
||||||
|
my_skiing_tracker.distance);
|
||||||
|
|
||||||
|
} else if (status == 0) {
|
||||||
|
// printf("Sensor is calibrating...\n");
|
||||||
|
} else {
|
||||||
|
// printf("Angle calculation error or calibration not finished.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
50
apps/earphone/xtell_Sensor/A_hide/3/skiing_tracker.h
Normal file
50
apps/earphone/xtell_Sensor/A_hide/3/skiing_tracker.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#ifndef SKIING_TRACKER_H
|
||||||
|
#define SKIING_TRACKER_H
|
||||||
|
|
||||||
|
// 定义滑雪者可能的状态
|
||||||
|
typedef enum {
|
||||||
|
SKIING_STATE_STATIC, // 静止或动态稳定
|
||||||
|
SKIING_STATE_SKIING, // 正在滑雪
|
||||||
|
SKIING_STATE_ROTATING, // 正在原地旋转 (新增)
|
||||||
|
SKIING_STATE_FALLEN, // 已摔倒
|
||||||
|
SKIING_STATE_UNKNOWN // 未知状态
|
||||||
|
} skiing_state_t;
|
||||||
|
|
||||||
|
#define VARIANCE_BUFFER_SIZE 15 // 用于计算方差的数据窗口大小 (15个样本 @ 100Hz = 150ms)
|
||||||
|
|
||||||
|
// 追踪器数据结构体
|
||||||
|
typedef struct {
|
||||||
|
// 公开数据
|
||||||
|
float velocity[3]; // 当前速度 (x, y, z),单位: m/s
|
||||||
|
float distance; // 总滑行距离,单位: m
|
||||||
|
float speed; // 当前速率 (标量),单位: m/s
|
||||||
|
skiing_state_t state; // 当前滑雪状态
|
||||||
|
|
||||||
|
// 内部计算使用的私有成员
|
||||||
|
float acc_world[3]; // 在世界坐标系下的加速度
|
||||||
|
|
||||||
|
// 用于动态零速更新和旋转检测的缓冲区
|
||||||
|
float acc_buffer[VARIANCE_BUFFER_SIZE][3]; // 加速度数据窗口
|
||||||
|
float gyr_buffer[VARIANCE_BUFFER_SIZE][3]; // 角速度数据窗口
|
||||||
|
int buffer_index; // 缓冲区当前索引
|
||||||
|
int buffer_filled; // 缓冲区是否已填满的标志
|
||||||
|
} skiing_tracker_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker 指向 skiing_tracker_t 结构体的指针
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 处理传感器数据并更新滑雪状态
|
||||||
|
*
|
||||||
|
* @param tracker 指向 skiing_tracker_t 结构体的指针
|
||||||
|
* @param acc_g 校准后的加速度数据 [x, y, z],单位: g (1g = 9.8m/s^2)
|
||||||
|
* @param gyr_dps 角速度
|
||||||
|
* @param angle 姿态角数据 [pitch, roll, yaw],单位: 度
|
||||||
|
* @param dt 采样时间间隔,单位: 秒 (s)
|
||||||
|
*/
|
||||||
|
void skiing_tracker_update(skiing_tracker_t *tracker, float *acc_g, float *gyr_dps, float *angle, float dt);
|
||||||
|
#endif // SKIING_TRACKER_H
|
||||||
465
apps/earphone/xtell_Sensor/A_hide/4/skiing_tracker.c
Normal file
465
apps/earphone/xtell_Sensor/A_hide/4/skiing_tracker.c
Normal file
@ -0,0 +1,465 @@
|
|||||||
|
/**
|
||||||
|
* 效果不行,对原地转动太灵敏了
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "skiing_tracker.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// --- 核心算法参数 ---
|
||||||
|
#define COMPLEMENTARY_FILTER_ALPHA 0.96f // 互补滤波器alpha值 (降低alpha, 增加对加速度计的信任, 更好地抑制陀螺仪漂移)
|
||||||
|
#define ACC_SENSITIVITY 8192.0f // 加速度计灵敏度 (LSB/g), 对应 ±4g 量程
|
||||||
|
#define GYRO_SENSITIVITY 16.4f // 陀螺仪灵敏度 (LSB/dps), 对应 ±2000dps 量程
|
||||||
|
#define SKI_DT_FIXED 0.01f // 固定时间间隔 10ms (100Hz)
|
||||||
|
|
||||||
|
// --- 状态机和阈值 ---
|
||||||
|
#define SKI_STATIC_THRESHOLD_ACC 0.3f // 静止检测加速度阈值 (m/s^2) - 提高以忽略更多噪声
|
||||||
|
#define SKI_STATIC_THRESHOLD_GYRO 3.0f // 静止检测角速度阈值 (dps) - 更严格
|
||||||
|
#define SKI_MOVEMENT_THRESHOLD 1.2f // 运动启动阈值 (m/s^2) - 显著提高,需要更明确的运动意图
|
||||||
|
#define SKI_WINDOW_SIZE 10 // 滑动窗口大小 (当前未使用)
|
||||||
|
#define SKI_CALIBRATION_SAMPLES 100 // 校准采样点数 (恢复到100,确保校准精度)
|
||||||
|
|
||||||
|
|
||||||
|
// 滑雪数据结构
|
||||||
|
typedef struct {
|
||||||
|
// 状态相关
|
||||||
|
SkiState_t current_state;
|
||||||
|
uint32_t state_duration; // 状态持续时间(ms)
|
||||||
|
uint8_t static_counter; // 静态计数器
|
||||||
|
|
||||||
|
// --- 核心运动数据 ---
|
||||||
|
// 姿态数据 (Roll, Pitch)
|
||||||
|
float attitude[2];
|
||||||
|
// 世界坐标系下的加速度
|
||||||
|
float world_acc[3];
|
||||||
|
// 世界坐标系下的速度
|
||||||
|
float velocity[3];
|
||||||
|
// 水平面速度和总距离
|
||||||
|
float horizontal_speed;
|
||||||
|
float total_horizontal_distance;
|
||||||
|
|
||||||
|
// 历史数据 (用于滤波)
|
||||||
|
float acc_history[SKI_WINDOW_SIZE][3];
|
||||||
|
float gyro_history[SKI_WINDOW_SIZE][3];
|
||||||
|
uint8_t history_index;
|
||||||
|
|
||||||
|
// 时间相关
|
||||||
|
float dt; // 时间间隔
|
||||||
|
|
||||||
|
// 运动检测
|
||||||
|
float movement_score; // 运动评分
|
||||||
|
float turning_score; // 转弯评分
|
||||||
|
|
||||||
|
// 校准数据 (用于陀螺仪零偏)
|
||||||
|
float gyro_bias[3];
|
||||||
|
float acc_bias[3];
|
||||||
|
float calibration_sum[6];
|
||||||
|
uint32_t calibration_count;
|
||||||
|
uint8_t calibrated;
|
||||||
|
|
||||||
|
// 状态标志和计数器
|
||||||
|
uint32_t update_count;
|
||||||
|
float velocity_decay_factor;
|
||||||
|
uint8_t is_moving;
|
||||||
|
|
||||||
|
} SkiData_t;
|
||||||
|
|
||||||
|
static SkiData_t ski_data = {0};
|
||||||
|
|
||||||
|
// --- 内部核心函数声明 ---
|
||||||
|
// 校准
|
||||||
|
static void Ski_CalibrateSensor(float *acc, float *gyro); // 校准传感器
|
||||||
|
// 姿态解算
|
||||||
|
static void Ski_UpdateAttitude(float *acc, float *gyro); // 更新姿态
|
||||||
|
// 坐标系转换
|
||||||
|
static void Ski_TransformToWorldFrame(float *acc, float *world_acc); // 转换到世界坐标系
|
||||||
|
// 速度与距离积分
|
||||||
|
static void Ski_UpdateVelocityAndDistance(void); // 更新速度和距离
|
||||||
|
|
||||||
|
// --- 辅助函数声明 ---
|
||||||
|
static float Ski_CalculateMovementScore(void); // 计算运动评分
|
||||||
|
static float Ski_CalculateTurningScore(float *gyro);
|
||||||
|
static void Ski_UpdateStateMachine(void);
|
||||||
|
static void Ski_MovingAverageFilter(float *new_acc, float *new_gyro, float *acc_filtered, float *gyro_filtered);
|
||||||
|
|
||||||
|
// 修改初始化函数
|
||||||
|
void Ski_Init(void)
|
||||||
|
{
|
||||||
|
memset(&ski_data, 0, sizeof(SkiData_t));
|
||||||
|
ski_data.current_state = SKI_STATE_STATIC;
|
||||||
|
|
||||||
|
// 初始化参数
|
||||||
|
ski_data.velocity_decay_factor = 0.8f; // 速度衰减因子
|
||||||
|
ski_data.is_moving = 0;
|
||||||
|
ski_data.update_count = 0;
|
||||||
|
ski_data.dt = SKI_DT_FIXED;
|
||||||
|
}
|
||||||
|
// 滑动窗口滤波
|
||||||
|
static void Ski_MovingAverageFilter(float *new_acc, float *new_gyro,
|
||||||
|
float *acc_filtered, float *gyro_filtered)
|
||||||
|
{
|
||||||
|
// 更新历史数据
|
||||||
|
ski_data.acc_history[ski_data.history_index][0] = new_acc[0];
|
||||||
|
ski_data.acc_history[ski_data.history_index][1] = new_acc[1];
|
||||||
|
ski_data.acc_history[ski_data.history_index][2] = new_acc[2];
|
||||||
|
|
||||||
|
ski_data.gyro_history[ski_data.history_index][0] = new_gyro[0];
|
||||||
|
ski_data.gyro_history[ski_data.history_index][1] = new_gyro[1];
|
||||||
|
ski_data.gyro_history[ski_data.history_index][2] = new_gyro[2];
|
||||||
|
|
||||||
|
ski_data.history_index = (ski_data.history_index + 1) % SKI_WINDOW_SIZE;
|
||||||
|
|
||||||
|
// 计算平均值
|
||||||
|
memset(acc_filtered, 0, 3 * sizeof(float));
|
||||||
|
memset(gyro_filtered, 0, 3 * sizeof(float));
|
||||||
|
|
||||||
|
for (int i = 0; i < SKI_WINDOW_SIZE; i++) {
|
||||||
|
acc_filtered[0] += ski_data.acc_history[i][0];
|
||||||
|
acc_filtered[1] += ski_data.acc_history[i][1];
|
||||||
|
acc_filtered[2] += ski_data.acc_history[i][2];
|
||||||
|
|
||||||
|
gyro_filtered[0] += ski_data.gyro_history[i][0];
|
||||||
|
gyro_filtered[1] += ski_data.gyro_history[i][1];
|
||||||
|
gyro_filtered[2] += ski_data.gyro_history[i][2];
|
||||||
|
}
|
||||||
|
|
||||||
|
acc_filtered[0] /= SKI_WINDOW_SIZE;
|
||||||
|
acc_filtered[1] /= SKI_WINDOW_SIZE;
|
||||||
|
acc_filtered[2] /= SKI_WINDOW_SIZE;
|
||||||
|
|
||||||
|
gyro_filtered[0] /= SKI_WINDOW_SIZE;
|
||||||
|
gyro_filtered[1] /= SKI_WINDOW_SIZE;
|
||||||
|
gyro_filtered[2] /= SKI_WINDOW_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =================================================================================
|
||||||
|
// 核心更新函数 - 已重构
|
||||||
|
// =================================================================================
|
||||||
|
void Ski_UpdateData(int16_t acc_x, int16_t acc_y, int16_t acc_z,
|
||||||
|
int16_t gyro_x, int16_t gyro_y, int16_t gyro_z)
|
||||||
|
{
|
||||||
|
ski_data.update_count++;
|
||||||
|
|
||||||
|
// 1. LSB原始数据转换为物理单位 (g 和 度/秒)
|
||||||
|
float acc[3] = { (float)acc_x / ACC_SENSITIVITY, (float)acc_y / ACC_SENSITIVITY, (float)acc_z / ACC_SENSITIVITY };
|
||||||
|
float gyro[3] = { (float)gyro_x / GYRO_SENSITIVITY, (float)gyro_y / GYRO_SENSITIVITY, (float)gyro_z / GYRO_SENSITIVITY };
|
||||||
|
|
||||||
|
// 2. 传感器校准 (移除零偏)
|
||||||
|
if (!ski_data.calibrated) {
|
||||||
|
Ski_CalibrateSensor(acc, gyro);
|
||||||
|
return; // 等待校准完成
|
||||||
|
}
|
||||||
|
acc[0] -= ski_data.acc_bias[0];
|
||||||
|
acc[1] -= ski_data.acc_bias[1];
|
||||||
|
acc[2] -= ski_data.acc_bias[2];
|
||||||
|
gyro[0] -= ski_data.gyro_bias[0];
|
||||||
|
gyro[1] -= ski_data.gyro_bias[1];
|
||||||
|
gyro[2] -= ski_data.gyro_bias[2];
|
||||||
|
|
||||||
|
// 3. 姿态解算 (互补滤波器)
|
||||||
|
Ski_UpdateAttitude(acc, gyro);
|
||||||
|
|
||||||
|
// 4. 将身体坐标系的加速度转换为世界坐标系
|
||||||
|
Ski_TransformToWorldFrame(acc, ski_data.world_acc);
|
||||||
|
|
||||||
|
// 5. 在世界坐标系中移除重力 (重力永远是 [0, 0, 1]g)
|
||||||
|
ski_data.world_acc[2] -= 1.0f;
|
||||||
|
|
||||||
|
// 6. 对世界坐标系下的加速度进行滤波 (可选,但推荐)
|
||||||
|
// 注意: 如果需要,可在此处重用滑动平均滤波器,但暂时我们直接使用原始世界坐标系加速度
|
||||||
|
|
||||||
|
// 7. 基于世界坐标系的数据更新状态机
|
||||||
|
Ski_UpdateStateMachine();
|
||||||
|
|
||||||
|
// 8. 基于世界坐标系的数据更新速度和距离
|
||||||
|
Ski_UpdateVelocityAndDistance();
|
||||||
|
}
|
||||||
|
// 计算转弯评分
|
||||||
|
static float Ski_CalculateTurningScore(float *gyro)
|
||||||
|
{
|
||||||
|
// 主要考虑Z轴旋转(偏航)和X轴旋转(俯仰)
|
||||||
|
float turning_score = fabsf(gyro[2]) * 0.6f + fabsf(gyro[0]) * 0.4f;
|
||||||
|
return turning_score;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =================================================================================
|
||||||
|
// 新增核心算法函数
|
||||||
|
// =================================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 在静止状态下计算传感器零偏
|
||||||
|
*/
|
||||||
|
static void Ski_CalibrateSensor(float *acc, float *gyro)
|
||||||
|
{
|
||||||
|
float acc_mag = sqrtf(acc[0]*acc[0] + acc[1]*acc[1] + acc[2]*acc[2]);
|
||||||
|
float gyro_mag = sqrtf(gyro[0]*gyro[0] + gyro[1]*gyro[1] + gyro[2]*gyro[2]);
|
||||||
|
|
||||||
|
// 放宽静止判断条件,使其更容易满足
|
||||||
|
if (fabsf(acc_mag - 1.0f) < 0.1f && gyro_mag < SKI_STATIC_THRESHOLD_GYRO) {
|
||||||
|
ski_data.calibration_sum[0] += acc[0];
|
||||||
|
ski_data.calibration_sum[1] += acc[1];
|
||||||
|
ski_data.calibration_sum[2] += acc[2];
|
||||||
|
ski_data.calibration_sum[3] += gyro[0];
|
||||||
|
ski_data.calibration_sum[4] += gyro[1];
|
||||||
|
ski_data.calibration_sum[5] += gyro[2];
|
||||||
|
ski_data.calibration_count++;
|
||||||
|
|
||||||
|
if (ski_data.calibration_count >= SKI_CALIBRATION_SAMPLES) {
|
||||||
|
// 计算加速度计零偏
|
||||||
|
ski_data.acc_bias[0] = ski_data.calibration_sum[0] / ski_data.calibration_count;
|
||||||
|
ski_data.acc_bias[1] = ski_data.calibration_sum[1] / ski_data.calibration_count;
|
||||||
|
// Z轴的零偏是相对于1g的, 需要找到重力轴
|
||||||
|
float gravity_mag = sqrtf(powf(ski_data.calibration_sum[0] / ski_data.calibration_count, 2) +
|
||||||
|
powf(ski_data.calibration_sum[1] / ski_data.calibration_count, 2) +
|
||||||
|
powf(ski_data.calibration_sum[2] / ski_data.calibration_count, 2));
|
||||||
|
ski_data.acc_bias[2] = ski_data.calibration_sum[2] / ski_data.calibration_count - gravity_mag;
|
||||||
|
|
||||||
|
|
||||||
|
// 计算陀螺仪零偏
|
||||||
|
ski_data.gyro_bias[0] = ski_data.calibration_sum[3] / ski_data.calibration_count;
|
||||||
|
ski_data.gyro_bias[1] = ski_data.calibration_sum[4] / ski_data.calibration_count;
|
||||||
|
ski_data.gyro_bias[2] = ski_data.calibration_sum[5] / ski_data.calibration_count;
|
||||||
|
|
||||||
|
ski_data.calibrated = 1;
|
||||||
|
printf("传感器校准完成!\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果检测到移动,则重置校准计数
|
||||||
|
ski_data.calibration_count = 0;
|
||||||
|
memset(ski_data.calibration_sum, 0, sizeof(ski_data.calibration_sum));
|
||||||
|
// 增加调试打印,方便定位问题
|
||||||
|
// printf("Calibration reset. Acc mag: %.3f, Gyro mag: %.3f\n", acc_mag, gyro_mag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 使用互补滤波器更新姿态角(Roll, Pitch)
|
||||||
|
*/
|
||||||
|
static void Ski_UpdateAttitude(float *acc, float *gyro)
|
||||||
|
{
|
||||||
|
float dt = ski_data.dt;
|
||||||
|
float alpha = COMPLEMENTARY_FILTER_ALPHA;
|
||||||
|
|
||||||
|
// 从加速度计计算角度 (单位: 度)
|
||||||
|
float roll_acc = atan2f(acc[1], acc[2]) * 180.0f / M_PI;
|
||||||
|
float pitch_acc = atan2f(-acc[0], sqrtf(acc[1] * acc[1] + acc[2] * acc[2])) * 180.0f / M_PI;
|
||||||
|
|
||||||
|
// 陀螺仪积分预测角度
|
||||||
|
// 注意: 这里的gyro单位是 度/秒
|
||||||
|
float roll_gyro = ski_data.attitude[0] + gyro[0] * dt;
|
||||||
|
float pitch_gyro = ski_data.attitude[1] + gyro[1] * dt;
|
||||||
|
|
||||||
|
// 互补滤波融合
|
||||||
|
ski_data.attitude[0] = alpha * roll_gyro + (1.0f - alpha) * roll_acc;
|
||||||
|
ski_data.attitude[1] = alpha * pitch_gyro + (1.0f - alpha) * pitch_acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 将身体坐标系的加速度转换为世界坐标系
|
||||||
|
*/
|
||||||
|
static void Ski_TransformToWorldFrame(float *acc, float *world_acc)
|
||||||
|
{
|
||||||
|
// 将姿态角转换为弧度
|
||||||
|
float roll = ski_data.attitude[0] * M_PI / 180.0f;
|
||||||
|
float pitch = ski_data.attitude[1] * M_PI / 180.0f;
|
||||||
|
|
||||||
|
float cos_roll = cosf(roll);
|
||||||
|
float sin_roll = sinf(roll);
|
||||||
|
float cos_pitch = cosf(pitch);
|
||||||
|
float sin_pitch = sinf(pitch);
|
||||||
|
|
||||||
|
// 通过旋转矩阵将身体坐标系的加速度(acc)转换到世界坐标系(world_acc)
|
||||||
|
// (简化版,假设偏航角yaw=0)
|
||||||
|
world_acc[0] = acc[0] * cos_pitch + acc[2] * sin_pitch;
|
||||||
|
world_acc[1] = acc[0] * sin_pitch * sin_roll + acc[1] * cos_roll - acc[2] * cos_pitch * sin_roll;
|
||||||
|
world_acc[2] = -acc[0] * sin_pitch * cos_roll + acc[1] * sin_roll + acc[2] * cos_pitch * cos_roll;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 改进的运动评分计算
|
||||||
|
static float Ski_CalculateMovementScore(void)
|
||||||
|
{
|
||||||
|
// 在世界坐标系下计算运动评分,只考虑水平加速度
|
||||||
|
float horizontal_acc_mag = sqrtf(ski_data.world_acc[0]*ski_data.world_acc[0] + ski_data.world_acc[1]*ski_data.world_acc[1]);
|
||||||
|
return horizontal_acc_mag * 9.81f; // 从 g 转换为 m/s^2
|
||||||
|
}
|
||||||
|
|
||||||
|
// 改进的状态机 - 添加更严格的转换条件
|
||||||
|
/**
|
||||||
|
* @brief 基于世界坐标系下的加速度更新状态机
|
||||||
|
*/
|
||||||
|
static void Ski_UpdateStateMachine(void)
|
||||||
|
{
|
||||||
|
ski_data.state_duration++;
|
||||||
|
ski_data.movement_score = Ski_CalculateMovementScore();
|
||||||
|
|
||||||
|
switch (ski_data.current_state) {
|
||||||
|
case SKI_STATE_STATIC:
|
||||||
|
if (ski_data.movement_score > SKI_MOVEMENT_THRESHOLD) {
|
||||||
|
ski_data.static_counter++;
|
||||||
|
if (ski_data.static_counter > 5) { // 需要连续几帧的运动才切换
|
||||||
|
ski_data.current_state = SKI_STATE_MOVING;
|
||||||
|
ski_data.is_moving = 1;
|
||||||
|
ski_data.state_duration = 0;
|
||||||
|
ski_data.static_counter = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ski_data.static_counter = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKI_STATE_MOVING:
|
||||||
|
// 使用更低的阈值来检测停止,形成迟滞效应,防止状态抖动
|
||||||
|
if (ski_data.movement_score < SKI_STATIC_THRESHOLD_ACC) {
|
||||||
|
ski_data.static_counter++;
|
||||||
|
if (ski_data.static_counter > 8) { // 减少进入静止状态的等待时间
|
||||||
|
ski_data.current_state = SKI_STATE_STATIC;
|
||||||
|
ski_data.is_moving = 0;
|
||||||
|
ski_data.state_duration = 0;
|
||||||
|
ski_data.static_counter = 0;
|
||||||
|
// 停止时强制将速度清零,以防止漂移
|
||||||
|
memset(ski_data.velocity, 0, sizeof(ski_data.velocity));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ski_data.static_counter = 0;
|
||||||
|
}
|
||||||
|
// TODO: 如果需要,可以增加转弯状态的检测
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 如果需要,可以增加其他状态 (例如 TURNING, STOPPING)
|
||||||
|
default:
|
||||||
|
ski_data.current_state = SKI_STATE_STATIC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 改进的速度和距离更新 - 添加零速度更新(ZUPT)
|
||||||
|
/**
|
||||||
|
* @brief 在世界坐标系下更新速度和距离
|
||||||
|
*/
|
||||||
|
static void Ski_UpdateVelocityAndDistance(void)
|
||||||
|
{
|
||||||
|
// 将世界坐标系下的加速度从 g 转换为 m/s^2
|
||||||
|
float acc_ms2[3];
|
||||||
|
acc_ms2[0] = ski_data.world_acc[0] * 9.81f;
|
||||||
|
acc_ms2[1] = ski_data.world_acc[1] * 9.81f;
|
||||||
|
acc_ms2[2] = ski_data.world_acc[2] * 9.81f;
|
||||||
|
|
||||||
|
// 是否进行积分的决定由状态机控制
|
||||||
|
if (ski_data.is_moving) {
|
||||||
|
// 速度积分
|
||||||
|
ski_data.velocity[0] += acc_ms2[0] * ski_data.dt;
|
||||||
|
ski_data.velocity[1] += acc_ms2[1] * ski_data.dt;
|
||||||
|
// 如果需要,也可以对垂直速度进行积分
|
||||||
|
// ski_data.velocity[2] += acc_ms2[2] * ski_data.dt;
|
||||||
|
|
||||||
|
// 通过累加每一步的位移来计算总距离
|
||||||
|
float distance_step = sqrtf(
|
||||||
|
(ski_data.velocity[0] * ski_data.dt) * (ski_data.velocity[0] * ski_data.dt) +
|
||||||
|
(ski_data.velocity[1] * ski_data.dt) * (ski_data.velocity[1] * ski_data.dt)
|
||||||
|
);
|
||||||
|
ski_data.total_horizontal_distance += distance_step;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// 当静止时,对速度进行衰减
|
||||||
|
ski_data.velocity[0] *= ski_data.velocity_decay_factor;
|
||||||
|
ski_data.velocity[1] *= ski_data.velocity_decay_factor;
|
||||||
|
ski_data.velocity[2] *= ski_data.velocity_decay_factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新当前水平速度
|
||||||
|
ski_data.horizontal_speed = sqrtf(ski_data.velocity[0]*ski_data.velocity[0] + ski_data.velocity[1]*ski_data.velocity[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 获取当前速度 (m/s)
|
||||||
|
float Ski_GetSpeed(void)
|
||||||
|
{
|
||||||
|
return ski_data.horizontal_speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取总移动距离 (m)
|
||||||
|
float Ski_GetDistance(void)
|
||||||
|
{
|
||||||
|
return ski_data.total_horizontal_distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前状态
|
||||||
|
SkiState_t Ski_GetState(void)
|
||||||
|
{
|
||||||
|
return ski_data.current_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置距离计数
|
||||||
|
void Ski_ResetDistance(void)
|
||||||
|
{
|
||||||
|
ski_data.total_horizontal_distance = 0;
|
||||||
|
// 速度也应该一起重置
|
||||||
|
memset(ski_data.velocity, 0, sizeof(ski_data.velocity));
|
||||||
|
ski_data.horizontal_speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取校准状态
|
||||||
|
uint8_t Ski_IsCalibrated(void)
|
||||||
|
{
|
||||||
|
return ski_data.calibrated;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手动设置重力向量
|
||||||
|
// 这个函数不再需要,将被姿态估计算法取代
|
||||||
|
/*
|
||||||
|
void Ski_SetGravityVector(float gx, float gy, float gz)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// 添加调试信息函数
|
||||||
|
void Ski_PrintDebugInfo(void)
|
||||||
|
{
|
||||||
|
printf("State: %d, MoveScore: %.2f, Speed: %.3f, Dist: %.3f, Roll: %.2f, Pitch: %.2f\n",
|
||||||
|
ski_data.current_state, ski_data.movement_score, ski_data.horizontal_speed, ski_data.total_horizontal_distance,
|
||||||
|
ski_data.attitude[0], ski_data.attitude[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sensor_processing_task(void){
|
||||||
|
static int first_init = 0;
|
||||||
|
if(!first_init){
|
||||||
|
Ski_Init();
|
||||||
|
first_init = 1;
|
||||||
|
}
|
||||||
|
static signed short acc_data[3], gyr_data[3];
|
||||||
|
static signed short combined_raw_data[6];
|
||||||
|
static float final_angle_data[3];
|
||||||
|
|
||||||
|
// 读取传感器数据
|
||||||
|
SL_SC7U22_RawData_Read(acc_data, gyr_data);
|
||||||
|
memcpy(&combined_raw_data[0], acc_data, 3 * sizeof(signed short));
|
||||||
|
memcpy(&combined_raw_data[3], gyr_data, 3 * sizeof(signed short));
|
||||||
|
|
||||||
|
// 校准逻辑已内置于Ski_UpdateData中,不再需要外部检查
|
||||||
|
// if(get_calibration_state() == 0){ ... }
|
||||||
|
|
||||||
|
// 更新滑雪数据
|
||||||
|
Ski_UpdateData(combined_raw_data[0], combined_raw_data[1], combined_raw_data[2],
|
||||||
|
combined_raw_data[3], combined_raw_data[4], combined_raw_data[5]);
|
||||||
|
|
||||||
|
static int count = 0;
|
||||||
|
if(count < 10){
|
||||||
|
count++;
|
||||||
|
return;
|
||||||
|
}else{
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印结果和调试信息
|
||||||
|
float speed = Ski_GetSpeed();
|
||||||
|
float distance = Ski_GetDistance();
|
||||||
|
SkiState_t state = Ski_GetState();
|
||||||
|
|
||||||
|
// printf("Speed: %.3f m/s, Distance: %.3f m, State: %d\n", speed, distance, state);
|
||||||
|
Ski_PrintDebugInfo();
|
||||||
|
}
|
||||||
40
apps/earphone/xtell_Sensor/A_hide/4/skiing_tracker.h
Normal file
40
apps/earphone/xtell_Sensor/A_hide/4/skiing_tracker.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef SKI_SPEED_DISTANCE_H
|
||||||
|
#define SKI_SPEED_DISTANCE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// 滑雪状态定义
|
||||||
|
typedef enum {
|
||||||
|
SKI_STATE_STATIC = 0, // 静止状态
|
||||||
|
SKI_STATE_STARTING, // 启动状态
|
||||||
|
SKI_STATE_MOVING, // 运动状态
|
||||||
|
SKI_STATE_TURNING, // 转弯状态
|
||||||
|
SKI_STATE_STOPPING // 停止状态
|
||||||
|
} SkiState_t;
|
||||||
|
|
||||||
|
// 初始化滑雪模块
|
||||||
|
void Ski_Init(void);
|
||||||
|
|
||||||
|
// 更新滑雪数据
|
||||||
|
void Ski_UpdateData(int16_t acc_x, int16_t acc_y, int16_t acc_z,
|
||||||
|
int16_t gyro_x, int16_t gyro_y, int16_t gyro_z);
|
||||||
|
|
||||||
|
// 获取当前速度 (m/s)
|
||||||
|
float Ski_GetSpeed(void);
|
||||||
|
|
||||||
|
// 获取总移动距离 (m)
|
||||||
|
float Ski_GetDistance(void);
|
||||||
|
|
||||||
|
// 获取当前状态
|
||||||
|
SkiState_t Ski_GetState(void);
|
||||||
|
|
||||||
|
// 重置距离计数
|
||||||
|
void Ski_ResetDistance(void);
|
||||||
|
|
||||||
|
// 获取校准状态
|
||||||
|
uint8_t Ski_IsCalibrated(void);
|
||||||
|
|
||||||
|
// 手动设置重力向量(可选)
|
||||||
|
void Ski_SetGravityVector(float gx, float gy, float gz);
|
||||||
|
|
||||||
|
#endif
|
||||||
311
apps/earphone/xtell_Sensor/A_hide/5/skiing_tracker.c
Normal file
311
apps/earphone/xtell_Sensor/A_hide/5/skiing_tracker.c
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
/*
|
||||||
|
动态ZUPT+卡尔曼
|
||||||
|
多了加速度死区、摩擦力速度衰减、高通滤波
|
||||||
|
原地摆动产生的速度、距离变化还是没法消除
|
||||||
|
水平移动、斜坡移动效果貌似还行
|
||||||
|
*/
|
||||||
|
#include "skiing_tracker.h"
|
||||||
|
#include "../sensor/SC7U22.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define G_ACCELERATION 9.81f
|
||||||
|
#define DEG_TO_RAD (3.14159265f / 180.0f)
|
||||||
|
|
||||||
|
// --- 算法阈值定义 ---
|
||||||
|
//两个判断是否静止的必要条件
|
||||||
|
// 动态零速更新(ZUPT)阈值
|
||||||
|
// 提高阈值,让“刹车”更灵敏,以便在波浪式前进等慢速漂移时也能触发零速更新
|
||||||
|
#define ZUPT_ACC_VARIANCE_THRESHOLD 0.2f
|
||||||
|
// 陀螺仪方差阈值
|
||||||
|
#define ZUPT_GYR_VARIANCE_THRESHOLD 5.0f
|
||||||
|
|
||||||
|
// 旋转/摆动检测阈值:角速度总模长大于此值(度/秒),认为正在进行非滑雪的旋转或摆动 -- 没法完全消除
|
||||||
|
#define ROTATION_GYR_MAG_THRESHOLD 45.0f
|
||||||
|
// 启动滑雪阈值:加速度模长与重力的差值大于此值,认为开始运动
|
||||||
|
// 降低阈值,让“油门”更灵敏,以便能捕捉到真实的慢速启动
|
||||||
|
#define START_SKIING_ACC_THRESHOLD 0.5f
|
||||||
|
|
||||||
|
// --- 用于消除积分漂移的滤波器和阈值 ---
|
||||||
|
// 高通滤波器系数 (alpha)。alpha 越接近1,滤除低频(直流偏移)的效果越强,但可能滤掉真实的慢速运动。
|
||||||
|
// alpha = RC / (RC + dt),
|
||||||
|
#define HPF_ALPHA 0.95f
|
||||||
|
// 加速度死区阈值 (m/s^2)。低于此阈值的加速度被认为是噪声,不参与积分。
|
||||||
|
// 设得太高会忽略真实的慢速启动,设得太低则无法有效抑制噪声。
|
||||||
|
#define ACC_DEAD_ZONE_THRESHOLD 0.1f
|
||||||
|
|
||||||
|
#define SPEED_ATTENUATION 0.98f //模拟摩擦力,进行速度衰减
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker)
|
||||||
|
{
|
||||||
|
if (!tracker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 使用memset一次性清零整个结构体,包括新增的缓冲区
|
||||||
|
memset(tracker, 0, sizeof(skiing_tracker_t));
|
||||||
|
tracker->state = SKIING_STATE_STATIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 将设备坐标系下的加速度转换为世界坐标系
|
||||||
|
* @param acc_device 设备坐标系下的加速度 [x, y, z]
|
||||||
|
* @param angle 姿态角 [pitch, roll, yaw],单位: 度
|
||||||
|
* @param acc_world 输出:世界坐标系下的加速度 [x, y, z]
|
||||||
|
*/
|
||||||
|
static void transform_acc_to_world_frame(const float *acc_device, const float *angle, float *acc_world)
|
||||||
|
{
|
||||||
|
// 驱动输出的角度与标准航空定义相反,需要取反才能用于标准旋转矩阵。
|
||||||
|
float pitch = -angle[0] * DEG_TO_RAD;
|
||||||
|
float roll = -angle[1] * DEG_TO_RAD;
|
||||||
|
|
||||||
|
// TODO: 当引入三轴磁力计后,这里的 yaw 应由磁力计和陀螺仪融合解算得出,以解决航向漂移问题。
|
||||||
|
// 目前 yaw 暂时不参与计算,因为仅靠加速度计和陀螺仪无法获得准确的绝对航向角。
|
||||||
|
// float yaw = -angle[2] * DEG_TO_RAD;
|
||||||
|
|
||||||
|
float cp = cosf(pitch);
|
||||||
|
float sp = sinf(pitch);
|
||||||
|
float cr = cosf(roll);
|
||||||
|
float sr = sinf(roll);
|
||||||
|
|
||||||
|
float ax = acc_device[0];
|
||||||
|
float ay = acc_device[1];
|
||||||
|
float az = acc_device[2];
|
||||||
|
|
||||||
|
// 使用经过验证的、正确的身体坐标系到世界坐标系的旋转矩阵 (基于 Y-X 旋转顺序)
|
||||||
|
// 这个矩阵将设备测量的加速度(ax, ay, az)正确地转换到世界坐标系(acc_world)。
|
||||||
|
// 注意:这里没有使用yaw,主要关心的是坡面上的运动,绝对航向暂时不影响速度和距离的计算。
|
||||||
|
// TODO
|
||||||
|
acc_world[0] = cp * ax + sp * sr * ay + sp * cr * az;
|
||||||
|
acc_world[1] = 0 * ax + cr * ay - sr * az;
|
||||||
|
acc_world[2] = -sp * ax + cp * sr * ay + cp * cr * az;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计算缓冲区内三轴数据的方差之和
|
||||||
|
*/
|
||||||
|
static float calculate_variance(float buffer[VARIANCE_BUFFER_SIZE][3])
|
||||||
|
{
|
||||||
|
float mean[3] = {0};
|
||||||
|
float variance[3] = {0};
|
||||||
|
|
||||||
|
// 1. 计算均值
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
mean[0] += buffer[i][0];
|
||||||
|
mean[1] += buffer[i][1];
|
||||||
|
mean[2] += buffer[i][2];
|
||||||
|
}
|
||||||
|
mean[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 2. 计算方差
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
variance[0] += (buffer[i][0] - mean[0]) * (buffer[i][0] - mean[0]);
|
||||||
|
variance[1] += (buffer[i][1] - mean[1]) * (buffer[i][1] - mean[1]);
|
||||||
|
variance[2] += (buffer[i][2] - mean[2]) * (buffer[i][2] - mean[2]);
|
||||||
|
}
|
||||||
|
variance[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 返回三轴方差之和,作为一个综合的稳定度指标
|
||||||
|
return variance[0] + variance[1] + variance[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 状态机更新
|
||||||
|
*/
|
||||||
|
static void update_state_machine(skiing_tracker_t *tracker, const float *acc_device_ms2, const float *gyr_dps)
|
||||||
|
{
|
||||||
|
// 缓冲区未填满时,不进行状态判断,默认为静止
|
||||||
|
if (!tracker->buffer_filled) {
|
||||||
|
tracker->state = SKIING_STATE_STATIC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 计算关键指标 ---
|
||||||
|
float acc_variance = calculate_variance(tracker->acc_buffer); // 计算加速度方差
|
||||||
|
float gyr_variance = calculate_variance(tracker->gyr_buffer); // 计算陀螺仪方差
|
||||||
|
float gyr_magnitude = sqrtf(gyr_dps[0]*gyr_dps[0] + gyr_dps[1]*gyr_dps[1] + gyr_dps[2]*gyr_dps[2]);
|
||||||
|
float acc_magnitude = sqrtf(acc_device_ms2[0]*acc_device_ms2[0] + acc_device_ms2[1]*acc_device_ms2[1] + acc_device_ms2[2]*acc_device_ms2[2]);
|
||||||
|
|
||||||
|
// --- 状态切换逻辑---
|
||||||
|
|
||||||
|
// 原地旋转/摆动检测
|
||||||
|
// 增加一个关键前提:只在当前不处于滑雪状态时,才检测原地旋转。
|
||||||
|
// 这可以防止滑雪过程中的高速转弯被误判为原地旋转。
|
||||||
|
// 暂时没办法完全消除
|
||||||
|
if (gyr_magnitude > ROTATION_GYR_MAG_THRESHOLD && tracker->state != SKIING_STATE_SKIING) {
|
||||||
|
tracker->state = SKIING_STATE_ROTATING;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态零速更新 (ZUPT)
|
||||||
|
// 必须同时满足加速度和角速度都稳定,才能判断为“真静止”,以区分匀速运动
|
||||||
|
if (acc_variance < ZUPT_ACC_VARIANCE_THRESHOLD && gyr_variance < ZUPT_GYR_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = SKIING_STATE_STATIC;
|
||||||
|
// 速度清零,抑制漂移
|
||||||
|
memset(tracker->velocity, 0, sizeof(tracker->velocity));
|
||||||
|
tracker->speed = 0.0f;
|
||||||
|
//当检测到静止时,必须重置高通滤波器的状态,否则下次启动时会有跳变
|
||||||
|
memset(tracker->acc_world_unfiltered_prev, 0, sizeof(tracker->acc_world_unfiltered_prev));
|
||||||
|
memset(tracker->acc_world_filtered, 0, sizeof(tracker->acc_world_filtered));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从静止/旋转状态启动
|
||||||
|
if (tracker->state == SKIING_STATE_STATIC || tracker->state == SKIING_STATE_ROTATING) {
|
||||||
|
// 最终版启动逻辑:必须同时满足“有足够大的线性加速度”和“旋转稳定”两个条件
|
||||||
|
if (fabsf(acc_magnitude - G_ACCELERATION) > START_SKIING_ACC_THRESHOLD && gyr_variance < ZUPT_GYR_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = SKIING_STATE_SKIING;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 滑雪
|
||||||
|
if (tracker->state != SKIING_STATE_STATIC) {
|
||||||
|
tracker->state = SKIING_STATE_SKIING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 主更新函数
|
||||||
|
*/
|
||||||
|
void skiing_tracker_update(skiing_tracker_t *tracker, float *acc_g, float *gyr_dps, float *angle, float dt)
|
||||||
|
{
|
||||||
|
if (!tracker || !acc_g || !gyr_dps || !angle || dt <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 数据预处理和缓冲 ---
|
||||||
|
float acc_device_ms2[3];
|
||||||
|
acc_device_ms2[0] = acc_g[0] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[1] = acc_g[1] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[2] = acc_g[2] * G_ACCELERATION;
|
||||||
|
|
||||||
|
// 将最新数据存入缓冲区
|
||||||
|
memcpy(tracker->acc_buffer[tracker->buffer_index], acc_device_ms2, sizeof(acc_device_ms2));
|
||||||
|
memcpy(tracker->gyr_buffer[tracker->buffer_index], gyr_dps, 3 * sizeof(float));
|
||||||
|
|
||||||
|
tracker->buffer_index++;
|
||||||
|
if (tracker->buffer_index >= VARIANCE_BUFFER_SIZE) {
|
||||||
|
tracker->buffer_index = 0;
|
||||||
|
tracker->buffer_filled = 1; // 标记缓冲区已满
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 更新状态机 ---
|
||||||
|
update_state_machine(tracker, acc_device_ms2, gyr_dps);
|
||||||
|
|
||||||
|
// --- 根据状态进行计算 ---
|
||||||
|
if (tracker->state == SKIING_STATE_SKIING) {
|
||||||
|
// 坐标转换 & 移除重力
|
||||||
|
transform_acc_to_world_frame(acc_device_ms2, angle, tracker->acc_world);
|
||||||
|
tracker->acc_world[2] -= G_ACCELERATION;
|
||||||
|
|
||||||
|
// 对世界坐标系下的加速度进行高通滤波,消除直流偏置和重力残差
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
tracker->acc_world_filtered[i] = HPF_ALPHA * (tracker->acc_world_filtered[i] + tracker->acc_world[i] - tracker->acc_world_unfiltered_prev[i]);
|
||||||
|
tracker->acc_world_unfiltered_prev[i] = tracker->acc_world[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用加速度死区,忽略微小抖动和噪声
|
||||||
|
float acc_horizontal_mag = sqrtf(tracker->acc_world_filtered[0] * tracker->acc_world_filtered[0] +
|
||||||
|
tracker->acc_world_filtered[1] * tracker->acc_world_filtered[1]);
|
||||||
|
|
||||||
|
if (acc_horizontal_mag > ACC_DEAD_ZONE_THRESHOLD) {
|
||||||
|
// 只有当水平加速度足够大时,才进行速度积分
|
||||||
|
tracker->velocity[0] += tracker->acc_world_filtered[0] * dt;
|
||||||
|
tracker->velocity[1] += tracker->acc_world_filtered[1] * dt;
|
||||||
|
// 垂直方向的速度暂时不积分,极易受姿态误差影响而漂移
|
||||||
|
// tracker->velocity[2] += tracker->acc_world_filtered[2] * dt;
|
||||||
|
}
|
||||||
|
// 如果加速度小于阈值,则不更新速度,相当于速度保持不变(或受下一步的阻尼影响而衰减)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// 在静止或旋转状态下,速度已经在状态机内部被清零
|
||||||
|
// 额外增加速度衰减,模拟摩擦力,进一步抑制漂移
|
||||||
|
tracker->velocity[0] *= SPEED_ATTENUATION;
|
||||||
|
tracker->velocity[1] *= SPEED_ATTENUATION;
|
||||||
|
tracker->velocity[2] = 0; // 垂直速度强制归零
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 更新速率和距离 ---
|
||||||
|
// 只基于水平速度计算速率和距离
|
||||||
|
tracker->speed = sqrtf(tracker->velocity[0] * tracker->velocity[0] +
|
||||||
|
tracker->velocity[1] * tracker->velocity[1]);
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 传感器数据采集与处理任务
|
||||||
|
void sensor_processing_task(signed short * acc_data_buf, signed short * gyr_data_buf) {
|
||||||
|
static skiing_tracker_t my_skiing_tracker;
|
||||||
|
static int initialized = 0;
|
||||||
|
static int calibration_done = 0;
|
||||||
|
|
||||||
|
static signed short combined_raw_data[6];
|
||||||
|
static float final_angle_data[3]; // 计算得到的欧若拉角
|
||||||
|
static float calibrated_acc_g[3]; // 转换后的加速度计数据
|
||||||
|
static float calibrated_gyr_dps[3]; // 转换后的陀螺仪数据
|
||||||
|
|
||||||
|
const float delta_time = 0.01f;
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
skiing_tracker_init(&my_skiing_tracker);
|
||||||
|
initialized = 1;
|
||||||
|
printf("Skiing Tracker Initialized. Waiting for sensor calibration...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&combined_raw_data[0], acc_data_buf, 3 * sizeof(signed short));
|
||||||
|
memcpy(&combined_raw_data[3], gyr_data_buf, 3 * sizeof(signed short));
|
||||||
|
|
||||||
|
unsigned char status;
|
||||||
|
if (!calibration_done) { //第1次启动,开启零漂检测
|
||||||
|
status = SL_SC7U22_Angle_Output(1, combined_raw_data, final_angle_data, 0);
|
||||||
|
if (status == 1) {
|
||||||
|
calibration_done = 1;
|
||||||
|
printf("Sensor calibration successful! Skiing mode is active.\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status = SL_SC7U22_Angle_Output(0, combined_raw_data, final_angle_data, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == 1) {
|
||||||
|
// 加速度 LSB to g
|
||||||
|
calibrated_acc_g[0] = (float)combined_raw_data[0] / 8192.0f;
|
||||||
|
calibrated_acc_g[1] = (float)combined_raw_data[1] / 8192.0f;
|
||||||
|
calibrated_acc_g[2] = (float)combined_raw_data[2] / 8192.0f;
|
||||||
|
|
||||||
|
// 陀螺仪 LSB to dps (度/秒)
|
||||||
|
// ±2000dps量程下,转换系数约为 0.061
|
||||||
|
calibrated_gyr_dps[0] = (float)combined_raw_data[3] * 0.061f;
|
||||||
|
calibrated_gyr_dps[1] = (float)combined_raw_data[4] * 0.061f;
|
||||||
|
calibrated_gyr_dps[2] = (float)combined_raw_data[5] * 0.061f;
|
||||||
|
|
||||||
|
skiing_tracker_update(&my_skiing_tracker, calibrated_acc_g, calibrated_gyr_dps, final_angle_data, delta_time);
|
||||||
|
|
||||||
|
// 打印逻辑保持不变
|
||||||
|
static int count = 0;
|
||||||
|
if(count < 10){
|
||||||
|
count++;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
printf("State: %d, Speed: %.2f m/s, Distance: %.2f m\n",
|
||||||
|
my_skiing_tracker.state,
|
||||||
|
my_skiing_tracker.speed,
|
||||||
|
my_skiing_tracker.distance);
|
||||||
|
|
||||||
|
} else if (status == 0) {
|
||||||
|
// printf("Sensor is calibrating...\n");
|
||||||
|
} else {
|
||||||
|
// printf("Angle calculation error or calibration not finished.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
55
apps/earphone/xtell_Sensor/A_hide/5/skiing_tracker.h
Normal file
55
apps/earphone/xtell_Sensor/A_hide/5/skiing_tracker.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#ifndef SKIING_TRACKER_H
|
||||||
|
#define SKIING_TRACKER_H
|
||||||
|
|
||||||
|
// 定义滑雪者可能的状态
|
||||||
|
typedef enum {
|
||||||
|
SKIING_STATE_STATIC, // 静止或动态稳定
|
||||||
|
SKIING_STATE_SKIING, // 正在滑雪
|
||||||
|
SKIING_STATE_ROTATING, // 正在原地旋转 (新增)
|
||||||
|
SKIING_STATE_FALLEN, // 已摔倒
|
||||||
|
SKIING_STATE_UNKNOWN // 未知状态
|
||||||
|
} skiing_state_t;
|
||||||
|
|
||||||
|
#define VARIANCE_BUFFER_SIZE 15 // 用于计算方差的数据窗口大小 (15个样本 @ 100Hz = 150ms)
|
||||||
|
|
||||||
|
// 追踪器数据结构体
|
||||||
|
typedef struct {
|
||||||
|
// 公开数据
|
||||||
|
float velocity[3]; // 当前速度 (x, y, z),单位: m/s
|
||||||
|
float distance; // 总滑行距离,单位: m
|
||||||
|
float speed; // 当前速率 (标量),单位: m/s
|
||||||
|
skiing_state_t state; // 当前滑雪状态
|
||||||
|
|
||||||
|
// 内部计算使用的私有成员
|
||||||
|
float acc_world[3]; // 在世界坐标系下的加速度
|
||||||
|
|
||||||
|
// --- 内部计算使用的私有成员 ---
|
||||||
|
// 用于动态零速更新和旋转检测的缓冲区
|
||||||
|
float acc_buffer[VARIANCE_BUFFER_SIZE][3]; // 加速度数据窗口
|
||||||
|
float gyr_buffer[VARIANCE_BUFFER_SIZE][3]; // 角速度数据窗口
|
||||||
|
int buffer_index; // 缓冲区当前索引
|
||||||
|
int buffer_filled; // 缓冲区是否已填满的标志
|
||||||
|
|
||||||
|
// 用于高通滤波器的私有成员,以消除加速度的直流偏置
|
||||||
|
float acc_world_filtered[3];
|
||||||
|
float acc_world_unfiltered_prev[3];
|
||||||
|
} skiing_tracker_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker 指向 skiing_tracker_t 结构体的指针
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 处理传感器数据并更新滑雪状态
|
||||||
|
*
|
||||||
|
* @param tracker 指向 skiing_tracker_t 结构体的指针
|
||||||
|
* @param acc_g 校准后的加速度数据 [x, y, z],单位: g (1g = 9.8m/s^2)
|
||||||
|
* @param gyr_dps 角速度
|
||||||
|
* @param angle 姿态角数据 [pitch, roll, yaw],单位: 度
|
||||||
|
* @param dt 采样时间间隔,单位: 秒 (s)
|
||||||
|
*/
|
||||||
|
void skiing_tracker_update(skiing_tracker_t *tracker, float *acc_g, float *gyr_dps, float *angle, float dt);
|
||||||
|
#endif // SKIING_TRACKER_H
|
||||||
374
apps/earphone/xtell_Sensor/A_hide/6/skiing_tracker.c
Normal file
374
apps/earphone/xtell_Sensor/A_hide/6/skiing_tracker.c
Normal file
@ -0,0 +1,374 @@
|
|||||||
|
/*
|
||||||
|
动态ZUPT+卡尔曼+巴特沃斯一阶滤波器
|
||||||
|
针对启动滑雪和停止滑雪,设置不同阈值
|
||||||
|
启动滑雪和ZUPT更新的陀螺仪方差阈值分开设置
|
||||||
|
- 启动滑雪的陀螺仪阈值会更宽松一些
|
||||||
|
原地旋转和ZUPT更新的加速度方差阈值分开设置
|
||||||
|
- 原地旋转的加速度阈值更宽松
|
||||||
|
能够从静止状态到变化状态,去根据阈值来判断这个“变化”:进入滑行状态 / 只是原地摆动
|
||||||
|
- 但是还是不够灵敏
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "skiing_tracker.h"
|
||||||
|
#include "../sensor/SC7U22.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define G_ACCELERATION 9.81f
|
||||||
|
#define DEG_TO_RAD (3.14159265f / 180.0f)
|
||||||
|
|
||||||
|
// --- 算法阈值定义 ---
|
||||||
|
//两个判断是否静止的必要条件:动态零速更新(ZUPT)阈值
|
||||||
|
// 加速方差阈值,提高阈值,让“刹车”更灵敏,以便在波浪式前进等慢速漂移时也能触发零速更新
|
||||||
|
#define ZUPT_ACC_VARIANCE_THRESHOLD 0.2f
|
||||||
|
// 陀螺仪方差阈值
|
||||||
|
#define ZUPT_GYR_VARIANCE_THRESHOLD 5.0f
|
||||||
|
|
||||||
|
// 用于原地旋转判断的加速度方差阈值。此值比ZUPT阈值更宽松,
|
||||||
|
// 以允许原地旋转时身体的正常晃动,但仍能与真实滑行时的剧烈加速度变化区分开。
|
||||||
|
#define ROTATING_ACC_VARIANCE_THRESHOLD 0.8f
|
||||||
|
// 用于启动滑雪判断的陀螺仪方差阈值。此值比ZUPT阈值更宽松,
|
||||||
|
// 以允许启动瞬间的正常抖动,但仍能过滤掉混乱的、非滑雪的晃动。
|
||||||
|
#define SKIING_GYR_VARIANCE_THRESHOLD 15.0f
|
||||||
|
|
||||||
|
|
||||||
|
// 旋转/摆动检测阈值:角速度总模长大于此值(度/秒),认为正在进行非滑雪的旋转或摆动
|
||||||
|
#define ROTATION_GYR_MAG_THRESHOLD 45.0f
|
||||||
|
// 启动滑雪阈值:加速度模长与重力的差值大于此值,认为开始运动
|
||||||
|
// 降低阈值,让“油门”更灵敏,以便能捕捉到真实的慢速启动
|
||||||
|
#define START_SKIING_ACC_THRESHOLD 0.5f
|
||||||
|
|
||||||
|
// --- 用于消除积分漂移的滤波器和阈值 ---
|
||||||
|
// 高通滤波器系数 (alpha)。alpha 越接近1,滤除低频(直流偏移)的效果越强,但可能滤掉真实的慢速运动。
|
||||||
|
// alpha = RC / (RC + dt),
|
||||||
|
#define HPF_ALPHA 0.95f // 换算大概就是衰减频率低于约 0.84 Hz 的信号
|
||||||
|
// 任何比“大约1秒钟变化一次”还要慢的运动,其加速度信号也会被部分衰减。
|
||||||
|
// 而滑雪时的快速转弯、加减速等动作,其频率远高于 0.84 Hz,它们的信号会被保留下来。
|
||||||
|
// 加速度死区阈值 (m/s^2)。低于此阈值的加速度被认为是噪声,不参与积分。
|
||||||
|
// 设得太高会忽略真实的慢速启动,设得太低则无法有效抑制噪声。
|
||||||
|
#define ACC_DEAD_ZONE_THRESHOLD 0.15f
|
||||||
|
|
||||||
|
// --- 模拟摩擦力,进行速度衰减 ---
|
||||||
|
#define SPEED_ATTENUATION 0.98f
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//实现
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker)
|
||||||
|
{
|
||||||
|
if (!tracker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 使用memset一次性清零整个结构体,包括新增的缓冲区
|
||||||
|
memset(tracker, 0, sizeof(skiing_tracker_t));
|
||||||
|
tracker->state = SKIING_STATE_STATIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 将设备坐标系下的加速度转换为世界坐标系
|
||||||
|
* @param acc_device 设备坐标系下的加速度 [x, y, z]
|
||||||
|
* @param angle 姿态角 [pitch, roll, yaw],单位: 度
|
||||||
|
* @param acc_world 输出:世界坐标系下的加速度 [x, y, z]
|
||||||
|
*/
|
||||||
|
static void transform_acc_to_world_frame(const float *acc_device, const float *angle, float *acc_world)
|
||||||
|
{
|
||||||
|
// 驱动输出的角度与标准航空定义相反,需要取反才能用于标准旋转矩阵。
|
||||||
|
float pitch = -angle[0] * DEG_TO_RAD;
|
||||||
|
float roll = -angle[1] * DEG_TO_RAD;
|
||||||
|
|
||||||
|
// TODO: 当引入三轴磁力计后,这里的 yaw 应由磁力计和陀螺仪融合解算得出,以解决航向漂移问题。
|
||||||
|
// 目前 yaw 暂时不参与计算,因为仅靠加速度计和陀螺仪无法获得准确的绝对航向角。
|
||||||
|
// float yaw = -angle[2] * DEG_TO_RAD;
|
||||||
|
|
||||||
|
float cp = cosf(pitch);
|
||||||
|
float sp = sinf(pitch);
|
||||||
|
float cr = cosf(roll);
|
||||||
|
float sr = sinf(roll);
|
||||||
|
|
||||||
|
float ax = acc_device[0];
|
||||||
|
float ay = acc_device[1];
|
||||||
|
float az = acc_device[2];
|
||||||
|
|
||||||
|
// 使用经过验证的、正确的身体坐标系到世界坐标系的旋转矩阵 (基于 Y-X 旋转顺序)
|
||||||
|
// 这个矩阵将设备测量的加速度(ax, ay, az)正确地转换到世界坐标系(acc_world)。
|
||||||
|
// 注意:这里没有使用yaw,主要关心的是坡面上的运动,绝对航向暂时不影响速度和距离的计算。
|
||||||
|
// TODO
|
||||||
|
acc_world[0] = cp * ax + sp * sr * ay + sp * cr * az;
|
||||||
|
acc_world[1] = 0 * ax + cr * ay - sr * az;
|
||||||
|
acc_world[2] = -sp * ax + cp * sr * ay + cp * cr * az;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计算缓冲区内三轴数据的方差之和
|
||||||
|
*
|
||||||
|
* @param buffer 传进来的三轴数据:陀螺仪/加速度
|
||||||
|
* @return float 返回方差和
|
||||||
|
*/
|
||||||
|
static float calculate_variance(float buffer[VARIANCE_BUFFER_SIZE][3])
|
||||||
|
{
|
||||||
|
float mean[3] = {0};
|
||||||
|
float variance[3] = {0};
|
||||||
|
|
||||||
|
// 计算均值
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
mean[0] += buffer[i][0];
|
||||||
|
mean[1] += buffer[i][1];
|
||||||
|
mean[2] += buffer[i][2];
|
||||||
|
}
|
||||||
|
mean[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 计算方差
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
variance[0] += (buffer[i][0] - mean[0]) * (buffer[i][0] - mean[0]);
|
||||||
|
variance[1] += (buffer[i][1] - mean[1]) * (buffer[i][1] - mean[1]);
|
||||||
|
variance[2] += (buffer[i][2] - mean[2]) * (buffer[i][2] - mean[2]);
|
||||||
|
}
|
||||||
|
variance[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 返回三轴方差之和,作为一个综合的稳定度指标
|
||||||
|
return variance[0] + variance[1] + variance[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 状态机更新
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
* @param acc_device_ms2 三轴加速度,m/s^2
|
||||||
|
* @param gyr_dps 三轴陀螺仪,dps
|
||||||
|
*/
|
||||||
|
static void update_state_machine(skiing_tracker_t *tracker, const float *acc_device_ms2, const float *gyr_dps)
|
||||||
|
{
|
||||||
|
// 缓冲区未填满时,不进行状态判断,默认为静止
|
||||||
|
if (!tracker->buffer_filled) {
|
||||||
|
tracker->state = SKIING_STATE_STATIC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 计算关键指标 ---
|
||||||
|
float acc_variance = calculate_variance(tracker->acc_buffer); // 计算加速度方差
|
||||||
|
float gyr_variance = calculate_variance(tracker->gyr_buffer); // 计算陀螺仪方差
|
||||||
|
float gyr_magnitude = sqrtf(gyr_dps[0]*gyr_dps[0] + gyr_dps[1]*gyr_dps[1] + gyr_dps[2]*gyr_dps[2]);
|
||||||
|
float acc_magnitude = sqrtf(acc_device_ms2[0]*acc_device_ms2[0] + acc_device_ms2[1]*acc_device_ms2[1] + acc_device_ms2[2]*acc_device_ms2[2]);
|
||||||
|
|
||||||
|
|
||||||
|
// --- 状态切换逻辑 (按优先级) ---
|
||||||
|
|
||||||
|
// 优先级1:动态零速更新 (ZUPT) - 最严格和最优先的“刹车”
|
||||||
|
if (acc_variance < ZUPT_ACC_VARIANCE_THRESHOLD && gyr_variance < ZUPT_GYR_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = SKIING_STATE_STATIC;
|
||||||
|
// 速度清零,抑制漂移
|
||||||
|
memset(tracker->velocity, 0, sizeof(tracker->velocity));
|
||||||
|
tracker->speed = 0.0f;
|
||||||
|
// 关键:当检测到静止时,必须重置高通滤波器的状态
|
||||||
|
memset(tracker->acc_world_unfiltered_prev, 0, sizeof(tracker->acc_world_unfiltered_prev));
|
||||||
|
memset(tracker->acc_world_filtered, 0, sizeof(tracker->acc_world_filtered));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优先级2:原地旋转 - 特殊的、非滑雪的运动状态
|
||||||
|
// 条件:角速度很大,同时线性加速度的晃动在一个“中等”范围内。
|
||||||
|
if (gyr_magnitude > ROTATION_GYR_MAG_THRESHOLD && acc_variance < ROTATING_ACC_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = SKIING_STATE_ROTATING;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优先级3:启动滑雪 - “油门”
|
||||||
|
// 条件:有足够大的线性加速度,同时陀螺仪的抖动在一个“合理”(而非“完全静止”)的范围内。
|
||||||
|
if (fabsf(acc_magnitude - G_ACCELERATION) > START_SKIING_ACC_THRESHOLD && gyr_variance < SKIING_GYR_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = SKIING_STATE_SKIING;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果不满足任何启动或停止条件,则保持当前状态(滑雪中)
|
||||||
|
// 如果当前是静止或旋转,但没有满足启动条件,则状态会保持,直到满足ZUPT或旋转条件。
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 主更新函数
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
* @param acc_g 三轴加速度,g
|
||||||
|
* @param gyr_dps 三轴陀螺仪,dps
|
||||||
|
* @param angle 欧若拉角
|
||||||
|
* @param dt 采样时间间隔,会用来积分求速度
|
||||||
|
*/
|
||||||
|
void skiing_tracker_update(skiing_tracker_t *tracker, float *acc_g, float *gyr_dps, float *angle, float dt)
|
||||||
|
{
|
||||||
|
if (!tracker || !acc_g || !gyr_dps || !angle || dt <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 数据预处理和缓冲 ---
|
||||||
|
float acc_device_ms2[3];
|
||||||
|
acc_device_ms2[0] = acc_g[0] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[1] = acc_g[1] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[2] = acc_g[2] * G_ACCELERATION;
|
||||||
|
|
||||||
|
// 将最新数据存入缓冲区
|
||||||
|
memcpy(tracker->acc_buffer[tracker->buffer_index], acc_device_ms2, sizeof(acc_device_ms2));
|
||||||
|
memcpy(tracker->gyr_buffer[tracker->buffer_index], gyr_dps, 3 * sizeof(float));
|
||||||
|
|
||||||
|
tracker->buffer_index++;
|
||||||
|
if (tracker->buffer_index >= VARIANCE_BUFFER_SIZE) {
|
||||||
|
tracker->buffer_index = 0;
|
||||||
|
tracker->buffer_filled = 1; // 标记缓冲区已满
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 更新状态机 ---
|
||||||
|
update_state_machine(tracker, acc_device_ms2, gyr_dps);
|
||||||
|
|
||||||
|
// --- 根据状态进行计算 ---
|
||||||
|
if (tracker->state == SKIING_STATE_SKIING) {
|
||||||
|
// 坐标转换 & 移除重力
|
||||||
|
transform_acc_to_world_frame(acc_device_ms2, angle, tracker->acc_world);
|
||||||
|
tracker->acc_world[2] -= G_ACCELERATION;
|
||||||
|
|
||||||
|
// 对世界坐标系下的加速度进行高通滤波,消除直流偏置和重力残差
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
tracker->acc_world_filtered[i] = HPF_ALPHA * (tracker->acc_world_filtered[i] + tracker->acc_world[i] - tracker->acc_world_unfiltered_prev[i]);
|
||||||
|
tracker->acc_world_unfiltered_prev[i] = tracker->acc_world[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用加速度死区,忽略微小抖动和噪声
|
||||||
|
float acc_horizontal_mag = sqrtf(tracker->acc_world_filtered[0] * tracker->acc_world_filtered[0] +
|
||||||
|
tracker->acc_world_filtered[1] * tracker->acc_world_filtered[1]);
|
||||||
|
|
||||||
|
if (acc_horizontal_mag > ACC_DEAD_ZONE_THRESHOLD) {
|
||||||
|
// 只有当水平加速度足够大时,才进行速度积分
|
||||||
|
tracker->velocity[0] += tracker->acc_world_filtered[0] * dt;
|
||||||
|
tracker->velocity[1] += tracker->acc_world_filtered[1] * dt;
|
||||||
|
// 垂直方向的速度暂时不积分,极易受姿态误差影响而漂移
|
||||||
|
// tracker->velocity[2] += tracker->acc_world_filtered[2] * dt;
|
||||||
|
}
|
||||||
|
// 如果加速度小于阈值,则不更新速度,相当于速度保持不变(或受下一步的阻尼影响而衰减)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// 在静止或旋转状态下,速度已经在状态机内部被清零
|
||||||
|
// 额外增加速度衰减,模拟摩擦力,进一步抑制漂移
|
||||||
|
tracker->velocity[0] *= SPEED_ATTENUATION;
|
||||||
|
tracker->velocity[1] *= SPEED_ATTENUATION;
|
||||||
|
tracker->velocity[2] = 0; // 垂直速度强制归零
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 更新速率和距离 ---
|
||||||
|
// 只基于水平速度计算速率和距离
|
||||||
|
tracker->speed = sqrtf(tracker->velocity[0] * tracker->velocity[0] +
|
||||||
|
tracker->velocity[1] * tracker->velocity[1]);
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 传感器数据采集与处理任务,外部每10ms调用一次,如果需要更新时间间隔,也需要同步更新宏“ DELTA_TIME ”
|
||||||
|
*
|
||||||
|
* @param acc_data_buf 三轴加速度原始数据
|
||||||
|
* @param gyr_data_buf 三轴陀螺仪原始数据
|
||||||
|
* @return BLE_send_data_t
|
||||||
|
*/
|
||||||
|
BLE_send_data_t sensor_processing_task(signed short * acc_data_buf, signed short * gyr_data_buf) {
|
||||||
|
static skiing_tracker_t my_skiing_tracker;
|
||||||
|
static int initialized = 0;
|
||||||
|
static int calibration_done = 0;
|
||||||
|
|
||||||
|
static signed short combined_raw_data[6];
|
||||||
|
static float final_angle_data[3]; // 计算得到的欧若拉角
|
||||||
|
static float calibrated_acc_g[3]; // 转换后的加速度计数据
|
||||||
|
static float calibrated_gyr_dps[3]; // 转换后的陀螺仪数据
|
||||||
|
|
||||||
|
const float delta_time = DELTA_TIME;
|
||||||
|
BLE_send_data_t BLE_send_data;
|
||||||
|
BLE_KS_send_data_t KS_data;
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
skiing_tracker_init(&my_skiing_tracker);
|
||||||
|
initialized = 1;
|
||||||
|
printf("Skiing Tracker Initialized. Waiting for sensor calibration...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&combined_raw_data[0], acc_data_buf, 3 * sizeof(signed short));
|
||||||
|
memcpy(&combined_raw_data[3], gyr_data_buf, 3 * sizeof(signed short));
|
||||||
|
|
||||||
|
unsigned char status;
|
||||||
|
if (!calibration_done) { //第1次启动,开启零漂检测
|
||||||
|
status = SL_SC7U22_Angle_Output(1, combined_raw_data, final_angle_data, 0);
|
||||||
|
if (status == 1) {
|
||||||
|
calibration_done = 1;
|
||||||
|
printf("Sensor calibration successful! Skiing mode is active.\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status = SL_SC7U22_Angle_Output(0, combined_raw_data, final_angle_data, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == 1) {
|
||||||
|
// 加速度 LSB to g
|
||||||
|
calibrated_acc_g[0] = (float)combined_raw_data[0] / 8192.0f;
|
||||||
|
calibrated_acc_g[1] = (float)combined_raw_data[1] / 8192.0f;
|
||||||
|
calibrated_acc_g[2] = (float)combined_raw_data[2] / 8192.0f;
|
||||||
|
|
||||||
|
// 陀螺仪 LSB to dps (度/秒)
|
||||||
|
// ±2000dps量程下,转换系数约为 0.061
|
||||||
|
calibrated_gyr_dps[0] = (float)combined_raw_data[3] * 0.061f;
|
||||||
|
calibrated_gyr_dps[1] = (float)combined_raw_data[4] * 0.061f;
|
||||||
|
calibrated_gyr_dps[2] = (float)combined_raw_data[5] * 0.061f;
|
||||||
|
|
||||||
|
skiing_tracker_update(&my_skiing_tracker, calibrated_acc_g, calibrated_gyr_dps, final_angle_data, delta_time);
|
||||||
|
|
||||||
|
// 打印逻辑保持不变
|
||||||
|
// static int count = 0;
|
||||||
|
// if(count >= 10){
|
||||||
|
// printf("State: %d, Speed: %.2f m/s, Distance: %.2f m\n",
|
||||||
|
// my_skiing_tracker.state,
|
||||||
|
// my_skiing_tracker.speed,
|
||||||
|
// my_skiing_tracker.distance);
|
||||||
|
// count = 0;
|
||||||
|
// } else {
|
||||||
|
// count++;
|
||||||
|
// }
|
||||||
|
|
||||||
|
BLE_send_data.sensor_state = status;
|
||||||
|
BLE_send_data.skiing_state = my_skiing_tracker.state;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
#ifndef XTELL_TEST
|
||||||
|
BLE_send_data.acc_original[i] = (int)acc_data_buf[i];
|
||||||
|
BLE_send_data.gyr_original[i] = (int)gyr_data_buf[i];
|
||||||
|
#endif
|
||||||
|
#if KS_BLE
|
||||||
|
KS_data.acc_KS_g[i] = (int)calibrated_acc_g[i];
|
||||||
|
KS_data.gyr_KS_dps[i] = (int)calibrated_gyr_dps[i];
|
||||||
|
KS_data.angle_KS[i] = (int)final_angle_data[i];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
BLE_send_data.speed_cms = (int)(my_skiing_tracker.speed * 100);
|
||||||
|
BLE_send_data.distance_cm = (int)(my_skiing_tracker.distance * 100);
|
||||||
|
|
||||||
|
} else if (status == 0) {
|
||||||
|
memset(&BLE_send_data, 0, sizeof(BLE_send_data_t));
|
||||||
|
BLE_send_data.sensor_state = status;
|
||||||
|
#if KS_BLE
|
||||||
|
memset(&KS_data, 0, sizeof(BLE_send_data_t));
|
||||||
|
#endif
|
||||||
|
// printf("Sensor is calibrating...\n");
|
||||||
|
} else {
|
||||||
|
memset(&BLE_send_data, 0, sizeof(BLE_send_data_t));
|
||||||
|
BLE_send_data.sensor_state = status;
|
||||||
|
#if KS_BLE
|
||||||
|
memset(&KS_data, 0, sizeof(BLE_send_data_t));
|
||||||
|
#endif
|
||||||
|
// printf("Angle calculation error or calibration not finished.\n");
|
||||||
|
}
|
||||||
|
return BLE_send_data;
|
||||||
|
}
|
||||||
74
apps/earphone/xtell_Sensor/A_hide/6/skiing_tracker.h
Normal file
74
apps/earphone/xtell_Sensor/A_hide/6/skiing_tracker.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#ifndef SKIING_TRACKER_H
|
||||||
|
#define SKIING_TRACKER_H
|
||||||
|
|
||||||
|
#include "../xtell.h"
|
||||||
|
// 定义滑雪者可能的状态
|
||||||
|
typedef enum {
|
||||||
|
SKIING_STATE_STATIC, // 静止或动态稳定
|
||||||
|
SKIING_STATE_SKIING, // 正在滑雪
|
||||||
|
SKIING_STATE_ROTATING, // 正在原地旋转 (新增)
|
||||||
|
SKIING_STATE_FALLEN, // 已摔倒
|
||||||
|
SKIING_STATE_UNKNOWN // 未知状态
|
||||||
|
} skiing_state_t;
|
||||||
|
|
||||||
|
#define VARIANCE_BUFFER_SIZE 5 // 用于计算方差的数据窗口大小 (5个样本 @ 100Hz = 50ms),减小延迟,提高实时性
|
||||||
|
#define DELTA_TIME 0.01f
|
||||||
|
|
||||||
|
|
||||||
|
// 追踪器数据结构体
|
||||||
|
typedef struct {
|
||||||
|
// 公开数据
|
||||||
|
float velocity[3]; // 当前速度 (x, y, z),单位: m/s
|
||||||
|
float distance; // 总滑行距离,单位: m
|
||||||
|
float speed; // 当前速率 (标量),单位: m/s
|
||||||
|
skiing_state_t state; // 当前滑雪状态
|
||||||
|
|
||||||
|
// 内部计算使用的私有成员
|
||||||
|
float acc_world[3]; // 在世界坐标系下的加速度
|
||||||
|
|
||||||
|
// --- 内部计算使用的私有成员 ---
|
||||||
|
// 用于动态零速更新和旋转检测的缓冲区
|
||||||
|
float acc_buffer[VARIANCE_BUFFER_SIZE][3]; // 加速度数据窗口
|
||||||
|
float gyr_buffer[VARIANCE_BUFFER_SIZE][3]; // 角速度数据窗口
|
||||||
|
int buffer_index; // 缓冲区当前索引
|
||||||
|
int buffer_filled; // 缓冲区是否已填满的标志
|
||||||
|
|
||||||
|
// 用于高通滤波器(巴特沃斯一阶滤波器)的私有成员,以消除加速度的直流偏置
|
||||||
|
float acc_world_filtered[3]; //过滤过的
|
||||||
|
float acc_world_unfiltered_prev[3]; //上一次没过滤的
|
||||||
|
} skiing_tracker_t;
|
||||||
|
|
||||||
|
//ble发送的数据
|
||||||
|
typedef struct __attribute__((packed)){ //该结构体取消内存对齐
|
||||||
|
char sensor_state;
|
||||||
|
char skiing_state;
|
||||||
|
int speed_cms; //求出的速度,cm/s
|
||||||
|
int distance_cm; //求出的距离,cm
|
||||||
|
#ifndef XTELL_TEST
|
||||||
|
int acc_original[3]; //直接读取传感器得到的原始三轴加速度
|
||||||
|
int gyr_original[3]; //直接读取传感器得到的原始三轴陀螺仪
|
||||||
|
#endif
|
||||||
|
}BLE_send_data_t;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
int acc_KS_g[3]; //卡尔曼后,LSB to g 三轴加速度数据
|
||||||
|
int gyr_KS_dps[3]; //卡尔曼后,LSB to dps 三轴陀螺仪数据
|
||||||
|
int angle_KS[3]; //卡尔曼后,计算得到的欧若拉角数据
|
||||||
|
}BLE_KS_send_data_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker 指向 skiing_tracker_t 结构体的指针
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 传感器数据采集与处理任务,外部每10ms调用一次,如果需要更新时间间隔,也需要同步更新宏“ DELTA_TIME ”
|
||||||
|
*
|
||||||
|
* @param acc_data_buf 三轴加速度原始数据
|
||||||
|
* @param gyr_data_buf 三轴陀螺仪原始数据
|
||||||
|
* @return BLE_send_data_t
|
||||||
|
*/
|
||||||
|
BLE_send_data_t sensor_processing_task(signed short * acc_data_buf, signed short * gyr_data_buf) ;
|
||||||
|
#endif // SKIING_TRACKER_H
|
||||||
276
apps/earphone/xtell_Sensor/A_hide/7/skiing_tracker.c
Normal file
276
apps/earphone/xtell_Sensor/A_hide/7/skiing_tracker.c
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
/*
|
||||||
|
简化的滑雪追踪器:
|
||||||
|
- 直接读取六轴数据
|
||||||
|
- 分离重力分量
|
||||||
|
- 直接积分求速度和距离
|
||||||
|
*/
|
||||||
|
#include "skiing_tracker.h"
|
||||||
|
#include "../sensor/SC7U22.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define ENABLE_XLOG 1
|
||||||
|
#ifdef xlog
|
||||||
|
#undef xlog
|
||||||
|
#endif
|
||||||
|
#if ENABLE_XLOG
|
||||||
|
#define xlog(format, ...) printf("[XT:%s] " format, __func__, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define xlog(format, ...) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define G_ACCELERATION 9.81f
|
||||||
|
#define DEG_TO_RAD (3.14159265f / 180.0f)
|
||||||
|
|
||||||
|
// 运动检测阈值 (m/s^2)。当水平加速度的模长大于此值时,认为处于运动状态。
|
||||||
|
#define MOTION_THRESHOLD 0.2f
|
||||||
|
|
||||||
|
static skiing_tracker_t my_skiing_tracker;
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
BLE_KS_send_data_t KS_data;
|
||||||
|
debug_t debug1;
|
||||||
|
debug_t debug2;
|
||||||
|
#endif
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//实现
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker)
|
||||||
|
{
|
||||||
|
if (!tracker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(tracker, 0, sizeof(skiing_tracker_t));
|
||||||
|
tracker->state = SKIING_STATE_STATIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 将设备坐标系下的加速度转换为世界坐标系
|
||||||
|
* @param acc_device 设备坐标系下的加速度 [x, y, z]
|
||||||
|
* @param angle 姿态角 [pitch, roll, yaw],单位: 度
|
||||||
|
* @param acc_world 输出:世界坐标系下的加速度 [x, y, z]
|
||||||
|
*/
|
||||||
|
static void transform_acc_to_world_frame(const float *acc_device, const float *angle, float *acc_world)
|
||||||
|
{
|
||||||
|
// 驱动输出的角度与标准航空定义相反,需要取反才能用于标准旋转矩阵。
|
||||||
|
float pitch = -angle[0] * DEG_TO_RAD;
|
||||||
|
float roll = -angle[1] * DEG_TO_RAD;
|
||||||
|
|
||||||
|
float cp = cosf(pitch);
|
||||||
|
float sp = sinf(pitch);
|
||||||
|
float cr = cosf(roll);
|
||||||
|
float sr = sinf(roll);
|
||||||
|
|
||||||
|
float ax = acc_device[0];
|
||||||
|
float ay = acc_device[1];
|
||||||
|
float az = acc_device[2];
|
||||||
|
|
||||||
|
// 使用经过验证的、正确的身体坐标系到世界坐标系的旋转矩阵 (基于 Y-X 旋转顺序)
|
||||||
|
acc_world[0] = cp * ax + sp * sr * ay + sp * cr * az;
|
||||||
|
acc_world[1] = 0 * ax + cr * ay - sr * az;
|
||||||
|
acc_world[2] = -sp * ax + cp * sr * ay + cp * cr * az;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_speed(void){
|
||||||
|
my_skiing_tracker.state = SKIING_STATE_STATIC;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_detection(void){
|
||||||
|
my_skiing_tracker.state = SKIING_STATE_STATIC;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.distance = 0;
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop_detection(void){
|
||||||
|
my_skiing_tracker.state = SKINNG_STOP_DETECTION;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 主更新函数
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
* @param acc_g 三轴加速度,g
|
||||||
|
* @param gyr_dps 三轴陀螺仪,dps (当前简化版本未使用)
|
||||||
|
* @param angle 欧拉角
|
||||||
|
* @param dt 采样时间间隔,会用来积分求速度
|
||||||
|
*/
|
||||||
|
void skiing_tracker_update(skiing_tracker_t *tracker, float *acc_g, float *gyr_dps, float *angle, float dt)
|
||||||
|
{
|
||||||
|
if (!tracker || !acc_g || !angle || dt <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//停止检测
|
||||||
|
if(my_skiing_tracker.state == SKINNG_STOP_DETECTION)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// --- 数据预处理 ---
|
||||||
|
float acc_device_ms2[3];
|
||||||
|
acc_device_ms2[0] = acc_g[0] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[1] = acc_g[1] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[2] = acc_g[2] * G_ACCELERATION;
|
||||||
|
|
||||||
|
// --- 坐标转换 & 移除重力 ---
|
||||||
|
// 1. 将设备坐标系下的总加速度转换到世界坐标系
|
||||||
|
transform_acc_to_world_frame(acc_device_ms2, angle, tracker->acc_world);
|
||||||
|
// 2. 在世界坐标系下,减去Z轴的重力分量,得到线性加速度
|
||||||
|
tracker->acc_world[2] -= G_ACCELERATION;
|
||||||
|
|
||||||
|
// --- 运动状态判断与计算 ---
|
||||||
|
// 计算水平方向的线性加速度模长
|
||||||
|
float acc_horizontal_mag = sqrtf(tracker->acc_world[0] * tracker->acc_world[0] +
|
||||||
|
tracker->acc_world[1] * tracker->acc_world[1]);
|
||||||
|
|
||||||
|
if (acc_horizontal_mag > MOTION_THRESHOLD) {
|
||||||
|
// 加速
|
||||||
|
tracker->state = SKIING_STATE_SKIING;
|
||||||
|
|
||||||
|
// 积分计算速度(只考虑水平方向,避免垂直方向漂移)
|
||||||
|
tracker->velocity[0] += tracker->acc_world[0] * dt;
|
||||||
|
tracker->velocity[1] += tracker->acc_world[1] * dt;
|
||||||
|
tracker->velocity[2] = 0; // 垂直速度强制为0
|
||||||
|
|
||||||
|
// --- 更新速率和距离 ---
|
||||||
|
// 只基于水平速度计算速率
|
||||||
|
tracker->speed = sqrtf(tracker->velocity[0] * tracker->velocity[0] +
|
||||||
|
tracker->velocity[1] * tracker->velocity[1]);
|
||||||
|
// 累加距离
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//匀速
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前 RTC 时间戳
|
||||||
|
time_t get_rtc_timestamp(void) {
|
||||||
|
static void *rtc_hdl = NULL;
|
||||||
|
struct sys_time rtc_time = {0};
|
||||||
|
dev_ioctl(rtc_hdl, IOCTL_GET_SYS_TIME, (u32)&rtc_time);
|
||||||
|
|
||||||
|
return rtc_sys_time_to_timestamp(&rtc_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 传感器数据采集与处理任务,外部每10ms调用一次,如果需要更新时间间隔,也需要同步更新宏“ DELTA_TIME ”
|
||||||
|
*
|
||||||
|
* @param acc_data_buf 三轴加速度原始数据
|
||||||
|
* @param gyr_data_buf 三轴陀螺仪原始数据
|
||||||
|
* @return BLE_send_data_t
|
||||||
|
*/
|
||||||
|
BLE_send_data_t sensor_processing_task(signed short * acc_data_buf, signed short * gyr_data_buf) {
|
||||||
|
|
||||||
|
static int initialized = 0;
|
||||||
|
static int calibration_done = 0;
|
||||||
|
|
||||||
|
static signed short combined_raw_data[6];
|
||||||
|
static float final_angle_data[3]; // 计算得到的欧若拉角
|
||||||
|
static float calibrated_acc_g[3]; // 转换后的加速度计数据
|
||||||
|
static float calibrated_gyr_dps[3]; // 转换后的陀螺仪数据
|
||||||
|
|
||||||
|
float delta_time = DELTA_TIME + 0.03f; //观察得到实际上调用间隔会多30ms
|
||||||
|
BLE_send_data_t BLE_send_data;
|
||||||
|
|
||||||
|
// xlog("===========start\n");
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
skiing_tracker_init(&my_skiing_tracker);
|
||||||
|
initialized = 1;
|
||||||
|
printf("Skiing Tracker Initialized. Waiting for sensor calibration...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&combined_raw_data[0], acc_data_buf, 3 * sizeof(signed short));
|
||||||
|
memcpy(&combined_raw_data[3], gyr_data_buf, 3 * sizeof(signed short));
|
||||||
|
|
||||||
|
unsigned char status;
|
||||||
|
if (!calibration_done) { //第1次启动,开启零漂检测
|
||||||
|
status = SL_SC7U22_Angle_Output(1, combined_raw_data, final_angle_data, 0);
|
||||||
|
if (status == 1) {
|
||||||
|
calibration_done = 1;
|
||||||
|
printf("Sensor calibration successful! Skiing mode is active.\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// printf("Calculate the time interval =============== start\n");
|
||||||
|
status = SL_SC7U22_Angle_Output(0, combined_raw_data, final_angle_data, 0);
|
||||||
|
// printf("Calculate the time interval =============== end\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == 1) {
|
||||||
|
// 加速度 LSB to g
|
||||||
|
calibrated_acc_g[0] = (float)combined_raw_data[0] / 8192.0f;
|
||||||
|
calibrated_acc_g[1] = (float)combined_raw_data[1] / 8192.0f;
|
||||||
|
calibrated_acc_g[2] = (float)combined_raw_data[2] / 8192.0f;
|
||||||
|
|
||||||
|
// 陀螺仪 LSB to dps (度/秒)
|
||||||
|
// ±2000dps量程下,转换系数约为 0.061
|
||||||
|
calibrated_gyr_dps[0] = (float)combined_raw_data[3] * 0.061f;
|
||||||
|
calibrated_gyr_dps[1] = (float)combined_raw_data[4] * 0.061f;
|
||||||
|
calibrated_gyr_dps[2] = (float)combined_raw_data[5] * 0.061f;
|
||||||
|
|
||||||
|
skiing_tracker_update(&my_skiing_tracker, calibrated_acc_g, calibrated_gyr_dps, final_angle_data, delta_time);
|
||||||
|
|
||||||
|
// static int count = 0;
|
||||||
|
// if(count >= 10){
|
||||||
|
// printf("State: %d, Speed: %.2f m/s, Distance: %.2f m\n",
|
||||||
|
// my_skiing_tracker.state,
|
||||||
|
// my_skiing_tracker.speed,
|
||||||
|
// my_skiing_tracker.distance);
|
||||||
|
// printf("calibrated_acc_g: %.2f, %.2f, %.2f\n",
|
||||||
|
// calibrated_acc_g[0],
|
||||||
|
// calibrated_acc_g[1],
|
||||||
|
// calibrated_acc_g[2]);
|
||||||
|
// count = 0;
|
||||||
|
// } else {
|
||||||
|
// count++;
|
||||||
|
// }
|
||||||
|
|
||||||
|
BLE_send_data.sensor_state = status;
|
||||||
|
BLE_send_data.skiing_state = my_skiing_tracker.state;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
#ifndef XTELL_TEST
|
||||||
|
BLE_send_data.acc_original[i] = (int)acc_data_buf[i];
|
||||||
|
BLE_send_data.gyr_original[i] = (int)gyr_data_buf[i];
|
||||||
|
#endif
|
||||||
|
#if KS_BLE
|
||||||
|
KS_data.acc_KS[i] = (int)(calibrated_acc_g[i] * G_ACCELERATION * 100); //cm/s^s
|
||||||
|
KS_data.gyr_KS_dps[i] = (int)calibrated_gyr_dps[i];
|
||||||
|
KS_data.angle_KS[i] = (int)final_angle_data[i];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
BLE_send_data.speed_cms = (int)(my_skiing_tracker.speed * 100);
|
||||||
|
BLE_send_data.distance_cm = (int)(my_skiing_tracker.distance * 100);
|
||||||
|
//
|
||||||
|
} else if (status == 0) {
|
||||||
|
memset(&BLE_send_data, 0, sizeof(BLE_send_data_t));
|
||||||
|
BLE_send_data.sensor_state = status;
|
||||||
|
#if KS_BLE
|
||||||
|
memset(&KS_data, 0, sizeof(BLE_send_data_t));
|
||||||
|
#endif
|
||||||
|
// printf("Sensor is calibrating...\n");
|
||||||
|
} else {
|
||||||
|
memset(&BLE_send_data, 0, sizeof(BLE_send_data_t));
|
||||||
|
BLE_send_data.sensor_state = status;
|
||||||
|
#if KS_BLE
|
||||||
|
memset(&KS_data, 0, sizeof(BLE_send_data_t));
|
||||||
|
#endif
|
||||||
|
// printf("Angle calculation error or calibration not finished.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// xlog("end++++++++++++++\n");
|
||||||
|
return BLE_send_data;
|
||||||
|
}
|
||||||
67
apps/earphone/xtell_Sensor/A_hide/7/skiing_tracker.h
Normal file
67
apps/earphone/xtell_Sensor/A_hide/7/skiing_tracker.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#ifndef SKIING_TRACKER_H
|
||||||
|
#define SKIING_TRACKER_H
|
||||||
|
|
||||||
|
#include "../xtell.h"
|
||||||
|
// 定义滑雪者可能的状态
|
||||||
|
typedef enum {
|
||||||
|
SKIING_STATE_STATIC, // 静止
|
||||||
|
SKIING_STATE_SKIING, // 正在滑雪
|
||||||
|
SKINNG_STOP_DETECTION, // 停止检测
|
||||||
|
} skiing_state_t;
|
||||||
|
#define DELTA_TIME 0.01f
|
||||||
|
|
||||||
|
|
||||||
|
// 追踪器数据结构体
|
||||||
|
typedef struct {
|
||||||
|
// 公开数据
|
||||||
|
float velocity[3]; // 当前速度 (x, y, z),单位: m/s
|
||||||
|
float distance; // 总滑行距离,单位: m
|
||||||
|
float speed; // 当前速率 (标量),单位: m/s
|
||||||
|
skiing_state_t state; // 当前滑雪状态
|
||||||
|
|
||||||
|
// 内部计算使用的私有成员
|
||||||
|
float acc_world[3]; // 在世界坐标系下的线性加速度
|
||||||
|
} skiing_tracker_t;
|
||||||
|
|
||||||
|
//ble发送的数据
|
||||||
|
typedef struct __attribute__((packed)){ //该结构体取消内存对齐
|
||||||
|
char sensor_state;
|
||||||
|
char skiing_state;
|
||||||
|
int speed_cms; //求出的速度,cm/s
|
||||||
|
int distance_cm; //求出的距离,cm
|
||||||
|
#ifndef XTELL_TEST
|
||||||
|
int acc_original[3]; //直接读取传感器得到的原始三轴加速度
|
||||||
|
int gyr_original[3]; //直接读取传感器得到的原始三轴陀螺仪
|
||||||
|
#endif
|
||||||
|
}BLE_send_data_t;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
int acc_KS[3]; //卡尔曼后,LSB转换后的 三轴加速度数据(cm/s^2)
|
||||||
|
int gyr_KS_dps[3]; //卡尔曼后,LSB to dps 三轴陀螺仪数据
|
||||||
|
int angle_KS[3]; //卡尔曼后,计算得到的欧若拉角数据
|
||||||
|
}BLE_KS_send_data_t;
|
||||||
|
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
typedef struct{
|
||||||
|
float acc_variance; //三轴加速度方差之和
|
||||||
|
float gyr_variance; //三轴陀螺仪方差之和
|
||||||
|
float acc_magnitude; //三轴加速度模长
|
||||||
|
float gyr_magnitude; //三轴陀螺仪模长
|
||||||
|
}debug_t;
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker 指向 skiing_tracker_t 结构体的指针
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 传感器数据采集与处理任务,外部每10ms调用一次,如果需要更新时间间隔,也需要同步更新宏“ DELTA_TIME ”
|
||||||
|
*
|
||||||
|
* @param acc_data_buf 三轴加速度原始数据
|
||||||
|
* @param gyr_data_buf 三轴陀螺仪原始数据
|
||||||
|
* @return BLE_send_data_t
|
||||||
|
*/
|
||||||
|
BLE_send_data_t sensor_processing_task(signed short * acc_data_buf, signed short * gyr_data_buf) ;
|
||||||
|
#endif // SKIING_TRACKER_H
|
||||||
501
apps/earphone/xtell_Sensor/A_hide/8/skiing_tracker.c
Normal file
501
apps/earphone/xtell_Sensor/A_hide/8/skiing_tracker.c
Normal file
@ -0,0 +1,501 @@
|
|||||||
|
/*
|
||||||
|
虽然sensor_processing_task是10ms调用一次
|
||||||
|
但是实际上上一次调用该函数的时间点和下一次调用该函数的时间点,会相差40ms
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "skiing_tracker.h"
|
||||||
|
#include "../sensor/SC7U22.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define G_ACCELERATION 9.81f
|
||||||
|
#define DEG_TO_RAD (3.14159265f / 180.0f)
|
||||||
|
|
||||||
|
// --- ZUPT ---
|
||||||
|
//两个判断是否静止的必要条件:动态零速更新(ZUPT)阈值
|
||||||
|
// 加速方差阈值,提高阈值,让“刹车”更灵敏,以便在波浪式前进等慢速漂移时也能触发零速更新
|
||||||
|
#define ZUPT_ACC_VARIANCE_THRESHOLD 0.2f
|
||||||
|
// 陀螺仪方差阈值
|
||||||
|
#define ZUPT_GYR_VARIANCE_THRESHOLD 5.0f
|
||||||
|
|
||||||
|
// --- 启动滑雪阈值 ---
|
||||||
|
// 加速度模长与重力的差值大于此值,认为开始运动;降低阈值,让“油门”更灵敏,以便能捕捉到真实的慢速启动
|
||||||
|
#define START_SKIING_ACC_THRESHOLD 0.5f
|
||||||
|
// 陀螺仪方差阈值,以允许启动瞬间的正常抖动,但仍能过滤掉混乱的、非滑雪的晃动。
|
||||||
|
#define SKIING_GYR_VARIANCE_THRESHOLD 15.0f
|
||||||
|
|
||||||
|
// --- 滑雪过程 ---
|
||||||
|
//加速度 模长,低于此值视为 在做匀速运动
|
||||||
|
#define SKIING_ACC_MAG_THRESHOLD 0.5f
|
||||||
|
//陀螺仪 模长,高于此值视为 摔倒了
|
||||||
|
#define FALLEN_GRY_MAG_THRESHOLD 1000.0f //未确定
|
||||||
|
|
||||||
|
// --- 原地旋转抖动 ---
|
||||||
|
// 用于原地旋转判断的加速度方差阈值。此值比ZUPT阈值更宽松,
|
||||||
|
// 以允许原地旋转时身体的正常晃动,但仍能与真实滑行时的剧烈加速度变化区分开。
|
||||||
|
#define ROTATING_ACC_VARIANCE_THRESHOLD 0.8f
|
||||||
|
// 旋转/摆动检测阈值:角速度总模长大于此值(度/秒),认为正在进行非滑雪的旋转或摆动
|
||||||
|
#define ROTATION_GYR_MAG_THRESHOLD 120.0f
|
||||||
|
|
||||||
|
// --- 滑雪转弯动 ---
|
||||||
|
// 加速度方差阈值,大于此值,滑雪过程可能发生了急转弯
|
||||||
|
#define WHEEL_ACC_VARIANCE_THRESHOLD 7.0f
|
||||||
|
// 旋转/摆动检测阈值:角速度总模长大于此值(度/秒),认为滑雪过程中进行急转弯
|
||||||
|
#define WHEEL_GYR_MAG_THRESHOLD 220.0f // 150.0f 到 250.0f之间进行调整
|
||||||
|
|
||||||
|
// --- 用于消除积分漂移的滤波器和阈值 ---
|
||||||
|
// 高通滤波器系数 (alpha)。alpha 越接近1,滤除低频(直流偏移)的效果越强,但可能滤掉真实的慢速运动。
|
||||||
|
// alpha = RC / (RC + dt),参考RC电路而来
|
||||||
|
#define HPF_ALPHA 0.995
|
||||||
|
|
||||||
|
// 加速度死区阈值 (m/s^2)。低于此阈值的加速度被认为是噪声,不参与积分。
|
||||||
|
// 设得太高会忽略真实的慢速启动,设得太低则无法有效抑制噪声。
|
||||||
|
#define ACC_DEAD_ZONE_THRESHOLD 0.05f
|
||||||
|
|
||||||
|
// --- 模拟摩擦力,进行速度衰减 ---
|
||||||
|
#define SPEED_ATTENUATION 1.0f //暂不模拟
|
||||||
|
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
BLE_KS_send_data_t KS_data;
|
||||||
|
debug_t debug1;
|
||||||
|
debug_t debug2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static skiing_tracker_t my_skiing_tracker;
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//实现
|
||||||
|
|
||||||
|
void clear_speed(void){
|
||||||
|
my_skiing_tracker.state = STATIC;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_detection(void){
|
||||||
|
my_skiing_tracker.state = STATIC;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.distance = 0;
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop_detection(void){
|
||||||
|
my_skiing_tracker.state = STOP_DETECTION;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker)
|
||||||
|
{
|
||||||
|
if (!tracker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 使用memset一次性清零整个结构体,包括新增的缓冲区
|
||||||
|
memset(tracker, 0, sizeof(skiing_tracker_t));
|
||||||
|
tracker->state = STATIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 将设备坐标系下的加速度转换为世界坐标系
|
||||||
|
* @param acc_device 设备坐标系下的加速度 [x, y, z]
|
||||||
|
* @param angle 姿态角 [pitch, roll, yaw],单位: 度
|
||||||
|
* @param acc_world 输出:世界坐标系下的加速度 [x, y, z]
|
||||||
|
*/
|
||||||
|
static void transform_acc_to_world_frame(const float *acc_device, const float *angle, float *acc_world)
|
||||||
|
{
|
||||||
|
// 驱动输出的角度与标准航空定义相反,需要取反才能用于标准旋转矩阵。
|
||||||
|
float pitch = -angle[0] * DEG_TO_RAD;
|
||||||
|
float roll = -angle[1] * DEG_TO_RAD;
|
||||||
|
|
||||||
|
// TODO: 当引入三轴磁力计后,这里的 yaw 应由磁力计和陀螺仪融合解算得出,以解决航向漂移问题。
|
||||||
|
// 目前 yaw 暂时不参与计算,因为仅靠加速度计和陀螺仪无法获得准确的绝对航向角。
|
||||||
|
// float yaw = -angle[2] * DEG_TO_RAD;
|
||||||
|
|
||||||
|
float cp = cosf(pitch);
|
||||||
|
float sp = sinf(pitch);
|
||||||
|
float cr = cosf(roll);
|
||||||
|
float sr = sinf(roll);
|
||||||
|
|
||||||
|
float ax = acc_device[0];
|
||||||
|
float ay = acc_device[1];
|
||||||
|
float az = acc_device[2];
|
||||||
|
|
||||||
|
// 使用经过验证的、正确的身体坐标系到世界坐标系的旋转矩阵 (基于 Y-X 旋转顺序)
|
||||||
|
// 这个矩阵将设备测量的加速度(ax, ay, az)正确地转换到世界坐标系(acc_world)。
|
||||||
|
// 注意:这里没有使用yaw,主要关心的是坡面上的运动,绝对航向暂时不影响速度和距离的计算。
|
||||||
|
// TODO
|
||||||
|
acc_world[0] = cp * ax + sp * sr * ay + sp * cr * az;
|
||||||
|
acc_world[1] = 0 * ax + cr * ay - sr * az;
|
||||||
|
acc_world[2] = -sp * ax + cp * sr * ay + cp * cr * az;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计算缓冲区内三轴数据的方差之和
|
||||||
|
*
|
||||||
|
* @param buffer 传进来的三轴数据:陀螺仪/加速度
|
||||||
|
* @return float 返回方差和
|
||||||
|
*/
|
||||||
|
static float calculate_variance(float buffer[VARIANCE_BUFFER_SIZE][3])
|
||||||
|
{
|
||||||
|
float mean[3] = {0};
|
||||||
|
float variance[3] = {0};
|
||||||
|
|
||||||
|
// 计算均值
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
mean[0] += buffer[i][0];
|
||||||
|
mean[1] += buffer[i][1];
|
||||||
|
mean[2] += buffer[i][2];
|
||||||
|
}
|
||||||
|
mean[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 计算方差
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
variance[0] += (buffer[i][0] - mean[0]) * (buffer[i][0] - mean[0]);
|
||||||
|
variance[1] += (buffer[i][1] - mean[1]) * (buffer[i][1] - mean[1]);
|
||||||
|
variance[2] += (buffer[i][2] - mean[2]) * (buffer[i][2] - mean[2]);
|
||||||
|
}
|
||||||
|
variance[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 返回三轴方差之和,作为一个综合的稳定度指标
|
||||||
|
return variance[0] + variance[1] + variance[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 状态机更新
|
||||||
|
*
|
||||||
|
* @param tracker 传入同步修改后传出
|
||||||
|
* @param acc_device_ms2 三轴加速度,m/s^2
|
||||||
|
* @param gyr_dps 三轴陀螺仪,dps
|
||||||
|
*/
|
||||||
|
static void update_state_machine(skiing_tracker_t *tracker, const float *acc_device_ms2, const float *gyr_dps)
|
||||||
|
{
|
||||||
|
// 缓冲区未填满时,不进行状态判断,默认为静止
|
||||||
|
if (!tracker->buffer_filled) {
|
||||||
|
tracker->state = STATIC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 计算关键指标 ---
|
||||||
|
float acc_variance = calculate_variance(tracker->acc_buffer); // 计算加速度方差
|
||||||
|
float gyr_variance = calculate_variance(tracker->gyr_buffer); // 计算陀螺仪方差
|
||||||
|
float gyr_magnitude = sqrtf(gyr_dps[0]*gyr_dps[0] + gyr_dps[1]*gyr_dps[1] + gyr_dps[2]*gyr_dps[2]);
|
||||||
|
float acc_magnitude = sqrtf(acc_device_ms2[0]*acc_device_ms2[0] + acc_device_ms2[1]*acc_device_ms2[1] + acc_device_ms2[2]*acc_device_ms2[2]);
|
||||||
|
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
debug1.acc_variance =acc_variance;
|
||||||
|
debug1.gyr_variance =gyr_variance;
|
||||||
|
debug1.gyr_magnitude=gyr_magnitude;
|
||||||
|
debug1.acc_magnitude=fabsf(acc_magnitude - G_ACCELERATION);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
//正在滑雪
|
||||||
|
if(tracker->state == NO_CONSTANT_SPEED ) {
|
||||||
|
//摔倒了
|
||||||
|
if(gyr_magnitude > FALLEN_GRY_MAG_THRESHOLD){
|
||||||
|
tracker->state = FALLEN;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//可能进入了匀速状态
|
||||||
|
if(gyr_magnitude > SKIING_GYR_MAG_THRESHOLD && acc_magnitude < SKIING_ACC_MAG_THRESHOLD){
|
||||||
|
tracker->state = CONSTANT_SPEED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//急转弯
|
||||||
|
if(gyr_magnitude > WHEEL_GYR_MAG_THRESHOLD && acc_variance > WHEEL_ACC_VARIANCE_THRESHOLD){
|
||||||
|
//TODO:可以考虑清掉速度消除积分带来的漂移
|
||||||
|
tracker->state = WHEEL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 状态切换逻辑 (按优先级) ---
|
||||||
|
// 优先级1:静止
|
||||||
|
if (acc_variance < ZUPT_ACC_VARIANCE_THRESHOLD && gyr_variance < ZUPT_GYR_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = STATIC;
|
||||||
|
// 速度清零,抑制漂移
|
||||||
|
memset(tracker->velocity, 0, sizeof(tracker->velocity));
|
||||||
|
tracker->speed = 0.0f;
|
||||||
|
memset(tracker->acc_world_unfiltered_prev, 0, sizeof(tracker->acc_world_unfiltered_prev));
|
||||||
|
memset(tracker->acc_world_filtered, 0, sizeof(tracker->acc_world_filtered));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 优先级2:原地旋转 - 特殊的、非滑雪的运动状态
|
||||||
|
// 条件:角速度很大,同时线性加速度的晃动在一个“中等”范围内。
|
||||||
|
if (tracker->state == STATIC && gyr_magnitude > ROTATION_GYR_MAG_THRESHOLD && acc_variance < ROTATING_ACC_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = ROTATING;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优先级3:启动滑雪 - “油门”
|
||||||
|
// 条件:有足够大的线性加速度,同时陀螺仪的抖动在一个“合理”(而非“完全静止”)的范围内。
|
||||||
|
if (fabsf(acc_magnitude - G_ACCELERATION) > START_SKIING_ACC_THRESHOLD && gyr_variance < SKIING_GYR_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果不满足任何启动或停止条件,则保持当前状态(滑雪中)
|
||||||
|
// 如果当前是静止或旋转,但没有满足启动条件,则状态会保持,直到满足ZUPT或旋转条件。
|
||||||
|
#else
|
||||||
|
|
||||||
|
// 无论当前是什么状态,静止总是最高优先级
|
||||||
|
if (acc_variance < ZUPT_ACC_VARIANCE_THRESHOLD && gyr_variance < ZUPT_GYR_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = STATIC;
|
||||||
|
// 速度清零,抑制漂移
|
||||||
|
memset(tracker->velocity, 0, sizeof(tracker->velocity));
|
||||||
|
tracker->speed = 0.0f;
|
||||||
|
memset(tracker->acc_world_unfiltered_prev, 0, sizeof(tracker->acc_world_unfiltered_prev));
|
||||||
|
memset(tracker->acc_world_filtered, 0, sizeof(tracker->acc_world_filtered));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (tracker->state) {
|
||||||
|
case STATIC:
|
||||||
|
//不break,会往下执行,判断是否进入非匀速状态
|
||||||
|
case ROTATING: // 从静止或原地旋转可以启动
|
||||||
|
if (fabsf(acc_magnitude - G_ACCELERATION) > START_SKIING_ACC_THRESHOLD && gyr_variance < SKIING_GYR_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
} else if (gyr_magnitude > ROTATION_GYR_MAG_THRESHOLD && acc_variance < ROTATING_ACC_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = ROTATING;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NO_CONSTANT_SPEED: //非匀速状态
|
||||||
|
if (gyr_magnitude > FALLEN_GRY_MAG_THRESHOLD) {
|
||||||
|
tracker->state = FALLEN; //摔倒
|
||||||
|
} else if (gyr_magnitude > WHEEL_GYR_MAG_THRESHOLD && acc_variance > WHEEL_ACC_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = WHEEL; //转弯
|
||||||
|
} else if (fabsf(acc_magnitude - G_ACCELERATION) < SKIING_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = CONSTANT_SPEED; //匀速
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONSTANT_SPEED: //匀速状态
|
||||||
|
if (fabsf(acc_magnitude - G_ACCELERATION) > START_SKIING_ACC_THRESHOLD) {
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
//TODO:可以添加进入转弯或摔倒的判断
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WHEEL:
|
||||||
|
// 从转弯状态,检查转弯是否结束
|
||||||
|
// 如果角速度和加速度方差都降下来了,就回到普通滑行状态
|
||||||
|
if (gyr_magnitude < WHEEL_GYR_MAG_THRESHOLD * 0.8f && acc_variance < WHEEL_ACC_VARIANCE_THRESHOLD * 0.8f) { // 乘以一个滞后系数避免抖动
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FALLEN:
|
||||||
|
// TODO:回到 STATIC
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 主更新函数
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
* @param acc_g 三轴加速度,g
|
||||||
|
* @param gyr_dps 三轴陀螺仪,dps
|
||||||
|
* @param angle 欧若拉角
|
||||||
|
* @param dt 采样时间间隔,会用来积分求速度
|
||||||
|
*/
|
||||||
|
void skiing_tracker_update(skiing_tracker_t *tracker, float *acc_g, float *gyr_dps, float *angle, float dt)
|
||||||
|
{
|
||||||
|
if (!tracker || !acc_g || !gyr_dps || !angle || dt <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(my_skiing_tracker.state == STOP_DETECTION)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// --- 数据预处理和缓冲 ---
|
||||||
|
float acc_device_ms2[3];
|
||||||
|
acc_device_ms2[0] = acc_g[0] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[1] = acc_g[1] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[2] = acc_g[2] * G_ACCELERATION;
|
||||||
|
|
||||||
|
// 将最新数据存入缓冲区
|
||||||
|
memcpy(tracker->acc_buffer[tracker->buffer_index], acc_device_ms2, sizeof(acc_device_ms2));
|
||||||
|
memcpy(tracker->gyr_buffer[tracker->buffer_index], gyr_dps, 3 * sizeof(float));
|
||||||
|
|
||||||
|
tracker->buffer_index++;
|
||||||
|
if (tracker->buffer_index >= VARIANCE_BUFFER_SIZE) {
|
||||||
|
tracker->buffer_index = 0;
|
||||||
|
tracker->buffer_filled = 1; // 标记缓冲区已满
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 更新状态机 ---
|
||||||
|
update_state_machine(tracker, acc_device_ms2, gyr_dps);
|
||||||
|
|
||||||
|
// 坐标转换 & 移除重力
|
||||||
|
transform_acc_to_world_frame(acc_device_ms2, angle, tracker->acc_world);
|
||||||
|
tracker->acc_world[2] -= G_ACCELERATION;
|
||||||
|
|
||||||
|
// 对世界坐标系下的加速度进行高通滤波,消除直流偏置和重力残差
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
tracker->acc_world_filtered[i] = HPF_ALPHA * (tracker->acc_world_filtered[i] + tracker->acc_world[i] - tracker->acc_world_unfiltered_prev[i]);
|
||||||
|
tracker->acc_world_unfiltered_prev[i] = tracker->acc_world[i];
|
||||||
|
}
|
||||||
|
// 应用加速度死区,忽略微小抖动和噪声
|
||||||
|
float acc_horizontal_mag = sqrtf(tracker->acc_world_filtered[0] * tracker->acc_world_filtered[0] +
|
||||||
|
tracker->acc_world_filtered[1] * tracker->acc_world_filtered[1]);
|
||||||
|
// --- 根据状态进行计算 ---
|
||||||
|
if (tracker->state == NO_CONSTANT_SPEED) {
|
||||||
|
if (acc_horizontal_mag > ACC_DEAD_ZONE_THRESHOLD) {
|
||||||
|
// 只有当水平加速度足够大时,才进行速度积分
|
||||||
|
tracker->velocity[0] += tracker->acc_world_filtered[0] * dt;
|
||||||
|
tracker->velocity[1] += tracker->acc_world_filtered[1] * dt;
|
||||||
|
// 垂直方向的速度暂时不积分,极易受姿态误差影响而漂移
|
||||||
|
// tracker->velocity[2] += tracker->acc_world_filtered[2] * dt;
|
||||||
|
}
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
debug2.acc_magnitude = acc_horizontal_mag;
|
||||||
|
#endif
|
||||||
|
// 如果加速度小于阈值,则不更新速度,相当于速度保持不变(或受下一步的阻尼影响而衰减)
|
||||||
|
|
||||||
|
// --- 更新速率和距离 ---
|
||||||
|
// 只基于水平速度计算速率和距离
|
||||||
|
tracker->speed = sqrtf(tracker->velocity[0] * tracker->velocity[0] +
|
||||||
|
tracker->velocity[1] * tracker->velocity[1]);
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
|
||||||
|
|
||||||
|
}else if(tracker->state == CONSTANT_SPEED){ //匀速
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
debug2.acc_magnitude = acc_horizontal_mag;
|
||||||
|
#endif
|
||||||
|
//保持上次的速度不变。只更新距离
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
|
||||||
|
}else{
|
||||||
|
// 在静止或旋转状态下,速度已经在状态机内部被清零
|
||||||
|
// 额外增加速度衰减,模拟摩擦力,进一步抑制漂移
|
||||||
|
tracker->velocity[0] *= SPEED_ATTENUATION;
|
||||||
|
tracker->velocity[1] *= SPEED_ATTENUATION;
|
||||||
|
tracker->velocity[2] = 0; // 垂直速度强制归零
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 传感器数据采集与处理任务,外部每10ms调用一次,如果需要更新时间间隔,也需要同步更新宏“ DELTA_TIME ”
|
||||||
|
*
|
||||||
|
* @param acc_data_buf 三轴加速度原始数据
|
||||||
|
* @param gyr_data_buf 三轴陀螺仪原始数据
|
||||||
|
* @return BLE_send_data_t
|
||||||
|
*/
|
||||||
|
BLE_send_data_t sensor_processing_task(signed short * acc_data_buf, signed short * gyr_data_buf) {
|
||||||
|
|
||||||
|
static int initialized = 0;
|
||||||
|
static int calibration_done = 0;
|
||||||
|
|
||||||
|
static signed short combined_raw_data[6];
|
||||||
|
static float final_angle_data[3]; // 计算得到的欧若拉角
|
||||||
|
static float calibrated_acc_g[3]; // 转换后的加速度计数据
|
||||||
|
static float calibrated_gyr_dps[3]; // 转换后的陀螺仪数据
|
||||||
|
|
||||||
|
const float delta_time = DELTA_TIME + 0.03f;
|
||||||
|
BLE_send_data_t BLE_send_data;
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
skiing_tracker_init(&my_skiing_tracker);
|
||||||
|
initialized = 1;
|
||||||
|
printf("Skiing Tracker Initialized. Waiting for sensor calibration...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&combined_raw_data[0], acc_data_buf, 3 * sizeof(signed short));
|
||||||
|
memcpy(&combined_raw_data[3], gyr_data_buf, 3 * sizeof(signed short));
|
||||||
|
|
||||||
|
unsigned char status;
|
||||||
|
if (!calibration_done) { //第1次启动,开启零漂检测
|
||||||
|
status = SL_SC7U22_Angle_Output(1, combined_raw_data, final_angle_data, 0);
|
||||||
|
if (status == 1) {
|
||||||
|
calibration_done = 1;
|
||||||
|
printf("Sensor calibration successful! Skiing mode is active.\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// printf("Calculate the time interval =============== start\n");
|
||||||
|
status = SL_SC7U22_Angle_Output(0, combined_raw_data, final_angle_data, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == 1) {
|
||||||
|
// 加速度 LSB to g
|
||||||
|
calibrated_acc_g[0] = (float)combined_raw_data[0] / 8192.0f;
|
||||||
|
calibrated_acc_g[1] = (float)combined_raw_data[1] / 8192.0f;
|
||||||
|
calibrated_acc_g[2] = (float)combined_raw_data[2] / 8192.0f;
|
||||||
|
|
||||||
|
// 陀螺仪 LSB to dps (度/秒)
|
||||||
|
// ±2000dps量程下,转换系数约为 0.061
|
||||||
|
calibrated_gyr_dps[0] = (float)combined_raw_data[3] * 0.061f;
|
||||||
|
calibrated_gyr_dps[1] = (float)combined_raw_data[4] * 0.061f;
|
||||||
|
calibrated_gyr_dps[2] = (float)combined_raw_data[5] * 0.061f;
|
||||||
|
|
||||||
|
skiing_tracker_update(&my_skiing_tracker, calibrated_acc_g, calibrated_gyr_dps, final_angle_data, delta_time);
|
||||||
|
|
||||||
|
// static int count = 0;
|
||||||
|
// if(count >= 10){
|
||||||
|
// printf("State: %d, Speed: %.2f m/s, Distance: %.2f m\n",
|
||||||
|
// my_skiing_tracker.state,
|
||||||
|
// my_skiing_tracker.speed,
|
||||||
|
// my_skiing_tracker.distance);
|
||||||
|
// printf("calibrated_acc_g: %.2f, %.2f, %.2f\n",
|
||||||
|
// calibrated_acc_g[0],
|
||||||
|
// calibrated_acc_g[1],
|
||||||
|
// calibrated_acc_g[2]);
|
||||||
|
// count = 0;
|
||||||
|
// } else {
|
||||||
|
// count++;
|
||||||
|
// }
|
||||||
|
|
||||||
|
BLE_send_data.sensor_state = status;
|
||||||
|
BLE_send_data.skiing_state = my_skiing_tracker.state;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
#ifndef XTELL_TEST
|
||||||
|
BLE_send_data.acc_original[i] = (int)acc_data_buf[i];
|
||||||
|
BLE_send_data.gyr_original[i] = (int)gyr_data_buf[i];
|
||||||
|
#endif
|
||||||
|
#if KS_BLE
|
||||||
|
KS_data.acc_KS[i] = (int)(calibrated_acc_g[i] * G_ACCELERATION * 100); //cm/s^s
|
||||||
|
KS_data.gyr_KS_dps[i] = (int)calibrated_gyr_dps[i];
|
||||||
|
KS_data.angle_KS[i] = (int)final_angle_data[i];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
BLE_send_data.speed_cms = (int)(my_skiing_tracker.speed * 100);
|
||||||
|
BLE_send_data.distance_cm = (int)(my_skiing_tracker.distance * 100);
|
||||||
|
// printf("Calculate the time interval =============== end\n");
|
||||||
|
} else if (status == 0) {
|
||||||
|
memset(&BLE_send_data, 0, sizeof(BLE_send_data_t));
|
||||||
|
BLE_send_data.sensor_state = status;
|
||||||
|
#if KS_BLE
|
||||||
|
memset(&KS_data, 0, sizeof(BLE_send_data_t));
|
||||||
|
#endif
|
||||||
|
// printf("Sensor is calibrating...\n");
|
||||||
|
} else {
|
||||||
|
memset(&BLE_send_data, 0, sizeof(BLE_send_data_t));
|
||||||
|
BLE_send_data.sensor_state = status;
|
||||||
|
#if KS_BLE
|
||||||
|
memset(&KS_data, 0, sizeof(BLE_send_data_t));
|
||||||
|
#endif
|
||||||
|
// printf("Angle calculation error or calibration not finished.\n");
|
||||||
|
}
|
||||||
|
return BLE_send_data;
|
||||||
|
}
|
||||||
85
apps/earphone/xtell_Sensor/A_hide/8/skiing_tracker.h
Normal file
85
apps/earphone/xtell_Sensor/A_hide/8/skiing_tracker.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#ifndef SKIING_TRACKER_H
|
||||||
|
#define SKIING_TRACKER_H
|
||||||
|
|
||||||
|
#include "../xtell.h"
|
||||||
|
// 定义滑雪者可能的状态
|
||||||
|
typedef enum {
|
||||||
|
STATIC, // 静止或动态稳定
|
||||||
|
NO_CONSTANT_SPEED, // 正在滑雪,非匀速
|
||||||
|
CONSTANT_SPEED, // 正在滑雪,匀速
|
||||||
|
ROTATING, // 正在原地旋转
|
||||||
|
WHEEL, // 转弯
|
||||||
|
FALLEN, // 已摔倒
|
||||||
|
STOP_DETECTION, // 停止检测
|
||||||
|
UNKNOWN // 未知状态
|
||||||
|
} skiing_state_t;
|
||||||
|
|
||||||
|
#define VARIANCE_BUFFER_SIZE 5 // 用于计算方差的数据窗口大小 (5个样本 @ 100Hz = 50ms),减小延迟,提高实时性
|
||||||
|
#define DELTA_TIME 0.01f
|
||||||
|
|
||||||
|
|
||||||
|
// 追踪器数据结构体
|
||||||
|
typedef struct {
|
||||||
|
// 公开数据
|
||||||
|
float velocity[3]; // 当前速度 (x, y, z),单位: m/s
|
||||||
|
float distance; // 总滑行距离,单位: m
|
||||||
|
float speed; // 当前速率 (标量),单位: m/s
|
||||||
|
skiing_state_t state; // 当前滑雪状态
|
||||||
|
|
||||||
|
// 内部计算使用的私有成员
|
||||||
|
float acc_world[3]; // 在世界坐标系下的加速度
|
||||||
|
|
||||||
|
// --- 内部计算使用的私有成员 ---
|
||||||
|
// 用于动态零速更新和旋转检测的缓冲区
|
||||||
|
float acc_buffer[VARIANCE_BUFFER_SIZE][3]; // 加速度数据窗口
|
||||||
|
float gyr_buffer[VARIANCE_BUFFER_SIZE][3]; // 角速度数据窗口
|
||||||
|
int buffer_index; // 缓冲区当前索引
|
||||||
|
int buffer_filled; // 缓冲区是否已填满的标志
|
||||||
|
|
||||||
|
// 用于高通滤波器(巴特沃斯一阶滤波器)的私有成员,以消除加速度的直流偏置
|
||||||
|
float acc_world_filtered[3]; //过滤过的
|
||||||
|
float acc_world_unfiltered_prev[3]; //上一次没过滤的
|
||||||
|
} skiing_tracker_t;
|
||||||
|
|
||||||
|
//ble发送的数据
|
||||||
|
typedef struct __attribute__((packed)){ //该结构体取消内存对齐
|
||||||
|
char sensor_state;
|
||||||
|
char skiing_state;
|
||||||
|
int speed_cms; //求出的速度,cm/s
|
||||||
|
int distance_cm; //求出的距离,cm
|
||||||
|
#ifndef XTELL_TEST
|
||||||
|
int acc_original[3]; //直接读取传感器得到的原始三轴加速度
|
||||||
|
int gyr_original[3]; //直接读取传感器得到的原始三轴陀螺仪
|
||||||
|
#endif
|
||||||
|
}BLE_send_data_t;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
int acc_KS[3]; //卡尔曼后,LSB转换后的 三轴加速度数据(cm/s^2)
|
||||||
|
int gyr_KS_dps[3]; //卡尔曼后,LSB to dps 三轴陀螺仪数据
|
||||||
|
int angle_KS[3]; //卡尔曼后,计算得到的欧若拉角数据
|
||||||
|
}BLE_KS_send_data_t;
|
||||||
|
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
typedef struct{
|
||||||
|
float acc_variance; //三轴加速度方差之和
|
||||||
|
float gyr_variance; //三轴陀螺仪方差之和
|
||||||
|
float acc_magnitude; //三轴加速度模长
|
||||||
|
float gyr_magnitude; //三轴陀螺仪模长
|
||||||
|
}debug_t;
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker 指向 skiing_tracker_t 结构体的指针
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 传感器数据采集与处理任务,外部每10ms调用一次,如果需要更新时间间隔,也需要同步更新宏“ DELTA_TIME ”
|
||||||
|
*
|
||||||
|
* @param acc_data_buf 三轴加速度原始数据
|
||||||
|
* @param gyr_data_buf 三轴陀螺仪原始数据
|
||||||
|
* @return BLE_send_data_t
|
||||||
|
*/
|
||||||
|
BLE_send_data_t sensor_processing_task(signed short * acc_data_buf, signed short * gyr_data_buf) ;
|
||||||
|
#endif // SKIING_TRACKER_H
|
||||||
583
apps/earphone/xtell_Sensor/A_hide/9/skiing_tracker.c
Normal file
583
apps/earphone/xtell_Sensor/A_hide/9/skiing_tracker.c
Normal file
@ -0,0 +1,583 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "skiing_tracker.h"
|
||||||
|
#include "../sensor/SC7U22.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define G_ACCELERATION 9.81f
|
||||||
|
#define DEG_TO_RAD (3.14159265f / 180.0f)
|
||||||
|
|
||||||
|
// --- 静止检测 ---
|
||||||
|
//两个判断是否静止的必要条件:动态零速更新(ZUPT)阈值
|
||||||
|
// 加速方差阈值,提高阈值,让“刹车”更灵敏,以便在波浪式前进等慢速漂移时也能触发零速更新
|
||||||
|
#define STOP_ACC_VARIANCE_THRESHOLD 0.2f
|
||||||
|
// 陀螺仪方差阈值
|
||||||
|
#define STOP_GYR_VARIANCE_THRESHOLD 5.0f
|
||||||
|
// 静止时候的陀螺仪模长
|
||||||
|
#define STOP_GYR_MAG_THRESHOLD 15
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 启动滑雪阈值 ---
|
||||||
|
// 加速度模长与重力的差值大于此值,认为开始运动;降低阈值,让“油门”更灵敏,以便能捕捉到真实的慢速启动
|
||||||
|
#define START_ACC_MAG_THRESHOLD 1.0f //0.5、1
|
||||||
|
// 陀螺仪方差阈值,以允许启动瞬间的正常抖动,但仍能过滤掉混乱的、非滑雪的晃动。
|
||||||
|
#define START_GYR_VARIANCE_THRESHOLD 15.0f
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 滑雪过程 ---
|
||||||
|
//加速度 模长(不含重力),低于此值视为 在做匀速运动
|
||||||
|
#define SKIING_ACC_MAG_THRESHOLD 0.5f
|
||||||
|
//陀螺仪 模长,高于此值视为 摔倒了
|
||||||
|
#define FALLEN_GRY_MAG_THRESHOLD 2000.0f //未确定
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 原地旋转抖动 ---
|
||||||
|
// 加速度 方差 阈值。此值比 静止检测 阈值更宽松,
|
||||||
|
#define WOBBLE_ACC_VARIANCE_THRESHOLD 0.5f
|
||||||
|
// 加速度 模长 阈值
|
||||||
|
#define WOBBLE_ACC_MAG_THRESHOLD 1.0f
|
||||||
|
// 角速度 总模长 大于此值(度/秒),认为正在进行非滑雪的旋转或摆动
|
||||||
|
#define ROTATION_GYR_MAG_THRESHOLD 30.0f
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 滑雪转弯动 ---
|
||||||
|
// 加速度 方差 阈值,大于此值,滑雪过程可能发生了急转弯
|
||||||
|
#define WHEEL_ACC_VARIANCE_THRESHOLD 7.0f
|
||||||
|
// 角速度 总模长 大于此值(度/秒),认为滑雪过程中进行急转弯
|
||||||
|
#define WHEEL_GYR_MAG_THRESHOLD 500.0f //
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 跳跃 ---
|
||||||
|
// 加速度模长低于此值(g),认为进入失重状态(IN_AIR)
|
||||||
|
#define AIRBORNE_ACC_MAG_LOW_THRESHOLD 0.4f
|
||||||
|
// 加速度模长高于此值(g),认为发生落地冲击(LANDING)
|
||||||
|
#define LANDING_ACC_MAG_HIGH_THRESHOLD 3.5f
|
||||||
|
// 起跳加速度阈值(g),用于进入TAKING_OFF状态
|
||||||
|
#define TAKEOFF_ACC_MAG_HIGH_THRESHOLD 1.8f
|
||||||
|
// 进入空中状态确认计数:需要连续3个采样点加速度低于阈值才判断为起跳
|
||||||
|
#define AIRBORNE_CONFIRM_COUNT 3
|
||||||
|
// 落地状态确认计数:加速度恢复到1g附近并持续2个采样点(20ms)则认为已落地
|
||||||
|
#define GROUNDED_CONFIRM_COUNT 2
|
||||||
|
// 最大滞空时间(秒),超过此时间强制认为已落地,防止状态锁死
|
||||||
|
#define MAX_TIME_IN_AIR 12.5f
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 用于消除积分漂移的滤波器和阈值 ---
|
||||||
|
// 高通滤波器系数 (alpha)。alpha 越接近1,滤除低频(直流偏移)的效果越强,但可能滤掉真实的慢速运动。
|
||||||
|
// alpha = RC / (RC + dt),参考RC电路而来,fc ≈ (1 - alpha) / (2 * π * dt)
|
||||||
|
#define HPF_ALPHA 0.999f
|
||||||
|
//0.995f: 0.08 Hz 的信号
|
||||||
|
//0.999f: 0.0159 Hz
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 低通滤波器 ---
|
||||||
|
// 低通滤波器系数 (alpha)。alpha 越小,滤波效果越强(更平滑),但延迟越大。
|
||||||
|
// alpha 推荐范围 0.7 ~ 0.95。可以从 0.85 开始尝试。
|
||||||
|
#define LPF_ALPHA 0.7f
|
||||||
|
|
||||||
|
// 加速度死区阈值 (m/s^2)。低于此阈值的加速度被认为是噪声,不参与积分。
|
||||||
|
// 设得太高会忽略真实的慢速启动,设得太低则无法有效抑制噪声。
|
||||||
|
//参考:0.2f ~ 0.4f
|
||||||
|
#define ACC_DEAD_ZONE_THRESHOLD 0.05f
|
||||||
|
|
||||||
|
// --- 模拟摩擦力,进行速度衰减 ---
|
||||||
|
#define SPEED_ATTENUATION 1.0f //暂不模拟
|
||||||
|
BLE_KS_send_data_t KS_data;
|
||||||
|
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
|
||||||
|
debug_t debug1;
|
||||||
|
debug_t debug2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static skiing_tracker_t my_skiing_tracker;
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//实现
|
||||||
|
|
||||||
|
void clear_speed(void){
|
||||||
|
my_skiing_tracker.state = STATIC;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_detection(void){
|
||||||
|
my_skiing_tracker.state = STATIC;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.distance = 0;
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop_detection(void){
|
||||||
|
my_skiing_tracker.state = STOP_DETECTION;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker)
|
||||||
|
{
|
||||||
|
if (!tracker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 使用memset一次性清零整个结构体,包括新增的缓冲区
|
||||||
|
memset(tracker, 0, sizeof(skiing_tracker_t));
|
||||||
|
tracker->state = STATIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 当检测到落地时,计算空中的水平飞行距离并累加到总距离
|
||||||
|
*/
|
||||||
|
static void calculate_air_distance(skiing_tracker_t *tracker) {
|
||||||
|
float horizontal_speed_on_takeoff = sqrtf(
|
||||||
|
tracker->initial_velocity_on_takeoff[0] * tracker->initial_velocity_on_takeoff[0] +
|
||||||
|
tracker->initial_velocity_on_takeoff[1] * tracker->initial_velocity_on_takeoff[1]
|
||||||
|
);
|
||||||
|
float distance_in_air = horizontal_speed_on_takeoff * tracker->time_in_air;
|
||||||
|
tracker->distance += distance_in_air;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 将设备坐标系下的加速度转换为世界坐标系
|
||||||
|
* @param acc_device 设备坐标系下的加速度 [x, y, z]
|
||||||
|
* @param angle 姿态角 [pitch, roll, yaw],单位: 度
|
||||||
|
* @param acc_world 输出:世界坐标系下的加速度 [x, y, z]
|
||||||
|
*/
|
||||||
|
static void transform_acc_to_world_frame(const float *acc_device, const float *angle, float *acc_world)
|
||||||
|
{
|
||||||
|
// 驱动输出的角度与标准航空定义相反,需要取反才能用于标准旋转矩阵。
|
||||||
|
float pitch = -angle[0] * DEG_TO_RAD;
|
||||||
|
float roll = -angle[1] * DEG_TO_RAD;
|
||||||
|
|
||||||
|
// TODO: 当引入三轴磁力计后,这里的 yaw 应由磁力计和陀螺仪融合解算得出,以解决航向漂移问题。
|
||||||
|
// 目前 yaw 暂时不参与计算,因为仅靠加速度计和陀螺仪无法获得准确的绝对航向角。
|
||||||
|
// float yaw = -angle[2] * DEG_TO_RAD;
|
||||||
|
|
||||||
|
float cp = cosf(pitch);
|
||||||
|
float sp = sinf(pitch);
|
||||||
|
float cr = cosf(roll);
|
||||||
|
float sr = sinf(roll);
|
||||||
|
|
||||||
|
float ax = acc_device[0];
|
||||||
|
float ay = acc_device[1];
|
||||||
|
float az = acc_device[2];
|
||||||
|
|
||||||
|
// 使用经过验证的、正确的身体坐标系到世界坐标系的旋转矩阵 (基于 Y-X 旋转顺序)
|
||||||
|
// 这个矩阵将设备测量的加速度(ax, ay, az)正确地转换到世界坐标系(acc_world)。
|
||||||
|
// 注意:这里没有使用yaw,主要关心的是坡面上的运动,绝对航向暂时不影响速度和距离的计算。
|
||||||
|
// TODO
|
||||||
|
acc_world[0] = cp * ax + sp * sr * ay + sp * cr * az;
|
||||||
|
acc_world[1] = 0 * ax + cr * ay - sr * az;
|
||||||
|
acc_world[2] = -sp * ax + cp * sr * ay + cp * cr * az;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计算缓冲区内三轴数据的方差之和
|
||||||
|
*
|
||||||
|
* @param buffer 传进来的三轴数据:陀螺仪/加速度
|
||||||
|
* @return float 返回方差和
|
||||||
|
*/
|
||||||
|
static float calculate_variance(float buffer[VARIANCE_BUFFER_SIZE][3])
|
||||||
|
{
|
||||||
|
float mean[3] = {0};
|
||||||
|
float variance[3] = {0};
|
||||||
|
|
||||||
|
// 计算均值
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
mean[0] += buffer[i][0];
|
||||||
|
mean[1] += buffer[i][1];
|
||||||
|
mean[2] += buffer[i][2];
|
||||||
|
}
|
||||||
|
mean[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 计算方差
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
variance[0] += (buffer[i][0] - mean[0]) * (buffer[i][0] - mean[0]);
|
||||||
|
variance[1] += (buffer[i][1] - mean[1]) * (buffer[i][1] - mean[1]);
|
||||||
|
variance[2] += (buffer[i][2] - mean[2]) * (buffer[i][2] - mean[2]);
|
||||||
|
}
|
||||||
|
variance[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 返回三轴方差之和,作为一个综合的稳定度指标
|
||||||
|
return variance[0] + variance[1] + variance[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 摩擦力模拟,进行速度衰减
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
*/
|
||||||
|
void forece_of_friction(skiing_tracker_t *tracker){
|
||||||
|
// 增加速度衰减,模拟摩擦力
|
||||||
|
tracker->velocity[0] *= SPEED_ATTENUATION;
|
||||||
|
tracker->velocity[1] *= SPEED_ATTENUATION;
|
||||||
|
tracker->velocity[2] = 0; // 垂直速度强制归零
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 状态机更新
|
||||||
|
*
|
||||||
|
* @param tracker 传入同步修改后传出
|
||||||
|
* @param acc_device_ms2 三轴加速度,m/s^2
|
||||||
|
* @param gyr_dps 三轴陀螺仪,dps
|
||||||
|
*/
|
||||||
|
static void update_state_machine(skiing_tracker_t *tracker, const float *acc_device_ms2, const float *gyr_dps)
|
||||||
|
{
|
||||||
|
// 缓冲区未填满时,不进行状态判断,默认为静止
|
||||||
|
if (!tracker->buffer_filled) {
|
||||||
|
tracker->state = STATIC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 计算关键指标 ---
|
||||||
|
float acc_variance = calculate_variance(tracker->acc_buffer); // 计算加速度方差
|
||||||
|
float gyr_variance = calculate_variance(tracker->gyr_buffer); // 计算陀螺仪方差
|
||||||
|
float gyr_magnitude = sqrtf(gyr_dps[0]*gyr_dps[0] + gyr_dps[1]*gyr_dps[1] + gyr_dps[2]*gyr_dps[2]); //dps
|
||||||
|
float acc_magnitude = sqrtf(acc_device_ms2[0]*acc_device_ms2[0] + acc_device_ms2[1]*acc_device_ms2[1] + acc_device_ms2[2]*acc_device_ms2[2]); //m/s^s
|
||||||
|
float acc_magnitude_g = acc_magnitude / G_ACCELERATION; // 转换为g单位,用于跳跃判断
|
||||||
|
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
debug1.acc_variance =acc_variance;
|
||||||
|
debug1.gyr_variance =gyr_variance;
|
||||||
|
debug1.gyr_magnitude=gyr_magnitude;
|
||||||
|
debug1.acc_magnitude=fabsf(acc_magnitude - G_ACCELERATION);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// --- 状态机逻辑 (核心修改区域) ---
|
||||||
|
|
||||||
|
#if 0 //暂时不考虑空中
|
||||||
|
// 1. 空中/落地状态的后续处理
|
||||||
|
if (tracker->state == IN_AIR) {
|
||||||
|
// A. 检测巨大冲击 -> 落地
|
||||||
|
if (acc_magnitude_g > LANDING_ACC_MAG_HIGH_THRESHOLD) {
|
||||||
|
tracker->state = LANDING;
|
||||||
|
// B. 检测超时 -> 强制落地 (安全机制)
|
||||||
|
} else if (tracker->time_in_air > MAX_TIME_IN_AIR) {
|
||||||
|
tracker->state = LANDING;
|
||||||
|
// C. 检测恢复正常重力 (平缓落地)
|
||||||
|
} else if (acc_magnitude_g > 0.8f && acc_magnitude_g < 1.5f) {
|
||||||
|
tracker->grounded_entry_counter++;
|
||||||
|
if (tracker->grounded_entry_counter >= GROUNDED_CONFIRM_COUNT) {
|
||||||
|
tracker->state = LANDING;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tracker->grounded_entry_counter = 0;
|
||||||
|
}
|
||||||
|
return; // 在空中或刚切换到落地,结束本次状态判断
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 严格的 "起跳->空中" 状态转换逻辑
|
||||||
|
// 只有当处于滑行状态时,才去检测起跳意图
|
||||||
|
if (tracker->state == NO_CONSTANT_SPEED || tracker->state == CONSTANT_SPEED || tracker->state == WHEEL) {
|
||||||
|
if (acc_magnitude_g > TAKEOFF_ACC_MAG_HIGH_THRESHOLD) {
|
||||||
|
tracker->state = TAKING_OFF;
|
||||||
|
tracker->airborne_entry_counter = 0; // 准备检测失重
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 只有在TAKING_OFF状态下,才去检测是否进入失重
|
||||||
|
if (tracker->state == TAKING_OFF) {
|
||||||
|
if (acc_magnitude_g < AIRBORNE_ACC_MAG_LOW_THRESHOLD) {
|
||||||
|
tracker->airborne_entry_counter++;
|
||||||
|
if (tracker->airborne_entry_counter >= AIRBORNE_CONFIRM_COUNT) {
|
||||||
|
memcpy(tracker->initial_velocity_on_takeoff, tracker->velocity, sizeof(tracker->velocity));
|
||||||
|
tracker->time_in_air = 0;
|
||||||
|
tracker->state = IN_AIR;
|
||||||
|
tracker->airborne_entry_counter = 0;
|
||||||
|
tracker->grounded_entry_counter = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果在起跳冲击后一段时间内没有失重,说明只是一个颠簸,恢复滑行
|
||||||
|
// 可以加一个小的超时计数器,这里为了简单先直接恢复
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
return; // 无论是否切换,都结束本次判断
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// --- 静止判断 ---
|
||||||
|
if (acc_variance < STOP_ACC_VARIANCE_THRESHOLD && gyr_variance < STOP_GYR_VARIANCE_THRESHOLD && gyr_magnitude < STOP_GYR_MAG_THRESHOLD) {
|
||||||
|
tracker->state = STATIC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 地面状态切换逻辑 ---
|
||||||
|
switch (tracker->state) {
|
||||||
|
case LANDING:
|
||||||
|
tracker->state = STATIC;
|
||||||
|
break;
|
||||||
|
case STATIC:
|
||||||
|
// 优先判断是否进入 WOBBLE 状态
|
||||||
|
// 条件:陀螺仪活动剧烈,但整体加速度变化不大(说明是原地转或晃)
|
||||||
|
if (gyr_magnitude > ROTATION_GYR_MAG_THRESHOLD && fabsf(acc_magnitude - G_ACCELERATION) < WOBBLE_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = WOBBLE;
|
||||||
|
}
|
||||||
|
// 只有在陀螺仪和加速度都满足“前进”特征时,才启动
|
||||||
|
else if (gyr_variance > START_GYR_VARIANCE_THRESHOLD && fabsf(acc_magnitude - G_ACCELERATION) > START_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WOBBLE:
|
||||||
|
// 从 WOBBLE 状态启动的条件应该和从 STATIC 启动一样严格
|
||||||
|
if (gyr_variance > START_GYR_VARIANCE_THRESHOLD && fabsf(acc_magnitude - G_ACCELERATION) > START_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
// 如果陀螺仪活动减弱,则可能恢复静止
|
||||||
|
else if (gyr_magnitude < ROTATION_GYR_MAG_THRESHOLD * 0.8f) { // 增加迟滞,避免抖动
|
||||||
|
// 不直接跳回STATIC,而是依赖下一轮的全局静止判断
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NO_CONSTANT_SPEED: //非匀速状态
|
||||||
|
//暂时不考虑摔倒
|
||||||
|
// if (gyr_magnitude > FALLEN_GRY_MAG_THRESHOLD) {
|
||||||
|
// tracker->state = FALLEN; //摔倒
|
||||||
|
// } else
|
||||||
|
if (gyr_magnitude > WHEEL_GYR_MAG_THRESHOLD && acc_variance > WHEEL_ACC_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = WHEEL; //转弯
|
||||||
|
} else if (fabsf(acc_magnitude - G_ACCELERATION) < SKIING_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = CONSTANT_SPEED; //匀速
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONSTANT_SPEED: //匀速状态
|
||||||
|
if (fabsf(acc_magnitude - G_ACCELERATION) > START_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
//TODO:可以添加进入转弯或摔倒的判断
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WHEEL:
|
||||||
|
// 从转弯状态,检查转弯是否结束
|
||||||
|
// 如果角速度和加速度方差都降下来了,就回到普通滑行状态
|
||||||
|
if (gyr_magnitude < WHEEL_GYR_MAG_THRESHOLD * 0.8f && acc_variance < WHEEL_ACC_VARIANCE_THRESHOLD * 0.8f) { // 乘以一个滞后系数避免抖动
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FALLEN:
|
||||||
|
// TODO:回到 STATIC
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 主更新函数
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
* @param acc_g 三轴加速度,g
|
||||||
|
* @param gyr_dps 三轴陀螺仪,dps
|
||||||
|
* @param angle 欧若拉角
|
||||||
|
* @param dt 采样时间间隔,会用来积分求速度
|
||||||
|
*/
|
||||||
|
void skiing_tracker_update(skiing_tracker_t *tracker, float *acc_g, float *gyr_dps, float *angle, float dt)
|
||||||
|
{
|
||||||
|
if (!tracker || !acc_g || !gyr_dps || !angle || dt <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(my_skiing_tracker.state == STOP_DETECTION)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// --- 数据预处理和缓冲 ---
|
||||||
|
float acc_device_ms2[3];
|
||||||
|
acc_device_ms2[0] = acc_g[0] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[1] = acc_g[1] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[2] = acc_g[2] * G_ACCELERATION;
|
||||||
|
|
||||||
|
// 将最新数据存入缓冲区
|
||||||
|
memcpy(tracker->acc_buffer[tracker->buffer_index], acc_device_ms2, sizeof(acc_device_ms2));
|
||||||
|
memcpy(tracker->gyr_buffer[tracker->buffer_index], gyr_dps, 3 * sizeof(float));
|
||||||
|
|
||||||
|
tracker->buffer_index++;
|
||||||
|
if (tracker->buffer_index >= VARIANCE_BUFFER_SIZE) {
|
||||||
|
tracker->buffer_index = 0;
|
||||||
|
tracker->buffer_filled = 1; // 标记缓冲区已满
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 更新状态机 ---
|
||||||
|
update_state_machine(tracker, acc_device_ms2, gyr_dps);
|
||||||
|
|
||||||
|
// --- 根据状态执行不同的计算逻辑 ---
|
||||||
|
switch (tracker->state) {
|
||||||
|
case TAKING_OFF:
|
||||||
|
tracker->speed = 0.0f;
|
||||||
|
break;
|
||||||
|
case IN_AIR:
|
||||||
|
// 在空中时,只累加滞空时间
|
||||||
|
tracker->time_in_air += dt;
|
||||||
|
break;
|
||||||
|
case LANDING:
|
||||||
|
// 刚落地,计算空中距离
|
||||||
|
calculate_air_distance(tracker);
|
||||||
|
// 清理速度和滤波器状态,为恢复地面追踪做准备
|
||||||
|
memset(tracker->velocity, 0, sizeof(tracker->velocity));
|
||||||
|
tracker->speed = 0;
|
||||||
|
memset(tracker->acc_world_unfiltered_prev, 0, sizeof(tracker->acc_world_unfiltered_prev));
|
||||||
|
memset(tracker->acc_world_filtered, 0, sizeof(tracker->acc_world_filtered));
|
||||||
|
memset(tracker->acc_world_lpf, 0, sizeof(tracker->acc_world_lpf)); // 清理新增的LPF状态
|
||||||
|
break;
|
||||||
|
case WHEEL:
|
||||||
|
case NO_CONSTANT_SPEED:
|
||||||
|
transform_acc_to_world_frame(acc_device_ms2, angle, tracker->acc_world);
|
||||||
|
tracker->acc_world[2] -= G_ACCELERATION;
|
||||||
|
|
||||||
|
float acc_world_temp[3]; // 临时变量存储当前周期的加速度
|
||||||
|
for (int i = 0; i < 2; i++) { // 只处理水平方向的 x 和 y 轴
|
||||||
|
|
||||||
|
// --- 核心修改:颠倒滤波器顺序为 HPF -> LPF ---
|
||||||
|
|
||||||
|
// 1. 高通滤波 (HPF) 先行: 消除因姿态误差导致的重力泄漏(直流偏置)
|
||||||
|
// HPF的瞬态响应会产生尖峰,这是正常的。
|
||||||
|
tracker->acc_world_filtered[i] = HPF_ALPHA * (tracker->acc_world_filtered[i] + tracker->acc_world[i] - tracker->acc_world_unfiltered_prev[i]);
|
||||||
|
tracker->acc_world_unfiltered_prev[i] = tracker->acc_world[i];
|
||||||
|
|
||||||
|
// 2. 低通滤波 (LPF) 殿后: 平滑掉HPF产生的尖峰和传感器自身的高频振动噪声。
|
||||||
|
// 这里使用 tracker->acc_world_filtered[i] 作为LPF的输入。
|
||||||
|
tracker->acc_world_lpf[i] = (1.0f - LPF_ALPHA) * tracker->acc_world_filtered[i] + LPF_ALPHA * tracker->acc_world_lpf[i];
|
||||||
|
|
||||||
|
// 将最终处理完的加速度值存入临时变量
|
||||||
|
acc_world_temp[i] = tracker->acc_world_lpf[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算处理后加速度的水平模长
|
||||||
|
float acc_horizontal_mag = sqrtf(acc_world_temp[0] * acc_world_temp[0] +
|
||||||
|
acc_world_temp[1] * acc_world_temp[1]);
|
||||||
|
#if XTELL_TEST
|
||||||
|
debug2.acc_magnitude = acc_horizontal_mag;
|
||||||
|
#endif
|
||||||
|
// 应用死区,并积分
|
||||||
|
if (acc_horizontal_mag > ACC_DEAD_ZONE_THRESHOLD) {
|
||||||
|
tracker->velocity[0] += acc_world_temp[0] * dt;
|
||||||
|
tracker->velocity[1] += acc_world_temp[1] * dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新速度和距离
|
||||||
|
tracker->speed = sqrtf(tracker->velocity[0] * tracker->velocity[0] +
|
||||||
|
tracker->velocity[1] * tracker->velocity[1]);
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
break;
|
||||||
|
case CONSTANT_SPEED:
|
||||||
|
//保持上次的速度不变。只更新距离
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
break;
|
||||||
|
case STATIC:
|
||||||
|
case WOBBLE:
|
||||||
|
// 速度清零,抑制漂移
|
||||||
|
memset(tracker->velocity, 0, sizeof(tracker->velocity));
|
||||||
|
tracker->speed = 0.0f;
|
||||||
|
memset(tracker->acc_world_unfiltered_prev, 0, sizeof(tracker->acc_world_unfiltered_prev));
|
||||||
|
memset(tracker->acc_world_filtered, 0, sizeof(tracker->acc_world_filtered));
|
||||||
|
memset(tracker->acc_world_lpf, 0, sizeof(tracker->acc_world_lpf)); // 清理新增的LPF状态
|
||||||
|
#if XTELL_TEST
|
||||||
|
debug2.acc_magnitude = 0;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case FALLEN:
|
||||||
|
// TODO
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 滑雪数据计算
|
||||||
|
*
|
||||||
|
* @param acc_data_buf 传入的三轴加速度数据
|
||||||
|
* @param gyr_data_buf 传入的三轴陀螺仪数据
|
||||||
|
* @param angle_data 传入的欧若拉角数据
|
||||||
|
* @return BLE_send_data_t 要发送给蓝牙的数据
|
||||||
|
*/
|
||||||
|
BLE_send_data_t sensor_processing_task(signed short* acc_data_buf, signed short* gyr_data_buf, float* angle_data) {
|
||||||
|
|
||||||
|
static int initialized = 0;
|
||||||
|
static float acc_data_g[3];
|
||||||
|
static float gyr_data_dps[3];
|
||||||
|
|
||||||
|
// const float delta_time = DELTA_TIME+0.01f;
|
||||||
|
// const float delta_time = DELTA_TIME + 0.005f;
|
||||||
|
const float delta_time = DELTA_TIME;
|
||||||
|
BLE_send_data_t BLE_send_data;
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
skiing_tracker_init(&my_skiing_tracker);
|
||||||
|
initialized = 1;
|
||||||
|
printf("Skiing Tracker Initialized. Waiting for sensor calibration...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if ACC_RANGE==2
|
||||||
|
// 加速度 LSB to g
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 16384.0f;
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 16384.0f;
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 16384.0f;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ACC_RANGE==4
|
||||||
|
// 加速度 LSB to g
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 8192.0f;
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 8192.0f;
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 8192.0f;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ACC_RANGE==8
|
||||||
|
//±8g 4096
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 4096.0f; //ax
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 4096.0f; //ay
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 4096.0f; //az
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ACC_RANGE==16
|
||||||
|
//±16g 2048
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 2048.0f; //ax
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 2048.0f; //ay
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 2048.0f; //az
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 陀螺仪 LSB to dps (度/秒)
|
||||||
|
// ±2000dps量程下,转换系数约为 0.061
|
||||||
|
gyr_data_dps[0] = (float)gyr_data_buf[0] * 0.061f;
|
||||||
|
gyr_data_dps[1] = (float)gyr_data_buf[1] * 0.061f;
|
||||||
|
gyr_data_dps[2] = (float)gyr_data_buf[2] * 0.061f;
|
||||||
|
|
||||||
|
skiing_tracker_update(&my_skiing_tracker, acc_data_g, gyr_data_dps, angle_data, delta_time);
|
||||||
|
|
||||||
|
BLE_send_data.skiing_state = my_skiing_tracker.state;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
BLE_send_data.acc_data[i] = (short)(acc_data_g[i] * 9.8f) * 100; //cm/^s2
|
||||||
|
BLE_send_data.gyr_data[i] = (short)gyr_data_dps[i]; //dps
|
||||||
|
BLE_send_data.angle_data[i] = angle_data[i];
|
||||||
|
#else
|
||||||
|
BLE_send_data.acc_data[i] = (short)acc_data_buf[i]; //原始adc数据
|
||||||
|
BLE_send_data.gyr_data[i] = (short)gyr_data_buf[i]; //原始adc数据
|
||||||
|
BLE_send_data.angle_data[i] = angle_data[i];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
BLE_send_data.speed_cms = (int)(my_skiing_tracker.speed * 100);
|
||||||
|
BLE_send_data.distance_cm = (int)(my_skiing_tracker.distance * 100);
|
||||||
|
// printf("Calculate the time interval =============== end\n");
|
||||||
|
|
||||||
|
return BLE_send_data;
|
||||||
|
}
|
||||||
|
|
||||||
88
apps/earphone/xtell_Sensor/A_hide/9/skiing_tracker.h
Normal file
88
apps/earphone/xtell_Sensor/A_hide/9/skiing_tracker.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#ifndef SKIING_TRACKER_H
|
||||||
|
#define SKIING_TRACKER_H
|
||||||
|
|
||||||
|
#include "../xtell.h"
|
||||||
|
// 定义滑雪者可能的状态
|
||||||
|
typedef enum {
|
||||||
|
STATIC, // 静止或动态稳定:0
|
||||||
|
NO_CONSTANT_SPEED, // 正在滑雪,非匀速:1
|
||||||
|
CONSTANT_SPEED, // 正在滑雪,匀速:2
|
||||||
|
WOBBLE, // 正在原地旋转:3
|
||||||
|
WHEEL, // 转弯:4
|
||||||
|
FALLEN, // 已摔倒:5
|
||||||
|
TAKING_OFF, // 起跳冲击阶段:6
|
||||||
|
IN_AIR, // 空中失重阶段:7
|
||||||
|
LANDING, // 落地冲击阶段:8
|
||||||
|
STOP_DETECTION, // 停止检测:9
|
||||||
|
UNKNOWN // 未知状态:10
|
||||||
|
} skiing_state_t;
|
||||||
|
|
||||||
|
#define VARIANCE_BUFFER_SIZE 5 // 用于计算方差的数据窗口大小 (5个样本 @ 100Hz = 50ms),减小延迟,提高实时性
|
||||||
|
#define DELTA_TIME 0.01f
|
||||||
|
|
||||||
|
|
||||||
|
// 追踪器数据结构体
|
||||||
|
typedef struct {
|
||||||
|
// 公开数据
|
||||||
|
float velocity[3]; // 当前速度 (x, y, z),单位: m/s
|
||||||
|
float distance; // 总滑行距离,单位: m
|
||||||
|
float speed; // 当前速率 (标量),单位: m/s
|
||||||
|
skiing_state_t state; // 当前滑雪状态
|
||||||
|
|
||||||
|
// 内部计算使用的私有成员
|
||||||
|
float acc_world[3]; // 在世界坐标系下的加速度
|
||||||
|
|
||||||
|
// 用于空中距离计算
|
||||||
|
float time_in_air; // 滞空时间计时器
|
||||||
|
float initial_velocity_on_takeoff[3]; // 起跳瞬间的速度向量
|
||||||
|
int airborne_entry_counter; // 进入空中状态的确认计数器
|
||||||
|
int grounded_entry_counter; // 落地确认计数器
|
||||||
|
|
||||||
|
// --- 内部计算使用的私有成员 ---
|
||||||
|
// 用于动态零速更新和旋转检测的缓冲区
|
||||||
|
float acc_buffer[VARIANCE_BUFFER_SIZE][3]; // 加速度数据窗口
|
||||||
|
float gyr_buffer[VARIANCE_BUFFER_SIZE][3]; // 角速度数据窗口
|
||||||
|
int buffer_index; // 缓冲区当前索引
|
||||||
|
int buffer_filled; // 缓冲区是否已填满的标志
|
||||||
|
|
||||||
|
// 用于高通滤波器(巴特沃斯一阶滤波器)的私有成员,以消除加速度的直流偏置
|
||||||
|
float acc_world_filtered[3]; //过滤过的
|
||||||
|
float acc_world_unfiltered_prev[3]; //上一次没过滤的
|
||||||
|
|
||||||
|
float acc_world_lpf[3]; // 经过低通滤波后的世界坐标系加速度
|
||||||
|
} skiing_tracker_t;
|
||||||
|
|
||||||
|
//ble发送的数据
|
||||||
|
typedef struct{ //__attribute__((packed)){ //该结构体取消内存对齐
|
||||||
|
char sensor_state;
|
||||||
|
char skiing_state;
|
||||||
|
int speed_cms; //求出的速度,cm/s
|
||||||
|
int distance_cm; //求出的距离,cm
|
||||||
|
short acc_data[3]; //三轴加速度, g
|
||||||
|
short gyr_data[3]; //三轴陀螺仪, dps
|
||||||
|
float angle_data[3]; //欧若拉角
|
||||||
|
}BLE_send_data_t;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
int acc_KS[3]; //卡尔曼后,LSB转换后的 三轴加速度数据(cm/s^2)
|
||||||
|
int gyr_KS_dps[3]; //卡尔曼后,LSB to dps 三轴陀螺仪数据
|
||||||
|
int angle_KS[3]; //卡尔曼后,计算得到的欧若拉角数据
|
||||||
|
}BLE_KS_send_data_t;
|
||||||
|
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
typedef struct{
|
||||||
|
float acc_variance; //三轴加速度方差之和
|
||||||
|
float gyr_variance; //三轴陀螺仪方差之和
|
||||||
|
float acc_magnitude; //三轴加速度模长
|
||||||
|
float gyr_magnitude; //三轴陀螺仪模长
|
||||||
|
}debug_t;
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker 指向 skiing_tracker_t 结构体的指针
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker);
|
||||||
|
|
||||||
|
BLE_send_data_t sensor_processing_task(signed short* acc_data_buf, signed short* gyr_data_buf, float* angle_data) ;
|
||||||
|
#endif // SKIING_TRACKER_H
|
||||||
651
apps/earphone/xtell_Sensor/A_hide/calculate/skiing_tracker.c
Normal file
651
apps/earphone/xtell_Sensor/A_hide/calculate/skiing_tracker.c
Normal file
@ -0,0 +1,651 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "skiing_tracker.h"
|
||||||
|
#include "../sensor/SC7U22.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define G_ACCELERATION 9.81f
|
||||||
|
#define DEG_TO_RAD (3.14159265f / 180.0f)
|
||||||
|
|
||||||
|
#define ENABLE_XLOG 1
|
||||||
|
#ifdef xlog
|
||||||
|
#undef xlog
|
||||||
|
#endif
|
||||||
|
#if ENABLE_XLOG
|
||||||
|
#define xlog(format, ...) printf("[XT:%s] " format, __func__, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define xlog(format, ...) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// --- 静止检测 ---
|
||||||
|
//两个判断是否静止的必要条件:动态零速更新(ZUPT)阈值
|
||||||
|
// 加速方差阈值,提高阈值,让“刹车”更灵敏,以便在波浪式前进等慢速漂移时也能触发零速更新
|
||||||
|
#define STOP_ACC_VARIANCE_THRESHOLD 0.2f
|
||||||
|
// 陀螺仪方差阈值
|
||||||
|
#define STOP_GYR_VARIANCE_THRESHOLD 5.0f
|
||||||
|
// 静止时候的陀螺仪模长
|
||||||
|
#define STOP_GYR_MAG_THRESHOLD 15
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 启动滑雪阈值 ---
|
||||||
|
// 加速度模长与重力的差值大于此值,认为开始运动;降低阈值,让“油门”更灵敏,以便能捕捉到真实的慢速启动
|
||||||
|
#define START_ACC_MAG_THRESHOLD 1.0f //0.5、1
|
||||||
|
// 陀螺仪方差阈值,以允许启动瞬间的正常抖动,但仍能过滤掉混乱的、非滑雪的晃动。
|
||||||
|
#define START_GYR_VARIANCE_THRESHOLD 15.0f
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 滑雪过程 ---
|
||||||
|
//加速度 模长(不含重力),低于此值视为 在做匀速运动
|
||||||
|
#define SKIING_ACC_MAG_THRESHOLD 0.5f
|
||||||
|
//陀螺仪 模长,高于此值视为 摔倒了
|
||||||
|
#define FALLEN_GRY_MAG_THRESHOLD 2000.0f //未确定
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 原地旋转抖动 ---
|
||||||
|
// 加速度 方差 阈值。此值比 静止检测 阈值更宽松,
|
||||||
|
#define WOBBLE_ACC_VARIANCE_THRESHOLD 0.5f
|
||||||
|
// 加速度 模长 阈值
|
||||||
|
#define WOBBLE_ACC_MAG_THRESHOLD 1.0f
|
||||||
|
// 角速度 总模长 大于此值(度/秒),认为正在进行非滑雪的旋转或摆动
|
||||||
|
#define ROTATION_GYR_MAG_THRESHOLD 30.0f
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 滑雪转弯动 ---
|
||||||
|
// 加速度 方差 阈值,大于此值,滑雪过程可能发生了急转弯
|
||||||
|
#define WHEEL_ACC_VARIANCE_THRESHOLD 7.0f
|
||||||
|
// 角速度 总模长 大于此值(度/秒),认为滑雪过程中进行急转弯
|
||||||
|
#define WHEEL_GYR_MAG_THRESHOLD 500.0f //
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 跳跃 ---
|
||||||
|
// 加速度模长低于此值(g),认为进入失重状态(IN_AIR)
|
||||||
|
#define AIRBORNE_ACC_MAG_LOW_THRESHOLD 0.4f
|
||||||
|
// 加速度模长高于此值(g),认为发生落地冲击(LANDING)
|
||||||
|
#define LANDING_ACC_MAG_HIGH_THRESHOLD 3.5f
|
||||||
|
// 起跳加速度阈值(g),用于进入TAKING_OFF状态
|
||||||
|
#define TAKEOFF_ACC_MAG_HIGH_THRESHOLD 1.8f
|
||||||
|
// 进入空中状态确认计数:需要连续3个采样点加速度低于阈值才判断为起跳
|
||||||
|
#define AIRBORNE_CONFIRM_COUNT 3
|
||||||
|
// 落地状态确认计数:加速度恢复到1g附近并持续2个采样点(20ms)则认为已落地
|
||||||
|
#define GROUNDED_CONFIRM_COUNT 2
|
||||||
|
// 最大滞空时间(秒),超过此时间强制认为已落地,防止状态锁死
|
||||||
|
#define MAX_TIME_IN_AIR 12.5f
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 用于消除积分漂移的滤波器和阈值 ---
|
||||||
|
// 高通滤波器系数 (alpha)。alpha 越接近1,滤除低频(直流偏移)的效果越强,但可能滤掉真实的慢速运动。
|
||||||
|
// alpha = RC / (RC + dt),参考RC电路而来,fc ≈ (1 - alpha) / (2 * π * dt)
|
||||||
|
#define HPF_ALPHA 0.999f
|
||||||
|
//0.995f: 0.08 Hz 的信号
|
||||||
|
//0.999f: 0.0159 Hz
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 低通滤波器 ---
|
||||||
|
// 低通滤波器系数 (alpha)。alpha 越小,滤波效果越强(更平滑),但延迟越大。
|
||||||
|
// alpha 推荐范围 0.7 ~ 0.95。可以从 0.85 开始尝试。
|
||||||
|
#define LPF_ALPHA 0.7f
|
||||||
|
|
||||||
|
// 加速度死区阈值 (m/s^2)。低于此阈值的加速度被认为是噪声,不参与积分。
|
||||||
|
// 设得太高会忽略真实的慢速启动,设得太低则无法有效抑制噪声。
|
||||||
|
//参考:0.2f ~ 0.4f
|
||||||
|
#define ACC_DEAD_ZONE_THRESHOLD 0.05f
|
||||||
|
|
||||||
|
// --- 模拟摩擦力,进行速度衰减 ---
|
||||||
|
#define SPEED_ATTENUATION 1.0f //暂不模拟
|
||||||
|
BLE_KS_send_data_t KS_data;
|
||||||
|
static float quaternion_data[4];
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
|
||||||
|
debug_t debug1;
|
||||||
|
debug_t debug2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static skiing_tracker_t my_skiing_tracker;
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//实现
|
||||||
|
|
||||||
|
void clear_speed(void){
|
||||||
|
my_skiing_tracker.state = STATIC;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_detection(void){
|
||||||
|
my_skiing_tracker.state = STATIC;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.distance = 0;
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop_detection(void){
|
||||||
|
my_skiing_tracker.state = STOP_DETECTION;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker)
|
||||||
|
{
|
||||||
|
if (!tracker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 使用memset一次性清零整个结构体,包括新增的缓冲区
|
||||||
|
memset(tracker, 0, sizeof(skiing_tracker_t));
|
||||||
|
tracker->state = STATIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 当检测到落地时,计算空中的水平飞行距离并累加到总距离
|
||||||
|
*/
|
||||||
|
static void calculate_air_distance(skiing_tracker_t *tracker) {
|
||||||
|
float horizontal_speed_on_takeoff = sqrtf(
|
||||||
|
tracker->initial_velocity_on_takeoff[0] * tracker->initial_velocity_on_takeoff[0] +
|
||||||
|
tracker->initial_velocity_on_takeoff[1] * tracker->initial_velocity_on_takeoff[1]
|
||||||
|
);
|
||||||
|
float distance_in_air = horizontal_speed_on_takeoff * tracker->time_in_air;
|
||||||
|
tracker->distance += distance_in_air;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 使用四元数直接从设备坐标系的加速度中移除重力分量
|
||||||
|
* @details 这种方法比使用欧拉角更精确、更稳定,且避免了万向节死锁。
|
||||||
|
* @param acc_device 输入:设备坐标系下的原始加速度 [x, y, z], 单位 m/s^2
|
||||||
|
* @param q 输入:表示姿态的四元数 [w, x, y, z]
|
||||||
|
* @param acc_linear_device 输出:设备坐标系下移除重力后的线性加速度 [x, y, z]
|
||||||
|
*/
|
||||||
|
void q_remove_gravity_with_quaternion(const float *acc_device, const float *q, float *acc_linear_device)
|
||||||
|
{
|
||||||
|
// 从四元数计算重力在设备坐标系下的投影
|
||||||
|
// G_device = R_transpose * G_world
|
||||||
|
// G_world = [0, 0, g]
|
||||||
|
// R_transpose 的第三列即为重力投影方向
|
||||||
|
float gx = 2.0f * (q[1] * q[3] - q[0] * q[2]);
|
||||||
|
float gy = 2.0f * (q[0] * q[1] + q[2] * q[3]);
|
||||||
|
float gz = q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3];
|
||||||
|
|
||||||
|
// 从原始加速度中减去重力分量
|
||||||
|
acc_linear_device[0] = acc_device[0] - gx * G_ACCELERATION;
|
||||||
|
acc_linear_device[1] = acc_device[1] - gy * G_ACCELERATION;
|
||||||
|
acc_linear_device[2] = acc_device[2] - gz * G_ACCELERATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 使用四元数将设备坐标系的线性加速度转换到世界坐标系
|
||||||
|
* @details 同样,此方法比使用欧拉角更优。
|
||||||
|
* @param acc_linear_device 输入:设备坐标系下的线性加速度 [x, y, z]
|
||||||
|
* @param q 输入:表示姿态的四元数 [w, x, y, z]
|
||||||
|
* @param acc_linear_world 输出:世界坐标系下的线性加速度 [x, y, z]
|
||||||
|
*/
|
||||||
|
void q_transform_to_world_with_quaternion(const float *acc_linear_device, const float *q, float *acc_linear_world)
|
||||||
|
{
|
||||||
|
// 这是 R_device_to_world * acc_linear_device 的展开形式
|
||||||
|
acc_linear_world[0] = (1.0f - 2.0f*q[2]*q[2] - 2.0f*q[3]*q[3]) * acc_linear_device[0] +
|
||||||
|
(2.0f*q[1]*q[2] - 2.0f*q[0]*q[3]) * acc_linear_device[1] +
|
||||||
|
(2.0f*q[1]*q[3] + 2.0f*q[0]*q[2]) * acc_linear_device[2];
|
||||||
|
|
||||||
|
acc_linear_world[1] = (2.0f*q[1]*q[2] + 2.0f*q[0]*q[3]) * acc_linear_device[0] +
|
||||||
|
(1.0f - 2.0f*q[1]*q[1] - 2.0f*q[3]*q[3]) * acc_linear_device[1] +
|
||||||
|
(2.0f*q[2]*q[3] - 2.0f*q[0]*q[1]) * acc_linear_device[2];
|
||||||
|
|
||||||
|
acc_linear_world[2] = (2.0f*q[1]*q[3] - 2.0f*q[0]*q[2]) * acc_linear_device[0] +
|
||||||
|
(2.0f*q[2]*q[3] + 2.0f*q[0]*q[1]) * acc_linear_device[1] +
|
||||||
|
(1.0f - 2.0f*q[1]*q[1] - 2.0f*q[2]*q[2]) * acc_linear_device[2];
|
||||||
|
// acc_linear_world[2] -= G_ACCELERATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计算缓冲区内三轴数据的方差之和
|
||||||
|
*
|
||||||
|
* @param buffer 传进来的三轴数据:陀螺仪/加速度
|
||||||
|
* @return float 返回方差和
|
||||||
|
*/
|
||||||
|
static float calculate_variance(float buffer[VARIANCE_BUFFER_SIZE][3])
|
||||||
|
{
|
||||||
|
float mean[3] = {0};
|
||||||
|
float variance[3] = {0};
|
||||||
|
|
||||||
|
// 计算均值
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
mean[0] += buffer[i][0];
|
||||||
|
mean[1] += buffer[i][1];
|
||||||
|
mean[2] += buffer[i][2];
|
||||||
|
}
|
||||||
|
mean[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 计算方差
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
variance[0] += (buffer[i][0] - mean[0]) * (buffer[i][0] - mean[0]);
|
||||||
|
variance[1] += (buffer[i][1] - mean[1]) * (buffer[i][1] - mean[1]);
|
||||||
|
variance[2] += (buffer[i][2] - mean[2]) * (buffer[i][2] - mean[2]);
|
||||||
|
}
|
||||||
|
variance[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 返回三轴方差之和,作为一个综合的稳定度指标
|
||||||
|
return variance[0] + variance[1] + variance[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 摩擦力模拟,进行速度衰减
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
*/
|
||||||
|
void forece_of_friction(skiing_tracker_t *tracker){
|
||||||
|
// 增加速度衰减,模拟摩擦力
|
||||||
|
tracker->velocity[0] *= SPEED_ATTENUATION;
|
||||||
|
tracker->velocity[1] *= SPEED_ATTENUATION;
|
||||||
|
tracker->velocity[2] = 0; // 垂直速度强制归零
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 状态机更新
|
||||||
|
*
|
||||||
|
* @param tracker 传入同步修改后传出
|
||||||
|
* @param acc_device_ms2 三轴加速度,m/s^2
|
||||||
|
* @param gyr_dps 三轴陀螺仪,dps
|
||||||
|
*/
|
||||||
|
static void update_state_machine(skiing_tracker_t *tracker, const float *acc_device_ms2, const float *gyr_dps)
|
||||||
|
{
|
||||||
|
// 缓冲区未填满时,不进行状态判断,默认为静止
|
||||||
|
if (!tracker->buffer_filled) {
|
||||||
|
tracker->state = STATIC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 计算关键指标 ---
|
||||||
|
float acc_variance = calculate_variance(tracker->acc_buffer); // 计算加速度方差
|
||||||
|
float gyr_variance = calculate_variance(tracker->gyr_buffer); // 计算陀螺仪方差
|
||||||
|
float gyr_magnitude = sqrtf(gyr_dps[0]*gyr_dps[0] + gyr_dps[1]*gyr_dps[1] + gyr_dps[2]*gyr_dps[2]); //dps
|
||||||
|
float acc_magnitude = sqrtf(acc_device_ms2[0]*acc_device_ms2[0] + acc_device_ms2[1]*acc_device_ms2[1] + acc_device_ms2[2]*acc_device_ms2[2]); //m/s^s
|
||||||
|
float acc_magnitude_g = acc_magnitude / G_ACCELERATION; // 转换为g单位,用于跳跃判断
|
||||||
|
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
debug1.acc_variance =acc_variance;
|
||||||
|
debug1.gyr_variance =gyr_variance;
|
||||||
|
debug1.gyr_magnitude=gyr_magnitude;
|
||||||
|
debug1.acc_magnitude=fabsf(acc_magnitude - G_ACCELERATION);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// --- 状态机逻辑 (核心修改区域) ---
|
||||||
|
|
||||||
|
#if 0 //暂时不考虑空中
|
||||||
|
// 1. 空中/落地状态的后续处理
|
||||||
|
if (tracker->state == IN_AIR) {
|
||||||
|
// A. 检测巨大冲击 -> 落地
|
||||||
|
if (acc_magnitude_g > LANDING_ACC_MAG_HIGH_THRESHOLD) {
|
||||||
|
tracker->state = LANDING;
|
||||||
|
// B. 检测超时 -> 强制落地 (安全机制)
|
||||||
|
} else if (tracker->time_in_air > MAX_TIME_IN_AIR) {
|
||||||
|
tracker->state = LANDING;
|
||||||
|
// C. 检测恢复正常重力 (平缓落地)
|
||||||
|
} else if (acc_magnitude_g > 0.8f && acc_magnitude_g < 1.5f) {
|
||||||
|
tracker->grounded_entry_counter++;
|
||||||
|
if (tracker->grounded_entry_counter >= GROUNDED_CONFIRM_COUNT) {
|
||||||
|
tracker->state = LANDING;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tracker->grounded_entry_counter = 0;
|
||||||
|
}
|
||||||
|
return; // 在空中或刚切换到落地,结束本次状态判断
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 严格的 "起跳->空中" 状态转换逻辑
|
||||||
|
// 只有当处于滑行状态时,才去检测起跳意图
|
||||||
|
if (tracker->state == NO_CONSTANT_SPEED || tracker->state == CONSTANT_SPEED || tracker->state == WHEEL) {
|
||||||
|
if (acc_magnitude_g > TAKEOFF_ACC_MAG_HIGH_THRESHOLD) {
|
||||||
|
tracker->state = TAKING_OFF;
|
||||||
|
tracker->airborne_entry_counter = 0; // 准备检测失重
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 只有在TAKING_OFF状态下,才去检测是否进入失重
|
||||||
|
if (tracker->state == TAKING_OFF) {
|
||||||
|
if (acc_magnitude_g < AIRBORNE_ACC_MAG_LOW_THRESHOLD) {
|
||||||
|
tracker->airborne_entry_counter++;
|
||||||
|
if (tracker->airborne_entry_counter >= AIRBORNE_CONFIRM_COUNT) {
|
||||||
|
memcpy(tracker->initial_velocity_on_takeoff, tracker->velocity, sizeof(tracker->velocity));
|
||||||
|
tracker->time_in_air = 0;
|
||||||
|
tracker->state = IN_AIR;
|
||||||
|
tracker->airborne_entry_counter = 0;
|
||||||
|
tracker->grounded_entry_counter = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果在起跳冲击后一段时间内没有失重,说明只是一个颠簸,恢复滑行
|
||||||
|
// 可以加一个小的超时计数器,这里为了简单先直接恢复
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
return; // 无论是否切换,都结束本次判断
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// --- 静止判断 ---
|
||||||
|
if (acc_variance < STOP_ACC_VARIANCE_THRESHOLD && gyr_variance < STOP_GYR_VARIANCE_THRESHOLD && gyr_magnitude < STOP_GYR_MAG_THRESHOLD) {
|
||||||
|
tracker->state = STATIC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 地面状态切换逻辑 ---
|
||||||
|
switch (tracker->state) {
|
||||||
|
case LANDING:
|
||||||
|
tracker->state = STATIC;
|
||||||
|
break;
|
||||||
|
case STATIC:
|
||||||
|
// 优先判断是否进入 WOBBLE 状态
|
||||||
|
// 条件:陀螺仪活动剧烈,但整体加速度变化不大(说明是原地转或晃)
|
||||||
|
if (gyr_magnitude > ROTATION_GYR_MAG_THRESHOLD && fabsf(acc_magnitude - G_ACCELERATION) < WOBBLE_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = WOBBLE;
|
||||||
|
}
|
||||||
|
// 只有在陀螺仪和加速度都满足“前进”特征时,才启动
|
||||||
|
else if (gyr_variance > START_GYR_VARIANCE_THRESHOLD && fabsf(acc_magnitude - G_ACCELERATION) > START_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WOBBLE:
|
||||||
|
// 从 WOBBLE 状态启动的条件应该和从 STATIC 启动一样严格
|
||||||
|
if (gyr_variance < START_GYR_VARIANCE_THRESHOLD * 2 && fabsf(acc_magnitude - G_ACCELERATION) > START_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
// 如果陀螺仪活动减弱,则可能恢复静止
|
||||||
|
else if (gyr_magnitude < ROTATION_GYR_MAG_THRESHOLD * 0.8f) { // 增加迟滞,避免抖动
|
||||||
|
// 不直接跳回STATIC,而是依赖下一轮的全局静止判断
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NO_CONSTANT_SPEED: //非匀速状态
|
||||||
|
//暂时不考虑摔倒
|
||||||
|
// if (gyr_magnitude > FALLEN_GRY_MAG_THRESHOLD) {
|
||||||
|
// tracker->state = FALLEN; //摔倒
|
||||||
|
// } else
|
||||||
|
if (gyr_magnitude > WHEEL_GYR_MAG_THRESHOLD && acc_variance > WHEEL_ACC_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = WHEEL; //转弯
|
||||||
|
} else if (fabsf(acc_magnitude - G_ACCELERATION) < SKIING_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = CONSTANT_SPEED; //匀速
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONSTANT_SPEED: //匀速状态
|
||||||
|
if (fabsf(acc_magnitude - G_ACCELERATION) > START_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
//TODO:可以添加进入转弯或摔倒的判断
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WHEEL:
|
||||||
|
// 从转弯状态,检查转弯是否结束
|
||||||
|
// 如果角速度和加速度方差都降下来了,就回到普通滑行状态
|
||||||
|
if (gyr_magnitude < WHEEL_GYR_MAG_THRESHOLD * 0.8f && acc_variance < WHEEL_ACC_VARIANCE_THRESHOLD * 0.8f) { // 乘以一个滞后系数避免抖动
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FALLEN:
|
||||||
|
// TODO:回到 STATIC
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 主更新函数
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
* @param acc_g 三轴加速度,g
|
||||||
|
* @param gyr_dps 三轴陀螺仪,dps
|
||||||
|
* @param angle 欧若拉角
|
||||||
|
* @param dt 采样时间间隔,会用来积分求速度
|
||||||
|
*/
|
||||||
|
void skiing_tracker_update(skiing_tracker_t *tracker, float *acc_g, float *gyr_dps, float *angle, float dt)
|
||||||
|
{
|
||||||
|
if (!tracker || !acc_g || !gyr_dps || !angle || dt <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(my_skiing_tracker.state == STOP_DETECTION)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// --- 数据预处理和缓冲 ---
|
||||||
|
float acc_device_ms2[3];
|
||||||
|
acc_device_ms2[0] = acc_g[0] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[1] = acc_g[1] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[2] = acc_g[2] * G_ACCELERATION;
|
||||||
|
|
||||||
|
// 将最新数据存入缓冲区
|
||||||
|
memcpy(tracker->acc_buffer[tracker->buffer_index], acc_device_ms2, sizeof(acc_device_ms2));
|
||||||
|
memcpy(tracker->gyr_buffer[tracker->buffer_index], gyr_dps, 3 * sizeof(float));
|
||||||
|
|
||||||
|
tracker->buffer_index++;
|
||||||
|
if (tracker->buffer_index >= VARIANCE_BUFFER_SIZE) {
|
||||||
|
tracker->buffer_index = 0;
|
||||||
|
tracker->buffer_filled = 1; // 标记缓冲区已满
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 更新状态机 ---
|
||||||
|
update_state_machine(tracker, acc_device_ms2, gyr_dps);
|
||||||
|
|
||||||
|
// --- 根据状态执行不同的计算逻辑 ---
|
||||||
|
switch (tracker->state) {
|
||||||
|
case TAKING_OFF:
|
||||||
|
tracker->speed = 0.0f;
|
||||||
|
break;
|
||||||
|
case IN_AIR:
|
||||||
|
// 在空中时,只累加滞空时间
|
||||||
|
tracker->time_in_air += dt;
|
||||||
|
break;
|
||||||
|
case LANDING:
|
||||||
|
// 刚落地,计算空中距离
|
||||||
|
calculate_air_distance(tracker);
|
||||||
|
// 清理速度和滤波器状态,为恢复地面追踪做准备
|
||||||
|
memset(tracker->velocity, 0, sizeof(tracker->velocity));
|
||||||
|
tracker->speed = 0;
|
||||||
|
memset(tracker->acc_world_unfiltered_prev, 0, sizeof(tracker->acc_world_unfiltered_prev));
|
||||||
|
memset(tracker->acc_world_filtered, 0, sizeof(tracker->acc_world_filtered));
|
||||||
|
memset(tracker->acc_world_lpf, 0, sizeof(tracker->acc_world_lpf)); // 清理新增的LPF状态
|
||||||
|
break;
|
||||||
|
case WHEEL:
|
||||||
|
case NO_CONSTANT_SPEED:
|
||||||
|
float linear_acc_device[3];
|
||||||
|
float linear_acc_world[3];
|
||||||
|
// 在设备坐标系下,移除重力,得到线性加速度
|
||||||
|
q_remove_gravity_with_quaternion(acc_device_ms2, quaternion_data, linear_acc_device);
|
||||||
|
|
||||||
|
// 将设备坐标系下的线性加速度,旋转到世界坐标系
|
||||||
|
q_transform_to_world_with_quaternion(linear_acc_device, quaternion_data, linear_acc_world);
|
||||||
|
// 将最终用于积分的加速度存入 tracker 结构体
|
||||||
|
memcpy(tracker->acc_no_g, linear_acc_world, sizeof(linear_acc_world));
|
||||||
|
|
||||||
|
float acc_world_temp[3]; // 临时变量存储当前周期的加速度
|
||||||
|
for (int i = 0; i < 2; i++) { // 只处理水平方向的 x 和 y 轴
|
||||||
|
|
||||||
|
// --- 核心修改:颠倒滤波器顺序为 HPF -> LPF ---
|
||||||
|
|
||||||
|
// 1. 高通滤波 (HPF) 先行: 消除因姿态误差导致的重力泄漏(直流偏置)
|
||||||
|
// HPF的瞬态响应会产生尖峰,这是正常的。
|
||||||
|
tracker->acc_world_filtered[i] = HPF_ALPHA * (tracker->acc_world_filtered[i] + tracker->acc_no_g[i] - tracker->acc_world_unfiltered_prev[i]);
|
||||||
|
tracker->acc_world_unfiltered_prev[i] = tracker->acc_no_g[i];
|
||||||
|
|
||||||
|
// 2. 低通滤波 (LPF) 殿后: 平滑掉HPF产生的尖峰和传感器自身的高频振动噪声。
|
||||||
|
// 这里使用 tracker->acc_world_filtered[i] 作为LPF的输入。
|
||||||
|
tracker->acc_world_lpf[i] = (1.0f - LPF_ALPHA) * tracker->acc_world_filtered[i] + LPF_ALPHA * tracker->acc_world_lpf[i];
|
||||||
|
|
||||||
|
// 将最终处理完的加速度值存入临时变量
|
||||||
|
acc_world_temp[i] = tracker->acc_world_lpf[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算处理后加速度的水平模长
|
||||||
|
float acc_horizontal_mag = sqrtf(acc_world_temp[0] * acc_world_temp[0] +
|
||||||
|
acc_world_temp[1] * acc_world_temp[1]);
|
||||||
|
#if XTELL_TEST
|
||||||
|
debug2.acc_magnitude = acc_horizontal_mag;
|
||||||
|
#endif
|
||||||
|
// 应用死区,并积分
|
||||||
|
if (acc_horizontal_mag > ACC_DEAD_ZONE_THRESHOLD) {
|
||||||
|
tracker->velocity[0] += acc_world_temp[0] * dt;
|
||||||
|
tracker->velocity[1] += acc_world_temp[1] * dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新速度和距离
|
||||||
|
tracker->speed = sqrtf(tracker->velocity[0] * tracker->velocity[0] +
|
||||||
|
tracker->velocity[1] * tracker->velocity[1]);
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
break;
|
||||||
|
case CONSTANT_SPEED:
|
||||||
|
//保持上次的速度不变。只更新距离
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
break;
|
||||||
|
case STATIC:
|
||||||
|
case WOBBLE:
|
||||||
|
// 速度清零,抑制漂移
|
||||||
|
memset(tracker->velocity, 0, sizeof(tracker->velocity));
|
||||||
|
tracker->speed = 0.0f;
|
||||||
|
memset(tracker->acc_world_unfiltered_prev, 0, sizeof(tracker->acc_world_unfiltered_prev));
|
||||||
|
memset(tracker->acc_world_filtered, 0, sizeof(tracker->acc_world_filtered));
|
||||||
|
memset(tracker->acc_world_lpf, 0, sizeof(tracker->acc_world_lpf)); // 清理新增的LPF状态
|
||||||
|
#if XTELL_TEST
|
||||||
|
debug2.acc_magnitude = 0;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case FALLEN:
|
||||||
|
// TODO
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
float linear_acc_device[3];
|
||||||
|
float linear_acc_world[3];
|
||||||
|
float tmp_world_acc[3];
|
||||||
|
// 在设备坐标系下,移除重力,得到线性加速度
|
||||||
|
q_remove_gravity_with_quaternion(acc_device_ms2, quaternion_data, linear_acc_device);
|
||||||
|
|
||||||
|
// 将设备坐标系下的线性加速度,旋转到世界坐标系
|
||||||
|
q_transform_to_world_with_quaternion(linear_acc_device, quaternion_data, tmp_world_acc);
|
||||||
|
|
||||||
|
|
||||||
|
float all_world_mag = sqrtf(tmp_world_acc[0] * tmp_world_acc[0] +
|
||||||
|
tmp_world_acc[1] * tmp_world_acc[1] +
|
||||||
|
tmp_world_acc[2] * tmp_world_acc[2]);
|
||||||
|
|
||||||
|
static int count = 0;
|
||||||
|
if(count > 100){
|
||||||
|
xlog("===original(g): x %.2f, y %.2f, z %.2f===\n",acc_g[0],acc_g[1],acc_g[2]);
|
||||||
|
xlog("===world(m/s^2) no g: x %.2f, y %.2f, z %.2f, all %.2f===\n",tmp_world_acc[0],tmp_world_acc[1],tmp_world_acc[2],all_world_mag); //去掉重力加速度
|
||||||
|
xlog("===gyr(dps) : x %.2f, y %.2f, z %.2f===\n",gyr_dps[0],gyr_dps[1],gyr_dps[2]); //angle
|
||||||
|
xlog("===angle : x %.2f, y %.2f, z %.2f,===\n",angle[0],angle[1],angle[2]);
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 滑雪数据计算
|
||||||
|
*
|
||||||
|
* @param acc_data_buf 传入的三轴加速度数据
|
||||||
|
* @param gyr_data_buf 传入的三轴陀螺仪数据
|
||||||
|
* @param angle_data 传入的欧若拉角数据
|
||||||
|
* @return BLE_send_data_t 要发送给蓝牙的数据
|
||||||
|
*/
|
||||||
|
BLE_send_data_t sensor_processing_task(signed short* acc_data_buf, signed short* gyr_data_buf, float* angle_data, float* quaternion) {
|
||||||
|
|
||||||
|
static int initialized = 0;
|
||||||
|
static float acc_data_g[3];
|
||||||
|
static float gyr_data_dps[3];
|
||||||
|
|
||||||
|
if(quaternion != NULL){
|
||||||
|
memcpy(quaternion_data, quaternion, 4 * sizeof(float));
|
||||||
|
}
|
||||||
|
|
||||||
|
// const float delta_time = DELTA_TIME+0.01f;
|
||||||
|
// const float delta_time = DELTA_TIME + 0.005f;
|
||||||
|
const float delta_time = DELTA_TIME;
|
||||||
|
BLE_send_data_t BLE_send_data;
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
skiing_tracker_init(&my_skiing_tracker);
|
||||||
|
initialized = 1;
|
||||||
|
printf("Skiing Tracker Initialized. Waiting for sensor calibration...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if ACC_RANGE==2
|
||||||
|
// 加速度 LSB to g
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 16384.0f;
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 16384.0f;
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 16384.0f;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ACC_RANGE==4
|
||||||
|
// 加速度 LSB to g
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 8192.0f;
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 8192.0f;
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 8192.0f;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ACC_RANGE==8
|
||||||
|
//±8g 4096
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 4096.0f; //ax
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 4096.0f; //ay
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 4096.0f; //az
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ACC_RANGE==16
|
||||||
|
//±16g 2048
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 2048.0f; //ax
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 2048.0f; //ay
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 2048.0f; //az
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 陀螺仪 LSB to dps (度/秒)
|
||||||
|
// ±2000dps量程下,转换系数约为 0.061
|
||||||
|
gyr_data_dps[0] = (float)gyr_data_buf[0] * 0.061f;
|
||||||
|
gyr_data_dps[1] = (float)gyr_data_buf[1] * 0.061f;
|
||||||
|
gyr_data_dps[2] = (float)gyr_data_buf[2] * 0.061f;
|
||||||
|
|
||||||
|
skiing_tracker_update(&my_skiing_tracker, acc_data_g, gyr_data_dps, angle_data, delta_time);
|
||||||
|
|
||||||
|
BLE_send_data.skiing_state = my_skiing_tracker.state;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
BLE_send_data.acc_data[i] = (short)(acc_data_g[i] * 9.8f) * 100; //cm/^s2
|
||||||
|
BLE_send_data.gyr_data[i] = (short)gyr_data_dps[i]; //dps
|
||||||
|
BLE_send_data.angle_data[i] = angle_data[i];
|
||||||
|
#else
|
||||||
|
BLE_send_data.acc_data[i] = (short)acc_data_buf[i]; //原始adc数据
|
||||||
|
BLE_send_data.gyr_data[i] = (short)gyr_data_buf[i]; //原始adc数据
|
||||||
|
BLE_send_data.angle_data[i] = angle_data[i];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
BLE_send_data.speed_cms = (int)(my_skiing_tracker.speed * 100);
|
||||||
|
BLE_send_data.distance_cm = (int)(my_skiing_tracker.distance * 100);
|
||||||
|
// printf("Calculate the time interval =============== end\n");
|
||||||
|
|
||||||
|
return BLE_send_data;
|
||||||
|
}
|
||||||
|
|
||||||
88
apps/earphone/xtell_Sensor/A_hide/calculate/skiing_tracker.h
Normal file
88
apps/earphone/xtell_Sensor/A_hide/calculate/skiing_tracker.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#ifndef SKIING_TRACKER_H
|
||||||
|
#define SKIING_TRACKER_H
|
||||||
|
|
||||||
|
#include "../xtell.h"
|
||||||
|
// 定义滑雪者可能的状态
|
||||||
|
typedef enum {
|
||||||
|
STATIC, // 静止或动态稳定:0
|
||||||
|
NO_CONSTANT_SPEED, // 正在滑雪,非匀速:1
|
||||||
|
CONSTANT_SPEED, // 正在滑雪,匀速:2
|
||||||
|
WOBBLE, // 正在原地旋转:3
|
||||||
|
WHEEL, // 转弯:4
|
||||||
|
FALLEN, // 已摔倒:5
|
||||||
|
TAKING_OFF, // 起跳冲击阶段:6
|
||||||
|
IN_AIR, // 空中失重阶段:7
|
||||||
|
LANDING, // 落地冲击阶段:8
|
||||||
|
STOP_DETECTION, // 停止检测:9
|
||||||
|
UNKNOWN // 未知状态:10
|
||||||
|
} skiing_state_t;
|
||||||
|
|
||||||
|
#define VARIANCE_BUFFER_SIZE 5 // 用于计算方差的数据窗口大小 (5个样本 @ 100Hz = 50ms),减小延迟,提高实时性
|
||||||
|
#define DELTA_TIME 0.01f
|
||||||
|
|
||||||
|
|
||||||
|
// 追踪器数据结构体
|
||||||
|
typedef struct {
|
||||||
|
// 公开数据
|
||||||
|
float velocity[3]; // 当前速度 (x, y, z),单位: m/s
|
||||||
|
float distance; // 总滑行距离,单位: m
|
||||||
|
float speed; // 当前速率 (标量),单位: m/s
|
||||||
|
skiing_state_t state; // 当前滑雪状态
|
||||||
|
|
||||||
|
// 内部计算使用的私有成员
|
||||||
|
float acc_no_g[3]; // 去掉重力分量后的加速度
|
||||||
|
|
||||||
|
// 用于空中距离计算
|
||||||
|
float time_in_air; // 滞空时间计时器
|
||||||
|
float initial_velocity_on_takeoff[3]; // 起跳瞬间的速度向量
|
||||||
|
int airborne_entry_counter; // 进入空中状态的确认计数器
|
||||||
|
int grounded_entry_counter; // 落地确认计数器
|
||||||
|
|
||||||
|
// --- 内部计算使用的私有成员 ---
|
||||||
|
// 用于动态零速更新和旋转检测的缓冲区
|
||||||
|
float acc_buffer[VARIANCE_BUFFER_SIZE][3]; // 加速度数据窗口
|
||||||
|
float gyr_buffer[VARIANCE_BUFFER_SIZE][3]; // 角速度数据窗口
|
||||||
|
int buffer_index; // 缓冲区当前索引
|
||||||
|
int buffer_filled; // 缓冲区是否已填满的标志
|
||||||
|
|
||||||
|
// 用于高通滤波器(巴特沃斯一阶滤波器)的私有成员,以消除加速度的直流偏置
|
||||||
|
float acc_world_filtered[3]; //过滤过的
|
||||||
|
float acc_world_unfiltered_prev[3]; //上一次没过滤的
|
||||||
|
|
||||||
|
float acc_world_lpf[3]; // 经过低通滤波后的世界坐标系加速度
|
||||||
|
} skiing_tracker_t;
|
||||||
|
|
||||||
|
//ble发送的数据
|
||||||
|
typedef struct{ //__attribute__((packed)){ //该结构体取消内存对齐
|
||||||
|
char sensor_state;
|
||||||
|
char skiing_state;
|
||||||
|
int speed_cms; //求出的速度,cm/s
|
||||||
|
int distance_cm; //求出的距离,cm
|
||||||
|
short acc_data[3]; //三轴加速度, g
|
||||||
|
short gyr_data[3]; //三轴陀螺仪, dps
|
||||||
|
float angle_data[3]; //欧若拉角
|
||||||
|
}BLE_send_data_t;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
int acc_KS[3]; //卡尔曼后,LSB转换后的 三轴加速度数据(cm/s^2)
|
||||||
|
int gyr_KS_dps[3]; //卡尔曼后,LSB to dps 三轴陀螺仪数据
|
||||||
|
int angle_KS[3]; //卡尔曼后,计算得到的欧若拉角数据
|
||||||
|
}BLE_KS_send_data_t;
|
||||||
|
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
typedef struct{
|
||||||
|
float acc_variance; //三轴加速度方差之和
|
||||||
|
float gyr_variance; //三轴陀螺仪方差之和
|
||||||
|
float acc_magnitude; //三轴加速度模长
|
||||||
|
float gyr_magnitude; //三轴陀螺仪模长
|
||||||
|
}debug_t;
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker 指向 skiing_tracker_t 结构体的指针
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker);
|
||||||
|
|
||||||
|
BLE_send_data_t sensor_processing_task(signed short* acc_data_buf, signed short* gyr_data_buf, float* angle_data, float* quaternion);
|
||||||
|
#endif // SKIING_TRACKER_H
|
||||||
95
apps/earphone/xtell_Sensor/README.md
Normal file
95
apps/earphone/xtell_Sensor/README.md
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
# 时间间隔 -- 软件模拟iic的情况下
|
||||||
|
|
||||||
|
目前测试代码如下:
|
||||||
|
|
||||||
|
```c
|
||||||
|
create_process(&test_id, "test",NULL, test, (int)(DELTA_TIME*1000));
|
||||||
|
```
|
||||||
|
|
||||||
|
对于test函数的调用时间设置的是10ms调用一次,test代码如下:
|
||||||
|
|
||||||
|
```c
|
||||||
|
void test(){
|
||||||
|
signed short acc_data_buf[3] = {0};
|
||||||
|
signed short gyr_data_buf[3] = {0};
|
||||||
|
signed short acc_gyro_input[6] = {0};
|
||||||
|
float Angle_output[3] = {0};
|
||||||
|
SL_SC7U22_RawData_Read(acc_data_buf,gyr_data_buf);
|
||||||
|
BLE_send_data = sensor_processing_task(acc_data_buf, gyr_data_buf);
|
||||||
|
//----省略-----
|
||||||
|
//一些ble数据发送
|
||||||
|
|
||||||
|
memset(&BLE_send_data, 0, sizeof(BLE_send_data_t));
|
||||||
|
memset(&data, 0, 50);
|
||||||
|
// xlog("end============\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
sensor_processing_task当中就进行了计算,包括卡尔曼等,在timer设置成10ms的情况下,实际上test函数(或者是sensor_processing_task函数),距离上次调用到本次调用,实际间隔为40ms
|
||||||
|
|
||||||
|
计算距离不能直接采用timers设置的时间间隔作为dt来求距离,实际每次计算求速度的时间应该是40ms
|
||||||
|
|
||||||
|
|
||||||
|
# 11.13
|
||||||
|
|
||||||
|
代码主要文件夹:apps\earphone\xtell_Sensor
|
||||||
|
|
||||||
|
- apps\earphone\xtell_Sensor\send_data.c,‘ xtell_task_create ’ 函数,传感器计算程序逻辑开始位置,包括传感器读取数据的任务、蓝牙发送任务、速度距离计算任务
|
||||||
|
|
||||||
|
- apps\earphone\xtell_Sensor\calculate:目前只有计算传感器去除重力分量的代码
|
||||||
|
- 问题:存在漂移
|
||||||
|
- 水平的情况下三轴去掉重力分量,计算出来的结果, 误差有0.0x m/s^s
|
||||||
|
- original(g): x -0.02, y 0.00, z 1.00
|
||||||
|
device(m/s^2) no g: x -0.08, y -0.01, z -0.04, all 0.08
|
||||||
|
|
||||||
|
- 在板子任意倾斜角度下,去掉各轴重力分量的情况下,误差有0.3x m/s^s
|
||||||
|
- ===original(g): x -0.20, y -0.85, z 0.41===
|
||||||
|
|
||||||
|
- ===device(m/s^2) no g: x 0.06, y 0.31, z -0.10, all 0.33===
|
||||||
|
|
||||||
|
- apps\earphone\xtell_Sensor\sensor:传感器驱动,参与编译的为SC7U22.c和SC7U22.h
|
||||||
|
- apps\earphone\xtell_Sensor\A_hide:速度和距离计算代码
|
||||||
|
- 最新一版为apps\earphone\xtell_Sensor\A_hide\10\,水平距离测速2、3m误差
|
||||||
|
- 要使用只需要把代码复制粘贴到calculate文件夹下
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 11.18
|
||||||
|
|
||||||
|
去除重力分量后仍有误差:
|
||||||
|
|
||||||
|
- 数据对齐?
|
||||||
|
- 有没有丢数据?
|
||||||
|
- 重复定位的数据?
|
||||||
|
- 静态时的角度误差?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
定时器1的回调函数(10ms调用一次)**A**:读取传感器数据,放进buff
|
||||||
|
|
||||||
|
定时器2的回调函数(5ms调用一次)**B**:读取buff的传感器数据,去除重力分离的计算
|
||||||
|
|
||||||
|
- **数据没有对齐**,A 的回调调用计数 > B 的回调调用计数
|
||||||
|
- **丢数据了**,A 读取传感器数据的回调函数中,打印了buff已满的log
|
||||||
|
- **重复定位**:移动后回到原先的位置,前后的计算得到的三轴角度相同
|
||||||
|
- **静态时的角度误差**:1°左右
|
||||||
|
- 定时器2不进行重力分离计算,只进行计数,也仍然有数据没有对齐和丢数据的情况
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
将读取传感器数据、去除重力分量计算放到同一个任务下,同步进行
|
||||||
|
|
||||||
|
- 数据没有丢失,数据也对齐了
|
||||||
|
- 在小倾斜的坡面下,去除重力分量后的总的加速度,**小于0.1m/s^2**
|
||||||
|
- 在大倾斜的坡面下(如旋转超过70°),去除重力分量后的总的加速度,在**0.4m/s^2上下**
|
||||||
|
- 貌似是角度越大,越接近方向锁,导致角度更容易漂移造错数据错误
|
||||||
|
|
||||||
|
采用四元数的方式做去除重力分量的计算:
|
||||||
|
|
||||||
|
- 将读取传感器数据、去除重力分量计算放到同一个任务下
|
||||||
|
|
||||||
|
- 在小倾斜的坡面下,去除重力分量后的总的加速度,低于**0.04m/s^2**
|
||||||
|
- 在大倾斜的坡面下(如旋转超过70°),去除重力分量后的总的加速度,在**0.1m/s^2上下**
|
||||||
|
|
||||||
|
- 大倾斜角度的误差要靠磁力计来消除(yaw无法通过加速度计来消除偏差)
|
||||||
166
apps/earphone/xtell_Sensor/ano/ano_protocol.c
Normal file
166
apps/earphone/xtell_Sensor/ano/ano_protocol.c
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
发送数据给上位机的,需要将log打印出口关闭
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ano_protocol.h"
|
||||||
|
#include "asm/uart_dev.h"
|
||||||
|
#include "app_config.h"
|
||||||
|
|
||||||
|
// 定义协议常量
|
||||||
|
#define ANO_FRAME_HEADER 0xAA
|
||||||
|
#define ANO_TO_COMPUTER_ADDR 0xFF
|
||||||
|
|
||||||
|
// 用于保存 uart_dev_open 返回的句柄
|
||||||
|
static const uart_bus_t *ano_uart_dev = NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计算并填充协议的校验和
|
||||||
|
* @param frame_buffer 指向数据帧缓冲区的指针
|
||||||
|
*/
|
||||||
|
static void ano_calculate_checksum(u8 *frame_buffer) {
|
||||||
|
#if TCFG_UART0_ENABLE==0
|
||||||
|
u8 sum_check = 0;
|
||||||
|
u8 add_check = 0;
|
||||||
|
|
||||||
|
// 数据长度在索引为 3 的位置
|
||||||
|
u8 data_len = frame_buffer[3];
|
||||||
|
// 需要计算校验和的总长度 = 帧头(1) + 地址(1) + ID(1) + 长度(1) + 数据(data_len)
|
||||||
|
u16 checksum_len = 4 + data_len;
|
||||||
|
|
||||||
|
for (u16 i = 0; i < checksum_len; i++) {
|
||||||
|
sum_check += frame_buffer[i];
|
||||||
|
add_check += sum_check;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将计算出的校验和填充到帧的末尾
|
||||||
|
frame_buffer[checksum_len] = sum_check;
|
||||||
|
frame_buffer[checksum_len + 1] = add_check;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化用于上位机通信的串口
|
||||||
|
*/
|
||||||
|
int ano_protocol_init(u32 baudrate) {
|
||||||
|
#if TCFG_UART0_ENABLE==0
|
||||||
|
// 防止重复初始化
|
||||||
|
if (ano_uart_dev) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct uart_platform_data_t ut_arg = {0};
|
||||||
|
|
||||||
|
// TCFG_ONLINE_TX_PORT 和 TCFG_ONLINE_RX_PORT 通常在 app_config.h 中定义
|
||||||
|
ut_arg.tx_pin = TCFG_ONLINE_TX_PORT;
|
||||||
|
ut_arg.rx_pin = (u8)-1; // -1 表示不使用该引脚,因为我们只发送数据
|
||||||
|
ut_arg.baud = baudrate;
|
||||||
|
|
||||||
|
// 以下为接收相关配置,由于只发送,全部设为0或NULL
|
||||||
|
ut_arg.rx_cbuf = NULL;
|
||||||
|
ut_arg.rx_cbuf_size = 0;
|
||||||
|
ut_arg.frame_length = 0;
|
||||||
|
ut_arg.rx_timeout = 0;
|
||||||
|
ut_arg.isr_cbfun = NULL;
|
||||||
|
|
||||||
|
ano_uart_dev = (uart_bus_t *)uart_dev_open(&ut_arg);
|
||||||
|
|
||||||
|
if (ano_uart_dev == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 发送惯性传感器数据 (ID: 0x01)
|
||||||
|
*/
|
||||||
|
void ano_send_inertial_data(s16 acc_x, s16 acc_y, s16 acc_z,
|
||||||
|
s16 gyr_x, s16 gyr_y, s16 gyr_z,
|
||||||
|
u8 shock_sta) {
|
||||||
|
#if TCFG_UART0_ENABLE==0
|
||||||
|
if (ano_uart_dev == NULL) {
|
||||||
|
return; // 如果串口未初始化,则不执行任何操作
|
||||||
|
}
|
||||||
|
|
||||||
|
// 帧总长度 = 4(固定头) + 13(数据) + 2(校验) = 19 字节
|
||||||
|
u8 frame_buffer[19];
|
||||||
|
u8 data_idx = 4; // DATA区域从索引4开始
|
||||||
|
|
||||||
|
// 1. 填充帧头、地址、ID、长度
|
||||||
|
frame_buffer[0] = ANO_FRAME_HEADER;
|
||||||
|
frame_buffer[1] = ANO_TO_COMPUTER_ADDR;
|
||||||
|
frame_buffer[2] = 0x01; // 功能码 ID
|
||||||
|
frame_buffer[3] = 13; // 数据长度 LEN
|
||||||
|
|
||||||
|
// 2. 填充数据内容 (DATA),注意小端模式 (低字节在前)
|
||||||
|
frame_buffer[data_idx++] = (u8)(acc_x & 0xFF);
|
||||||
|
frame_buffer[data_idx++] = (u8)(acc_x >> 8);
|
||||||
|
frame_buffer[data_idx++] = (u8)(acc_y & 0xFF);
|
||||||
|
frame_buffer[data_idx++] = (u8)(acc_y >> 8);
|
||||||
|
frame_buffer[data_idx++] = (u8)(acc_z & 0xFF);
|
||||||
|
frame_buffer[data_idx++] = (u8)(acc_z >> 8);
|
||||||
|
|
||||||
|
frame_buffer[data_idx++] = (u8)(gyr_x & 0xFF);
|
||||||
|
frame_buffer[data_idx++] = (u8)(gyr_x >> 8);
|
||||||
|
frame_buffer[data_idx++] = (u8)(gyr_y & 0xFF);
|
||||||
|
frame_buffer[data_idx++] = (u8)(gyr_y >> 8);
|
||||||
|
frame_buffer[data_idx++] = (u8)(gyr_z & 0xFF);
|
||||||
|
frame_buffer[data_idx++] = (u8)(gyr_z >> 8);
|
||||||
|
|
||||||
|
frame_buffer[data_idx++] = shock_sta;
|
||||||
|
|
||||||
|
// 3. 计算并填充校验和
|
||||||
|
ano_calculate_checksum(frame_buffer);
|
||||||
|
|
||||||
|
// 4. 通过串口发送整个数据帧
|
||||||
|
ano_uart_dev->write(frame_buffer, sizeof(frame_buffer));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 发送飞控姿态数据 (ID: 0x03)
|
||||||
|
*
|
||||||
|
* @param rol
|
||||||
|
* @param pit
|
||||||
|
* @param yaw
|
||||||
|
* @param fusion_sta
|
||||||
|
*/
|
||||||
|
void ano_send_attitude_data(float rol, float pit, float yaw, u8 fusion_sta) {
|
||||||
|
#if TCFG_UART0_ENABLE==0
|
||||||
|
if (ano_uart_dev == NULL) {
|
||||||
|
return; // 如果串口未初始化,则不执行任何操作
|
||||||
|
}
|
||||||
|
|
||||||
|
// 帧总长度 = 4(固定头) + 7(数据) + 2(校验) = 13 字节
|
||||||
|
u8 frame_buffer[13];
|
||||||
|
u8 data_idx = 4; // DATA区域从索引4开始
|
||||||
|
|
||||||
|
// 1. 填充帧头、地址、ID、长度
|
||||||
|
frame_buffer[0] = ANO_FRAME_HEADER;
|
||||||
|
frame_buffer[1] = ANO_TO_COMPUTER_ADDR;
|
||||||
|
frame_buffer[2] = 0x03; // 功能码 ID
|
||||||
|
frame_buffer[3] = 7; // 数据长度 LEN
|
||||||
|
|
||||||
|
// 2. 转换浮点数为整数并填充 (DATA),注意小端模式
|
||||||
|
s16 rol_int = (s16)(rol * 100);
|
||||||
|
s16 pit_int = (s16)(pit * 100);
|
||||||
|
s16 yaw_int = (s16)(yaw * 100);
|
||||||
|
|
||||||
|
frame_buffer[data_idx++] = (u8)(rol_int & 0xFF);
|
||||||
|
frame_buffer[data_idx++] = (u8)(rol_int >> 8);
|
||||||
|
frame_buffer[data_idx++] = (u8)(pit_int & 0xFF);
|
||||||
|
frame_buffer[data_idx++] = (u8)(pit_int >> 8);
|
||||||
|
frame_buffer[data_idx++] = (u8)(yaw_int & 0xFF);
|
||||||
|
frame_buffer[data_idx++] = (u8)(yaw_int >> 8);
|
||||||
|
|
||||||
|
frame_buffer[data_idx++] = fusion_sta;
|
||||||
|
|
||||||
|
// 3. 计算并填充校验和
|
||||||
|
ano_calculate_checksum(frame_buffer);
|
||||||
|
|
||||||
|
// 4. 通过串口发送整个数据帧
|
||||||
|
ano_uart_dev->write(frame_buffer, sizeof(frame_buffer));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
37
apps/earphone/xtell_Sensor/ano/ano_protocol.h
Normal file
37
apps/earphone/xtell_Sensor/ano/ano_protocol.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#ifndef __ANO_PROTOCOL_H__
|
||||||
|
#define __ANO_PROTOCOL_H__
|
||||||
|
|
||||||
|
#include "system/includes.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化用于上位机通信的串口
|
||||||
|
*
|
||||||
|
* @param baudrate 波特率,例如 115200
|
||||||
|
* @return 0: 成功, -1: 失败
|
||||||
|
*/
|
||||||
|
int ano_protocol_init(u32 baudrate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 发送惯性传感器数据 (ID: 0x01)
|
||||||
|
* @param acc_x X轴加速度
|
||||||
|
* @param acc_y Y轴加速度
|
||||||
|
* @param acc_z Z轴加速度
|
||||||
|
* @param gyr_x X轴陀螺仪
|
||||||
|
* @param gyr_y Y轴陀螺仪
|
||||||
|
* @param gyr_z Z轴陀螺仪
|
||||||
|
* @param shock_sta 震动状态
|
||||||
|
*/
|
||||||
|
void ano_send_inertial_data(s16 acc_x, s16 acc_y, s16 acc_z,
|
||||||
|
s16 gyr_x, s16 gyr_y, s16 gyr_z,
|
||||||
|
u8 shock_sta);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 发送飞控姿态数据 (ID: 0x03)
|
||||||
|
* @param rol 横滚角 (单位: 度)
|
||||||
|
* @param pit 俯仰角 (单位: 度)
|
||||||
|
* @param yaw 航向角 (单位: 度)
|
||||||
|
* @param fusion_sta 融合状态
|
||||||
|
*/
|
||||||
|
void ano_send_attitude_data(float rol, float pit, float yaw, u8 fusion_sta);
|
||||||
|
|
||||||
|
#endif // __ANO_PROTOCOL_H__
|
||||||
@ -1,117 +1,84 @@
|
|||||||
#include "circle_buffer.h"
|
#include "circle_buffer.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//START -- 宏定义
|
|
||||||
#define ENABLE_XLOG 1
|
|
||||||
#ifdef xlog
|
|
||||||
#undef xlog
|
|
||||||
#endif
|
|
||||||
#if ENABLE_XLOG
|
|
||||||
#define xlog(format, ...) printf("[%s] " format, __func__, ##__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define xlog(format, ...) ((void)0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//END -- 宏定义
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//START -- 变量定义
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//END -- 变量定义
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//START -- 函数定义
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//END -- 函数定义
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//实现
|
|
||||||
|
|
||||||
// 初始化环形缓冲区
|
// 初始化环形缓冲区
|
||||||
void circle_buffer_init(circle_buffer_t *cb, u8 *buffer, u16 capacity) {
|
void circle_buffer_init(circle_buffer_t *cb, void *buffer, u16 capacity, u16 element_size) {
|
||||||
cb->buffer = buffer;
|
cb->buffer = (u8 *)buffer;
|
||||||
cb->capacity = capacity;
|
cb->capacity = capacity;
|
||||||
|
cb->element_size = element_size;
|
||||||
cb->head = 0;
|
cb->head = 0;
|
||||||
cb->tail = 0;
|
cb->tail = 0;
|
||||||
cb->size = 0;
|
cb->size = 0;
|
||||||
|
os_mutex_create(&cb->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 向环形缓冲区写入数据
|
// 销毁环形缓冲区
|
||||||
u16 circle_buffer_write(circle_buffer_t *cb, const u8 *data, u16 length) {
|
void circle_buffer_deinit(circle_buffer_t *cb) {
|
||||||
if (length > circle_buffer_get_free_space(cb)) {
|
os_mutex_del(&cb->mutex, 0);
|
||||||
// 如果剩余空间不足,则只写入能放下的部分
|
|
||||||
length = circle_buffer_get_free_space(cb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length == 0) {
|
// 向环形缓冲区写入一个元素
|
||||||
return 0;
|
bool circle_buffer_write(circle_buffer_t *cb, const void *element) {
|
||||||
|
os_mutex_pend(&cb->mutex, 0);
|
||||||
|
if (circle_buffer_is_full(cb)) {
|
||||||
|
os_mutex_post(&cb->mutex);
|
||||||
|
return false; // 缓冲区已满
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否需要回环
|
u8 *dest = cb->buffer + (cb->head * cb->element_size);
|
||||||
if (cb->head + length > cb->capacity) {
|
memcpy(dest, element, cb->element_size);
|
||||||
u16 part1_len = cb->capacity - cb->head;
|
|
||||||
u16 part2_len = length - part1_len;
|
cb->head = (cb->head + 1) % cb->capacity;
|
||||||
memcpy(cb->buffer + cb->head, data, part1_len);
|
cb->size++;
|
||||||
memcpy(cb->buffer, data + part1_len, part2_len);
|
os_mutex_post(&cb->mutex);
|
||||||
cb->head = part2_len;
|
return true;
|
||||||
} else {
|
|
||||||
memcpy(cb->buffer + cb->head, data, length);
|
|
||||||
cb->head += length;
|
|
||||||
if (cb->head == cb->capacity) {
|
|
||||||
cb->head = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cb->size += length;
|
// 从环形缓冲区读取一个元素
|
||||||
return length;
|
bool circle_buffer_read(circle_buffer_t *cb, void *element) {
|
||||||
|
os_mutex_pend(&cb->mutex, 0);
|
||||||
|
if (circle_buffer_is_empty(cb)) {
|
||||||
|
os_mutex_post(&cb->mutex);
|
||||||
|
return false; // 缓冲区为空
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从环形缓冲区读取数据
|
u8 *src = cb->buffer + (cb->tail * cb->element_size);
|
||||||
u16 circle_buffer_read(circle_buffer_t *cb, u8 *data, u16 length) {
|
memcpy(element, src, cb->element_size);
|
||||||
if (length > cb->size) {
|
|
||||||
// 如果要读取的长度超过了已有的数据,则只读取已有的部分
|
cb->tail = (cb->tail + 1) % cb->capacity;
|
||||||
length = cb->size;
|
cb->size--;
|
||||||
|
os_mutex_post(&cb->mutex);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length == 0) {
|
// 获取已用空间的大小(以元素为单位)
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否需要回环
|
|
||||||
if (cb->tail + length > cb->capacity) {
|
|
||||||
u16 part1_len = cb->capacity - cb->tail;
|
|
||||||
u16 part2_len = length - part1_len;
|
|
||||||
memcpy(data, cb->buffer + cb->tail, part1_len);
|
|
||||||
memcpy(data + part1_len, cb->buffer, part2_len);
|
|
||||||
cb->tail = part2_len;
|
|
||||||
} else {
|
|
||||||
memcpy(data, cb->buffer + cb->tail, length);
|
|
||||||
cb->tail += length;
|
|
||||||
if (cb->tail == cb->capacity) {
|
|
||||||
cb->tail = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cb->size -= length;
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取已用空间的大小
|
|
||||||
u16 circle_buffer_get_size(circle_buffer_t *cb) {
|
u16 circle_buffer_get_size(circle_buffer_t *cb) {
|
||||||
return cb->size;
|
os_mutex_pend(&cb->mutex, 0);
|
||||||
|
u16 size = cb->size;
|
||||||
|
os_mutex_post(&cb->mutex);
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取剩余空间的大小
|
// 获取剩余空间的大小(以元素为单位)
|
||||||
u16 circle_buffer_get_free_space(circle_buffer_t *cb) {
|
u16 circle_buffer_get_free_space(circle_buffer_t *cb) {
|
||||||
return cb->capacity - cb->size;
|
os_mutex_pend(&cb->mutex, 0);
|
||||||
|
u16 free_space = cb->capacity - cb->size;
|
||||||
|
os_mutex_post(&cb->mutex);
|
||||||
|
return free_space;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查缓冲区是否已满
|
||||||
|
bool circle_buffer_is_full(circle_buffer_t *cb) {
|
||||||
|
os_mutex_pend(&cb->mutex, 0);
|
||||||
|
bool is_full = (cb->size == cb->capacity);
|
||||||
|
os_mutex_post(&cb->mutex);
|
||||||
|
return is_full;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查缓冲区是否为空
|
||||||
|
bool circle_buffer_is_empty(circle_buffer_t *cb) {
|
||||||
|
os_mutex_pend(&cb->mutex, 0);
|
||||||
|
bool is_empty = (cb->size == 0);
|
||||||
|
os_mutex_post(&cb->mutex);
|
||||||
|
return is_empty;
|
||||||
}
|
}
|
||||||
@ -2,54 +2,77 @@
|
|||||||
#define CIRCLE_BUFFER_H
|
#define CIRCLE_BUFFER_H
|
||||||
|
|
||||||
#include "system/includes.h"
|
#include "system/includes.h"
|
||||||
|
#include "os/os_api.h"
|
||||||
|
|
||||||
// 定义环形缓冲区的结构体
|
// 定义环形缓冲区的结构体
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u8 *buffer; // 缓冲区指针
|
u8 *buffer; // 缓冲区指针
|
||||||
u16 capacity; // 缓冲区总容量
|
u16 capacity; // 缓冲区总容量(以元素为单位)
|
||||||
u16 head; // 头部指针(写入位置)
|
u16 element_size; // 每个元素的大小(以字节为单位)
|
||||||
u16 tail; // 尾部指针(读取位置)
|
u16 head; // 头部指针(写入位置,以元素为单位)
|
||||||
u16 size; // 当前已用大小
|
u16 tail; // 尾部指针(读取位置,以元素为单位)
|
||||||
|
u16 size; // 当前已用大小(以元素为单位)
|
||||||
|
OS_MUTEX mutex; // 用于保护缓冲区的互斥锁
|
||||||
} circle_buffer_t;
|
} circle_buffer_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 初始化环形缓冲区
|
* @brief 初始化环形缓冲区
|
||||||
* @param cb 指向环形缓冲区结构体的指针
|
* @param cb 指向环形缓冲区结构体的指针
|
||||||
* @param buffer 外部提供的缓冲区内存
|
* @param buffer 外部提供的缓冲区内存
|
||||||
* @param capacity 缓冲区的总容量
|
* @param capacity 缓冲区的总容量(以元素数量为单位)
|
||||||
|
* @param element_size 每个元素的大小(字节)
|
||||||
*/
|
*/
|
||||||
void circle_buffer_init(circle_buffer_t *cb, u8 *buffer, u16 capacity);
|
void circle_buffer_init(circle_buffer_t *cb, void *buffer, u16 capacity, u16 element_size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 向环形缓冲区写入数据
|
* @brief 销毁环形缓冲区,释放相关资源
|
||||||
* @param cb 指向环形缓冲区结构体的指针
|
* @param cb 指向环形缓冲区结构体的指针
|
||||||
* @param data 要写入的数据的指针
|
|
||||||
* @param length 要写入的数据的长度
|
|
||||||
* @return 实际写入的字节数
|
|
||||||
*/
|
*/
|
||||||
u16 circle_buffer_write(circle_buffer_t *cb, const u8 *data, u16 length);
|
void circle_buffer_deinit(circle_buffer_t *cb);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 从环形缓冲区读取数据
|
* @brief 向环形缓冲区写入一个元素
|
||||||
* @param cb 指向环形缓冲区结构体的指针
|
* @param cb 指向环形缓冲区结构体的指针
|
||||||
* @param data 用于存放读取数据的缓冲区的指针
|
* @param element 要写入的元素的指针
|
||||||
* @param length 想要读取的数据的长度
|
* @return 成功返回true,失败返回false
|
||||||
* @return 实际读取的字节数
|
|
||||||
*/
|
*/
|
||||||
u16 circle_buffer_read(circle_buffer_t *cb, u8 *data, u16 length);
|
bool circle_buffer_write(circle_buffer_t *cb, const void *element);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取环形缓冲区中已用空间的大小
|
* @brief 从环形缓冲区读取一个元素
|
||||||
* @param cb 指向环形缓冲区结构体的指针
|
* @param cb 指向环形缓冲区结构体的指针
|
||||||
* @return 已用空间的大小
|
* @param element 用于存放读取元素的缓冲区的指针
|
||||||
|
* @return 成功返回true,失败返回false
|
||||||
|
*/
|
||||||
|
bool circle_buffer_read(circle_buffer_t *cb, void *element);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取环形缓冲区中已用空间的大小(以元素为单位)
|
||||||
|
* @param cb 指向环形缓冲区结构体的指针
|
||||||
|
* @return 已用空间的大小(元素数量)
|
||||||
*/
|
*/
|
||||||
u16 circle_buffer_get_size(circle_buffer_t *cb);
|
u16 circle_buffer_get_size(circle_buffer_t *cb);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取环形缓冲区中剩余空间的大小
|
* @brief 获取环形缓冲区中剩余空间的大小(以元素为单位)
|
||||||
* @param cb 指向环形缓冲区结构体的指针
|
* @param cb 指向环形缓冲区结构体的指针
|
||||||
* @return 剩余空间的大小
|
* @return 剩余空间的大小(元素数量)
|
||||||
*/
|
*/
|
||||||
u16 circle_buffer_get_free_space(circle_buffer_t *cb);
|
u16 circle_buffer_get_free_space(circle_buffer_t *cb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查缓冲区是否已满
|
||||||
|
* @param cb 指向环形缓冲区结构体的指针
|
||||||
|
* @return 如果已满返回true,否则返回false
|
||||||
|
*/
|
||||||
|
bool circle_buffer_is_full(circle_buffer_t *cb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查缓冲区是否为空
|
||||||
|
* @param cb 指向环形缓冲区结构体的指针
|
||||||
|
* @return 如果为空返回true,否则返回false
|
||||||
|
*/
|
||||||
|
bool circle_buffer_is_empty(circle_buffer_t *cb);
|
||||||
|
|
||||||
|
|
||||||
#endif // CIRCLE_BUFFER_H
|
#endif // CIRCLE_BUFFER_H
|
||||||
635
apps/earphone/xtell_Sensor/calculate/skiing_tracker.c
Normal file
635
apps/earphone/xtell_Sensor/calculate/skiing_tracker.c
Normal file
@ -0,0 +1,635 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "skiing_tracker.h"
|
||||||
|
#include "../sensor/SC7U22.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define G_ACCELERATION 9.81f
|
||||||
|
#define DEG_TO_RAD (3.14159265f / 180.0f)
|
||||||
|
|
||||||
|
#define ENABLE_XLOG 1
|
||||||
|
#ifdef xlog
|
||||||
|
#undef xlog
|
||||||
|
#endif
|
||||||
|
#if ENABLE_XLOG
|
||||||
|
#define xlog(format, ...) printf("[XT:%s] " format, __func__, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define xlog(format, ...) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// --- 静止检测 ---
|
||||||
|
//两个判断是否静止的必要条件:动态零速更新(ZUPT)阈值
|
||||||
|
// 加速方差阈值,提高阈值,让“刹车”更灵敏,以便在波浪式前进等慢速漂移时也能触发零速更新
|
||||||
|
#define STOP_ACC_VARIANCE_THRESHOLD 0.2f
|
||||||
|
// 陀螺仪方差阈值
|
||||||
|
#define STOP_GYR_VARIANCE_THRESHOLD 5.0f
|
||||||
|
// 静止时候的陀螺仪模长
|
||||||
|
#define STOP_GYR_MAG_THRESHOLD 15
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 启动滑雪阈值 ---
|
||||||
|
// 加速度模长与重力的差值大于此值,认为开始运动;降低阈值,让“油门”更灵敏,以便能捕捉到真实的慢速启动
|
||||||
|
#define START_ACC_MAG_THRESHOLD 1.0f //0.5、1
|
||||||
|
// 陀螺仪方差阈值,以允许启动瞬间的正常抖动,但仍能过滤掉混乱的、非滑雪的晃动。
|
||||||
|
#define START_GYR_VARIANCE_THRESHOLD 15.0f
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 滑雪过程 ---
|
||||||
|
//加速度 模长(不含重力),低于此值视为 在做匀速运动
|
||||||
|
#define SKIING_ACC_MAG_THRESHOLD 0.5f
|
||||||
|
//陀螺仪 模长,高于此值视为 摔倒了
|
||||||
|
#define FALLEN_GRY_MAG_THRESHOLD 2000.0f //未确定
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 原地旋转抖动 ---
|
||||||
|
// 加速度 方差 阈值。此值比 静止检测 阈值更宽松,
|
||||||
|
#define WOBBLE_ACC_VARIANCE_THRESHOLD 0.5f
|
||||||
|
// 加速度 模长 阈值
|
||||||
|
#define WOBBLE_ACC_MAG_THRESHOLD 1.0f
|
||||||
|
// 角速度 总模长 大于此值(度/秒),认为正在进行非滑雪的旋转或摆动
|
||||||
|
#define ROTATION_GYR_MAG_THRESHOLD 30.0f
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 滑雪转弯动 ---
|
||||||
|
// 加速度 方差 阈值,大于此值,滑雪过程可能发生了急转弯
|
||||||
|
#define WHEEL_ACC_VARIANCE_THRESHOLD 7.0f
|
||||||
|
// 角速度 总模长 大于此值(度/秒),认为滑雪过程中进行急转弯
|
||||||
|
#define WHEEL_GYR_MAG_THRESHOLD 500.0f //
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 跳跃 ---
|
||||||
|
// 加速度模长低于此值(g),认为进入失重状态(IN_AIR)
|
||||||
|
#define AIRBORNE_ACC_MAG_LOW_THRESHOLD 0.4f
|
||||||
|
// 加速度模长高于此值(g),认为发生落地冲击(LANDING)
|
||||||
|
#define LANDING_ACC_MAG_HIGH_THRESHOLD 3.5f
|
||||||
|
// 起跳加速度阈值(g),用于进入TAKING_OFF状态
|
||||||
|
#define TAKEOFF_ACC_MAG_HIGH_THRESHOLD 1.8f
|
||||||
|
// 进入空中状态确认计数:需要连续3个采样点加速度低于阈值才判断为起跳
|
||||||
|
#define AIRBORNE_CONFIRM_COUNT 3
|
||||||
|
// 落地状态确认计数:加速度恢复到1g附近并持续2个采样点(20ms)则认为已落地
|
||||||
|
#define GROUNDED_CONFIRM_COUNT 2
|
||||||
|
// 最大滞空时间(秒),超过此时间强制认为已落地,防止状态锁死
|
||||||
|
#define MAX_TIME_IN_AIR 12.5f
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 用于消除积分漂移的滤波器和阈值 ---
|
||||||
|
// 高通滤波器系数 (alpha)。alpha 越接近1,滤除低频(直流偏移)的效果越强,但可能滤掉真实的慢速运动。
|
||||||
|
// alpha = RC / (RC + dt),参考RC电路而来,fc ≈ (1 - alpha) / (2 * π * dt)
|
||||||
|
#define HPF_ALPHA 0.999f
|
||||||
|
//0.995f: 0.08 Hz 的信号
|
||||||
|
//0.999f: 0.0159 Hz
|
||||||
|
// --- --- ---
|
||||||
|
|
||||||
|
// --- 低通滤波器 ---
|
||||||
|
// 低通滤波器系数 (alpha)。alpha 越小,滤波效果越强(更平滑),但延迟越大。
|
||||||
|
// alpha 推荐范围 0.7 ~ 0.95。可以从 0.85 开始尝试。
|
||||||
|
#define LPF_ALPHA 0.7f
|
||||||
|
|
||||||
|
// 加速度死区阈值 (m/s^2)。低于此阈值的加速度被认为是噪声,不参与积分。
|
||||||
|
// 设得太高会忽略真实的慢速启动,设得太低则无法有效抑制噪声。
|
||||||
|
//参考:0.2f ~ 0.4f
|
||||||
|
#define ACC_DEAD_ZONE_THRESHOLD 0.05f
|
||||||
|
|
||||||
|
// --- 模拟摩擦力,进行速度衰减 ---
|
||||||
|
#define SPEED_ATTENUATION 1.0f //暂不模拟
|
||||||
|
BLE_KS_send_data_t KS_data;
|
||||||
|
static float quaternion_data[4];
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
|
||||||
|
debug_t debug1;
|
||||||
|
debug_t debug2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static skiing_tracker_t my_skiing_tracker;
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//实现
|
||||||
|
|
||||||
|
void clear_speed(void){
|
||||||
|
my_skiing_tracker.state = STATIC;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_detection(void){
|
||||||
|
my_skiing_tracker.state = STATIC;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.distance = 0;
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop_detection(void){
|
||||||
|
my_skiing_tracker.state = STOP_DETECTION;
|
||||||
|
memset(my_skiing_tracker.velocity, 0, sizeof(my_skiing_tracker.velocity));
|
||||||
|
my_skiing_tracker.speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker)
|
||||||
|
{
|
||||||
|
if (!tracker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 使用memset一次性清零整个结构体,包括新增的缓冲区
|
||||||
|
memset(tracker, 0, sizeof(skiing_tracker_t));
|
||||||
|
tracker->state = STATIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 当检测到落地时,计算空中的水平飞行距离并累加到总距离
|
||||||
|
*/
|
||||||
|
static void calculate_air_distance(skiing_tracker_t *tracker) {
|
||||||
|
float horizontal_speed_on_takeoff = sqrtf(
|
||||||
|
tracker->initial_velocity_on_takeoff[0] * tracker->initial_velocity_on_takeoff[0] +
|
||||||
|
tracker->initial_velocity_on_takeoff[1] * tracker->initial_velocity_on_takeoff[1]
|
||||||
|
);
|
||||||
|
float distance_in_air = horizontal_speed_on_takeoff * tracker->time_in_air;
|
||||||
|
tracker->distance += distance_in_air;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 使用四元数直接从设备坐标系的加速度中移除重力分量
|
||||||
|
* @details 这种方法比使用欧拉角更精确、更稳定,且避免了万向节死锁。
|
||||||
|
* @param acc_device 输入:设备坐标系下的原始加速度 [x, y, z], 单位 m/s^2
|
||||||
|
* @param q 输入:表示姿态的四元数 [w, x, y, z]
|
||||||
|
* @param acc_linear_device 输出:设备坐标系下移除重力后的线性加速度 [x, y, z]
|
||||||
|
*/
|
||||||
|
void q_remove_gravity_with_quaternion(const float *acc_device, const float *q, float *acc_linear_device)
|
||||||
|
{
|
||||||
|
// 从四元数计算重力在设备坐标系下的投影
|
||||||
|
// G_device = R_transpose * G_world
|
||||||
|
// G_world = [0, 0, g]
|
||||||
|
// R_transpose 的第三列即为重力投影方向
|
||||||
|
float gx = 2.0f * (q[1] * q[3] - q[0] * q[2]);
|
||||||
|
float gy = 2.0f * (q[0] * q[1] + q[2] * q[3]);
|
||||||
|
float gz = q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3];
|
||||||
|
|
||||||
|
// 从原始加速度中减去重力分量
|
||||||
|
acc_linear_device[0] = acc_device[0] - gx * G_ACCELERATION;
|
||||||
|
acc_linear_device[1] = acc_device[1] - gy * G_ACCELERATION;
|
||||||
|
acc_linear_device[2] = acc_device[2] - gz * G_ACCELERATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 使用四元数将设备坐标系的线性加速度转换到世界坐标系
|
||||||
|
* @details 同样,此方法比使用欧拉角更优。
|
||||||
|
* @param acc_linear_device 输入:设备坐标系下的线性加速度 [x, y, z]
|
||||||
|
* @param q 输入:表示姿态的四元数 [w, x, y, z]
|
||||||
|
* @param acc_linear_world 输出:世界坐标系下的线性加速度 [x, y, z]
|
||||||
|
*/
|
||||||
|
void q_transform_to_world_with_quaternion(const float *acc_linear_device, const float *q, float *acc_linear_world)
|
||||||
|
{
|
||||||
|
// 这是 R_device_to_world * acc_linear_device 的展开形式
|
||||||
|
acc_linear_world[0] = (1.0f - 2.0f*q[2]*q[2] - 2.0f*q[3]*q[3]) * acc_linear_device[0] +
|
||||||
|
(2.0f*q[1]*q[2] - 2.0f*q[0]*q[3]) * acc_linear_device[1] +
|
||||||
|
(2.0f*q[1]*q[3] + 2.0f*q[0]*q[2]) * acc_linear_device[2];
|
||||||
|
|
||||||
|
acc_linear_world[1] = (2.0f*q[1]*q[2] + 2.0f*q[0]*q[3]) * acc_linear_device[0] +
|
||||||
|
(1.0f - 2.0f*q[1]*q[1] - 2.0f*q[3]*q[3]) * acc_linear_device[1] +
|
||||||
|
(2.0f*q[2]*q[3] - 2.0f*q[0]*q[1]) * acc_linear_device[2];
|
||||||
|
|
||||||
|
acc_linear_world[2] = (2.0f*q[1]*q[3] - 2.0f*q[0]*q[2]) * acc_linear_device[0] +
|
||||||
|
(2.0f*q[2]*q[3] + 2.0f*q[0]*q[1]) * acc_linear_device[1] +
|
||||||
|
(1.0f - 2.0f*q[1]*q[1] - 2.0f*q[2]*q[2]) * acc_linear_device[2];
|
||||||
|
// acc_linear_world[2] -= G_ACCELERATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计算缓冲区内三轴数据的方差之和
|
||||||
|
*
|
||||||
|
* @param buffer 传进来的三轴数据:陀螺仪/加速度
|
||||||
|
* @return float 返回方差和
|
||||||
|
*/
|
||||||
|
static float calculate_variance(float buffer[VARIANCE_BUFFER_SIZE][3])
|
||||||
|
{
|
||||||
|
float mean[3] = {0};
|
||||||
|
float variance[3] = {0};
|
||||||
|
|
||||||
|
// 计算均值
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
mean[0] += buffer[i][0];
|
||||||
|
mean[1] += buffer[i][1];
|
||||||
|
mean[2] += buffer[i][2];
|
||||||
|
}
|
||||||
|
mean[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
mean[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 计算方差
|
||||||
|
for (int i = 0; i < VARIANCE_BUFFER_SIZE; i++) {
|
||||||
|
variance[0] += (buffer[i][0] - mean[0]) * (buffer[i][0] - mean[0]);
|
||||||
|
variance[1] += (buffer[i][1] - mean[1]) * (buffer[i][1] - mean[1]);
|
||||||
|
variance[2] += (buffer[i][2] - mean[2]) * (buffer[i][2] - mean[2]);
|
||||||
|
}
|
||||||
|
variance[0] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[1] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
variance[2] /= VARIANCE_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// 返回三轴方差之和,作为一个综合的稳定度指标
|
||||||
|
return variance[0] + variance[1] + variance[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 摩擦力模拟,进行速度衰减
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
*/
|
||||||
|
void forece_of_friction(skiing_tracker_t *tracker){
|
||||||
|
// 增加速度衰减,模拟摩擦力
|
||||||
|
tracker->velocity[0] *= SPEED_ATTENUATION;
|
||||||
|
tracker->velocity[1] *= SPEED_ATTENUATION;
|
||||||
|
tracker->velocity[2] = 0; // 垂直速度强制归零
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 状态机更新
|
||||||
|
*
|
||||||
|
* @param tracker 传入同步修改后传出
|
||||||
|
* @param acc_device_ms2 三轴加速度,m/s^2
|
||||||
|
* @param gyr_dps 三轴陀螺仪,dps
|
||||||
|
*/
|
||||||
|
static void update_state_machine(skiing_tracker_t *tracker, const float *acc_device_ms2, const float *gyr_dps)
|
||||||
|
{
|
||||||
|
// 缓冲区未填满时,不进行状态判断,默认为静止
|
||||||
|
if (!tracker->buffer_filled) {
|
||||||
|
tracker->state = STATIC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 计算关键指标 ---
|
||||||
|
float acc_variance = calculate_variance(tracker->acc_buffer); // 计算加速度方差
|
||||||
|
float gyr_variance = calculate_variance(tracker->gyr_buffer); // 计算陀螺仪方差
|
||||||
|
float gyr_magnitude = sqrtf(gyr_dps[0]*gyr_dps[0] + gyr_dps[1]*gyr_dps[1] + gyr_dps[2]*gyr_dps[2]); //dps
|
||||||
|
float acc_magnitude = sqrtf(acc_device_ms2[0]*acc_device_ms2[0] + acc_device_ms2[1]*acc_device_ms2[1] + acc_device_ms2[2]*acc_device_ms2[2]); //m/s^s
|
||||||
|
float acc_magnitude_g = acc_magnitude / G_ACCELERATION; // 转换为g单位,用于跳跃判断
|
||||||
|
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
debug1.acc_variance =acc_variance;
|
||||||
|
debug1.gyr_variance =gyr_variance;
|
||||||
|
debug1.gyr_magnitude=gyr_magnitude;
|
||||||
|
debug1.acc_magnitude=fabsf(acc_magnitude - G_ACCELERATION);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// --- 状态机逻辑 (核心修改区域) ---
|
||||||
|
|
||||||
|
#if 0 //暂时不考虑空中
|
||||||
|
// 1. 空中/落地状态的后续处理
|
||||||
|
if (tracker->state == IN_AIR) {
|
||||||
|
// A. 检测巨大冲击 -> 落地
|
||||||
|
if (acc_magnitude_g > LANDING_ACC_MAG_HIGH_THRESHOLD) {
|
||||||
|
tracker->state = LANDING;
|
||||||
|
// B. 检测超时 -> 强制落地 (安全机制)
|
||||||
|
} else if (tracker->time_in_air > MAX_TIME_IN_AIR) {
|
||||||
|
tracker->state = LANDING;
|
||||||
|
// C. 检测恢复正常重力 (平缓落地)
|
||||||
|
} else if (acc_magnitude_g > 0.8f && acc_magnitude_g < 1.5f) {
|
||||||
|
tracker->grounded_entry_counter++;
|
||||||
|
if (tracker->grounded_entry_counter >= GROUNDED_CONFIRM_COUNT) {
|
||||||
|
tracker->state = LANDING;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tracker->grounded_entry_counter = 0;
|
||||||
|
}
|
||||||
|
return; // 在空中或刚切换到落地,结束本次状态判断
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 严格的 "起跳->空中" 状态转换逻辑
|
||||||
|
// 只有当处于滑行状态时,才去检测起跳意图
|
||||||
|
if (tracker->state == NO_CONSTANT_SPEED || tracker->state == CONSTANT_SPEED || tracker->state == WHEEL) {
|
||||||
|
if (acc_magnitude_g > TAKEOFF_ACC_MAG_HIGH_THRESHOLD) {
|
||||||
|
tracker->state = TAKING_OFF;
|
||||||
|
tracker->airborne_entry_counter = 0; // 准备检测失重
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 只有在TAKING_OFF状态下,才去检测是否进入失重
|
||||||
|
if (tracker->state == TAKING_OFF) {
|
||||||
|
if (acc_magnitude_g < AIRBORNE_ACC_MAG_LOW_THRESHOLD) {
|
||||||
|
tracker->airborne_entry_counter++;
|
||||||
|
if (tracker->airborne_entry_counter >= AIRBORNE_CONFIRM_COUNT) {
|
||||||
|
memcpy(tracker->initial_velocity_on_takeoff, tracker->velocity, sizeof(tracker->velocity));
|
||||||
|
tracker->time_in_air = 0;
|
||||||
|
tracker->state = IN_AIR;
|
||||||
|
tracker->airborne_entry_counter = 0;
|
||||||
|
tracker->grounded_entry_counter = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果在起跳冲击后一段时间内没有失重,说明只是一个颠簸,恢复滑行
|
||||||
|
// 可以加一个小的超时计数器,这里为了简单先直接恢复
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
return; // 无论是否切换,都结束本次判断
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// --- 静止判断 ---
|
||||||
|
if (acc_variance < STOP_ACC_VARIANCE_THRESHOLD && gyr_variance < STOP_GYR_VARIANCE_THRESHOLD && gyr_magnitude < STOP_GYR_MAG_THRESHOLD) {
|
||||||
|
tracker->state = STATIC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 地面状态切换逻辑 ---
|
||||||
|
switch (tracker->state) {
|
||||||
|
case LANDING:
|
||||||
|
tracker->state = STATIC;
|
||||||
|
break;
|
||||||
|
case STATIC:
|
||||||
|
// 优先判断是否进入 WOBBLE 状态
|
||||||
|
// 条件:陀螺仪活动剧烈,但整体加速度变化不大(说明是原地转或晃)
|
||||||
|
if (gyr_magnitude > ROTATION_GYR_MAG_THRESHOLD && fabsf(acc_magnitude - G_ACCELERATION) < WOBBLE_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = WOBBLE;
|
||||||
|
}
|
||||||
|
// 只有在陀螺仪和加速度都满足“前进”特征时,才启动
|
||||||
|
else if (gyr_variance > START_GYR_VARIANCE_THRESHOLD && fabsf(acc_magnitude - G_ACCELERATION) > START_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WOBBLE:
|
||||||
|
// 从 WOBBLE 状态启动的条件应该和从 STATIC 启动一样严格
|
||||||
|
if (gyr_variance < START_GYR_VARIANCE_THRESHOLD * 2 && fabsf(acc_magnitude - G_ACCELERATION) > START_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
// 如果陀螺仪活动减弱,则可能恢复静止
|
||||||
|
else if (gyr_magnitude < ROTATION_GYR_MAG_THRESHOLD * 0.8f) { // 增加迟滞,避免抖动
|
||||||
|
// 不直接跳回STATIC,而是依赖下一轮的全局静止判断
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NO_CONSTANT_SPEED: //非匀速状态
|
||||||
|
//暂时不考虑摔倒
|
||||||
|
// if (gyr_magnitude > FALLEN_GRY_MAG_THRESHOLD) {
|
||||||
|
// tracker->state = FALLEN; //摔倒
|
||||||
|
// } else
|
||||||
|
if (gyr_magnitude > WHEEL_GYR_MAG_THRESHOLD && acc_variance > WHEEL_ACC_VARIANCE_THRESHOLD) {
|
||||||
|
tracker->state = WHEEL; //转弯
|
||||||
|
} else if (fabsf(acc_magnitude - G_ACCELERATION) < SKIING_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = CONSTANT_SPEED; //匀速
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONSTANT_SPEED: //匀速状态
|
||||||
|
if (fabsf(acc_magnitude - G_ACCELERATION) > START_ACC_MAG_THRESHOLD) {
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
//TODO:可以添加进入转弯或摔倒的判断
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WHEEL:
|
||||||
|
// 从转弯状态,检查转弯是否结束
|
||||||
|
// 如果角速度和加速度方差都降下来了,就回到普通滑行状态
|
||||||
|
if (gyr_magnitude < WHEEL_GYR_MAG_THRESHOLD * 0.8f && acc_variance < WHEEL_ACC_VARIANCE_THRESHOLD * 0.8f) { // 乘以一个滞后系数避免抖动
|
||||||
|
tracker->state = NO_CONSTANT_SPEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FALLEN:
|
||||||
|
// TODO:回到 STATIC
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 主更新函数
|
||||||
|
*
|
||||||
|
* @param tracker
|
||||||
|
* @param acc_g 三轴加速度,g
|
||||||
|
* @param gyr_dps 三轴陀螺仪,dps
|
||||||
|
* @param angle 欧若拉角
|
||||||
|
* @param dt 采样时间间隔,会用来积分求速度
|
||||||
|
*/
|
||||||
|
void skiing_tracker_update(skiing_tracker_t *tracker, float *acc_g, float *gyr_dps, float *angle, float dt)
|
||||||
|
{
|
||||||
|
if (!tracker || !acc_g || !gyr_dps || !angle || dt <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(my_skiing_tracker.state == STOP_DETECTION)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// --- 数据预处理和缓冲 ---
|
||||||
|
float acc_device_ms2[3];
|
||||||
|
acc_device_ms2[0] = acc_g[0] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[1] = acc_g[1] * G_ACCELERATION;
|
||||||
|
acc_device_ms2[2] = acc_g[2] * G_ACCELERATION;
|
||||||
|
|
||||||
|
// 将最新数据存入缓冲区
|
||||||
|
memcpy(tracker->acc_buffer[tracker->buffer_index], acc_device_ms2, sizeof(acc_device_ms2));
|
||||||
|
memcpy(tracker->gyr_buffer[tracker->buffer_index], gyr_dps, 3 * sizeof(float));
|
||||||
|
|
||||||
|
tracker->buffer_index++;
|
||||||
|
if (tracker->buffer_index >= VARIANCE_BUFFER_SIZE) {
|
||||||
|
tracker->buffer_index = 0;
|
||||||
|
tracker->buffer_filled = 1; // 标记缓冲区已满
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 更新状态机 ---
|
||||||
|
update_state_machine(tracker, acc_device_ms2, gyr_dps);
|
||||||
|
|
||||||
|
// --- 根据状态执行不同的计算逻辑 ---
|
||||||
|
switch (tracker->state) {
|
||||||
|
case TAKING_OFF:
|
||||||
|
tracker->speed = 0.0f;
|
||||||
|
break;
|
||||||
|
case IN_AIR:
|
||||||
|
// 在空中时,只累加滞空时间
|
||||||
|
tracker->time_in_air += dt;
|
||||||
|
break;
|
||||||
|
case LANDING:
|
||||||
|
// 刚落地,计算空中距离
|
||||||
|
calculate_air_distance(tracker);
|
||||||
|
// 清理速度和滤波器状态,为恢复地面追踪做准备
|
||||||
|
memset(tracker->velocity, 0, sizeof(tracker->velocity));
|
||||||
|
tracker->speed = 0;
|
||||||
|
memset(tracker->acc_world_unfiltered_prev, 0, sizeof(tracker->acc_world_unfiltered_prev));
|
||||||
|
memset(tracker->acc_world_filtered, 0, sizeof(tracker->acc_world_filtered));
|
||||||
|
memset(tracker->acc_world_lpf, 0, sizeof(tracker->acc_world_lpf)); // 清理新增的LPF状态
|
||||||
|
break;
|
||||||
|
case WHEEL:
|
||||||
|
case NO_CONSTANT_SPEED:
|
||||||
|
float linear_acc_device[3];
|
||||||
|
float linear_acc_world[3];
|
||||||
|
// 在设备坐标系下,移除重力,得到线性加速度
|
||||||
|
q_remove_gravity_with_quaternion(acc_device_ms2, quaternion_data, linear_acc_device);
|
||||||
|
|
||||||
|
// 将设备坐标系下的线性加速度,旋转到世界坐标系
|
||||||
|
q_transform_to_world_with_quaternion(linear_acc_device, quaternion_data, linear_acc_world);
|
||||||
|
// 将最终用于积分的加速度存入 tracker 结构体
|
||||||
|
memcpy(tracker->acc_no_g, linear_acc_world, sizeof(linear_acc_world));
|
||||||
|
|
||||||
|
float acc_world_temp[3]; // 临时变量存储当前周期的加速度
|
||||||
|
for (int i = 0; i < 2; i++) { // 只处理水平方向的 x 和 y 轴
|
||||||
|
|
||||||
|
// --- 核心修改:颠倒滤波器顺序为 HPF -> LPF ---
|
||||||
|
|
||||||
|
// 1. 高通滤波 (HPF) 先行: 消除因姿态误差导致的重力泄漏(直流偏置)
|
||||||
|
// HPF的瞬态响应会产生尖峰,这是正常的。
|
||||||
|
tracker->acc_world_filtered[i] = HPF_ALPHA * (tracker->acc_world_filtered[i] + tracker->acc_no_g[i] - tracker->acc_world_unfiltered_prev[i]);
|
||||||
|
tracker->acc_world_unfiltered_prev[i] = tracker->acc_no_g[i];
|
||||||
|
|
||||||
|
// 2. 低通滤波 (LPF) 殿后: 平滑掉HPF产生的尖峰和传感器自身的高频振动噪声。
|
||||||
|
// 这里使用 tracker->acc_world_filtered[i] 作为LPF的输入。
|
||||||
|
tracker->acc_world_lpf[i] = (1.0f - LPF_ALPHA) * tracker->acc_world_filtered[i] + LPF_ALPHA * tracker->acc_world_lpf[i];
|
||||||
|
|
||||||
|
// 将最终处理完的加速度值存入临时变量
|
||||||
|
acc_world_temp[i] = tracker->acc_world_lpf[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算处理后加速度的水平模长
|
||||||
|
float acc_horizontal_mag = sqrtf(acc_world_temp[0] * acc_world_temp[0] +
|
||||||
|
acc_world_temp[1] * acc_world_temp[1]);
|
||||||
|
#if XTELL_TEST
|
||||||
|
debug2.acc_magnitude = acc_horizontal_mag;
|
||||||
|
#endif
|
||||||
|
// 应用死区,并积分
|
||||||
|
if (acc_horizontal_mag > ACC_DEAD_ZONE_THRESHOLD) {
|
||||||
|
tracker->velocity[0] += acc_world_temp[0] * dt;
|
||||||
|
tracker->velocity[1] += acc_world_temp[1] * dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新速度和距离
|
||||||
|
tracker->speed = sqrtf(tracker->velocity[0] * tracker->velocity[0] +
|
||||||
|
tracker->velocity[1] * tracker->velocity[1]);
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
break;
|
||||||
|
case CONSTANT_SPEED:
|
||||||
|
//保持上次的速度不变。只更新距离
|
||||||
|
tracker->distance += tracker->speed * dt;
|
||||||
|
break;
|
||||||
|
case STATIC:
|
||||||
|
case WOBBLE:
|
||||||
|
// 速度清零,抑制漂移
|
||||||
|
memset(tracker->velocity, 0, sizeof(tracker->velocity));
|
||||||
|
tracker->speed = 0.0f;
|
||||||
|
memset(tracker->acc_world_unfiltered_prev, 0, sizeof(tracker->acc_world_unfiltered_prev));
|
||||||
|
memset(tracker->acc_world_filtered, 0, sizeof(tracker->acc_world_filtered));
|
||||||
|
memset(tracker->acc_world_lpf, 0, sizeof(tracker->acc_world_lpf)); // 清理新增的LPF状态
|
||||||
|
#if XTELL_TEST
|
||||||
|
debug2.acc_magnitude = 0;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case FALLEN:
|
||||||
|
// TODO
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
float linear_acc_device[3];
|
||||||
|
float linear_acc_world[3];
|
||||||
|
float tmp_world_acc[3];
|
||||||
|
// 在设备坐标系下,移除重力,得到线性加速度
|
||||||
|
q_remove_gravity_with_quaternion(acc_device_ms2, quaternion_data, linear_acc_device);
|
||||||
|
|
||||||
|
// 将设备坐标系下的线性加速度,旋转到世界坐标系
|
||||||
|
q_transform_to_world_with_quaternion(linear_acc_device, quaternion_data, tmp_world_acc);
|
||||||
|
|
||||||
|
|
||||||
|
float all_world_mag = sqrtf(tmp_world_acc[0] * tmp_world_acc[0] +
|
||||||
|
tmp_world_acc[1] * tmp_world_acc[1] +
|
||||||
|
tmp_world_acc[2] * tmp_world_acc[2]);
|
||||||
|
|
||||||
|
static int count = 0;
|
||||||
|
if(count > 100){
|
||||||
|
xlog("===original(g): x %.2f, y %.2f, z %.2f===\n",acc_g[0],acc_g[1],acc_g[2]);
|
||||||
|
xlog("===world(m/s^2) no g: x %.2f, y %.2f, z %.2f, all %.2f===\n",tmp_world_acc[0],tmp_world_acc[1],tmp_world_acc[2],all_world_mag); //去掉重力加速度
|
||||||
|
xlog("===gyr(dps) : x %.2f, y %.2f, z %.2f===\n",gyr_dps[0],gyr_dps[1],gyr_dps[2]); //angle
|
||||||
|
xlog("===angle : x %.2f, y %.2f, z %.2f,===\n",angle[0],angle[1],angle[2]);
|
||||||
|
xlog("===speed(cm/s): %d\n",(int)(tracker->speed*100) );
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 滑雪数据计算
|
||||||
|
*
|
||||||
|
* @param acc_data_buf 传入的三轴加速度数据
|
||||||
|
* @param gyr_data_buf 传入的三轴陀螺仪数据
|
||||||
|
* @param angle_data 传入的欧若拉角数据
|
||||||
|
* @return 速度cm/s
|
||||||
|
*/
|
||||||
|
uint16_t sensor_processing_task(signed short* acc_data_buf, signed short* gyr_data_buf, float* angle_data, float* quaternion) {
|
||||||
|
|
||||||
|
static int initialized = 0;
|
||||||
|
static float acc_data_g[3];
|
||||||
|
static float gyr_data_dps[3];
|
||||||
|
|
||||||
|
if(quaternion != NULL){
|
||||||
|
memcpy(quaternion_data, quaternion, 4 * sizeof(float));
|
||||||
|
}
|
||||||
|
|
||||||
|
// const float delta_time = DELTA_TIME+0.01f;
|
||||||
|
// const float delta_time = DELTA_TIME + 0.005f;
|
||||||
|
const float delta_time = DELTA_TIME;
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
skiing_tracker_init(&my_skiing_tracker);
|
||||||
|
initialized = 1;
|
||||||
|
printf("Skiing Tracker Initialized. Waiting for sensor calibration...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if ACC_RANGE==2
|
||||||
|
// 加速度 LSB to g
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 16384.0f;
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 16384.0f;
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 16384.0f;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ACC_RANGE==4
|
||||||
|
// 加速度 LSB to g
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 8192.0f;
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 8192.0f;
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 8192.0f;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ACC_RANGE==8
|
||||||
|
//±8g 4096
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 4096.0f; //ax
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 4096.0f; //ay
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 4096.0f; //az
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ACC_RANGE==16
|
||||||
|
//±16g 2048
|
||||||
|
acc_data_g[0] = (float)acc_data_buf[0] / 2048.0f; //ax
|
||||||
|
acc_data_g[1] = (float)acc_data_buf[1] / 2048.0f; //ay
|
||||||
|
acc_data_g[2] = (float)acc_data_buf[2] / 2048.0f; //az
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 陀螺仪 LSB to dps (度/秒)
|
||||||
|
// ±2000dps量程下,转换系数约为 0.061
|
||||||
|
gyr_data_dps[0] = (float)gyr_data_buf[0] * 0.061f;
|
||||||
|
gyr_data_dps[1] = (float)gyr_data_buf[1] * 0.061f;
|
||||||
|
gyr_data_dps[2] = (float)gyr_data_buf[2] * 0.061f;
|
||||||
|
|
||||||
|
skiing_tracker_update(&my_skiing_tracker, acc_data_g, gyr_data_dps, angle_data, delta_time);
|
||||||
|
|
||||||
|
|
||||||
|
return (uint16_t)(my_skiing_tracker.speed * 100);
|
||||||
|
}
|
||||||
|
|
||||||
83
apps/earphone/xtell_Sensor/calculate/skiing_tracker.h
Normal file
83
apps/earphone/xtell_Sensor/calculate/skiing_tracker.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#ifndef SKIING_TRACKER_H
|
||||||
|
#define SKIING_TRACKER_H
|
||||||
|
|
||||||
|
#include "../xtell.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
// 定义滑雪者可能的状态
|
||||||
|
typedef enum {
|
||||||
|
STATIC, // 静止或动态稳定:0
|
||||||
|
NO_CONSTANT_SPEED, // 正在滑雪,非匀速:1
|
||||||
|
CONSTANT_SPEED, // 正在滑雪,匀速:2
|
||||||
|
WOBBLE, // 正在原地旋转:3
|
||||||
|
WHEEL, // 转弯:4
|
||||||
|
FALLEN, // 已摔倒:5
|
||||||
|
TAKING_OFF, // 起跳冲击阶段:6
|
||||||
|
IN_AIR, // 空中失重阶段:7
|
||||||
|
LANDING, // 落地冲击阶段:8
|
||||||
|
STOP_DETECTION, // 停止检测:9
|
||||||
|
UNKNOWN // 未知状态:10
|
||||||
|
} skiing_state_t;
|
||||||
|
|
||||||
|
#define VARIANCE_BUFFER_SIZE 5 // 用于计算方差的数据窗口大小 (5个样本 @ 100Hz = 50ms),减小延迟,提高实时性
|
||||||
|
#define DELTA_TIME 0.01f
|
||||||
|
|
||||||
|
|
||||||
|
// 追踪器数据结构体
|
||||||
|
typedef struct {
|
||||||
|
// 公开数据
|
||||||
|
float velocity[3]; // 当前速度 (x, y, z),单位: m/s
|
||||||
|
float distance; // 总滑行距离,单位: m
|
||||||
|
float speed; // 当前速率 (标量),单位: m/s
|
||||||
|
skiing_state_t state; // 当前滑雪状态
|
||||||
|
|
||||||
|
// 内部计算使用的私有成员
|
||||||
|
float acc_no_g[3]; // 去掉重力分量后的加速度
|
||||||
|
|
||||||
|
// 用于空中距离计算
|
||||||
|
float time_in_air; // 滞空时间计时器
|
||||||
|
float initial_velocity_on_takeoff[3]; // 起跳瞬间的速度向量
|
||||||
|
int airborne_entry_counter; // 进入空中状态的确认计数器
|
||||||
|
int grounded_entry_counter; // 落地确认计数器
|
||||||
|
|
||||||
|
// --- 内部计算使用的私有成员 ---
|
||||||
|
// 用于动态零速更新和旋转检测的缓冲区
|
||||||
|
float acc_buffer[VARIANCE_BUFFER_SIZE][3]; // 加速度数据窗口
|
||||||
|
float gyr_buffer[VARIANCE_BUFFER_SIZE][3]; // 角速度数据窗口
|
||||||
|
int buffer_index; // 缓冲区当前索引
|
||||||
|
int buffer_filled; // 缓冲区是否已填满的标志
|
||||||
|
|
||||||
|
// 用于高通滤波器(巴特沃斯一阶滤波器)的私有成员,以消除加速度的直流偏置
|
||||||
|
float acc_world_filtered[3]; //过滤过的
|
||||||
|
float acc_world_unfiltered_prev[3]; //上一次没过滤的
|
||||||
|
|
||||||
|
float acc_world_lpf[3]; // 经过低通滤波后的世界坐标系加速度
|
||||||
|
} skiing_tracker_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
int acc_KS[3]; //卡尔曼后,LSB转换后的 三轴加速度数据(cm/s^2)
|
||||||
|
int gyr_KS_dps[3]; //卡尔曼后,LSB to dps 三轴陀螺仪数据
|
||||||
|
int angle_KS[3]; //卡尔曼后,计算得到的欧若拉角数据
|
||||||
|
}BLE_KS_send_data_t;
|
||||||
|
|
||||||
|
#ifdef XTELL_TEST
|
||||||
|
typedef struct{
|
||||||
|
float acc_variance; //三轴加速度方差之和
|
||||||
|
float gyr_variance; //三轴陀螺仪方差之和
|
||||||
|
float acc_magnitude; //三轴加速度模长
|
||||||
|
float gyr_magnitude; //三轴陀螺仪模长
|
||||||
|
}debug_t;
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* @brief 初始化滑雪追踪器
|
||||||
|
*
|
||||||
|
* @param tracker 指向 skiing_tracker_t 结构体的指针
|
||||||
|
*/
|
||||||
|
void skiing_tracker_init(skiing_tracker_t *tracker);
|
||||||
|
|
||||||
|
uint16_t sensor_processing_task(signed short* acc_data_buf, signed short* gyr_data_buf, float* angle_data, float* quaternion);
|
||||||
|
#endif // SKIING_TRACKER_H
|
||||||
@ -6,6 +6,8 @@
|
|||||||
#include "tone_player.h"
|
#include "tone_player.h"
|
||||||
#include "ui_manage.h"
|
#include "ui_manage.h"
|
||||||
#include "gpio.h"
|
#include "gpio.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
#include "app_main.h"
|
#include "app_main.h"
|
||||||
#include "asm/charge.h"
|
#include "asm/charge.h"
|
||||||
#include "update.h"
|
#include "update.h"
|
||||||
@ -15,11 +17,19 @@
|
|||||||
#include "bt_profile_cfg.h"
|
#include "bt_profile_cfg.h"
|
||||||
#include "dev_manager/dev_manager.h"
|
#include "dev_manager/dev_manager.h"
|
||||||
#include "update_loader_download.h"
|
#include "update_loader_download.h"
|
||||||
#include "LIS2DH12.h"
|
#include "./sensor/SC7U22.h"
|
||||||
#include "circle_buffer.h"
|
#include "./buffer/circle_buffer.h"
|
||||||
#include "circle_buffer.h"
|
|
||||||
#include "btstack/avctp_user.h"
|
#include "btstack/avctp_user.h"
|
||||||
|
#include "calculate/skiing_tracker.h"
|
||||||
|
#include "xtell.h"
|
||||||
|
#include "./ano/ano_protocol.h"
|
||||||
|
#include "./sensor/MMC56.h"
|
||||||
|
#include "./sensor/BMP280.h"
|
||||||
|
#include "./sensor/AK8963.h"
|
||||||
|
#include "asm/rtc.h"
|
||||||
|
#include "system/timer.h"
|
||||||
|
#include "adv_time_stamp_setting.h"
|
||||||
|
#include "btstack/le/le_user.h"
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//宏定义
|
//宏定义
|
||||||
#define ENABLE_XLOG 1
|
#define ENABLE_XLOG 1
|
||||||
@ -31,98 +41,481 @@
|
|||||||
#else
|
#else
|
||||||
#define xlog(format, ...) ((void)0)
|
#define xlog(format, ...) ((void)0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SENSOR_DATA_BUFFER_SIZE 200 // 定义缓冲区可以存储XXX个sensor_data_t元素
|
||||||
|
|
||||||
|
#define MPU_FIFO_INTERVAL 4 //隔多久读取六轴fifo,单位10ms
|
||||||
|
#define MPU_FIFO_LEN 16 //(MPU_FIFO_INTERVAL*10/2.5) //400hz采用频率,那每40ms的时间,fifo就有16组六轴数据
|
||||||
|
|
||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//START -- 函数定义
|
//START -- 函数定义
|
||||||
void send_data_to_ble_client(const u8* data, u16 length);
|
void send_data_to_ble_client(const u8* data, u16 length);
|
||||||
|
extern void create_process(u16* pid, const char* name, void *priv, void (*func)(void *priv), u32 msec);
|
||||||
|
extern void close_process(u16* pid,char* name);
|
||||||
|
void BLE_send_fuc(void);
|
||||||
//END -- 函数定义
|
//END -- 函数定义
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//START -- 变量定义
|
//START -- 变量定义
|
||||||
|
static u32 timer_offset_ms = 0;
|
||||||
|
|
||||||
// --- 任务ID ---
|
typedef struct{
|
||||||
static u16 xtell_i2c_test_id;
|
signed short SC7U22_data[6]; //12字节
|
||||||
static u16 collect_data_id;
|
int mmc5603nj_buffer[3]; //12字节
|
||||||
static u16 send_data_id;
|
int16_t temperature; //2
|
||||||
|
uint32_t pressure; //4
|
||||||
|
}sensor_package_t __attribute__((packed));
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
uint8_t checkout_1;
|
||||||
|
uint8_t checkout_2;
|
||||||
|
uint8_t foot; //1:左脚,2:右脚
|
||||||
|
uint8_t package_index;
|
||||||
|
sensor_package_t sensor_package[MPU_FIFO_LEN];//一次蓝牙发送MPU_FIFO_LEN组传感器数据
|
||||||
|
}ble_send_data_t; //一次蓝牙发送的数据内容
|
||||||
|
|
||||||
// --- 环形缓冲区 ---
|
// --- 环形缓冲区 ---
|
||||||
#define SENSOR_DATA_BUFFER_SIZE 512
|
static circle_buffer_t g_ble_send_cb; // 环形缓冲区管理结构体
|
||||||
static u8 sensor_data_buffer[SENSOR_DATA_BUFFER_SIZE];
|
static ble_send_data_t g_sensor_data_storage[SENSOR_DATA_BUFFER_SIZE]; //缓冲区
|
||||||
static circle_buffer_t sensor_cb;
|
|
||||||
|
extern u8 foot_init;
|
||||||
|
static OS_SEM receiver_ready_sem; // 用于启动同步的信号量
|
||||||
|
|
||||||
|
static const uart_bus_t *uart_bus = NULL;
|
||||||
|
|
||||||
|
static u16 test_id = 0;
|
||||||
//END -- 变量定义
|
//END -- 变量定义
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
// 采集传感器数据并存入环形缓冲区的任务
|
// 重置计时器
|
||||||
void collect_and_buffer_sensor_data_task(void) {
|
void reset_ms_timer(void) {
|
||||||
|
timer_offset_ms = sys_timer_get_ms();
|
||||||
motion_data_t current_motion;
|
xlog("Timer has been reset.\n");
|
||||||
axis_info_xtell total_accel;
|
|
||||||
axis_info_xtell linear_accel;
|
|
||||||
char data_string[256];
|
|
||||||
|
|
||||||
// 从驱动获取最新的运动数据
|
|
||||||
get_motion_data(¤t_motion);
|
|
||||||
total_accel = get_current_accel_mss();
|
|
||||||
linear_accel = get_linear_accel_mss();
|
|
||||||
|
|
||||||
// 将浮点数据转换为整数(乘以100以保留两位小数)进行格式化
|
|
||||||
int len = snprintf(data_string, sizeof(data_string),
|
|
||||||
"T:%d,%d,%d;L:%d,%d,%d;V:%d,%d,%d;D:%d,%d,%d\n",
|
|
||||||
(int)(total_accel.x * 100), (int)(total_accel.y * 100), (int)(total_accel.z * 100),
|
|
||||||
(int)(linear_accel.x * 100), (int)(linear_accel.y * 100), (int)(linear_accel.z * 100),
|
|
||||||
(int)(current_motion.velocity.x * 100), (int)(current_motion.velocity.y * 100), (int)(current_motion.velocity.z * 100),
|
|
||||||
(int)(current_motion.distance.x * 100), (int)(current_motion.distance.y * 100), (int)(current_motion.distance.z * 100));
|
|
||||||
|
|
||||||
// 写入环形缓冲区
|
|
||||||
u16 written = circle_buffer_write(&sensor_cb, (u8*)data_string, len);
|
|
||||||
if (written < len) {
|
|
||||||
xlog("The circular buffer is full!\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定义数组大小
|
// 获取从上次重置后经过的毫秒数
|
||||||
#define ARRAY_SIZE (178)
|
u32 get_ms_timer(void) {
|
||||||
// 在 main 函数外部声明为全局变量,它将被存储在静态数据区
|
return sys_timer_get_ms() - timer_offset_ms;
|
||||||
unsigned char global_data_array[ARRAY_SIZE];
|
|
||||||
|
|
||||||
// 从环形缓冲区读取数据并发送
|
|
||||||
void send_sensor_data_task(void) {
|
|
||||||
|
|
||||||
// printf("xtell_ble_send\n");
|
|
||||||
send_data_to_ble_client(&global_data_array,ARRAY_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void create_process(u16* pid, const char* name, void *priv, void (*func)(void *priv), u32 msec);
|
|
||||||
|
|
||||||
void rcsp_adv_fill_mac_addr(u8 *mac_addr_buf) //by xtell
|
|
||||||
{
|
|
||||||
swapX(bt_get_mac_addr(), mac_addr_buf, 6);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 传感器采集任务
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void sensor_collect_task(void){
|
||||||
|
static ble_send_data_t send_data;
|
||||||
|
mmc5603nj_mag_data_t mmc5603nj_buffer;
|
||||||
|
float temperature = 0;
|
||||||
|
float pressure = 0;
|
||||||
|
int interval = 0;
|
||||||
|
signed short accx_buf[100];
|
||||||
|
signed short accy_buf[100];
|
||||||
|
signed short accz_buf[100];
|
||||||
|
signed short gyrx_buf[100];
|
||||||
|
signed short gyry_buf[100];
|
||||||
|
signed short gyrz_buf[100];
|
||||||
|
int fifo_num = 0;
|
||||||
|
static int SL_data_index = 0;
|
||||||
|
u8 package_index = 1;
|
||||||
|
int tmp_index = 0;
|
||||||
|
|
||||||
|
while(1){//4组地磁数据、16组六轴数据、1组气压计数据
|
||||||
|
interval++;
|
||||||
|
mmc5603nj_read_mag_data(&mmc5603nj_buffer);
|
||||||
|
for(int i = (interval-1)*4; i < interval*4; i++){
|
||||||
|
send_data.sensor_package[i].mmc5603nj_buffer[0] = (int32_t)(mmc5603nj_buffer.x * 1000.0f);
|
||||||
|
send_data.sensor_package[i].mmc5603nj_buffer[1] = (int32_t)(mmc5603nj_buffer.y * 1000.0f);
|
||||||
|
send_data.sensor_package[i].mmc5603nj_buffer[2] = (int32_t)(mmc5603nj_buffer.z * 1000.0f);
|
||||||
|
}
|
||||||
|
// xlog("MAG x: %.2f,y: %.2f,z: %.2f\n",mmc5603nj_buffer.x,mmc5603nj_buffer.y,mmc5603nj_buffer.z);
|
||||||
|
|
||||||
|
SL_SC7U22_FIFO_Read(accx_buf,accy_buf,accz_buf,gyrx_buf,gyry_buf,gyrz_buf); //一次性读取内置fifo的数据
|
||||||
|
for(int i = 0; i < MPU_FIFO_LEN/4; i++){
|
||||||
|
tmp_index = SL_data_index + i;
|
||||||
|
// if(tmp_index >= MPU_FIFO_LEN-1) tmp_index = MPU_FIFO_LEN-1;
|
||||||
|
send_data.sensor_package[tmp_index].SC7U22_data[0] = accx_buf[i]; //acc_x
|
||||||
|
send_data.sensor_package[tmp_index].SC7U22_data[1] = accy_buf[i]; //acc_y
|
||||||
|
send_data.sensor_package[tmp_index].SC7U22_data[2] = accz_buf[i]; //acc_z
|
||||||
|
send_data.sensor_package[tmp_index].SC7U22_data[3] = gyrx_buf[i]; //gyr_x
|
||||||
|
send_data.sensor_package[tmp_index].SC7U22_data[4] = gyry_buf[i]; //gyr_y
|
||||||
|
send_data.sensor_package[tmp_index].SC7U22_data[5] = gyrz_buf[i]; //gyr_z
|
||||||
|
|
||||||
|
// xlog(" Acc_x : %4d, Acc_y : %4d, Acc_z : %4d,\r\n", send_data.sensor_package[tmp_index].SC7U22_data[0], send_data.sensor_package[tmp_index].SC7U22_data[1], send_data.sensor_package[tmp_index].SC7U22_data[2]);
|
||||||
|
#if 0
|
||||||
|
float acc_g[3];
|
||||||
|
float gyr_dps[3];
|
||||||
|
acc_g[0] = (float)send_data.sensor_package[tmp_index].SC7U22_data[0] / 2048.0f;
|
||||||
|
acc_g[1] = (float)send_data.sensor_package[tmp_index].SC7U22_data[1] / 2048.0f;
|
||||||
|
acc_g[2] = (float)send_data.sensor_package[tmp_index].SC7U22_data[2] / 2048.0f;
|
||||||
|
gyr_dps[0] = (float)send_data.sensor_package[tmp_index].SC7U22_data[3] * 0.061f;
|
||||||
|
gyr_dps[1] = (float)send_data.sensor_package[tmp_index].SC7U22_data[4] * 0.061f;
|
||||||
|
gyr_dps[2] = (float)send_data.sensor_package[tmp_index].SC7U22_data[5] * 0.061f;
|
||||||
|
printf(" ACC(g): x=%.3f, y=%.3f, z=%.3f\n", acc_g[0], acc_g[1], acc_g[2]);
|
||||||
|
printf(" GYR(dps):x=%.3f, y=%.3f, z=%.3f\n", gyr_dps[0], gyr_dps[1], gyr_dps[2]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
SL_data_index += MPU_FIFO_LEN/4;
|
||||||
|
|
||||||
|
|
||||||
|
if(interval >= 4){
|
||||||
|
interval = 0;
|
||||||
|
SL_data_index = 0;
|
||||||
|
// bmp280_read_data(&temperature, &pressure);//每40ms读取一次
|
||||||
|
for(int i = 0;i<MPU_FIFO_LEN;i++){
|
||||||
|
send_data.sensor_package[i].temperature = (int16_t)(temperature * 1000.0f);
|
||||||
|
send_data.sensor_package[i].pressure = (int32_t)(pressure * 1000.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// xlog("temperature: %.2f,pressure: %.2f\n",temperature,pressure);
|
||||||
|
// xlog("fifo_num:%d\n",fifo_num);
|
||||||
|
|
||||||
|
send_data.checkout_1 = 0xBE;
|
||||||
|
send_data.checkout_2 = 0xBB;
|
||||||
|
send_data.foot = foot_init;
|
||||||
|
send_data.package_index = package_index;
|
||||||
|
circle_buffer_write(&g_ble_send_cb, &send_data);
|
||||||
|
os_sem_post(&receiver_ready_sem); //通知另一个发送任务
|
||||||
|
|
||||||
|
memset(&send_data, 0, sizeof(ble_send_data_t));
|
||||||
|
memset(&accx_buf, 0, sizeof(accx_buf));
|
||||||
|
memset(&accy_buf, 0, sizeof(accy_buf));
|
||||||
|
memset(&accz_buf, 0, sizeof(accz_buf));
|
||||||
|
memset(&gyrx_buf, 0, sizeof(gyrx_buf));
|
||||||
|
memset(&gyry_buf, 0, sizeof(gyry_buf));
|
||||||
|
memset(&gyrz_buf, 0, sizeof(gyrz_buf));
|
||||||
|
|
||||||
|
package_index++;
|
||||||
|
if(package_index >= 0xFF) package_index = 1;
|
||||||
|
// xlog("=====================%d============================\n",get_ms_timer());
|
||||||
|
}
|
||||||
|
os_time_dly(1); //10ms为单位
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void data_log(uint8_t* data){
|
||||||
|
static u8 imu_airplane[MPU_FIFO_LEN][12];
|
||||||
|
// 检查数据包头部
|
||||||
|
if (data[0] != 0xBE || data[1] != 0xBB) {
|
||||||
|
printf("Error: Invalid data packet header.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//左右脚
|
||||||
|
uint8_t package_foot = data[2];
|
||||||
|
|
||||||
|
// 解析包索引
|
||||||
|
uint8_t package_index = data[3];
|
||||||
|
printf("--- Parsing Data Packet Index: %d ---\n", package_index);
|
||||||
|
|
||||||
|
uint8_t* p = &data[4]; // 指向数据负载的起始位置
|
||||||
|
|
||||||
|
// 循环解析16组数据
|
||||||
|
for (int i = 0; i < MPU_FIFO_LEN; i++) {
|
||||||
|
// 1. 解析六轴传感器数据 (12 bytes)
|
||||||
|
int16_t imu_raw[6];
|
||||||
|
for (int j = 0; j < 6; j++) {
|
||||||
|
imu_airplane[i][2*j] = p[0];
|
||||||
|
imu_airplane[i][2*j+1] = p[1];
|
||||||
|
// 小端模式: 低字节在前, 高字节在后
|
||||||
|
imu_raw[j] = (int16_t)(((uint16_t)p[1] << 8) | (uint16_t)p[0]);
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
float acc_g[3];
|
||||||
|
float gyr_dps[3];
|
||||||
|
acc_g[0] = (float)imu_raw[0] / 2048.0f;
|
||||||
|
acc_g[1] = (float)imu_raw[1] / 2048.0f;
|
||||||
|
acc_g[2] = (float)imu_raw[2] / 2048.0f;
|
||||||
|
gyr_dps[0] = (float)imu_raw[3] * 0.061f;
|
||||||
|
gyr_dps[1] = (float)imu_raw[4] * 0.061f;
|
||||||
|
gyr_dps[2] = (float)imu_raw[5] * 0.061f;
|
||||||
|
|
||||||
|
// 2. 解析地磁传感器数据 (12 bytes)
|
||||||
|
int32_t mag_raw[3];
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
// 小端模式
|
||||||
|
mag_raw[j] = (int32_t)(((uint32_t)p[3] << 24) | ((uint32_t)p[2] << 16) | ((uint32_t)p[1] << 8) | (uint32_t)p[0]);
|
||||||
|
p += 4;
|
||||||
|
}
|
||||||
|
float mag_gauss[3];
|
||||||
|
mag_gauss[0] = (float)mag_raw[0] / 1000.0f;
|
||||||
|
mag_gauss[1] = (float)mag_raw[1] / 1000.0f;
|
||||||
|
mag_gauss[2] = (float)mag_raw[2] / 1000.0f;
|
||||||
|
|
||||||
|
// 3. 解析温度数据 (2 bytes)
|
||||||
|
int16_t temp_raw = (int16_t)(((uint16_t)p[1] << 8) | (uint16_t)p[0]);
|
||||||
|
p += 2;
|
||||||
|
float temperature = (float)temp_raw / 1000.0f;
|
||||||
|
|
||||||
|
// 4. 解析气压数据 (4 bytes)
|
||||||
|
uint32_t press_raw = (uint32_t)(((uint32_t)p[3] << 24) | ((uint32_t)p[2] << 16) | ((uint32_t)p[1] << 8) | (uint32_t)p[0]);
|
||||||
|
p += 4;
|
||||||
|
float pressure = (float)press_raw / 1000.0f;
|
||||||
|
|
||||||
|
// 打印解析后的数据
|
||||||
|
// if(i % 8 == 0){
|
||||||
|
// printf(" ==================ble index: %d\n", *p);
|
||||||
|
// printf("Package[%d]:\n", i);
|
||||||
|
// printf(" ACC(g): x=%.3f, y=%.3f, z=%.3f\n", acc_g[0], acc_g[1], acc_g[2]);
|
||||||
|
// printf(" GYR(dps):x=%.3f, y=%.3f, z=%.3f\n", gyr_dps[0], gyr_dps[1], gyr_dps[2]);
|
||||||
|
// printf(" MAG(Gs): x=%.3f, y=%.3f, z=%.3f\n", mag_gauss[0], mag_gauss[1], mag_gauss[2]);
|
||||||
|
// printf(" TEMP(C): %.3f, PRESS(Pa): %.3f\n", temperature, pressure);
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
// printf("--- End of Packet ---\n\n");
|
||||||
|
|
||||||
|
extern void uartSendData(void *buf, u16 len) ; // 确保u16是uint16_t或unsigned short
|
||||||
|
// uartSendData(imu_airplane, sizeof(imu_airplane));
|
||||||
|
uartSendData(data, 484); // 发送总共17字节
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ble数据发送函数
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void BLE_send_fuc(void){
|
||||||
|
ble_send_data_t send_data;
|
||||||
|
uint8_t send_buffer[484];
|
||||||
|
while(1){
|
||||||
|
os_sem_pend(&receiver_ready_sem, 0); //阻塞等待
|
||||||
|
circle_buffer_read(&g_ble_send_cb, &send_data);
|
||||||
|
|
||||||
|
// 逐字节打包数据到 send_buffer, 采用小端模式
|
||||||
|
uint8_t *p = send_buffer;
|
||||||
|
*p++ = send_data.checkout_1;
|
||||||
|
*p++ = send_data.checkout_2;
|
||||||
|
*p++ = send_data.foot;
|
||||||
|
*p++ = send_data.package_index;
|
||||||
|
|
||||||
|
for (int i = 0; i < MPU_FIFO_LEN; i++) {
|
||||||
|
sensor_package_t *pkg = &send_data.sensor_package[i];
|
||||||
|
|
||||||
|
// 1. 打包六轴数据 (6 * int16_t)
|
||||||
|
for (int j = 0; j < 6; j++) {
|
||||||
|
*p++ = (uint8_t)(pkg->SC7U22_data[j] & 0xFF);
|
||||||
|
*p++ = (uint8_t)((pkg->SC7U22_data[j] >> 8) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 打包地磁数据 (3 * int32_t)
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
*p++ = (uint8_t)(pkg->mmc5603nj_buffer[j] & 0xFF);
|
||||||
|
*p++ = (uint8_t)((pkg->mmc5603nj_buffer[j] >> 8) & 0xFF);
|
||||||
|
*p++ = (uint8_t)((pkg->mmc5603nj_buffer[j] >> 16) & 0xFF);
|
||||||
|
*p++ = (uint8_t)((pkg->mmc5603nj_buffer[j] >> 24) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 打包温度数据 (int16_t)
|
||||||
|
*p++ = (uint8_t)(pkg->temperature & 0xFF);
|
||||||
|
*p++ = (uint8_t)((pkg->temperature >> 8) & 0xFF);
|
||||||
|
|
||||||
|
// 4. 打包气压数据 (uint32_t)
|
||||||
|
*p++ = (uint8_t)(pkg->pressure & 0xFF);
|
||||||
|
*p++ = (uint8_t)((pkg->pressure >> 8) & 0xFF);
|
||||||
|
*p++ = (uint8_t)((pkg->pressure >> 16) & 0xFF);
|
||||||
|
*p++ = (uint8_t)((pkg->pressure >> 24) & 0xFF);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
float acc_g[3];
|
||||||
|
float gyr_dps[3];
|
||||||
|
acc_g[0] = (float)send_data.sensor_package[i].SC7U22_data[0] / 2048.0f;
|
||||||
|
acc_g[1] = (float)send_data.sensor_package[i].SC7U22_data[1] / 2048.0f;
|
||||||
|
acc_g[2] = (float)send_data.sensor_package[i].SC7U22_data[2] / 2048.0f;
|
||||||
|
gyr_dps[0] = (float)send_data.sensor_package[i].SC7U22_data[3] * 0.061f;
|
||||||
|
gyr_dps[1] = (float)send_data.sensor_package[i].SC7U22_data[4] * 0.061f;
|
||||||
|
gyr_dps[2] = (float)send_data.sensor_package[i].SC7U22_data[5] * 0.061f;
|
||||||
|
printf(" ACC(g): x=%.3f, y=%.3f, z=%.3f\n", acc_g[0], acc_g[1], acc_g[2]);
|
||||||
|
printf(" GYR(dps):x=%.3f, y=%.3f, z=%.3f\n", gyr_dps[0], gyr_dps[1], gyr_dps[2]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// extern void uartSendData(void *buf, u16 len) ; // 确保u16是uint16_t或unsigned short
|
||||||
|
// uartSendData(send_buffer, 484); // 发送总共17字节
|
||||||
|
send_data_to_ble_client(send_buffer, 484); // 发送数据
|
||||||
|
|
||||||
|
// data_log(send_buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------------
|
||||||
|
// ------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 开始采集传感器数据并通过ble发送
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void start_clloct(void){
|
||||||
|
os_task_create(sensor_collect_task,NULL,5,1024,32,"sensor_collect_task");
|
||||||
|
os_task_create(BLE_send_fuc,NULL,5,1024,32,"BLE_send_fuc");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 停止采集和ble发送
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void stop_clloct(void){
|
||||||
|
os_task_del("sensor_collect_task");
|
||||||
|
os_task_del("BLE_send_fuc");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化,在app_main.c的app_main函数被调用
|
||||||
|
*
|
||||||
|
*/
|
||||||
void xtell_task_create(void){
|
void xtell_task_create(void){
|
||||||
|
|
||||||
|
#if TCFG_GSENOR_USER_IIC_TYPE
|
||||||
|
int ret = hw_iic_init(0);
|
||||||
|
xlog("init iic result:%d\n", ret); //返回0成功
|
||||||
|
#else
|
||||||
|
int ret = soft_iic_init(0);
|
||||||
|
int num_chars_written = snprintf(log_buffer_1, sizeof(log_buffer_1),"init iic: %d\n", ret);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// MPU9250_Mag_Init();
|
||||||
|
//iic总线设备扫描
|
||||||
|
// extern void i2c_scanner_probe(void);
|
||||||
|
// i2c_scanner_probe();
|
||||||
|
|
||||||
xlog("xtell_task_create\n");
|
xlog("xtell_task_create\n");
|
||||||
//写入测试数据
|
|
||||||
for (int i = 0; i < ARRAY_SIZE; i++) { //ARRAY_SIZE字节的数组
|
circle_buffer_init(&g_ble_send_cb, g_sensor_data_storage, SENSOR_DATA_BUFFER_SIZE, sizeof(ble_send_data_t));
|
||||||
global_data_array[i] = i % 256;
|
|
||||||
|
os_sem_create(&receiver_ready_sem, 0);
|
||||||
|
|
||||||
|
extern void test_uart_init(void);
|
||||||
|
test_uart_init();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化环形缓冲区
|
|
||||||
circle_buffer_init(&sensor_cb, sensor_data_buffer, SENSOR_DATA_BUFFER_SIZE);
|
|
||||||
|
|
||||||
|
/**
|
||||||
// 创建一个定时器,每200ms调用一次核心计算任务
|
* @brief 发给上位机
|
||||||
// create_process(&xtell_i2c_test_id, "xtell_i2c_test", NULL, xtell_i2c_test, (u32)(SAMPLING_PERIOD_S * 1000));
|
*
|
||||||
|
*/
|
||||||
// 创建一个定时器,每1000ms采集一次数据
|
void test_uart_init(void){
|
||||||
// create_process(&collect_data_id, "collect_data", NULL, collect_and_buffer_sensor_data_task, 1000);
|
#if TCFG_UART0_ENABLE == 0
|
||||||
|
static u8 buff[40];
|
||||||
// 创建一个定时器,每200ms尝试发送一次数据
|
struct uart_platform_data_t u_arg = {0};
|
||||||
create_process(&send_data_id, "send_data", NULL, send_sensor_data_task, 1);
|
u_arg.tx_pin = IO_PORT_DP;
|
||||||
|
u_arg.rx_cbuf = buff;
|
||||||
|
u_arg.rx_cbuf_size = 32;
|
||||||
|
u_arg.frame_length = 6;
|
||||||
|
u_arg.rx_timeout = 100;
|
||||||
|
u_arg.isr_cbfun = NULL;
|
||||||
|
u_arg.baud = 1000000;
|
||||||
|
u_arg.is_9bit = 0;
|
||||||
|
uart_bus = uart_dev_open(&u_arg);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void uartSendData(void *buf, u16 len) //发送数据的接口。
|
||||||
|
{
|
||||||
|
#if TCFG_UART0_ENABLE == 0
|
||||||
|
if (uart_bus) {
|
||||||
|
uart_bus->write(buf, len); //把数据写到DMA
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//test
|
||||||
|
//
|
||||||
|
|
||||||
|
#define BUFF_LEN 500
|
||||||
|
static signed char acc_data_buf[BUFF_LEN] = {0};
|
||||||
|
// 1. 定义一个全局的信号量
|
||||||
|
static OS_SEM ble_send_sem;
|
||||||
|
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
void data_send_task(void){
|
||||||
|
signed short accx_buf[100];
|
||||||
|
signed short accy_buf[100];
|
||||||
|
signed short accz_buf[100];
|
||||||
|
signed short gyrx_buf[100];
|
||||||
|
signed short gyry_buf[100];
|
||||||
|
signed short gyrz_buf[100];
|
||||||
|
SL_SC7U22_FIFO_Read(accx_buf,accy_buf,accz_buf,gyrx_buf,gyry_buf,gyrz_buf); //一次性读取内置fifo的数据
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
// 定义新的Packet ID和数据长度
|
||||||
|
#define PACKET_ID_RAW_IMU 0x04
|
||||||
|
#define PACKET_LENGTH_RAW_IMU 12 // 6个传感器值,每个2字节
|
||||||
|
|
||||||
|
// 声明一个发送缓冲区,用于包含帧头、ID、长度、数据和校验和
|
||||||
|
// 帧头 (2) + ID (1) + 长度 (1) + 数据 (12) + 校验和 (1) = 17 字节
|
||||||
|
uint8_t tx_buffer[2 + 1 + 1 + PACKET_LENGTH_RAW_IMU + 1];
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
int i; // 用于循环计算校验和
|
||||||
|
|
||||||
|
// 填充帧头
|
||||||
|
tx_buffer[0] = 0xAA;
|
||||||
|
tx_buffer[1] = 0xFF;
|
||||||
|
|
||||||
|
// 填充Packet ID和长度
|
||||||
|
tx_buffer[2] = PACKET_ID_RAW_IMU;
|
||||||
|
tx_buffer[3] = PACKET_LENGTH_RAW_IMU;
|
||||||
|
|
||||||
|
// 填充原始传感器数据 (与你原先的processing_data内容相同)
|
||||||
|
tx_buffer[4] = (uint8_t)(accx_buf[0] & 0xFF); // accX LSB
|
||||||
|
tx_buffer[5] = (uint8_t)(accx_buf[0] >> 8 & 0xFF); // accX MSB
|
||||||
|
tx_buffer[6] = (uint8_t)(accy_buf[0] & 0xFF); // accY LSB
|
||||||
|
tx_buffer[7] = (uint8_t)(accy_buf[0] >> 8 & 0xFF); // accY MSB
|
||||||
|
tx_buffer[8] = (uint8_t)(accz_buf[0] & 0xFF); // accZ LSB
|
||||||
|
tx_buffer[9] = (uint8_t)(accz_buf[0] >> 8 & 0xFF); // accZ MSB
|
||||||
|
tx_buffer[10] = (uint8_t)(gyrx_buf[0] & 0xFF); // gyrX LSB
|
||||||
|
tx_buffer[11] = (uint8_t)(gyrx_buf[0] >> 8 & 0xFF); // gyrX MSB
|
||||||
|
tx_buffer[12] = (uint8_t)(gyry_buf[0] & 0xFF); // gyrY LSB
|
||||||
|
tx_buffer[13] = (uint8_t)(gyry_buf[0] >> 8 & 0xFF); // gyrY MSB
|
||||||
|
tx_buffer[14] = (uint8_t)(gyrz_buf[0] & 0xFF); // gyrZ LSB
|
||||||
|
tx_buffer[15] = (uint8_t)(gyrz_buf[0] >> 8 & 0xFF); // gyrZ MSB
|
||||||
|
|
||||||
|
// 计算校验和 (从 Packet ID 到所有数据字节的和)
|
||||||
|
checksum = tx_buffer[2] + tx_buffer[3]; // ID + Length
|
||||||
|
for (i = 0; i < PACKET_LENGTH_RAW_IMU; i++) {
|
||||||
|
checksum += tx_buffer[4 + i]; // 加上所有数据字节
|
||||||
|
}
|
||||||
|
tx_buffer[4 + PACKET_LENGTH_RAW_IMU] = checksum; // 校验和是最后一个字节
|
||||||
|
|
||||||
|
// 发送整个缓冲区
|
||||||
|
extern void uartSendData(void *buf, u16 len) ; // 确保u16是uint16_t或unsigned short
|
||||||
|
uartSendData(tx_buffer, sizeof(tx_buffer)); // 发送总共17字节
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
static u16 gtest_id = 0;
|
||||||
|
void test_func(void){
|
||||||
|
// a. 初始化信号量,初始值为0
|
||||||
|
// os_sem_create(&ble_send_sem, 0);
|
||||||
|
|
||||||
|
// b. 注册回调函数,让协议栈知道在准备好时该调用谁
|
||||||
|
// struct ble_server_operation_t *ble_ops;
|
||||||
|
// ble_get_server_operation_table(&ble_ops);
|
||||||
|
// ble_ops->regist_wakeup_send(NULL, on_ble_can_send);
|
||||||
|
for(int i = 0;i<BUFF_LEN;i++){
|
||||||
|
acc_data_buf[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
SL_SC7U22_Config();
|
||||||
|
mmc5603nj_init();
|
||||||
|
bmp280_init();
|
||||||
|
os_task_create(BLE_send_fuc,NULL,5,1024,32,"BLE_send_fuc");
|
||||||
|
os_task_create(sensor_collect_task,NULL,5,1024,32,"sensor_collect_task");
|
||||||
|
// create_process(&test_id, "sensor_test",NULL,data_send_task ,3);
|
||||||
|
// data_send_task();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
133
apps/earphone/xtell_Sensor/sensor/AK8963.c
Normal file
133
apps/earphone/xtell_Sensor/sensor/AK8963.c
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
|
||||||
|
#include "AK8963.h"
|
||||||
|
#include "math.h"
|
||||||
|
#include "os/os_api.h"
|
||||||
|
#include "../xtell.h"
|
||||||
|
#include "printf.h"
|
||||||
|
|
||||||
|
// 用于存放从Fuse ROM读取的磁力计灵敏度校准值
|
||||||
|
static float mag_asa_x = 1.0f;
|
||||||
|
static float mag_asa_y = 1.0f;
|
||||||
|
static float mag_asa_z = 1.0f;
|
||||||
|
|
||||||
|
// 磁力计在16-bit分辨率下的转换因子 (单位: uT/LSB)
|
||||||
|
#define MAG_RAW_TO_UT_FACTOR (4912.0f / 32760.0f)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化MPU9250的磁力计AK8963
|
||||||
|
* @return 0: 成功, 1: MPU9250连接失败, 2: AK8963连接失败
|
||||||
|
*/
|
||||||
|
u8 MPU9250_Mag_Init(void) {
|
||||||
|
|
||||||
|
u8 temp_data[3];
|
||||||
|
|
||||||
|
// --- 检查 MPU9250 连接并复位 ---
|
||||||
|
_gravity_sensor_get_ndata(MPU9250_ADDR_R, MPU9250_WHO_AM_I, temp_data, 1);
|
||||||
|
if (temp_data[0] != 0x71 && temp_data[0] != 0x73) {
|
||||||
|
printf("MPU9250 comm failed, read ID: 0x%X\n", temp_data[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("MPU9250 get id:0x%X\n", temp_data[0]);
|
||||||
|
|
||||||
|
gravity_sensor_command(MPU9250_ADDR_W, MPU9250_PWR_MGMT_1, 0x80); // 软复位
|
||||||
|
os_time_dly(10); // 等待复位完成
|
||||||
|
|
||||||
|
gravity_sensor_command(MPU9250_ADDR_W, MPU9250_PWR_MGMT_1, 0x01); // 退出睡眠,选择时钟源
|
||||||
|
os_time_dly(2);
|
||||||
|
|
||||||
|
// --- 强制复位 I2C Master 模块并开启旁路 ---
|
||||||
|
|
||||||
|
gravity_sensor_command(MPU9250_ADDR_W, MPU9250_USER_CTRL, 0x20);
|
||||||
|
os_time_dly(1);
|
||||||
|
gravity_sensor_command(MPU9250_ADDR_W, MPU9250_USER_CTRL, 0x00);
|
||||||
|
os_time_dly(1);
|
||||||
|
|
||||||
|
gravity_sensor_command(MPU9250_ADDR_W, MPU9250_INT_PIN_CFG, 0x02);
|
||||||
|
os_time_dly(2);
|
||||||
|
|
||||||
|
// --- 再次验证 AK8963 连接 ---
|
||||||
|
_gravity_sensor_get_ndata(AK8963_ADDR_R, AK8963_WIA, temp_data, 1);
|
||||||
|
if (temp_data[0] != 0x48) {
|
||||||
|
printf("AK8963 comm failed after final attempt, read ID: 0x%X\n", temp_data[0]);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
printf("AK8963 get id: 0x%X\n", temp_data[0]);
|
||||||
|
|
||||||
|
// ------------------ 配置 AK8963 ------------------
|
||||||
|
// Power-down模式
|
||||||
|
gravity_sensor_command(AK8963_ADDR_W, AK8963_CNTL1, 0x00);
|
||||||
|
os_time_dly(1);
|
||||||
|
|
||||||
|
// Fuse ROM access模式
|
||||||
|
gravity_sensor_command(AK8963_ADDR_W, AK8963_CNTL1, 0x0F);
|
||||||
|
os_time_dly(1);
|
||||||
|
_gravity_sensor_get_ndata(AK8963_ADDR_R, AK8963_ASAX, temp_data, 3);
|
||||||
|
|
||||||
|
// 计算校准系数
|
||||||
|
mag_asa_x = (float)(temp_data[0] - 128) / 256.0f + 1.0f;
|
||||||
|
mag_asa_y = (float)(temp_data[1] - 128) / 256.0f + 1.0f;
|
||||||
|
mag_asa_z = (float)(temp_data[2] - 128) / 256.0f + 1.0f;
|
||||||
|
|
||||||
|
// 再次进入Power-down模式
|
||||||
|
gravity_sensor_command(AK8963_ADDR_W, AK8963_CNTL1, 0x00);
|
||||||
|
os_time_dly(1);
|
||||||
|
|
||||||
|
// 设置工作模式:16-bit分辨率,100Hz连续测量模式 (0x16)
|
||||||
|
gravity_sensor_command(AK8963_ADDR_W, AK8963_CNTL1, 0x16);
|
||||||
|
os_time_dly(1);
|
||||||
|
|
||||||
|
printf("AK8963 configured successfully.\n");
|
||||||
|
return 0; // 初始化成功
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取磁力计的三轴原始数据
|
||||||
|
* @param mx, my, mz - 用于存放X, Y, Z轴数据的指针 (int16_t类型)
|
||||||
|
* @return 0: 成功, 1: 数据未就绪, 2: 数据溢出
|
||||||
|
*/
|
||||||
|
u8 MPU9250_Read_Mag_Raw(int16_t *mx, int16_t *my, int16_t *mz) {
|
||||||
|
u8 read_buf[7];
|
||||||
|
|
||||||
|
// 检查数据是否准备好 (使用8位读地址)
|
||||||
|
_gravity_sensor_get_ndata(AK8963_ADDR_R, AK8963_ST1, read_buf, 1);
|
||||||
|
if (!(read_buf[0] & 0x01)) {
|
||||||
|
return 1; // 数据未就绪
|
||||||
|
}
|
||||||
|
|
||||||
|
// 连续读取7个字节 (使用8位读地址)
|
||||||
|
_gravity_sensor_get_ndata(AK8963_ADDR_R, AK8963_HXL, read_buf, 7);
|
||||||
|
|
||||||
|
// 检查数据是否溢出
|
||||||
|
if (read_buf[6] & 0x08) {
|
||||||
|
return 2; // 数据溢出
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组合数据
|
||||||
|
*mx = (int16_t)((read_buf[1] << 8) | read_buf[0]);
|
||||||
|
*my = (int16_t)((read_buf[3] << 8) | read_buf[2]);
|
||||||
|
*mz = (int16_t)((read_buf[5] << 8) | read_buf[4]);
|
||||||
|
|
||||||
|
return 0; // 读取成功
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取磁力计的三轴数据,并转换为uT(微特斯拉) (此函数内部逻辑不变)
|
||||||
|
* @param mx, my, mz - 用于存放X, Y, Z轴数据的指针 (float类型)
|
||||||
|
* @return 0: 成功, 1: 数据未就绪, 2: 数据溢出
|
||||||
|
*/
|
||||||
|
u8 MPU9250_Read_Mag_uT(float *mx, float *my, float *mz) {
|
||||||
|
int16_t raw_mx, raw_my, raw_mz;
|
||||||
|
|
||||||
|
u8 status = MPU9250_Read_Mag_Raw(&raw_mx, &raw_my, &raw_mz);
|
||||||
|
if (status != 0) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用灵敏度校准,并转换为uT单位
|
||||||
|
*mx = (float)raw_mx * mag_asa_x * MAG_RAW_TO_UT_FACTOR;
|
||||||
|
*my = (float)raw_my * mag_asa_y * MAG_RAW_TO_UT_FACTOR;
|
||||||
|
*mz = (float)raw_mz * mag_asa_z * MAG_RAW_TO_UT_FACTOR;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
46
apps/earphone/xtell_Sensor/sensor/AK8963.h
Normal file
46
apps/earphone/xtell_Sensor/sensor/AK8963.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// mpu9250_mag.h
|
||||||
|
|
||||||
|
#ifndef __MPU9250_MAG_H
|
||||||
|
#define __MPU9250_MAG_H
|
||||||
|
|
||||||
|
#include "stdint.h" // 假设你有标准整数类型,u8 对应 uint8_t
|
||||||
|
#include "gSensor/gSensor_manage.h"
|
||||||
|
|
||||||
|
//==================================================================================
|
||||||
|
// MPU9250 和 AK8963 的 I2C 地址 (已转换为8位格式)
|
||||||
|
//==================================================================================
|
||||||
|
// MPU9250的7位地址是 0x68(接地)
|
||||||
|
#define MPU9250_ADDR_7BIT 0x69
|
||||||
|
#define MPU9250_ADDR_W (MPU9250_ADDR_7BIT << 1 | 0) // 8位写地址: 0xD0
|
||||||
|
#define MPU9250_ADDR_R (MPU9250_ADDR_7BIT << 1 | 1) // 8位读地址: 0xD1
|
||||||
|
|
||||||
|
// AK8963磁力计的7位地址是 0x0C
|
||||||
|
#define AK8963_ADDR_7BIT 0x0C
|
||||||
|
#define AK8963_ADDR_W (AK8963_ADDR_7BIT << 1 | 0) // 8位写地址: 0x18
|
||||||
|
#define AK8963_ADDR_R (AK8963_ADDR_7BIT << 1 | 1) // 8位读地址: 0x19
|
||||||
|
|
||||||
|
|
||||||
|
//==================================================================================
|
||||||
|
// MPU9250 相关寄存器 (用于开启旁路模式)
|
||||||
|
//==================================================================================
|
||||||
|
#define MPU9250_WHO_AM_I 0x75
|
||||||
|
#define MPU9250_INT_PIN_CFG 0x37
|
||||||
|
#define MPU9250_USER_CTRL 0x6A
|
||||||
|
#define MPU9250_PWR_MGMT_1 0x6B
|
||||||
|
//==================================================================================
|
||||||
|
// AK8963 磁力计相关寄存器
|
||||||
|
//==================================================================================
|
||||||
|
#define AK8963_WIA 0x00
|
||||||
|
#define AK8963_ST1 0x02
|
||||||
|
#define AK8963_HXL 0x03
|
||||||
|
#define AK8963_ST2 0x09
|
||||||
|
#define AK8963_CNTL1 0x0A
|
||||||
|
#define AK8963_ASAX 0x10
|
||||||
|
|
||||||
|
|
||||||
|
u8 MPU9250_Mag_Init(void);
|
||||||
|
u8 MPU9250_Read_Mag_Raw(int16_t *mx, int16_t *my, int16_t *mz);
|
||||||
|
u8 MPU9250_Read_Mag_uT(float *mx, float *my, float *mz);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // __MPU9250_MAG_H
|
||||||
216
apps/earphone/xtell_Sensor/sensor/BMP280.c
Normal file
216
apps/earphone/xtell_Sensor/sensor/BMP280.c
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
气压计
|
||||||
|
根据手册,对于室内导航的配置推荐:
|
||||||
|
t_standby=0.5ms, filter=16, spi_en=0
|
||||||
|
osrs_t=x2, osrs_p=x16, mode=normal
|
||||||
|
采样率为26.3Hz,外部每40ms读取一次
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "BMP280.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include "os/os_api.h"
|
||||||
|
#include "gSensor/gSensor_manage.h"
|
||||||
|
|
||||||
|
/*==================================================================================*/
|
||||||
|
/* BMP280 内部定义 */
|
||||||
|
/*==================================================================================*/
|
||||||
|
|
||||||
|
// 存储校准参数的静态全局变量
|
||||||
|
static uint16_t t1;
|
||||||
|
static int16_t t2, t3;
|
||||||
|
static uint16_t p1;
|
||||||
|
static int16_t p2, p3, p4, p5, p6, p7, p8, p9;
|
||||||
|
static int32_t t_fine;
|
||||||
|
|
||||||
|
/*==================================================================================*/
|
||||||
|
/* 封装的底层I2C读写函数 */
|
||||||
|
/*==================================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 写入单个字节到BMP280寄存器
|
||||||
|
*/
|
||||||
|
static uint8_t bmp280_write_reg(uint8_t reg, uint8_t data) {
|
||||||
|
gravity_sensor_command(BMP_IIC_WRITE_ADDRESS, reg, data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 从BMP280读取多个字节
|
||||||
|
*/
|
||||||
|
static uint8_t bmp280_read_regs(uint8_t reg, uint8_t *buf, uint16_t len) {
|
||||||
|
return _gravity_sensor_get_ndata(BMP_IIC_READ_ADDRESS, reg, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==================================================================================*/
|
||||||
|
/* 核心算法 */
|
||||||
|
/*==================================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 温度补偿计算
|
||||||
|
* @param adc_T - 原始温度数据
|
||||||
|
* @return 补偿后的温度值 (单位: °C)
|
||||||
|
*/
|
||||||
|
static float compensate_temperature(int32_t adc_T) {
|
||||||
|
float var1, var2, temperature;
|
||||||
|
|
||||||
|
var1 = (((float)adc_T) / 16384.0f - ((float)t1) / 1024.0f) * ((float)t2);
|
||||||
|
var2 = ((((float)adc_T) / 131072.0f - ((float)t1) / 8192.0f) *
|
||||||
|
(((float)adc_T) / 131072.0f - ((float)t1) / 8192.0f)) *
|
||||||
|
((float)t3);
|
||||||
|
t_fine = (int32_t)(var1 + var2);
|
||||||
|
temperature = (var1 + var2) / 5120.0f;
|
||||||
|
|
||||||
|
if (temperature < -40.0f) return -40.0f;
|
||||||
|
if (temperature > 85.0f) return 85.0f;
|
||||||
|
|
||||||
|
return temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 气压补偿计算
|
||||||
|
* @param adc_P - 原始气压数据
|
||||||
|
* @return 补偿后的气压值 (单位: Pa)
|
||||||
|
*/
|
||||||
|
static float compensate_pressure(int32_t adc_P) {
|
||||||
|
float var1, var2, pressure;
|
||||||
|
|
||||||
|
var1 = ((float)t_fine / 2.0f) - 64000.0f;
|
||||||
|
var2 = var1 * var1 * ((float)p6) / 32768.0f;
|
||||||
|
var2 = var2 + var1 * ((float)p5) * 2.0f;
|
||||||
|
var2 = (var2 / 4.0f) + (((float)p4) * 65536.0f);
|
||||||
|
var1 = (((float)p3) * var1 * var1 / 524288.0f + ((float)p2) * var1) / 524288.0f;
|
||||||
|
var1 = (1.0f + var1 / 32768.0f) * ((float)p1);
|
||||||
|
|
||||||
|
if (var1 == 0.0f) {
|
||||||
|
return 0; // 避免除以零
|
||||||
|
}
|
||||||
|
|
||||||
|
pressure = 1048576.0f - (float)adc_P;
|
||||||
|
pressure = (pressure - (var2 / 4096.0f)) * 6250.0f / var1;
|
||||||
|
var1 = ((float)p9) * pressure * pressure / 2147483648.0f;
|
||||||
|
var2 = pressure * ((float)p8) / 32768.0f;
|
||||||
|
pressure = pressure + (var1 + var2 + ((float)p7)) / 16.0f;
|
||||||
|
|
||||||
|
if (pressure < 30000.0f) return 30000.0f;
|
||||||
|
if (pressure > 110000.0f) return 110000.0f;
|
||||||
|
|
||||||
|
return pressure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==================================================================================*/
|
||||||
|
/* 外部接口函数实现 */
|
||||||
|
/*==================================================================================*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t bmp280_init(void) {
|
||||||
|
uint8_t id;
|
||||||
|
uint8_t calib_data[24];
|
||||||
|
|
||||||
|
// 1. 检查芯片ID
|
||||||
|
if (bmp280_read_regs(BMP280_REG_ID, &id, 1) == 0) {
|
||||||
|
printf("bmp280 get id error:%d\n",id );
|
||||||
|
return 1; // I2C读取失败
|
||||||
|
}
|
||||||
|
if (id != 0x58) {
|
||||||
|
printf("bmp280 check diff:%d\n",id );
|
||||||
|
return 1; // ID不匹配
|
||||||
|
}
|
||||||
|
printf("bmp280 get id:0%X\n",id );
|
||||||
|
|
||||||
|
// 2. 软复位
|
||||||
|
bmp280_write_reg(BMP280_REG_RESET, 0xB6);
|
||||||
|
os_time_dly(10); // 等待复位完成
|
||||||
|
|
||||||
|
// 3. 一次性读取所有校准参数
|
||||||
|
if (bmp280_read_regs(BMP280_REG_CALIB_START, calib_data, 24) == 0) {
|
||||||
|
return 2; // 读取校准数据失败
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 解析校准参数
|
||||||
|
t1 = (uint16_t)(((uint16_t)calib_data[1] << 8) | calib_data[0]);
|
||||||
|
t2 = (int16_t)(((int16_t)calib_data[3] << 8) | calib_data[2]);
|
||||||
|
t3 = (int16_t)(((int16_t)calib_data[5] << 8) | calib_data[4]);
|
||||||
|
p1 = (uint16_t)(((uint16_t)calib_data[7] << 8) | calib_data[6]);
|
||||||
|
p2 = (int16_t)(((int16_t)calib_data[9] << 8) | calib_data[8]);
|
||||||
|
p3 = (int16_t)(((int16_t)calib_data[11] << 8) | calib_data[10]);
|
||||||
|
p4 = (int16_t)(((int16_t)calib_data[13] << 8) | calib_data[12]);
|
||||||
|
p5 = (int16_t)(((int16_t)calib_data[15] << 8) | calib_data[14]);
|
||||||
|
p6 = (int16_t)(((int16_t)calib_data[17] << 8) | calib_data[16]);
|
||||||
|
p7 = (int16_t)(((int16_t)calib_data[19] << 8) | calib_data[18]);
|
||||||
|
p8 = (int16_t)(((int16_t)calib_data[21] << 8) | calib_data[20]);
|
||||||
|
p9 = (int16_t)(((int16_t)calib_data[23] << 8) | calib_data[22]);
|
||||||
|
|
||||||
|
// 5. 配置传感器 (推荐设置: 正常模式,高精度)
|
||||||
|
// t_standby=0.5ms, filter=16, spi_en=0
|
||||||
|
uint8_t config_reg = (0 << 5) | (4 << 2) | (0 << 0);
|
||||||
|
bmp280_write_reg(BMP280_REG_CONFIG, config_reg);
|
||||||
|
|
||||||
|
// osrs_t=x2, osrs_p=x16, mode=normal
|
||||||
|
uint8_t ctrl_meas_reg = (2 << 5) | (5 << 2) | (3 << 0);
|
||||||
|
bmp280_write_reg(BMP280_REG_CTRL_MEAS, ctrl_meas_reg);
|
||||||
|
|
||||||
|
os_time_dly(10); // 等待配置生效
|
||||||
|
|
||||||
|
printf("bmp280 init success\n");
|
||||||
|
return 0; // 初始化成功
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取转换后的温度和压力数据
|
||||||
|
*
|
||||||
|
* @param temperature 传出,温度
|
||||||
|
* @param pressure 传出,压力
|
||||||
|
* @return uint8_t
|
||||||
|
*/
|
||||||
|
uint8_t bmp280_read_data(float *temperature, float *pressure) {
|
||||||
|
uint8_t data[6];
|
||||||
|
int32_t adc_P, adc_T;
|
||||||
|
|
||||||
|
// printf("==========debug1===========\n");
|
||||||
|
// 一次性读取6个字节的温度和气压原始数据
|
||||||
|
if (bmp280_read_regs(BMP280_REG_PRESS_MSB, data, 6) == 0) {
|
||||||
|
printf("bmp280:read data error\n");
|
||||||
|
return 1; // 读取失败
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("==========debug2===========\n");
|
||||||
|
// 组合原始数据 (20位)
|
||||||
|
adc_P = (int32_t)((((uint32_t)(data[0])) << 12) | (((uint32_t)(data[1])) << 4) | (((uint32_t)(data[2])) >> 4));
|
||||||
|
adc_T = (int32_t)((((uint32_t)(data[3])) << 12) | (((uint32_t)(data[4])) << 4) | (((uint32_t)(data[5])) >> 4));
|
||||||
|
|
||||||
|
// 如果没有数据,直接返回错误 (ADC读数为0x80000是未测量状态)
|
||||||
|
if (adc_T == 0x80000 || adc_P == 0x80000) {
|
||||||
|
*temperature = 0.0f;
|
||||||
|
*pressure = 0.0f;
|
||||||
|
printf("bmp280:no data\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("==========debug3===========\n");
|
||||||
|
// 进行补偿计算
|
||||||
|
*temperature = compensate_temperature(adc_T);
|
||||||
|
*pressure = compensate_pressure(adc_P);
|
||||||
|
|
||||||
|
return 0; // 成功
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取该气压计的原始adc数据
|
||||||
|
*
|
||||||
|
* @param adc_P 传出,气压
|
||||||
|
* @param adc_T 传出,温度
|
||||||
|
*/
|
||||||
|
void bmp280_read_originanl_data(int* adc_P, int* adc_T){
|
||||||
|
uint8_t data[6];
|
||||||
|
// 一次性读取6个字节的温度和气压原始数据
|
||||||
|
if (bmp280_read_regs(BMP280_REG_PRESS_MSB, data, 6) != 0) {
|
||||||
|
return; // 读取失败
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组合原始数据 (20位)
|
||||||
|
adc_P = (int32_t)((((uint32_t)(data[0])) << 12) | (((uint32_t)(data[1])) << 4) | (((uint32_t)(data[2])) >> 4));
|
||||||
|
adc_T = (int32_t)((((uint32_t)(data[3])) << 12) | (((uint32_t)(data[4])) << 4) | (((uint32_t)(data[5])) >> 4));
|
||||||
|
|
||||||
|
}
|
||||||
54
apps/earphone/xtell_Sensor/sensor/BMP280.h
Normal file
54
apps/earphone/xtell_Sensor/sensor/BMP280.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#ifndef BMP280_DRIVER_H
|
||||||
|
#define BMP280_DRIVER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define BMP_PULL_UP 0 //外部是否接的上拉
|
||||||
|
|
||||||
|
// I2C 从设备地址
|
||||||
|
#if BMP_PULL_UP == 1 //外部接的高
|
||||||
|
#define BMP_IIC_7BIT_ADDRESS 0x76 //7位,外部接高为0x77
|
||||||
|
#define BMP_IIC_WRITE_ADDRESS (BMP_IIC_7BIT_ADDRESS<<1) //8位地址
|
||||||
|
#define BMP_IIC_READ_ADDRESS (BMP_IIC_WRITE_ADDRESS | 0x01)
|
||||||
|
#else
|
||||||
|
#define BMP_IIC_7BIT_ADDRESS 0x77 //7位,外部接低为0x76
|
||||||
|
#define BMP_IIC_WRITE_ADDRESS (BMP_IIC_7BIT_ADDRESS<<1) //8位地址
|
||||||
|
#define BMP_IIC_READ_ADDRESS (BMP_IIC_WRITE_ADDRESS | 0x01)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// BMP280 寄存器地址
|
||||||
|
#define BMP280_REG_CALIB_START 0x88
|
||||||
|
#define BMP280_REG_ID 0xD0
|
||||||
|
#define BMP280_REG_RESET 0xE0
|
||||||
|
#define BMP280_REG_STATUS 0xF3
|
||||||
|
#define BMP280_REG_CTRL_MEAS 0xF4
|
||||||
|
#define BMP280_REG_CONFIG 0xF5
|
||||||
|
#define BMP280_REG_PRESS_MSB 0xF7
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化BMP280传感器
|
||||||
|
* @return 0: 成功, 1: 芯片ID错误, 2: 读取校准参数失败
|
||||||
|
* @note 此函数会完成ID检查、软复位、读取校准参数,并设置传感器为连续测量模式。
|
||||||
|
*/
|
||||||
|
uint8_t bmp280_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 从BMP280读取温度和气压数据
|
||||||
|
* @param[out] temperature - 指向浮点数变量的指针,用于存储温度值 (单位: °C)
|
||||||
|
* @param[out] pressure - 指向浮点数变量的指针,用于存储气压值 (单位: Pa)
|
||||||
|
* @return 0: 成功, 1: 读取数据失败
|
||||||
|
*/
|
||||||
|
uint8_t bmp280_read_data(float *temperature, float *pressure);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取该气压计的原始adc数据
|
||||||
|
*
|
||||||
|
* @param adc_P 传出,气压
|
||||||
|
* @param adc_T 传出,温度
|
||||||
|
*/
|
||||||
|
void bmp280_read_originanl_data(int* adc_P, int* adc_T);
|
||||||
|
|
||||||
|
#endif // BMP280_DRIVER_H
|
||||||
@ -33,7 +33,7 @@
|
|||||||
#define LIS2DH12_R_ADDR 0x33
|
#define LIS2DH12_R_ADDR 0x33
|
||||||
|
|
||||||
// --- IIC 寄存器地址宏定义 ---
|
// --- IIC 寄存器地址宏定义 ---
|
||||||
#define LIS2DH12_WHO_AM_I 0x0F
|
#define LIS2DH12_WHO_AM_I 0x01 //0F
|
||||||
#define LIS2DH12_CTRL_REG1 0x20
|
#define LIS2DH12_CTRL_REG1 0x20
|
||||||
#define LIS2DH12_CTRL_REG4 0x23
|
#define LIS2DH12_CTRL_REG4 0x23
|
||||||
#define LIS2DH12_CTRL_REG5 0x24
|
#define LIS2DH12_CTRL_REG5 0x24
|
||||||
@ -93,7 +93,7 @@ static u8 SL_MEMS_i2cWrite(u8 addr, u8 reg, u8 data) {
|
|||||||
char LIS2DH12_Check() {
|
char LIS2DH12_Check() {
|
||||||
u8 reg_value = 0;
|
u8 reg_value = 0;
|
||||||
SL_MEMS_i2cRead(LIS2DH12_R_ADDR, LIS2DH12_WHO_AM_I, 1, ®_value);
|
SL_MEMS_i2cRead(LIS2DH12_R_ADDR, LIS2DH12_WHO_AM_I, 1, ®_value);
|
||||||
if (reg_value == 0x33) {
|
if (reg_value == 0x6A) { //0x33
|
||||||
return 0x01;
|
return 0x01;
|
||||||
}
|
}
|
||||||
return 0x00;
|
return 0x00;
|
||||||
@ -150,7 +150,7 @@ void LIS2DH12_calibrate() {
|
|||||||
// 初始化并配置LIS2DH12传感器
|
// 初始化并配置LIS2DH12传感器
|
||||||
u8 LIS2DH12_Config(void) {
|
u8 LIS2DH12_Config(void) {
|
||||||
if (LIS2DH12_Check() != 1) {
|
if (LIS2DH12_Check() != 1) {
|
||||||
xlog("LIS2DH12 I2C检查失败\n");
|
xlog("LIS2DH12 I2C error\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +163,7 @@ u8 LIS2DH12_Config(void) {
|
|||||||
// 执行开机校准
|
// 执行开机校准
|
||||||
LIS2DH12_calibrate();
|
LIS2DH12_calibrate();
|
||||||
|
|
||||||
xlog("LIS2DH12 I2C检查成功\n");
|
xlog("LIS2DH12 I2C success\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
266
apps/earphone/xtell_Sensor/sensor/MMC56.c
Normal file
266
apps/earphone/xtell_Sensor/sensor/MMC56.c
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
/*
|
||||||
|
MMC5603nj
|
||||||
|
1-255的采样率,这里设置为200Hz,5ms
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "MMC56.h"
|
||||||
|
#include "math.h"
|
||||||
|
#include "os/os_api.h"
|
||||||
|
#include "../xtell.h"
|
||||||
|
#include "gSensor/gSensor_manage.h"
|
||||||
|
#include "printf.h"
|
||||||
|
|
||||||
|
#define CALIBRATION_TIME 20000 //校准持续时间 ms
|
||||||
|
#define SAMPLE_INTERVAL 100 //校准采样间隔
|
||||||
|
|
||||||
|
// 用于跟踪当前是否处于连续测量模式
|
||||||
|
static uint8_t g_continuous_mode_enabled = 0;
|
||||||
|
mmc5603nj_cal_data_t cal_data; //校准数据
|
||||||
|
|
||||||
|
static void mmc5603nj_write_reg(uint8_t reg, uint8_t data) {
|
||||||
|
gravity_sensor_command(MMC_IIC_WRITE_ADDRESS, reg, data);
|
||||||
|
}
|
||||||
|
static uint32_t mmc5603nj_read_regs(uint8_t reg, uint8_t *buf, uint8_t len) {
|
||||||
|
return _gravity_sensor_get_ndata(MMC_IIC_READ_ADDRESS, reg, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 外部接口函数实现
|
||||||
|
|
||||||
|
uint8_t mmc5603nj_get_pid(void) {
|
||||||
|
uint8_t pid = 0;
|
||||||
|
mmc5603nj_read_regs(MMC_PID, &pid, 1);
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mmc5603nj_init(void) {
|
||||||
|
// ID
|
||||||
|
if ( mmc5603nj_get_pid() != 0x10) {
|
||||||
|
printf("MMC5603NJ init failed: wrong Product ID (read: 0x%X)\n", mmc5603nj_get_pid());
|
||||||
|
// return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 软件复位
|
||||||
|
mmc5603nj_write_reg(MMC_INCTRL1, 0x80); // SW_RESET bit
|
||||||
|
os_time_dly(20); // 等待复位完成
|
||||||
|
|
||||||
|
// 设置20位分辨率 (BW[1:0] = 11)
|
||||||
|
// 同时确保所有轴都使能 (X/Y/Z_inhibit = 0)
|
||||||
|
// mmc5603nj_write_reg(MMC_INCTRL1, 0x03);
|
||||||
|
mmc5603nj_write_reg(MMC_INCTRL1, 0x03);
|
||||||
|
os_time_dly(1);
|
||||||
|
|
||||||
|
// 设置内部控制寄存器2
|
||||||
|
// CMM_EN = 1 (使能连续模式功能)
|
||||||
|
// HPOWER = 0
|
||||||
|
// mmc5603nj_write_reg(MMC_INCTRL2, 0x10); // 0b00010000
|
||||||
|
mmc5603nj_write_reg(MMC_INCTRL2, 0x10); // 0b10010000
|
||||||
|
|
||||||
|
// 设置自动SET/RESET功能
|
||||||
|
// AUTO_SR_EN = 1
|
||||||
|
mmc5603nj_write_reg(MMC_INCTRL0, 0x20); // 0b00100000
|
||||||
|
|
||||||
|
g_continuous_mode_enabled = 0;
|
||||||
|
printf("MMC5603NJ initialized successfully.\n");
|
||||||
|
|
||||||
|
// mmc5603nj_enable_continuous_mode(0xC8); //200Hz的采样率,最高支持255
|
||||||
|
mmc5603nj_enable_continuous_mode(0xCF);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmc5603nj_start_calibration(void){
|
||||||
|
printf("\n--- Magnetometer Calibration Start ---\n");
|
||||||
|
printf("Slowly rotate the device in all directions (like drawing a 3D '8')...\n");
|
||||||
|
printf("Calibration will last for 20 seconds.\n\n");
|
||||||
|
printf("will start after 5 seconds\n\n");
|
||||||
|
os_time_dly(500);
|
||||||
|
|
||||||
|
// 初始化最大最小值
|
||||||
|
// 使用一个临时变量来读取数据,避免干扰read函数的正常逻辑
|
||||||
|
mmc5603nj_mag_data_t temp_mag_data;
|
||||||
|
// 首次读取以获取初始值
|
||||||
|
mmc5603nj_read_mag_data(&temp_mag_data); // 首次读取不应用校准
|
||||||
|
|
||||||
|
float max_x = temp_mag_data.x;
|
||||||
|
float min_x = temp_mag_data.x;
|
||||||
|
float max_y = temp_mag_data.y;
|
||||||
|
float min_y = temp_mag_data.y;
|
||||||
|
float max_z = temp_mag_data.z;
|
||||||
|
float min_z = temp_mag_data.z;
|
||||||
|
|
||||||
|
uint32_t start_time = os_time_get(); // 假设os_time_get()返回毫秒级时间戳
|
||||||
|
int samples = 0;
|
||||||
|
int over = CALIBRATION_TIME/SAMPLE_INTERVAL;
|
||||||
|
|
||||||
|
while (samples <= over) {
|
||||||
|
// 读取原始磁力计数据
|
||||||
|
mmc5603nj_read_mag_data(&temp_mag_data);
|
||||||
|
|
||||||
|
// 更新最大最小值
|
||||||
|
if (temp_mag_data.x > max_x) max_x = temp_mag_data.x;
|
||||||
|
if (temp_mag_data.x < min_x) min_x = temp_mag_data.x;
|
||||||
|
|
||||||
|
if (temp_mag_data.y > max_y) max_y = temp_mag_data.y;
|
||||||
|
if (temp_mag_data.y < min_y) min_y = temp_mag_data.y;
|
||||||
|
|
||||||
|
if (temp_mag_data.z > max_z) max_z = temp_mag_data.z;
|
||||||
|
if (temp_mag_data.z < min_z) min_z = temp_mag_data.z;
|
||||||
|
|
||||||
|
samples++;
|
||||||
|
os_time_dly(SAMPLE_INTERVAL / 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查数据范围是否合理,防止传感器未动或故障
|
||||||
|
if ((max_x - min_x < 0.1f) || (max_y - min_y < 0.1f) || (max_z - min_z < 0.1f)) {
|
||||||
|
printf("\n--- Calibration Failed ---\n");
|
||||||
|
printf("Device might not have been rotated enough.\n");
|
||||||
|
printf("X range: %.2f, Y range: %.2f, Z range: %.2f\n", max_x - min_x, max_y - min_y, max_z - min_z);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算硬磁偏移 (椭球中心)
|
||||||
|
cal_data.offset_x = (max_x + min_x) / 2.0f;
|
||||||
|
cal_data.offset_y = (max_y + min_y) / 2.0f;
|
||||||
|
cal_data.offset_z = (max_z + min_z) / 2.0f;
|
||||||
|
|
||||||
|
printf("\n--- Calibration Complete ---\n");
|
||||||
|
printf("Collected %d samples.\n", samples);
|
||||||
|
printf("Offsets (Gauss):\n");
|
||||||
|
printf(" X: %.4f\n", cal_data.offset_x);
|
||||||
|
printf(" Y: %.4f\n", cal_data.offset_y);
|
||||||
|
printf(" Z: %.4f\n", cal_data.offset_z);
|
||||||
|
printf("Please save these values and apply them in your code.\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void mmc5603nj_enable_continuous_mode(uint8_t rate) {
|
||||||
|
// 在连续模式下,ODR寄存器必须被设置
|
||||||
|
mmc5603nj_write_reg(MMC_ODR, rate); //要设置频率
|
||||||
|
// mmc5603nj_set_data_rate(0x04);
|
||||||
|
|
||||||
|
// 启用连续模式 (INCTRL2的CMM_EN位已在init中设置)
|
||||||
|
// 只需要设置 INCTRL0 的 CMM_FREQ_EN 位
|
||||||
|
mmc5603nj_write_reg(MMC_INCTRL0, 0xA0); // 0b10100000 (CMM_FREQ_EN=1, AUTO_SR_EN=1)
|
||||||
|
g_continuous_mode_enabled = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmc5603nj_disable_continuous_mode(void) {
|
||||||
|
// 禁用连续模式
|
||||||
|
mmc5603nj_write_reg(MMC_INCTRL0, 0x20); // 恢复到仅使能 AUTO_SR_EN 的状态
|
||||||
|
g_continuous_mode_enabled = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float mmc5603nj_get_temperature(void) {
|
||||||
|
uint8_t status = 0;
|
||||||
|
uint8_t temp_raw = 0;
|
||||||
|
uint8_t timeout = 20;
|
||||||
|
|
||||||
|
// 触发一次温度测量
|
||||||
|
mmc5603nj_write_reg(MMC_INCTRL0, 0x02); // TAKE_MEAS_T
|
||||||
|
|
||||||
|
// 等待测量完成
|
||||||
|
do {
|
||||||
|
os_time_dly(10);
|
||||||
|
mmc5603nj_read_regs(MMC_STATUS1, &status, 1);
|
||||||
|
timeout--;
|
||||||
|
} while ((status & 0x80) == 0 && timeout > 0);
|
||||||
|
|
||||||
|
if (timeout == 0) {
|
||||||
|
printf("Error: Temperature measurement timeout!\n");
|
||||||
|
return -273.15f; // 返回一个绝对零度的错误值
|
||||||
|
}
|
||||||
|
|
||||||
|
mmc5603nj_read_regs(MMC_TOUT, &temp_raw, 1);
|
||||||
|
return ((float)temp_raw * 0.8f) - 75.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmc5603nj_read_mag_data(mmc5603nj_mag_data_t *mag_data) {
|
||||||
|
uint8_t buffer[9];
|
||||||
|
|
||||||
|
if (g_continuous_mode_enabled) {
|
||||||
|
// 连续模式下,只需检查数据是否就绪
|
||||||
|
uint8_t status = 0;
|
||||||
|
mmc5603nj_read_regs(MMC_STATUS1, &status, 1);
|
||||||
|
if ((status & 0x40) == 0) { // Meas_M_done bit
|
||||||
|
// 数据未就绪,可以选择返回或等待,这里我们直接返回旧数据
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 单次测量模式
|
||||||
|
uint8_t status = 0;
|
||||||
|
uint8_t timeout = 20;
|
||||||
|
|
||||||
|
// 触发一次带自动SET/RESET的磁场测量
|
||||||
|
mmc5603nj_write_reg(MMC_INCTRL0, 0x21); // 0b00100001 (TAKE_MEAS_M=1, AUTO_SR_EN=1)
|
||||||
|
|
||||||
|
// 等待测量完成
|
||||||
|
do {
|
||||||
|
os_time_dly(10);
|
||||||
|
mmc5603nj_read_regs(MMC_STATUS1, &status, 1);
|
||||||
|
timeout--;
|
||||||
|
} while ((status & 0x40) == 0 && timeout > 0);
|
||||||
|
|
||||||
|
if (timeout == 0) {
|
||||||
|
// printf("Error: Magnetic measurement timeout!\n");
|
||||||
|
mag_data->x = mag_data->y = mag_data->z = 0.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取9个字节的原始数据
|
||||||
|
mmc5603nj_read_regs(MMC_XOUT0, buffer, 9);
|
||||||
|
|
||||||
|
// 解析数据 (20位分辨率)
|
||||||
|
int32_t raw_x = ((uint32_t)buffer[0] << 12) | ((uint32_t)buffer[1] << 4) | ((uint32_t)buffer[6] & 0x0F);
|
||||||
|
int32_t raw_y = ((uint32_t)buffer[2] << 12) | ((uint32_t)buffer[3] << 4) | ((uint32_t)buffer[6] >> 4);
|
||||||
|
int32_t raw_z = ((uint32_t)buffer[4] << 12) | ((uint32_t)buffer[5] << 4) | ((uint32_t)buffer[8] & 0x0F);
|
||||||
|
|
||||||
|
// 应用偏置和灵敏度进行转换
|
||||||
|
mag_data->x = ((float)raw_x - 524288.0f) / 16384.0f;
|
||||||
|
mag_data->y = ((float)raw_y - 524288.0f) / 16384.0f;
|
||||||
|
mag_data->z = ((float)raw_z - 524288.0f) / 16384.0f;
|
||||||
|
|
||||||
|
//减去偏移
|
||||||
|
mag_data->x -= cal_data.offset_x;
|
||||||
|
mag_data->y -= cal_data.offset_y;
|
||||||
|
mag_data->z -= cal_data.offset_z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mmc5603nj_read_origin_data(uint8_t *buffer) {
|
||||||
|
|
||||||
|
if (g_continuous_mode_enabled) {
|
||||||
|
// 连续模式下,只需检查数据是否就绪
|
||||||
|
uint8_t status = 0;
|
||||||
|
mmc5603nj_read_regs(MMC_STATUS1, &status, 1);
|
||||||
|
if ((status & 0x40) == 0) { // Meas_M_done bit
|
||||||
|
// 数据未就绪,可以选择返回或等待,这里我们直接返回旧数据
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 单次测量模式
|
||||||
|
uint8_t status = 0;
|
||||||
|
uint8_t timeout = 20;
|
||||||
|
|
||||||
|
// 触发一次带自动SET/RESET的磁场测量
|
||||||
|
mmc5603nj_write_reg(MMC_INCTRL0, 0x21); // 0b00100001 (TAKE_MEAS_M=1, AUTO_SR_EN=1)
|
||||||
|
|
||||||
|
// 等待测量完成
|
||||||
|
do {
|
||||||
|
os_time_dly(10);
|
||||||
|
mmc5603nj_read_regs(MMC_STATUS1, &status, 1);
|
||||||
|
timeout--;
|
||||||
|
} while ((status & 0x40) == 0 && timeout > 0);
|
||||||
|
|
||||||
|
if (timeout == 0) {
|
||||||
|
printf("Error: Magnetic measurement timeout!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取9个字节的原始数据
|
||||||
|
mmc5603nj_read_regs(MMC_XOUT0, buffer, 9);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
103
apps/earphone/xtell_Sensor/sensor/MMC56.h
Normal file
103
apps/earphone/xtell_Sensor/sensor/MMC56.h
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#ifndef MMC5603NJ_DRIVER_H
|
||||||
|
#define MMC5603NJ_DRIVER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
//该芯片的iic地址是固定的, 没法通过外部上下拉来改变
|
||||||
|
#define BMP_IIC_7BIT_ADDRESS 0x30 //0110000 手册第12页
|
||||||
|
//8位地址:
|
||||||
|
#define MMC_IIC_WRITE_ADDRESS (BMP_IIC_7BIT_ADDRESS <<1) // 0x60 : 01100000
|
||||||
|
#define MMC_IIC_READ_ADDRESS (MMC_IIC_WRITE_ADDRESS | 0x01) // 0x61 : 01100001
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 寄存器地址定义 -- 数据手册第6页
|
||||||
|
#define MMC_XOUT0 0x00
|
||||||
|
#define MMC_XOUT1 0x01
|
||||||
|
#define MMC_YOUT0 0x02
|
||||||
|
#define MMC_YOUT1 0x03
|
||||||
|
#define MMC_ZOUT0 0x04
|
||||||
|
#define MMC_ZOUT1 0x05
|
||||||
|
#define MMC_XOUT2 0x06
|
||||||
|
#define MMC_YOUT2 0x07
|
||||||
|
#define MMC_ZOUT2 0x08
|
||||||
|
#define MMC_TOUT 0x09
|
||||||
|
#define MMC_STATUS1 0x18
|
||||||
|
#define MMC_ODR 0x1A
|
||||||
|
#define MMC_INCTRL0 0x1B
|
||||||
|
#define MMC_INCTRL1 0x1C
|
||||||
|
#define MMC_INCTRL2 0x1D
|
||||||
|
#define MMC_ST_X_TH 0x1E
|
||||||
|
#define MMC_ST_Y_TH 0x1F
|
||||||
|
#define MMC_ST_Z_TH 0x20
|
||||||
|
#define MMC_ST_X 0x27
|
||||||
|
#define MMC_ST_Y 0x28
|
||||||
|
#define MMC_ST_Z 0x29
|
||||||
|
#define MMC_PID 0x39
|
||||||
|
|
||||||
|
// 定义一个结构体来存放三轴磁场数据(原始数据)
|
||||||
|
typedef struct {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
} mmc5603nj_original_data_t;
|
||||||
|
|
||||||
|
|
||||||
|
// 定义一个结构体来存放三轴磁场数据(单位:高斯 Gauss)
|
||||||
|
typedef struct {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
} mmc5603nj_mag_data_t;
|
||||||
|
|
||||||
|
// 定义一个结构体来存放磁力计的硬磁偏移校准数据
|
||||||
|
typedef struct {
|
||||||
|
float offset_x;
|
||||||
|
float offset_y;
|
||||||
|
float offset_z;
|
||||||
|
} mmc5603nj_cal_data_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化MMC5603NJ传感器
|
||||||
|
* 该函数会对传感器进行软件复位,并检查设备ID。
|
||||||
|
* @return 0 表示成功, -1 表示失败 (设备ID不匹配).
|
||||||
|
*/
|
||||||
|
int mmc5603nj_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置传感器的数据输出速率 (ODR - Output Data Rate)
|
||||||
|
* @param rate 速率值,具体含义请参考datasheet ODR寄存器说明。
|
||||||
|
*/
|
||||||
|
void mmc5603nj_set_data_rate(uint8_t rate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 启用连续测量模式
|
||||||
|
*/
|
||||||
|
void mmc5603nj_enable_continuous_mode(uint8_t rate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 禁用连续测量模式
|
||||||
|
*/
|
||||||
|
void mmc5603nj_disable_continuous_mode(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取产品ID
|
||||||
|
* @return 产品的ID值,对于MMC5603NJ,应为0x10.
|
||||||
|
*/
|
||||||
|
uint8_t mmc5603nj_get_pid(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取传感器的温度
|
||||||
|
* @return 温度值 (单位: 摄氏度 °C).
|
||||||
|
*/
|
||||||
|
float mmc5603nj_get_temperature(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取三轴磁场数据
|
||||||
|
* 此函数会根据当前是连续模式还是单次模式来读取数据。
|
||||||
|
* @param mag_data 指向 mmc5603nj_mag_data_t 结构体的指针,用于存放结果。
|
||||||
|
*/
|
||||||
|
void mmc5603nj_read_mag_data(mmc5603nj_mag_data_t *mag_data);
|
||||||
|
|
||||||
|
#endif // MMC5603NJ_DRIVER_H
|
||||||
2000
apps/earphone/xtell_Sensor/sensor/SC7U22.c
Normal file
2000
apps/earphone/xtell_Sensor/sensor/SC7U22.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -9,22 +9,23 @@ Copyright (c) 2022 Silan MEMS. All Rights Reserved.
|
|||||||
|
|
||||||
#include "gSensor/gSensor_manage.h"
|
#include "gSensor/gSensor_manage.h"
|
||||||
#include "printf.h"
|
#include "printf.h"
|
||||||
|
#include "MMC56.h"
|
||||||
|
|
||||||
//是否使能串口打印调试
|
//是否使能串口打印调试
|
||||||
#define SL_Sensor_Algo_Release_Enable 0x01
|
#define SL_Sensor_Algo_Release_Enable 0x00
|
||||||
//是否开启FIFO模式,默认STREAM模式
|
//是否开启FIFO模式,默认STREAM模式
|
||||||
#define SL_SC7U22_FIFO_ENABLE 0x00
|
#define SL_SC7U22_FIFO_ENABLE 0x01
|
||||||
|
|
||||||
|
|
||||||
/***使用前请根据实际情况配置以下参数******/
|
/***使用前请根据实际情况配置以下参数******/
|
||||||
/**SC7U22的SDO 接地: 0****************/
|
/**SC7U22的SDO 接地: 0****************/
|
||||||
/**SC7U22的SDO 接电源:1****************/
|
/**SC7U22的SDO 接电源:1****************/
|
||||||
#define SL_SC7U22_SDO_VDD_GND 1
|
#define SL_SC7U22_SDO_VDD_GND 0
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
/***使用前请根据实际IIC地址配置参数***/
|
/***使用前请根据实际IIC地址配置参数***/
|
||||||
/**SC7U22的IIC 接口地址为 7bits: 0****/
|
/**SC7U22的IIC 接口地址为 7bits: 0****/
|
||||||
/**SC7U22的IIC 接口地址为 8bits: 1****/
|
/**SC7U22的IIC 接口地址为 8bits: 1****/
|
||||||
#define SL_SC7U22_IIC_7BITS_8BITS 0
|
#define SL_SC7U22_IIC_7BITS_8BITS 1
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
#if SL_SC7U22_SDO_VDD_GND==0
|
#if SL_SC7U22_SDO_VDD_GND==0
|
||||||
#define SL_SC7U22_IIC_7BITS_ADDR 0x18
|
#define SL_SC7U22_IIC_7BITS_ADDR 0x18
|
||||||
@ -130,7 +131,11 @@ unsigned char SL_SC7U22_Angle_Output(unsigned char calibration_en,signed short *
|
|||||||
/**output Angle_output[2]: Yaw*******************************/
|
/**output Angle_output[2]: Yaw*******************************/
|
||||||
/**input yaw_rst: reset yaw value***************************/
|
/**input yaw_rst: reset yaw value***************************/
|
||||||
|
|
||||||
|
void set_SC7U22_Error_Flag(char flag);
|
||||||
|
unsigned char Original_SL_SC7U22_Angle_Output(unsigned char calibration_en, signed short *acc_gyro_input, float *Angle_output, unsigned char yaw_rst);
|
||||||
|
unsigned char SIX_SL_SC7U22_Angle_Output(unsigned char auto_calib_start, signed short *acc_gyro_input, float *Angle_output, unsigned char yaw_rst);
|
||||||
|
unsigned char Q_SL_SC7U22_Angle_Output(unsigned char calibration_en, signed short *acc_gyro_input, float *Angle_output, const mmc5603nj_mag_data_t *mag_data_input, unsigned char yaw_rst, float *quaternion_output);
|
||||||
|
unsigned char get_calibration_state(void);
|
||||||
/**寄存器宏定义*******************************/
|
/**寄存器宏定义*******************************/
|
||||||
#define SC7U22_WHO_AM_I 0x01
|
#define SC7U22_WHO_AM_I 0x01
|
||||||
|
|
||||||
@ -1,5 +1,4 @@
|
|||||||
|
#include "SC7U22.h"
|
||||||
#include "SCU722.h"
|
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
#include "os/os_api.h"
|
#include "os/os_api.h"
|
||||||
|
|
||||||
@ -119,10 +118,9 @@ unsigned char SL_SC7U22_Config(void)
|
|||||||
SL_SC7U22_I2c_Spi_Write(SL_SPI_IIC_INTERFACE, 0x7D, 0x0E);//PWR_CTRL ENABLE ACC+GYR+TEMP
|
SL_SC7U22_I2c_Spi_Write(SL_SPI_IIC_INTERFACE, 0x7D, 0x0E);//PWR_CTRL ENABLE ACC+GYR+TEMP
|
||||||
os_time_dly(1);//10ms
|
os_time_dly(1);//10ms
|
||||||
|
|
||||||
SL_SC7U22_I2c_Spi_Write(SL_SPI_IIC_INTERFACE, 0x40, 0x06);//ACC_CONF 0x07=50Hz
|
SL_SC7U22_I2c_Spi_Write(SL_SPI_IIC_INTERFACE, 0x40, 0x08);//ACC_CONF 0x08=100Hz
|
||||||
SL_SC7U22_I2c_Spi_Write(SL_SPI_IIC_INTERFACE, 0x41, 0x01);//ACC_RANGE ±8G
|
SL_SC7U22_I2c_Spi_Write(SL_SPI_IIC_INTERFACE, 0x41, 0x01);//ACC_RANGE ±4G
|
||||||
SL_SC7U22_I2c_Spi_Write(SL_SPI_IIC_INTERFACE, 0x42, 0x86);//GYR_CONF 0x87=50Hz
|
SL_SC7U22_I2c_Spi_Write(SL_SPI_IIC_INTERFACE, 0x42, 0x88);//GYR_CONF 0x88=100Hz
|
||||||
SL_SC7U22_I2c_Spi_Write(SL_SPI_IIC_INTERFACE, 0x43, 0x00);//GYR_RANGE 2000dps
|
|
||||||
SL_SC7U22_I2c_Spi_Write(SL_SPI_IIC_INTERFACE, 0x43, 0x00);//GYR_RANGE 2000dps
|
SL_SC7U22_I2c_Spi_Write(SL_SPI_IIC_INTERFACE, 0x43, 0x00);//GYR_RANGE 2000dps
|
||||||
SL_SC7U22_I2c_Spi_Write(SL_SPI_IIC_INTERFACE, 0x04, 0x50);//COM_CFG
|
SL_SC7U22_I2c_Spi_Write(SL_SPI_IIC_INTERFACE, 0x04, 0x50);//COM_CFG
|
||||||
|
|
||||||
@ -149,9 +147,6 @@ unsigned char SL_SC7U22_Config(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if SL_SC7U22_SDO_PullUP_ENABLE ==0x01
|
#if SL_SC7U22_SDO_PullUP_ENABLE ==0x01
|
||||||
SL_SC7U22_I2c_Spi_Write(SL_SPI_IIC_INTERFACE,0x7F, 0x8C);//goto 0x8C
|
SL_SC7U22_I2c_Spi_Write(SL_SPI_IIC_INTERFACE,0x7F, 0x8C);//goto 0x8C
|
||||||
sl_delay(1);
|
sl_delay(1);
|
||||||
@ -642,50 +637,128 @@ unsigned char SL_SC7U22_WakeUp_SET(unsigned char odr_mode,unsigned char acc_rang
|
|||||||
|
|
||||||
#if SL_SC7U22_FIFO_ENABLE ==0x00
|
#if SL_SC7U22_FIFO_ENABLE ==0x00
|
||||||
// =================================================================================================
|
// =================================================================================================
|
||||||
// 卡尔曼滤波器(Kalman Filter)相关变量定义
|
// Madgwick AHRS 滤波器相关变量和函数
|
||||||
// 卡尔曼滤波器是一种高效的递归滤波器,它能够从一系列不完全及包含噪声的测量中,估计动态系统的状态。
|
|
||||||
// 在这里,它被用来融合加速度计和陀螺仪的数据,以获得更精确、更稳定的姿态角(Pitch 和 Roll)。
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// --- 状态变量 ---
|
// 定义常量
|
||||||
float angle[3] = {0, 0, 0}, angle_dot[3] = {0, 0, 0}; // 姿态角(Pitch, Roll, Yaw)和角速度
|
#define sampleFreq 100.0f // 传感器采样频率 (Hz),必须与实际的传感器数据更新频率一致
|
||||||
float angle0[3] = {0, 0, 0}, angle_dot0[3] = {0, 0, 0}; // 姿态角的估计值
|
#define betaDef 0.1f // 算法的比例增益 beta,影响加速度计修正陀螺仪的权重
|
||||||
|
|
||||||
// --- 卡尔曼滤波器参数 ---
|
// 全局变量
|
||||||
// Q_angle: 过程噪声协方差,表示角度预测模型的不确定性。值越小,表示越相信陀螺仪的积分结果。
|
static volatile float beta = betaDef; // 算法增益 beta
|
||||||
// Q_gyro: 过程噪声协方差,表示陀螺仪偏置(bias)的不确定性。
|
static volatile float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f; // 表示姿态的四元数 (w, x, y, z)
|
||||||
// R_angle: 测量噪声协方差,表示通过加速度计计算出的角度测量值的不确定性。值越小,表示越相信加速度计的测量结果。
|
|
||||||
// dt: 采样时间间隔(单位:秒),这里是10ms (0.01s),对应100Hz的采样率。
|
|
||||||
//float Q_angle=0.0003, Q_gyro=0.001, R_angle=0.005, dt=0.005;//5ms ST
|
|
||||||
//float Q_angle=0.00001, Q_gyro=0.00001, R_angle=0.005, dt=0.0025;//5ms ST
|
|
||||||
float Q_angle = 0.0003, Q_gyro = 0.001, R_angle = 0.005, dt = 0.01; //10ms
|
|
||||||
|
|
||||||
// --- 协方差矩阵 P ---
|
/**
|
||||||
// P矩阵表示系统状态估计的不确定性程度。它是一个2x2的矩阵:
|
* @brief 快速计算 1/sqrt(x)
|
||||||
// P[0][0]: 角度估计的方差
|
* @param x 输入的浮点数
|
||||||
// P[0][1], P[1][0]: 角度和陀螺仪偏置的协方差
|
* @return 1/sqrt(x) 的近似值
|
||||||
// P[1][1]: 陀螺仪偏置估计的方差
|
*/
|
||||||
// P0, P1, P2 分别用于 Pitch, Roll, Yaw 的计算(尽管Yaw未使用卡尔曼滤波)。
|
static float invSqrt(float x) {
|
||||||
float P[2][2] = {{ 1, 0 }, { 0, 1 }};
|
float halfx = 0.5f * x;
|
||||||
float P0[2][2] = {{ 1, 0 }, { 0, 1 }}; // Pitch 轴的协方差矩阵
|
float y = x;
|
||||||
float P1[2][2] = {{ 1, 0 }, { 0, 1 }}; // Roll 轴的协方差矩阵
|
long i = *(long*)&y;
|
||||||
float P2[2][2] = {{ 1, 0 }, { 0, 1 }}; // Yaw 轴的协方差矩阵(未使用)
|
i = 0x5f3759df - (i>>1);
|
||||||
|
y = *(float*)&i;
|
||||||
|
y = y * (1.5f - (halfx * y * y)); // 牛顿迭代法,提高精度
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
// --- 中间计算变量 ---
|
/**
|
||||||
float Pdot0[4] = {0, 0, 0, 0}; // P0矩阵的微分,用于预测步骤
|
* @brief Madgwick AHRS 姿态更新函数 (IMU版本)
|
||||||
float Pdot1[4] = {0, 0, 0, 0}; // P1矩阵的微分,用于预测步骤
|
* @details 该函数融合了陀螺仪和加速度计的数据,计算出表示设备姿态的四元数。
|
||||||
float Pdot2[4] = {0, 0, 0, 0}; // P2矩阵的微分,用于预测步骤
|
* 1. 使用陀螺仪数据积分,得到一个初步的姿态估计(预测)。
|
||||||
const float C_0 = 1.0; // 测量矩阵H的元素,因为直接测量角度,所以为1
|
* 2. 使用加速度计数据(当设备处于静止或低速运动时,加速度计主要测量重力)来修正这个估计(修正)。
|
||||||
const float C_1 = 1.0;
|
* 3. 通过梯度下降法找到一个最优的旋转,使得在当前姿态下,重力向量的方向与加速度计测量的方向最接近。
|
||||||
const float C_2 = 1.0;
|
* @param gx, gy, gz 陀螺仪三轴角速度 (单位: rad/s)
|
||||||
float q_bias0[3] = {0, 0, 0}; // 陀螺仪零点偏置(bias)的估计值
|
* @param ax, ay, az 加速度计三轴加速度 (单位: g)
|
||||||
float angle_err0[3] = {0, 0, 0}; // 测量值与预测值之间的误差
|
*/
|
||||||
float PCt0_0[3] = {0, 0, 0}, PCt0_1[3] = {0, 0, 0}; // 中间变量,用于计算卡尔曼增益
|
static void MadgwickAHRSupdateIMU(float gx, float gy, float gz, float ax, float ay, float az) {
|
||||||
float E0[3] = {0, 0, 0}; // 误差的协方差
|
float recipNorm;
|
||||||
float K0_0[3] = {0, 0, 0}, K0_1[3] = {0, 0, 0}; // 卡尔曼增益K
|
float s0, s1, s2, s3;
|
||||||
float t0_0[3] = {0, 0, 0}, t0_1[3] = {0, 0, 0}; // 中间变量,用于更新P矩阵
|
float qDot1, qDot2, qDot3, qDot4;
|
||||||
|
float _2q0, _2q1, _2q2, _2q3, _4q0, _4q1, _4q2 ,_8q1, _8q2, q0q0, q1q1, q2q2, q3q3;
|
||||||
|
float dt = 1.0f / sampleFreq; // 采样时间间隔
|
||||||
|
|
||||||
|
// --- 1. 陀螺仪积分:计算四元数的变化率 ---
|
||||||
|
// 姿态运动学的基本方程,描述了姿态如何随角速度变化。
|
||||||
|
qDot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz);
|
||||||
|
qDot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy);
|
||||||
|
qDot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx);
|
||||||
|
qDot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx);
|
||||||
|
|
||||||
|
// --- 2. 加速度计修正 ---
|
||||||
|
// 仅当加速度计读数有效时(即模长不为0)才进行修正,防止计算NaN。
|
||||||
|
if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) {
|
||||||
|
|
||||||
|
// 将加速度计读数归一化,得到单位向量
|
||||||
|
recipNorm = invSqrt(ax * ax + ay * ay + az * az);
|
||||||
|
ax *= recipNorm;
|
||||||
|
ay *= recipNorm;
|
||||||
|
az *= recipNorm;
|
||||||
|
|
||||||
|
// 预先计算一些重复使用的值,提高效率
|
||||||
|
_2q0 = 2.0f * q0;
|
||||||
|
_2q1 = 2.0f * q1;
|
||||||
|
_2q2 = 2.0f * q2;
|
||||||
|
_2q3 = 2.0f * q3;
|
||||||
|
_4q0 = 4.0f * q0;
|
||||||
|
_4q1 = 4.0f * q1;
|
||||||
|
_4q2 = 4.0f * q2;
|
||||||
|
_8q1 = 8.0f * q1;
|
||||||
|
_8q2 = 8.0f * q2;
|
||||||
|
q0q0 = q0 * q0;
|
||||||
|
q1q1 = q1 * q1;
|
||||||
|
q2q2 = q2 * q2;
|
||||||
|
q3q3 = q3 * q3;
|
||||||
|
|
||||||
|
// --- 梯度下降法:计算修正量 ---
|
||||||
|
// 目标函数 f(q, a) = [2(q1q3 - q0q2) - ax, 2(q0q1 + q2q3) - ay, 2(0.5 - q1^2 - q2^2) - az]^T
|
||||||
|
// s0, s1, s2, s3 是目标函数 f 对四元数 q 的雅可比矩阵 J 与 f 的乘积。
|
||||||
|
// 这个结果代表了误差函数的梯度方向,用于修正四元数的变化率。
|
||||||
|
s0 = _4q0 * q2q2 + _2q2 * ax + _4q0 * q1q1 - _2q1 * ay;
|
||||||
|
s1 = _4q1 * q3q3 - _2q3 * ax + 4.0f * q0q0 * q1 - _2q0 * ay - _4q1 + _8q1 * q1q1 + _8q1 * q2q2 + _4q1 * az;
|
||||||
|
s2 = 4.0f * q0q0 * q2 + _2q0 * ax + _4q2 * q3q3 - _2q3 * ay - _4q2 + _8q2 * q1q1 + _8q2 * q2q2 + _4q2 * az;
|
||||||
|
s3 = 4.0f * q1q1 * q3 - _2q1 * ax + 4.0f * q2q2 * q3 - _2q2 * ay;
|
||||||
|
recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // 归一化梯度
|
||||||
|
s0 *= recipNorm;
|
||||||
|
s1 *= recipNorm;
|
||||||
|
s2 *= recipNorm;
|
||||||
|
s3 *= recipNorm;
|
||||||
|
|
||||||
|
// --- 应用修正量 ---
|
||||||
|
// 将计算出的修正量(梯度)从陀螺仪积分结果中减去,beta是修正的权重。
|
||||||
|
qDot1 -= beta * s0;
|
||||||
|
qDot2 -= beta * s1;
|
||||||
|
qDot3 -= beta * s2;
|
||||||
|
qDot4 -= beta * s3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 3. 积分:更新四元数 ---
|
||||||
|
// 使用一阶龙格-库塔法(即欧拉法)进行积分,得到新的四元数。
|
||||||
|
q0 += qDot1 * dt;
|
||||||
|
q1 += qDot2 * dt;
|
||||||
|
q2 += qDot3 * dt;
|
||||||
|
q3 += qDot4 * dt;
|
||||||
|
|
||||||
|
// --- 4. 归一化四元数 ---
|
||||||
|
// 保持四元数的模长为1,防止由于计算误差导致的累积漂移。
|
||||||
|
recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
|
||||||
|
q0 *= recipNorm;
|
||||||
|
q1 *= recipNorm;
|
||||||
|
q2 *= recipNorm;
|
||||||
|
q3 *= recipNorm;
|
||||||
|
}
|
||||||
// =================================================================================================
|
// =================================================================================================
|
||||||
|
|
||||||
|
// --- 静态校准相关变量 ---
|
||||||
|
static unsigned char SL_SC7U22_Error_Flag=0;
|
||||||
|
static unsigned char SL_SC7U22_Error_cnt=0;
|
||||||
|
static unsigned char SL_SC7U22_Error_cnt2=0;
|
||||||
|
static signed short Temp_Accgyro[6] ={0};
|
||||||
|
static signed short Error_Accgyro[6]={0};
|
||||||
|
static signed int Sum_Avg_Accgyro[6] ={0};
|
||||||
|
static float yaw_offset = 0.0f;
|
||||||
|
|
||||||
static signed short SL_GetAbsShort(signed short v_Val_s16r)
|
static signed short SL_GetAbsShort(signed short v_Val_s16r)
|
||||||
{
|
{
|
||||||
if(v_Val_s16r==(-32768))
|
if(v_Val_s16r==(-32768))
|
||||||
@ -693,18 +766,12 @@ static signed short SL_GetAbsShort(signed short v_Val_s16r)
|
|||||||
return (v_Val_s16r < 0) ? -v_Val_s16r : v_Val_s16r;
|
return (v_Val_s16r < 0) ? -v_Val_s16r : v_Val_s16r;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char SL_SC7U22_Error_Flag=0;
|
|
||||||
unsigned char SL_SC7U22_Error_cnt=0;
|
|
||||||
unsigned char SL_SC7U22_Error_cnt2=0;
|
|
||||||
signed short Temp_Accgyro[6] ={0};
|
|
||||||
signed short Error_Accgyro[6]={0};
|
|
||||||
signed int Sum_Avg_Accgyro[6] ={0};
|
|
||||||
/**
|
/**
|
||||||
* @brief 姿态角解算函数
|
* @brief 姿态角解算函数
|
||||||
* @details
|
* @details
|
||||||
* 该函数主要完成两项工作:
|
* 该函数主要完成两项工作:
|
||||||
* 1. 静态校准:在初始阶段,检测传感器是否处于静止状态。如果是,则计算加速度计和陀螺仪的零点偏移(误差),用于后续的数据补偿。
|
* 1. 静态校准:在初始阶段,检测传感器是否处于静止状态。如果是,则计算加速度计和陀螺仪的零点偏移(误差),用于后续的数据补偿。
|
||||||
* 2. 姿态解算:使用卡尔曼滤波器融合经过校准后的加速度计和陀螺仪数据,计算出物体的俯仰角(Pitch)、横滚角(Roll)和偏航角(Yaw)。
|
* 2. 姿态解算:使用 Madgwick 滤波器融合经过校准后的加速度计和陀螺仪数据,计算出物体的俯仰角(Pitch)、横滚角(Roll)和偏航角(Yaw)。
|
||||||
*
|
*
|
||||||
* @param calibration_en 传入:外部校准使能标志。如果为0,则强制认为已经校准完成。
|
* @param calibration_en 传入:外部校准使能标志。如果为0,则强制认为已经校准完成。
|
||||||
* @param acc_gyro_input 传入和传出:包含6轴原始数据的数组指针,顺序为 [ACC_X, ACC_Y, ACC_Z, GYR_X, GYR_Y, GYR_Z]。该函数会对其进行原地修改,填充为校准后的数据。
|
* @param acc_gyro_input 传入和传出:包含6轴原始数据的数组指针,顺序为 [ACC_X, ACC_Y, ACC_Z, GYR_X, GYR_Y, GYR_Z]。该函数会对其进行原地修改,填充为校准后的数据。
|
||||||
@ -720,8 +787,6 @@ unsigned char SL_SC7U22_Angle_Output(unsigned char calibration_en, signed short
|
|||||||
{
|
{
|
||||||
unsigned short acc_gyro_delta[2];
|
unsigned short acc_gyro_delta[2];
|
||||||
unsigned char sl_i = 0;
|
unsigned char sl_i = 0;
|
||||||
float angle_acc[3] = {0};
|
|
||||||
float gyro_val[3] = {0};
|
|
||||||
|
|
||||||
// 如果外部强制使能校准,则将标志位置1
|
// 如果外部强制使能校准,则将标志位置1
|
||||||
if (calibration_en == 0) {
|
if (calibration_en == 0) {
|
||||||
@ -729,11 +794,8 @@ unsigned char SL_SC7U22_Angle_Output(unsigned char calibration_en, signed short
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =================================================================================
|
// =================================================================================
|
||||||
// 步骤 1: 静态校准
|
// 步骤 1: 静态校准 (与原版逻辑相同)
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
// SL_SC7U22_Error_Flag 为0时,表示需要进行校准。
|
|
||||||
// 校准的原理是:当传感器长时间处于静止状态时,认为其三轴加速度输出应为(0, 0, g),三轴角速度输出应为(0, 0, 0)。
|
|
||||||
// 通过采集一段时间的静止数据并求平均,可以得到传感器的零点偏移量。
|
|
||||||
if (SL_SC7U22_Error_Flag == 0) {
|
if (SL_SC7U22_Error_Flag == 0) {
|
||||||
// 计算当前数据与上一帧数据的差值,用于判断是否静止
|
// 计算当前数据与上一帧数据的差值,用于判断是否静止
|
||||||
acc_gyro_delta[0] = 0;
|
acc_gyro_delta[0] = 0;
|
||||||
@ -748,6 +810,7 @@ unsigned char SL_SC7U22_Angle_Output(unsigned char calibration_en, signed short
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 判断是否处于静止状态:加速度变化量、陀螺仪变化量、各轴加速度值都在一个很小的范围内
|
// 判断是否处于静止状态:加速度变化量、陀螺仪变化量、各轴加速度值都在一个很小的范围内
|
||||||
|
// 假设1g = 8192 (对应 +/-4g 量程)
|
||||||
if ((acc_gyro_delta[0] / 8 < 80) && (acc_gyro_delta[1] < 20) && (SL_GetAbsShort(acc_gyro_input[0]) < 3000) && (SL_GetAbsShort(acc_gyro_input[1]) < 3000) && (SL_GetAbsShort(acc_gyro_input[2] - 8192) < 3000)) { //acc<80mg gyro<20 lsb
|
if ((acc_gyro_delta[0] / 8 < 80) && (acc_gyro_delta[1] < 20) && (SL_GetAbsShort(acc_gyro_input[0]) < 3000) && (SL_GetAbsShort(acc_gyro_input[1]) < 3000) && (SL_GetAbsShort(acc_gyro_input[2] - 8192) < 3000)) { //acc<80mg gyro<20 lsb
|
||||||
if (SL_SC7U22_Error_cnt < 200) {
|
if (SL_SC7U22_Error_cnt < 200) {
|
||||||
SL_SC7U22_Error_cnt++; // 静止计数器累加
|
SL_SC7U22_Error_cnt++; // 静止计数器累加
|
||||||
@ -773,7 +836,7 @@ unsigned char SL_SC7U22_Angle_Output(unsigned char calibration_en, signed short
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 计算零点偏移:理想值 - 实际平均值
|
// 计算零点偏移:理想值 - 实际平均值
|
||||||
// 加速度Z轴的理想值是8192,对应1g(假设量程为±8g)
|
// 加速度Z轴的理想值是8192,对应1g(假设量程为±4g)
|
||||||
Error_Accgyro[0] = 0 - Sum_Avg_Accgyro[0];
|
Error_Accgyro[0] = 0 - Sum_Avg_Accgyro[0];
|
||||||
Error_Accgyro[1] = 0 - Sum_Avg_Accgyro[1];
|
Error_Accgyro[1] = 0 - Sum_Avg_Accgyro[1];
|
||||||
Error_Accgyro[2] = 8192 - Sum_Avg_Accgyro[2];
|
Error_Accgyro[2] = 8192 - Sum_Avg_Accgyro[2];
|
||||||
@ -797,7 +860,7 @@ unsigned char SL_SC7U22_Angle_Output(unsigned char calibration_en, signed short
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =================================================================================
|
// =================================================================================
|
||||||
// 步骤 2: 姿态解算
|
// 步骤 2: 姿态解算 (Madgwick)
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
if (SL_SC7U22_Error_Flag == 1) { // 确认已经校准完成
|
if (SL_SC7U22_Error_Flag == 1) { // 确认已经校准完成
|
||||||
// --- 2.1 数据预处理 ---
|
// --- 2.1 数据预处理 ---
|
||||||
@ -811,209 +874,54 @@ unsigned char SL_SC7U22_Angle_Output(unsigned char calibration_en, signed short
|
|||||||
acc_gyro_input[sl_i] = Temp_Accgyro[sl_i];
|
acc_gyro_input[sl_i] = Temp_Accgyro[sl_i];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// --- 2.2 使用加速度计计算姿态角 ---
|
// --- 2.2 转换数据单位 ---
|
||||||
// 将加速度原始值转换为归一化的重力分量
|
// 将校准后的传感器原始值 (LSB) 转换为 Madgwick 算法所需的物理单位。
|
||||||
angle_acc[0] = (float)Temp_Accgyro[0] / 8192; //ax
|
// 加速度: LSB -> g (重力加速度)。转换系数 = 量程 / (2^15)。假设 +/-4g 量程, 系数 = 4 / 32768 = 1/8192。
|
||||||
angle_acc[1] = (float)Temp_Accgyro[1] / 8192; //ay
|
float ax = (float)Temp_Accgyro[0] / 8192.0f;
|
||||||
angle_acc[2] = (float)Temp_Accgyro[2] / 8192; //az
|
float ay = (float)Temp_Accgyro[1] / 8192.0f;
|
||||||
|
float az = (float)Temp_Accgyro[2] / 8192.0f;
|
||||||
|
// 角速度: LSB -> rad/s (弧度/秒)。转换系数 = (量程 * PI) / (180 * 2^15)。
|
||||||
|
// 假设 +/-2000dps 量程, 系数 = (2000 * 3.14159) / (180 * 32768) ≈ 0.001064
|
||||||
|
float gx = (float)Temp_Accgyro[3] * 0.001064f;
|
||||||
|
float gy = (float)Temp_Accgyro[4] * 0.001064f;
|
||||||
|
float gz = (float)Temp_Accgyro[5] * 0.001064f;
|
||||||
|
|
||||||
// 限制范围,防止asinf/atanf计算错误
|
// --- 2.3 调用 Madgwick 更新函数 ---
|
||||||
if (angle_acc[0] > 1.0) angle_acc[0] = 1.0;
|
// 将处理好的物理单位数据传入滤波器,更新姿态四元数。
|
||||||
if (angle_acc[0] < -1.0) angle_acc[0] = -1.0;
|
MadgwickAHRSupdateIMU(gx, gy, gz, ax, ay, az);
|
||||||
if (angle_acc[1] > 1.0) angle_acc[1] = 1.0;
|
|
||||||
if (angle_acc[1] < -1.0) angle_acc[1] = -1.0;
|
|
||||||
if (angle_acc[2] > 1.0) angle_acc[2] = 1.0;
|
|
||||||
if (angle_acc[2] < -1.0) angle_acc[2] = -1.0;
|
|
||||||
|
|
||||||
// 根据重力分量计算Pitch和Roll角(单位:度)
|
// --- 2.4 将四元数转换为欧拉角 ---
|
||||||
// Pitch = arcsin(ax / g)
|
// 欧拉角(Pitch, Roll, Yaw)更直观,便于使用。转换公式如下。
|
||||||
angle_acc[0] = asinf(angle_acc[0]) * 57.32484; //Pitch:-90~+90
|
// 转换结果单位为度 (乘以 180/PI ≈ 57.29578)。
|
||||||
// Roll = -arctan(ay / az)
|
float yaw, pitch, roll;
|
||||||
angle_acc[1] = -atanf(angle_acc[1] / angle_acc[2]) * 57.32484; //Roll: -180~+180
|
|
||||||
// 对Roll角进行象限补偿
|
// Roll (横滚角,绕x轴旋转)
|
||||||
if (angle_acc[2] < 0) {
|
roll = atan2f(2.0f * (q0 * q1 + q2 * q3), 1.0f - 2.0f * (q1 * q1 + q2 * q2)) * 57.29578f;
|
||||||
if (angle_acc[1] >= 0) {
|
// Pitch (俯仰角,绕y轴旋转)
|
||||||
angle_acc[1] = -180 + angle_acc[1];
|
float sinp = 2.0f * (q0 * q2 - q3 * q1);
|
||||||
} else {
|
if (fabsf(sinp) >= 1)
|
||||||
angle_acc[1] = 180 + angle_acc[1];
|
pitch = copysignf(3.14159265f / 2, sinp) * 57.29578f; // 防止万向节死锁,当sinp接近+/-1时,直接赋+/-90度
|
||||||
}
|
else
|
||||||
|
pitch = asinf(sinp) * 57.29578f;
|
||||||
|
// Yaw (偏航角,绕z轴旋转)
|
||||||
|
yaw = atan2f(2.0f * (q0 * q3 + q1 * q2), 1.0f - 2.0f * (q2 * q2 + q3 * q3)) * 57.29578f;
|
||||||
|
|
||||||
|
// --- 2.5 处理Yaw轴重置 ---
|
||||||
|
// Yaw角无法通过加速度计校正,会随时间漂移。提供一个重置机制,将当前Yaw角作为新的零点。
|
||||||
|
if (yaw_rst) {
|
||||||
|
yaw_offset = yaw;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 2.3 转换陀螺仪数据单位 ---
|
// --- 2.6 输出最终角度 ---
|
||||||
// 将陀螺仪原始值(LSB)转换为角速度(度/秒)
|
// 将计算出的欧拉角存入输出数组。
|
||||||
// 转换系数0.061 ≈ 2000dps / 32768 LSB
|
Angle_output[0] = pitch;
|
||||||
gyro_val[0] = Temp_Accgyro[4] * 0.061; // GYR-Y -> Pitch
|
Angle_output[1] = roll;
|
||||||
gyro_val[1] = Temp_Accgyro[3] * 0.061; // GYR-X -> Roll
|
Angle_output[2] = yaw - yaw_offset; // 输出减去偏移量的相对Yaw角
|
||||||
gyro_val[2] = Temp_Accgyro[5] * 0.061; // GYR-Z -> Yaw
|
|
||||||
|
|
||||||
// =================================================================================
|
|
||||||
// 步骤 2.4: 卡尔曼滤波
|
|
||||||
// 对Pitch和Roll分别进行滤波
|
|
||||||
// ---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/************** Pitch 轴滤波 **************/
|
|
||||||
// --- 预测步骤 ---
|
|
||||||
// 1. 预测状态:根据上一时刻的角度和当前角速度,预测当前角度
|
|
||||||
angle0[0] += (gyro_val[0] - q_bias0[0]) * dt;
|
|
||||||
// 2. 预测协方差:更新P矩阵,表示预测状态的不确定性
|
|
||||||
Pdot0[0] = Q_angle - P0[0][1] - P0[1][0] + P0[1][1] * dt;
|
|
||||||
Pdot0[1] = -P0[1][1];
|
|
||||||
Pdot0[2] = -P0[1][1];
|
|
||||||
Pdot0[3] = Q_gyro;
|
|
||||||
P0[0][0] += Pdot0[0] * dt;
|
|
||||||
P0[0][1] += Pdot0[1] * dt;
|
|
||||||
P0[1][0] += Pdot0[2] * dt;
|
|
||||||
P0[1][1] += Pdot0[3] * dt;
|
|
||||||
|
|
||||||
// --- 更新步骤 ---
|
|
||||||
// 1. 计算卡尔曼增益 K
|
|
||||||
PCt0_0[0] = C_0 * P0[0][0];
|
|
||||||
PCt0_1[0] = C_0 * P0[1][0];
|
|
||||||
E0[0] = R_angle + C_0 * PCt0_0[0];
|
|
||||||
if (E0[0] == 0) { E0[0] = 0.0001; } // 防止除零
|
|
||||||
K0_0[0] = PCt0_0[0] / E0[0];
|
|
||||||
K0_1[0] = PCt0_1[0] / E0[0];
|
|
||||||
|
|
||||||
// 2. 计算测量余差(innovation)
|
|
||||||
angle_err0[0] = angle_acc[0] - angle0[0];
|
|
||||||
// 3. 更新状态估计:结合预测值和测量值,得到最优估计
|
|
||||||
angle0[0] += K0_0[0] * angle_err0[0];
|
|
||||||
// 4. 更新陀螺仪偏置估计
|
|
||||||
q_bias0[0] += K0_1[0] * angle_err0[0];
|
|
||||||
angle_dot0[0] = gyro_val[0] - q_bias0[0];
|
|
||||||
|
|
||||||
// 5. 更新协方差矩阵 P
|
|
||||||
t0_0[0] = PCt0_0[0];
|
|
||||||
t0_1[0] = C_0 * P0[0][1];
|
|
||||||
P0[0][0] -= K0_0[0] * t0_0[0];
|
|
||||||
P0[0][1] -= K0_0[0] * t0_1[0];
|
|
||||||
P0[1][0] -= K0_1[0] * t0_0[0];
|
|
||||||
P0[1][1] -= K0_1[0] * t0_1[0];
|
|
||||||
|
|
||||||
// 输出最终的Pitch角
|
|
||||||
Angle_output[0] = angle0[0];
|
|
||||||
|
|
||||||
/************** Roll 轴滤波 (过程同Pitch) **************/
|
|
||||||
// --- 预测步骤 ---
|
|
||||||
angle0[1] += (gyro_val[1] - q_bias0[1]) * dt;
|
|
||||||
Pdot1[0] = Q_angle - P1[0][1] - P1[1][0] + P1[1][1] * dt;
|
|
||||||
Pdot1[1] = -P1[1][1];
|
|
||||||
Pdot1[2] = -P1[1][1];
|
|
||||||
Pdot1[3] = Q_gyro;
|
|
||||||
P1[0][0] += Pdot1[0] * dt;
|
|
||||||
P1[0][1] += Pdot1[1] * dt;
|
|
||||||
P1[1][0] += Pdot1[2] * dt;
|
|
||||||
P1[1][1] += Pdot1[3] * dt;
|
|
||||||
|
|
||||||
// --- 更新步骤 ---
|
|
||||||
PCt0_0[1] = C_1 * P1[0][0];
|
|
||||||
PCt0_1[1] = C_1 * P1[1][0];
|
|
||||||
E0[1] = R_angle + C_1 * PCt0_0[1];
|
|
||||||
if (E0[1] == 0) { E0[1] = 0.0001; }
|
|
||||||
K0_0[1] = PCt0_0[1] / E0[1];
|
|
||||||
K0_1[1] = PCt0_1[1] / E0[1];
|
|
||||||
angle_err0[1] = angle_acc[1] - angle0[1];
|
|
||||||
angle0[1] += K0_0[1] * angle_err0[1];
|
|
||||||
q_bias0[1] += K0_1[1] * angle_err0[1];
|
|
||||||
angle_dot0[1] = gyro_val[1] - q_bias0[1];
|
|
||||||
t0_0[1] = PCt0_0[1];
|
|
||||||
t0_1[1] = C_1 * P1[0][1];
|
|
||||||
P1[0][0] -= K0_0[1] * t0_0[1];
|
|
||||||
P1[0][1] -= K0_0[1] * t0_1[1];
|
|
||||||
P1[1][0] -= K0_1[1] * t0_0[1];
|
|
||||||
P1[1][1] -= K0_1[1] * t0_1[1];
|
|
||||||
|
|
||||||
// 输出最终的Roll角
|
|
||||||
Angle_output[1] = angle0[1];
|
|
||||||
|
|
||||||
/************** Yaw 轴计算 **************/
|
|
||||||
// Yaw角无法通过加速度计(重力)来校正,因此这里只使用陀螺仪进行简单积分。
|
|
||||||
// 这种方法会因为陀螺仪的漂移而导致误差随时间累积。
|
|
||||||
if (yaw_rst == 1) {
|
|
||||||
Angle_output[2] = 0; // 如果有复位信号,则清零
|
|
||||||
}
|
|
||||||
|
|
||||||
// 增加一个简单的阈值,当角速度较小时,认为没有转动,以减少漂移
|
|
||||||
if (SL_GetAbsShort(Temp_Accgyro[5]) > 8) {
|
|
||||||
Angle_output[2] += gyro_val[2] * dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1; // 返回1,表示计算成功
|
return 1; // 返回1,表示计算成功
|
||||||
}
|
}
|
||||||
|
|
||||||
return 2; // 校准未完成,返回错误状态
|
return 2; // 校准未完成,返回错误状态
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
//-----------------------------------------
|
|
||||||
调用示例-by_lmx:
|
|
||||||
|
|
||||||
|
|
||||||
//1.
|
|
||||||
// 定义用于存放传感器数据的缓冲区
|
|
||||||
static signed short acc_raw_data[3]; // [0]: acc_x, [1]: acc_y, [2]: acc_z
|
|
||||||
static signed short gyr_raw_data[3]; // [0]: gyr_x, [1]: gyr_y, [2]: gyr_z
|
|
||||||
static signed short combined_raw_data[6]; // 用于合并 acc 和 gyr 数据
|
|
||||||
static float final_angle_data[3]; // [0]: Pitch, [1]: Roll, [2]: Yaw
|
|
||||||
|
|
||||||
// 传感器数据处理任务
|
|
||||||
void sensor_processing_task(void *priv)
|
|
||||||
{
|
|
||||||
while (1) {
|
|
||||||
// 4. 周期性调用读取函数,获取原始数据
|
|
||||||
SL_SC7U22_RawData_Read(acc_raw_data, gyr_raw_data);
|
|
||||||
|
|
||||||
// 5. 合并加速度和角速度数据到一个数组中
|
|
||||||
// SL_SC7U22_Angle_Output 函数需要一个包含6个元素的数组作为输入
|
|
||||||
memcpy(&combined_raw_data[0], acc_raw_data, sizeof(acc_raw_data));
|
|
||||||
memcpy(&combined_raw_data[3], gyr_raw_data, sizeof(gyr_raw_data));
|
|
||||||
|
|
||||||
// 6. 调用姿态解算函数
|
|
||||||
// 参数: (校准使能, 输入的6轴数据, 输出的角度数据, Yaw轴复位标志)
|
|
||||||
// calibration_en = 1: 让函数内部自动管理校准过程
|
|
||||||
// yaw_rst = 0: 不复位Yaw角
|
|
||||||
unsigned char status = SL_SC7U22_Angle_Output(1, combined_raw_data, final_angle_data, 0);
|
|
||||||
|
|
||||||
// 7. 检查函数返回的状态
|
|
||||||
if (status == 1) {
|
|
||||||
// 计算成功,final_angle_data 中的数据有效
|
|
||||||
printf("Pitch: %.2f, Roll: %.2f, Yaw: %.2f\n", final_angle_data[0], final_angle_data[1], final_angle_data[2]);
|
|
||||||
} else if (status == 0) {
|
|
||||||
// 传感器正在进行静态校准,此时角度数据可能不准确
|
|
||||||
printf("Sensor is calibrating...\n");
|
|
||||||
} else {
|
|
||||||
// status == 2, 表示校准未完成或发生错误
|
|
||||||
printf("Angle calculation error or calibration not finished.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 延时一段时间,例如10ms (对应100Hz)
|
|
||||||
os_time_dly(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 应用程序主入口或初始化函数
|
|
||||||
void app_main()
|
|
||||||
{
|
|
||||||
// ... 其他初始化代码 ...
|
|
||||||
|
|
||||||
// 2. 调用初始化函数来配置SCU722传感器
|
|
||||||
unsigned char init_success = SL_SC7U22_Config();
|
|
||||||
|
|
||||||
if (init_success) {
|
|
||||||
printf("SCU722 初始化成功!\n");
|
|
||||||
// 3. 创建一个任务来周期性地读取和处理数据
|
|
||||||
task_create(sensor_processing_task, NULL, "sensor_task");
|
|
||||||
} else {
|
|
||||||
printf("SCU722 初始化失败!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------
|
|
||||||
*/
|
|
||||||
181
apps/earphone/xtell_Sensor/sensor/WF282A.c
Normal file
181
apps/earphone/xtell_Sensor/sensor/WF282A.c
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
气压计 - WF282A
|
||||||
|
*/
|
||||||
|
#include "wf282a.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdint.h> // 推荐使用标准类型
|
||||||
|
#include "gSensor/gSensor_manage.h"
|
||||||
|
|
||||||
|
/*==================================================================================*/
|
||||||
|
/* WF282A 内部定义 */
|
||||||
|
/*==================================================================================*/
|
||||||
|
|
||||||
|
// 存储校准系数的静态全局变量
|
||||||
|
static int16_t c0, c1, c01, c11, c20, c21, c30;
|
||||||
|
static int32_t c00, c10;
|
||||||
|
|
||||||
|
/*==================================================================================*/
|
||||||
|
/* 封装的底层I2C读写函数 */
|
||||||
|
/*==================================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 写入单个字节到WF282A寄存器
|
||||||
|
*/
|
||||||
|
static void wf282a_write_reg(uint8_t reg, uint8_t data) {
|
||||||
|
gravity_sensor_command(WF_IIC_WRITE_ADDRESS, reg, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 从WF282A读取多个字节
|
||||||
|
*/
|
||||||
|
static uint32_t wf282a_read_regs(uint8_t reg, uint8_t *buf, uint8_t len) {
|
||||||
|
return _gravity_sensor_get_ndata(WF_IIC_READ_ADDRESS, reg, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==================================================================================*/
|
||||||
|
/* 内部辅助函数 */
|
||||||
|
/*==================================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 从缓冲区中解析所有校准系数
|
||||||
|
* @param buf 包含从寄存器0x10开始读取的18个字节的校准数据
|
||||||
|
*/
|
||||||
|
static void parse_calibration_data(const uint8_t *buf) {
|
||||||
|
// c0 (12-bit)
|
||||||
|
c0 = ((int16_t)buf[0] << 4) | (buf[1] >> 4);
|
||||||
|
if (c0 & (1 << 11)) c0 |= 0xF000;
|
||||||
|
|
||||||
|
// c1 (12-bit)
|
||||||
|
c1 = (((int16_t)buf[1] & 0x0F) << 8) | buf[2];
|
||||||
|
if (c1 & (1 << 11)) c1 |= 0xF000;
|
||||||
|
|
||||||
|
// c00 (20-bit)
|
||||||
|
c00 = ((int32_t)buf[3] << 12) | ((int32_t)buf[4] << 4) | (buf[5] >> 4);
|
||||||
|
if (c00 & (1 << 19)) c00 |= 0xFFF00000;
|
||||||
|
|
||||||
|
// c10 (20-bit)
|
||||||
|
c10 = (((int32_t)buf[5] & 0x0F) << 16) | ((int32_t)buf[6] << 8) | buf[7];
|
||||||
|
if (c10 & (1 << 19)) c10 |= 0xFFF00000;
|
||||||
|
|
||||||
|
// c01, c11, c20, c21, c30 (16-bit)
|
||||||
|
c01 = (int16_t)((uint16_t)buf[8] << 8 | buf[9]);
|
||||||
|
c11 = (int16_t)((uint16_t)buf[10] << 8 | buf[11]);
|
||||||
|
c20 = (int16_t)((uint16_t)buf[12] << 8 | buf[13]);
|
||||||
|
c21 = (int16_t)((uint16_t)buf[14] << 8 | buf[15]);
|
||||||
|
c30 = (int16_t)((uint16_t)buf[16] << 8 | buf[17]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取原始温度值 (ADC)
|
||||||
|
*/
|
||||||
|
static int32_t Get_Traw() {
|
||||||
|
uint8_t buff[3];
|
||||||
|
int32_t Traw;
|
||||||
|
// 从 MSB 寄存器 WF_TMP_B2 (0x03) 开始连续读取3个字节
|
||||||
|
wf282a_read_regs(WF_TMP_B2, buff, 3);
|
||||||
|
// buff[0] = B2 (MSB), buff[1] = B1, buff[2] = B0 (LSB)
|
||||||
|
Traw = (int32_t)buff[0] << 16 | (int32_t)buff[1] << 8 | (int32_t)buff[2];
|
||||||
|
// 24位二进制补码转32位
|
||||||
|
if (Traw & (1 << 23)) {
|
||||||
|
Traw |= 0xFF000000;
|
||||||
|
}
|
||||||
|
return Traw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取原始气压值 (ADC)
|
||||||
|
*/
|
||||||
|
static int32_t Get_Praw() {
|
||||||
|
uint8_t buff[3];
|
||||||
|
int32_t Praw;
|
||||||
|
// 从 MSB 寄存器 WF_PRS_B2 (0x00) 开始连续读取3个字节
|
||||||
|
wf282a_read_regs(WF_PRS_B2, buff, 3);
|
||||||
|
// buff[0] = B2 (MSB), buff[1] = B1, buff[2] = B0 (LSB)
|
||||||
|
Praw = (int32_t)buff[0] << 16 | (int32_t)buff[1] << 8 | (int32_t)buff[2];
|
||||||
|
// 24位二进制补码转32位
|
||||||
|
if (Praw & (1 << 23)) {
|
||||||
|
Praw |= 0xFF000000;
|
||||||
|
}
|
||||||
|
return Praw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==================================================================================*/
|
||||||
|
/* 4. 外部接口函数实现 */
|
||||||
|
/*==================================================================================*/
|
||||||
|
|
||||||
|
uint8_t WF_Init() {
|
||||||
|
uint8_t calib_buf[18];
|
||||||
|
uint8_t check_cfg;
|
||||||
|
|
||||||
|
// 1. 配置传感器工作模式
|
||||||
|
// 推荐配置:压力8次过采样,温度1次过采样,测量速率16Hz
|
||||||
|
wf282a_write_reg(WF_PRS_CFG, (PM_RATE_16 << 4) | PM_PRC_8);
|
||||||
|
wf282a_write_reg(WF_TMP_CFG, (TMP_RATE_16 << 4) | TMP_PRC_1 | TMP_INT_SENSOR);
|
||||||
|
wf282a_write_reg(WF_MEAS_CFG, 0x07); // 启动连续压力和温度测量
|
||||||
|
wf282a_write_reg(WF_CFG_REG, 0x00); // 无中断或FIFO移位配置
|
||||||
|
|
||||||
|
// 2. 一次性读取所有校准系数 (从0x10到0x21,共18字节)
|
||||||
|
if (wf282a_read_regs(COEF_C0, calib_buf, 18) != 0) {
|
||||||
|
return 2; // 读取校准数据失败
|
||||||
|
}
|
||||||
|
parse_calibration_data(calib_buf);
|
||||||
|
|
||||||
|
// 3. 检查配置是否写入成功
|
||||||
|
wf282a_read_regs(WF_MEAS_CFG, &check_cfg, 1);
|
||||||
|
if (check_cfg != 0x07) {
|
||||||
|
return 1; // 错误
|
||||||
|
} else {
|
||||||
|
return 0; // 成功
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WF_Sleep() {
|
||||||
|
wf282a_write_reg(WF_MEAS_CFG, 0x00); // 待机模式
|
||||||
|
}
|
||||||
|
|
||||||
|
void WF_Wakeup() {
|
||||||
|
wf282a_write_reg(WF_MEAS_CFG, 0x07); // 恢复连续测量
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t WF_GetID() {
|
||||||
|
uint8_t id;
|
||||||
|
wf282a_read_regs(WF_ID_REG, &id, 1);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
float WF_Temperature_Calculate() {
|
||||||
|
float Traw_sc;
|
||||||
|
int32_t Traw = Get_Traw();
|
||||||
|
|
||||||
|
Traw_sc = (float)Traw / KT; // 缩放原始温度值
|
||||||
|
return (float)c0 * 0.5f + (float)c1 * Traw_sc;
|
||||||
|
}
|
||||||
|
|
||||||
|
float WF_Pressure_Calculate() {
|
||||||
|
float Traw_sc, Praw_sc, Pcomp;
|
||||||
|
int32_t Traw = Get_Traw();
|
||||||
|
int32_t Praw = Get_Praw();
|
||||||
|
|
||||||
|
Traw_sc = (float)Traw / KT; // 缩放原始温度值
|
||||||
|
Praw_sc = (float)Praw / KP; // 缩放原始压力值
|
||||||
|
|
||||||
|
// 公式: 手册给出
|
||||||
|
Pcomp = (float)c00
|
||||||
|
+ Praw_sc * ((float)c10 + Praw_sc * ((float)c20 + Praw_sc * (float)c30))
|
||||||
|
+ Traw_sc * (float)c01
|
||||||
|
+ Traw_sc * Praw_sc * ((float)c11 + Praw_sc * (float)c21);
|
||||||
|
|
||||||
|
return Pcomp;
|
||||||
|
}
|
||||||
|
|
||||||
|
float WF_Altitude_Calculate() {
|
||||||
|
float pressure_pa = WF_Pressure_Calculate();
|
||||||
|
// 使用标准大气压公式计算海拔
|
||||||
|
// P = P0 * (1 - L*h / T0)^(g*M / (R*L))
|
||||||
|
// 简化公式: h = 44330 * (1 - (P/P0)^(1/5.255))
|
||||||
|
// 1/5.255 ≈ 0.1903
|
||||||
|
if (pressure_pa <= 0) {
|
||||||
|
return 0.0f; // 避免无效计算
|
||||||
|
}
|
||||||
|
return 44330.0f * (1.0f - powf(pressure_pa / 101325.0f, 0.1902949f));
|
||||||
|
}
|
||||||
148
apps/earphone/xtell_Sensor/sensor/WF282A.h
Normal file
148
apps/earphone/xtell_Sensor/sensor/WF282A.h
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
#ifndef _WF282A_H_
|
||||||
|
#define _WF282A_H_
|
||||||
|
|
||||||
|
#include <stdint.h> // 使用标准整数类型
|
||||||
|
|
||||||
|
// 标定值
|
||||||
|
#define KT 524288.0f
|
||||||
|
#define KP 1572864.0f
|
||||||
|
|
||||||
|
|
||||||
|
#define WF_PULL_UP 1 //外部是否接的上拉
|
||||||
|
|
||||||
|
// I2C 从设备地址
|
||||||
|
#if WF_PULL_UP == 1 //外部接的高
|
||||||
|
#define WF_IIC_7BIT_ADDRESS 0x77 //7位,外部接高为0x77
|
||||||
|
#define WF_IIC_WRITE_ADDRESS (WF_IIC_7BIT_ADDRESS<<1) //8位地址
|
||||||
|
#define WF_IIC_READ_ADDRESS (WF_IIC_WRITE_ADDRESS | 0x01)
|
||||||
|
#else
|
||||||
|
#define WF_IIC_7BIT_ADDRESS 0x76 //7位,外部接低为0x76
|
||||||
|
#define WF_IIC_WRITE_ADDRESS (WF_IIC_7BIT_ADDRESS<<1) //8位地址
|
||||||
|
#define WF_IIC_READ_ADDRESS (WF_IIC_WRITE_ADDRESS | 0x01)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define WF_CHIP_ID 0X10
|
||||||
|
|
||||||
|
// 寄存器映射
|
||||||
|
// 压力数据
|
||||||
|
#define WF_PRS_B2 0x00
|
||||||
|
#define WF_PRS_B1 0x01
|
||||||
|
#define WF_PRS_B0 0x02
|
||||||
|
// 温度数据
|
||||||
|
#define WF_TMP_B2 0x03
|
||||||
|
#define WF_TMP_B1 0x04
|
||||||
|
#define WF_TMP_B0 0x05
|
||||||
|
// 配置寄存器
|
||||||
|
#define WF_PRS_CFG 0x06
|
||||||
|
#define WF_TMP_CFG 0x07
|
||||||
|
#define WF_MEAS_CFG 0x08
|
||||||
|
#define WF_CFG_REG 0x09
|
||||||
|
#define WF_INT_STS 0x0A
|
||||||
|
#define WF_FIFO_STS 0x0B
|
||||||
|
#define WF_RESET_REG 0x0C
|
||||||
|
// ID寄存器
|
||||||
|
#define WF_ID_REG 0x0D
|
||||||
|
// 校准系数寄存器
|
||||||
|
#define COEF_C0 0x10
|
||||||
|
#define COEF_C0_C1 0x11
|
||||||
|
#define COEF_C1 0x12
|
||||||
|
#define COEF_C00_H 0x13
|
||||||
|
#define COEF_C00_L 0x14
|
||||||
|
#define COEF_C00_C10 0x15
|
||||||
|
#define COEF_C10_M 0x16
|
||||||
|
#define COEF_C10_L 0x17
|
||||||
|
#define COEF_C01_H 0x18
|
||||||
|
#define COEF_C01_L 0x19
|
||||||
|
#define COEF_C11_H 0x1A
|
||||||
|
#define COEF_C11_L 0x1B
|
||||||
|
#define COEF_C20_H 0x1C
|
||||||
|
#define COEF_C20_L 0x1D
|
||||||
|
#define COEF_C21_H 0x1E
|
||||||
|
#define COEF_C21_L 0x1F
|
||||||
|
#define COEF_C30_H 0x20
|
||||||
|
#define COEF_C30_L 0x21
|
||||||
|
|
||||||
|
// --- 配置宏 ---
|
||||||
|
|
||||||
|
// 压力配置 (PRS_CFG[6:4]) - 测量速率
|
||||||
|
#define PM_RATE_1 0x00 // 1 次/秒
|
||||||
|
#define PM_RATE_2 0x01 // 2 次/秒
|
||||||
|
#define PM_RATE_4 0x02 // 4 次/秒
|
||||||
|
#define PM_RATE_8 0x03 // 8 次/秒
|
||||||
|
#define PM_RATE_16 0x04 // 16 次/秒
|
||||||
|
#define PM_RATE_32 0x05 // 32 次/秒
|
||||||
|
#define PM_RATE_64 0x06 // 64 次/秒
|
||||||
|
#define PM_RATE_128 0x07 // 128 次/秒
|
||||||
|
// 压力配置 (PRS_CFG[3:0]) - 过采样率
|
||||||
|
#define PM_PRC_1 0x00 // 1 次 (单次)
|
||||||
|
#define PM_PRC_2 0x01 // 2 次 (低功耗)
|
||||||
|
#define PM_PRC_4 0x02 // 4 次
|
||||||
|
#define PM_PRC_8 0x03 // 8 次 (标准)
|
||||||
|
#define PM_PRC_16 0x04 // 16 次 (需要移位)
|
||||||
|
#define PM_PRC_32 0x05 // 32 次 (需要移位)
|
||||||
|
#define PM_PRC_64 0x06 // 64 次 (高精度, 需要移位)
|
||||||
|
#define PM_PRC_128 0x07 // 128 次 (需要移位)
|
||||||
|
|
||||||
|
// 温度配置 (TMP_CFG[7]) - 传感器源
|
||||||
|
#define TMP_EXT_SENSOR 0x80 // 使用外部传感器
|
||||||
|
#define TMP_INT_SENSOR 0x00 // 使用内部传感器
|
||||||
|
// 温度配置 (TMP_CFG[6:4]) - 测量速率
|
||||||
|
#define TMP_RATE_1 0x00 // 1 次/秒
|
||||||
|
#define TMP_RATE_2 0x01 // 2 次/秒
|
||||||
|
#define TMP_RATE_4 0x02 // 4 次/秒
|
||||||
|
#define TMP_RATE_8 0x03 // 8 次/秒
|
||||||
|
#define TMP_RATE_16 0x04 // 16 次/秒
|
||||||
|
#define TMP_RATE_32 0x05 // 32 次/秒
|
||||||
|
#define TMP_RATE_64 0x06 // 64 次/秒
|
||||||
|
#define TMP_RATE_128 0x07 // 128 次/秒
|
||||||
|
// 温度配置 (TMP_CFG[3:0]) - 过采样率
|
||||||
|
#define TMP_PRC_1 0x00 // 1 次
|
||||||
|
#define TMP_PRC_2 0x01 // 2 次
|
||||||
|
#define TMP_PRC_4 0x02 // 4 次
|
||||||
|
#define TMP_PRC_8 0x03 // 8 次
|
||||||
|
#define TMP_PRC_16 0x04 // 16 次
|
||||||
|
#define TMP_PRC_32 0x05 // 32 次
|
||||||
|
#define TMP_PRC_64 0x06 // 64 次
|
||||||
|
#define TMP_PRC_128 0x07 // 128 次
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化WF282A传感器
|
||||||
|
* @return 0: 成功, 1: 失败
|
||||||
|
*/
|
||||||
|
uint8_t WF_Init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 使传感器进入休眠/待机模式
|
||||||
|
*/
|
||||||
|
void WF_Sleep(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 唤醒传感器,开始连续测量
|
||||||
|
*/
|
||||||
|
void WF_Wakeup(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取传感器芯片ID
|
||||||
|
* @return 芯片ID (应为 0x10)
|
||||||
|
*/
|
||||||
|
uint8_t WF_GetID(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计算并返回当前海拔高度
|
||||||
|
* @return 海拔高度 (单位: 米)
|
||||||
|
*/
|
||||||
|
float WF_Altitude_Calculate(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计算并返回补偿后的压力值
|
||||||
|
* @return 压力 (单位: Pa)
|
||||||
|
*/
|
||||||
|
float WF_Pressure_Calculate(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计算并返回补偿后的温度值
|
||||||
|
* @return 温度 (单位: °C)
|
||||||
|
*/
|
||||||
|
float WF_Temperature_Calculate(void);
|
||||||
|
|
||||||
|
#endif // _WF282A_H_
|
||||||
10
apps/earphone/xtell_Sensor/xtell.h
Normal file
10
apps/earphone/xtell_Sensor/xtell.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef XTELL_H
|
||||||
|
#define XTELL_H
|
||||||
|
#include "system/includes.h"
|
||||||
|
#include "generic/typedef.h"
|
||||||
|
// #define KS_BLE 1
|
||||||
|
#define XTELL_TEST 1
|
||||||
|
|
||||||
|
#define ACC_RANGE 16 //g,加速度满量程:2、4、8、16
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -100,6 +100,10 @@ void close_BL(){
|
|||||||
close_process(&close_BL_number,__func__);
|
close_process(&close_BL_number,__func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void xtell_set_ble_name(char* name){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
extern u32 timer_get_ms(void);
|
extern u32 timer_get_ms(void);
|
||||||
void xtell_app_main()
|
void xtell_app_main()
|
||||||
@ -145,13 +149,13 @@ void xtell_app_main()
|
|||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
|
|
||||||
//开机必须延时关闭经典蓝牙,不然底层代码会再次把蓝牙 打开
|
//开机必须延时关闭经典蓝牙,不然底层代码会再次把蓝牙 打开
|
||||||
create_process(&close_BL_number, "close_BL",NULL, close_BL, 3000);
|
// create_process(&close_BL_number, "close_BL",NULL, close_BL, 3000);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
soft_iic_init(0);
|
|
||||||
extern u8 LIS2DH12_Config(void);
|
|
||||||
LIS2DH12_Config();
|
|
||||||
u8 mac_data[6];
|
u8 mac_data[6];
|
||||||
|
extern void rcsp_adv_fill_mac_addr(u8 *mac_addr_buf);
|
||||||
rcsp_adv_fill_mac_addr(mac_data); //读取MAC地址
|
rcsp_adv_fill_mac_addr(mac_data); //读取MAC地址
|
||||||
xlog("xtell BT mac data:%x:%x:%x:%x:%x:%x",mac_data[0],mac_data[1],mac_data[2],mac_data[3],mac_data[4],mac_data[5]);
|
xlog("xtell BT mac data:%x:%x:%x:%x:%x:%x",mac_data[0],mac_data[1],mac_data[2],mac_data[3],mac_data[4],mac_data[5]);
|
||||||
|
|
||||||
|
|||||||
@ -44,7 +44,12 @@
|
|||||||
#include "bt_background.h"
|
#include "bt_background.h"
|
||||||
#include "default_event_handler.h"
|
#include "default_event_handler.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "system/event.h"
|
||||||
|
#include "./ano/ano_protocol.h"
|
||||||
|
#include "./sensor/MMC56.h"
|
||||||
|
#include "./sensor/BMP280.h"
|
||||||
|
#include "./sensor/AK8963.h"
|
||||||
|
#include "./calculate/skiing_tracker.h"
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//宏定义
|
//宏定义
|
||||||
#define LOG_TAG_CONST EARPHONE
|
#define LOG_TAG_CONST EARPHONE
|
||||||
@ -78,15 +83,31 @@ extern u8 init_ok;
|
|||||||
extern u8 sniff_out;
|
extern u8 sniff_out;
|
||||||
unsigned char xtell_bl_state=0; //存放经典蓝牙的连接状态,0断开,1是连接
|
unsigned char xtell_bl_state=0; //存放经典蓝牙的连接状态,0断开,1是连接
|
||||||
u8 bt_newname =0;
|
u8 bt_newname =0;
|
||||||
unsigned char xt_ble_new_name[9] = "CM-11111";
|
unsigned char xt_ble_new_name[9] = "xtell_1";
|
||||||
static u16 play_poweron_ok_timer_id = 0;
|
static u16 play_poweron_ok_timer_id = 0;
|
||||||
|
|
||||||
|
// -- 初始化标志位 --
|
||||||
|
u8 SC7U22_init = 0x10; //六轴是否初始化
|
||||||
|
u8 MMC5603nj_init = 0x20; //地磁是否初始化
|
||||||
|
u8 BMP280_init = 0x30; //气压计初始化
|
||||||
|
u8 foot_init = 0x40; //数据来源初始化:左脚0x41 or 右脚0x42
|
||||||
|
// -- 线程id --
|
||||||
|
|
||||||
|
|
||||||
|
u16 gsensor_test_id = 0;
|
||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extern int bt_hci_event_handler(struct bt_event *bt);
|
extern int bt_hci_event_handler(struct bt_event *bt);
|
||||||
|
extern void SC7U22_static_calibration(void);
|
||||||
|
extern void create_process(u16* pid, const char* name, void *priv, void (*func)(void *priv), u32 msec);
|
||||||
|
extern void close_process(u16* pid,char* name);
|
||||||
|
extern void start_collect_fuc(void);
|
||||||
|
extern void BLE_send_fuc(void);
|
||||||
|
extern void start_calibration(void);
|
||||||
|
extern void start_clloct(void);
|
||||||
|
extern void stop_clloct(void);
|
||||||
|
extern void set_foot_state(u8 state);
|
||||||
|
extern void stop_calibration(void);
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
/*
|
/*
|
||||||
* 模式状态机, 通过start_app()控制状态切换
|
* 模式状态机, 通过start_app()控制状态切换
|
||||||
@ -170,6 +191,239 @@ static int state_machine(struct application *app, enum app_state state, struct i
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//handle
|
//handle
|
||||||
|
void le_user_app_event(u8* buffer){
|
||||||
|
if (buffer[0] == 0xBE && buffer[1] == 0xBB) {
|
||||||
|
if(buffer[2] == 0x01){ //后面的数据长度 1
|
||||||
|
switch (buffer[3]){
|
||||||
|
case 0x01:
|
||||||
|
// extern void gsensor_test(void);
|
||||||
|
// create_process(&gsensor_test_id,"gsensor_test",NULL,gsensor_test,1000);
|
||||||
|
xlog("ota_test");
|
||||||
|
cpu_reset();
|
||||||
|
break;
|
||||||
|
case 0xff: //测试
|
||||||
|
u8 device_buff[10];
|
||||||
|
u8 founds = 0;
|
||||||
|
extern void i2c_scanner_probe(u8* device_addr, u8* found_number);
|
||||||
|
i2c_scanner_probe(device_buff,&founds);
|
||||||
|
for(int i = 0;i < founds;i++){
|
||||||
|
send_data_to_ble_client(&device_buff,founds);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
extern void test_func(void);
|
||||||
|
test_func();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else if(buffer[2] == 0x02){ //后面数据长度为2
|
||||||
|
switch (buffer[3]){ //数据包类型
|
||||||
|
case 0x00: //数据包类型为:指定传感器初始化
|
||||||
|
u8 send2_0[5] = {0xBB,0xBE,0x02,0x00,0x00};
|
||||||
|
if(buffer[4] == 0x01){ //六轴
|
||||||
|
// stop_calibration();
|
||||||
|
if (SL_SC7U22_Config() == 0) {
|
||||||
|
SC7U22_init = 0x10;
|
||||||
|
}else{
|
||||||
|
SC7U22_init = 0x11;
|
||||||
|
}
|
||||||
|
send2_0[4] = SC7U22_init;
|
||||||
|
send_data_to_ble_client(&send2_0,5);
|
||||||
|
// start_calibration();
|
||||||
|
}else if(buffer[4] == 0x02){ //地磁
|
||||||
|
if(mmc5603nj_init() == 0){
|
||||||
|
MMC5603nj_init = 0x20;
|
||||||
|
send2_0[4] = MMC5603nj_init; //地磁初始化失败
|
||||||
|
send_data_to_ble_client(&send2_0,5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MMC5603nj_init = 0x21;
|
||||||
|
send2_0[4] = MMC5603nj_init; //地磁初始化成功
|
||||||
|
send_data_to_ble_client(&send2_0,5);
|
||||||
|
}else if(buffer[4] == 0x03){ //气压计初始化
|
||||||
|
if(bmp280_init() != 0){
|
||||||
|
//初始化失败
|
||||||
|
BMP280_init = 0x30;
|
||||||
|
send2_0[4] = BMP280_init;
|
||||||
|
send_data_to_ble_client(&send2_0,5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BMP280_init = 0x31;
|
||||||
|
send2_0[4] = BMP280_init; //气压计初始化成功
|
||||||
|
send_data_to_ble_client(&send2_0,5);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x01: //设置传感器采集对象:左脚or右脚
|
||||||
|
u8 send2_1[5] = {0xBB,0xBE,0x06,0x05,0x00};
|
||||||
|
if(buffer[4] == 0x01){ //设定数据来源是左脚
|
||||||
|
foot_init = 0x41;
|
||||||
|
}else if(buffer[4] == 0x02){//设定数据来源是右脚
|
||||||
|
foot_init = 0x42;
|
||||||
|
}
|
||||||
|
send2_1[4] = foot_init;
|
||||||
|
send_data_to_ble_client(&send2_1,9);
|
||||||
|
break;
|
||||||
|
case 0x02: //数据包类型为:获取指定传感器初始化状态
|
||||||
|
u8 send2_2[5] = {0xBB,0xBE,0x02,0x00,0x00};
|
||||||
|
if(buffer[4] == 0x01){ //六轴
|
||||||
|
send2_2[4] = SC7U22_init;
|
||||||
|
}else if(buffer[4] == 0x02){ //地磁
|
||||||
|
send2_2[4] = MMC5603nj_init;
|
||||||
|
}else if(buffer[4] == 0x03){ //气压计
|
||||||
|
send2_2[4] = BMP280_init;
|
||||||
|
}
|
||||||
|
send_data_to_ble_client(&send2_2,5);
|
||||||
|
break;
|
||||||
|
case 0x03: //开始/停止滑雪计算
|
||||||
|
if(buffer[4] == 0x01){ //开始滑雪计算
|
||||||
|
if(SC7U22_init == 0x10 || MMC5603nj_init == 0x20 || BMP280_init == 0x30){ //传感器未进行初始化
|
||||||
|
u8 send2_3[5] = {0xBB,0xBE,0x02,0x00,0x00};
|
||||||
|
send_data_to_ble_client(&send2_3,5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
start_clloct();
|
||||||
|
}else if(buffer[4] == 0x02){ //停止滑雪计算
|
||||||
|
stop_clloct();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void le_user_app_send_event(size_t command, unsigned char* data, size_t size)
|
||||||
|
{
|
||||||
|
// 中断->事件
|
||||||
|
static unsigned char buffer[512];
|
||||||
|
if(data && size && size <= sizeof(buffer)) {
|
||||||
|
// 拷贝到缓存,避免转发事件的时候,地址发送改变。
|
||||||
|
memcpy(buffer, data, size);
|
||||||
|
struct sys_event event;
|
||||||
|
event.type = SYS_APP_USER_EVENT;
|
||||||
|
event.u.app.command = command;
|
||||||
|
event.u.app.buffer = buffer;
|
||||||
|
event.u.app.size = size;
|
||||||
|
sys_event_notify(&event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void le_user_app_event_handler(struct sys_event* event){
|
||||||
|
|
||||||
|
switch (event->type) {
|
||||||
|
// 打印接收到的数据
|
||||||
|
printf("BLE data\n");
|
||||||
|
put_buf(event->u.app.buffer, event->u.app.size);
|
||||||
|
case SYS_APP_USER_EVENT:
|
||||||
|
if (event->u.app.buffer[0] == 0xBE && event->u.app.buffer[1] == 0xBB) {
|
||||||
|
if(event->u.app.buffer[2] == 0x01){ //后面的数据长度 1
|
||||||
|
switch (event->u.app.buffer[3]){
|
||||||
|
case 0x01:
|
||||||
|
// extern void gsensor_test(void);
|
||||||
|
// create_process(&gsensor_test_id,"gsensor_test",NULL,gsensor_test,1000);
|
||||||
|
xlog("ota_test");
|
||||||
|
cpu_reset();
|
||||||
|
break;
|
||||||
|
case 0xff: //测试
|
||||||
|
u8 device_buff[10];
|
||||||
|
u8 founds = 0;
|
||||||
|
extern void i2c_scanner_probe(u8* device_addr, u8* found_number);
|
||||||
|
i2c_scanner_probe(device_buff,&founds);
|
||||||
|
for(int i = 0;i < founds;i++){
|
||||||
|
send_data_to_ble_client(&device_buff,founds);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
extern void test_func(void);
|
||||||
|
test_func();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else if(event->u.app.buffer[2] == 0x02){ //后面数据长度为2
|
||||||
|
switch (event->u.app.buffer[3]){ //数据包类型
|
||||||
|
case 0x00: //数据包类型为:指定传感器初始化
|
||||||
|
u8 send2_0[5] = {0xBB,0xBE,0x02,0x00,0x00};
|
||||||
|
if(event->u.app.buffer[4] == 0x01){ //六轴
|
||||||
|
// stop_calibration();
|
||||||
|
if (SL_SC7U22_Config() == 0) {
|
||||||
|
SC7U22_init = 0x10; //初始化失败
|
||||||
|
}else{
|
||||||
|
SC7U22_init = 0x11;
|
||||||
|
}
|
||||||
|
send2_0[4] = SC7U22_init;
|
||||||
|
send_data_to_ble_client(&send2_0,5);
|
||||||
|
// start_calibration();
|
||||||
|
}else if(event->u.app.buffer[4] == 0x02){ //地磁
|
||||||
|
if(mmc5603nj_init() == 0){
|
||||||
|
MMC5603nj_init = 0x20;
|
||||||
|
send2_0[4] = MMC5603nj_init; //地磁初始化失败
|
||||||
|
send_data_to_ble_client(&send2_0,5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MMC5603nj_init = 0x21;
|
||||||
|
send2_0[4] = MMC5603nj_init; //地磁初始化成功
|
||||||
|
send_data_to_ble_client(&send2_0,5);
|
||||||
|
}else if(event->u.app.buffer[4] == 0x03){ //气压计初始化
|
||||||
|
if(bmp280_init() != 0){
|
||||||
|
//初始化失败
|
||||||
|
BMP280_init = 0x30;
|
||||||
|
send2_0[4] = BMP280_init;
|
||||||
|
send_data_to_ble_client(&send2_0,5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BMP280_init = 0x31;
|
||||||
|
send2_0[4] = BMP280_init; //气压计初始化成功
|
||||||
|
send_data_to_ble_client(&send2_0,5);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x01: //设置传感器采集对象:左脚or右脚
|
||||||
|
u8 send2_1[9] = {0xBB,0xBE,0x06,0x05,0x00,0x00,0x00,0x00,0x00};
|
||||||
|
if(event->u.app.buffer[4] == 0x01){ //设定数据来源是左脚
|
||||||
|
foot_init = 0x41;
|
||||||
|
}else if(event->u.app.buffer[4] == 0x02){//设定数据来源是右脚
|
||||||
|
foot_init = 0x42;
|
||||||
|
}
|
||||||
|
send2_1[4] = foot_init;
|
||||||
|
send_data_to_ble_client(&send2_1,9);
|
||||||
|
break;
|
||||||
|
case 0x02: //数据包类型为:获取指定传感器初始化状态
|
||||||
|
u8 send2_2[5] = {0xBB,0xBE,0x02,0x00,0x00};
|
||||||
|
if(event->u.app.buffer[4] == 0x01){ //六轴
|
||||||
|
send2_2[4] = SC7U22_init;
|
||||||
|
}else if(event->u.app.buffer[4] == 0x02){ //地磁
|
||||||
|
send2_2[4] = MMC5603nj_init;
|
||||||
|
}else if(event->u.app.buffer[4] == 0x03){ //气压计
|
||||||
|
send2_2[4] = BMP280_init;
|
||||||
|
}
|
||||||
|
send_data_to_ble_client(&send2_2,5);
|
||||||
|
break;
|
||||||
|
case 0x03: //开始/停止滑雪计算
|
||||||
|
if(event->u.app.buffer[4] == 0x01){ //开始滑雪计算
|
||||||
|
if(SC7U22_init == 0x10 || MMC5603nj_init == 0x20 || BMP280_init == 0x30){ //传感器未进行初始化
|
||||||
|
u8 send2_3[5] = {0xBB,0xBE,0x02,0x00,0x00};
|
||||||
|
send_data_to_ble_client(&send2_3,5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
start_clloct();
|
||||||
|
}else if(event->u.app.buffer[4] == 0x02){ //停止滑雪计算
|
||||||
|
stop_clloct();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
xlog("%d\n",event->type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void play_poweron_ok_timer(void *priv)
|
static void play_poweron_ok_timer(void *priv)
|
||||||
{
|
{
|
||||||
@ -250,7 +504,7 @@ static int bt_connction_status_event_handler(struct bt_event *bt)
|
|||||||
case BT_STATUS_FIRST_CONNECTED:
|
case BT_STATUS_FIRST_CONNECTED:
|
||||||
xlog("BT_STATUS_CONNECTED\n");
|
xlog("BT_STATUS_CONNECTED\n");
|
||||||
xtell_bl_state = 1; //蓝牙连接成功 置1
|
xtell_bl_state = 1; //蓝牙连接成功 置1
|
||||||
if(strcmp(xt_ble_new_name,"CM-1111") != 0){
|
if(strcmp(xt_ble_new_name,"CM-11111") != 0){
|
||||||
//蓝牙连接成功
|
//蓝牙连接成功
|
||||||
bt_newname =1;
|
bt_newname =1;
|
||||||
u8 temp[5]={0xBB,0xBE,0x02,0x04,0x00};
|
u8 temp[5]={0xBB,0xBE,0x02,0x04,0x00};
|
||||||
@ -355,9 +609,11 @@ static int bt_connction_status_event_handler(struct bt_event *bt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int event_handler(struct application *app, struct sys_event *event)
|
static int event_handler(struct application *app, struct sys_event *event)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
le_user_app_event_handler(event);
|
||||||
|
|
||||||
if (SYS_EVENT_REMAP(event)) {
|
if (SYS_EVENT_REMAP(event)) {
|
||||||
g_printf("****SYS_EVENT_REMAP**** \n");
|
g_printf("****SYS_EVENT_REMAP**** \n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -1,259 +0,0 @@
|
|||||||
#include "system/includes.h"
|
|
||||||
/*#include "btcontroller_config.h"*/
|
|
||||||
#include "btstack/btstack_task.h"
|
|
||||||
#include "app_config.h"
|
|
||||||
#include "app_action.h"
|
|
||||||
#include "asm/pwm_led.h"
|
|
||||||
#include "tone_player.h"
|
|
||||||
#include "gpio.h"
|
|
||||||
#include "app_main.h"
|
|
||||||
#include "asm/charge.h"
|
|
||||||
#include "update.h"
|
|
||||||
#include "app_power_manage.h"
|
|
||||||
#include "app_charge.h"
|
|
||||||
#include "bt_profile_cfg.h"
|
|
||||||
#include "dev_manager/dev_manager.h"
|
|
||||||
#include "update_loader_download.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define LOG_TAG_CONST APP
|
|
||||||
#define LOG_TAG "[APP]"
|
|
||||||
#define LOG_ERROR_ENABLE
|
|
||||||
#define LOG_DEBUG_ENABLE
|
|
||||||
#define LOG_INFO_ENABLE
|
|
||||||
/* #define LOG_DUMP_ENABLE */
|
|
||||||
#define LOG_CLI_ENABLE
|
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
#ifdef CONFIG_BOARD_AISPEECH_VAD_ASR
|
|
||||||
u8 user_at_cmd_send_support = 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*任务列表 */
|
|
||||||
const struct task_info task_info_table[] = {
|
|
||||||
{"app_core", 1, 0, 768, 256 },
|
|
||||||
{"sys_event", 7, 0, 256, 0 },
|
|
||||||
{"systimer", 7, 0, 128, 0 },
|
|
||||||
{"btctrler", 4, 0, 512, 384 },
|
|
||||||
{"btencry", 1, 0, 512, 128 },
|
|
||||||
{"tws", 5, 0, 512, 128 },
|
|
||||||
#if (BT_FOR_APP_EN)
|
|
||||||
{"btstack", 3, 0, 1024, 256 },
|
|
||||||
#else
|
|
||||||
{"btstack", 3, 0, 768, 256 },
|
|
||||||
#endif
|
|
||||||
{"audio_dec", 5, 0, 800, 128 },
|
|
||||||
{"aud_effect", 5, 1, 800, 128 },
|
|
||||||
/*
|
|
||||||
*为了防止dac buf太大,通话一开始一直解码,
|
|
||||||
*导致编码输入数据需要很大的缓存,这里提高编码的优先级
|
|
||||||
*/
|
|
||||||
{"audio_enc", 6, 0, 768, 128 },
|
|
||||||
{"aec", 2, 1, 768, 128 },
|
|
||||||
#if TCFG_AUDIO_HEARING_AID_ENABLE
|
|
||||||
{"HearingAid", 6, 0, 768, 128 },
|
|
||||||
#endif/*TCFG_AUDIO_HEARING_AID_ENABLE*/
|
|
||||||
#ifdef CONFIG_BOARD_AISPEECH_NR
|
|
||||||
{"aispeech_enc", 2, 1, 512, 128 },
|
|
||||||
#endif /*CONFIG_BOARD_AISPEECH_NR*/
|
|
||||||
#ifdef CONFIG_BOARD_AISPEECH_VAD_ASR
|
|
||||||
{"asr", 1, 0, 768, 128 },
|
|
||||||
{"audio_asr_export_task", 1, 0, 512, 128 },
|
|
||||||
#endif/*CONFIG_BOARD_AISPEECH_VAD_ASR*/
|
|
||||||
#ifndef CONFIG_256K_FLASH
|
|
||||||
{"aec_dbg", 3, 0, 128, 128 },
|
|
||||||
|
|
||||||
#if AUDIO_ENC_MPT_SELF_ENABLE
|
|
||||||
{"enc_mpt_self", 3, 0, 512, 128 },
|
|
||||||
#endif/*AUDIO_ENC_MPT_SELF_ENABLE*/
|
|
||||||
{"update", 1, 0, 256, 0 },
|
|
||||||
{"tws_ota", 2, 0, 256, 0 },
|
|
||||||
{"tws_ota_msg", 2, 0, 256, 128 },
|
|
||||||
{"dw_update", 2, 0, 256, 128 },
|
|
||||||
{"rcsp_task", 2, 0, 640, 128 },
|
|
||||||
{"aud_capture", 4, 0, 512, 256 },
|
|
||||||
{"data_export", 5, 0, 512, 256 },
|
|
||||||
{"anc", 3, 1, 512, 128 },
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if TCFG_GX8002_NPU_ENABLE
|
|
||||||
{"gx8002", 2, 0, 256, 64 },
|
|
||||||
#endif /* #if TCFG_GX8002_NPU_ENABLE */
|
|
||||||
#if TCFG_GX8002_ENC_ENABLE
|
|
||||||
{"gx8002_enc", 2, 0, 128, 64 },
|
|
||||||
#endif /* #if TCFG_GX8002_ENC_ENABLE */
|
|
||||||
|
|
||||||
|
|
||||||
#if TCFG_KWS_VOICE_RECOGNITION_ENABLE
|
|
||||||
{"kws", 2, 0, 256, 64 },
|
|
||||||
#endif /* #if TCFG_KWS_VOICE_RECOGNITION_ENABLE */
|
|
||||||
{"usb_msd", 1, 0, 512, 128 },
|
|
||||||
#if !TCFG_USB_MIC_CVP_ENABLE
|
|
||||||
{"usbmic_write", 2, 0, 256, 128 },
|
|
||||||
#endif
|
|
||||||
#if AI_APP_PROTOCOL
|
|
||||||
{"app_proto", 2, 0, 768, 64 },
|
|
||||||
#endif
|
|
||||||
#if (TCFG_SPI_LCD_ENABLE||TCFG_SIMPLE_LCD_ENABLE)
|
|
||||||
{"ui", 2, 0, 768, 256 },
|
|
||||||
#else
|
|
||||||
{"ui", 3, 0, 384 - 64, 128 },
|
|
||||||
#endif
|
|
||||||
#if (TCFG_DEV_MANAGER_ENABLE)
|
|
||||||
{"dev_mg", 3, 0, 512, 512 },
|
|
||||||
#endif
|
|
||||||
{"audio_vad", 1, 1, 512, 128 },
|
|
||||||
#if TCFG_KEY_TONE_EN
|
|
||||||
{"key_tone", 5, 0, 256, 32 },
|
|
||||||
#endif
|
|
||||||
#if (TCFG_WIRELESS_MIC_ENABLE)
|
|
||||||
{"wl_mic_enc", 2, 0, 768, 128 },
|
|
||||||
#endif
|
|
||||||
#if (TUYA_DEMO_EN)
|
|
||||||
{"user_deal", 7, 0, 512, 512 },//定义线程 tuya任务调度
|
|
||||||
{"dw_update", 2, 0, 256, 128 },
|
|
||||||
#endif
|
|
||||||
#if TCFG_AUDIO_SPATIAL_EFFECT_ENABLE
|
|
||||||
{"imu_trim", 1, 0, 256, 128 },
|
|
||||||
#endif /*TCFG_AUDIO_SPATIAL_EFFECT_ENABLE*/
|
|
||||||
#if TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN
|
|
||||||
{"speak_to_chat", 2, 0, 256, 128 },
|
|
||||||
{"icsd_adt", 2, 0, 512, 128 },
|
|
||||||
{"icsd_src", 2, 1, 512, 128 },
|
|
||||||
#endif /*TCFG_AUDIO_ANC_ACOUSTIC_DETECTOR_EN*/
|
|
||||||
{"pmu_task", 6, 0, 256, 128 },
|
|
||||||
{"WindDetect", 2, 0, 256, 128 },
|
|
||||||
{0, 0},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
APP_VAR app_var;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 2ms timer中断回调函数
|
|
||||||
*/
|
|
||||||
void timer_2ms_handler()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_var_init(void)
|
|
||||||
{
|
|
||||||
memset((u8 *)&bt_user_priv_var, 0, sizeof(BT_USER_PRIV_VAR));
|
|
||||||
app_var.play_poweron_tone = 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_earphone_play_voice_file(const char *name);
|
|
||||||
|
|
||||||
void clr_wdt(void);
|
|
||||||
|
|
||||||
void check_power_on_key(void)
|
|
||||||
{
|
|
||||||
u32 delay_10ms_cnt = 0;
|
|
||||||
|
|
||||||
#if 0 //PC_MODE_DETECTION
|
|
||||||
gpio_set_pull_up(IO_PORTP_00, 0);
|
|
||||||
gpio_set_pull_down(IO_PORTP_00, 1);
|
|
||||||
gpio_set_direction(IO_PORTP_00, 1);
|
|
||||||
gpio_set_die(IO_PORTP_00, 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
clr_wdt();
|
|
||||||
os_time_dly(1);
|
|
||||||
|
|
||||||
extern u8 get_power_on_status(void);
|
|
||||||
if (get_power_on_status()) {
|
|
||||||
log_info("+");
|
|
||||||
delay_10ms_cnt++;
|
|
||||||
if (delay_10ms_cnt > 70) {
|
|
||||||
/* extern void set_key_poweron_flag(u8 flag); */
|
|
||||||
/* set_key_poweron_flag(1); */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log_info("-");
|
|
||||||
delay_10ms_cnt = 0;
|
|
||||||
log_info("enter softpoweroff\n");
|
|
||||||
power_set_soft_poweroff();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
extern int cpu_reset_by_soft();
|
|
||||||
extern int audio_dec_init();
|
|
||||||
extern int audio_enc_init();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__attribute__((weak))
|
|
||||||
u8 get_charge_online_flag(void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*充电拔出,CPU软件复位, 不检测按键,直接开机*/
|
|
||||||
static void app_poweron_check(int update)
|
|
||||||
{
|
|
||||||
#if (CONFIG_BT_MODE == BT_NORMAL)
|
|
||||||
if (!update && cpu_reset_by_soft()) {
|
|
||||||
app_var.play_poweron_tone = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if TCFG_CHARGE_OFF_POWERON_NE
|
|
||||||
if (is_ldo5v_wakeup()) {
|
|
||||||
app_var.play_poweron_tone = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
//#ifdef CONFIG_RELEASE_ENABLE
|
|
||||||
#if TCFG_POWER_ON_NEED_KEY
|
|
||||||
check_power_on_key();
|
|
||||||
#endif
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
extern u32 timer_get_ms(void);
|
|
||||||
void app_main()
|
|
||||||
{
|
|
||||||
int update = 0;
|
|
||||||
u32 addr = 0, size = 0;
|
|
||||||
struct intent it;
|
|
||||||
|
|
||||||
|
|
||||||
if (!UPDATE_SUPPORT_DEV_IS_NULL()) {
|
|
||||||
update = update_result_deal();
|
|
||||||
}
|
|
||||||
|
|
||||||
app_var_init();
|
|
||||||
|
|
||||||
// if (get_charge_online_flag()) {
|
|
||||||
#if(TCFG_SYS_LVD_EN == 1)
|
|
||||||
vbat_check_init();
|
|
||||||
#endif
|
|
||||||
// init_intent(&it);
|
|
||||||
// it.name = "idle";
|
|
||||||
// it.action = ACTION_IDLE_MAIN;
|
|
||||||
// start_app(&it);
|
|
||||||
// } else {
|
|
||||||
check_power_on_voltage();
|
|
||||||
app_poweron_check(update);
|
|
||||||
init_intent(&it);
|
|
||||||
it.name = "handler";
|
|
||||||
it.action = ACTION_EARPHONE_MAIN;
|
|
||||||
start_app(&it);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
log_info("app_main\n");
|
|
||||||
app_var.start_time = timer_get_ms();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
#include "app_config.h"
|
|
||||||
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
.text : ALIGN(4)
|
|
||||||
{
|
|
||||||
gsensor_dev_begin = .;
|
|
||||||
KEEP(*(.gsensor_dev))
|
|
||||||
gsensor_dev_end = .;
|
|
||||||
|
|
||||||
fm_dev_begin = .;
|
|
||||||
KEEP(*(.fm_dev))
|
|
||||||
fm_dev_end = .;
|
|
||||||
|
|
||||||
fm_emitter_dev_begin = .;
|
|
||||||
KEEP(*(.fm_emitter_dev))
|
|
||||||
fm_emitter_dev_end = .;
|
|
||||||
|
|
||||||
storage_device_begin = .;
|
|
||||||
KEEP(*(.storage_device))
|
|
||||||
storage_device_end = .;
|
|
||||||
|
|
||||||
imusensor_dev_begin = .;
|
|
||||||
KEEP(*(.imusensor_dev))
|
|
||||||
imusensor_dev_end = .;
|
|
||||||
|
|
||||||
#if TCFG_APP_PC_EN
|
|
||||||
aac_dec_code_begin = .;
|
|
||||||
*(.bt_aac_dec_code)
|
|
||||||
*(.bt_aac_dec_sparse_code)
|
|
||||||
aac_dec_code_end = .;
|
|
||||||
aac_dec_code_size = aac_dec_code_end - aac_dec_code_begin ;
|
|
||||||
|
|
||||||
. = ALIGN(4);
|
|
||||||
bt_aac_dec_const_begin = .;
|
|
||||||
*(.bt_aac_dec_const)
|
|
||||||
*(.bt_aac_dec_sparse_const)
|
|
||||||
bt_aac_dec_const_end = .;
|
|
||||||
bt_aac_dec_const_size = bt_aac_dec_const_end - bt_aac_dec_const_begin ;
|
|
||||||
|
|
||||||
*(.bt_aac_dec_data)
|
|
||||||
*(.bt_aac_dec_bss)
|
|
||||||
|
|
||||||
. = ALIGN(4);
|
|
||||||
*(.aac_mem)
|
|
||||||
*(.aac_ctrl_mem)
|
|
||||||
/* . += 0x5fe8 ; */
|
|
||||||
/* . += 0xef88 ; */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
. = ALIGN(32);
|
|
||||||
}
|
|
||||||
|
|
||||||
.data ALIGN(32):
|
|
||||||
{
|
|
||||||
} > ram0
|
|
||||||
|
|
||||||
.bss ALIGN(32):
|
|
||||||
{
|
|
||||||
} > ram0
|
|
||||||
|
|
||||||
.data_code ALIGN(32):
|
|
||||||
{
|
|
||||||
} > ram0
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,164 +0,0 @@
|
|||||||
|
|
||||||
OVERLAY : AT(0x200000) SUBALIGN(4)
|
|
||||||
{
|
|
||||||
.overlay_aec
|
|
||||||
{
|
|
||||||
aec_code_begin = . ;
|
|
||||||
*(.text._*)
|
|
||||||
*(.data._*)
|
|
||||||
*(.aec_code)
|
|
||||||
*(.aec_const)
|
|
||||||
*(.res_code)
|
|
||||||
*(.res_const)
|
|
||||||
*(.ns_code)
|
|
||||||
*(.ns_const)
|
|
||||||
*(.bark_const)
|
|
||||||
*(.fft_code)
|
|
||||||
*(.fft_const)
|
|
||||||
*(.agc_code)
|
|
||||||
*(.dms_code)
|
|
||||||
*(.dms_const)
|
|
||||||
*(.dms_sparse_code)
|
|
||||||
aec_code_end = . ;
|
|
||||||
aec_code_size = aec_code_end - aec_code_begin ;
|
|
||||||
|
|
||||||
*(.msbc_enc)
|
|
||||||
*(.cvsd_codec)
|
|
||||||
*(.aec_bss)
|
|
||||||
*(.aec_data)
|
|
||||||
*(.res_data)
|
|
||||||
*(.ns_data)
|
|
||||||
*(.dns_common_data)
|
|
||||||
*(.dns_param_data_single)
|
|
||||||
*(.dns_param_data_dual)
|
|
||||||
*(.jlsp_nlp_code)
|
|
||||||
*(.jlsp_nlp_const)
|
|
||||||
*(.jlsp_aec_code)
|
|
||||||
*(.jlsp_aec_const)
|
|
||||||
*(.jlsp_prep_code)
|
|
||||||
*(.jlsp_prep_const)
|
|
||||||
*(.jlsp_enc_code)
|
|
||||||
*(.jlsp_enc_const)
|
|
||||||
*(.jlsp_wn_code)
|
|
||||||
*(.jlsp_wn_const)
|
|
||||||
*(.jlsp_tri_code)
|
|
||||||
*(.jlsp_tri_const)
|
|
||||||
*(.jlsp_agc_code)
|
|
||||||
*(.jlsp_agc_const)
|
|
||||||
*(.res_bss)
|
|
||||||
*(.ns_bss)
|
|
||||||
*(.aec_mem)
|
|
||||||
}
|
|
||||||
.overlay_aac
|
|
||||||
{
|
|
||||||
#if !TCFG_APP_PC_EN
|
|
||||||
aac_dec_code_begin = .;
|
|
||||||
*(.bt_aac_dec_code)
|
|
||||||
*(.bt_aac_dec_sparse_code)
|
|
||||||
aac_dec_code_end = .;
|
|
||||||
aac_dec_code_size = aac_dec_code_end - aac_dec_code_begin ;
|
|
||||||
|
|
||||||
. = ALIGN(4);
|
|
||||||
bt_aac_dec_const_begin = .;
|
|
||||||
*(.bt_aac_dec_const)
|
|
||||||
*(.bt_aac_dec_sparse_const)
|
|
||||||
bt_aac_dec_const_end = .;
|
|
||||||
bt_aac_dec_const_size = bt_aac_dec_const_end - bt_aac_dec_const_begin ;
|
|
||||||
|
|
||||||
*(.bt_aac_dec_data)
|
|
||||||
*(.bt_aac_dec_bss)
|
|
||||||
|
|
||||||
. = ALIGN(4);
|
|
||||||
*(.aac_mem)
|
|
||||||
*(.aac_ctrl_mem)
|
|
||||||
/* . += 0x5fe8 ; */
|
|
||||||
/* . += 0xef88 ; */
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
.overlay_lc3
|
|
||||||
{
|
|
||||||
lc3_dec_code_begin = .;
|
|
||||||
*(.lc3_dec_code)
|
|
||||||
lc3_dec_code_end = .;
|
|
||||||
lc3_dec_code_size = lc3_dec_code_end - lc3_dec_code_begin;
|
|
||||||
|
|
||||||
. = ALIGN(4);
|
|
||||||
lc3_dec_const_begin = .;
|
|
||||||
*(.lc3_dec_const)
|
|
||||||
lc3_dec_const_end = .;
|
|
||||||
lc3_dec_const_size = lc3_dec_const_end - lc3_dec_const_begin;
|
|
||||||
*(.lc3_dec_data)
|
|
||||||
*(.lc3_dec_bss)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
.overlay_mp3
|
|
||||||
{
|
|
||||||
*(.mp3_mem)
|
|
||||||
*(.mp3_ctrl_mem)
|
|
||||||
*(.mp3pick_mem)
|
|
||||||
*(.mp3pick_ctrl_mem)
|
|
||||||
*(.dec2tws_mem)
|
|
||||||
}
|
|
||||||
.overlay_wma
|
|
||||||
{
|
|
||||||
*(.wma_mem)
|
|
||||||
*(.wma_ctrl_mem)
|
|
||||||
*(.wmapick_mem)
|
|
||||||
*(.wmapick_ctrl_mem)
|
|
||||||
}
|
|
||||||
.overlay_wav
|
|
||||||
{
|
|
||||||
*(.wav_mem)
|
|
||||||
*(.wav_ctrl_mem)
|
|
||||||
}
|
|
||||||
.overlay_ape
|
|
||||||
{
|
|
||||||
*(.ape_mem)
|
|
||||||
*(.ape_ctrl_mem)
|
|
||||||
}
|
|
||||||
.overlay_flac
|
|
||||||
{
|
|
||||||
*(.flac_mem)
|
|
||||||
*(.flac_ctrl_mem)
|
|
||||||
}
|
|
||||||
.overlay_m4a
|
|
||||||
{
|
|
||||||
*(.m4a_mem)
|
|
||||||
*(.m4a_ctrl_mem)
|
|
||||||
}
|
|
||||||
.overlay_amr
|
|
||||||
{
|
|
||||||
*(.amr_mem)
|
|
||||||
*(.amr_ctrl_mem)
|
|
||||||
}
|
|
||||||
.overlay_dts
|
|
||||||
{
|
|
||||||
*(.dts_mem)
|
|
||||||
*(.dts_ctrl_mem)
|
|
||||||
}
|
|
||||||
.overlay_fm
|
|
||||||
{
|
|
||||||
*(.fm_mem)
|
|
||||||
}
|
|
||||||
.overlay_pc
|
|
||||||
{
|
|
||||||
*(.usb_audio_play_dma)
|
|
||||||
*(.usb_audio_rec_dma)
|
|
||||||
*(.uac_rx)
|
|
||||||
*(.mass_storage)
|
|
||||||
|
|
||||||
*(.usb_ep0)
|
|
||||||
*(.usb_msd_dma)
|
|
||||||
*(.usb_hid_dma)
|
|
||||||
*(.usb_iso_dma)
|
|
||||||
*(.usb_cdc_dma)
|
|
||||||
*(.uac_var)
|
|
||||||
*(.usb_config_var)
|
|
||||||
*(.cdc_var)
|
|
||||||
}
|
|
||||||
|
|
||||||
} > ram0
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
#ifndef BOARD_CONFIG_H
|
|
||||||
#define BOARD_CONFIG_H
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 板级配置选择
|
|
||||||
*/
|
|
||||||
#define CONFIG_BOARD_JL701N_DEMO //编译正常 2025-4-29
|
|
||||||
// #define CONFIG_BOARD_JL701N_BTEMITTER
|
|
||||||
// #define CONFIG_BOARD_JL701N_ANC
|
|
||||||
// #define CONFIG_BOARD_JL7016G_HYBRID
|
|
||||||
// #define CONFIG_BOARD_JL7018F_DEMO //编译不过 2025-4-29
|
|
||||||
|
|
||||||
#include "media/audio_def.h"
|
|
||||||
#include "board_jl701n_demo_cfg.h"
|
|
||||||
#include "board_jl701n_btemitter_cfg.h"
|
|
||||||
#include "board_jl701n_anc_cfg.h"
|
|
||||||
#include "board_jl7016g_hybrid_cfg.h"
|
|
||||||
#include "board_jl7018f_demo_cfg.h"
|
|
||||||
|
|
||||||
#define DUT_AUDIO_DAC_LDO_VOLT DACVDD_LDO_1_25V
|
|
||||||
|
|
||||||
#ifdef CONFIG_NEW_CFG_TOOL_ENABLE
|
|
||||||
#define CONFIG_ENTRY_ADDRESS 0x6000100
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,123 +0,0 @@
|
|||||||
#ifndef CONFIG_BOARD_JL7016G_HYBRID_POST_BUILD_CFG_H
|
|
||||||
#define CONFIG_BOARD_JL7016G_HYBRID_POST_BUILD_CFG_H
|
|
||||||
|
|
||||||
/* 改文件只添加和isd_config.ini相关的配置,用以生成isd_config.ini */
|
|
||||||
/* 其他不相关的配置请勿添加在改文件 */
|
|
||||||
|
|
||||||
#ifdef CONFIG_BOARD_JL7016G_HYBRID
|
|
||||||
|
|
||||||
/* Following Macros Affect Periods Of Both Code Compiling And Post-build */
|
|
||||||
|
|
||||||
#define CONFIG_DOUBLE_BANK_ENABLE 0 //单双备份选择(若打开了改宏,FLASH结构变为双备份结构,适用于接入第三方协议的OTA, PS: JL-OTA同样支持双备份升级, 需要根据实际FLASH大小同时配置CONFIG_FLASH_SIZE)
|
|
||||||
#define CONFIG_APP_OTA_ENABLE 0 //是否支持RCSP升级(JL-OTA)
|
|
||||||
|
|
||||||
#define CONFIG_UPDATE_JUMP_TO_MASK 0 //配置升级到loader的方式0为直接reset,1为跳转(适用于芯片电源由IO口KEEP住的方案,需要注意检查跳转前是否将使用DMA的硬件模块全部关闭)
|
|
||||||
|
|
||||||
#define CONFIG_IO_KEY_EN 0 //配置是否使用IO按键,配合RESET1
|
|
||||||
#define CONFIG_UPDATE_WITH_MD5_CHECK_EN 0 //配置升级是否支持MD5校验
|
|
||||||
|
|
||||||
#define CONFIG_ANC_ENABLE 1 //配置是否支持ANC
|
|
||||||
|
|
||||||
//flash size vaule definition
|
|
||||||
#define FLASH_SIZE_256K 0x40000
|
|
||||||
#define FLASH_SIZE_512K 0x80000
|
|
||||||
#define FLASH_SIZE_1M 0x100000
|
|
||||||
#define FLASH_SIZE_2M 0x200000
|
|
||||||
#define FLASH_SIZE_4M 0x400000
|
|
||||||
|
|
||||||
#define CONFIG_FLASH_SIZE FLASH_SIZE_1M //配置FLASH大小
|
|
||||||
|
|
||||||
|
|
||||||
/* Above Macros Affect Periods Of Both Code Compiling And Post-build */
|
|
||||||
|
|
||||||
/* Following Macros Only For Post Bulid Configuaration */
|
|
||||||
|
|
||||||
#define CONFIG_DB_UPDATE_DATA_GENERATE_EN 0 //是否生成db_data.bin(用于第三方协议接入使用)
|
|
||||||
#define CONFIG_ONLY_GRENERATE_ALIGN_4K_CODE 0 //ufw只生成1份4K对齐的代码
|
|
||||||
|
|
||||||
//config for supported chip version
|
|
||||||
#ifdef CONFIG_BR30_C_VERSION
|
|
||||||
#define CONFIG_SUPPORTED_CHIP_VERSION C
|
|
||||||
#else
|
|
||||||
#define CONFIG_SUPPORTED_CHIP_VERSION B,D,E,M,N,O,P
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//DON'T MODIFY THIS CONFIG EXCEPT SDK PUBLISHER
|
|
||||||
#define CONFIG_CHIP_NAME AC701N //除了SDK发布者,请不要修改
|
|
||||||
//it can be modified before first programming,but keep the same as the original version
|
|
||||||
#define CONFIG_PID AC701N //烧写或强制升级之前可以修改,之后升级要保持一致
|
|
||||||
//it can be modified before first programming,but keep the same as the original version
|
|
||||||
#define CONFIG_VID 0.01 //烧写或强制升级之前可以修改,之后升级要保持一致
|
|
||||||
|
|
||||||
//Project with bluetooth,it must use OSC as PLL_SOURCE;
|
|
||||||
#define CONFIG_PLL_SOURCE_USING_LRC 0 //PLL时钟源选择 1:LRC 2:OSC
|
|
||||||
|
|
||||||
//config alignment size unit
|
|
||||||
#ifdef CONFIG_256K_FLASH
|
|
||||||
#define ALIGN_UNIT_256B 1 //FLASH对齐方式选择,如果是256K的FLASH,选择256BYTE对齐方式
|
|
||||||
#else
|
|
||||||
#define ALIGN_UNIT_256B 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//partial platform check this config to select the uart IO for wired update
|
|
||||||
#define CONFIG_UART_UPDATE_PIN PP00
|
|
||||||
|
|
||||||
//isd_download loader/uboot/update_loader debug io config
|
|
||||||
//#define CONFIG_UBOOT_DEBUG_PIN PA05
|
|
||||||
//#define CONFIG_UBOOT_DEBUG_BAUD_RATE 1000000
|
|
||||||
|
|
||||||
//config long-press reset io pin,time,trigger level
|
|
||||||
#define CONFIG_RESET_PIN LDO //io pin
|
|
||||||
#define CONFIG_RESET_TIME 04 //unit:second
|
|
||||||
#define CONFIG_RESET_LEVEL 1 //tigger level(0/1)
|
|
||||||
|
|
||||||
#if CONFIG_IO_KEY_EN
|
|
||||||
#define CONFIG_SUPPORT_RESET1
|
|
||||||
#define CONFIG_RESET1_PIN PB01 //io pin
|
|
||||||
#define CONFIG_RESET1_TIME 08 //unit:second
|
|
||||||
#define CONFIG_RESET1_LEVEL 0 //tigger level(0/1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//reserved three custom cfg item for the future definition
|
|
||||||
//#define CONFIG_CUSTOM_CFG1_TYPE POWER_PIN
|
|
||||||
//#define CONFIG_CUSTOM_CFG1_VALUE PC01_1
|
|
||||||
|
|
||||||
//#define CONFIG_CUSTOM_CFG2_TYPE
|
|
||||||
//#define CONFIG_CUSTOM_CFG2_VALUE
|
|
||||||
|
|
||||||
//#define CONFIG_CUSTOM_CFG3_TYPE
|
|
||||||
//#define CONFIG_CUSTOM_CFG3_VALUE
|
|
||||||
|
|
||||||
|
|
||||||
//#define CONFIG_VDDIO_LVD_LEVEL 4 ////VDDIO_LVD挡位,0: 1.9V 1: 2.0V 2: 2.1V 3: 2.2V 4: 2.3V 5: 2.4V 6: 2.5V 7: 2.6V
|
|
||||||
|
|
||||||
//with single-bank mode,actual vm size should larger this VM_LEAST_SIZE,and dual bank mode,actual vm size equals this;
|
|
||||||
#define CONFIG_VM_LEAST_SIZE 8K
|
|
||||||
//config whether erased this area when do a update,1-No Operation,0-Erase
|
|
||||||
#define CONFIG_VM_OPT 1
|
|
||||||
|
|
||||||
//config whether erased this area when do a update,1-No Operation,0-Erase
|
|
||||||
#define CONFIG_BTIF_OPT 1
|
|
||||||
|
|
||||||
//reserved two custom cfg area for the future definition
|
|
||||||
//#define CONFIG_RESERVED_AREA1 EXIF1
|
|
||||||
#ifdef CONFIG_RESERVED_AREA1
|
|
||||||
#define CONFIG_RESERVED_AREA1_ADDR AUTO
|
|
||||||
#define CONFIG_RESERVED_AREA1_LEN 0x1000
|
|
||||||
#define CONFIG_RESERVED_AREA1_OPT 1
|
|
||||||
//#define CONFIG_RESERVED_AREA1_FILE anc_gains.bin
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//#define CONFIG_RESERVED_AREA2 EXIF2
|
|
||||||
#ifdef CONFIG_RESERVED_AREA2
|
|
||||||
#define CONFIG_RESERVED_AREA2_ADDR AUTO
|
|
||||||
#define CONFIG_RESERVED_AREA2_LEN 0x1000
|
|
||||||
#define CONFIG_RESERVED_AREA2_OPT 1
|
|
||||||
//#define CONFIG_RESERVED_AREA2_FILE anc_gains.bin
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Above Macros Only For Post Bulid Configuaration */
|
|
||||||
#endif /* #ifdef CONFIG_BOARD_JL7016G_HYBRID */
|
|
||||||
|
|
||||||
#endif /* #ifndef CONFIG_BOARD_JL701N_ANC_POST_BUILD_CFG_H */
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,123 +0,0 @@
|
|||||||
#ifndef CONFIG_BOARD_JL7018F_DEMO_POST_BUILD_CFG_H
|
|
||||||
#define CONFIG_BOARD_JL7018F_DEMO_POST_BUILD_CFG_H
|
|
||||||
|
|
||||||
/* 改文件只添加和isd_config.ini相关的配置,用以生成isd_config.ini */
|
|
||||||
/* 其他不相关的配置请勿添加在改文件 */
|
|
||||||
|
|
||||||
#ifdef CONFIG_BOARD_JL7018F_DEMO
|
|
||||||
|
|
||||||
/* Following Macros Affect Periods Of Both Code Compiling And Post-build */
|
|
||||||
|
|
||||||
#define CONFIG_DOUBLE_BANK_ENABLE 0 //单双备份选择(若打开了改宏,FLASH结构变为双备份结构,适用于接入第三方协议的OTA, PS: JL-OTA同样支持双备份升级, 需要根据实际FLASH大小同时配置CONFIG_FLASH_SIZE)
|
|
||||||
#define CONFIG_APP_OTA_ENABLE 0 //是否支持RCSP升级(JL-OTA)
|
|
||||||
|
|
||||||
#define CONFIG_UPDATE_JUMP_TO_MASK 0 //配置升级到loader的方式0为直接reset,1为跳转(适用于芯片电源由IO口KEEP住的方案,需要注意检查跳转前是否将使用DMA的硬件模块全部关闭)
|
|
||||||
|
|
||||||
#define CONFIG_IO_KEY_EN 0 //配置是否使用IO按键,配合RESET1
|
|
||||||
#define CONFIG_UPDATE_WITH_MD5_CHECK_EN 0 //配置升级是否支持MD5校验
|
|
||||||
|
|
||||||
#define CONFIG_ANC_ENABLE 1 //配置是否支持ANC
|
|
||||||
|
|
||||||
//flash size vaule definition
|
|
||||||
#define FLASH_SIZE_256K 0x40000
|
|
||||||
#define FLASH_SIZE_512K 0x80000
|
|
||||||
#define FLASH_SIZE_1M 0x100000
|
|
||||||
#define FLASH_SIZE_2M 0x200000
|
|
||||||
#define FLASH_SIZE_4M 0x400000
|
|
||||||
|
|
||||||
#define CONFIG_FLASH_SIZE FLASH_SIZE_1M //配置FLASH大小
|
|
||||||
|
|
||||||
|
|
||||||
/* Above Macros Affect Periods Of Both Code Compiling And Post-build */
|
|
||||||
|
|
||||||
/* Following Macros Only For Post Bulid Configuaration */
|
|
||||||
|
|
||||||
#define CONFIG_DB_UPDATE_DATA_GENERATE_EN 0 //是否生成db_data.bin(用于第三方协议接入使用)
|
|
||||||
#define CONFIG_ONLY_GRENERATE_ALIGN_4K_CODE 0 //ufw只生成1份4K对齐的代码
|
|
||||||
|
|
||||||
//config for supported chip version
|
|
||||||
#ifdef CONFIG_BR30_C_VERSION
|
|
||||||
#define CONFIG_SUPPORTED_CHIP_VERSION C
|
|
||||||
#else
|
|
||||||
#define CONFIG_SUPPORTED_CHIP_VERSION B,D,E,M,N,O,P
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//DON'T MODIFY THIS CONFIG EXCEPT SDK PUBLISHER
|
|
||||||
#define CONFIG_CHIP_NAME AC701N //除了SDK发布者,请不要修改
|
|
||||||
//it can be modified before first programming,but keep the same as the original version
|
|
||||||
#define CONFIG_PID AC701N //烧写或强制升级之前可以修改,之后升级要保持一致
|
|
||||||
//it can be modified before first programming,but keep the same as the original version
|
|
||||||
#define CONFIG_VID 0.01 //烧写或强制升级之前可以修改,之后升级要保持一致
|
|
||||||
|
|
||||||
//Project with bluetooth,it must use OSC as PLL_SOURCE;
|
|
||||||
#define CONFIG_PLL_SOURCE_USING_LRC 0 //PLL时钟源选择 1:LRC 2:OSC
|
|
||||||
|
|
||||||
//config alignment size unit
|
|
||||||
#ifdef CONFIG_256K_FLASH
|
|
||||||
#define ALIGN_UNIT_256B 1 //FLASH对齐方式选择,如果是256K的FLASH,选择256BYTE对齐方式
|
|
||||||
#else
|
|
||||||
#define ALIGN_UNIT_256B 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//partial platform check this config to select the uart IO for wired update
|
|
||||||
#define CONFIG_UART_UPDATE_PIN PP00
|
|
||||||
|
|
||||||
//isd_download loader/uboot/update_loader debug io config
|
|
||||||
//#define CONFIG_UBOOT_DEBUG_PIN PA05
|
|
||||||
//#define CONFIG_UBOOT_DEBUG_BAUD_RATE 1000000
|
|
||||||
|
|
||||||
//config long-press reset io pin,time,trigger level
|
|
||||||
#define CONFIG_RESET_PIN LDO //io pin
|
|
||||||
#define CONFIG_RESET_TIME 04 //unit:second
|
|
||||||
#define CONFIG_RESET_LEVEL 1 //tigger level(0/1)
|
|
||||||
|
|
||||||
#if CONFIG_IO_KEY_EN
|
|
||||||
#define CONFIG_SUPPORT_RESET1
|
|
||||||
#define CONFIG_RESET1_PIN PB01 //io pin
|
|
||||||
#define CONFIG_RESET1_TIME 08 //unit:second
|
|
||||||
#define CONFIG_RESET1_LEVEL 0 //tigger level(0/1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//reserved three custom cfg item for the future definition
|
|
||||||
//#define CONFIG_CUSTOM_CFG1_TYPE POWER_PIN
|
|
||||||
//#define CONFIG_CUSTOM_CFG1_VALUE PC01_1
|
|
||||||
|
|
||||||
//#define CONFIG_CUSTOM_CFG2_TYPE
|
|
||||||
//#define CONFIG_CUSTOM_CFG2_VALUE
|
|
||||||
|
|
||||||
//#define CONFIG_CUSTOM_CFG3_TYPE
|
|
||||||
//#define CONFIG_CUSTOM_CFG3_VALUE
|
|
||||||
|
|
||||||
|
|
||||||
//#define CONFIG_VDDIO_LVD_LEVEL 4 ////VDDIO_LVD挡位,0: 1.9V 1: 2.0V 2: 2.1V 3: 2.2V 4: 2.3V 5: 2.4V 6: 2.5V 7: 2.6V
|
|
||||||
|
|
||||||
//with single-bank mode,actual vm size should larger this VM_LEAST_SIZE,and dual bank mode,actual vm size equals this;
|
|
||||||
#define CONFIG_VM_LEAST_SIZE 8K
|
|
||||||
//config whether erased this area when do a update,1-No Operation,0-Erase
|
|
||||||
#define CONFIG_VM_OPT 1
|
|
||||||
|
|
||||||
//config whether erased this area when do a update,1-No Operation,0-Erase
|
|
||||||
#define CONFIG_BTIF_OPT 1
|
|
||||||
|
|
||||||
//reserved two custom cfg area for the future definition
|
|
||||||
//#define CONFIG_RESERVED_AREA1 EXIF1
|
|
||||||
#ifdef CONFIG_RESERVED_AREA1
|
|
||||||
#define CONFIG_RESERVED_AREA1_ADDR AUTO
|
|
||||||
#define CONFIG_RESERVED_AREA1_LEN 0x1000
|
|
||||||
#define CONFIG_RESERVED_AREA1_OPT 1
|
|
||||||
//#define CONFIG_RESERVED_AREA1_FILE anc_gains.bin
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//#define CONFIG_RESERVED_AREA2 EXIF2
|
|
||||||
#ifdef CONFIG_RESERVED_AREA2
|
|
||||||
#define CONFIG_RESERVED_AREA2_ADDR AUTO
|
|
||||||
#define CONFIG_RESERVED_AREA2_LEN 0x1000
|
|
||||||
#define CONFIG_RESERVED_AREA2_OPT 1
|
|
||||||
//#define CONFIG_RESERVED_AREA2_FILE anc_gains.bin
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Above Macros Only For Post Bulid Configuaration */
|
|
||||||
#endif /* #ifdef CONFIG_BOARD_JL7018F_DEMO */
|
|
||||||
|
|
||||||
#endif /* #ifndef CONFIG_BOARD_JL7018F_DEMO_POST_BUILD_CFG_H */
|
|
||||||
|
|
||||||
@ -1,992 +0,0 @@
|
|||||||
#include "app_config.h"
|
|
||||||
|
|
||||||
#ifdef CONFIG_BOARD_JL701N_ANC
|
|
||||||
|
|
||||||
#include "system/includes.h"
|
|
||||||
#include "media/includes.h"
|
|
||||||
#include "asm/sdmmc.h"
|
|
||||||
#include "asm/chargestore.h"
|
|
||||||
#include "asm/umidigi_chargestore.h"
|
|
||||||
#include "asm/charge.h"
|
|
||||||
#include "asm/pwm_led.h"
|
|
||||||
#include "tone_player.h"
|
|
||||||
#include "audio_config.h"
|
|
||||||
#include "gSensor/gSensor_manage.h"
|
|
||||||
#include "key_event_deal.h"
|
|
||||||
#include "asm/lp_touch_key_api.h"
|
|
||||||
#include "user_cfg.h"
|
|
||||||
#include "norflash_sfc.h"
|
|
||||||
#include "asm/power/power_port.h"
|
|
||||||
#include "app_umidigi_chargestore.h"
|
|
||||||
#include "audio_link.h"
|
|
||||||
#if TCFG_AUDIO_ANC_ENABLE
|
|
||||||
#include "audio_anc.h"
|
|
||||||
#endif/*TCFG_AUDIO_ANC_ENABLE*/
|
|
||||||
|
|
||||||
#define LOG_TAG_CONST BOARD
|
|
||||||
#define LOG_TAG "[BOARD]"
|
|
||||||
#define LOG_ERROR_ENABLE
|
|
||||||
#define LOG_DEBUG_ENABLE
|
|
||||||
#define LOG_INFO_ENABLE
|
|
||||||
/* #define LOG_DUMP_ENABLE */
|
|
||||||
#define LOG_CLI_ENABLE
|
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
void board_power_init(void);
|
|
||||||
|
|
||||||
/*各个状态下默认的闪灯方式和提示音设置,如果USER_CFG中设置了USE_CONFIG_STATUS_SETTING为1,则会从配置文件读取对应的配置来填充改结构体*/
|
|
||||||
STATUS_CONFIG status_config = {
|
|
||||||
//灯状态设置
|
|
||||||
.led = {
|
|
||||||
.charge_start = PWM_LED1_ON,
|
|
||||||
.charge_full = PWM_LED0_ON,
|
|
||||||
.power_on = PWM_LED0_ON,
|
|
||||||
.power_off = PWM_LED1_FLASH_THREE,
|
|
||||||
.lowpower = PWM_LED1_SLOW_FLASH,
|
|
||||||
.max_vol = PWM_LED_NULL,
|
|
||||||
.phone_in = PWM_LED_NULL,
|
|
||||||
.phone_out = PWM_LED_NULL,
|
|
||||||
.phone_activ = PWM_LED_NULL,
|
|
||||||
.bt_init_ok = PWM_LED0_LED1_SLOW_FLASH,
|
|
||||||
.bt_connect_ok = PWM_LED0_ONE_FLASH_5S,
|
|
||||||
.bt_disconnect = PWM_LED0_LED1_FAST_FLASH,
|
|
||||||
.tws_connect_ok = PWM_LED0_LED1_FAST_FLASH,
|
|
||||||
.tws_disconnect = PWM_LED0_LED1_SLOW_FLASH,
|
|
||||||
},
|
|
||||||
//提示音设置
|
|
||||||
.tone = {
|
|
||||||
.charge_start = IDEX_TONE_NONE,
|
|
||||||
.charge_full = IDEX_TONE_NONE,
|
|
||||||
.power_on = IDEX_TONE_POWER_ON,
|
|
||||||
.power_off = IDEX_TONE_POWER_OFF,
|
|
||||||
.lowpower = IDEX_TONE_LOW_POWER,
|
|
||||||
.max_vol = IDEX_TONE_MAX_VOL,
|
|
||||||
.phone_in = IDEX_TONE_NONE,
|
|
||||||
.phone_out = IDEX_TONE_NONE,
|
|
||||||
.phone_activ = IDEX_TONE_NONE,
|
|
||||||
.bt_init_ok = IDEX_TONE_BT_MODE,
|
|
||||||
.bt_connect_ok = IDEX_TONE_BT_CONN,
|
|
||||||
.bt_disconnect = IDEX_TONE_BT_DISCONN,
|
|
||||||
.tws_connect_ok = IDEX_TONE_TWS_CONN,
|
|
||||||
.tws_disconnect = IDEX_TONE_TWS_DISCONN,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#define __this (&status_config)
|
|
||||||
|
|
||||||
/************************** KEY MSG****************************/
|
|
||||||
/*各个按键的消息设置,如果USER_CFG中设置了USE_CONFIG_KEY_SETTING为1,则会从配置文件读取对应的配置来填充改结构体*/
|
|
||||||
#if CLIENT_BOARD == CUSTOM10_CFG
|
|
||||||
u8 key_table[KEY_NUM_MAX][KEY_EVENT_MAX] = {
|
|
||||||
// SHORT LONG HOLD UP DOUBLE TRIPLE
|
|
||||||
{KEY_MUSIC_PP, KEY_NULL, KEY_NULL, KEY_NULL, KEY_ANC_SWITCH, KEY_NULL}, //KEY_0
|
|
||||||
{KEY_MUSIC_NEXT, KEY_VOL_UP, KEY_VOL_UP, KEY_NULL, KEY_OPEN_SIRI, KEY_NULL}, //KEY_1
|
|
||||||
{KEY_MUSIC_PREV, KEY_VOL_DOWN, KEY_VOL_DOWN, KEY_NULL, KEY_HID_CONTROL, KEY_NULL}, //KEY_2
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
u8 key_table[KEY_NUM_MAX][KEY_EVENT_MAX] = {
|
|
||||||
// SHORT LONG HOLD UP DOUBLE TRIPLE
|
|
||||||
{KEY_MUSIC_PP, KEY_ANC_SWITCH, KEY_NULL, KEY_NULL, KEY_CALL_LAST_NO, KEY_NULL}, //KEY_0
|
|
||||||
{KEY_MUSIC_NEXT, KEY_VOL_UP, KEY_VOL_UP, KEY_NULL, KEY_OPEN_SIRI, KEY_NULL}, //KEY_1
|
|
||||||
{KEY_MUSIC_PREV, KEY_VOL_DOWN, KEY_VOL_DOWN, KEY_NULL, KEY_HID_CONTROL, KEY_NULL}, //KEY_2
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// *INDENT-OFF*
|
|
||||||
/************************** UART config****************************/
|
|
||||||
#if TCFG_UART0_ENABLE
|
|
||||||
UART0_PLATFORM_DATA_BEGIN(uart0_data)
|
|
||||||
.tx_pin = TCFG_UART0_TX_PORT, //串口打印TX引脚选择
|
|
||||||
.rx_pin = TCFG_UART0_RX_PORT, //串口打印RX引脚选择
|
|
||||||
.baudrate = TCFG_UART0_BAUDRATE, //串口波特率
|
|
||||||
|
|
||||||
.flags = UART_DEBUG, //串口用来打印需要把改参数设置为UART_DEBUG
|
|
||||||
UART0_PLATFORM_DATA_END()
|
|
||||||
#endif //TCFG_UART0_ENABLE
|
|
||||||
|
|
||||||
/************************** CHARGE config****************************/
|
|
||||||
#if TCFG_CHARGE_ENABLE
|
|
||||||
CHARGE_PLATFORM_DATA_BEGIN(charge_data)
|
|
||||||
.charge_en = TCFG_CHARGE_ENABLE, //内置充电使能
|
|
||||||
.charge_poweron_en = TCFG_CHARGE_POWERON_ENABLE, //是否支持充电开机
|
|
||||||
.charge_full_V = TCFG_CHARGE_FULL_V, //充电截止电压
|
|
||||||
.charge_full_mA = TCFG_CHARGE_FULL_MA, //充电截止电流
|
|
||||||
.charge_mA = TCFG_CHARGE_MA, //恒流充电电流
|
|
||||||
.charge_trickle_mA = TCFG_CHARGE_TRICKLE_MA, //涓流充电电流
|
|
||||||
/*ldo5v拔出过滤值,过滤时间 = (filter*2 + 20)ms,ldoin<0.6V且时间大于过滤时间才认为拔出
|
|
||||||
对于充满直接从5V掉到0V的充电仓,该值必须设置成0,对于充满由5V先掉到0V之后再升压到xV的
|
|
||||||
充电仓,需要根据实际情况设置该值大小*/
|
|
||||||
.ldo5v_off_filter = 100,
|
|
||||||
.ldo5v_on_filter = 50,
|
|
||||||
.ldo5v_keep_filter = 220,
|
|
||||||
.ldo5v_pulldown_lvl = CHARGE_PULLDOWN_200K, //下拉电阻档位选择
|
|
||||||
.ldo5v_pulldown_keep = 0,
|
|
||||||
//1、对于自动升压充电舱,若充电舱需要更大的负载才能检测到插入时,请将该变量置1,并且根据需求配置下拉电阻档位
|
|
||||||
//2、对于按键升压,并且是通过上拉电阻去提供维持电压的舱,请将该变量设置1,并且根据舱的上拉配置下拉需要的电阻挡位
|
|
||||||
//3、对于常5V的舱,可将改变量设为0,省功耗
|
|
||||||
//4、为LDOIN防止被误触发唤醒,可设置为200k下拉
|
|
||||||
.ldo5v_pulldown_en = 1,
|
|
||||||
CHARGE_PLATFORM_DATA_END()
|
|
||||||
#endif//TCFG_CHARGE_ENABLE
|
|
||||||
|
|
||||||
/************************** chargestore config****************************/
|
|
||||||
#if TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE
|
|
||||||
CHARGESTORE_PLATFORM_DATA_BEGIN(chargestore_data)
|
|
||||||
.io_port = TCFG_CHARGESTORE_PORT,
|
|
||||||
CHARGESTORE_PLATFORM_DATA_END()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/************************** DAC ****************************/
|
|
||||||
#if TCFG_AUDIO_DAC_ENABLE
|
|
||||||
struct dac_platform_data dac_data = {
|
|
||||||
.mode = TCFG_AUDIO_DAC_MODE, //dac输出模式
|
|
||||||
.ldo_id = TCFG_AUDIO_DAC_LDO_SEL, //保留位
|
|
||||||
.pa_mute_port = TCFG_AUDIO_DAC_PA_PORT, //暂时无作用
|
|
||||||
.vcmo_en = 0, //是否打开VCOMO
|
|
||||||
.pa_mute_value = 1, //暂时无作用
|
|
||||||
.output = TCFG_AUDIO_DAC_CONNECT_MODE, //DAC输出配置,和具体硬件连接有关,需根据硬件来设置
|
|
||||||
.lpf_isel = 0xf,
|
|
||||||
.sys_vol_type = SYS_VOL_TYPE, //系统音量选择:模拟音量/数字音量,调节时调节对应的音量
|
|
||||||
.max_ana_vol = MAX_ANA_VOL, //模拟音量最大等级
|
|
||||||
.max_dig_vol = MAX_DIG_VOL, //数字音量最大等级
|
|
||||||
/* .dig_vol_tab = (s16 *)dig_vol_table, //数字音量表 */
|
|
||||||
.vcm_cap_en = 1, //配1代表走外部通路,vcm上有电容时,可以提升电路抑制电源噪声能力,提高ADC的性能,配0相当于vcm上无电容,抑制电源噪声能力下降,ADC性能下降
|
|
||||||
#if (SYS_VOL_TYPE == VOL_TYPE_AD)
|
|
||||||
.digital_gain_limit = 16384,
|
|
||||||
#endif // #if (SYS_VOL_TYPE == VOL_TYPE_AD)
|
|
||||||
|
|
||||||
.power_on_mode = 0,
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/************************** ADC ****************************/
|
|
||||||
#if TCFG_AUDIO_ADC_ENABLE
|
|
||||||
#ifndef TCFG_AUDIO_MIC0_BIAS_EN
|
|
||||||
#define TCFG_AUDIO_MIC0_BIAS_EN 0
|
|
||||||
#endif/*TCFG_AUDIO_MIC0_BIAS_EN*/
|
|
||||||
#ifndef TCFG_AUDIO_MIC1_BIAS_EN
|
|
||||||
#define TCFG_AUDIO_MIC1_BIAS_EN 0
|
|
||||||
#endif/*TCFG_AUDIO_MIC1_BIAS_EN*/
|
|
||||||
#ifndef TCFG_AUDIO_MIC2_BIAS_EN
|
|
||||||
#define TCFG_AUDIO_MIC2_BIAS_EN 0
|
|
||||||
#endif/*TCFG_AUDIO_MIC2_BIAS_EN*/
|
|
||||||
#ifndef TCFG_AUDIO_MIC3_BIAS_EN
|
|
||||||
#define TCFG_AUDIO_MIC3_BIAS_EN 0
|
|
||||||
#endif/*TCFG_AUDIO_MIC3_BIAS_EN*/
|
|
||||||
#ifndef TCFG_AUDIO_MIC_LDO_EN
|
|
||||||
#define TCFG_AUDIO_MIC_LDO_EN 0
|
|
||||||
#endif/*TCFG_AUDIO_MIC_LDO_EN*/
|
|
||||||
|
|
||||||
struct adc_platform_data adc_data = {
|
|
||||||
|
|
||||||
/*MIC LDO电流档位设置:
|
|
||||||
0:0.625ua 1:1.25ua 2:1.875ua 3:2.5ua*/
|
|
||||||
.mic_ldo_isel = TCFG_AUDIO_ADC_LD0_SEL,
|
|
||||||
|
|
||||||
/*mic_mode 工作模式定义
|
|
||||||
#define AUDIO_MIC_CAP_MODE 0 //单端隔直电容模式
|
|
||||||
#define AUDIO_MIC_CAP_DIFF_MODE 1 //差分隔直电容模式
|
|
||||||
#define AUDIO_MIC_CAPLESS_MODE 2 //单端省电容模式
|
|
||||||
*/
|
|
||||||
.mic_mode = TCFG_AUDIO_MIC_MODE,
|
|
||||||
.mic1_mode = TCFG_AUDIO_MIC1_MODE,
|
|
||||||
.mic2_mode = TCFG_AUDIO_MIC2_MODE,
|
|
||||||
.mic3_mode = TCFG_AUDIO_MIC3_MODE,
|
|
||||||
|
|
||||||
.mic_bias_inside = TCFG_AUDIO_MIC0_BIAS_EN,
|
|
||||||
.mic1_bias_inside = TCFG_AUDIO_MIC1_BIAS_EN,
|
|
||||||
.mic2_bias_inside = TCFG_AUDIO_MIC2_BIAS_EN,
|
|
||||||
.mic3_bias_inside = TCFG_AUDIO_MIC3_BIAS_EN,
|
|
||||||
|
|
||||||
/*MICLDO供电输出到PAD(PA0)控制使能*/
|
|
||||||
.mic_ldo_pwr = TCFG_AUDIO_MIC_LDO_EN, // MIC LDO 输出到 PA0
|
|
||||||
|
|
||||||
/*MIC免电容方案需要设置,影响MIC的偏置电压
|
|
||||||
0b0001~0b1001 : 0.5k ~ 4.5k step = 0.5k
|
|
||||||
0b1010~0b1111 : 5k ~ 10k step = 1k */
|
|
||||||
.mic_bias_res = 4,
|
|
||||||
.mic1_bias_res = 4,
|
|
||||||
.mic2_bias_res = 4,
|
|
||||||
.mic3_bias_res = 4,
|
|
||||||
/*MIC LDO电压档位设置,也会影响MIC的偏置电压
|
|
||||||
3:2.0v 4:2.2v 5:2.4v 6:2.6v 7:2.8v */
|
|
||||||
.mic_ldo_vsel = 5,
|
|
||||||
//mic的去直流dcc寄存器配置值,可配0到15,数值越大,其高通转折点越低
|
|
||||||
.mic_dcc = 8,
|
|
||||||
/*ADC低功耗等级,越大功耗越低,对应影响THD和底噪, 范围 (0 - 2)*/
|
|
||||||
.lowpower_lvl = 0,
|
|
||||||
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const struct vad_mic_platform_data vad_mic_data = {
|
|
||||||
.mic_data = { //
|
|
||||||
.mic_mode = TCFG_AUDIO_MIC_MODE,
|
|
||||||
.mic_ldo_isel = 2,
|
|
||||||
.mic_ldo_vsel = 5,
|
|
||||||
.mic_ldo2PAD_en = 1,
|
|
||||||
.mic_bias_en = 0,
|
|
||||||
.mic_bias_res = 0,
|
|
||||||
.mic_bias_inside = TCFG_AUDIO_MIC0_BIAS_EN,
|
|
||||||
/* ADC偏置电阻配置*/
|
|
||||||
.adc_rbs = 3,
|
|
||||||
/* ADC输入电阻配置*/
|
|
||||||
.adc_rin = 3,
|
|
||||||
/*.adc_test = 1,*/
|
|
||||||
},
|
|
||||||
.power_data = {
|
|
||||||
/*VADLDO电压档位:0~7*/
|
|
||||||
.ldo_vs = 3,
|
|
||||||
/*VADLDO误差运放电流档位:0~3*/
|
|
||||||
#if TCFG_VAD_LOWPOWER_CLOCK == VAD_CLOCK_USE_PMU_STD12M
|
|
||||||
.ldo_is = 1,
|
|
||||||
#else
|
|
||||||
.ldo_is = 2,
|
|
||||||
#endif
|
|
||||||
.clock = TCFG_VAD_LOWPOWER_CLOCK, /*VAD时钟选项*/
|
|
||||||
.acm_select = 8,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
/* struct audio_pf_data audio_pf_d = { */
|
|
||||||
/* #if TCFG_AUDIO_DAC_ENABLE */
|
|
||||||
/* .adc_pf_data = &adc_data, */
|
|
||||||
/* #endif */
|
|
||||||
|
|
||||||
/* #if TCFG_AUDIO_ADC_ENABLE */
|
|
||||||
/* .dac_pf_data = &dac_data, */
|
|
||||||
/* #endif */
|
|
||||||
/* }; */
|
|
||||||
|
|
||||||
/* struct audio_platform_data audio_data = { */
|
|
||||||
/* .private_data = (void *) &audio_pf_d, */
|
|
||||||
/* }; */
|
|
||||||
|
|
||||||
|
|
||||||
/************************** IO KEY ****************************/
|
|
||||||
#if TCFG_IOKEY_ENABLE
|
|
||||||
const struct iokey_port iokey_list[] = {
|
|
||||||
|
|
||||||
{
|
|
||||||
.connect_way = TCFG_IOKEY_POWER_CONNECT_WAY, //IO按键的连接方式
|
|
||||||
.key_type.one_io.port = TCFG_IOKEY_POWER_ONE_PORT, //IO按键对应的引脚
|
|
||||||
.key_value = 0, //按键值
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const struct iokey_platform_data iokey_data = {
|
|
||||||
.enable = TCFG_IOKEY_ENABLE, //是否使能IO按键
|
|
||||||
.num = ARRAY_SIZE(iokey_list), //IO按键的个数
|
|
||||||
.port = iokey_list, //IO按键参数表
|
|
||||||
};
|
|
||||||
|
|
||||||
#if MULT_KEY_ENABLE
|
|
||||||
//组合按键消息映射表
|
|
||||||
//配置注意事项:单个按键按键值需要按照顺序编号,如power:0, prev:1, next:2
|
|
||||||
//bit_value = BIT(0) | BIT(1) 指按键值为0和按键值为1的两个按键被同时按下,
|
|
||||||
//remap_value = 3指当这两个按键被同时按下后重新映射的按键值;
|
|
||||||
const struct key_remap iokey_remap_table[] = {
|
|
||||||
{.bit_value = BIT(0) | BIT(1), .remap_value = 3},
|
|
||||||
{.bit_value = BIT(0) | BIT(2), .remap_value = 4},
|
|
||||||
{.bit_value = BIT(1) | BIT(2), .remap_value = 5},
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct key_remap_data iokey_remap_data = {
|
|
||||||
.remap_num = ARRAY_SIZE(iokey_remap_table),
|
|
||||||
.table = iokey_remap_table,
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
/*********************** LP TOUCH KEY ****************************/
|
|
||||||
#if TCFG_LP_TOUCH_KEY_ENABLE
|
|
||||||
const struct lp_touch_key_platform_data lp_touch_key_config = {
|
|
||||||
/*触摸按键*/
|
|
||||||
.ch[0].enable = TCFG_LP_TOUCH_KEY0_EN,
|
|
||||||
.ch[0].wakeup_enable = TCFG_LP_TOUCH_KEY0_WAKEUP_EN,
|
|
||||||
.ch[0].port = IO_PORTB_00,
|
|
||||||
.ch[0].sensitivity = TCFG_LP_TOUCH_KEY0_SENSITIVITY,
|
|
||||||
.ch[0].key_value = 0,
|
|
||||||
|
|
||||||
.ch[1].enable = TCFG_LP_TOUCH_KEY1_EN,
|
|
||||||
.ch[1].wakeup_enable = TCFG_LP_TOUCH_KEY1_WAKEUP_EN,
|
|
||||||
.ch[1].port = IO_PORTB_01,
|
|
||||||
.ch[1].sensitivity = TCFG_LP_TOUCH_KEY1_SENSITIVITY,
|
|
||||||
.ch[1].key_value = 0,
|
|
||||||
|
|
||||||
.ch[2].enable = TCFG_LP_TOUCH_KEY2_EN,
|
|
||||||
.ch[2].wakeup_enable = TCFG_LP_TOUCH_KEY2_WAKEUP_EN,
|
|
||||||
.ch[2].port = IO_PORTB_02,
|
|
||||||
.ch[2].sensitivity = TCFG_LP_TOUCH_KEY2_SENSITIVITY,
|
|
||||||
.ch[2].key_value = 1,
|
|
||||||
|
|
||||||
.ch[3].enable = TCFG_LP_TOUCH_KEY3_EN,
|
|
||||||
.ch[3].wakeup_enable = TCFG_LP_TOUCH_KEY3_WAKEUP_EN,
|
|
||||||
.ch[3].port = IO_PORTB_04,
|
|
||||||
.ch[3].sensitivity = TCFG_LP_TOUCH_KEY3_SENSITIVITY,
|
|
||||||
.ch[3].key_value = 2,
|
|
||||||
|
|
||||||
.ch[4].enable = TCFG_LP_TOUCH_KEY4_EN,
|
|
||||||
.ch[4].wakeup_enable = TCFG_LP_TOUCH_KEY4_WAKEUP_EN,
|
|
||||||
.ch[4].port = IO_PORTB_05,
|
|
||||||
.ch[4].sensitivity = TCFG_LP_TOUCH_KEY4_SENSITIVITY,
|
|
||||||
.ch[4].key_value = 3,
|
|
||||||
|
|
||||||
//把触摸按键之间的滑动也当做按键处理,有上滑,下滑,左滑,右滑
|
|
||||||
.slide_mode_en = TCFG_LP_SLIDE_KEY_ENABLE,
|
|
||||||
.slide_mode_key_value = 3,
|
|
||||||
|
|
||||||
//入耳检测相关的配置
|
|
||||||
.eartch_en = TCFG_LP_EARTCH_KEY_ENABLE,
|
|
||||||
.eartch_ch = TCFG_LP_EARTCH_KEY_CH,
|
|
||||||
.eartch_ref_ch = TCFG_LP_EARTCH_KEY_REF_CH,
|
|
||||||
.eartch_soft_inear_val = TCFG_LP_EARTCH_SOFT_INEAR_VAL,
|
|
||||||
.eartch_soft_outear_val = TCFG_LP_EARTCH_SOFT_OUTEAR_VAL,
|
|
||||||
};
|
|
||||||
#endif /* #if TCFG_LP_TOUCH_KEY_ENABLE */
|
|
||||||
|
|
||||||
/************************** PLCNT TOUCH_KEY ****************************/
|
|
||||||
#if TCFG_TOUCH_KEY_ENABLE
|
|
||||||
const const struct touch_key_port touch_key_list[] = {
|
|
||||||
{
|
|
||||||
.press_delta = TCFG_TOUCH_KEY0_PRESS_DELTA,
|
|
||||||
.port = TCFG_TOUCH_KEY0_PORT,
|
|
||||||
.key_value = TCFG_TOUCH_KEY0_VALUE,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.press_delta = TCFG_TOUCH_KEY1_PRESS_DELTA,
|
|
||||||
.port = TCFG_TOUCH_KEY1_PORT,
|
|
||||||
.key_value = TCFG_TOUCH_KEY1_VALUE,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct touch_key_platform_data touch_key_data = {
|
|
||||||
.num = ARRAY_SIZE(touch_key_list),
|
|
||||||
.port_list = touch_key_list,
|
|
||||||
};
|
|
||||||
#endif /* #if TCFG_TOUCH_KEY_ENABLE */
|
|
||||||
|
|
||||||
/************************** AD KEY ****************************/
|
|
||||||
#if TCFG_ADKEY_ENABLE
|
|
||||||
const struct adkey_platform_data adkey_data = {
|
|
||||||
.enable = TCFG_ADKEY_ENABLE, //AD按键使能
|
|
||||||
.adkey_pin = TCFG_ADKEY_PORT, //AD按键对应引脚
|
|
||||||
.ad_channel = TCFG_ADKEY_AD_CHANNEL, //AD通道值
|
|
||||||
.extern_up_en = TCFG_ADKEY_EXTERN_UP_ENABLE, //是否使用外接上拉电阻
|
|
||||||
.ad_value = { //根据电阻算出来的电压值
|
|
||||||
TCFG_ADKEY_VOLTAGE0,
|
|
||||||
TCFG_ADKEY_VOLTAGE1,
|
|
||||||
TCFG_ADKEY_VOLTAGE2,
|
|
||||||
TCFG_ADKEY_VOLTAGE3,
|
|
||||||
TCFG_ADKEY_VOLTAGE4,
|
|
||||||
TCFG_ADKEY_VOLTAGE5,
|
|
||||||
TCFG_ADKEY_VOLTAGE6,
|
|
||||||
TCFG_ADKEY_VOLTAGE7,
|
|
||||||
TCFG_ADKEY_VOLTAGE8,
|
|
||||||
TCFG_ADKEY_VOLTAGE9,
|
|
||||||
},
|
|
||||||
.key_value = { //AD按键各个按键的键值
|
|
||||||
TCFG_ADKEY_VALUE0,
|
|
||||||
TCFG_ADKEY_VALUE1,
|
|
||||||
TCFG_ADKEY_VALUE2,
|
|
||||||
TCFG_ADKEY_VALUE3,
|
|
||||||
TCFG_ADKEY_VALUE4,
|
|
||||||
TCFG_ADKEY_VALUE5,
|
|
||||||
TCFG_ADKEY_VALUE6,
|
|
||||||
TCFG_ADKEY_VALUE7,
|
|
||||||
TCFG_ADKEY_VALUE8,
|
|
||||||
TCFG_ADKEY_VALUE9,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/************************** RDEC_KEY ****************************/
|
|
||||||
#if TCFG_RDEC_KEY_ENABLE
|
|
||||||
const struct rdec_device rdeckey_list[] = {
|
|
||||||
{
|
|
||||||
.index = RDEC0 ,
|
|
||||||
.sin_port0 = TCFG_RDEC0_ECODE1_PORT,
|
|
||||||
.sin_port1 = TCFG_RDEC0_ECODE2_PORT,
|
|
||||||
.key_value0 = TCFG_RDEC0_KEY0_VALUE | BIT(7),
|
|
||||||
.key_value1 = TCFG_RDEC0_KEY1_VALUE | BIT(7),
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
.index = RDEC1 ,
|
|
||||||
.sin_port0 = TCFG_RDEC1_ECODE1_PORT,
|
|
||||||
.sin_port1 = TCFG_RDEC1_ECODE2_PORT,
|
|
||||||
.key_value0 = TCFG_RDEC1_KEY0_VALUE | BIT(7),
|
|
||||||
.key_value1 = TCFG_RDEC1_KEY1_VALUE | BIT(7),
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
.index = RDEC2 ,
|
|
||||||
.sin_port0 = TCFG_RDEC2_ECODE1_PORT,
|
|
||||||
.sin_port1 = TCFG_RDEC2_ECODE2_PORT,
|
|
||||||
.key_value0 = TCFG_RDEC2_KEY0_VALUE | BIT(7),
|
|
||||||
.key_value1 = TCFG_RDEC2_KEY1_VALUE | BIT(7),
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
const struct rdec_platform_data rdec_key_data = {
|
|
||||||
.enable = 1, //TCFG_RDEC_KEY_ENABLE, //是否使能RDEC按键
|
|
||||||
.num = ARRAY_SIZE(rdeckey_list), //RDEC按键的个数
|
|
||||||
.rdec = rdeckey_list, //RDEC按键参数表
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/************************** IIS config ****************************/
|
|
||||||
#if (TCFG_AUDIO_INPUT_IIS || TCFG_AUDIO_OUTPUT_IIS)
|
|
||||||
ALINK_PARM alink0_platform_data = {
|
|
||||||
.module = ALINK0,
|
|
||||||
.mclk_io = TCFG_IIS_MCLK_IO,
|
|
||||||
.sclk_io = TCFG_SCLK_IO,
|
|
||||||
.lrclk_io = TCFG_LRCLK_IO,
|
|
||||||
.ch_cfg[0].data_io = TCFG_DATA0_IO,
|
|
||||||
.ch_cfg[1].data_io = TCFG_DATA1_IO,
|
|
||||||
.ch_cfg[2].data_io = TCFG_DATA2_IO,
|
|
||||||
.ch_cfg[3].data_io = TCFG_DATA3_IO,
|
|
||||||
.mode = ALINK_MD_IIS,
|
|
||||||
#if TCFG_IIS_MODE
|
|
||||||
.role = ALINK_ROLE_SLAVE,
|
|
||||||
#else
|
|
||||||
.role = ALINK_ROLE_MASTER,
|
|
||||||
#endif /*TCFG_IIS_MODE*/
|
|
||||||
.clk_mode = ALINK_CLK_FALL_UPDATE_RAISE_SAMPLE,
|
|
||||||
.bitwide = ALINK_LEN_16BIT,
|
|
||||||
.sclk_per_frame = ALINK_FRAME_32SCLK,
|
|
||||||
.dma_len = 4 * 1024,
|
|
||||||
.sample_rate = TCFG_IIS_SR,
|
|
||||||
.buf_mode = ALINK_BUF_CIRCLE,
|
|
||||||
/*.iperiod = 64, //配置该项可以控制输入的延时*/
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/************************** PWM_LED ****************************/
|
|
||||||
#if TCFG_PWMLED_ENABLE
|
|
||||||
LED_PLATFORM_DATA_BEGIN(pwm_led_data)
|
|
||||||
.io_mode = TCFG_PWMLED_IOMODE, //推灯模式设置:支持单个IO推两个灯和两个IO推两个灯
|
|
||||||
.io_cfg.one_io.pin = TCFG_PWMLED_PIN, //单个IO推两个灯的IO口配置
|
|
||||||
LED_PLATFORM_DATA_END()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const struct soft_iic_config soft_iic_cfg[] = {
|
|
||||||
#if 0
|
|
||||||
//iic0 data
|
|
||||||
{
|
|
||||||
.scl = TCFG_SW_I2C0_CLK_PORT, //IIC CLK脚
|
|
||||||
.sda = TCFG_SW_I2C0_DAT_PORT, //IIC DAT脚
|
|
||||||
.delay = TCFG_SW_I2C0_DELAY_CNT, //软件IIC延时参数,影响通讯时钟频率
|
|
||||||
.io_pu = 1, //是否打开上拉电阻,如果外部电路没有焊接上拉电阻需要置1
|
|
||||||
},
|
|
||||||
#endif
|
|
||||||
#if 0
|
|
||||||
//iic1 data
|
|
||||||
{
|
|
||||||
.scl = IO_PORTA_05,
|
|
||||||
.sda = IO_PORTA_06,
|
|
||||||
.delay = 50,
|
|
||||||
.io_pu = 1,
|
|
||||||
},
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const struct hw_iic_config hw_iic_cfg[] = {
|
|
||||||
#if 0
|
|
||||||
//iic0 data
|
|
||||||
{
|
|
||||||
/*硬件IIC端口下选择
|
|
||||||
SCL SDA
|
|
||||||
{IO_PORT_DP, IO_PORT_DM}, //group a
|
|
||||||
{IO_PORTC_04, IO_PORTC_05}, //group b
|
|
||||||
{IO_PORTC_02, IO_PORTC_03}, //group c
|
|
||||||
{IO_PORTA_05, IO_PORTA_06}, //group d
|
|
||||||
*/
|
|
||||||
.port = TCFG_HW_I2C0_PORTS,
|
|
||||||
.baudrate = TCFG_HW_I2C0_CLK, //IIC通讯波特率
|
|
||||||
.hdrive = 0, //是否打开IO口强驱
|
|
||||||
.io_filter = 1, //是否打开滤波器(去纹波)
|
|
||||||
.io_pu = 1, //是否打开上拉电阻,如果外部电路没有焊接上拉电阻需要置1
|
|
||||||
},
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#if TCFG_SD0_ENABLE
|
|
||||||
SD0_PLATFORM_DATA_BEGIN(sd0_data)
|
|
||||||
.port = {
|
|
||||||
TCFG_SD0_PORT_CMD,
|
|
||||||
TCFG_SD0_PORT_CLK,
|
|
||||||
TCFG_SD0_PORT_DA0,
|
|
||||||
TCFG_SD0_PORT_DA1,
|
|
||||||
TCFG_SD0_PORT_DA2,
|
|
||||||
TCFG_SD0_PORT_DA3,
|
|
||||||
},
|
|
||||||
.data_width = TCFG_SD0_DAT_MODE,
|
|
||||||
.speed = TCFG_SD0_CLK,
|
|
||||||
.detect_mode = TCFG_SD0_DET_MODE,
|
|
||||||
.priority = 3,
|
|
||||||
|
|
||||||
#if (TCFG_SD0_DET_MODE == SD_IO_DECT)
|
|
||||||
.detect_io = TCFG_SD0_DET_IO,
|
|
||||||
.detect_io_level = TCFG_SD0_DET_IO_LEVEL,
|
|
||||||
.detect_func = sdmmc_0_io_detect,
|
|
||||||
.power = sd_set_power,
|
|
||||||
/* .power = NULL, */
|
|
||||||
#elif (TCFG_SD0_DET_MODE == SD_CLK_DECT)
|
|
||||||
.detect_io_level = TCFG_SD0_DET_IO_LEVEL,
|
|
||||||
.detect_func = sdmmc_0_clk_detect,
|
|
||||||
.power = sd_set_power,
|
|
||||||
/* .power = NULL, */
|
|
||||||
#else
|
|
||||||
.detect_func = sdmmc_cmd_detect,
|
|
||||||
.power = NULL,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SD0_PLATFORM_DATA_END()
|
|
||||||
#endif /* #if TCFG_SD0_ENABLE */
|
|
||||||
|
|
||||||
REGISTER_DEVICES(device_table) = {
|
|
||||||
/* { "audio", &audio_dev_ops, (void *) &audio_data }, */
|
|
||||||
|
|
||||||
#if TCFG_CHARGE_ENABLE
|
|
||||||
{ "charge", &charge_dev_ops, (void *)&charge_data },
|
|
||||||
#endif
|
|
||||||
#if TCFG_SD0_ENABLE
|
|
||||||
{ "sd0", &sd_dev_ops, (void *) &sd0_data},
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/************************** power_param ****************************/
|
|
||||||
const struct low_power_param power_param = {
|
|
||||||
.config = TCFG_LOWPOWER_LOWPOWER_SEL, //低功耗使能,蓝牙&&系统空闲可进入低功耗
|
|
||||||
.btosc_hz = TCFG_CLOCK_OSC_HZ, //蓝牙晶振频率
|
|
||||||
.delay_us = TCFG_CLOCK_SYS_HZ / 1000000L, //提供给低功耗模块的延时(不需要需修改)
|
|
||||||
.vddiom_lev = TCFG_LOWPOWER_VDDIOM_LEVEL, //vddiom等级
|
|
||||||
.osc_type = TCFG_LOWPOWER_OSC_TYPE, //低功耗晶振类型,btosc/lrc
|
|
||||||
#if (TCFG_LOWPOWER_RAM_SIZE)
|
|
||||||
.mem_init_con = MEM_PWR_RAM_SET(TCFG_LOWPOWER_RAM_SIZE),
|
|
||||||
#else
|
|
||||||
.mem_init_con = 0,
|
|
||||||
#endif
|
|
||||||
#if (TCFG_LP_TOUCH_KEY_ENABLE && \
|
|
||||||
(TCFG_LP_TOUCH_KEY0_WAKEUP_EN || \
|
|
||||||
TCFG_LP_TOUCH_KEY1_WAKEUP_EN || \
|
|
||||||
TCFG_LP_TOUCH_KEY2_WAKEUP_EN || \
|
|
||||||
TCFG_LP_TOUCH_KEY3_WAKEUP_EN || \
|
|
||||||
TCFG_LP_TOUCH_KEY4_WAKEUP_EN ))
|
|
||||||
.lpctmu_en = 1,
|
|
||||||
#else
|
|
||||||
.lpctmu_en = 0,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/************************** wk_param ****************************/
|
|
||||||
struct port_wakeup port0 = {
|
|
||||||
.pullup_down_enable = ENABLE, //配置I/O 内部上下拉是否使能
|
|
||||||
.edge = FALLING_EDGE, //唤醒方式选择,可选:上升沿\下降沿
|
|
||||||
.filter = PORT_FLT_8ms,
|
|
||||||
.iomap = TCFG_IOKEY_POWER_ONE_PORT, //唤醒口选择
|
|
||||||
};
|
|
||||||
|
|
||||||
#if (TCFG_TEST_BOX_ENABLE || TCFG_CHARGESTORE_ENABLE || TCFG_ANC_BOX_ENABLE || TCFG_UMIDIGI_BOX_ENABLE)
|
|
||||||
struct port_wakeup port1 = {
|
|
||||||
.pullup_down_enable = DISABLE, //配置I/O 内部上下拉是否使能
|
|
||||||
.edge = FALLING_EDGE, //唤醒方式选择,可选:上升沿\下降沿
|
|
||||||
.filter = PORT_FLT_1ms,
|
|
||||||
.iomap = TCFG_CHARGESTORE_PORT, //唤醒口选择
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if TCFG_CHARGE_ENABLE
|
|
||||||
struct port_wakeup charge_port = {
|
|
||||||
.edge = RISING_EDGE, //唤醒方式选择,可选:上升沿\下降沿\双边沿
|
|
||||||
.filter = PORT_FLT_16ms,
|
|
||||||
.iomap = IO_CHGFL_DET, //唤醒口选择
|
|
||||||
};
|
|
||||||
|
|
||||||
struct port_wakeup vbat_port = {
|
|
||||||
.edge = BOTH_EDGE, //唤醒方式选择,可选:上升沿\下降沿\双边沿
|
|
||||||
.filter = PORT_FLT_16ms,
|
|
||||||
.iomap = IO_VBTCH_DET, //唤醒口选择
|
|
||||||
};
|
|
||||||
|
|
||||||
struct port_wakeup ldoin_port = {
|
|
||||||
.edge = BOTH_EDGE, //唤醒方式选择,可选:上升沿\下降沿\双边沿
|
|
||||||
.filter = PORT_FLT_16ms,
|
|
||||||
.iomap = IO_LDOIN_DET, //唤醒口选择
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const struct wakeup_param wk_param = {
|
|
||||||
#if (!(TCFG_LP_TOUCH_KEY_ENABLE && TCFG_LP_TOUCH_KEY1_EN))
|
|
||||||
.port[1] = &port0,
|
|
||||||
#endif
|
|
||||||
#if (TCFG_TEST_BOX_ENABLE || TCFG_CHARGESTORE_ENABLE || TCFG_ANC_BOX_ENABLE || TCFG_UMIDIGI_BOX_ENABLE)
|
|
||||||
.port[2] = &port1,
|
|
||||||
#endif
|
|
||||||
#if TCFG_CHARGE_ENABLE
|
|
||||||
.aport[0] = &charge_port,
|
|
||||||
.aport[1] = &vbat_port,
|
|
||||||
.aport[2] = &ldoin_port,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
void gSensor_wkupup_disable(void)
|
|
||||||
{
|
|
||||||
log_info("gSensor wkup disable\n");
|
|
||||||
power_wakeup_index_enable(1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void gSensor_wkupup_enable(void)
|
|
||||||
{
|
|
||||||
log_info("gSensor wkup enable\n");
|
|
||||||
power_wakeup_index_enable(1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void debug_uart_init(const struct uart_platform_data *data)
|
|
||||||
{
|
|
||||||
#if TCFG_UART0_ENABLE
|
|
||||||
if (data) {
|
|
||||||
uart_init(data);
|
|
||||||
} else {
|
|
||||||
uart_init(&uart0_data);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
STATUS *get_led_config(void)
|
|
||||||
{
|
|
||||||
return &(__this->led);
|
|
||||||
}
|
|
||||||
|
|
||||||
STATUS *get_tone_config(void)
|
|
||||||
{
|
|
||||||
return &(__this->tone);
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 get_sys_default_vol(void)
|
|
||||||
{
|
|
||||||
return 21;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 get_power_on_status(void)
|
|
||||||
{
|
|
||||||
#if TCFG_IOKEY_ENABLE
|
|
||||||
struct iokey_port *power_io_list = NULL;
|
|
||||||
power_io_list = iokey_data.port;
|
|
||||||
|
|
||||||
if (iokey_data.enable) {
|
|
||||||
if (gpio_read(power_io_list->key_type.one_io.port) == power_io_list->connect_way){
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if TCFG_ADKEY_ENABLE
|
|
||||||
if (adkey_data.enable) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if TCFG_LP_TOUCH_KEY_ENABLE
|
|
||||||
return lp_touch_key_power_on_status();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void board_devices_init(void)
|
|
||||||
{
|
|
||||||
#if TCFG_PWMLED_ENABLE
|
|
||||||
pwm_led_init(&pwm_led_data);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (TCFG_IOKEY_ENABLE || TCFG_ADKEY_ENABLE || TCFG_RDEC_KEY_ENABLE || TCFG_TOUCH_KEY_ENABLE)
|
|
||||||
key_driver_init();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if TCFG_UART_KEY_ENABLE
|
|
||||||
extern int uart_key_init(void);
|
|
||||||
uart_key_init();
|
|
||||||
#endif /* #if TCFG_UART_KEY_ENABLE */
|
|
||||||
|
|
||||||
#if TCFG_LP_TOUCH_KEY_ENABLE
|
|
||||||
lp_touch_key_init(&lp_touch_key_config);
|
|
||||||
#endif /* #if TCFG_LP_TOUCH_KEY_ENABLE */
|
|
||||||
|
|
||||||
#if (!TCFG_CHARGE_ENABLE)
|
|
||||||
CHARGE_EN(0);
|
|
||||||
CHGGO_EN(0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE
|
|
||||||
chargestore_api_init(&chargestore_data);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//外置触摸电源控制 1:输出高 0:输出地
|
|
||||||
static void pwr_set_external_touch(u8 high_low)
|
|
||||||
{
|
|
||||||
if(TCFG_EXTERNAL_TOUCH_KEY_POWER_PORT == NO_CONFIG_PORT){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
gpio_set_pull_up(TCFG_EXTERNAL_TOUCH_KEY_POWER_PORT, 1);
|
|
||||||
gpio_set_pull_down(TCFG_EXTERNAL_TOUCH_KEY_POWER_PORT, 0);
|
|
||||||
gpio_set_direction(TCFG_EXTERNAL_TOUCH_KEY_POWER_PORT, 0);
|
|
||||||
gpio_set_output_value(TCFG_EXTERNAL_TOUCH_KEY_POWER_PORT, high_low);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CLIENT_BOARD == CUSTOM9_CFG
|
|
||||||
#define TCFG_TALKING_FB_MIC_IO IO_PORTB_02
|
|
||||||
/*
|
|
||||||
0:MIC0 作为FB MIC,引脚输出低电平。
|
|
||||||
1:MIC0 作为通话MIC,引脚输出高电平。
|
|
||||||
*/
|
|
||||||
void TALKING_FB_MIC_sel(u8 mic_type)
|
|
||||||
{
|
|
||||||
gpio_set_pull_up(TCFG_TALKING_FB_MIC_IO , 0);
|
|
||||||
gpio_set_pull_down(TCFG_TALKING_FB_MIC_IO , 0);
|
|
||||||
gpio_set_direction(TCFG_TALKING_FB_MIC_IO , 0);
|
|
||||||
gpio_set_die(TCFG_TALKING_FB_MIC_IO , 1);
|
|
||||||
switch (mic_type)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
gpio_set_output_value(TCFG_TALKING_FB_MIC_IO , 0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
gpio_set_output_value(TCFG_TALKING_FB_MIC_IO , 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static u8 dcda_en_state = 0;
|
|
||||||
#define DCDC_EN_PORT IO_PORTC_02
|
|
||||||
static void dcdc_en(u8 en)
|
|
||||||
{
|
|
||||||
if (dcda_en_state == en)
|
|
||||||
{
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
dcda_en_state = en;
|
|
||||||
|
|
||||||
gpio_set_die(DCDC_EN_PORT, 0);
|
|
||||||
gpio_set_direction(IO_PORTB_04, 0);
|
|
||||||
gpio_set_pull_up(DCDC_EN_PORT, 0);
|
|
||||||
gpio_set_pull_down(DCDC_EN_PORT, 0);
|
|
||||||
|
|
||||||
switch (en)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
printf("external dcdc disable \n");
|
|
||||||
gpio_direction_output(DCDC_EN_PORT, 0);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
printf("external dcdc enable \n");
|
|
||||||
gpio_direction_output(DCDC_EN_PORT, 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dcdc_init(void)
|
|
||||||
{
|
|
||||||
gpio_set_die(DCDC_EN_PORT, 0);
|
|
||||||
gpio_set_direction(IO_PORTB_04, 0);
|
|
||||||
gpio_set_pull_up(DCDC_EN_PORT, 0);
|
|
||||||
gpio_set_pull_down(DCDC_EN_PORT, 0);
|
|
||||||
gpio_direction_output(DCDC_EN_PORT, 0);
|
|
||||||
dcda_en_state = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*dcdc switch*/
|
|
||||||
void audio_dac_power_state(u8 state)
|
|
||||||
{
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case DAC_ANALOG_OPEN_PREPARE:
|
|
||||||
dcdc_en(1);
|
|
||||||
break;
|
|
||||||
case DAC_ANALOG_OPEN_FINISH:
|
|
||||||
break;
|
|
||||||
case DAC_ANALOG_CLOSE_PREPARE:
|
|
||||||
break;
|
|
||||||
case DAC_ANALOG_CLOSE_FINISH:
|
|
||||||
dcdc_en(0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern void cfg_file_parse(u8 idx);
|
|
||||||
void board_init()
|
|
||||||
{
|
|
||||||
|
|
||||||
pwr_set_external_touch(1);
|
|
||||||
board_power_init();
|
|
||||||
//adc_vbg_init();
|
|
||||||
adc_init();
|
|
||||||
#if CLIENT_BOARD == CUSTOM9_CFG
|
|
||||||
dcdc_init();
|
|
||||||
TALKING_FB_MIC_sel(0);
|
|
||||||
#endif
|
|
||||||
cfg_file_parse(0);
|
|
||||||
devices_init();
|
|
||||||
#if TCFG_AUDIO_ANC_ENABLE
|
|
||||||
anc_init();
|
|
||||||
#endif/*TCFG_AUDIO_ANC_ENABLE*/
|
|
||||||
|
|
||||||
board_devices_init();
|
|
||||||
|
|
||||||
#if TCFG_CHARGE_ENABLE
|
|
||||||
if(get_charge_online_flag())
|
|
||||||
#else
|
|
||||||
if (0)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
power_set_mode(PWR_LDO15);
|
|
||||||
}else{
|
|
||||||
power_set_mode(TCFG_LOWPOWER_POWER_SEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
//针对硅mic要输出1给mic供电
|
|
||||||
/* gpio_set_pull_up(IO_PORTA_04, 0); */
|
|
||||||
/* gpio_set_pull_down(IO_PORTA_04, 0); */
|
|
||||||
/* gpio_set_direction(IO_PORTA_04, 0); */
|
|
||||||
/* gpio_set_output_value(IO_PORTA_04,1); */
|
|
||||||
|
|
||||||
#if TCFG_UART0_ENABLE
|
|
||||||
if (uart0_data.rx_pin < IO_MAX_NUM) {
|
|
||||||
gpio_set_die(uart0_data.rx_pin, 1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if TCFG_SMART_VOICE_ENABLE
|
|
||||||
int audio_smart_voice_detect_init(struct vad_mic_platform_data *mic_data);
|
|
||||||
audio_smart_voice_detect_init((struct vad_mic_platform_data *)&vad_mic_data);
|
|
||||||
#endif /* #if TCFG_SMART_VOICE_ENABLE */
|
|
||||||
|
|
||||||
#ifdef CONFIG_BOARD_AISPEECH_VAD_ASR
|
|
||||||
extern int audio_ais_platform_asr_init(struct vad_mic_platform_data *mic_data);
|
|
||||||
audio_ais_platform_asr_init((struct vad_mic_platform_data *)&vad_mic_data);
|
|
||||||
#endif /*CONFIG_BOARD_AISPEECH_VAD_ASR*/
|
|
||||||
|
|
||||||
#ifdef AUDIO_PCM_DEBUG
|
|
||||||
extern void uartSendInit();
|
|
||||||
uartSendInit();
|
|
||||||
#endif/*AUDIO_PCM_DEBUG*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/*进软关机之前默认将IO口都设置成高阻状态,需要保留原来状态的请修改该函数*/
|
|
||||||
extern void dac_power_off(void);
|
|
||||||
void board_set_soft_poweroff(void)
|
|
||||||
{
|
|
||||||
//power按键
|
|
||||||
#if TCFG_IOKEY_ENABLE
|
|
||||||
soff_gpio_protect(TCFG_IOKEY_POWER_ONE_PORT);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
soff_gpio_protect(TCFG_EXTERNAL_TOUCH_KEY_POWER_PORT);//软关机KEEP外置触摸供电
|
|
||||||
|
|
||||||
#if (!(TCFG_LP_TOUCH_KEY_ENABLE && TCFG_LP_TOUCH_KEY1_EN))
|
|
||||||
//默认唤醒io
|
|
||||||
soff_gpio_protect(IO_PORTB_01);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (TCFG_TEST_BOX_ENABLE || TCFG_CHARGESTORE_ENABLE || TCFG_ANC_BOX_ENABLE || TCFG_UMIDIGI_BOX_ENABLE)
|
|
||||||
power_wakeup_index_enable(2, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
board_set_soft_poweroff_common(NULL);
|
|
||||||
|
|
||||||
dac_power_off();
|
|
||||||
}
|
|
||||||
|
|
||||||
#define APP_IO_DEBUG_0(i,x) {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT &= ~BIT(x);}
|
|
||||||
#define APP_IO_DEBUG_1(i,x) {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT |= BIT(x);}
|
|
||||||
|
|
||||||
void sleep_exit_callback(u32 usec)
|
|
||||||
{
|
|
||||||
sleep_exit_callback_common(NULL);
|
|
||||||
|
|
||||||
putchar('>');
|
|
||||||
}
|
|
||||||
void sleep_enter_callback(u8 step)
|
|
||||||
{
|
|
||||||
/* 此函数禁止添加打印 */
|
|
||||||
if (step == 1) {
|
|
||||||
putchar('<');
|
|
||||||
} else {
|
|
||||||
//外置触摸供电
|
|
||||||
pwr_set_external_touch(1);
|
|
||||||
|
|
||||||
sleep_enter_callback_common(NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void port_wakeup_callback(u8 index, u8 gpio)
|
|
||||||
{
|
|
||||||
log_info("%s:%d,%d",__FUNCTION__,index,gpio);
|
|
||||||
#if TCFG_UMIDIGI_BOX_ENABLE
|
|
||||||
if (index == 2) {
|
|
||||||
ldo_port_wakeup_to_cmessage();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
switch (index) {
|
|
||||||
#if (TCFG_TEST_BOX_ENABLE || TCFG_CHARGESTORE_ENABLE || TCFG_ANC_BOX_ENABLE)
|
|
||||||
case 2:
|
|
||||||
extern void chargestore_ldo5v_fall_deal(void);
|
|
||||||
chargestore_ldo5v_fall_deal();
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void aport_wakeup_callback(u8 index, u8 gpio, u8 edge)
|
|
||||||
{
|
|
||||||
log_info("%s:%d,%d",__FUNCTION__,index,gpio);
|
|
||||||
#if TCFG_CHARGE_ENABLE
|
|
||||||
switch (gpio) {
|
|
||||||
case IO_CHGFL_DET://charge port
|
|
||||||
charge_wakeup_isr();
|
|
||||||
break;
|
|
||||||
case IO_VBTCH_DET://vbat port
|
|
||||||
case IO_LDOIN_DET://ldoin port
|
|
||||||
ldoin_wakeup_isr();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void board_power_init(void)
|
|
||||||
{
|
|
||||||
log_info("Power init : %s", __FILE__);
|
|
||||||
|
|
||||||
power_init(&power_param);
|
|
||||||
|
|
||||||
power_set_callback(TCFG_LOWPOWER_LOWPOWER_SEL, sleep_enter_callback, sleep_exit_callback, board_set_soft_poweroff);
|
|
||||||
|
|
||||||
#if TCFG_UMIDIGI_BOX_ENABLE
|
|
||||||
gpio_set_die(TCFG_CHARGESTORE_PORT, 1);
|
|
||||||
umidigi_chargestore_message_callback(app_umidigi_chargetore_message_deal);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
power_keep_dacvdd_en(0);
|
|
||||||
|
|
||||||
power_wakeup_init(&wk_param);
|
|
||||||
|
|
||||||
power_awakeup_set_callback(aport_wakeup_callback);
|
|
||||||
power_wakeup_set_callback(port_wakeup_callback);
|
|
||||||
}
|
|
||||||
#endif /* #ifdef CONFIG_BOARD_JL701N_ANC */
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,123 +0,0 @@
|
|||||||
#ifndef CONFIG_BOARD_JL701N_ANC_POST_BUILD_CFG_H
|
|
||||||
#define CONFIG_BOARD_JL701N_ANC_POST_BUILD_CFG_H
|
|
||||||
|
|
||||||
/* 改文件只添加和isd_config.ini相关的配置,用以生成isd_config.ini */
|
|
||||||
/* 其他不相关的配置请勿添加在改文件 */
|
|
||||||
|
|
||||||
#ifdef CONFIG_BOARD_JL701N_ANC
|
|
||||||
|
|
||||||
/* Following Macros Affect Periods Of Both Code Compiling And Post-build */
|
|
||||||
|
|
||||||
#define CONFIG_DOUBLE_BANK_ENABLE 0 //单双备份选择(若打开了改宏,FLASH结构变为双备份结构,适用于接入第三方协议的OTA, PS: JL-OTA同样支持双备份升级, 需要根据实际FLASH大小同时配置CONFIG_FLASH_SIZE)
|
|
||||||
#define CONFIG_APP_OTA_ENABLE 0 //是否支持RCSP升级(JL-OTA)
|
|
||||||
|
|
||||||
#define CONFIG_UPDATE_JUMP_TO_MASK 0 //配置升级到loader的方式0为直接reset,1为跳转(适用于芯片电源由IO口KEEP住的方案,需要注意检查跳转前是否将使用DMA的硬件模块全部关闭)
|
|
||||||
|
|
||||||
#define CONFIG_IO_KEY_EN 0 //配置是否使用IO按键,配合RESET1
|
|
||||||
#define CONFIG_UPDATE_WITH_MD5_CHECK_EN 0 //配置升级是否支持MD5校验
|
|
||||||
|
|
||||||
#define CONFIG_ANC_ENABLE 1 //配置是否支持ANC
|
|
||||||
|
|
||||||
//flash size vaule definition
|
|
||||||
#define FLASH_SIZE_256K 0x40000
|
|
||||||
#define FLASH_SIZE_512K 0x80000
|
|
||||||
#define FLASH_SIZE_1M 0x100000
|
|
||||||
#define FLASH_SIZE_2M 0x200000
|
|
||||||
#define FLASH_SIZE_4M 0x400000
|
|
||||||
|
|
||||||
#define CONFIG_FLASH_SIZE FLASH_SIZE_1M //配置FLASH大小
|
|
||||||
|
|
||||||
|
|
||||||
/* Above Macros Affect Periods Of Both Code Compiling And Post-build */
|
|
||||||
|
|
||||||
/* Following Macros Only For Post Bulid Configuaration */
|
|
||||||
|
|
||||||
#define CONFIG_DB_UPDATE_DATA_GENERATE_EN 0 //是否生成db_data.bin(用于第三方协议接入使用)
|
|
||||||
#define CONFIG_ONLY_GRENERATE_ALIGN_4K_CODE 0 //ufw只生成1份4K对齐的代码
|
|
||||||
|
|
||||||
//config for supported chip version
|
|
||||||
#ifdef CONFIG_BR30_C_VERSION
|
|
||||||
#define CONFIG_SUPPORTED_CHIP_VERSION C
|
|
||||||
#else
|
|
||||||
#define CONFIG_SUPPORTED_CHIP_VERSION B,D,E,M,N,O,P
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//DON'T MODIFY THIS CONFIG EXCEPT SDK PUBLISHER
|
|
||||||
#define CONFIG_CHIP_NAME AC701N //除了SDK发布者,请不要修改
|
|
||||||
//it can be modified before first programming,but keep the same as the original version
|
|
||||||
#define CONFIG_PID AC701N //烧写或强制升级之前可以修改,之后升级要保持一致
|
|
||||||
//it can be modified before first programming,but keep the same as the original version
|
|
||||||
#define CONFIG_VID 0.01 //烧写或强制升级之前可以修改,之后升级要保持一致
|
|
||||||
|
|
||||||
//Project with bluetooth,it must use OSC as PLL_SOURCE;
|
|
||||||
#define CONFIG_PLL_SOURCE_USING_LRC 0 //PLL时钟源选择 1:LRC 2:OSC
|
|
||||||
|
|
||||||
//config alignment size unit
|
|
||||||
#ifdef CONFIG_256K_FLASH
|
|
||||||
#define ALIGN_UNIT_256B 1 //FLASH对齐方式选择,如果是256K的FLASH,选择256BYTE对齐方式
|
|
||||||
#else
|
|
||||||
#define ALIGN_UNIT_256B 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//partial platform check this config to select the uart IO for wired update
|
|
||||||
#define CONFIG_UART_UPDATE_PIN PP00
|
|
||||||
|
|
||||||
//isd_download loader/uboot/update_loader debug io config
|
|
||||||
//#define CONFIG_UBOOT_DEBUG_PIN PA05
|
|
||||||
//#define CONFIG_UBOOT_DEBUG_BAUD_RATE 1000000
|
|
||||||
|
|
||||||
//config long-press reset io pin,time,trigger level
|
|
||||||
#define CONFIG_RESET_PIN LDO //io pin
|
|
||||||
#define CONFIG_RESET_TIME 04 //unit:second
|
|
||||||
#define CONFIG_RESET_LEVEL 1 //tigger level(0/1)
|
|
||||||
|
|
||||||
#if CONFIG_IO_KEY_EN
|
|
||||||
#define CONFIG_SUPPORT_RESET1
|
|
||||||
#define CONFIG_RESET1_PIN PB01 //io pin
|
|
||||||
#define CONFIG_RESET1_TIME 08 //unit:second
|
|
||||||
#define CONFIG_RESET1_LEVEL 0 //tigger level(0/1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//reserved three custom cfg item for the future definition
|
|
||||||
//#define CONFIG_CUSTOM_CFG1_TYPE POWER_PIN
|
|
||||||
//#define CONFIG_CUSTOM_CFG1_VALUE PC01_1
|
|
||||||
|
|
||||||
//#define CONFIG_CUSTOM_CFG2_TYPE
|
|
||||||
//#define CONFIG_CUSTOM_CFG2_VALUE
|
|
||||||
|
|
||||||
//#define CONFIG_CUSTOM_CFG3_TYPE
|
|
||||||
//#define CONFIG_CUSTOM_CFG3_VALUE
|
|
||||||
|
|
||||||
|
|
||||||
//#define CONFIG_VDDIO_LVD_LEVEL 4 ////VDDIO_LVD挡位,0: 1.9V 1: 2.0V 2: 2.1V 3: 2.2V 4: 2.3V 5: 2.4V 6: 2.5V 7: 2.6V
|
|
||||||
|
|
||||||
//with single-bank mode,actual vm size should larger this VM_LEAST_SIZE,and dual bank mode,actual vm size equals this;
|
|
||||||
#define CONFIG_VM_LEAST_SIZE 8K
|
|
||||||
//config whether erased this area when do a update,1-No Operation,0-Erase
|
|
||||||
#define CONFIG_VM_OPT 1
|
|
||||||
|
|
||||||
//config whether erased this area when do a update,1-No Operation,0-Erase
|
|
||||||
#define CONFIG_BTIF_OPT 1
|
|
||||||
|
|
||||||
//reserved two custom cfg area for the future definition
|
|
||||||
//#define CONFIG_RESERVED_AREA1 EXIF1
|
|
||||||
#ifdef CONFIG_RESERVED_AREA1
|
|
||||||
#define CONFIG_RESERVED_AREA1_ADDR AUTO
|
|
||||||
#define CONFIG_RESERVED_AREA1_LEN 0x1000
|
|
||||||
#define CONFIG_RESERVED_AREA1_OPT 1
|
|
||||||
//#define CONFIG_RESERVED_AREA1_FILE anc_gains.bin
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//#define CONFIG_RESERVED_AREA2 EXIF2
|
|
||||||
#ifdef CONFIG_RESERVED_AREA2
|
|
||||||
#define CONFIG_RESERVED_AREA2_ADDR AUTO
|
|
||||||
#define CONFIG_RESERVED_AREA2_LEN 0x1000
|
|
||||||
#define CONFIG_RESERVED_AREA2_OPT 1
|
|
||||||
//#define CONFIG_RESERVED_AREA2_FILE anc_gains.bin
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Above Macros Only For Post Bulid Configuaration */
|
|
||||||
#endif /* #ifdef CONFIG_BOARD_JL701N_ANC */
|
|
||||||
|
|
||||||
#endif /* #ifndef CONFIG_BOARD_JL701N_ANC_POST_BUILD_CFG_H */
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,123 +0,0 @@
|
|||||||
#ifndef CONFIG_BOARD_JL701N_BTEMITTER_BUILD_CFG_H
|
|
||||||
#define CONFIG_BOARD_JL701N_BTEMITTER_BUILD_CFG_H
|
|
||||||
|
|
||||||
/* 改文件只添加和isd_config.ini相关的配置,用以生成isd_config.ini */
|
|
||||||
/* 其他不相关的配置请勿添加在改文件 */
|
|
||||||
|
|
||||||
#ifdef CONFIG_BOARD_JL701N_BTEMITTER
|
|
||||||
|
|
||||||
/* Following Macros Affect Periods Of Both Code Compiling And Post-build */
|
|
||||||
|
|
||||||
#define CONFIG_DOUBLE_BANK_ENABLE 0 //单双备份选择(若打开了改宏,FLASH结构变为双备份结构,适用于接入第三方协议的OTA, PS: JL-OTA同样支持双备份升级, 需要根据实际FLASH大小同时配置CONFIG_FLASH_SIZE)
|
|
||||||
#define CONFIG_APP_OTA_ENABLE 0 //是否支持RCSP升级(JL-OTA)
|
|
||||||
|
|
||||||
#define CONFIG_UPDATE_JUMP_TO_MASK 0 //配置升级到loader的方式0为直接reset,1为跳转(适用于芯片电源由IO口KEEP住的方案,需要注意检查跳转前是否将使用DMA的硬件模块全部关闭)
|
|
||||||
|
|
||||||
#define CONFIG_IO_KEY_EN 0 //配置是否使用IO按键,配合RESET1
|
|
||||||
#define CONFIG_UPDATE_WITH_MD5_CHECK_EN 0 //配置升级是否支持MD5校验
|
|
||||||
|
|
||||||
#define CONFIG_ANC_ENABLE 0 //配置是否支持ANC
|
|
||||||
|
|
||||||
//flash size vaule definition
|
|
||||||
#define FLASH_SIZE_256K 0x40000
|
|
||||||
#define FLASH_SIZE_512K 0x80000
|
|
||||||
#define FLASH_SIZE_1M 0x100000
|
|
||||||
#define FLASH_SIZE_2M 0x200000
|
|
||||||
#define FLASH_SIZE_4M 0x400000
|
|
||||||
|
|
||||||
#define CONFIG_FLASH_SIZE FLASH_SIZE_1M //配置FLASH大小
|
|
||||||
|
|
||||||
|
|
||||||
/* Above Macros Affect Periods Of Both Code Compiling And Post-build */
|
|
||||||
|
|
||||||
/* Following Macros Only For Post Bulid Configuaration */
|
|
||||||
|
|
||||||
#define CONFIG_DB_UPDATE_DATA_GENERATE_EN 0 //是否生成db_data.bin(用于第三方协议接入使用)
|
|
||||||
#define CONFIG_ONLY_GRENERATE_ALIGN_4K_CODE 0 //ufw只生成1份4K对齐的代码
|
|
||||||
|
|
||||||
//config for supported chip version
|
|
||||||
#ifdef CONFIG_BR30_C_VERSION
|
|
||||||
#define CONFIG_SUPPORTED_CHIP_VERSION C
|
|
||||||
#else
|
|
||||||
#define CONFIG_SUPPORTED_CHIP_VERSION B,D,E,M,N,O,P
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//DON'T MODIFY THIS CONFIG EXCEPT SDK PUBLISHER
|
|
||||||
#define CONFIG_CHIP_NAME AC701N //除了SDK发布者,请不要修改
|
|
||||||
//it can be modified before first programming,but keep the same as the original version
|
|
||||||
#define CONFIG_PID AC701N //烧写或强制升级之前可以修改,之后升级要保持一致
|
|
||||||
//it can be modified before first programming,but keep the same as the original version
|
|
||||||
#define CONFIG_VID 0.01 //烧写或强制升级之前可以修改,之后升级要保持一致
|
|
||||||
|
|
||||||
//Project with bluetooth,it must use OSC as PLL_SOURCE;
|
|
||||||
#define CONFIG_PLL_SOURCE_USING_LRC 0 //PLL时钟源选择 1:LRC 2:OSC
|
|
||||||
|
|
||||||
//config alignment size unit
|
|
||||||
#ifdef CONFIG_256K_FLASH
|
|
||||||
#define ALIGN_UNIT_256B 1 //FLASH对齐方式选择,如果是256K的FLASH,选择256BYTE对齐方式
|
|
||||||
#else
|
|
||||||
#define ALIGN_UNIT_256B 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//partial platform check this config to select the uart IO for wired update
|
|
||||||
#define CONFIG_UART_UPDATE_PIN PP00
|
|
||||||
|
|
||||||
//isd_download loader/uboot/update_loader debug io config
|
|
||||||
//#define CONFIG_UBOOT_DEBUG_PIN PA05
|
|
||||||
//#define CONFIG_UBOOT_DEBUG_BAUD_RATE 1000000
|
|
||||||
|
|
||||||
//config long-press reset io pin,time,trigger level
|
|
||||||
#define CONFIG_RESET_PIN LDO //io pin
|
|
||||||
#define CONFIG_RESET_TIME 04 //unit:second
|
|
||||||
#define CONFIG_RESET_LEVEL 1 //tigger level(0/1)
|
|
||||||
|
|
||||||
#if CONFIG_IO_KEY_EN
|
|
||||||
#define CONFIG_SUPPORT_RESET1
|
|
||||||
#define CONFIG_RESET1_PIN PB01 //io pin
|
|
||||||
#define CONFIG_RESET1_TIME 08 //unit:second
|
|
||||||
#define CONFIG_RESET1_LEVEL 0 //tigger level(0/1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//reserved three custom cfg item for the future definition
|
|
||||||
//#define CONFIG_CUSTOM_CFG1_TYPE POWER_PIN
|
|
||||||
//#define CONFIG_CUSTOM_CFG1_VALUE PC01_1
|
|
||||||
|
|
||||||
//#define CONFIG_CUSTOM_CFG2_TYPE
|
|
||||||
//#define CONFIG_CUSTOM_CFG2_VALUE
|
|
||||||
|
|
||||||
//#define CONFIG_CUSTOM_CFG3_TYPE
|
|
||||||
//#define CONFIG_CUSTOM_CFG3_VALUE
|
|
||||||
|
|
||||||
|
|
||||||
//#define CONFIG_VDDIO_LVD_LEVEL 4 ////VDDIO_LVD挡位,0: 1.9V 1: 2.0V 2: 2.1V 3: 2.2V 4: 2.3V 5: 2.4V 6: 2.5V 7: 2.6V
|
|
||||||
|
|
||||||
//with single-bank mode,actual vm size should larger this VM_LEAST_SIZE,and dual bank mode,actual vm size equals this;
|
|
||||||
#define CONFIG_VM_LEAST_SIZE 8K
|
|
||||||
//config whether erased this area when do a update,1-No Operation,0-Erase
|
|
||||||
#define CONFIG_VM_OPT 1
|
|
||||||
|
|
||||||
//config whether erased this area when do a update,1-No Operation,0-Erase
|
|
||||||
#define CONFIG_BTIF_OPT 1
|
|
||||||
|
|
||||||
//reserved two custom cfg area for the future definition
|
|
||||||
//#define CONFIG_RESERVED_AREA1 EXIF1
|
|
||||||
#ifdef CONFIG_RESERVED_AREA1
|
|
||||||
#define CONFIG_RESERVED_AREA1_ADDR AUTO
|
|
||||||
#define CONFIG_RESERVED_AREA1_LEN 0x1000
|
|
||||||
#define CONFIG_RESERVED_AREA1_OPT 1
|
|
||||||
//#define CONFIG_RESERVED_AREA1_FILE anc_gains.bin
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//#define CONFIG_RESERVED_AREA2 EXIF2
|
|
||||||
#ifdef CONFIG_RESERVED_AREA2
|
|
||||||
#define CONFIG_RESERVED_AREA2_ADDR AUTO
|
|
||||||
#define CONFIG_RESERVED_AREA2_LEN 0x1000
|
|
||||||
#define CONFIG_RESERVED_AREA2_OPT 1
|
|
||||||
//#define CONFIG_RESERVED_AREA2_FILE anc_gains.bin
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Above Macros Only For Post Bulid Configuaration */
|
|
||||||
#endif /* #ifdef CONFIG_BOARD_JL701N_BTEMITTER */
|
|
||||||
|
|
||||||
#endif /* #ifndef CONFIG_BOARD_JL701N_BTEMITTER_BUILD_CFG_H */
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,123 +0,0 @@
|
|||||||
#ifndef CONFIG_BOARD_JL701N_DEMO_POST_BUILD_CFG_H
|
|
||||||
#define CONFIG_BOARD_JL701N_DEMO_POST_BUILD_CFG_H
|
|
||||||
|
|
||||||
/* 改文件只添加和isd_config.ini相关的配置,用以生成isd_config.ini */
|
|
||||||
/* 其他不相关的配置请勿添加在改文件 */
|
|
||||||
|
|
||||||
#ifdef CONFIG_BOARD_JL701N_DEMO
|
|
||||||
|
|
||||||
/* Following Macros Affect Periods Of Both Code Compiling And Post-build */
|
|
||||||
|
|
||||||
#define CONFIG_DOUBLE_BANK_ENABLE 0 //单双备份选择(若打开了改宏,FLASH结构变为双备份结构,适用于接入第三方协议的OTA, PS: JL-OTA同样支持双备份升级, 需要根据实际FLASH大小同时配置CONFIG_FLASH_SIZE)
|
|
||||||
#define CONFIG_APP_OTA_ENABLE 0 //是否支持RCSP升级(JL-OTA)
|
|
||||||
|
|
||||||
#define CONFIG_UPDATE_JUMP_TO_MASK 0 //配置升级到loader的方式0为直接reset,1为跳转(适用于芯片电源由IO口KEEP住的方案,需要注意检查跳转前是否将使用DMA的硬件模块全部关闭)
|
|
||||||
|
|
||||||
#define CONFIG_IO_KEY_EN 0 //配置是否使用IO按键,配合RESET1
|
|
||||||
#define CONFIG_UPDATE_WITH_MD5_CHECK_EN 0 //配置升级是否支持MD5校验
|
|
||||||
|
|
||||||
#define CONFIG_ANC_ENABLE 0 //配置是否支持ANC
|
|
||||||
|
|
||||||
//flash size vaule definition
|
|
||||||
#define FLASH_SIZE_256K 0x40000
|
|
||||||
#define FLASH_SIZE_512K 0x80000
|
|
||||||
#define FLASH_SIZE_1M 0x100000
|
|
||||||
#define FLASH_SIZE_2M 0x200000
|
|
||||||
#define FLASH_SIZE_4M 0x400000
|
|
||||||
|
|
||||||
#define CONFIG_FLASH_SIZE FLASH_SIZE_1M //配置FLASH大小
|
|
||||||
|
|
||||||
|
|
||||||
/* Above Macros Affect Periods Of Both Code Compiling And Post-build */
|
|
||||||
|
|
||||||
/* Following Macros Only For Post Bulid Configuaration */
|
|
||||||
|
|
||||||
#define CONFIG_DB_UPDATE_DATA_GENERATE_EN 0 //是否生成db_data.bin(用于第三方协议接入使用)
|
|
||||||
#define CONFIG_ONLY_GRENERATE_ALIGN_4K_CODE 0 //ufw只生成1份4K对齐的代码
|
|
||||||
|
|
||||||
//config for supported chip version
|
|
||||||
#ifdef CONFIG_BR30_C_VERSION
|
|
||||||
#define CONFIG_SUPPORTED_CHIP_VERSION C
|
|
||||||
#else
|
|
||||||
#define CONFIG_SUPPORTED_CHIP_VERSION B,D,E,M,N,O,P
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//DON'T MODIFY THIS CONFIG EXCEPT SDK PUBLISHER
|
|
||||||
#define CONFIG_CHIP_NAME AC701N //除了SDK发布者,请不要修改
|
|
||||||
//it can be modified before first programming,but keep the same as the original version
|
|
||||||
#define CONFIG_PID AC701N //烧写或强制升级之前可以修改,之后升级要保持一致
|
|
||||||
//it can be modified before first programming,but keep the same as the original version
|
|
||||||
#define CONFIG_VID 0.01 //烧写或强制升级之前可以修改,之后升级要保持一致
|
|
||||||
|
|
||||||
//Project with bluetooth,it must use OSC as PLL_SOURCE;
|
|
||||||
#define CONFIG_PLL_SOURCE_USING_LRC 0 //PLL时钟源选择 1:LRC 2:OSC
|
|
||||||
|
|
||||||
//config alignment size unit
|
|
||||||
#ifdef CONFIG_256K_FLASH
|
|
||||||
#define ALIGN_UNIT_256B 1 //FLASH对齐方式选择,如果是256K的FLASH,选择256BYTE对齐方式
|
|
||||||
#else
|
|
||||||
#define ALIGN_UNIT_256B 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//partial platform check this config to select the uart IO for wired update
|
|
||||||
#define CONFIG_UART_UPDATE_PIN PP00
|
|
||||||
|
|
||||||
//isd_download loader/uboot/update_loader debug io config
|
|
||||||
//#define CONFIG_UBOOT_DEBUG_PIN PA05
|
|
||||||
//#define CONFIG_UBOOT_DEBUG_BAUD_RATE 1000000
|
|
||||||
|
|
||||||
//config long-press reset io pin,time,trigger level
|
|
||||||
#define CONFIG_RESET_PIN LDO //io pin
|
|
||||||
#define CONFIG_RESET_TIME 04 //unit:second
|
|
||||||
#define CONFIG_RESET_LEVEL 1 //tigger level(0/1)
|
|
||||||
|
|
||||||
#if CONFIG_IO_KEY_EN
|
|
||||||
#define CONFIG_SUPPORT_RESET1
|
|
||||||
#define CONFIG_RESET1_PIN PB01 //io pin
|
|
||||||
#define CONFIG_RESET1_TIME 08 //unit:second
|
|
||||||
#define CONFIG_RESET1_LEVEL 0 //tigger level(0/1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//reserved three custom cfg item for the future definition
|
|
||||||
//#define CONFIG_CUSTOM_CFG1_TYPE POWER_PIN
|
|
||||||
//#define CONFIG_CUSTOM_CFG1_VALUE PC01_1
|
|
||||||
|
|
||||||
//#define CONFIG_CUSTOM_CFG2_TYPE
|
|
||||||
//#define CONFIG_CUSTOM_CFG2_VALUE
|
|
||||||
|
|
||||||
//#define CONFIG_CUSTOM_CFG3_TYPE
|
|
||||||
//#define CONFIG_CUSTOM_CFG3_VALUE
|
|
||||||
|
|
||||||
|
|
||||||
//#define CONFIG_VDDIO_LVD_LEVEL 4 ////VDDIO_LVD挡位,0: 1.9V 1: 2.0V 2: 2.1V 3: 2.2V 4: 2.3V 5: 2.4V 6: 2.5V 7: 2.6V
|
|
||||||
|
|
||||||
//with single-bank mode,actual vm size should larger this VM_LEAST_SIZE,and dual bank mode,actual vm size equals this;
|
|
||||||
#define CONFIG_VM_LEAST_SIZE 8K
|
|
||||||
//config whether erased this area when do a update,1-No Operation,0-Erase
|
|
||||||
#define CONFIG_VM_OPT 1
|
|
||||||
|
|
||||||
//config whether erased this area when do a update,1-No Operation,0-Erase
|
|
||||||
#define CONFIG_BTIF_OPT 1
|
|
||||||
|
|
||||||
//reserved two custom cfg area for the future definition
|
|
||||||
//#define CONFIG_RESERVED_AREA1 EXIF1
|
|
||||||
#ifdef CONFIG_RESERVED_AREA1
|
|
||||||
#define CONFIG_RESERVED_AREA1_ADDR AUTO
|
|
||||||
#define CONFIG_RESERVED_AREA1_LEN 0x1000
|
|
||||||
#define CONFIG_RESERVED_AREA1_OPT 1
|
|
||||||
//#define CONFIG_RESERVED_AREA1_FILE anc_gains.bin
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//#define CONFIG_RESERVED_AREA2 EXIF2
|
|
||||||
#ifdef CONFIG_RESERVED_AREA2
|
|
||||||
#define CONFIG_RESERVED_AREA2_ADDR AUTO
|
|
||||||
#define CONFIG_RESERVED_AREA2_LEN 0x1000
|
|
||||||
#define CONFIG_RESERVED_AREA2_OPT 1
|
|
||||||
//#define CONFIG_RESERVED_AREA2_FILE anc_gains.bin
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Above Macros Only For Post Bulid Configuaration */
|
|
||||||
#endif /* #ifdef CONFIG_BOARD_JL701N_DEMO */
|
|
||||||
|
|
||||||
#endif /* #ifndef CONFIG_BOARD_JL701N_DEMO_POST_BUILD_CFG_H */
|
|
||||||
|
|
||||||
@ -1,418 +0,0 @@
|
|||||||
#include "system/includes.h"
|
|
||||||
#include "media/includes.h"
|
|
||||||
#include "tone_player.h"
|
|
||||||
#include "earphone.h"
|
|
||||||
|
|
||||||
#include "app_config.h"
|
|
||||||
#include "app_action.h"
|
|
||||||
#include "app_task.h"
|
|
||||||
|
|
||||||
#include "btstack/avctp_user.h"
|
|
||||||
#include "btstack/btstack_task.h"
|
|
||||||
#include "btctrler/btctrler_task.h"
|
|
||||||
#include "btstack/frame_queque.h"
|
|
||||||
#include "user_cfg.h"
|
|
||||||
// #include "aec_user.h"
|
|
||||||
#include "classic/hci_lmp.h"
|
|
||||||
#include "bt_common.h"
|
|
||||||
#include "bt_ble.h"
|
|
||||||
#include "bt_tws.h"
|
|
||||||
#include "pbg_user.h"
|
|
||||||
#include "btstack/bluetooth.h"
|
|
||||||
#include "colorful_lights/colorful_lights.h"
|
|
||||||
|
|
||||||
#include "app_chargestore.h"
|
|
||||||
#include "jl_kws/jl_kws_api.h"
|
|
||||||
|
|
||||||
#include "asm/charge.h"
|
|
||||||
#include "app_charge.h"
|
|
||||||
#include "ui_manage.h"
|
|
||||||
|
|
||||||
#include "app_chargestore.h"
|
|
||||||
#include "app_umidigi_chargestore.h"
|
|
||||||
#include "app_testbox.h"
|
|
||||||
#include "app_online_cfg.h"
|
|
||||||
#include "app_main.h"
|
|
||||||
#include "app_power_manage.h"
|
|
||||||
#include "gSensor/gSensor_manage.h"
|
|
||||||
#include "key_event_deal.h"
|
|
||||||
#include "classic/tws_api.h"
|
|
||||||
#include "asm/pwm_led.h"
|
|
||||||
#include "ir_sensor/ir_manage.h"
|
|
||||||
#include "in_ear_detect/in_ear_manage.h"
|
|
||||||
#include "vol_sync.h"
|
|
||||||
#include "bt_background.h"
|
|
||||||
#include "default_event_handler.h"
|
|
||||||
|
|
||||||
|
|
||||||
#if(USE_DMA_UART_TEST) //使用dm串口测试时不能同时打开
|
|
||||||
#define MY_SNIFF_EN 0
|
|
||||||
#else
|
|
||||||
#define MY_SNIFF_EN 1 //默认打开
|
|
||||||
#endif
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//变量
|
|
||||||
u8 init_ok = 0;
|
|
||||||
static u8 sniff_out = 0;
|
|
||||||
unsigned char xtell_bl_state=0; //存放经典蓝牙的连接状态,0断开,1是连接
|
|
||||||
u8 bt_newname =0;
|
|
||||||
unsigned char xt_ble_new_name[9] = "CM-11111";
|
|
||||||
static u16 play_poweron_ok_timer_id = 0;
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
u8 get_bt_init_status(void)
|
|
||||||
{
|
|
||||||
return init_ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 get_sniff_out_status()
|
|
||||||
{
|
|
||||||
return sniff_out;
|
|
||||||
}
|
|
||||||
void clear_sniff_out_status()
|
|
||||||
{
|
|
||||||
sniff_out = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/*
|
|
||||||
* 模式状态机, 通过start_app()控制状态切换
|
|
||||||
*/
|
|
||||||
/* extern int audio_mic_init(); */
|
|
||||||
|
|
||||||
static int state_machine(struct application *app, enum app_state state, struct intent *it){
|
|
||||||
int error = 0;
|
|
||||||
static u8 tone_player_err = 0;
|
|
||||||
r_printf("bt_state_machine=%d\n", state);
|
|
||||||
switch (state) {
|
|
||||||
case APP_STA_CREATE:
|
|
||||||
/* set_adjust_conn_dac_check(0); */
|
|
||||||
STATUS *p_tone = get_tone_config();
|
|
||||||
tone_play_index(p_tone->bt_init_ok, 1);
|
|
||||||
break;
|
|
||||||
case APP_STA_START:
|
|
||||||
if (!it) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
switch (it->action) {
|
|
||||||
case ACTION_EARPHONE_MAIN:
|
|
||||||
/*
|
|
||||||
* earphone 模式初始化
|
|
||||||
*/
|
|
||||||
clk_set("sys", BT_NORMAL_HZ);
|
|
||||||
u32 sys_clk = clk_get("sys");
|
|
||||||
bt_pll_para(TCFG_CLOCK_OSC_HZ, sys_clk, 0, 0);
|
|
||||||
/* bredr_set_dut_enble(1, 1); */
|
|
||||||
bt_function_select_init();
|
|
||||||
bredr_handle_register();
|
|
||||||
EARPHONE_STATE_INIT();
|
|
||||||
btstack_init();
|
|
||||||
sys_auto_shut_down_enable();
|
|
||||||
bt_sniff_feature_init();
|
|
||||||
sys_auto_sniff_controle(MY_SNIFF_EN, NULL);
|
|
||||||
app_var.dev_volume = -1;
|
|
||||||
break;
|
|
||||||
case ACTION_A2DP_START: //蓝牙音频传输协议
|
|
||||||
break;
|
|
||||||
case ACTION_BY_KEY_MODE:
|
|
||||||
break;
|
|
||||||
case ACTION_TONE_PLAY:
|
|
||||||
STATUS *p_tone = get_tone_config();
|
|
||||||
tone_play_index(p_tone->bt_init_ok, 1);
|
|
||||||
break;
|
|
||||||
case ACTION_DO_NOTHING:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case APP_STA_PAUSE:
|
|
||||||
break;
|
|
||||||
case APP_STA_RESUME:
|
|
||||||
//恢复前台运行
|
|
||||||
sys_auto_shut_down_disable();
|
|
||||||
sys_key_event_enable();
|
|
||||||
break;
|
|
||||||
case APP_STA_STOP:
|
|
||||||
break;
|
|
||||||
case APP_STA_DESTROY:
|
|
||||||
r_printf("APP_STA_DESTROY\n");
|
|
||||||
if (!app_var.goto_poweroff_flag) {
|
|
||||||
bt_app_exit(NULL);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//handle
|
|
||||||
|
|
||||||
static void play_poweron_ok_timer(void *priv)
|
|
||||||
{
|
|
||||||
app_var.wait_timer_do = 0;
|
|
||||||
|
|
||||||
log_d("\n-------play_poweron_ok_timer-------\n", priv);
|
|
||||||
if (is_dac_power_off()) {
|
|
||||||
#if TCFG_USER_TWS_ENABLE
|
|
||||||
bt_tws_poweron();
|
|
||||||
#else
|
|
||||||
bt_wait_connect_and_phone_connect_switch(0);
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
app_var.wait_timer_do = sys_timeout_add(priv, play_poweron_ok_timer, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void play_bt_connect_dly(void *priv)
|
|
||||||
{
|
|
||||||
app_var.wait_timer_do = 0;
|
|
||||||
|
|
||||||
log_d("\n-------play_bt_connect_dly-------\n", priv);
|
|
||||||
|
|
||||||
if (!app_var.goto_poweroff_flag) {
|
|
||||||
STATUS *p_tone = get_tone_config();
|
|
||||||
tone_play_index(p_tone->bt_connect_ok, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int bt_connction_status_event_handler(struct bt_event *bt)
|
|
||||||
{
|
|
||||||
STATUS *p_tone = get_tone_config();
|
|
||||||
u8 *phone_number = NULL;
|
|
||||||
|
|
||||||
switch (bt->event) {
|
|
||||||
case BT_STATUS_INIT_OK:
|
|
||||||
/*
|
|
||||||
* 蓝牙初始化完成
|
|
||||||
*/
|
|
||||||
log_info("BT_STATUS_INIT_OK\n");
|
|
||||||
init_ok = 1;
|
|
||||||
__set_sbc_cap_bitpool(38);
|
|
||||||
|
|
||||||
#if (TCFG_USER_BLE_ENABLE)
|
|
||||||
if (BT_MODE_IS(BT_BQB)) {
|
|
||||||
ble_bqb_test_thread_init();
|
|
||||||
} else {
|
|
||||||
#if !TCFG_WIRELESS_MIC_ENABLE
|
|
||||||
bt_ble_init();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
bt_init_ok_search_index();
|
|
||||||
#if TCFG_TEST_BOX_ENABLE
|
|
||||||
testbox_set_bt_init_ok(1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ((CONFIG_BT_MODE == BT_BQB)||(CONFIG_BT_MODE == BT_PER))
|
|
||||||
bt_wait_phone_connect_control(1);
|
|
||||||
#else
|
|
||||||
if (is_dac_power_off()) {
|
|
||||||
bt_wait_connect_and_phone_connect_switch(0);
|
|
||||||
} else {
|
|
||||||
app_var.wait_timer_do = sys_timeout_add(NULL, play_poweron_ok_timer, 100);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*if (app_var.play_poweron_tone) {
|
|
||||||
tone_play_index(p_tone->power_on, 1);
|
|
||||||
}*/
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BT_STATUS_SECOND_CONNECTED:
|
|
||||||
clear_current_poweron_memory_search_index(0);
|
|
||||||
case BT_STATUS_FIRST_CONNECTED:
|
|
||||||
log_info("BT_STATUS_CONNECTED\n");
|
|
||||||
xtell_bl_state = 1; //蓝牙连接成功 置1
|
|
||||||
if(strcmp(xt_ble_new_name,"CM-1111") != 0){
|
|
||||||
//蓝牙连接成功
|
|
||||||
bt_newname =1;
|
|
||||||
u8 temp[5]={0xBB,0xBE,0x02,0x04,0x00};
|
|
||||||
temp[4] = xtell_bl_state; //经典蓝牙连接状态
|
|
||||||
send_data_to_ble_client(&temp,5);
|
|
||||||
}
|
|
||||||
earphone_change_pwr_mode(PWR_DCDC15, 3000);
|
|
||||||
sys_auto_shut_down_disable();
|
|
||||||
|
|
||||||
ui_update_status(STATUS_BT_CONN); //单台在此处设置连接状态,对耳的连接状态需要同步,在bt_tws.c中去设置
|
|
||||||
|
|
||||||
/* tone_play(TONE_CONN); */
|
|
||||||
/*os_time_dly(40); // for test*/
|
|
||||||
log_info("tone status:%d\n", tone_get_status());
|
|
||||||
if (get_call_status() == BT_CALL_HANGUP) {
|
|
||||||
if (app_var.phone_dly_discon_time) {
|
|
||||||
sys_timeout_del(app_var.phone_dly_discon_time);
|
|
||||||
app_var.phone_dly_discon_time = 0;
|
|
||||||
} else {
|
|
||||||
app_var.wait_timer_do = sys_timeout_add(NULL, play_bt_connect_dly, 1600);
|
|
||||||
/* tone_play_index(p_tone->bt_connect_ok, 1); */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*int timeout = 5000 + rand32() % 10000;
|
|
||||||
sys_timeout_add(NULL, connect_phone_test, timeout);*/
|
|
||||||
break;
|
|
||||||
case BT_STATUS_FIRST_DISCONNECT:
|
|
||||||
case BT_STATUS_SECOND_DISCONNECT:
|
|
||||||
log_info("BT_STATUS_DISCONNECT\n");
|
|
||||||
xtell_bl_state = 0; //断开蓝牙 清0
|
|
||||||
//蓝牙断开连接
|
|
||||||
if(bt_newname){ //已经改成新蓝牙名字,断开才播报
|
|
||||||
bt_newname=0;
|
|
||||||
u8 temp[5]={0xBB,0xBE,0x02,0x04,0x00};
|
|
||||||
temp[4] = xtell_bl_state; //经典蓝牙连接状态
|
|
||||||
send_data_to_ble_client(&temp,5);
|
|
||||||
}
|
|
||||||
if (app_var.goto_poweroff_flag) {
|
|
||||||
/*关机不播断开提示音*/
|
|
||||||
/*关机时不改UI*/
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
bt_discon_dly_handle(NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
//phone status deal
|
|
||||||
case BT_STATUS_PHONE_INCOME:
|
|
||||||
break;
|
|
||||||
case BT_STATUS_PHONE_OUT:
|
|
||||||
|
|
||||||
break;
|
|
||||||
case BT_STATUS_PHONE_ACTIVE:
|
|
||||||
break;
|
|
||||||
case BT_STATUS_PHONE_HANGUP:
|
|
||||||
break;
|
|
||||||
case BT_STATUS_PHONE_NUMBER:
|
|
||||||
break;
|
|
||||||
case BT_STATUS_INBAND_RINGTONE: //铃声
|
|
||||||
break;
|
|
||||||
case BT_STATUS_CALL_VOL_CHANGE:
|
|
||||||
|
|
||||||
break;
|
|
||||||
case BT_STATUS_SNIFF_STATE_UPDATE:
|
|
||||||
log_info(" BT_STATUS_SNIFF_STATE_UPDATE %d\n", bt->value); //0退出SNIFF
|
|
||||||
if (bt->value == 0) {
|
|
||||||
sniff_out = 1;
|
|
||||||
sys_auto_sniff_controle(MY_SNIFF_EN, bt->args);
|
|
||||||
} else {
|
|
||||||
sys_auto_sniff_controle(0, bt->args);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BT_STATUS_LAST_CALL_TYPE_CHANGE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BT_STATUS_CONN_A2DP_CH:
|
|
||||||
case BT_STATUS_CONN_HFP_CH:
|
|
||||||
|
|
||||||
if ((!is_1t2_connection()) && (get_current_poweron_memory_search_index(NULL))) { //回连下一个device
|
|
||||||
if (get_esco_coder_busy_flag()) {
|
|
||||||
clear_current_poweron_memory_search_index(0);
|
|
||||||
} else {
|
|
||||||
user_send_cmd_prepare(USER_CTRL_START_CONNECTION, 0, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BT_STATUS_PHONE_MANUFACTURER:
|
|
||||||
break;
|
|
||||||
case BT_STATUS_VOICE_RECOGNITION:
|
|
||||||
|
|
||||||
break;
|
|
||||||
case BT_STATUS_AVRCP_INCOME_OPID:
|
|
||||||
#define AVC_VOLUME_UP 0x41
|
|
||||||
#define AVC_VOLUME_DOWN 0x42
|
|
||||||
log_info("BT_STATUS_AVRCP_INCOME_OPID:%d\n", bt->value);
|
|
||||||
if (bt->value == AVC_VOLUME_UP) {
|
|
||||||
|
|
||||||
}
|
|
||||||
if (bt->value == AVC_VOLUME_DOWN) {
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
log_info(" BT STATUS DEFAULT\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int event_handler(struct application *app, struct sys_event *event)
|
|
||||||
{
|
|
||||||
if (SYS_EVENT_REMAP(event)) {
|
|
||||||
g_printf("****SYS_EVENT_REMAP**** \n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (event->type) {
|
|
||||||
case SYS_KEY_EVENT:
|
|
||||||
break;
|
|
||||||
case SYS_BT_EVENT:
|
|
||||||
/*
|
|
||||||
* 蓝牙事件处理
|
|
||||||
*/
|
|
||||||
if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
|
|
||||||
printf("in event_handler:bt_connction_status_event_handler");
|
|
||||||
bt_connction_status_event_handler(&event->u.bt);
|
|
||||||
} else if ((u32)event->arg == SYS_BT_EVENT_TYPE_HCI_STATUS) {
|
|
||||||
bt_hci_event_handler(&event->u.bt);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SYS_DEVICE_EVENT:
|
|
||||||
/*
|
|
||||||
* 系统设备事件处理
|
|
||||||
*/
|
|
||||||
if ((u32)event->arg == DEVICE_EVENT_FROM_CHARGE) {
|
|
||||||
|
|
||||||
} else if ((u32)event->arg == DEVICE_EVENT_FROM_POWER) {
|
|
||||||
return app_power_event_handler(&event->u.dev);
|
|
||||||
}
|
|
||||||
#if TCFG_UMIDIGI_BOX_ENABLE
|
|
||||||
else if ((u32)event->arg == DEVICE_EVENT_UMIDIGI_CHARGE_STORE) {
|
|
||||||
app_umidigi_chargestore_event_handler(&event->u.umidigi_chargestore);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if TCFG_TEST_BOX_ENABLE
|
|
||||||
else if ((u32)event->arg == DEVICE_EVENT_TEST_BOX) {
|
|
||||||
app_testbox_event_handler(&event->u.testbox);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SYS_EVENT_HANDLER_SPECIFIC(event);
|
|
||||||
#ifdef CONFIG_BT_BACKGROUND_ENABLE
|
|
||||||
if (app) {
|
|
||||||
default_event_handler(event);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static const struct application_operation app_handler_ops = {
|
|
||||||
.state_machine = state_machine,
|
|
||||||
.event_handler = event_handler,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 注册earphone模式
|
|
||||||
*/
|
|
||||||
REGISTER_APPLICATION(app_handler) = {
|
|
||||||
.name = "handler",
|
|
||||||
.action = ACTION_EARPHONE_MAIN,
|
|
||||||
.ops = &app_handler_ops,
|
|
||||||
.state = APP_STA_DESTROY,
|
|
||||||
};
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
#ifndef APP_ACTION_H
|
|
||||||
#define APP_ACTION_H
|
|
||||||
|
|
||||||
|
|
||||||
#define ACTION_EARPHONE_MAIN 0x0001
|
|
||||||
#define ACTION_A2DP_START 0x0002
|
|
||||||
#define ACTION_ESCO_START 0x0003
|
|
||||||
#define ACTION_BY_KEY_MODE 0x0004
|
|
||||||
|
|
||||||
#define ACTION_IDLE_MAIN 0x0010
|
|
||||||
#define ACTION_IDLE_POWER_OFF 0x0011
|
|
||||||
|
|
||||||
#define ACTION_MUSIC_MAIN 0x0020
|
|
||||||
#define ACTION_MUSIC_TWS_RX 0x0021
|
|
||||||
|
|
||||||
#define ACTION_PC_MAIN 0x0030
|
|
||||||
|
|
||||||
#define ACTION_AUX_MAIN 0x0040
|
|
||||||
|
|
||||||
#define APP_NAME_BT "earphone"
|
|
||||||
#define APP_NAME_IDLE "idle"
|
|
||||||
#define APP_NAME_PC "pc"
|
|
||||||
#define APP_NAME_MUSIC "music"
|
|
||||||
#define APP_NAME_AUX "aux"
|
|
||||||
|
|
||||||
extern void task_switch(const char *name, int action);
|
|
||||||
#define task_switch_to_bt() task_switch(APP_NAME_BT, ACTION_EARPHONE_MAIN)
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
#ifndef _APP_ANCBOX_H_
|
|
||||||
#define _APP_ANCBOX_H_
|
|
||||||
|
|
||||||
#include "typedef.h"
|
|
||||||
#include "system/event.h"
|
|
||||||
|
|
||||||
extern int app_ancbox_event_handler(struct ancbox_event *anc_dev);
|
|
||||||
extern u8 ancbox_get_status(void);
|
|
||||||
extern void ancbox_clear_status(void);
|
|
||||||
|
|
||||||
#endif //_APP_CHARGESTORE_H_
|
|
||||||
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
#ifndef _APP_ANCTOOL_H_
|
|
||||||
#define _APP_ANCTOOL_H_
|
|
||||||
|
|
||||||
#include "typedef.h"
|
|
||||||
#include "anctool.h"
|
|
||||||
|
|
||||||
u8 app_anctool_spp_rx_data(u8 *packet, u16 size);
|
|
||||||
void app_anctool_spp_connect(void);
|
|
||||||
void app_anctool_spp_disconnect(void);
|
|
||||||
u8 get_app_anctool_spp_connected_flag();
|
|
||||||
|
|
||||||
#endif //_APP_CHARGESTORE_H_
|
|
||||||
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
#ifndef _APP_CHARGE_H_
|
|
||||||
#define _APP_CHARGE_H_
|
|
||||||
|
|
||||||
#include "typedef.h"
|
|
||||||
#include "system/event.h"
|
|
||||||
|
|
||||||
extern void charge_close_deal(void);
|
|
||||||
extern void charge_start_deal(void);
|
|
||||||
extern void ldo5v_keep_deal(void);
|
|
||||||
extern void charge_full_deal(void);
|
|
||||||
extern void charge_ldo5v_in_deal(void);
|
|
||||||
extern void charge_ldo5v_off_deal(void);
|
|
||||||
extern u8 get_charge_full_flag(void);
|
|
||||||
|
|
||||||
extern int app_charge_event_handler(struct device_event *dev);
|
|
||||||
|
|
||||||
#endif //_APP_CHARGE_H_
|
|
||||||
@ -1,78 +0,0 @@
|
|||||||
#ifndef _APP_CHARGESTORE_H_
|
|
||||||
#define _APP_CHARGESTORE_H_
|
|
||||||
|
|
||||||
#include "typedef.h"
|
|
||||||
#include "system/event.h"
|
|
||||||
|
|
||||||
//LDOIN升级口命令定义
|
|
||||||
#define CMD_TWS_CHANNEL_SET 0x01
|
|
||||||
#define CMD_TWS_REMOTE_ADDR 0x02
|
|
||||||
#define CMD_TWS_ADDR_DELETE 0x03
|
|
||||||
#define CMD_BOX_TWS_CHANNEL_SEL 0x04//测试盒获取地址
|
|
||||||
#define CMD_BOX_TWS_REMOTE_ADDR 0x05//测试盒交换地址
|
|
||||||
#define CMD_POWER_LEVEL_OPEN 0x06//开盖充电舱报告/获取电量
|
|
||||||
#define CMD_POWER_LEVEL_CLOSE 0x07//合盖充电舱报告/获取电量
|
|
||||||
#define CMD_RESTORE_SYS 0x08//恢复出厂设置
|
|
||||||
#define CMD_ENTER_DUT 0x09//进入测试模式
|
|
||||||
#define CMD_EX_FIRST_READ_INFO 0x0A//F95读取数据首包信息
|
|
||||||
#define CMD_EX_CONTINUE_READ_INFO 0x0B//F95读取数据后续包信息
|
|
||||||
#define CMD_EX_FIRST_WRITE_INFO 0x0C//F95写入数据首包信息
|
|
||||||
#define CMD_EX_CONTINUE_WRITE_INFO 0x0D//F95写入数据后续包信息
|
|
||||||
#define CMD_EX_INFO_COMPLETE 0x0E//F95完成信息交换
|
|
||||||
#define CMD_TWS_SET_CHANNEL 0x0F//F95设置左右声道信息
|
|
||||||
#define CMD_BOX_UPDATE 0x20//测试盒升级
|
|
||||||
#define CMD_BOX_MODULE 0x21//测试盒一级命令
|
|
||||||
|
|
||||||
#define CMD_SHUT_DOWN 0x80//充电舱关机,充满电关机,或者是低电关机
|
|
||||||
#define CMD_CLOSE_CID 0x81//充电舱盒盖
|
|
||||||
#define CMD_ANC_MODULE 0x90//ANC一级命令
|
|
||||||
#define CMD_FAIL 0xfe//失败
|
|
||||||
#define CMD_UNDEFINE 0xff//未知命令回复
|
|
||||||
|
|
||||||
enum {
|
|
||||||
TWS_CHANNEL_LEFT = 1, //左耳
|
|
||||||
TWS_CHANNEL_RIGHT, //右耳
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
TWS_DEL_TWS_ADDR = 1, //删除对箱地址
|
|
||||||
TWS_DEL_PHONE_ADDR,//删除手机地址
|
|
||||||
TWS_DEL_ALL_ADDR,//删除手机与对箱地址
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _CHARGE_STORE_INFO {
|
|
||||||
u8 tws_local_addr[6];
|
|
||||||
u8 tws_remote_addr[6];
|
|
||||||
u8 tws_mac_addr[6];
|
|
||||||
u32 search_aa;
|
|
||||||
u32 pair_aa;
|
|
||||||
u8 local_channel;
|
|
||||||
u16 device_ind;
|
|
||||||
u16 reserved_data;
|
|
||||||
} _GNU_PACKED_;
|
|
||||||
typedef struct _CHARGE_STORE_INFO CHARGE_STORE_INFO;
|
|
||||||
|
|
||||||
extern void chargestore_set_tws_channel_info(u8 channel);
|
|
||||||
extern bool chargestore_set_tws_remote_info(u8 *data, u8 len);
|
|
||||||
extern u16 chargestore_get_tws_remote_info(u8 *data);
|
|
||||||
extern u8 chargestore_get_power_level(void);
|
|
||||||
extern u8 chargestore_get_power_status(void);
|
|
||||||
extern u8 chargestore_get_cover_status(void);
|
|
||||||
extern u8 chargestore_get_sibling_power_level(void);
|
|
||||||
extern void chargestore_set_bt_init_ok(u8 flag);
|
|
||||||
extern int app_chargestore_event_handler(struct chargestore_event *chargestore_dev);
|
|
||||||
extern u8 chargestore_get_earphone_online(void);
|
|
||||||
extern u8 chargestore_get_earphone_pos(void);
|
|
||||||
extern int chargestore_sync_chg_level(void);
|
|
||||||
extern void chargestore_set_power_level(u8 power);
|
|
||||||
extern void chargestore_set_sibling_chg_lev(u8 chg_lev);
|
|
||||||
extern void chargestore_set_phone_disconnect(void);
|
|
||||||
extern void chargestore_set_phone_connect(void);
|
|
||||||
extern u8 chargestore_check_going_to_poweroff(void);
|
|
||||||
extern void chargestore_shutdown_reset(void);
|
|
||||||
extern void testbox_set_testbox_tws_paired(u8 flag);
|
|
||||||
extern u8 testbox_get_testbox_tws_paired(void);
|
|
||||||
extern u8 testbox_get_touch_trim_en(u8 *sec);
|
|
||||||
extern u8 testbox_get_softpwroff_after_paired(void);
|
|
||||||
|
|
||||||
#endif //_APP_CHARGESTORE_H_
|
|
||||||
@ -1,555 +0,0 @@
|
|||||||
#ifndef APP_CONFIG_H
|
|
||||||
#define APP_CONFIG_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 系统打印总开关
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define LIB_DEBUG 1 //1 //xtelllog 1是打开库打印
|
|
||||||
#define CONFIG_DEBUG_LIB(x) (x & LIB_DEBUG)
|
|
||||||
|
|
||||||
#define CONFIG_DEBUG_ENABLE //xtelllog 注释就关闭log
|
|
||||||
|
|
||||||
#ifndef CONFIG_DEBUG_ENABLE
|
|
||||||
//#define CONFIG_DEBUG_LITE_ENABLE //轻量级打印开关, 默认关闭
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//*********************************************************************************//
|
|
||||||
// AI配置 //
|
|
||||||
//*********************************************************************************//
|
|
||||||
#define CONFIG_APP_BT_ENABLE
|
|
||||||
|
|
||||||
#ifdef CONFIG_APP_BT_ENABLE
|
|
||||||
#define TRANS_DATA_EN 0
|
|
||||||
#define RCSP_BTMATE_EN 0
|
|
||||||
#define RCSP_ADV_EN 1
|
|
||||||
#define AI_APP_PROTOCOL 0
|
|
||||||
#define LL_SYNC_EN 0
|
|
||||||
#define TUYA_DEMO_EN 0
|
|
||||||
#else
|
|
||||||
#define TRANS_DATA_EN 1
|
|
||||||
#define RCSP_BTMATE_EN 0
|
|
||||||
#define RCSP_ADV_EN 0
|
|
||||||
#define AI_APP_PROTOCOL 0
|
|
||||||
#define LL_SYNC_EN 0
|
|
||||||
#define TUYA_DEMO_EN 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "board_config.h"
|
|
||||||
#ifdef TCFG_AUDIO_CVP_NS_MODE
|
|
||||||
#if (TCFG_AUDIO_CVP_NS_MODE==CVP_DNS_MODE) || (TCFG_KWS_VOICE_RECOGNITION_ENABLE == 1)||(TCFG_AUDIO_ANC_ENABLE==1&&TCFG_AUDIO_DUAL_MIC_ENABLE==1)
|
|
||||||
#undef CONFIG_MOVABLE_ENABLE
|
|
||||||
#define CONFIG_MOVABLE_ENABLE //省ram空间,将部分ram空间的代码挪到flash
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(TCFG_CVP_DEVELOP_ENABLE) && (TCFG_CVP_DEVELOP_ENABLE == 1)
|
|
||||||
#undef CONFIG_MOVABLE_ENABLE
|
|
||||||
#define CONFIG_MOVABLE_ENABLE //省ram空间,将部分ram空间的代码挪到flash
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CONFIG_UPDATE_WITH_MD5_CHECK_EN
|
|
||||||
#define UPDATE_MD5_ENABLE 1
|
|
||||||
#else
|
|
||||||
#define UPDATE_MD5_ENABLE 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//升级需要打开CONFIG_APP_OTA_ENABLE,同时单双备份的配置也在board_xxx_global_cfg里配置,需要注意只有JL_RCSP才支持单备份,其余升级都是只支持双备份升级
|
|
||||||
//支持TWS同步升级,OTA_TWS_SAME_TIME_NEW宏需要配置为1,旧的流程已不再支持
|
|
||||||
#if (RCSP_ADV_EN) //rcsp需要打开ble
|
|
||||||
#define JL_EARPHONE_APP_EN 1
|
|
||||||
// #define CONFIG_CHARGESTORE_REMAP_ENABLE //充电仓重映射接收函数使能
|
|
||||||
#if CONFIG_APP_OTA_ENABLE
|
|
||||||
#define RCSP_UPDATE_EN 1 //是否支持rcsp升级
|
|
||||||
#if CONFIG_DOUBLE_BANK_ENABLE //双备份才能打开同步升级流程
|
|
||||||
#define OTA_TWS_SAME_TIME_ENABLE 1 //是否支持TWS同步升级
|
|
||||||
#define OTA_TWS_SAME_TIME_NEW 1 //使用新的tws ota流程
|
|
||||||
#else
|
|
||||||
#define OTA_TWS_SAME_TIME_ENABLE 1//0 xtellota //是否支持TWS同步升级
|
|
||||||
#define OTA_TWS_SAME_TIME_NEW 1//0 //使用新的tws ota流程
|
|
||||||
#endif //CONFIG_DOUBLE_BANK_ENABLE
|
|
||||||
#else
|
|
||||||
#define RCSP_UPDATE_EN 0 //是否支持rcsp升级
|
|
||||||
#define OTA_TWS_SAME_TIME_ENABLE 0 //是否支持TWS同步升级
|
|
||||||
#define OTA_TWS_SAME_TIME_NEW 0 //使用新的tws ota流程
|
|
||||||
#endif
|
|
||||||
#undef TCFG_USER_BLE_ENABLE
|
|
||||||
#define TCFG_USER_BLE_ENABLE 1 //BLE功能使能
|
|
||||||
#elif (AI_APP_PROTOCOL)
|
|
||||||
#define BT_MIC_EN 0
|
|
||||||
#define OTA_TWS_SAME_TIME_ENABLE 0 //是否支持TWS同步升级
|
|
||||||
#elif (LL_SYNC_EN)
|
|
||||||
#define JL_EARPHONE_APP_EN 0
|
|
||||||
#define OTA_TWS_SAME_TIME_ENABLE 1
|
|
||||||
#define OTA_TWS_SAME_TIME_NEW 1 //使用新的tws ota流程
|
|
||||||
#elif (TUYA_DEMO_EN)
|
|
||||||
#define JL_EARPHONE_APP_EN 0
|
|
||||||
#define OTA_TWS_SAME_TIME_ENABLE 0
|
|
||||||
#define OTA_TWS_SAME_TIME_NEW 0 //使用新的tws ota流程
|
|
||||||
#else
|
|
||||||
#define JL_EARPHONE_APP_EN 0
|
|
||||||
#define OTA_TWS_SAME_TIME_ENABLE 0
|
|
||||||
#define OTA_TWS_SAME_TIME_NEW 0 //使用新的tws ota流程
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CONFIG_MEDIA_LIB_USE_MALLOC 1
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "usb_std_class_def.h"
|
|
||||||
|
|
||||||
#undef USB_MALLOC_ENABLE
|
|
||||||
#define USB_MALLOC_ENABLE 1
|
|
||||||
///USB 配置重定义
|
|
||||||
// #undef USB_DEVICE_CLASS_CONFIG
|
|
||||||
// #define USB_DEVICE_CLASS_CONFIG (AUDIO_CLASS)
|
|
||||||
/////要确保 上面 undef 后在include usb
|
|
||||||
#include "usb_common_def.h"
|
|
||||||
|
|
||||||
#define USB_PC_NO_APP_MODE 0
|
|
||||||
|
|
||||||
#if ((TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE) \
|
|
||||||
&& TCFG_CHARGESTORE_PORT == IO_PORT_DP)
|
|
||||||
#undef TCFG_OTG_MODE
|
|
||||||
#define TCFG_OTG_MODE (TCFG_OTG_MODE_HOST|TCFG_OTG_MODE_SLAVE|TCFG_OTG_MODE_CHARGE|OTG_DET_DM_ONLY)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "btcontroller_mode.h"
|
|
||||||
|
|
||||||
#include "user_cfg_id.h"
|
|
||||||
|
|
||||||
#ifndef __LD__
|
|
||||||
#include "bt_profile_cfg.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// #ifdef CONFIG_APP_BT_ENABLE
|
|
||||||
// #if(APP_ONLINE_DEBUG)
|
|
||||||
// #error "they can not enable at the same time,just select one!!!"
|
|
||||||
// #endif
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_SDFILE_ENABLE
|
|
||||||
|
|
||||||
#define SDFILE_DEV "sdfile"
|
|
||||||
#define SDFILE_MOUNT_PATH "mnt/sdfile"
|
|
||||||
|
|
||||||
#if (USE_SDFILE_NEW)
|
|
||||||
#define SDFILE_APP_ROOT_PATH SDFILE_MOUNT_PATH"/app/" //app分区
|
|
||||||
#define SDFILE_RES_ROOT_PATH SDFILE_MOUNT_PATH"/res/" //资源文件分区
|
|
||||||
#else
|
|
||||||
#define SDFILE_RES_ROOT_PATH SDFILE_MOUNT_PATH"/C/"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define STYLE_JL_WTACH (1)//彩屏demo
|
|
||||||
#define STYLE_JL_SOUNDBOX (2)//点阵屏demo
|
|
||||||
#define STYLE_JL_CHARGE (3)//点阵屏充电仓
|
|
||||||
#define STYLE_JL_LED7 (4)//led7
|
|
||||||
#define STYLE_UI_SIMPLE (5)//没有ui框架
|
|
||||||
|
|
||||||
|
|
||||||
//*********************************************************************************//
|
|
||||||
// 测试模式配置 //
|
|
||||||
//*********************************************************************************//
|
|
||||||
#if (CONFIG_BT_MODE != BT_NORMAL)
|
|
||||||
#undef TCFG_BD_NUM
|
|
||||||
#define TCFG_BD_NUM 1
|
|
||||||
|
|
||||||
#undef TCFG_USER_TWS_ENABLE
|
|
||||||
#define TCFG_USER_TWS_ENABLE 0 //tws功能使能
|
|
||||||
|
|
||||||
#undef TCFG_USER_BLE_ENABLE
|
|
||||||
#define TCFG_USER_BLE_ENABLE 1 //BLE功能使能
|
|
||||||
|
|
||||||
#undef TCFG_AUTO_SHUT_DOWN_TIME
|
|
||||||
#define TCFG_AUTO_SHUT_DOWN_TIME 0
|
|
||||||
|
|
||||||
#undef TCFG_SYS_LVD_EN
|
|
||||||
#define TCFG_SYS_LVD_EN 0
|
|
||||||
|
|
||||||
#undef TCFG_LOWPOWER_LOWPOWER_SEL
|
|
||||||
#define TCFG_LOWPOWER_LOWPOWER_SEL 0
|
|
||||||
|
|
||||||
#undef TCFG_AUDIO_DAC_LDO_VOLT
|
|
||||||
#define TCFG_AUDIO_DAC_LDO_VOLT DUT_AUDIO_DAC_LDO_VOLT
|
|
||||||
|
|
||||||
#undef TCFG_LOWPOWER_POWER_SEL
|
|
||||||
#define TCFG_LOWPOWER_POWER_SEL PWR_LDO15
|
|
||||||
|
|
||||||
#undef TCFG_PWMLED_ENABLE
|
|
||||||
#define TCFG_PWMLED_ENABLE DISABLE_THIS_MOUDLE
|
|
||||||
|
|
||||||
#undef TCFG_ADKEY_ENABLE
|
|
||||||
#define TCFG_ADKEY_ENABLE DISABLE_THIS_MOUDLE
|
|
||||||
|
|
||||||
#undef TCFG_IOKEY_ENABLE
|
|
||||||
#define TCFG_IOKEY_ENABLE DISABLE_THIS_MOUDLE
|
|
||||||
|
|
||||||
#undef TCFG_TEST_BOX_ENABLE
|
|
||||||
#define TCFG_TEST_BOX_ENABLE 0
|
|
||||||
|
|
||||||
#undef TCFG_AUTO_SHUT_DOWN_TIME
|
|
||||||
#define TCFG_AUTO_SHUT_DOWN_TIME 0
|
|
||||||
|
|
||||||
#undef TCFG_POWER_ON_NEED_KEY
|
|
||||||
#define TCFG_POWER_ON_NEED_KEY 0
|
|
||||||
|
|
||||||
/* #undef TCFG_UART0_ENABLE
|
|
||||||
#define TCFG_UART0_ENABLE DISABLE_THIS_MOUDLE */
|
|
||||||
dzfghsdfhgsfgh
|
|
||||||
#endif //(CONFIG_BT_MODE != BT_NORMAL)
|
|
||||||
|
|
||||||
|
|
||||||
#if TCFG_USER_TWS_ENABLE
|
|
||||||
|
|
||||||
#define CONFIG_TWS_COMMON_ADDR_AUTO 0 /* 自动生成TWS配对后的MAC地址 */
|
|
||||||
#define CONFIG_TWS_COMMON_ADDR_USED_LEFT 1 /* 使用左耳的MAC地址作为TWS配对后的地址
|
|
||||||
可配合烧写器MAC地址自增功能一起使用
|
|
||||||
多台交叉配对会出现MAC地址相同情况 */
|
|
||||||
#define CONFIG_TWS_COMMON_ADDR_SELECT CONFIG_TWS_COMMON_ADDR_AUTO
|
|
||||||
|
|
||||||
//*********************************************************************************//
|
|
||||||
// 对耳配置方式配置 //
|
|
||||||
//*********************************************************************************//
|
|
||||||
#define CONFIG_TWS_CONNECT_SIBLING_TIMEOUT 4 /* 开机或超时断开后对耳互连超时时间,单位s */
|
|
||||||
// #define CONFIG_TWS_REMOVE_PAIR_ENABLE [> 不连手机的情况下双击按键删除配对信息 <]
|
|
||||||
#define CONFIG_TWS_POWEROFF_SAME_TIME 1 /*按键关机时两个耳机同时关机*/
|
|
||||||
|
|
||||||
#define ONE_KEY_CTL_DIFF_FUNC 1 /*通过左右耳实现一个按键控制两个功能*/
|
|
||||||
#define CONFIG_TWS_SCO_ONLY_MASTER 0 /*通话的时候只有主机出声音*/
|
|
||||||
|
|
||||||
/* 配对方式选择 */
|
|
||||||
#define CONFIG_TWS_PAIR_BY_CLICK 0 /* 按键发起配对 */
|
|
||||||
#define CONFIG_TWS_PAIR_BY_AUTO 1 /* 开机自动配对 */
|
|
||||||
#define CONFIG_TWS_PAIR_BY_FAST_CONN 2 /* 开机快速连接,连接速度比自动配对快,不支持取消配对操作 */
|
|
||||||
#define CONFIG_TWS_PAIR_MODE CONFIG_TWS_PAIR_BY_AUTO
|
|
||||||
|
|
||||||
|
|
||||||
/* 声道确定方式选择 */
|
|
||||||
#define CONFIG_TWS_MASTER_AS_LEFT 0 //主机作为左耳
|
|
||||||
#define CONFIG_TWS_AS_LEFT_CHANNEL 1 //固定左耳
|
|
||||||
#define CONFIG_TWS_AS_RIGHT_CHANNEL 2 //固定右耳
|
|
||||||
#define CONFIG_TWS_LEFT_START_PAIR 3 //双击发起配对的耳机做左耳
|
|
||||||
#define CONFIG_TWS_RIGHT_START_PAIR 4 //双击发起配对的耳机做右耳
|
|
||||||
#define CONFIG_TWS_EXTERN_UP_AS_LEFT 5 //外部有上拉电阻作为左耳
|
|
||||||
#define CONFIG_TWS_EXTERN_DOWN_AS_LEFT 6 //外部有下拉电阻作为左耳
|
|
||||||
#define CONFIG_TWS_SECECT_BY_CHARGESTORE 7 //充电仓决定左右耳
|
|
||||||
#define CONFIG_TWS_CHANNEL_SELECT CONFIG_TWS_LEFT_START_PAIR //配对方式选择
|
|
||||||
|
|
||||||
#define CONFIG_TWS_CHANNEL_CHECK_IO IO_PORTA_07 //上下拉电阻检测引脚
|
|
||||||
|
|
||||||
|
|
||||||
#if CONFIG_TWS_PAIR_MODE != CONFIG_TWS_PAIR_BY_CLICK
|
|
||||||
#if (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_LEFT_START_PAIR) ||\
|
|
||||||
(CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_RIGHT_START_PAIR)
|
|
||||||
#undef CONFIG_TWS_CHANNEL_SELECT
|
|
||||||
#define CONFIG_TWS_CHANNEL_SELECT CONFIG_TWS_MASTER_AS_LEFT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_AUTO
|
|
||||||
#define CONFIG_TWS_AUTO_PAIR_WITHOUT_UNPAIR /* 不取消配对也可以配对新的耳机 */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_FAST_CONN
|
|
||||||
#undef CONFIG_TWS_REMOVE_PAIR_ENABLE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CONFIG_A2DP_GAME_MODE_ENABLE 0 //游戏模式
|
|
||||||
#define CONFIG_A2DP_GAME_MODE_DELAY_TIME 35 //游戏模式延时ms
|
|
||||||
|
|
||||||
//*********************************************************************************//
|
|
||||||
// 低延时游戏模式脚步声、枪声增强,需使能蓝牙音乐10段eq以及蓝牙音乐drc
|
|
||||||
// 用户开关宏AUDIO_GAME_EFFECT_CONFIG(开关蓝牙低延时模式的游戏音效)
|
|
||||||
// 低延时eq效果文件使用eq_game_eff.bin,调试时需保存成该文件,并在批处理-res后添加
|
|
||||||
// 非低延时eq效果文件使用eq_cfg_hw.bin,也需在批处理-res后添加
|
|
||||||
//*********************************************************************************//
|
|
||||||
#if CONFIG_A2DP_GAME_MODE_ENABLE
|
|
||||||
#define AUDIO_GAME_EFFECT_CONFIG 1 //低延时游戏模式脚步声、枪声增强 1:使能、0:关闭
|
|
||||||
#else
|
|
||||||
#define AUDIO_GAME_EFFECT_CONFIG 0 //低延时游戏模式脚步声、枪声增强 1:使能、0:关闭
|
|
||||||
#endif
|
|
||||||
/***********************************非用户配置区***********************************/
|
|
||||||
//以下宏定义,是游戏音效使能后,需要开启的宏定义,已配好,用户不用修改
|
|
||||||
#if AUDIO_GAME_EFFECT_CONFIG
|
|
||||||
#if (TCFG_EQ_ENABLE == 0)
|
|
||||||
#undef TCFG_EQ_ENABLE
|
|
||||||
#define TCFG_EQ_ENABLE 1
|
|
||||||
#endif/* (TCFG_EQ_ENABLE == 0) */
|
|
||||||
#if (TCFG_BT_MUSIC_EQ_ENABLE == 0)
|
|
||||||
#undef TCFG_BT_MUSIC_EQ_ENABLE
|
|
||||||
#define TCFG_BT_MUSIC_EQ_ENABLE 1
|
|
||||||
#endif/*(TCFG_BT_MUSIC_EQ_ENABLE == 0)*/
|
|
||||||
#if (TCFG_DRC_ENABLE == 0)
|
|
||||||
#undef TCFG_DRC_ENABLE
|
|
||||||
#define TCFG_DRC_ENABLE 1
|
|
||||||
#endif/* (TCFG_DRC_ENABLE == 0) */
|
|
||||||
#if (TCFG_BT_MUSIC_DRC_ENABLE == 0)
|
|
||||||
#undef TCFG_BT_MUSIC_DRC_ENABLE
|
|
||||||
#define TCFG_BT_MUSIC_DRC_ENABLE 1
|
|
||||||
#endif/* (TCFG_BT_MUSIC_DRC_ENABLE == 0) */
|
|
||||||
#if (EQ_SECTION_MAX < 10)
|
|
||||||
#undef EQ_SECTION_MAX
|
|
||||||
#define EQ_SECTION_MAX 10
|
|
||||||
#endif/* (EQ_SECTION_MAX < 10) */
|
|
||||||
#if (TCFG_USE_EQ_FILE == 0)
|
|
||||||
#undef TCFG_USE_EQ_FILE
|
|
||||||
#define TCFG_USE_EQ_FILE 1
|
|
||||||
#endif/* TCFG_USE_EQ_FILE */
|
|
||||||
#endif/* AUDIO_GAME_EFFECT_CONFIG */
|
|
||||||
/**********************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if CONFIG_TWS_PAIR_MODE == CONFIG_TWS_PAIR_BY_CLICK
|
|
||||||
#define CONFIG_TWS_BY_CLICK_PAIR_WITHOUT_PAIR /*双击按键可以配对已配对过的样机,即交叉配对 */
|
|
||||||
#ifdef CONFIG_TWS_BY_CLICK_PAIR_WITHOUT_PAIR
|
|
||||||
#define CONFIG_TWS_AUTO_PAIR_WITHOUT_UNPAIR /* 不取消配对也可以配对新的耳机 */
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if TCFG_CHARGESTORE_ENABLE
|
|
||||||
#undef CONFIG_TWS_CHANNEL_SELECT
|
|
||||||
#define CONFIG_TWS_CHANNEL_SELECT CONFIG_TWS_SECECT_BY_CHARGESTORE //充电仓区分左右
|
|
||||||
#endif //TCFG_CHARGESTORE_ENABLE
|
|
||||||
|
|
||||||
#if TCFG_TEST_BOX_ENABLE && (!TCFG_CHARGESTORE_ENABLE)
|
|
||||||
#define CONFIG_TWS_SECECT_CHARGESTORE_PRIO 1 //测试盒配置左右耳优先
|
|
||||||
#else
|
|
||||||
#define CONFIG_TWS_SECECT_CHARGESTORE_PRIO 0
|
|
||||||
#endif //TCFG_TEST_BOX_ENABLE
|
|
||||||
|
|
||||||
//*********************************************************************************//
|
|
||||||
// 对耳电量显示方式 //
|
|
||||||
//*********************************************************************************//
|
|
||||||
|
|
||||||
#if BT_SUPPORT_DISPLAY_BAT
|
|
||||||
#define CONFIG_DISPLAY_TWS_BAT_LOWER 1 //对耳手机端电量显示,显示低电量耳机的电量
|
|
||||||
#define CONFIG_DISPLAY_TWS_BAT_HIGHER 2 //对耳手机端电量显示,显示高电量耳机的电量
|
|
||||||
#define CONFIG_DISPLAY_TWS_BAT_LEFT 3 //对耳手机端电量显示,显示左耳的电量
|
|
||||||
#define CONFIG_DISPLAY_TWS_BAT_RIGHT 4 //对耳手机端电量显示,显示右耳的电量
|
|
||||||
|
|
||||||
#define CONFIG_DISPLAY_TWS_BAT_TYPE CONFIG_DISPLAY_TWS_BAT_LOWER
|
|
||||||
#endif //BT_SUPPORT_DISPLAY_BAT
|
|
||||||
|
|
||||||
#define CONFIG_DISPLAY_DETAIL_BAT 0 //BLE广播显示具体的电量
|
|
||||||
#define CONFIG_NO_DISPLAY_BUTTON_ICON 1 //BLE广播不显示按键界面,智能充电仓置1
|
|
||||||
|
|
||||||
#endif //TCFG_USER_TWS_ENABLE
|
|
||||||
|
|
||||||
#ifndef CONFIG_BT_RX_BUFF_SIZE
|
|
||||||
#define CONFIG_BT_RX_BUFF_SIZE (14 * 1024)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_APP_BT_ENABLE
|
|
||||||
#if TCFG_BT_SUPPORT_AAC || TCFG_BT_SUPPORT_LDAC
|
|
||||||
#define CONFIG_BT_TX_BUFF_SIZE (5 * 1024)
|
|
||||||
#else
|
|
||||||
#define CONFIG_BT_TX_BUFF_SIZE (4 * 1024)
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#if TCFG_BT_SUPPORT_AAC || TCFG_BT_SUPPORT_LDAC
|
|
||||||
#define CONFIG_BT_TX_BUFF_SIZE (4 * 1024)
|
|
||||||
#else
|
|
||||||
#define CONFIG_BT_TX_BUFF_SIZE (3 * 1024)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef CONFIG_NEW_BREDR_ENABLE
|
|
||||||
|
|
||||||
#if TCFG_USER_TWS_ENABLE
|
|
||||||
|
|
||||||
#ifdef CONFIG_LOCAL_TWS_ENABLE
|
|
||||||
#define CONFIG_TWS_BULK_POOL_SIZE (4 * 1024)
|
|
||||||
#else
|
|
||||||
#define CONFIG_TWS_BULK_POOL_SIZE (2 * 1024)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if (CONFIG_BT_MODE != BT_NORMAL)
|
|
||||||
////bqb 如果测试3M tx buf 最好加大一点
|
|
||||||
#undef CONFIG_BT_TX_BUFF_SIZE
|
|
||||||
#define CONFIG_BT_TX_BUFF_SIZE (6 * 1024)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//*********************************************************************************//
|
|
||||||
// 电源切换配置 //
|
|
||||||
//*********************************************************************************//
|
|
||||||
|
|
||||||
#define PHONE_CALL_USE_LDO15 CONFIG_PHONE_CALL_USE_LDO15
|
|
||||||
|
|
||||||
//*********************************************************************************//
|
|
||||||
// 时钟切换配置 //
|
|
||||||
//*********************************************************************************//
|
|
||||||
#define BT_NORMAL_HZ CONFIG_BT_NORMAL_HZ
|
|
||||||
#define BT_CONNECT_HZ CONFIG_BT_CONNECT_HZ
|
|
||||||
|
|
||||||
#define BT_A2DP_HZ CONFIG_BT_A2DP_HZ
|
|
||||||
|
|
||||||
#define BT_CALL_HZ CONFIG_BT_CALL_HZ
|
|
||||||
#define BT_CALL_ADVANCE_HZ CONFIG_BT_CALL_ADVANCE_HZ
|
|
||||||
#define BT_CALL_16k_HZ CONFIG_BT_CALL_16k_HZ
|
|
||||||
#define BT_CALL_16k_ADVANCE_HZ CONFIG_BT_CALL_16k_ADVANCE_HZ
|
|
||||||
|
|
||||||
|
|
||||||
#define MUSIC_DEC_FASTEST_CLOCK CONFIG_MUSIC_DEC_FASTEST_CLOCK
|
|
||||||
#define MUSIC_DEC_FAST_CLOCK CONFIG_MUSIC_DEC_FAST_CLOCK
|
|
||||||
#define MUSIC_DEC_CLOCK CONFIG_MUSIC_DEC_CLOCK
|
|
||||||
#define MUSIC_DEC_IDLE_CLOCK CONFIG_MUSIC_IDLE_CLOCK
|
|
||||||
#define MUSIC_FSCAN_CLOCK CONFIG_MUSIC_FSCAN_CLOCK
|
|
||||||
#define LINEIN_CLOCK CONFIG_LINEIN_CLOCK
|
|
||||||
#define FM_CLOCK CONFIG_FM_CLOCK
|
|
||||||
#define FM_EMITTER_CLOCK CONFIG_FM_EMITTER_CLOCK
|
|
||||||
#define PC_CLOCK CONFIG_PC_CLOCK
|
|
||||||
#define RECODRD_CLOCK CONFIG_RECORD_CLOCK
|
|
||||||
#define SPDIF_CLOCK CONFIG_SPDIF_CLOCK
|
|
||||||
|
|
||||||
////////////////////////
|
|
||||||
#if TCFG_BT_SUPPORT_AAC || TCFG_BT_SUPPORT_LDAC
|
|
||||||
#define BT_A2DP_STEREO_EQ_HZ 48 * 1000000L
|
|
||||||
#else
|
|
||||||
#define BT_A2DP_STEREO_EQ_HZ 32 * 1000000L
|
|
||||||
#endif
|
|
||||||
#define BT_A2DP_AAC_HZ 48 * 1000000L
|
|
||||||
#define BT_A2DP_TWS_AAC_HZ 64 * 1000000L
|
|
||||||
#define BT_A2DP_MONO_EQ_HZ 32 * 1000000L
|
|
||||||
#define BT_A2DP_ONLINE_EQ_HZ 48 * 1000000L
|
|
||||||
|
|
||||||
#define BT_CALL_SIMPLEX_HZ 96 * 1000000L
|
|
||||||
#ifdef CONFIG_ANS_V2
|
|
||||||
//#define BT_CALL_16k_HZ 96 * 1000000L
|
|
||||||
//#define BT_CALL_16k_ADVANCE_HZ 120 * 1000000L
|
|
||||||
#else
|
|
||||||
//#define BT_CALL_16k_HZ 80 * 1000000L
|
|
||||||
//#define BT_CALL_16k_ADVANCE_HZ 96 * 1000000L
|
|
||||||
#endif
|
|
||||||
#define BT_CALL_16k_SIMPLEX_HZ 120 * 1000000L
|
|
||||||
////////////////////////
|
|
||||||
|
|
||||||
#ifdef CONFIG_FPGA_ENABLE
|
|
||||||
|
|
||||||
// #undef TCFG_CLOCK_OSC_HZ
|
|
||||||
// #define TCFG_CLOCK_OSC_HZ 12000000
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_CPU_BR26
|
|
||||||
#undef BT_CALL_16k_HZ
|
|
||||||
#undef BT_CALL_16k_ADVANCE_HZ
|
|
||||||
#define BT_CALL_16k_HZ 96 * 1000000L
|
|
||||||
#define BT_CALL_16k_ADVANCE_HZ 96 * 1000000L
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_CPU_BR23
|
|
||||||
#undef BT_A2DP_STEREO_EQ_HZ
|
|
||||||
#define BT_A2DP_STEREO_EQ_HZ 48 * 1000000L
|
|
||||||
#undef BT_A2DP_MONO_EQ_HZ
|
|
||||||
#define BT_A2DP_MONO_EQ_HZ 48 * 1000000L
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_CPU_BR25
|
|
||||||
#undef BT_A2DP_STEREO_EQ_HZ
|
|
||||||
#define BT_A2DP_STEREO_EQ_HZ 48 * 1000000L
|
|
||||||
#undef BT_A2DP_MONO_EQ_HZ
|
|
||||||
#define BT_A2DP_MONO_EQ_HZ 48 * 1000000L
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_FPGA_ENABLE
|
|
||||||
|
|
||||||
// #undef TCFG_CLOCK_OSC_HZ
|
|
||||||
// #define TCFG_CLOCK_OSC_HZ 12000000
|
|
||||||
|
|
||||||
#undef TCFG_MC_BIAS_AUTO_ADJUST
|
|
||||||
#define TCFG_MC_BIAS_AUTO_ADJUST MC_BIAS_ADJUST_DISABLE
|
|
||||||
|
|
||||||
#endif
|
|
||||||
//*********************************************************************************//
|
|
||||||
// 低功耗配置 //
|
|
||||||
//*********************************************************************************//
|
|
||||||
#if TCFG_IRKEY_ENABLE
|
|
||||||
#undef TCFG_LOWPOWER_LOWPOWER_SEL
|
|
||||||
#define TCFG_LOWPOWER_LOWPOWER_SEL 0 //开红外不进入低功耗
|
|
||||||
#endif /* #if TCFG_IRKEY_ENABLE */
|
|
||||||
|
|
||||||
//*********************************************************************************//
|
|
||||||
// LED使用 16SLOT TIMER 同步 //
|
|
||||||
//*********************************************************************************//
|
|
||||||
//LED模块使用slot timer同步使用注意点:
|
|
||||||
// 1.soundbox不开该功能, 原因: 默认打开osc时钟, 使用原来的osc流程同步即可
|
|
||||||
// 2.带sd卡earphone不开该功能, 一般为单耳, 不需要同步, 使用原来的流程(lrc)
|
|
||||||
// 3.一般用在tws应用中, 而且默认关闭osc;
|
|
||||||
#if TCFG_USER_TWS_ENABLE
|
|
||||||
#define TCFG_PWMLED_USE_SLOT_TIME ENABLE_THIS_MOUDLE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//*********************************************************************************//
|
|
||||||
// 升级配置 //
|
|
||||||
//*********************************************************************************//
|
|
||||||
//升级LED显示使能
|
|
||||||
#define UPDATE_LED_REMIND
|
|
||||||
//升级提示音使能
|
|
||||||
#define UPDATE_VOICE_REMIND
|
|
||||||
|
|
||||||
#ifndef CONFIG_UPDATE_JUMP_TO_MASK
|
|
||||||
#define CONFIG_UPDATE_JUMP_TO_MASK 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CONFIG_UPDATE_JUMP_TO_MASK
|
|
||||||
//升级IO保持使能
|
|
||||||
#define DEV_UPDATE_SUPPORT_JUMP //目前只有br23\br25支持
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if TCFG_APP_MUSIC_EN
|
|
||||||
#define CONFIG_SD_UPDATE_ENABLE
|
|
||||||
#define CONFIG_USB_UPDATE_ENABLE
|
|
||||||
#endif
|
|
||||||
//*********************************************************************************//
|
|
||||||
// Audio配置 //
|
|
||||||
//*********************************************************************************//
|
|
||||||
|
|
||||||
#if TCFG_AUDIO_ANC_ENABLE
|
|
||||||
#if ((defined VOL_TYPE_ANALOG) && (SYS_VOL_TYPE == VOL_TYPE_ANALOG)) || \
|
|
||||||
((defined VOL_TYPE_AD) && (SYS_VOL_TYPE == VOL_TYPE_AD))
|
|
||||||
#error "ANC can not use VOL_TYPE_ANALOG and VOL_TYPE_AD!!!"
|
|
||||||
#endif/*(SYS_VOL_TYPE = VOL_TYPE_ANALOG) || (SYS_VOL_TYPE = VOL_TYPE_AD)*/
|
|
||||||
#endif/*TCFG_AUDIO_ANC_ENABLE*/
|
|
||||||
|
|
||||||
/*通话语音处理算法放在.data段*/
|
|
||||||
#ifndef TCFG_AUDIO_CVP_CODE_AT_RAM
|
|
||||||
#define TCFG_AUDIO_CVP_CODE_AT_RAM 1
|
|
||||||
#endif/*TCFG_AUDIO_CVP_CODE_AT_RAM*/
|
|
||||||
|
|
||||||
/*AAC解码算法放在.data段*/
|
|
||||||
#ifndef TCFG_AUDIO_AAC_CODE_AT_RAM
|
|
||||||
#define TCFG_AUDIO_AAC_CODE_AT_RAM 1
|
|
||||||
#endif/*TCFG_AUDIO_AAC_CODE_AT_RAM*/
|
|
||||||
|
|
||||||
#if (TCFG_AUDIO_DUAL_MIC_ENABLE && TCFG_AUDIO_TRIPLE_MIC_ENABLE)
|
|
||||||
#error "TCFG_AUDIO_DUAL_MIC_ENABLE and TCFG_AUDIO_TRIPLE_MIC_ENABLE can not enable together !!!"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//*********************************************************************************//
|
|
||||||
// 充电中按键清除手机配对信息配置 //
|
|
||||||
//*********************************************************************************//
|
|
||||||
|
|
||||||
#define CHARGING_CLEAN_PHONE_INFO 0
|
|
||||||
|
|
||||||
|
|
||||||
#define PC_MODE_DETECTION
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,90 +0,0 @@
|
|||||||
#ifndef APP_MAIN_H
|
|
||||||
#define APP_MAIN_H
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
float talk;
|
|
||||||
float ff;
|
|
||||||
float fb;
|
|
||||||
} audio_mic_cmp_t;
|
|
||||||
|
|
||||||
typedef struct _APP_VAR {
|
|
||||||
s8 bt_volume;
|
|
||||||
s8 dev_volume;
|
|
||||||
s8 music_volume;
|
|
||||||
s8 call_volume;
|
|
||||||
s8 wtone_volume;
|
|
||||||
u8 opid_play_vol_sync;
|
|
||||||
u8 aec_dac_gain;
|
|
||||||
u8 aec_mic_gain;
|
|
||||||
u8 aec_mic1_gain;
|
|
||||||
u8 aec_mic2_gain;
|
|
||||||
u8 aec_mic3_gain;
|
|
||||||
u8 rf_power;
|
|
||||||
u8 goto_poweroff_flag;
|
|
||||||
u8 goto_poweroff_cnt;
|
|
||||||
u8 play_poweron_tone;
|
|
||||||
u8 remote_dev_company;
|
|
||||||
u8 siri_stu;
|
|
||||||
u8 cycle_mode;
|
|
||||||
u8 have_mass_storage;
|
|
||||||
int auto_stop_page_scan_timer; //用于1拖2时,有一台连接上后,超过三分钟自动关闭Page Scan
|
|
||||||
volatile int auto_shut_down_timer;
|
|
||||||
volatile int wait_exit_timer;
|
|
||||||
u16 auto_off_time;
|
|
||||||
u16 warning_tone_v;
|
|
||||||
u16 poweroff_tone_v;
|
|
||||||
u16 phone_dly_discon_time;
|
|
||||||
u8 usb_mic_gain;
|
|
||||||
int wait_timer_do;
|
|
||||||
u32 start_time;
|
|
||||||
float audio_mic_array_diff_cmp;//麦克风阵列补偿值
|
|
||||||
u8 audio_mic_array_trim_en; //麦克风阵列校准
|
|
||||||
audio_mic_cmp_t audio_mic_cmp;
|
|
||||||
float enc_degradation;//default:1,range[0:1]
|
|
||||||
/*3麦通话配置使用:选择第几个mic*/
|
|
||||||
u8 talk_mic_ch; //主MIC通道选择
|
|
||||||
u8 talk_ref_mic_ch; //副MIC通道选择
|
|
||||||
u8 talk_fb_mic_ch; //FB通道选择
|
|
||||||
} APP_VAR;
|
|
||||||
|
|
||||||
typedef struct _BT_USER_PRIV_VAR {
|
|
||||||
//phone
|
|
||||||
u8 phone_ring_flag: 1;
|
|
||||||
u8 phone_num_flag: 1;
|
|
||||||
u8 phone_income_flag: 1;
|
|
||||||
u8 phone_call_dec_begin: 1;
|
|
||||||
u8 phone_con_sync_num_ring: 1;
|
|
||||||
u8 phone_con_sync_ring: 1;
|
|
||||||
// u8 reserved: 2;
|
|
||||||
u8 emitter_or_receiver: 2;
|
|
||||||
u8 get_phone_num_timecnt;
|
|
||||||
|
|
||||||
u8 inband_ringtone;
|
|
||||||
u8 phone_vol;
|
|
||||||
u16 phone_timer_id;
|
|
||||||
u8 last_call_type;
|
|
||||||
u8 income_phone_num[30];
|
|
||||||
u8 income_phone_len;
|
|
||||||
s32 auto_connection_counter;
|
|
||||||
int auto_connection_timer;
|
|
||||||
u8 auto_connection_addr[6];
|
|
||||||
int tws_con_timer;
|
|
||||||
u8 tws_start_con_cnt;
|
|
||||||
u8 tws_conn_state;
|
|
||||||
bool search_tws_ing;
|
|
||||||
int sniff_timer;
|
|
||||||
bool fast_test_mode;
|
|
||||||
} BT_USER_PRIV_VAR;
|
|
||||||
|
|
||||||
#define BT_EMITTER_EN 1
|
|
||||||
#define BT_RECEIVER_EN 2
|
|
||||||
|
|
||||||
typedef struct _BT_USER_COMM_VAR {
|
|
||||||
} BT_USER_COMM_VAR;
|
|
||||||
|
|
||||||
extern APP_VAR app_var;
|
|
||||||
extern BT_USER_PRIV_VAR bt_user_priv_var;
|
|
||||||
|
|
||||||
#define earphone (&bt_user_priv_var)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
#ifndef CONFIG_APP_MUSIC_H
|
|
||||||
#define CONFIG_APP_MUSIC_H
|
|
||||||
|
|
||||||
void app_music_exit();
|
|
||||||
int music_app_check(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
#ifndef ONLINE_CONFIG_H
|
|
||||||
#define ONLINE_CONFIG_H
|
|
||||||
|
|
||||||
#define DEVICE_EVENT_FROM_CI_UART (('C' << 24) | ('I' << 16) | ('U' << 8) | '\0')
|
|
||||||
#define DEVICE_EVENT_FROM_CI_TWS (('C' << 24) | ('I' << 16) | ('T' << 8) | '\0')
|
|
||||||
|
|
||||||
#define CI_UART 0
|
|
||||||
#define CI_TWS 1
|
|
||||||
|
|
||||||
void ci_data_rx_handler(u8 type);
|
|
||||||
u32 eq_cfg_sync(u8 priority);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
#ifndef APP_POWER_MANAGE_H
|
|
||||||
#define APP_POWER_MANAGE_H
|
|
||||||
|
|
||||||
#include "typedef.h"
|
|
||||||
#include "system/event.h"
|
|
||||||
|
|
||||||
#define LOW_POWER_SHUTDOWN 300 //低电直接关机电压-拔出不开机-开盖不开机
|
|
||||||
#define LOW_POWER_OFF_VAL 330 //低电关机电压
|
|
||||||
#define LOW_POWER_WARN_VAL 340 //低电提醒电压
|
|
||||||
#define LOW_POWER_WARN_TIME (60 * 1000) //低电提醒时间
|
|
||||||
|
|
||||||
#define DEVICE_EVENT_FROM_POWER (('P' << 24) | ('O' << 16) | ('W' << 8) | '\0')
|
|
||||||
|
|
||||||
enum {
|
|
||||||
POWER_EVENT_POWER_NORMAL,
|
|
||||||
POWER_EVENT_POWER_WARNING,
|
|
||||||
POWER_EVENT_POWER_LOW,
|
|
||||||
POWER_EVENT_POWER_CHANGE,
|
|
||||||
POWER_EVENT_SYNC_TWS_VBAT_LEVEL,
|
|
||||||
POWER_EVENT_POWER_CHARGE,
|
|
||||||
};
|
|
||||||
|
|
||||||
int app_power_event_handler(struct device_event *dev);
|
|
||||||
void check_power_on_voltage(void);
|
|
||||||
u16 get_vbat_level(void);
|
|
||||||
u8 get_vbat_percent(void);
|
|
||||||
void vbat_check_init(void);
|
|
||||||
void vbat_timer_update(u32 msec);
|
|
||||||
void vbat_timer_delete(void);
|
|
||||||
void tws_sync_bat_level(void);
|
|
||||||
u8 get_tws_sibling_bat_level(void);
|
|
||||||
u8 get_tws_sibling_bat_persent(void);
|
|
||||||
bool get_vbat_need_shutdown(void);
|
|
||||||
u8 get_self_battery_level(void);
|
|
||||||
|
|
||||||
void app_power_set_tws_sibling_bat_level(u8 vbat, u8 percent);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
#ifndef CONFIG_APP_SD_MUSIC_H
|
|
||||||
#define CONFIG_APP_SD_MUSIC_H
|
|
||||||
|
|
||||||
int music_app_check(void);//music 在线检测 切换模式判断使用
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
#ifndef APP_TASK_H
|
|
||||||
#define APP_TASK_H
|
|
||||||
|
|
||||||
#include "typedef.h"
|
|
||||||
#define NULL_VALUE 0
|
|
||||||
|
|
||||||
enum {
|
|
||||||
APP_BT_TASK,
|
|
||||||
#if TCFG_APP_MUSIC_EN
|
|
||||||
APP_MUSIC_TASK,
|
|
||||||
#endif
|
|
||||||
#if TCFG_PC_ENABLE
|
|
||||||
APP_PC_TASK,
|
|
||||||
#endif
|
|
||||||
#if TCFG_APP_AUX_EN
|
|
||||||
APP_AUX_TASK,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
extern u8 app_curr_task;
|
|
||||||
extern u8 app_next_task;
|
|
||||||
extern u8 app_prev_task;
|
|
||||||
|
|
||||||
int app_task_switch_check(u8 app_task);
|
|
||||||
int app_core_back_to_prev_app_over_check(void);
|
|
||||||
int app_task_switch_to(u8 app_task, int priv);
|
|
||||||
void app_task_switch_next(void);
|
|
||||||
void app_task_switch_prev(void);
|
|
||||||
u8 app_get_curr_task(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
#ifndef _APP_TESTBOX_H_
|
|
||||||
#define _APP_TESTBOX_H_
|
|
||||||
|
|
||||||
#include "typedef.h"
|
|
||||||
#include "system/event.h"
|
|
||||||
|
|
||||||
extern void testbox_set_bt_init_ok(u8 flag);
|
|
||||||
extern u8 testbox_get_status(void);
|
|
||||||
extern void testbox_clear_status(void);
|
|
||||||
extern u8 testbox_get_ex_enter_dut_flag(void);
|
|
||||||
extern u8 testbox_get_ex_enter_storage_mode_flag(void);
|
|
||||||
extern u8 testbox_get_connect_status(void);
|
|
||||||
extern void testbox_clear_connect_status(void);
|
|
||||||
extern u8 testbox_get_keep_tws_conn_flag(void);
|
|
||||||
extern int app_testbox_event_handler(struct testbox_event *testbox_dev);
|
|
||||||
|
|
||||||
|
|
||||||
#endif //_APP_TESTBOX_H_
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
#ifndef _APP_UMIDIGI_CHARGESTORE_H_
|
|
||||||
#define _APP_UMIDIGI_CHARGESTORE_H_
|
|
||||||
|
|
||||||
#include "typedef.h"
|
|
||||||
#include "system/event.h"
|
|
||||||
#include "board_config.h"
|
|
||||||
|
|
||||||
/*******************************UMIDIGI充电舱数据包格式*****************************/
|
|
||||||
/*
|
|
||||||
* |<--1bit-->||<-------4bits----->||<--------------8bits------------>||<--1bit-->||<--1bits-->|
|
|
||||||
* |<-start-->||<-------CMD------->||<--------------DATA------------->|| crc_odd ||<--stop--->|
|
|
||||||
* | 14 || 13 | 12 | 11 | 10 || 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 || 1 || 0 |
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*充电舱发送的命令列表*/
|
|
||||||
#define CMD_RESERVED_0 0x00 //reserved
|
|
||||||
#define CMD_FACTORY_RESET 0x01 //恢复出厂设置
|
|
||||||
#define CMD_RESERVED_2 0x02 //reserved
|
|
||||||
#define CMD_OPEN_CASE 0x03 //充电舱开盖
|
|
||||||
#define CMD_CLOSE_CASE 0x04 //充电舱关盖
|
|
||||||
#define CMD_ENTER_PAIRING_MODE 0x06 //进入配对模式
|
|
||||||
#define CMD_DUT_MODE_CMD 0x08 //进入DUT模式
|
|
||||||
#define CMD_USB_STATE 0x0A //USB状态
|
|
||||||
#define CMD_RESERVED_B 0x0B //reserved(RTK internal use)
|
|
||||||
#define CMD_SEND_CASE_BATTERY 0x0D //发送充电舱电量
|
|
||||||
|
|
||||||
/*message中的CMD与DATA位置,用于从一个完整的数据包中截取CMD和DATA*/
|
|
||||||
/*CMD_IN_MESSAGE = 0xf000*/
|
|
||||||
#define CMD_IN_MESSAGE (BIT(13) | BIT(12) | BIT(11) | BIT(10))
|
|
||||||
/*DATA_IN_MESSAGE = 0x0ff0*/
|
|
||||||
#define DATA_IN_MESSAGE (BIT(9) | BIT(8) | BIT(7) | BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2))
|
|
||||||
|
|
||||||
void app_umidigi_chargetore_message_deal(u16 message);
|
|
||||||
|
|
||||||
extern u8 umidigi_chargestore_get_power_level(void); //获取充电舱电池电量
|
|
||||||
extern u8 umidigi_chargestore_get_power_status(void); //获取充电舱充电状态
|
|
||||||
extern u8 umidigi_chargestore_get_cover_status(void); //获取充电舱合盖或开盖状态
|
|
||||||
extern u8 umidigi_chargestore_get_earphone_online(void); //获取合盖状态时耳机在仓数量
|
|
||||||
extern void umidigi_chargestore_set_bt_init_ok(u8 flag); //获取蓝牙初始化成功标志位
|
|
||||||
extern u8 umidigi_chargestore_check_going_to_poweroff(void); //获取允许poweroff标志位
|
|
||||||
extern void umidigi_chargestore_set_phone_disconnect(void);
|
|
||||||
extern void umidigi_chargestore_set_phone_connect(void);
|
|
||||||
extern void umidigi_chargestore_set_sibling_chg_lev(u8 chg_lev);//设置对耳同步的充电舱电量
|
|
||||||
extern void umidigi_chargestore_set_power_level(u8 power); //设置充电舱电池电量
|
|
||||||
extern int umidigi_chargestore_sync_chg_level(void);
|
|
||||||
|
|
||||||
extern int app_umidigi_chargestore_event_handler(struct umidigi_chargestore_event *umidigi_chargestore_dev);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
|
|
||||||
#ifndef __AUDIO_ENC_MPT_FRE_RESPONE_H_
|
|
||||||
#define __AUDIO_ENC_MPT_FRE_RESPONE_H_
|
|
||||||
|
|
||||||
#include "asm/cpu.h"
|
|
||||||
|
|
||||||
/********************用户配置****************************/
|
|
||||||
|
|
||||||
//计算长度 输入单位s16/输出单位float
|
|
||||||
#define AUDIO_ENC_MPT_FRERES_POINT 1024
|
|
||||||
|
|
||||||
/********************非用户配置****************************/
|
|
||||||
|
|
||||||
//MIC频响测试通道ID u16
|
|
||||||
#define AUDIO_ENC_MPT_FF_MIC 0X01 //测试TWS FFMIC or 头戴式LFF MIC
|
|
||||||
#define AUDIO_ENC_MPT_FB_MIC 0X02 //测试TWS FBMIC or 头戴式LFB MIC
|
|
||||||
#define AUDIO_ENC_MPT_RFF_MIC 0X04 //测试头戴式RFF MIC
|
|
||||||
#define AUDIO_ENC_MPT_RFB_MIC 0X08 //测试头戴式RFB MIC
|
|
||||||
#define AUDIO_ENC_MPT_CVP_OUT 0X10 //测试通话算法输出
|
|
||||||
#define AUDIO_ENC_MPT_TALK_MIC 0X20 //测试通话TALK 主MIC
|
|
||||||
#define AUDIO_ENC_MPT_SLAVE_MIC 0X40 //测试通话TALK 副MIC
|
|
||||||
#define AUDIO_ENC_MPT_TALK_FB_MIC 0X80 //测试通话TALK FBMIC
|
|
||||||
|
|
||||||
//常见通道组合
|
|
||||||
//FF+TALK+算法输出频响测试,默认关闭DNS, 外部喇叭发声
|
|
||||||
#define AUDIO_ENC_MPT_CH_TWS_CVP_ENC (AUDIO_ENC_MPT_SLAVE_MIC | AUDIO_ENC_MPT_TALK_MIC | AUDIO_ENC_MPT_CVP_OUT)
|
|
||||||
|
|
||||||
//FF回声/气密性+FB频响测试,耳机喇叭发声
|
|
||||||
#define AUDIO_ENC_MPT_CH_TWS_FF_FB (AUDIO_ENC_MPT_FF_MIC | AUDIO_ENC_MPT_FB_MIC)
|
|
||||||
|
|
||||||
|
|
||||||
#define AUDIO_ENC_MPT_FRERES_ASYNC 1 //是否异步处理, 异步算不过来要加时钟提醒
|
|
||||||
|
|
||||||
enum {
|
|
||||||
ENC_FRE_RES_STATE_START = 0,
|
|
||||||
ENC_FRE_RES_STATE_RUN,
|
|
||||||
ENC_FRE_RES_STATE_STOP,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
ENC_FRE_RESPONE_MSG_RUN = 0xA1,
|
|
||||||
};
|
|
||||||
|
|
||||||
//更新目标通道输入buf、len
|
|
||||||
void audio_enc_mpt_fre_response_inbuf(u16 id, s16 *buf, int len);
|
|
||||||
|
|
||||||
//音频测试频响计算运行
|
|
||||||
void audio_enc_mpt_fre_response_post_run(u16 id);
|
|
||||||
|
|
||||||
//音频测试频响计算启动, ch 对应目标的通道
|
|
||||||
void audio_enc_mpt_fre_response_start(u16 ch);
|
|
||||||
|
|
||||||
//音频测试频响计算停止
|
|
||||||
void audio_enc_mpt_fre_response_stop(void);
|
|
||||||
|
|
||||||
//工具获取数据文件
|
|
||||||
int audio_enc_mpt_fre_response_file_get(u8 **buf);
|
|
||||||
|
|
||||||
//数据获取结束,释放内存
|
|
||||||
void audio_enc_mpt_fre_response_release(void);
|
|
||||||
|
|
||||||
//音频测试MIC频响开启, ch 对应目标的通道
|
|
||||||
void audio_enc_mpt_fre_response_open(u16 ch);
|
|
||||||
|
|
||||||
//音频测试MIC频响关闭
|
|
||||||
void audio_enc_mpt_fre_response_close(void);
|
|
||||||
|
|
||||||
#endif /*__AUDIO_ENC_MPT_FRE_RESPONE_H_*/
|
|
||||||
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
#ifndef BT_BACKGROUND_H
|
|
||||||
#define BT_BACKGROUND_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "generic/typedef.h"
|
|
||||||
|
|
||||||
bool bt_in_background();
|
|
||||||
|
|
||||||
|
|
||||||
void bt_switch_to_foreground(int action, bool exit_curr_app);
|
|
||||||
|
|
||||||
|
|
||||||
int bt_switch_to_background();
|
|
||||||
|
|
||||||
|
|
||||||
void bt_stop_a2dp_slience_detect();
|
|
||||||
|
|
||||||
|
|
||||||
void bt_start_a2dp_slience_detect(int ingore_packet_num);
|
|
||||||
|
|
||||||
|
|
||||||
int bt_background_event_probe_handler(struct bt_event *bt);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user