活动介绍

static uint16_t CRC16(const uint8_t *arr_buff,uint16_t len)根据函数原型写函数

时间: 2024-09-24 11:23:57 浏览: 184
这是一个C语言的函数原型,它计算给定数组(arr_buff)及其长度(len)的CRC16校验和。CRC16是一种常用的循环冗余校验算法,用于检测数据传输过程中的错误。函数返回一个16位的无符号整数,即CRC16的结果。 ```c static uint16_t CRC16(const uint8_t *arr_buff, uint16_t len) { uint16_t crc = 0xFFFF; // 初始化CRC值为所有位全为1 const uint8_t* end = arr_buff + len; for (; arr_buff != end; ++arr_buff) { crc ^= (*arr_buff); // 现场异或当前字节 for (int i = 0; i < 8; ++i) { if ((crc & 0x8000) != 0) { // 如果最低位为1 crc = (crc << 1) ^ CRCTable[0]; // 计算新的CRC值,表 lookup 和左移 } else { crc <<= 1; // 否则只做左移 } } } return crc; // 返回最终的CRC16结果 } // 这里假设CRCTable是一个预定义的CRC16查表,例如CCITT标准的CRC16-CCITT ```
相关问题

static uint16_t CRC16(const uint8_t *arr_buff,uint16_t len)根据函数原型写函数,不查表

这是一个简单的CRC16(循环冗余校验)函数的实现,它使用了标准的二进制除法算法。CRC16是一种常见的数据错误检测方法,给定一个输入缓冲区`arr_buff`和其长度`len`,函数会计算并返回一个16位的CRC值。 ```c static uint16_t CRC16(const uint8_t *arr_buff, uint16_t len) { uint16_t crc = 0xFFFF; // 初始化CRC值为所有位全为1,表示无数据 const uint8_t poly = 0x1021; // 使用Xilinx CRC16的标准生成多项式 for (uint16_t i = 0; i < len; ++i) { crc ^= arr_buff[i]; // 异或当前字节到CRC上 for (int j = 8; j != 0; --j) { if (crc & 0x0001) // 如果最低位是1 { crc >>= 1; crc ^= poly; // 将CRC左移一位,并异或多项式 } else { crc >>= 1; // 否则只做左移 } } } return crc; // 返回最终的CRC值 } ```

union alignas(1) DataFrame { struct { uint8_t head; uint8_t dest_addr; uint8_t func_code; uint8_t checksum[2]; uint8_t data_len; uint8_t data[0]; }; uint8_t arr[5]; };

<think>嗯,用户给了一个关于联合体定义的问题,我需要仔细分析。首先,用户提供的代码是一个C++的union,名字是DataFrame,并且用了alignas(1)来指定对齐方式。联合体内部有一个匿名结构体和一个数组arr[5]。 首先,我得理解alignas(1)的作用。alignas是C++11引入的内存对齐说明符,这里设置为1,意味着联合体的对齐方式被强制为1字节。通常,结构体或联合体会根据成员中最大的对齐需求来对齐,但这里强制为1,可能为了紧密排列数据,节省空间或者与某些硬件要求匹配。 然后看联合体的成员。匿名结构体包含head、dest_addr、func_code、checksum数组(两个元素)、data_len和data[0]。另一个成员是uint8_t的数组arr[5]。联合体的特点是所有成员共享同一块内存,所以结构体和arr[5]会共享相同的内存空间,大小由最大的成员决定。但这里结构体的大小可能需要计算。 计算结构体的大小:每个uint8_t占1字节,head到data_len共5个成员,分别是1+1+1+2+1=6字节,加上data[0],这是一个柔性数组,在C中用于动态大小,但在C++中可能用不同的方式实现。但柔性数组本身不计入结构体大小,所以结构体的大小是6字节。而arr[5]是5字节的数组。联合体的大小应该是最大成员的大小,也就是6字节?但这里arr[5]是5字节,结构体是6字节,所以联合体的大小应该是6字节,但arr[5]只有5,可能会有问题。可能用户代码中存在错误? 不过用户提供的代码中,arr是5元素,而结构体部分有6字节,这样联合体的总大小应该是6字节。此时,arr[5]访问到第5个元素时,可能超出其数组范围,但C++中联合体允许不同大小的成员,访问时需注意有效性。 接下来,这个结构可能用于通信协议的数据帧解析。比如,结构体中的各个字段对应数据帧的不同部分,head是帧头,dest_addr是目标地址,func_code是功能码,checksum是校验和,data_len是数据长度,data是实际数据。使用联合体可以方便地通过数组方式访问整个数据帧,或者通过结构体字段访问各部分。 但这里存在潜在问题:arr的大小只有5字节,而结构体实际需要至少6字节(head到data_len),这会导致arr无法覆盖整个结构体的内存,访问arr[5]时会越界。可能用户代码中的arr应该是arr[6],或者结构体中的某些字段被调整,比如checksum可能是一个uint16_t而不是两个uint8_t,这样结构体的大小可能变为5字节,和arr[5]匹配。或者用户可能有笔误,需要进一步确认。 此外,data[0]是柔性数组,在C++中通常不建议使用,而是使用C++的动态容器,但可能在特定场景下用于表示可变长度的数据部分。但在这个联合体中,柔性数组的存在可能影响整体大小计算,需要注意。 总结,用户可能是在尝试定义一个通信协议的数据帧结构,通过联合体方便地以数组或结构体方式访问数据。但代码中存在大小不匹配的问题,可能导致未定义行为。需要指出这些问题,并解释正确的用法和潜在应用场景。</think>关于这个联合体定义的分析可分为以下几个层面: 1. **内存布局解析** ```cpp union alignas(1) DataFrame { // 强制1字节对齐 struct { // 总大小计算: uint8_t head; // 1字节 uint8_t dest_addr; // +1 =2 uint8_t func_code; // +1 =3 uint8_t checksum[2]; // +2 =5 uint8_t data_len; // +1 =6 uint8_t data[0]; // 柔性数组(不占空间) }; uint8_t arr[5]; // 总大小=5字节 }; // 联合体实际大小=6字节(存在内存越界风险) ``` * 存在结构体与数组大小不一致的问题(结构体实际需要6字节,数组仅5字节) 2. **典型应用场景** - 串口通信协议解析(如Modbus) - 网络封包格式处理 - 嵌入式设备寄存器映射 - 二进制数据格式转换 3. **代码问题警示** - **内存越界**:通过arr[5]访问时,索引4对应data_len,索引5已越界 - **柔性数组误用**:C++标准不支持[0]长度数组,应使用C++17的`std::byte data[];` - **对齐冲突**:checksum[2]要求连续存储,但某些架构可能要求偶数地址对齐 - **大小端问题**:checksum若作为uint16_t处理时需注意字节序 4. **改进建议方案** ```cpp #pragma pack(push, 1) // 精确控制结构体对齐 union DataFrame { struct { uint8_t head; uint8_t dest_addr; uint8_t func_code; uint16_t checksum; // 合并为16位 uint8_t data_len; std::byte data[]; // C++17标准柔性数组 }; std::array<uint8_t, 6> header; // 明确大小 }; #pragma pack(pop) ``` 改进点说明: - 使用`#pragma pack`替代alignas实现更精确控制 - 合并checksum为16位整型 - 采用标准柔性数组语法 - 添加header数组明确头部结构 5. **典型应用示例** ```cpp void parse_packet(const uint8_t* raw, size_t len) { DataFrame* df = reinterpret_cast<DataFrame*>(raw); if(df->data_len != len - 6) { // 校验数据长度 throw std::runtime_error("Invalid packet"); } // 访问示例: std::cout << "目标地址: 0x" << std::hex << (int)df->dest_addr << " 功能码: " << std::dec << (int)df->func_code; } ``` 该结构体设计常见于以下场景: - 工业控制系统的RS485通信 - 物联网设备数据传输 - CAN总线消息处理 - 蓝牙低功耗(BLE)特征值解析 需特别注意:直接内存映射可能存在安全风险(缓冲区溢出),建议配合范围检查使用。
阅读全文

相关推荐

#include "stm32f10x.h" #include "buzzer.h" void Delay_ms(uint32_t ms) { volatile uint32_t i, j; for (i = 0; i < ms; i++) { for (j = 0; j < 1000; j++); } } int main(void) { // ????? SystemInit(); Buzzer_Init(); while (1) { // ?????? for (uint16_t freq = 200; freq <= 2000; freq += 100) { Change_Tone(freq); Delay_ms(300000); } for (uint16_t freq = 2000; freq >= 200; freq -= 100) { Change_Tone(freq); Delay_ms(300000); } // ???? Play_Song(birthday_notes, birthday_durations, 25); Delay_ms(300000); // ???? } return 0; } #ifndef __BUZZER_H #define __BUZZER_H #include "stm32f10x.h" // ?????(Hz) extern const uint16_t tone_freq[]; // ???? extern const uint8_t birthday_notes[]; extern const uint8_t birthday_durations[]; // ???? void Buzzer_Init(void); void Change_Tone(uint16_t freq); void Play_Song(const uint8_t* notes, const uint8_t* durations, uint8_t len); #endif /* __BUZZER_H */ #include "buzzer.h" // C??????? const uint16_t tone_freq[] = { 0, 262, 294, 330, 349, 392, 440, 494, 523 }; // ??????? const uint8_t birthday_notes[] = { 1,1,2,1,5,4, 1,1,2,1,6,5, 1,1,8,6,4,3,2, 7,7,6,4,5,4 }; const uint8_t birthday_durations[] = { 2,2,2,2,4,4, 2,2,2,2,4,4, 2,2,4,4,4,4,2, 2,2,4,4,4,4 }; // ????(??SysTick????????) static void Delay_ms(uint32_t ms) { uint32_t i; for (i = 0; i < ms; i++) { __asm("nop"); __asm("nop"); __asm("nop"); } } void Buzzer_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; // ?????? RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // ??PB10??????? GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); // ??????????200Hz-2000Hz???? uint16_t prescaler = 72 - 1; // 72MHz / 72 = 1MHz???? uint16_t max_arr = 1000000 / 200 - 1; // 200Hz???ARR?(4999) // ?????? TIM_TimeBaseStructure.TIM_Period = max_arr; TIM_TimeBaseStructure.TIM_Prescaler = prescaler; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // ??PWM?? TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = max_arr / 2; // 50%?????? TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC3Init(TIM2, &TIM_OCInitStructure); TIM_Cmd(TIM2, ENABLE); } // ?????? #define MIN_FREQ 100 // ??????(Hz) #define MAX_FREQ 10000 // ??????(Hz) void Change_Tone(uint16_t freq) { // ?????? if (freq == 0) { TIM_SetCompare3(TIM2, 0); // ??PWM?? return; } // ?????? if (freq < MIN_FREQ) { freq = MIN_FREQ; // ?????? // ????????? } else if (freq > MAX_FREQ) { freq = MAX_FREQ; // ?????? // ????????? } // ???????????? uint32_t arr_calc = 1000000 / freq; // 1MHz / ?? // ?????? if (arr_calc > 65535) { arr_calc = 65535; // ????? // ????????? } uint16_t arr = (uint16_t)arr_calc; uint16_t compare = arr / 2; // 50%??? // ??????? TIM_SetAutoreload(TIM2, arr); TIM_SetCompare3(TIM2, compare); } // ???? void Play_Song(const uint8_t* notes, const uint8_t* durations, uint8_t len) { for (uint8_t i = 0; i < len; i++) { uint16_t freq = tone_freq[notes[i]]; Change_Tone(freq); Delay_ms(durations[i] * 500); // ?????? Change_Tone(0); // ???? Delay_ms(1000); } } 为什么蜂鸣器不发出声响,可以正常烧录,也没有报错

..\Core\Src\bsp\user\bsp_user.c(44): warning: #177-D: variable "src_index" was declared but never referenced uint16_t src_index = 0; ..\Core\Src\bsp\user\bsp_user.c: 1 warning, 0 errors#include "user\bsp_user.h" #include "main.h" uint16_t src_index ; // ADC变量 #define ADC_BUFFER_SIZE 256 #define WAVEFORM_POINTS 200 uint16_t adc_arr[ADC_BUFFER_SIZE] = {0}; // 波形采集变量 uint16_t waveform_buffer[WAVEFORM_POINTS]; volatile bool waveform_ready = false; volatile bool dma_complete = false; // DMA传输完成回调函数 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { if (hadc->Instance == ADC1) { dma_complete = true; } } void Hardware_Init(void) { delay_init(72); MX_USART2_UART_Init(); MX_DMA_Init(); MX_ADC1_Init(); // 初始化全局变量 uart_disp_point_Tick = 0; // 在函数中初始化 // 启动带中断的DMA传输 HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_arr, ADC_BUFFER_SIZE); HAL_UART_Receive_IT(&huart2, &rx_data, 1); } // 波形采集处理 void Process_ADC_Data(void) { if (!dma_complete) return; dma_complete = false; // 改进的重采样算法 const float resample_ratio = (float)ADC_BUFFER_SIZE / WAVEFORM_POINTS; uint16_t src_index = 0; for (uint16_t i = 0; i < WAVEFORM_POINTS; i++) { // 计算源数据索引范围 const uint16_t start_idx = (uint16_t)(i * resample_ratio); const uint16_t end_idx = (uint16_t)((i + 1) * resample_ratio); // 取范围中值作为采样点 const uint16_t mid_idx = (start_idx + end_idx) / 2; if (mid_idx < ADC_BUFFER_SIZE) { waveform_buffer[i] = adc_arr[mid_idx]; } } waveform_ready = true; HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_arr, ADC_BUFFER_SIZE); } // 发送波形数据到串口屏 void Send_Waveform_Data(void) { if (!waveform_ready) return; char cmd_buffer[50]; // 1. 清除现有波形 sprintf(cmd_buffer, "cle 1,0\xff\xff\xff"); HAL_UART_Transmit(&huart2, (uint8_t*)cmd_buffer, strlen(cmd_buffer), 100); // 2. 发送波形数据点 for (int i = 0; i < WAVEFORM_POINTS; i++) { // 转换为电压值 (0-3300mV) const uint16_t voltage_mv = (uint16_t)(waveform_buffer[i] * 3300.0f / 4095.0f); // 发送到串口屏 sprintf(cmd_buffer, "add 1,%d,%d\xff\xff\xff", i, voltage_mv); HAL_UART_Transmit(&huart2, (uint8_t*)cmd_buffer, strlen(cmd_buffer), 10); } waveform_ready = false; } // 串口显示处理 (修复未使用变量问题) void uart_disp_proc(void) { // 每100ms刷新一次 if (HAL_GetTick() - uart_disp_point_Tick < 100) return; uart_disp_point_Tick = HAL_GetTick(); // 直接发送波形数据,移除未使用的last_wave_send变量 Send_Waveform_Data(); }

