/* 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****/