/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file o2_sensor.c * @author Motor Control SDK Team, Yuwell Software XiangenWang * @brief Voice Recognition Module Initialization Section, including peripheral initialization and message node insertion, etc. * @version 1.0 * @changelog version 1.0 初始版本 2025.11.21 - 新增:新建第一个版本的软件,待完善解析命令后的程序执行部分 ****************************************************************************** * @attention * *

© Copyright (c) 2025 Yuwell Software Danyang.Jiangsu.China. * All rights reserved.

* * Redistribution and use in source and binary forms, with or without * modification, are permitted, provided that the following conditions are met: * * 1. Redistribution of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of Yuwell Software nor the names of other * contributors to this software may be used to endorse or promote products * derived from this software without specific written permission. * 4. This software, including modifications and/or derivative works of this * software, must execute solely and exclusively on microcontroller or * microprocessor devices manufactured by or for Yuwell Software. * 5. Redistribution and use of this software other than as permitted under * this license is void and will automatically terminate your rights under * this license. * * THIS SOFTWARE IS PROVIDED BY Yuwell Software AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT * SHALL Yuwell Software OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /* USER CODE END Header */ #include "o2_sensor.h" #include "string.h" // 存储氧传感器数据 O2SensorData o2_sensor_data; #define REQUEST_FRAME_LENGTH (4) #define OXG_FAULT_MAX (30) /** * @brief 向氧传感器发送数据请求指令 * @param NONE * @retval NONE * @note 1. 固定发送请求帧:{0x11, 0x01, 0x01, 0xED},帧长度由REQUEST_FRAME_LENGTH宏定义 * 2. 通过OXG_UART_TRANS_BYTE函数逐字节发送数据,依赖UART外设已初始化完成 * @author jarvis * @date 2025.11.25 */ void oxg_sensor_task(void) { const uint8_t sendDate[REQUEST_FRAME_LENGTH] = {0x11, 0x01, 0x01, 0xED}; for(uint8_t i = 0;i < REQUEST_FRAME_LENGTH; i++) { OXG_UART_TRANS_BYTE(sendDate[i]); } o2_sensor_data.receive_state = O2_STATE_WAIT_HEADER1; if(!xOxygenEventGroupCheckBit(&global_event, EVENT_O2_SENSOR_ERROR)) // 若当前未发生传感器故障 { o2_sensor_data.fault_count++; if(o2_sensor_data.fault_count > OXG_FAULT_MAX) { vOxygenEventGroupSetBits(&global_event, EVENT_O2_SENSOR_ERROR); // 标志当前已发生氧传感器故障信号 } } } /** * @brief 初始化氧传感器故障计数器 * @param NONE * @retval NONE * @note NONE * @author jarvis * @date 2025.11.25 */ void oxg_sensor_init(void) { FL_GPIO_InitTypeDef GPIO_InitStruct; o2_sensor_data.fault_count = 0; o2_sensor_data.receive_state = O2_STATE_WAIT_HEADER1; /* 氧传感器初始化 */ GPIO_InitStruct.pin = FL_GPIO_PIN_4|FL_GPIO_PIN_5; GPIO_InitStruct.mode = FL_GPIO_MODE_DIGITAL; GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL; GPIO_InitStruct.pull = FL_DISABLE; GPIO_InitStruct.remapPin = FL_DISABLE; GPIO_InitStruct.analogSwitch = FL_DISABLE; FL_GPIO_Init(GPIOC, &GPIO_InitStruct); // 需要单独拿出来初始化 因为时钟初始化的比较晚 FL_UART_InitTypeDef UART_InitStruct = {0}; UART_InitStruct.baudRate = 9600; //波特率 UART_InitStruct.dataWidth = FL_UART_DATA_WIDTH_8B; //数据位数 UART_InitStruct.stopBits = FL_UART_STOP_BIT_WIDTH_1B; //停止位 UART_InitStruct.parity = FL_UART_PARITY_NONE; //奇偶校验 UART_InitStruct.transferDirection = FL_UART_DIRECTION_TX_RX; //接收-发送使能 FL_UART_Init(UART5, &UART_InitStruct); NVIC_DisableIRQ(UART5_IRQn); NVIC_SetPriority(UART5_IRQn,2);//中断优先级配置 NVIC_EnableIRQ(UART5_IRQn); FL_UART_ClearFlag_RXBuffFull(UART5); FL_UART_EnableIT_RXBuffFull(UART5); FL_UART_ClearFlag_TXShiftBuffEmpty(UART5); } /** * @brief 解析氧传感器接收的原始数据 * @param p_o2_frame - O2SensorData类型指针,指向存储原始数据和解析结果的结构体 * @retval NONE * @note 1. 氧浓度 = DF[0]*256 + DF[1](16位无符号数据拼接) * 2. 氧流量 = DF[2]*256 + DF[3](16位无符号数据拼接) * 3. 温度解析功能默认注释禁用,如需启用可取消#if 0宏定义 * 4. 需确保p_o2_frame指针非空,且O2_raw_data.DF数组已存储有效原始数据 * @author jarvis * @date 2025.11.25 */ static void o2_data_decode(O2SensorData* p_o2_frame) { MsgQueueItem queue_item; // 计算氧传感器的氧浓度 p_o2_frame->o2_concentration = p_o2_frame->O2_raw_data.DF[0]*256+p_o2_frame->O2_raw_data.DF[1]; // 计算氧浓度的流量值 p_o2_frame->o2_flow = p_o2_frame->O2_raw_data.DF[2]*256+p_o2_frame->O2_raw_data.DF[3]; // 向队列中插入一条氧传感器数据 queue_item.type = MSG_TYPE_OXYGEN_SENSOR; queue_item.data.oxygen.concentration = p_o2_frame->o2_concentration; queue_item.data.oxygen.flow_rate = p_o2_frame->o2_flow; modify_or_add_queue_node_by_type(&global_queue, queue_item.type, queue_item); // 修改队列中的浓度数据 if(xOxygenEventGroupCheckBit(&global_event, EVENT_O2_SENSOR_ERROR)) // 若当前存在错误标志则清空故障 { vOxygenEventGroupClearBits(&global_event, EVENT_O2_SENSOR_ERROR); o2_sensor_data.fault_count = 0; } } /** * @brief 氧传感器数据接收字节处理函数(状态机实现) * @param byte - 从UART接收的单个字节数据 * @retval NONE * @note 1. 采用状态机处理帧接收:等待帧头1(0x16)→等待帧头2(0x09)→等待帧头3(0x01)→接收数据→校验帧 * 2. 数据段长度固定为8字节(DF_DATE_LENGTH=8),接收完成后进行求和校验 * 3. 校验逻辑:sum=0x16+0x09+0x01+8字节数据 → 校验和=256-sum,与接收的校验字节比对 * 4. 校验成功后更新帧状态为O2_FRAME_COMPLETE,并调用o2_data_decode解析数据 * 5. 依赖全局变量o2_sensor_data存储接收状态、帧状态和原始数据 * @author jarvis * @date 2025.11.25 */ static void request_o2_byte_process(uint8_t byte) { static uint8_t wait_data_count = 0; const uint8_t DF_DATE_LENGTH = 8; uint8_t check_sum = 0; switch(o2_sensor_data.receive_state) { case O2_STATE_WAIT_HEADER1: if(byte == 0x16) { o2_sensor_data.receive_state = O2_STATE_WAIT_HEADER2; o2_sensor_data.frame_state = O2_FRAME_RECEIVING; }else{ o2_sensor_data.receive_state = O2_STATE_WAIT_HEADER1; } break; case O2_STATE_WAIT_HEADER2: if(byte == 0x09) { o2_sensor_data.receive_state = O2_STATE_WAIT_HEADER3; }else{ o2_sensor_data.receive_state = O2_STATE_WAIT_HEADER1; } break; case O2_STATE_WAIT_HEADER3: if(byte == 0x01) { o2_sensor_data.receive_state = O2_STATE_RECV_DATA; wait_data_count = 0; memset(o2_sensor_data.O2_raw_data.DF, 0, sizeof(o2_sensor_data.O2_raw_data.DF)); // 清空缓存 }else{ o2_sensor_data.receive_state = O2_STATE_WAIT_HEADER1; } break; case O2_STATE_RECV_DATA: o2_sensor_data.O2_raw_data.DF[wait_data_count] = byte; wait_data_count++; if(wait_data_count == DF_DATE_LENGTH) { o2_sensor_data.receive_state = O2_STATE_CHECK_FRAME; } break; case O2_STATE_CHECK_FRAME: check_sum = 0x16 + 0x09 + 0x01 + o2_sensor_data.O2_raw_data.DF[0] +\ o2_sensor_data.O2_raw_data.DF[1] + o2_sensor_data.O2_raw_data.DF[2] + \ o2_sensor_data.O2_raw_data.DF[3] + o2_sensor_data.O2_raw_data.DF[4] + \ o2_sensor_data.O2_raw_data.DF[5] + o2_sensor_data.O2_raw_data.DF[6] + o2_sensor_data.O2_raw_data.DF[7]; check_sum = 256 - check_sum; if(check_sum == byte) // 对数据进行校验 校验合格之后对数据进行处理 { o2_sensor_data.receive_state = O2_STATE_WAIT_HEADER1; o2_sensor_data.frame_state = O2_FRAME_COMPLETE; o2_data_decode(&o2_sensor_data); }else{ o2_sensor_data.receive_state = O2_STATE_WAIT_HEADER1; o2_sensor_data.frame_state = O2_FRAME_IDLE; } break; default: o2_sensor_data.frame_state = O2_FRAME_IDLE; o2_sensor_data.receive_state = O2_STATE_WAIT_HEADER1; // 默认状态下将状态机改为原始状态 } } /** * @brief UART5接收中断服务函数 * @param NONE * @retval NONE * @note 1. 中断触发条件:UART5接收缓冲区非空(RXBuffFull中断) * 2. 读取接收字节后,调用request_o2_byte_process函数进行状态机处理 * 3. 静态变量count未实际使用,可根据需求保留或删除 * 4. 需提前配置UART5接收中断使能,确保FL_UART相关驱动函数已实现 * @author jarvis * @date 2025.11.25 */ void UART5_IRQHandler(void) { uint8_t temp_data; if((FL_ENABLE == FL_UART_IsEnabledIT_RXBuffFull(O2_SENSOR_USED_UART_NUM)) &&(FL_SET == FL_UART_IsActiveFlag_RXBuffFull(O2_SENSOR_USED_UART_NUM))) { temp_data = FL_UART_ReadRXBuff(O2_SENSOR_USED_UART_NUM); request_o2_byte_process(temp_data); } } /************************ (C) COPYRIGHT YUWELL *****END OF FILE****/