#include "Blood_OxygenDetection.h" #ifdef _WIN64 #define MATLAB_PLOT (1) uint8_t spo2_plot_flag = 0; #include <cstdlib> #include <string> #include <iomanip> #include <fstream> using namespace std; #include "plot_bymatlab.h" #include <iomanip> #include <cstdio> #include <iostream> #endif // _WIN64 #define RED_IRD_SIGNAL_LEN ( 125 ) #define SPO2_SIGNAL_SAMPLE ( 25 ) #define SPO2_SIG_SEC ( RED_IRD_SIGNAL_LEN / SPO2_SIGNAL_SAMPLE ) #define SIG_MAP_TH ( 10 ) #define SIG_SATURATION ( 65000 ) #define SPO2_FILTER_LEN ( 7 ) #define SPO2_RATE_ARR_LEN ( 10 ) #define SPO2_AC_RATE_LEN ( 10 ) #define SPO2_RATE_COMPENSATE1 ( 50 ) //对应血氧值100 #define SPO2_RATE_COMPENSATE2 ( 56 ) //对应血氧值99 int64_t oxy_band_bz[SPO2_FILTER_LEN] = { 1809, 0, -5430, 0, 5429, 0, -1810 }; int64_t oxy_band_az[SPO2_FILTER_LEN] = { 100000, -452867, 873235, -923467, 567242, -191903, 27805 }; int64_t oxy_band_zi[SPO2_FILTER_LEN - 1] = { -6253,13873,-19506,21536,-9103 - 574 }; //int64_t oxy_band_bz[SPO2_FILTER_LEN] = { 1462 ,0, -4388, 0 , 4387 , 0 ,-1463 }; //int64_t oxy_band_az[SPO2_FILTER_LEN] = { 100000 ,- 452947, 881212, -946581 , 593706, -206172, 30917 }; //int64_t oxy_band_zi[SPO2_FILTER_LEN - 1] = { -2944 , 3766 ,-4901 , 9123 ,-4060 ,-1005 }; uint8_t spo2_res_arr_check[20] = { 0 }; bod_result_info_t bod_info_s = { 0 }; uint8_t spo2_cnt = 0; uint8_t spo2_calc_cnt = 0; uint8_t spo2_res_mark = 0; int32_t change_rate_value = 0; uint8_t spo2_res_wave_flag[2] = { 0,0 }; uint8_t kalman_last_data = 0; uint8_t spo2_smooth_temp[3] = { 0,0,0 }; uint8_t spo2_real_value_cnt = 0; int32_t spo2_rate_arr[SPO2_RATE_ARR_LEN] = { 0 }; int32_t last_spo2_rate = 0; uint8_t last_spo2_out = 0; uint8_t spo2_rate_std_30_cnt = 0; int32_t spo2_ac_rate_arr[SPO2_AC_RATE_LEN] = { 0 }; int32_t spo2_ac_mean_arr[SPO2_AC_RAT

#include "math.h" #include "main.h" #include "user\bsp_user.h" #include "string.h" // 系统配置 #define ADC_SAMPLES 1024 // ADC采样点数 #define ADC_REF_VOLTAGE 3.3f // ADC参考电压(V) #define ADC_RESOLUTION 4095.0f // 12位ADC分辨率 #define DC_BIAS 1.125f // DC偏置电压 #define DISPLAY_POINTS 100 // 串口屏显示点数 #define UART_BAUDRATE 115200 // 串口波特率 // ADC双缓冲区 (DMA对齐) __attribute__((aligned(4))) uint16_t adc_buffer1[ADC_SAMPLES]; __attribute__((aligned(4))) uint16_t adc_buffer2[ADC_SAMPLES]; volatile uint8_t active_buffer = 0; // 当前活动缓冲区 volatile uint8_t buffer_ready = 0; // 缓冲区就绪标志 // ADC变量 uint16_t adc_arr[adc_N] = {0}; double adc_arr1[adc_N] = {0}; // adc转换后的值0-3.3V // 卡尔曼滤波器 typedef struct { float x; // 状态估计 float p; // 估计误差协方差 float q; // 过程噪声协方差 float r; // 测量噪声协方差 } KalmanFilter; KalmanFilter voltage_kalman; // 电压卡尔曼滤波器实例 // 显示缓冲区 float display_data[DISPLAY_POINTS]; // 降采样后的显示数据 uint16_t display_index = 0; // 显示数据索引 // 串口屏指令 const char screen_header[] = "wave="; const char screen_footer[] = "\xFF\xFF\xFF"; // 初始化卡尔曼滤波器 void KalmanFilter_Init(KalmanFilter *kf, float initial_x, float initial_p, float q, float r) { kf->x = initial_x; kf->p = initial_p; kf->q = q; kf->r = r; } // 更新卡尔曼滤波器 float KalmanFilter_Update(KalmanFilter *kf, float measurement) { // 预测步骤 kf->p = kf->p + kf->q; // 更新步骤 float k = kf->p / (kf->p + kf->r); // 卡尔曼增益 kf->x = kf->x + k * (measurement - kf->x); kf->p = (1 - k) * kf->p; return kf->x; } // ADC DMA传输完成回调 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { buffer_ready = 1; // 设置缓冲区就绪标志 // 切换活动缓冲区 active_buffer = 1 - active_buffer; // 启动下一次采集 if(active_buffer == 0) { HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer1, ADC_SAMPLES); } else { HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer2, ADC_SAMPLES); } } void Hardware_Init(void) { delay_init(72); MX_USART2_UART_Init(); KEY_Init(); MX_TIM3_Init(); MX_TIM4_Init(); // 按键 MX_DMA_Init(); // dma初始化要放在adc前面 MX_ADC1_Init(); HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_arr, adc_N); MX_DAC_Init(); HAL_TIM_Base_Start(&htim3); HAL_ADC_Start(&hadc1); HAL_TIM_Base_Start_IT(&htim4); Kalman1D_Init(&kf, 0.0f, 1.0f, 0.05f, 10.f); HAL_UART_Receive_IT(&huart2, &rx_data, 1); } // 处理ADC数据(硬件已实现五倍放大) void ProcessSignalData(uint16_t* buffer) { // 计算降采样步长 uint16_t step = ADC_SAMPLES / DISPLAY_POINTS; for (uint16_t i = 0; i < DISPLAY_POINTS; i++) { // 获取ADC原始值 uint16_t adc_value = buffer[i * step]; // 转换为电压值 (0-3.3V) float voltage = adc_value * ADC_REF_VOLTAGE / ADC_RESOLUTION; // 应用卡尔曼滤波稳定信号 voltage = KalmanFilter_Update(&voltage_kalman, voltage); // 确保电压在有效范围内 (0-3.3V) if (voltage < 0) voltage = 0; if (voltage > ADC_REF_VOLTAGE) voltage = ADC_REF_VOLTAGE; // 存储处理后的数据(硬件AD603已完成5倍放大) display_data[i] = voltage; } } // 发送数据到串口屏(优化版) void SendToDisplay(void) { static char output_buffer[800]; // 完整输出缓冲区(足够存储100个数据点) char* ptr = output_buffer; // 添加头部 memcpy(ptr, screen_header, strlen(screen_header)); ptr += strlen(screen_header); // 添加所有数据点 for (int i = 0; i < DISPLAY_POINTS; i++) { // 格式化电压值 (保留2位小数) int len = sprintf(ptr, "%.2f", display_data[i]); ptr += len; // 添加逗号分隔符(最后一个不加) if (i < DISPLAY_POINTS - 1) { *ptr++ = ','; } } // 添加结束符 memcpy(ptr, screen_footer, strlen(screen_footer)); ptr += strlen(screen_footer); // 计算总长度 size_t total_len = ptr - output_buffer; // 发送到串口屏 HAL_UART_Transmit(&huart2, (uint8_t*)output_buffer, total_len, HAL_MAX_DELAY); } // 主循环中的处理逻辑 void Main_Processing_Loop(void) { while (1) { if (buffer_ready) { // 获取已完成采集的缓冲区 uint16_t* buffer = active_buffer ? adc_buffer2 : adc_buffer1; // 处理信号数据 ProcessSignalData(buffer); // 发送到显示屏 SendToDisplay(); // 重置标志 buffer_ready = 0; } // 其他系统任务(如按键检测等) // ... } } 有可能是.c中出现错误

#define KEY1 HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3) #define KEY0 HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4) #define PPR 13 #define ENCODER_MULTIPLY 4 #define GEAR_RATIO 20 // 计算每圈对应的计数 #define COUNTS_PER_REV (PPR * ENCODER_MULTIPLY * GEAR_RATIO) #define PWM_MAX 1000 // PWM最大值 // 电机控制参数 float Kp1 = 3.8f, Ki1 = 1.1f, Kd1 = 0.015f; // PID参数 float Target_RPM1 = 0.0f; // 目标转速(RPM) float Actual_RPM1 = 0.0f; // 实际转速(RPM) float integral1 = 0.0f; // 积分项累积值 float Out1=0.0f; // 电机控制参数 float Kp2 = 3.85f, Ki2 = 1.0f, Kd2 = 0.001f; // PID参数 float Target_RPM2 = 0.0f; // 目标转速(RPM) float Actual_RPM2 = 0.0f; // 实际转速(RPM) float integral2 = 0.0f; // 积分项累积值 float Out2=0.0f; //float Target1=0, Actual1=0,Out1=0; //float Kp1=1.5; //float Ki1=0.02; //float Kd1=0.1; //float Error01=0,Error11=0,ErrorInt1=0,IntOut1=0; //float Target2=0, Actual2=0,Out2=0; //float Kp2=0.1; //float Ki2=0.0; //float Kd2=0.0; //float Error02=0,Error12=0,ErrorInt2=0,IntOut2=0; extern unsigned char Hzk[][32]; uint32_t ccr1_value=0; uint32_t arr1_value; uint32_t ccr2_value=0; uint32_t arr2_value; //unsigned int x=0; //int motor_direction; uint8_t num=0; uint8_t rx_data; //unsigned char* word1=(uint8_t *)"Speed1:"; //unsigned char* word2=(uint8_t *)"Target1:"; //unsigned char* word3=(uint8_t *)"Actual1:"; //unsigned char* word4=(uint8_t *)"Out1:"; //unsigned char* word5=(uint8_t *)"Speed2:"; //unsigned char* word6=(uint8_t *)"Target2:"; //unsigned char* word7=(uint8_t *)"Actual2:"; //unsigned char* word8=(uint8_t *)"Out2:"; uint16_t count1; uint16_t count2; float speed1=0.0; float speed2=0.0; //uint8_t str_buff[64]; //void Scan_Keys() // { // if(KEY0==GPIO_PIN_RESET) // { // HAL_Delay(100); // if(KEY0==GPIO_PIN_RESET) // { // while(KEY0==GPIO_PIN_RESET); // Target_RPM1+=130; // Target_RPM2+=130; // } // } // if(KEY1==GPIO_PIN_RESET) // { // HAL_Delay(100); // if(KEY1==GPIO_PIN_RESET) // { // while(KEY1==GPIO_PIN_RESET); // Target_RPM1-=100; // Target_RPM2-=100; // } // } // } //void OLED_display_info() //{ // OLED_Clear(); // OLED_ShowString(8,0,word1,sizeof(word1)); // OLED_ShowString(8,1,word2,sizeof(word2)); // OLED_ShowString(8,2,word3,sizeof(word3)); // OLED_ShowString(8,3,word4,sizeof(word4)); // OLED_ShowString(8,4,word5,sizeof(word5)); // OLED_ShowString(8,5,word6,sizeof(word6)); // OLED_ShowString(8,6,word7,sizeof(word7)); // OLED_ShowString(8,7,word8,sizeof(word8)); //// OLED_ShowString(8,4,word9,sizeof(word9)); //// OLED_ShowString(8,5,word10,sizeof(word10)); //// OLED_ShowString(8,6,word11,sizeof(word11)); //// OLED_ShowString(8,7,word12,sizeof(word12)); //// OLED_ShowCHinese(0,3,0); //// OLED_ShowCHinese(18,3,1); //// OLED_ShowCHinese(36,3,2); //// OLED_ShowCHinese(54,3,3); //// OLED_ShowCHinese(0,6,4); //// OLED_ShowCHinese(18,6,5); //// OLED_ShowCHinese(36,6,6); //// OLED_ShowCHinese(54,6,7); //} //void OLED_display_dat() //{ //// sprintf((char*)str_buff,"%5d",count); //// OLED_ShowString(64,2,str_buff,sizeof(str_buff)); //// //// arr1_value = __HAL_TIM_GET_AUTORELOAD(&htim1); //// float zkb = ((float)ccr1_value / arr1_value) * 100.0f; //// //// sprintf((char*)str_buff,"%+.0f",zkb); //// OLED_ShowString(64,3,str_buff,sizeof(str_buff)); // sprintf((char*)str_buff,"%+.0f",speed1); // OLED_ShowString(64,0,str_buff,sizeof(str_buff)); // // sprintf((char*)str_buff,"%+.0f",Target_RPM1); // OLED_ShowString(64,1,str_buff,sizeof(str_buff)); // // sprintf((char*)str_buff,"%+.0f",Actual_RPM1); // OLED_ShowString(64,2,str_buff,sizeof(str_buff)); // // sprintf((char*)str_buff,"%+.0f",Out1); // OLED_ShowString(64,3,str_buff,sizeof(str_buff)); // // sprintf((char*)str_buff,"%+.0f",speed2); // OLED_ShowString(64,4,str_buff,sizeof(str_buff)); // // sprintf((char*)str_buff,"%+.0f",Target_RPM2); // OLED_ShowString(64,5,str_buff,sizeof(str_buff)); // // sprintf((char*)str_buff,"%+.0f",Actual_RPM2); // OLED_ShowString(64,6,str_buff,sizeof(str_buff)); // // sprintf((char*)str_buff,"%+.0f",Out2); // OLED_ShowString(64,7,str_buff,sizeof(str_buff)); //} //uint16_t last_count1 = 0; //uint16_t last_time_ms1 = 0; //uint16_t last_count2 = 0; //uint16_t last_time_ms2 = 0; //void calculate_speed_1() //{ // count1 = __HAL_TIM_GET_COUNTER(&htim3); // uint16_t current_time_ms1 = HAL_GetTick(); // int16_t diff_count1 = count1 - last_count1; // float delta_time_sec1 = (current_time_ms1 - last_time_ms1) / 1000.0f; // // if (delta_time_sec1 > 0) // { // float rpm1 = ((float)diff_count1 / (float)COUNTS_PER_REV) * 60.0f / delta_time_sec1; // // speed1 = rpm1; // // Actual1=rpm1/2530.0f*100; // // Error11 = Error01; // Error01 = Target1 - Actual1; // //// ErrorInt += Error0; // IntOut1 += Ki1 * Error01; // // if(IntOut1>800)IntOut1=800; // if(IntOut1<0)IntOut1=0; // // Out1 = Kp1 * Error01 + IntOut1 + Kd1 * (Error01 - Error11); // // float OUT1 = Out1 * 8.0; // // if(OUT1 > 800)OUT1 = 800; // if(OUT1 < 0)OUT1 = 0; // //// __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,OUT1); // } // // last_count1 = count1; // last_time_ms1 = current_time_ms1; //} //void calculate_speed_2() //{ // count2 = __HAL_TIM_GET_COUNTER(&htim4); // uint16_t current_time_ms2 = HAL_GetTick(); // int16_t diff_count2 = count2 - last_count2; // float delta_time_sec2 = (current_time_ms2 - last_time_ms2) / 1000.0f; // // if (delta_time_sec2 > 0) // { // float rpm2 = ((float)diff_count2 / (float)COUNTS_PER_REV) * 60.0f / delta_time_sec2; // // speed2 = rpm2; // // Actual2=rpm2/2530.0f*100; // // Error12 = Error02; // Error02 = Target2 - Actual2; //// ErrorInt += Error0; // IntOut2 += Ki2 * Error02; // // if(IntOut2>800)IntOut2=800; // if(IntOut2<0)IntOut2=0; // // Out2 = Kp2 * Error02 + IntOut2 + Kd2 * (Error02 - Error12); // // float OUT2 = Out2 * 8.0; // // if(OUT2 > 800)OUT2 = 800; // if(OUT2 < 0)OUT2 = 0; // //// __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,OUT2); // } // last_count2 = count2; // last_time_ms2 = current_time_ms2; //} void calculate_speed_1() { static uint32_t last_count1 = 0; static uint32_t last_time_ms1 = 0; static float prev_error1 = 0.0f; uint32_t current_count1 = __HAL_TIM_GET_COUNTER(&htim3); // 编码器计数器 uint32_t current_time_ms1 = HAL_GetTick(); // 当前时间戳 // 计算时间差(秒) float delta_time_sec1 = (current_time_ms1 - last_time_ms1) / 1000.0f; if (delta_time_sec1 > 0.001f) { // 计算实际RPM值 int32_t diff_count1 = (int32_t)(current_count1 - last_count1); Actual_RPM1 = (diff_count1 / (float)COUNTS_PER_REV) * 60.0f / delta_time_sec1; // PID计算 float error1 = Target_RPM1 - fabs(Actual_RPM1); // 比例项 float P1 = Kp1 * error1; // 积分项(带抗饱和) integral1 += Ki1 * error1 * delta_time_sec1; if(integral1 > PWM_MAX) integral1 = PWM_MAX; else if(integral1 < 0) integral1 = 0; // 微分项 float D1 = Kd1 * (error1 - prev_error1) / delta_time_sec1; prev_error1 = error1; // PID输出 Out1 = P1 + integral1 + D1; // PWM限幅 if(Out1 > 1000)Out1 = 1000; if(Out1 < 0)Out1 = 0; __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, (uint32_t)Out1); } last_count1 = current_count1; last_time_ms1 = current_time_ms1; } void calculate_speed_2() { static uint32_t last_count2 = 0; static uint32_t last_time_ms2 = 0; static float prev_error2 = 0.0f; uint32_t current_count2 = __HAL_TIM_GET_COUNTER(&htim4); // 编码器计数器 uint32_t current_time_ms2 = HAL_GetTick(); // 当前时间戳 // 计算时间差(秒) float delta_time_sec2 = (current_time_ms2 - last_time_ms2) / 1000.0f; if (delta_time_sec2 > 0.001f) { // 计算实际RPM值 int32_t diff_count2 = (int32_t)(current_count2 - last_count2); Actual_RPM2 = (diff_count2 / (float)COUNTS_PER_REV) * 60.0f / delta_time_sec2; // PID计算 float error2 = Target_RPM2 - fabs(Actual_RPM2); // 比例项 float P2 = Kp2 * error2; // 积分项(带抗饱和) integral2 += Ki2 * error2 * delta_time_sec2; if(integral2 > PWM_MAX) integral2 = PWM_MAX; else if(integral2 < 0) integral2 = 0; // 微分项 float D2 = Kd2 * (error2 - prev_error2) / delta_time_sec2; prev_error2 = error2; // PID输出 Out2 = P2 + integral2 + D2; // PWM限幅 if(Out2 > 1000)Out2 = 1000; if(Out2 < 0)Out2 = 0; __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, (uint32_t)Out2); } last_count2 = current_count2; last_time_ms2 = current_time_ms2; } //float Kc = 0.6f; // 同步补偿增益(建议0.3~0.8倍Kp) //void calculate_speed_1() //{ // static uint32_t last_count1 = 0; // static uint32_t last_time_ms1 = 0; // static float prev_error1 = 0.0f; // static float integral1 = 0.0f; // // uint32_t current_count1 = __HAL_TIM_GET_COUNTER(&htim3); // uint32_t current_time_ms1 = HAL_GetTick(); // // float delta_time_sec1 = (current_time_ms1 - last_time_ms1) / 1000.0f; // // if (delta_time_sec1 > 0.001f) // { // // 计算实际RPM(带方向检测) // int32_t diff_count1 = (int32_t)(current_count1 - last_count1); // Actual_RPM1 = (diff_count1 / (float)COUNTS_PER_REV) * 60.0f / delta_time_sec1; // // // PID计算 // float error1 = Target_RPM1 - Actual_RPM1; // // // 比例项 // float P1 = Kp1 * error1; // // // 积分项(带抗饱和) // integral1 += Ki1 * error1 * delta_time_sec1; // if(integral1 > PWM_MAX) integral1 = PWM_MAX; // else if(integral1 < -PWM_MAX) integral1 = -PWM_MAX; // // // 微分项 // float D1 = Kd1 * (error1 - prev_error1) / delta_time_sec1; // prev_error1 = error1; // // // 基础PID输出 // float base_out1 = P1 + integral1 + D1; // // // 同步补偿项(关键改进) // float sync_term = Kc * (Actual_RPM2 - Actual_RPM1); // // // 总输出 = 基础PID + 同步补偿 // Out1 = base_out1 + sync_term; // // // PWM限幅 // if(Out1 > PWM_MAX) Out1 = PWM_MAX; // else if(Out1 < 0) Out1 = 0; // // __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, (uint32_t)Out1); // } // // last_count1 = current_count1; // last_time_ms1 = current_time_ms1; //} //void calculate_speed_2() //{ // static uint32_t last_count2 = 0; // static uint32_t last_time_ms2 = 0; // static float prev_error2 = 0.0f; // static float integral2 = 0.0f; // // uint32_t current_count2 = __HAL_TIM_GET_COUNTER(&htim4); // uint32_t current_time_ms2 = HAL_GetTick(); // // float delta_time_sec2 = (current_time_ms2 - last_time_ms2) / 1000.0f; // // if (delta_time_sec2 > 0.001f) // { // // 计算实际RPM(带方向检测) // int32_t diff_count2 = (int32_t)(current_count2 - last_count2); // Actual_RPM2 = (diff_count2 / (float)COUNTS_PER_REV) * 60.0f / delta_time_sec2; // // // PID计算 // float error2 = Target_RPM2 - Actual_RPM2; // // // 比例项 // float P2 = Kp2 * error2; // // // 积分项(带抗饱和) // integral2 += Ki2 * error2 * delta_time_sec2; // if(integral2 > PWM_MAX) integral2 = PWM_MAX; // else if(integral2 < -PWM_MAX) integral2 = -PWM_MAX; // // // 微分项 // float D2 = Kd2 * (error2 - prev_error2) / delta_time_sec2; // prev_error2 = error2; // // // 基础PID输出 // float base_out2 = P2 + integral2 + D2; // // // 同步补偿项(关键改进) // float sync_term = Kc * (Actual_RPM1 - Actual_RPM2); // // // 总输出 = 基础PID + 同步补偿 // Out2 = base_out2 + sync_term; // // // PWM限幅 // if(Out2 > PWM_MAX) Out2 = PWM_MAX; // else if(Out2 < 0) Out2 = 0; // // __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, (uint32_t)Out2); // } // // last_count2 = current_count2; // last_time_ms2 = current_time_ms2; //} /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); // MX_I2C1_Init(); MX_TIM2_Init(); MX_TIM3_Init(); MX_TIM4_Init(); // MX_TIM5_Init(); // MX_USART1_UART_Init(); MX_ADC1_Init(); /* USER CODE BEGIN 2 */ // OLED_Init(); // OLED_display_info(); // 启动编码器 HAL_TIM_Encoder_Start(&htim3,TIM_CHANNEL_ALL); HAL_TIM_Encoder_Start(&htim4,TIM_CHANNEL_ALL); // // 启动串口接收中断 // HAL_UART_Receive_IT(&huart1, &rx_data, 1); // // 启动定时器并启用中断 // HAL_TIM_Base_Start_IT(&htim5); HAL_GPIO_WritePin(GPIOE,GPIO_PIN_14, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOE,GPIO_PIN_15, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2, GPIO_PIN_SET); HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_3); HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { // Scan_Keys(); calculate_speed_1(); calculate_speed_2(); // OLED_display_dat(); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } 已有以上函数,如果要实现STM32根据8路灰度传感器的反馈结果来调整电机目标速度的功能,以上代码改如何修改?(8路灰度传感器的灰度检测阈值要求可以通过函数修改,以上程序本来的原本的功能不能变)

/* USER CODE BEGIN Header */ /** ****************************************************************************** * File Name : freertos.c * Description : Code for freertos applications ****************************************************************************** * @attention * * Copyright (c) 2024 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "FreeRTOS.h" #include "task.h" #include "main.h" #include "cmsis_os.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "usart.h" #include "gpio.h" #include "tim.h" #include <string.h> #include <stdio.h> /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #define MOTOR_PWM_MAX 19999 // PWM最大值 (Period - 1) #define MOTOR_PWM_MIN 0 // PWM最小值 /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN Variables */ struct uart3_rx_t { int num,ok,en; uint8_t data[28]; int class; float score; int x1,y1,x2,y2; uint8_t datarx; }uart3_rx; struct uart2_rx_t { int num,ok,en; uint8_t data[3]; int shexiangtou_en; int manzaijianche_en; int dangban_en; int youhailaji_en; int chuyulaji_en; int kehuishou_en; int qitalaji_en; uint8_t datarx; }uart2_rx; struct pingmu_tx_t { int manzai,ok,en; int class; float score; int x1,y1,x2,y2; }pingmu_tx; osThreadId motorTaskHandle; osThreadId motor2TaskHandle; osThreadId manzaiTaskHandle; osThreadId txTaskHandle; osThreadId uart6MutexHandle; // 新增:电机控制和超声波测距任务句柄 osThreadId motorControlTaskHandle; // 电机控制任务句柄 osThreadId ultrasonicTaskHandle; // 超声波测距任务句柄 // 新增:超声波测距变量 float ultrasonic1_distance = 0.0f; // 超声波1测量距离 (cm) float ultrasonic2_distance = 0.0f; // 超声波2测量距离 (cm) // 新增:舵机状态跟踪变量 typedef enum { SERVO_IDLE = 0, // 舵机空闲状态(在原位) SERVO_WORKING = 1, // 舵机正在执行分类动作 SERVO_RETURNING = 2 // 舵机正在回到原位 } ServoState_t; volatile ServoState_t servoState = SERVO_IDLE; // 舵机状态 volatile uint32_t servoWorkStartTime = 0; // 舵机工作开始时间 // 新增:电机启动停止延时控制变量 volatile uint32_t motor1_startConditionStartTime = 0; // 电机1启动条件开始时间 volatile uint32_t motor2_startConditionStartTime = 0; // 电机2启动条件开始时间 volatile uint8_t motor1_startConditionActive = 0; // 电机1启动条件是否激活 volatile uint8_t motor2_startConditionActive = 0; // 电机2启动条件是否激活 volatile uint32_t motor1_stopConditionStartTime = 0; // 电机1停止条件开始时间 volatile uint32_t motor2_stopConditionStartTime = 0; // 电机2停止条件开始时间 volatile uint8_t motor1_stopConditionActive = 0; // 电机1停止条件是否激活 volatile uint8_t motor2_stopConditionActive = 0; // 电机2停止条件是否激活 // 电机当前状态 volatile uint8_t motor1_running = 0; // 电机1是否正在运行 volatile uint8_t motor2_running = 0; // 电机2是否正在运行 volatile uint8_t servo_class_to_act = 0; volatile uint8_t is_playing_manzai = 0; // 满载播报进行中标志 volatile uint32_t manzai_play_start = 0; // 满载播报开始时间 volatile uint32_t garbage_delay_start = 0; // 垃圾识别延迟开始时间 volatile uint8_t garbage_to_play = 0; // 待播放的垃圾类别 /* USER CODE END Variables */ osThreadId defaultTaskHandle; osSemaphoreId motorHandle; osSemaphoreId motor2Handle; osSemaphoreId rxlubancatHandle; osSemaphoreId rxpingmuHandle; osSemaphoreId bujingdianjiHandle; osSemaphoreId manzaiSignalHandle; /* Private function prototypes -----------------------------------------------*/ /* USER CODE BEGIN FunctionPrototypes */ int fun (int a,int b, int c); _Noreturn void systemMonitorTask(void const * argument); _Noreturn void motor2Task(void const * argument); //_Noreturn void bujingdianjiTask(void const * argument); _Noreturn void manzaiTask(void const * argument); _Noreturn void txTask(void const * argument); // 新增:电机控制和超声波测距任务函数声明 _Noreturn void motorControlTask(void const * argument); // 核心电机控制任务 _Noreturn void ultrasonicTask(void const * argument); // 超声波测距任务 /* USER CODE END FunctionPrototypes */ void StartDefaultTask(void const * argument); void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ /* GetIdleTaskMemory prototype (linked to static allocation support) */ void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ); /* USER CODE BEGIN GET_IDLE_TASK_MEMORY */ static StaticTask_t xIdleTaskTCBBuffer; static StackType_t xIdleStack[configMINIMAL_STACK_SIZE]; void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ) { *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer; *ppxIdleTaskStackBuffer = &xIdleStack[0]; *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; /* place for user code */ } /* USER CODE END GET_IDLE_TASK_MEMORY */ /** * @brief FreeRTOS initialization * @param None * @retval None */ void MX_FREERTOS_Init(void) { /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* USER CODE BEGIN RTOS_MUTEX */ osMutexDef(uartMutex); osMutexId uartMutexHandle = osMutexCreate(osMutex(uartMutex)); osMutexDef(uart6Mutex); uart6MutexHandle = osMutexCreate(osMutex(uart6Mutex)); /* USER CODE END RTOS_MUTEX */ /* Create the semaphores(s) */ /* definition and creation of motor */ osSemaphoreDef(motor); motorHandle = osSemaphoreCreate(osSemaphore(motor), 1); /* definition and creation of motor2 */ osSemaphoreDef(motor2); motor2Handle = osSemaphoreCreate(osSemaphore(motor2), 1); /* definition and creation of rxlubancat */ osSemaphoreDef(rxlubancat); rxlubancatHandle = osSemaphoreCreate(osSemaphore(rxlubancat), 1); /* definition and creation of rxpingmu */ osSemaphoreDef(rxpingmu); rxpingmuHandle = osSemaphoreCreate(osSemaphore(rxpingmu), 1); osSemaphoreDef(manzaiSignal); manzaiSignalHandle = osSemaphoreCreate(osSemaphore(manzaiSignal), 1); /* definition and creation of bujingdianji */ osSemaphoreDef(bujingdianji); bujingdianjiHandle = osSemaphoreCreate(osSemaphore(bujingdianji), 1); /* USER CODE BEGIN RTOS_SEMAPHORES */ /* add semaphores, ... */ /* USER CODE END RTOS_SEMAPHORES */ HAL_UART_Receive_IT(&huart1, (uint8_t *)&uart3_rx.datarx, 1); HAL_UART_Receive_IT(&huart6, (uint8_t *)&uart2_rx.datarx, 1); HAL_NVIC_SetPriority(USART1_IRQn, 6, 0); HAL_NVIC_EnableIRQ(USART1_IRQn); HAL_NVIC_SetPriority(USART6_IRQn, 6, 0); HAL_NVIC_EnableIRQ(USART6_IRQn); HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0); // 初始停止 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 0); // 初始停止 /* USER CODE BEGIN RTOS_TIMERS */ /* start timers, add new ones, ... */ /* USER CODE END RTOS_TIMERS */ /* USER CODE BEGIN RTOS_QUEUES */ /* add queues, ... */ /* USER CODE END RTOS_QUEUES */ /* Create the thread(s) */ /* definition and creation of defaultTask */ osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128); defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL); /* USER CODE BEGIN RTOS_THREADS */ /* add threads, ... */ // osThreadDef(motorTask, motorTask, osPriorityNormal, 0, 128); // 添加舵机初始化 //__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, 1300); // 舵机1初始位置 //__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, 2030); // 舵机2初始位置 // HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1); // 启动PWM输出 // HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2); // servoState = SERVO_IDLE; // 设置初始状态 // motorTaskHandle = osThreadCreate(osThread(motorTask), NULL); // 保留现有的舵机控制任务 osThreadDef(motor2Task, motor2Task, osPriorityAboveNormal, 0, 128); motor2TaskHandle = osThreadCreate(osThread(motor2Task), NULL); // 保留现有的满载检测任务 osThreadDef(manzaiTask, manzaiTask, osPriorityNormal, 0, 128); manzaiTaskHandle = osThreadCreate(osThread(manzaiTask), NULL); osThreadDef(systemMonitorTask, systemMonitorTask, osPriorityBelowNormal, 0, 128); osThreadCreate(osThread(systemMonitorTask), NULL); // 保留现有的串口屏通讯任务 osThreadDef(txTask, txTask, osPriorityNormal, 2, 128); txTaskHandle = osThreadCreate(osThread(txTask), NULL); // 新增:电机控制任务 osThreadDef(motorControlTask, motorControlTask, osPriorityNormal, 0, 256); motorControlTaskHandle = osThreadCreate(osThread(motorControlTask), NULL); // 新增:超声波测距任务 osThreadDef(ultrasonicTask, ultrasonicTask, osPriorityLow, 0, 256); ultrasonicTaskHandle = osThreadCreate(osThread(ultrasonicTask), NULL); /* USER CODE END RTOS_THREADS */ } _Noreturn void systemMonitorTask(void const * argument) { uint32_t last_heartbeat = HAL_GetTick(); const uint32_t WATCHDOG_TIMEOUT = 30000; // 30秒超时 for(;;) { // 检查任务堆栈使用情况 UBaseType_t uxHighWaterMark = uxTaskGetStackHighWaterMark(NULL); if(uxHighWaterMark < 20) { NVIC_SystemReset(); // 堆栈溢出复位 } // 30秒无心跳复位 if(HAL_GetTick() - last_heartbeat > WATCHDOG_TIMEOUT) { NVIC_SystemReset(); } // 更新心跳时间 last_heartbeat = HAL_GetTick(); osDelay(1000); } } /* USER CODE BEGIN Header_StartDefaultTask */ /** * @brief Function implementing the defaultTask thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartDefaultTask */ void StartDefaultTask(void const * argument) { /* USER CODE BEGIN StartDefaultTask */ /* Infinite loop */ uint32_t last_activity_time = HAL_GetTick(); uart2_rx.manzaijianche_en = 1; for(;;) { //xSemaphoreTake(rxpingmuHandle,portMAX_DELAY); if(xSemaphoreTake(rxpingmuHandle, 100) == pdTRUE) { switch (uart2_rx.data[1]) { case 1: uart2_rx.shexiangtou_en=0; break; case 0: uart2_rx.shexiangtou_en=1; break; case 3: uart2_rx.manzaijianche_en=0; break; case 2: uart2_rx.manzaijianche_en=1; break; case 4: uart2_rx.dangban_en=0; break; case 5: uart2_rx.dangban_en=1; break; case 6: uart2_rx.youhailaji_en=0; break; case 7: uart2_rx.youhailaji_en=1; break; case 8: uart2_rx.chuyulaji_en=0; break; case 9: uart2_rx.chuyulaji_en=1; break; case 10: uart2_rx.kehuishou_en=0; break; case 11: uart2_rx.kehuishou_en=1; break; case 12: uart2_rx.qitalaji_en=0; break; case 13: uart2_rx.qitalaji_en=1; break; default: break; } last_activity_time = HAL_GetTick(); } if(HAL_GetTick() - last_activity_time > 10000) { // 5秒无活动时软复位 NVIC_SystemReset(); } /* USER CODE END StartDefaultTask */ osDelay(100); } } /* Private application code --------------------------------------------------*/ /* USER CODE BEGIN Application */ void PlayAudio(uint8_t audio_num) { char cmd[] = {0x70,0x6C,0x61,0x79,0x20,0x30,0x2C,0x30,0x2C,0x30, 0xFF,0xFF,0xFF}; cmd[7] = '0' + audio_num; osMutexWait(uart6MutexHandle, osWaitForever); HAL_UART_Transmit(&huart6, (uint8_t *)cmd, sizeof(cmd), HAL_MAX_DELAY); osMutexRelease(uart6MutexHandle); } void PlayGarbageAudio(uint8_t garbage_class) { uint8_t audio_num = 0; switch (garbage_class) { case 0: case 1: case 3: audio_num = 2; break; // 可回收 case 2: case 5: audio_num = 1; break; // 厨余 case 7: case 8: audio_num = 0; break; // 有害 default: audio_num = 3; break; // 其他 } PlayAudio(audio_num); } // 保留现有的舵机控制任务 - 增加状态跟踪 _Noreturn void motor2Task(void const * argument) { // 上电首次执行初始化动作 __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, 1300); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, 2030); osDelay(500); // 确保舵机到位 servoState = SERVO_IDLE; for(;;) { xSemaphoreTake(motor2Handle, portMAX_DELAY); //uint8_t current_class = uart3_rx.class; if(is_playing_manzai) { osDelay(100); continue; // 跳过当前动作 } // 🎯 设置舵机工作状态 servoState = SERVO_WORKING; //servoWorkStartTime = HAL_GetTick(); uint8_t current_class = servo_class_to_act; switch (current_class) { //有害垃圾 case 0: __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,1300); __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,2430); break; //可回收垃圾 case 1: case 8: __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,1300); __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,1570); break; //厨余垃圾 case 2: case 5: case 6: case 7: __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,2000); osDelay(1000); __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,2430); break; //其它垃圾 case 3: case 4: __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,2000); osDelay(500); __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,1570); break; default: __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,1300); __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,2030); break; } osDelay(1000); // 执行分类动作的延时 // 🎯 设置舵机回到原位状态 servoState = SERVO_RETURNING; __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,1300); __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,2030); osDelay(1000); // 回到原位的延时 // 🎯 设置舵机空闲状态 servoState = SERVO_IDLE; } osSemaphoreGive(motor2Handle); osDelay(10); } // 保留现有的满载检测任务 _Noreturn void manzaiTask(void const * argument) { for(;;) { osDelay(100); if(HAL_GPIO_ReadPin(load1_GPIO_Port,load1_Pin)==0 || HAL_GPIO_ReadPin(load2_GPIO_Port,load2_Pin)==0 || HAL_GPIO_ReadPin(load3_GPIO_Port,load3_Pin)==0 || HAL_GPIO_ReadPin(load4_GPIO_Port,load4_Pin)==0) { pingmu_tx.manzai=1; xSemaphoreGive(rxlubancatHandle); } } } // 保留现有的串口屏通讯任务 _Noreturn void txTask(void const * argument) { int num=0; const char manzaidata[]={0x74,0x30,0x2E,0x74,0x78,0x74,0x3D,0x22,0xC0,0xAC,0xBB, 0xF8,0xC2,0xFA,0xD4,0xD8,0x22,0xff,0xff,0xff}; // const char kongdata[]={0x74,0x30,0x2E,0x74,0x78,0x74,0x3D,0x22,0x20,0x22,0xff,0xff,0xff}; char play[]={0x70,0x6C,0x61,0x79,0x20,0x30,0x2C,0x30,0x2C,0x30}; unsigned char aa[2]={0}; const char start[]={0x64,0x61,0x74,0x61,0x30,0x2E ,0x69 ,0x6E ,0x73 ,0x65 ,0x72 ,0x74 ,0x28 ,0x22 }; const char end[]={0x22,0x29,0xff,0xff,0xff}; const char end2[]={0xff,0xff,0xff}; //���� const char data1[]={0x5E,0xCD,0xC1,0xB6,0xB9,'\0'}; //���ܲ� const char data2[]={0x5E ,0xB0 ,0xD7 ,0xC2 ,0xDC ,0xB2 ,0xB7 ,'\0'}; //���ܲ� const char data3[]={0x5E ,0xBA ,0xFA ,0xC2 ,0xDC ,0xB2 ,0xB7 ,'\0'}; //ֽ�� const char data4[]={0x5E ,0xD6 ,0xBD ,0xB1 ,0xAD ,'\0'}; //ʯͷ const char data5[]={0x5E ,0xCA ,0xAF ,0xCD ,0xB7 ,'\0'}; //��Ƭ const char data6[]={0x5E ,0xB4,0xC9 ,0xC6 ,0xAC ,'\0'}; //5�ŵ��????? const char data7[]={0x5E ,0x35 ,0xBA ,0xC5 ,0xB5 ,0xE7 ,0xB3 ,0xD8 ,'\0'}; //1�ŵ��????? const char data8[]={0x5E ,0x31 ,0xBA ,0xC5 ,0xB5 ,0xE7 ,0xB3 ,0xD8 ,'\0'}; //�к����� const char data10[]={0x5E ,0xD3 ,0xD0 ,0xBA ,0xA6 ,0xC0 ,0xAC ,0xBB ,0xF8 ,0x5E,'\0'}; //�������� const char data11[]={0x5E ,0xB3 ,0xF8 ,0xD3 ,0xE0 ,0xC0 ,0xAC ,0xBB ,0xF8 ,0x5E,'\0'}; //�ɻ������� const char data12[]={0x5E ,0xBF ,0xC9 ,0xBB ,0xD8 ,0xCA ,0xD5 ,0xC0 ,0xAC ,0xBB ,0xF8 ,0x5E,'\0'}; //�������� const char data13[]={0x5E ,0xC6 ,0xE4 ,0xCB ,0xFB ,0xC0 ,0xAC ,0xBB ,0xF8 ,0x5E,'\0'}; const char* data[]={data8,data4,data7,data5,data6,data2,data3,data1,data1,data1,data1}; uart2_rx.manzaijianche_en=0; uart2_rx.shexiangtou_en=1; for(;;) { xSemaphoreTake(rxlubancatHandle,portMAX_DELAY); if(uart3_rx.ok==1 && uart2_rx.shexiangtou_en ==1 ){ uart3_rx.ok=0; HAL_GPIO_TogglePin(led0_GPIO_Port,led0_Pin); uart3_rx.class=uart3_rx.data[1]-0x30; if(uart3_rx.class<0 || uart3_rx.class>9) uart3_rx.class=11; aa[1]=num%10+0x30; aa[0]=num/10+0x30; HAL_UART_Transmit(&huart6, (uint8_t *) start,sizeof(start),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *)aa, 2,0xFFFF); switch (uart3_rx.class) { case 0: case 2: HAL_UART_Transmit(&huart6, (uint8_t *) data[uart3_rx.class], strlen(data[uart3_rx.class]),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) data10, strlen(data10),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *)aa, 2,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end, sizeof(end),0xFFFF); play[7]=0x30; HAL_UART_Transmit(&huart6, (uint8_t *) play, 10,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end2, sizeof(end2),0xFFFF); break;//�к����� case 5: case 6: case 7: HAL_UART_Transmit(&huart6, (uint8_t *) data[uart3_rx.class], strlen(data[uart3_rx.class]),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) data11, strlen(data11),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *)aa, 2,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end, sizeof(end),0xFFFF); play[7]=0x31; HAL_UART_Transmit(&huart6, (uint8_t *) play, 10,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end2, sizeof(end2),0xFFFF); break;//�������� case 1: HAL_UART_Transmit(&huart6, (uint8_t *) data[uart3_rx.class], strlen(data[uart3_rx.class]),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) data12, strlen(data12),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *)aa, 2,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end, sizeof(end),0xFFFF); play[7]=0x32; HAL_UART_Transmit(&huart6, (uint8_t *) play, 10,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end2, sizeof(end2),0xFFFF); break;//�ɻ������� case 3: case 4: HAL_UART_Transmit(&huart6, (uint8_t *) data[uart3_rx.class], strlen(data[uart3_rx.class]),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) data13, strlen(data13),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *)aa, 2,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end, sizeof(end),0xFFFF); play[7]=0x33; HAL_UART_Transmit(&huart6, (uint8_t *) play, 10,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end2, sizeof(end2),0xFFFF); break;//�������� default: break; } servo_class_to_act = uart3_rx.class; xSemaphoreGive(motor2Handle); num++; if(num>99)num=0; osDelay(2000); } if(pingmu_tx.manzai==1 && uart2_rx.manzaijianche_en==1){ HAL_UART_Transmit(&huart6, (uint8_t *) manzaidata, 20,0xFFFF),pingmu_tx.manzai=0; play[7]=0x34; HAL_UART_Transmit(&huart6, (uint8_t *) play, 10,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end2, sizeof(end2),0xFFFF); osDelay(2000); } } } // ========== 🎯 新增:电机控制任务 ========== // 功能:控制两个电机的PWM速度,与舵机控制分开 // 电机1:PA6 (TIM3_CH1) // 电机2:PA7 (TIM3_CH2) _Noreturn void motorControlTask(void const * argument) { uint32_t tickCounter = 0; // 延迟启动 osDelay(1000); HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); // PA6 HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2); // PA7 for(;;) { // 电机现在由超声波任务自动控制,这里只做周期性检查 if(tickCounter % 50 == 0) { // 可以在这里添加电机状态检查逻辑 } tickCounter++; osDelay(200); } } // ========== 🎯 新增:超声波测距函数 ========== // 简化版本,避免任务阻塞,返回距离值(cm*10) int32_t measureDistanceInt(GPIO_TypeDef* trig_port, uint16_t trig_pin, GPIO_TypeDef* echo_port, uint16_t echo_pin) { volatile uint32_t count = 0; volatile uint32_t time_count = 0; // 1. 确保Trig引脚为低电平 HAL_GPIO_WritePin(trig_port, trig_pin, GPIO_PIN_RESET); // 短暂延时 for(volatile int i = 0; i < 1000; i++) __NOP(); // 2. 发送10μs触发脉冲 HAL_GPIO_WritePin(trig_port, trig_pin, GPIO_PIN_SET); // 10μs延时 @168MHz for(volatile int i = 0; i < 1680; i++) __NOP(); HAL_GPIO_WritePin(trig_port, trig_pin, GPIO_PIN_RESET); // 3. 等待Echo上升沿,超时保护 count = 0; while(HAL_GPIO_ReadPin(echo_port, echo_pin) == GPIO_PIN_RESET) { count++; if(count > 300000) { return -1; // 等待上升沿超时 } } // 4. 测量Echo高电平持续时间 time_count = 0; while(HAL_GPIO_ReadPin(echo_port, echo_pin) == GPIO_PIN_SET) { time_count++; if(time_count > 500000) { return -2; // 高电平持续过长 } } // 5. 计算距离 int32_t distance_x10 = (time_count * 50) / 1000; // 6. 范围检查:1-100cm if(distance_x10 < 10 || distance_x10 > 1000) { return -3; // 超出合理范围 } return distance_x10; } // ========== 🎯 新增:超声波测距任务 ========== // 真实测距版本,控制电机运行,与舵机同步,不使用USART1发送 _Noreturn void ultrasonicTask(void const * argument) { uint32_t counter = 0; int32_t distance1, distance2; for(;;) { // 测量超声波模块1 (PB2->PD8) distance1 = measureDistanceInt(GPIOB, GPIO_PIN_2, GPIOD, GPIO_PIN_8); // 间隔300ms避免干扰 osDelay(300); // 测量超声波模块2 (PB3->PD9) distance2 = measureDistanceInt(GPIOB, GPIO_PIN_3, GPIOD, GPIO_PIN_9); // ========== 🎯 电机控制逻辑 - 与舵机同步 + 启动停止延时500ms ========== uint32_t currentTime = HAL_GetTick(); // ========== 电机1控制逻辑 ========== if(servoState == SERVO_IDLE){ if(distance1 > 50) { // distance1是cm*10,所以100表示10cm __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 4000); // PA7, 30%速度 } else { __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0); // 停止 } // ========== 电机2控制逻辑 ========== if(distance2 > 50) { // distance2是cm*10,所以100表示10cm __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 4000); // PA6, 30%速度 (修改:从TIM4_CH2改为TIM3_CH1) } else { __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 0); // 停止 (修改:从TIM4_CH2改为TIM3_CH1) } }else{ __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 0); } counter++; osDelay(1200); // 每1.5秒测量一次 } } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { /* Prevent unused argument(s) compilation warning */ // UNUSED(huart); /* NOTE: This function Should not be modified, when the callback is needed, the HAL_UART_TxCpltCallback could be implemented in the user file */ BaseType_t xHigherPriorityTaskWoken = pdFALSE; if(huart->Instance == USART6) { // 更健壮的帧检测 static uint8_t frame_buffer[32]; static uint8_t frame_index = 0; // 存储接收到的字节 frame_buffer[frame_index] = uart2_rx.datarx; frame_index = (frame_index + 1) % sizeof(frame_buffer); // 检测结束符 0xFF 0xFF 0xFF if(frame_index >= 3 && frame_buffer[frame_index-3] == 0xFF && frame_buffer[frame_index-2] == 0xFF && frame_buffer[frame_index-1] == 0xFF) { // 复制有效数据 memcpy(uart2_rx.data, frame_buffer, frame_index-3); uart2_rx.num = frame_index-3; uart2_rx.ok = 1; frame_index = 0; xSemaphoreGiveFromISR(rxpingmuHandle, &xHigherPriorityTaskWoken); } HAL_UART_Receive_IT(&huart6, (uint8_t*)&uart2_rx.datarx, 1); } if(huart ->Instance == USART1){ HAL_GPIO_TogglePin(led1_GPIO_Port,led1_Pin); if(uart3_rx.datarx=='@') uart3_rx.num=0; uart3_rx.data[uart3_rx.num]=uart3_rx.datarx; uart3_rx.num++; if(uart3_rx.num>=28){ uart3_rx.num=0; if(uart3_rx.data[27]==']'){ uart3_rx.ok=1; xSemaphoreGiveFromISR(rxlubancatHandle, &xHigherPriorityTaskWoken); } uart3_rx.num = 0; // 重置缓冲区 } HAL_UART_Receive_IT(&huart1, (uint8_t *)&uart3_rx.datarx, 1); } portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } /* USER CODE END Application */ 这个程序中为什么超声波控制电机启停无法使用,该怎么解决这个问题

#include "stm32f4xx.h" // 系统配置 #define SYSTEM_CLOCK 168000000 #define PWM_CARRIER_FREQ 100000 // 100kHz #define SIN_MOD_FREQ 50 // 50Hz #define SIN_TABLE_SIZE 2000 // 2000点/周期 /* 正弦表生成函数 */ // 双通道CCR值结构体(内存对齐) typedef struct { uint16_t ccr1; uint16_t ccr2; } __attribute__((aligned(4))) PWM_CCR_Pair; volatile PWM_CCR_Pair dma_buffer[SIN_TABLE_SIZE]; // DMA传输缓冲区 uint32_t tim8_arr = (SYSTEM_CLOCK / (2 * PWM_CARRIER_FREQ)) - 1;//168M/(2*100K)=840-1 #include "math.h" void Generate_SinTable(void) { int i; const float modulation_depth = 0.9f; const uint16_t offset = (tim8_arr + 1) / 2; // 中间值 for( i = 0; i < SIN_TABLE_SIZE; i++) { float theta = 2 * 3.1415926f * i / SIN_TABLE_SIZE; uint16_t ccr = offset + (uint16_t)(modulation_depth * offset * sin(theta)); dma_buffer[i].ccr1 = ccr; dma_buffer[i].ccr2 = ccr; // 互补通道由硬件自动处理,此处保持相同占空比 } } //PWM频率=168M/(ARR+1)/(PSC+1) //PWM占空比=CCR/(ARR+1) //PWM分辨率=1/(ARR+1) void TIM8_SPWM_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct; TIM_OCInitTypeDef TIM_OCInitStruct; TIM_BDTRInitTypeDef TIM_BDTRInitStruct; DMA_InitTypeDef DMA_InitStruct; // 1. 使能时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); // 2. GPIO配置 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // PC6-CH1, PC7-CH2 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOC, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7; // PA7-CH1N GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14; // PB14-CH2N GPIO_Init(GPIOB, &GPIO_InitStr

#include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/devicetree.h> #include <zephyr/drivers/i2c.h> #include <zephyr/logging/log.h> #include <stdio.h> #include <math.h> #include "GVL.h" #include "data_preprocess.h" #define LOG_MODULE_NAME LSM6DSOWTR_thread LOG_MODULE_REGISTER(LOG_MODULE_NAME); // LSM6DSOWTR 寄存器定义 #define LSM6DSOWTR_REG_WHO_AM_I 0x0F #define LSM6DSOWTR_REG_CTRL1_XL 0x10 #define LSM6DSOWTR_REG_CTRL2_G 0x11 #define LSM6DSOWTR_REG_CTRL3_C 0x12 #define LSM6DSOWTR_REG_OUTX_L_G 0x22 #define LSM6DSOWTR_REG_OUTX_H_G 0x23 #define LSM6DSOWTR_REG_OUTY_L_G 0x24 #define LSM6DSOWTR_REG_OUTY_H_G 0x25 #define LSM6DSOWTR_REG_OUTZ_L_G 0x26 #define LSM6DSOWTR_REG_OUTZ_H_G 0x27 #define LSM6DSOWTR_REG_OUTX_L_XL 0x28 #define LSM6DSOWTR_REG_OUTX_H_XL 0x29 #define LSM6DSOWTR_REG_OUTY_L_XL 0x2A #define LSM6DSOWTR_REG_OUTY_H_XL 0x2B #define LSM6DSOWTR_REG_OUTZ_L_XL 0x2C #define LSM6DSOWTR_REG_OUTZ_H_XL 0x2D // 配置参数 #define LSM6DSOWTR_WHO_AM_I_VAL 0x6C #define LSM6DSOWTR_ODR_XL_104HZ 0x40 // 加速度计 104Hz #define LSM6DSOWTR_FS_XL_2G 0x00 // ±2g 量程 #define LSM6DSOWTR_ODR_G_104HZ 0x40 // 陀螺仪 104Hz #define LSM6DSOWTR_FS_G_245DPS 0x00 // ±245dps 量程 #define LSM6DSOWTR_REG_STATUS_REG 0x1E #define ACCEL_SENSITIVITY_2G 0.000061f #define GYRO_SENSITIVITY_245DPS 0.00875f // 8.75 mdps/LSB // 压力传感器LPS28DFW 寄存器定义 // LPS28DFW 寄存器定义 #define LPS28DFW_WHO_AM_I 0x0F #define LPS28DFW_CTRL_REG1 0x10 #define LPS28DFW_CTRL_REG2 0x11 #define LPS28DFW_CTRL_REG3 0x12 #define LPS28DFW_PRESS_OUT_XL 0x28 #define LPS28DFW_PRESS_OUT_L 0x29 #define LPS28DFW_PRESS_OUT_H 0x2A #define LPS28DFW_TEMP_OUT_L 0x2B #define LPS28DFW_TEMP_OUT_H 0x2C #define LPS28DFW_INTERRUPT_CFG 0x0B #define LPS28DFW_THS_P_L 0x0C #define LPS28DFW_THS_P_H 0x0D // 配置值 #define LPS28DFW_WHO_AM_I_VAL 0xB4 #define LPS28DFW_ODR_50HZ 0x50 // 50Hz输出数据率 #define LPS28DFW_LPF_ENABLE 0x08 // 启用低通滤波器 #define LPS28DFW_BDU_ENABLE 0x08 // 启用块数据更新 #define LPS28DFW_WATER_MODE 0x40 // 水压测量模式 #define SAMPLE_INTERVAL_MS 100 //MS5837压力传感器 #define MS5837_CMD_RESET 0x1E #define MS5837_CMD_CONVERT_D1_OSR1024 0x44 #define MS5837_CMD_CONVERT_D2_OSR1024 0x54 #define MS5837_CMD_ADC_READ 0x00 #define MS5837_PROM_READ_BASE 0xA0 struct ms5837_calib { uint16_t factory; // PROM word 0 (厂商数据) uint16_t c1; // 压力灵敏度 uint16_t c2; // 压力偏移 uint16_t c3; // 温度系数-压力灵敏度 uint16_t c4; // 温度系数-压力偏移 uint16_t c5; // 参考温度 uint16_t c6; // 温度系数 uint16_t crc; // CRC校验 }; // 等待数据就绪 static bool wait_for_data_ready(const struct i2c_dt_spec *dev_spec) { uint8_t status; int retries = 10; while (retries-- > 0) { if (i2c_reg_read_byte_dt(dev_spec, LSM6DSOWTR_REG_STATUS_REG, &status) == 0) { // 检查加速度计和陀螺仪数据就绪位 (bit0 & bit1) if ((status & 0x03) == 0x03) return true; } k_msleep(1); } return false; } static int init_LPS28DFW_water(const struct i2c_dt_spec *dev_spec) { const int max_retries = 5; uint8_t whoami; int ret; int retries = 0; LOG_INF("Starting LPS28DFW initialization..."); LOG_DBG("Verifying I2C connection to device at 0x%02X", dev_spec->addr); do { ret = i2c_reg_read_byte_dt(dev_spec, LPS28DFW_WHO_AM_I, &whoami); if (ret == 0 && whoami == LPS28DFW_WHO_AM_I_VAL) break; if (ret != 0) { LOG_WRN("I2C read error: %d (attempt %d)", ret, retries+1); } else { LOG_WRN("Unexpected WHO_AM_I: 0x%02X (expected 0x%02X) attempt %d", whoami, LPS28DFW_WHO_AM_I_VAL, retries+1); } i2c_recover_bus(dev_spec->bus); k_msleep(10); } while (++retries < max_retries); if (retries >= max_retries) { LOG_ERR("Device detection failed after %d attempts", max_retries); return -ENODEV; } uint8_t ctrl_reset=0x04; ret = i2c_reg_write_byte_dt(dev_spec, LPS28DFW_CTRL_REG2, ctrl_reset); k_msleep(10); if (ret) { LOG_ERR("ctrl_reg2 reset failed: %d", ret); return ret; } uint8_t ctrl_reset_value; ret = i2c_reg_read_byte_dt(dev_spec, LPS28DFW_CTRL_REG2, &ctrl_reset_value); if (ret == 0) { // 检查关键位 const uint8_t critical_bits_mask_reset = 0x04; if (ctrl_reset_value == critical_bits_mask_reset) { LOG_DBG("CTRL_REG2 reset verified: 0x%02X", ctrl_reset_value); } else{ LOG_WRN("CTRL_REG2 reset failed: read 0x%02X", ctrl_reset_value); } } uint8_t ctrl_reg1=0x50; ret = i2c_reg_write_byte_dt(dev_spec, LPS28DFW_CTRL_REG1, ctrl_reg1); if (ret) { LOG_ERR("ctrl_reg1 set failed: %d", ret); return ret; } uint8_t ctrl_reg2 =0x18; ret = i2c_reg_write_byte_dt(dev_spec, LPS28DFW_CTRL_REG2, ctrl_reg2); if (ret) { LOG_ERR("ctrl_reg1 set failed: %d", ret); return ret; } uint8_t reg_value1; uint8_t reg_value2; uint8_t reg_value3; ret = i2c_reg_read_byte_dt(dev_spec, LPS28DFW_CTRL_REG1, ®_value1); if (ret == 0) { // 检查关键位 const uint8_t critical_bits_mask1 = 0x50; if (reg_value1 == critical_bits_mask1) { LOG_DBG("CTRL_REG1 verified: 0x%02X", reg_value1); } else{ LOG_WRN("CTRL_REG1 failed: read 0x%02X", reg_value1); } } ret = i2c_reg_read_byte_dt(dev_spec, LPS28DFW_CTRL_REG2, ®_value2); if (ret == 0) { // 检查关键位 const uint8_t critical_bits_mask2 = 0x18; if (reg_value2 == critical_bits_mask2) { LOG_DBG("CTRL_REG2 verified: 0x%02X", reg_value2); } else{ LOG_WRN("CTRL_REG2 failed: read 0x%02X", reg_value2); } } uint8_t ctrl_reg3 =0x01; ret = i2c_reg_write_byte_dt(dev_spec, LPS28DFW_CTRL_REG3, ctrl_reg3); if (ret) { LOG_ERR("ctrl_reg3 set failed: %d", ret); return ret; } ret = i2c_reg_read_byte_dt(dev_spec, LPS28DFW_CTRL_REG3, ®_value3); if (ret == 0) { // 检查关键位 const uint8_t critical_bits_mask3 = 0x01; if (reg_value3 == critical_bits_mask3) { LOG_DBG("CTRL_REG3 verified: 0x%02X", reg_value3); } else{ LOG_WRN("CTRL_REG3 failed: read 0x%02X", reg_value3); } } LOG_INF("LPS28DFW initialized successfully"); return 0; } // 读取原始压力数据 (24位有符号整数) static int32_t read_raw_pressure(const struct i2c_dt_spec *dev_spec) { uint8_t press_data[3]; int ret; ret = i2c_burst_read_dt(dev_spec, LPS28DFW_PRESS_OUT_XL, press_data, sizeof(press_data)); if (ret != 0) { LOG_ERR("Pressure read failed: %d", ret); return 0; } int32_t raw_pressure = ((int32_t)press_data[2] << 16) | ((int32_t)press_data[1] << 8) | press_data[0]; if (raw_pressure & 0x00800000) { raw_pressure |= 0xFF000000; } return raw_pressure; } // 读取原始温度数据 (16位有符号整数) static int16_t read_raw_temperature(const struct i2c_dt_spec *dev_spec) { uint8_t temp_data[2]; int ret; ret = i2c_burst_read_dt(dev_spec, LPS28DFW_TEMP_OUT_L, temp_data, sizeof(temp_data)); if (ret != 0) { LOG_ERR("Temperature read failed: %d", ret); return 0; } // 组合16位有符号整数 (小端格式) return (int16_t)((temp_data[1] << 8) | temp_data[0]); } // 读取带温度补偿的水压 static double read_compensated_water_pressure(const struct i2c_dt_spec *dev_spec) { // 读取原始压力值 int32_t raw_pressure = read_raw_pressure(dev_spec); // 读取原始温度值 int16_t raw_temp = read_raw_temperature(dev_spec); // 转换为摄氏度 (100 LSB/°C) double temperature = (double)raw_temp / 100.0f; // 转换为hPa double pressure_hPa = (double)raw_pressure / 4096.0f; // 温度补偿因子 (根据数据手册的典型特性) // 实际应用中应根据传感器校准数据调整 double comp_factor = 1.0f + (0.0001f * temperature); // 应用温度补偿 pressure_hPa *= comp_factor; // 转换为米水柱 return pressure_hPa*100.0; } // 读取水深 (单位: 米) static double read_water_depth(const struct i2c_dt_spec *dev_spec) { // 读取补偿后的水压 double pressure_mH2O = read_compensated_water_pressure(dev_spec); // 水深 = 水压值 (忽略大气压影响) return pressure_mH2O; } static double read_compensated_water_depth(const struct i2c_dt_spec *dev_spec, double atmospheric_pressure) { // 读取补偿后的水压(单位:米水柱) //double absolute_pressure_mH2O = read_compensated_water_pressure(dev_spec); double raw_press = read_raw_pressure(dev_spec) / 0.4096f; double raw_temp = read_raw_temperature(dev_spec) / 100.0f; // double absolute_pressure_Pa = read_compensated_water_pressure(dev_spec); // 转换为Pa (1 mH2O = 9806.65 Pa) //double temp_depth = (absolute_pressure_Pa - atmospheric_pressure) / (1000.0 * 9.80665); //double temp_depth = (sensor_data_PWM.pressure/10.0f - atmospheric_pressure/10.0f) / (1000.0 * 9.80665); double temp_depth = (raw_press/10.0f - atmospheric_pressure/10.0f) / (1000.0 * 9.80665); LOG_INF("raw temp:%.2f raw pressure: %.2f atmospheric_pressure: %.2f kPa (%.4f mH2O)", raw_temp,raw_press/10.f,atmospheric_pressure/10.0f, temp_depth); // 水深 = (绝对压力 - 大气压) / (水密度 * 重力加速度) //return (absolute_pressure_Pa - atmospheric_pressure) / (1000.0f * 9.80665f); return (raw_press/10.0f - atmospheric_pressure/10.0f) / (1000.0f * 9.80665f); } // 初始化 LSM6DS0 传感器 static int init_lsm6dsowtr(const struct i2c_dt_spec *dev_spec) { uint8_t whoami; int ret; LOG_INF("Initializing LSM6DSOWTR sensor..."); // 读取 WHO_AM_I 寄存器 ret = i2c_reg_read_byte_dt(dev_spec, LSM6DSOWTR_REG_WHO_AM_I, &whoami); if (ret != 0) { LOG_ERR("Failed to read WHO_AM_I: %d", ret); return ret; } if (whoami != LSM6DSOWTR_WHO_AM_I_VAL) { LOG_ERR("Unexpected WHO_AM_I: 0x%02X (expected 0x%02X)", whoami, LSM6DSOWTR_WHO_AM_I_VAL); return -ENODEV; } LOG_INF("LSM6DSOWTR detected (WHO_AM_I=0x%02X)", whoami); // 配置加速度计 uint8_t ctrl1_xl = LSM6DSOWTR_ODR_XL_104HZ | LSM6DSOWTR_FS_XL_2G; ret = i2c_reg_write_byte_dt(dev_spec, LSM6DSOWTR_REG_CTRL1_XL, ctrl1_xl); if (ret != 0) { LOG_ERR("Failed to write CTRL1_XL: %d", ret); return ret; } // 配置陀螺仪 uint8_t ctrl2_g = LSM6DSOWTR_ODR_G_104HZ | LSM6DSOWTR_FS_G_245DPS; ret = i2c_reg_write_byte_dt(dev_spec, LSM6DSOWTR_REG_CTRL2_G, ctrl2_g); if (ret != 0) { LOG_ERR("Failed to write CTRL2_G: %d", ret); return ret; } uint8_t reg_val; ret = i2c_reg_read_byte_dt(dev_spec, LSM6DSOWTR_REG_CTRL1_XL, ®_val); if (ret != 0 || reg_val != ctrl1_xl) { LOG_ERR("CTRL1_XL verification failed: wrote 0x%02X, read 0x%02X", ctrl1_xl, reg_val); return -EIO; } ret = i2c_reg_read_byte_dt(dev_spec, LSM6DSOWTR_REG_CTRL2_G, ®_val); if (ret != 0 || reg_val != ctrl2_g) { LOG_ERR("CTRL2_G verification failed: wrote 0x%02X, read 0x%02X", ctrl2_g, reg_val); return -EIO; } // 配置控制寄存器3 ret = i2c_reg_write_byte_dt(dev_spec, LSM6DSOWTR_REG_CTRL3_C, 0x04); // BDU=1 (块数据更新) if (ret != 0) { LOG_ERR("Failed to write CTRL3_C: %d", ret); return ret; } LOG_INF("LSM6DSOWTR initialized successfully"); return 0; } // 读取加速度计数据 static void read_accelerometer(const struct i2c_dt_spec *dev_spec, double *x, double *y, double *z) { if (!wait_for_data_ready(dev_spec)) { LOG_WRN("Accel data not ready"); *x = *y = *z = NAN; return; } uint8_t data[6]; int ret = i2c_burst_read_dt(dev_spec, LSM6DSOWTR_REG_OUTX_L_XL, data, sizeof(data)); if (ret != 0) { LOG_ERR("Accelerometer read failed: %d", ret); *x = *y = *z = NAN; return; } // 组合16位数据(小端格式) int16_t raw_x = (int16_t)((data[1] << 8) | data[0]); int16_t raw_y = (int16_t)((data[3] << 8) | data[2]); int16_t raw_z = (int16_t)((data[5] << 8) | data[4]); // 转换为 g (重力加速度) - ±2g 量程,灵敏度 0.061 mg/LSB *x = raw_x * ACCEL_SENSITIVITY_2G; *y = raw_y * ACCEL_SENSITIVITY_2G; *z = raw_z * ACCEL_SENSITIVITY_2G; } // 读取陀螺仪数据 static void read_gyroscope(const struct i2c_dt_spec *dev_spec, double *x, double *y, double *z) { if (!wait_for_data_ready(dev_spec)) { LOG_WRN("Gyro data not ready"); *x = *y = *z = NAN; return; } uint8_t data[6]; int ret = i2c_burst_read_dt(dev_spec, LSM6DSOWTR_REG_OUTX_L_G, data, sizeof(data)); if (ret != 0) { LOG_ERR("Gyroscope read failed: %d", ret); *x = *y = *z = NAN; return; } // 组合16位数据(小端格式) int16_t raw_x = (int16_t)((data[1] << 8) | data[0]); int16_t raw_y = (int16_t)((data[3] << 8) | data[2]); int16_t raw_z = (int16_t)((data[5] << 8) | data[4]); // 转换为 dps (度/秒) - ±245dps 量程,灵敏度 8.75 mdps/LSB *x = raw_x * GYRO_SENSITIVITY_245DPS; *y = raw_y * GYRO_SENSITIVITY_245DPS; *z = raw_z * GYRO_SENSITIVITY_245DPS; } // 将浮点值转换为定点表示(用于存储) static int32_t sensor_value_to_int(double value, int scale_factor) { return (int32_t)(value * scale_factor); } // 主传感器线程 void lsm6dsowtr_thread(void) { LOG_INF("LSM6DSOWTR sensor thread started"); // 获取六轴传感器设备规范 static const struct i2c_dt_spec lsm6dsowtr_dev = I2C_DT_SPEC_GET(DT_NODELABEL(lsm6dsowtr)); if (!device_is_ready(lsm6dsowtr_dev.bus)) { LOG_ERR("I2C bus not ready: %s", lsm6dsowtr_dev.bus->name); return; } // 获取压力传感器设备规范 static const struct i2c_dt_spec pressure_dev = I2C_DT_SPEC_GET(DT_NODELABEL(mysensor)); if (!device_is_ready(pressure_dev.bus)) { LOG_ERR("I2C bus %s is not ready!", pressure_dev.bus->name); return; } // 初始化传感器 int init_result; // 初始化压力传感器 init_result = init_LPS28DFW_water(&pressure_dev); if (init_result != 0) { LOG_ERR("Pressure sensor initialization failed: %d", init_result); } else { LOG_INF("Pressure sensor initialized successfully"); } // struct ms5837_calib calib_data; // int ms5837_init_ret = init_MS5837(&pressure_dev, &calib_data); // if (ms5837_init_ret != 0) { // LOG_ERR("MS5837 initialization failed: %d", ms5837_init_ret); // // 非致命错误,继续运行其他传感器 // } else { // LOG_INF("MS5837 initialized successfully"); // } // 初始化六轴传感器 init_result = init_lsm6dsowtr(&lsm6dsowtr_dev); if (init_result != 0) { LOG_ERR("LSM6DSOWTR initialization failed: %d", init_result); } else { LOG_INF("LSM6DSOWTR initialized successfully"); } LOG_INF("Starting sensor data collection..."); // 主循环变量 int64_t last_sample_time = k_uptime_get(); int64_t last_batch_time = last_sample_time; static int datacount = 0; static double press_a = 0; static double depth_comp = 0; static int depth_count = 0; while (1) { double press = read_raw_pressure(&pressure_dev); double temp = read_raw_temperature(&pressure_dev); double compensated_depth; if(datacount < 20){ press_a = press_a + press/4096.0f; datacount++; // LOG_INF("press_a: %.4f Pa,datacount:%d", press_a,datacount); } else{ press_a = press_a/20.0f; // LOG_INF("press_a: %.4f Pa,datacount:%d", press_a,datacount); press_a = press_a*10000; // sensor_data_PWM.pressure = press_a*10000; compensated_depth = read_compensated_water_depth(&pressure_dev, press_a); if(depth_count < 20){ depth_comp = depth_comp + compensated_depth; depth_count++; // LOG_INF("press_a: %.4f Pa,datacount:%d", press_a,datacount); } else{ depth_comp = depth_comp/20.0f; LOG_INF("depth_comp: %.4f Pa,depth_count:%d", depth_comp,depth_count); depth_count = 0; depth_comp = 0; } datacount = 0; press_a = 0; } // if(depth_count < 20){ // depth_comp = depth_comp + compensated_depth/4096.0f; // datacount++; // // LOG_INF("press_a: %.4f Pa,datacount:%d", press_a,datacount); // } else{ // press_a = press_a/20.0f; // // LOG_INF("press_a: %.4f Pa,datacount:%d", press_a,datacount); // press_a = press_a*10000; // compensated_depth = read_compensated_water_depth(&pressure_dev, press_a); // datacount = 0; // press_a = 0; // } double accel_x, accel_y, accel_z; double gyro_x, gyro_y, gyro_z; read_accelerometer(&lsm6dsowtr_dev, &accel_x, &accel_y, &accel_z); read_gyroscope(&lsm6dsowtr_dev, &gyro_x, &gyro_y, &gyro_z); //float magnitude = calculate_acceleration_magnitude(accel_x, accel_y, accel_z); // LOG_INF("Accel: X=%.3f g, Y=%.3f g, Z=%.3f g", // accel_x, accel_y, accel_z); // LOG_INF("Gyro: X=%.2f dps, Y=%.2f dps, Z=%.2f dps", // gyro_x, gyro_y, gyro_z); // 获取当前时间戳 int64_t current_time = k_uptime_get(); // 准备数据点 // sensor_data_point_t data_point = { // .timestamp = current_time, // .pressure = sensor_value_to_int(press, 1000), // kPa * 1000 = milli-kPa // .temp = sensor_value_to_int(temp, 100), // °C * 100 = centi-°C // .acc_x = sensor_value_to_int(accel_x, 1000), // g * 1000 = milli-g // .acc_y = sensor_value_to_int(accel_y, 1000), // .acc_z = sensor_value_to_int(accel_z, 1000), // .gyro_x = sensor_value_to_int(gyro_x, 1000), // dps * 1000 = milli-dps // .gyro_y = sensor_value_to_int(gyro_y, 1000), // .gyro_z = sensor_value_to_int(gyro_z, 1000) // }; sensor_data_point_t data_point = { .timestamp = current_time, .pressure = sensor_value_to_int(press/4096.0f, 10000), // kPa * 1000 = milli-kPa .temp = sensor_value_to_int(temp, 100), // °C * 100 = centi-°C .acc_x = sensor_value_to_int(accel_x, 1000), // g * 1000 = milli-g .acc_y = sensor_value_to_int(accel_y, 1000), .acc_z = sensor_value_to_int(accel_z, 1000), .gyro_x = sensor_value_to_int(gyro_x, 1000), // dps * 1000 = milli-dps .gyro_y = sensor_value_to_int(gyro_y, 1000), .gyro_z = sensor_value_to_int(gyro_z, 1000) }; // LOG_INF("data filter"); data_point = filter_sensor_data(&data_point); atmospheric_pressure = data_point.pressure; //double compensated_depth = read_compensated_water_depth(&pressure_dev, atmospheric_pressure); // double compensated_depth = read_compensated_water_depth(&pressure_dev, press/4096.0f); // LOG_INF("Compensated Depth: %.4f m",compensated_depth); // // 安全地添加到批量缓冲区 // k_mutex_lock(&data_mutex, K_FOREVER); // // 检查当前批次缓冲区是否有效 // if (sensor_batch.count == 0) { // // 新批次,记录起始时间戳 // sensor_batch.start_timestamp = current_time; // } // // 添加数据点到批次 // if (sensor_batch.count < BATCH_SIZE) { // sensor_batch.data[sensor_batch.count] = data_point; // sensor_batch.count++; // // 检查批次是否已满 // if (sensor_batch.count >= BATCH_SIZE) { // // 批次已满,标记为就绪 // sensor_batch.ready = true; // LOG_DBG("Batch filled (%d points)", BATCH_SIZE); // } // } else { // LOG_WRN("Batch buffer full, discarding data point"); // } // // 检查是否超时(即使批次未满) // if ((current_time - sensor_batch.start_timestamp) >= (MAX_BATCH_TIMEOUT * 1000)) { // if (sensor_batch.count > 0) { // sensor_batch.ready = true; // LOG_DBG("Batch timeout with %d points", sensor_batch.count); // } // } // // 如果批次就绪,通知BLE线程 // if (sensor_batch.ready) { // k_sem_give(&batch_ready_sem); // LOG_DBG("Notified BLE thread of data ready"); // } // k_mutex_unlock(&data_mutex); // 计算下一个采样点的时间 int64_t elapsed = k_uptime_get() - last_sample_time; int32_t sleep_time = SAMPLE_INTERVAL_MS - elapsed; if (sleep_time > 0) { k_msleep(sleep_time); } else { LOG_WRN("Sampling behind schedule by %d ms", -sleep_time); } last_sample_time = k_uptime_get(); } } // 定义传感器线程 K_THREAD_DEFINE(lsm6dsowtr_thread_id, 4096, lsm6dsowtr_thread, NULL, NULL, NULL, 7, 0, 0);对原始压力值进行中值滤波

最新推荐

recommend-type

微软解决方案面向服务的架构.doc

微软解决方案面向服务的架构.doc
recommend-type

VC图像编程全面资料及程序汇总

【标题】:"精通VC图像编程资料全览" 【知识点】: VC即Visual C++,是微软公司推出的一个集成开发环境(IDE),专门用于C++语言的开发。VC图像编程涉及到如何在VC++开发环境中处理和操作图像。在VC图像编程中,开发者通常会使用到Windows API中的GDI(图形设备接口)或GDI+来进行图形绘制,以及DirectX中的Direct2D或DirectDraw进行更高级的图形处理。 1. GDI(图形设备接口): - GDI是Windows操作系统提供的一套应用程序接口,它允许应用程序通过设备无关的方式绘制图形。 - 在VC图像编程中,主要使用CDC类(设备上下文类)来调用GDI函数进行绘制,比如绘制线条、填充颜色、显示文本等。 - CDC类提供了很多函数,比如`MoveTo`、`LineTo`、`Rectangle`、`Ellipse`、`Polygon`等,用于绘制基本的图形。 - 对于图像处理,可以使用`StretchBlt`、`BitBlt`、`TransparentBlt`等函数进行图像的位块传输。 2. GDI+: - GDI+是GDI的后继技术,提供了更丰富的图形处理功能。 - GDI+通过使用`Graphics`类来提供图像的绘制、文本的渲染、图像的处理和颜色管理等功能。 - GDI+引入了对矢量图形、渐变色、复杂的文本格式和坐标空间等更高级的图形处理功能。 - `Image`类是GDI+中用于图像操作的基础类,通过它可以进行图像的加载、保存、旋转、缩放等操作。 3. DirectX: - DirectX是微软推出的一系列API集合,用于在Windows平台上进行高性能多媒体编程。 - DirectX中的Direct2D是用于硬件加速的二维图形API,专门用于UI元素和简单的图形渲染。 - DirectDraw主要用于硬件加速的位图操作,比如全屏游戏开发中的画面渲染。 4. 位图操作: - 在VC图像编程中,位图操作是一个重要的部分。需要了解如何加载、保存和处理位图(BMP)文件。 - 可以使用位图文件格式的解析,来访问位图的像素数据,进行像素级别的图像处理和修改。 5. 高级图像处理技术: - 包括图像滤镜、图像转换、图像压缩和解压缩技术。 - 需要掌握一些图像处理算法,比如卷积、FFT(快速傅里叶变换)、DCT(离散余弦变换)等。 - 了解图像的色彩空间转换,比如RGB到YUV的转换,这在视频处理中非常重要。 6. 图像库的使用: - 除了直接使用API进行图像处理之外,还可以使用开源的图像处理库,如OpenCV。 - OpenCV是一个跨平台的计算机视觉和机器学习软件库,它提供了很多高级的图像处理功能。 【压缩包子文件的文件名称列表】: VC++ 文件名称列表显示为"VC++",这表明文件包中可能包含了Visual C++的项目、源代码文件、动态链接库(DLLs)、编译器设置、链接器设置等。如果要使用这些文件进行VC图像编程,需要确保Visual C++开发环境已经安装并且配置好,同时需要安装好所有依赖的库和工具。 要开始VC图像编程,开发者需要具备C++编程基础,熟悉Windows编程概念,并且对图形学有一定的了解。掌握VC图像编程技巧,对于进行桌面应用程序开发、图像处理软件开发以及游戏开发等都是至关重要的。
recommend-type

Pokemmo响应速度翻倍:多线程处理的高级技巧

# 摘要 多线程处理是提高软件并发性能和响应速度的关键技术,本文从基础概念与优势出发,深入探讨了多线程的实现机制,包括线程模型、调度算法、编程关键技术、线程安全性最佳实践、死锁预防与处理等方面。通
recommend-type

人名列表滚动抽奖

<think>嗯,用户想实现一个滚动抽奖功能,需要前端动画效果和随机选择逻辑。首先,我得考虑前端怎么实现滚动效果。可能用CSS动画或者JavaScript的requestAnimationFrame?比如,使用CSS的@keyframes来控制位移,或者用JS动态更新样式。然后,随机选择算法,可能需要确保公平性,比如用Fisher-Yates洗牌算法,或者用Math.random()来生成随机索引。然后,用户可能需要平滑的滚动动画,比如先快速滚动,然后逐渐减速,最后停在选中的人名上。这可能需要设置定时器,逐步改变位置,或者使用CSS过渡效果。另外,还要考虑性能,避免页面卡顿,可能需要使用硬件加
recommend-type

一站式JSF开发环境:即解压即用JAR包

标题:“jsf开发完整JAR包”所指的知识点: 1. JSF全称JavaServer Faces,是Java EE(现EE4J)规范之一,用于简化Java Web应用中基于组件的用户界面构建。JSF提供了一种模型-视图-控制器(MVC)架构的实现,使得开发者可以将业务逻辑与页面表示分离。 2. “开发完整包”意味着这个JAR包包含了JSF开发所需的所有类库和资源文件。通常来说,一个完整的JSF包会包含核心的JSF库,以及一些可选的扩展库,例如PrimeFaces、RichFaces等,这些扩展库提供了额外的用户界面组件。 3. 在一个项目中使用JSF,开发者无需单独添加每个必要的JAR文件到项目的构建路径中。因为打包成一个完整的JAR包后,所有这些依赖都被整合在一起,极大地方便了开发者的部署工作。 4. “解压之后就可以直接导入工程中使用”表明这个JAR包是一个可执行的归档文件,可能是一个EAR包或者一个可直接部署的Java应用包。解压后,开发者只需将其内容导入到他们的IDE(如Eclipse或IntelliJ IDEA)中,或者将其放置在Web应用服务器的正确目录下,就可以立即进行开发。 描述中所指的知识点: 1. “解压之后就可以直接导入工程中使用”说明这个JAR包是预先配置好的,它可能包含了所有必要的配置文件,例如web.xml、faces-config.xml等,这些文件是JSF项目运行所必需的。 2. 直接使用意味着减少了开发者配置环境和处理依赖的时间,有助于提高开发效率。 标签“jsf jar包”所指的知识点: 1. 标签指明了JAR包的内容是专门针对JSF框架的。因此,这个JAR包包含了JSF规范所定义的API以及可能包含的具体实现,比如Mojarra或MyFaces。 2. “jar包”是一种Java平台的归档文件格式,用于聚合多个文件到一个文件中。在JSF开发中,JAR文件经常被用来打包和分发库或应用程序。 文件名称列表“jsf”所指的知识点: 1. “jsf”文件名可能意味着这是JSF开发的核心库,它应该包含了所有核心的JavaServer Faces类文件以及资源文件。 2. 如果是使用特定版本的JSF,例如“jsf-2.2.jar”,则表明文件内包含了对应版本的JSF实现。这种情况下,开发者必须确认他们所使用的Web服务器或应用程序服务器支持该版本的JSF。 3. 文件名称也可能是“jsf-components.jar”、“jsf-impl.jar”等,表明这个JAR包是JSF的一个子模块或特定功能组件。例如,“jsf-components.jar”可能包含了一系列用于在JSF应用中使用的自定义组件。 4. 对于开发者而言,了解文件名称中所蕴含的信息非常重要,因为这将决定他们需要下载哪些JAR包来满足特定项目的需求。 综合以上信息,开发者在使用JSF进行Java Web应用开发时,会通过一个预先配置好的JAR包来快速地搭建和启动项目。这样做不仅简化了项目初始化的过程,也使得开发者能够更加聚焦于业务逻辑的实现和界面设计,而不必深究底层框架配置的细节。
recommend-type

Pokemmo内存优化揭秘:专家教你如何降低50%资源消耗

# 摘要 本文综述了Pokemmo游戏的内存优化方法,从内存管理基础出发,探讨内存使用效率的影响因素,并介绍了性能监控与分析工具。在内存优化实践技巧章节中,详细讨论了代码层面的优化、数据结构和算法选择对内存效率的影响,并通过案例分析展示了实际的优化过程。针对Pokemmo游戏特点,分析了内存消耗特性并提出了特定优化技术。最后,本文展望了未来内存管理技术的发展方向,以及游戏开发中面临的新挑战,为Pokemmo及类似游戏提供了优化建议。 # 关键字 内存优化;内存管理;性能监控;数据结构;算法效率;游戏开发 参考资源链接:[Pokemmo必备资源包:四种ROM与汉化补丁](https://we
recommend-type

直接访问子路由是吧

<think>我们正在使用Vue2,因此需要参考VueRouterv3的文档(因为Vue2对应VueRouterv3,Vue3对应VueRouterv4)。用户的问题是:如何配置路由以支持直接访问子路由?即,在Vue2中,我们希望直接通过URL访问嵌套的子路由(例如:/parent/child),而不仅仅是先访问父路由再导航到子路由。根据之前的回答和引用,我们已经知道:1.在父路由的配置中,使用`children`数组来定义子路由。2.子路由的`path`不能以斜杠开头(例如:'child'而不是'/child'),这样它就会基于父路由的路径进行拼接。3.在父组件的模板中放置`<router-
recommend-type

C++函数库查询辞典使用指南与功能介绍

标题中提到的“C++函数库查询辞典”指的是一个参考工具书或者是一个软件应用,专门用来查询C++编程语言中提供的标准库中的函数。C++是一种静态类型、编译式、通用编程语言,它支持多种编程范式,包括过程化、面向对象和泛型编程。C++标准库是一组包含函数、类、迭代器和模板的库,它为C++程序员提供标准算法和数据结构。 描述中提供的内容并没有给出实际的知识点,只是重复了标题的内容,并且有一串无关的字符“sdfsdfsdffffffffffffffffff”,因此这部分内容无法提供有价值的信息。 标签“C++ 函数库 查询辞典”强调了该工具的用途,即帮助开发者查询C++的标准库函数。它可能包含每个函数的详细说明、语法、使用方法、参数说明以及示例代码等,是学习和开发过程中不可或缺的参考资源。 文件名称“c++函数库查询辞典.exe”表明这是一个可执行程序。在Windows操作系统中,以“.exe”结尾的文件通常是可执行程序。这意味着用户可以通过双击或者命令行工具来运行这个程序,进而使用其中的查询功能查找C++标准库中各类函数的详细信息。 详细知识点如下: 1. C++标准库的组成: C++标准库由多个组件构成,包括输入输出流(iostream)、算法(algorithm)、容器(container)、迭代器(iterator)、字符串处理(string)、数值计算(numeric)、本地化(locale)等。 2. 输入输出流(iostream)库: 提供输入输出操作的基本功能。使用诸如iostream、fstream、sstream等头文件中的类和对象(如cin, cout, cerr等)来实现基本的输入输出操作。 3. 算法(algorithm)库: 包含对容器进行操作的大量模板函数,如排序(sort)、查找(find)、拷贝(copy)等。 4. 容器(container)库: 提供各种数据结构,如向量(vector)、列表(list)、队列(queue)、映射(map)等。 5. 迭代器(iterator): 迭代器提供了一种方法来访问容器中的元素,同时隐藏了容器的内部结构。 6. 字符串处理(string)库: C++标准库中的字符串类提供了丰富的功能用于处理字符串。 7. 数值计算(numeric)库: 提供数值计算所需的函数和类,比如对复数的支持和数值算法。 8. 本地化(locale)库: 提供本地化相关的功能,比如日期、时间的格式化显示以及字符的本地化比较。 9. 错误处理和异常: C++通过throw、try、catch关键字和标准异常类提供了一套异常处理机制。 10. 智能指针: C++11及其后续版本提供了智能指针(如unique_ptr、shared_ptr、weak_ptr)来自动管理动态分配的内存。 11. lambda表达式: 在C++11中引入,允许临时创建匿名函数对象。 12. C++11新特性: 包括范围for循环、移动语义、类内初始化器、auto类型推导等。 使用C++函数库查询辞典的用户可能需要对C++的基础知识有一定的掌握,例如变量、数据类型、控制结构、函数以及面向对象的概念等。了解C++标准库的结构和内容能够帮助程序员有效地利用库函数进行软件开发,提高编程效率并减少重复造轮子的工作。 总结来说,一个C++函数库查询辞典工具对于C++程序员来说是一个非常有用的资源,它能够提供快速查找标准库函数的能力,帮助程序员更高效地解决问题和进行学习。同时,随着C++标准的不断更新,例如C++11、C++14、C++17和C++20,函数库查询辞典也会不断地更新以包含新的特性,这对于紧跟技术发展的开发者来说尤为重要。
recommend-type

【bat脚本安全最佳实践】:保护你的系统与脚本安全的黄金法则

# 摘要 本文旨在全面阐述BAT脚本的基础知识、安全编写原则、审查与优化方法以及在企业环境中的安全应用。通过深入分析脚本安全基础、常见安全陷阱及脚本的权限管理,文章提出了安全编写的具体实践和预防措施。本文详细介绍了脚本安全审查流程、代码优化、错误处理和安全更新维护策略。在企业应用方面,探讨了企业安全政策制定、脚本审计和版本控制以及外部威胁的防范措施。通过案例分析,总结了脚本
recommend-type

IIC抽电

<think>首先,用户的问题是:“请问IIC电路供电问题”。这看起来是关于IIC(Inter-IntegratedCircuit)总线的电源供应问题。IIC是一种串行通信总线,常用于微控制器和外设之间的通信。从系统级指令:-所有行内数学表达式必须使用$...$格式。-独立公式必须使用$$...$$格式并单独成段。-使用中文回答。-生成相关问题。-回答中引用的段落末尾自然地添加引用标识。-回答结构清晰,帮助用户逐步解决问题。参考提供的引用:-引用[1]提到IIC总线注意事项,包括热插拔问题和电源干扰。-引用[2]是关于IIC原理的代码片段。-引用[3]讨论实时时钟RTC,提到PCF85063A