/* * @Author: mbw * @Date: 2024-11-14 10:21:04 * @LastEditors: mbw && 1600520629@qq.com * @LastEditTime: 2025-01-17 10:46:51 * @FilePath: \JT-DT-YD4N02A_RTT_MRS-NT26K\bsp\src\bsp_h308.c * @Description: * * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. */ #include "bsp_h308.h" // #include "drv_usart.h" #include "lwrb.h" // 用到了atoi #include #include "bsp_flash.h" #include "bsp_rtc.h" #include "user_sys.h" #define LOG_TAG "bsp_h308" #define LOG_LVL LOG_LVL_DBG #include // 用了浮点打印 ALIGN(8) static char h308_thread_stack[H308_THREAD_STACK_SIZE]; static struct rt_thread h308_thread; #define UART4_RX_RB_LENGTH (128U) static lwrb_t uart4_rx_rb; static rt_uint8_t uart4_rx_rb_data[UART4_RX_RB_LENGTH]; static rt_sem_t uart4_rx_ok_sem; static rt_timer_t uart4_rx_timer; uint8_t sensor_rx_count = 0; // 接收缓冲区中,已经收到的数据包数量 TsH308 H308 = {0}; void _UART4_RxTimeout(void *parameter) { rt_sem_release(uart4_rx_ok_sem); rt_timer_stop(uart4_rx_timer); } static uint8_t H308_XorChecksum(char *str, int len) { uint8_t xorvalue = 0; if (str == RT_NULL || len < 2) { // 处理错误或返回 return 0; // 或者选择抛出异常 } for (int i = 0; i < len - 4; i++) // 校验值前面的空格要, { xorvalue ^= str[i]; } return xorvalue; } // float打印问题 // https://www.wch.cn/bbs/thread-108241-1.html // https://www.wch.cn/bbs/thread-91909-1.html // https://club.rt-thread.org/ask/article/1d040664a33a7b46.html // https://club.rt-thread.org/ask/article/1d040664a33a7b46.html /** * @brief 打印数据 * @param data:使用8字节对齐就好着,4字节对齐就出现问题,问题解决,在cpuport.c中将RT_ALIGN_DOWN((rt_ubase_t)stk, REGBYTES)改为RT_ALIGN_DOWN((rt_ubase_t)stk, 8); * @retval None */ void H308_ShowData(TsH308Data data) { // A+000.00 +31.1 0657.80 +18.1 B+008.0 00 12 LOG_D("H308Data: %6.2f, %5.1f, %7.2f, %5.1f, %5.1f, %02X, %02X", data.lel, data.temp, data.laser_temp, data.signal_strength, data.gain, data.fault_code, data.checksum); } #ifdef TEST_ENABLE void Sensor_ShowData(void) { H308_ShowData(H308.Data); } MSH_CMD_EXPORT(Sensor_ShowData, Sensor_ShowData); #endif uint8_t H308_GetFrameData(const char *p_src, const rt_uint8_t src_len, TsH308Data *pData) { // A+000.00 +31.1 0657.80 +18.1 B+008.0 00 12 rt_uint8_t xor = 0; uint8_t ret = 0; char *p_str = strstr(p_src, "A+"); // 查找子字符串的位置 uint32_t offset = p_str - p_src; // 计算偏移量 TsH308StrData _H308StrData = {0}; if ((p_str != NULL) && (offset <= src_len - 44)) { if (sscanf(p_str, "A+%6s %6s %8s %6s B+%6s %2s %2s", _H308StrData.vol, _H308StrData.temp, _H308StrData.laser_temp, _H308StrData.signal_strength, _H308StrData.gain, _H308StrData.fault_code, _H308StrData.checksum) == 7) { pData->checksum = (rt_uint8_t)strtol(_H308StrData.checksum, NULL, 16); xor = H308_XorChecksum(p_str, 44); // 对数据进行异或校验 if (xor == pData->checksum) { pData->lel = (float)(atof(_H308StrData.vol) * 20); pData->temp = (float)atof(_H308StrData.temp); pData->laser_temp = (float)atof(_H308StrData.laser_temp); pData->signal_strength = (float)atof(_H308StrData.signal_strength); pData->gain = (float)atof(_H308StrData.gain); pData->fault_code = (rt_uint8_t)strtol(_H308StrData.fault_code, NULL, 16); pData->checksum = (rt_uint8_t)strtol(_H308StrData.checksum, NULL, 16); ret = 0; } else { LOG_E("xor failed"); ret = RT_ERROR; } } else { ret = RT_ERROR; LOG_E("H308_ExtractData failed"); } } return ret; } static uint8_t H308_Count(const rt_uint8_t *buffer, uint8_t value, uint8_t size) { uint8_t count = 0; for (uint8_t i = 0; i < size; i++) { if (buffer[i] == value) { count++; } } return count; } // static void H308_HandleAbnormal(uint8_t count, uint8_t *flag, uint8_t threshold) //{ // if (count > threshold && *flag == 0) // { // H308.detection_flag = kH308Abnormal; // Send_Laser_Alarm_Event(kAlarmExceptionEvent); // *flag = 1; // } // else if (*flag == 1 && count < threshold) // { // *flag = 0; // H308.detection_flag = kH308Normal; // Send_Laser_Alarm_Event(kNormalDetectionEvents); // } // } static void H308_HandleAlarm(uint8_t count, uint8_t *flag, uint8_t threshold) { if (count >= threshold && *flag == 0) { H308.detection_flag = kH308Alarm; Send_Laser_Alarm_Event(kAlarmEvent); *flag = 1; } else if (*flag == 1 && count == 0) { *flag = 0; H308.detection_flag = kH308Normal; Send_Laser_Alarm_Event(kAlarmRcyEvent); } } static void H308_HandleFault(uint8_t count, uint8_t *flag, uint8_t threshold) { if (count >= threshold && *flag != 1) { *flag = 1; H308.detection_flag = kH308Fault; Send_Laser_Alarm_Event(kFaultEvent); } else if (*flag == 1 && count == 0) { *flag = 0; H308.detection_flag = kH308Normal; Send_Laser_Alarm_Event(kFaultRcyEvent); } } static uint8_t H308_CheckData(void) { static rt_uint8_t alarm_flag = 0, fault_flag = 0; static rt_uint8_t alarm_count = 0, fault_count = 0; static rt_uint8_t index = 0; static rt_uint8_t alarm_status_buffer[H308_SAMPLING_TIMS] = {0}; static rt_uint8_t fault_buf[H308_SAMPLING_TIMS] = {0}; alarm_status_buffer[index] = (H308.Data.lel < (float)H308.alarm_value) ? kH308Normal : kH308Alarm; fault_buf[index] = (H308.Data.fault_code == 0) ? kH308Normal : kH308Fault; index++; if (index >= H308_SAMPLING_TIMS) { index = 0; } alarm_count = H308_Count(alarm_status_buffer, kH308Alarm, H308_SAMPLING_TIMS); fault_count = H308_Count(fault_buf, kH308Fault, H308_SAMPLING_TIMS); H308_HandleAlarm(alarm_count, &alarm_flag, H308_SAMPLING_TIMS); H308_HandleFault(fault_count, &fault_flag, H308_SAMPLING_TIMS); return RT_EOK; } // TODO: 寿命检测 uint8_t IS_H308_EndOfLife(void) { RTC_GetTime(); if (RtcDateTime.year > 2035)//至少大于2035年再检测 { if (RTC_GetCounter() >= H308.expiration_seconds) { H308.end_of_life = 1; } } return H308.end_of_life; } void UART4_Init(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; USART_InitTypeDef USART_InitStructure = {0}; NVIC_InitTypeDef NVIC_InitStructure = {0}; lwrb_init(&uart4_rx_rb, uart4_rx_rb_data, sizeof(uart4_rx_rb_data)); USART_DeInit(UART4); // 寄存器恢复默认值 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOC, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_Init(UART4, &USART_InitStructure); USART_ITConfig(UART4, USART_IT_RXNE, ENABLE); NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_Cmd(UART4, ENABLE); LOG_I("UART4 Init"); } static void h308_thread_entry(void *param) { rt_err_t ret; static uint8_t str[UART4_RX_RB_LENGTH] = {0}; static uint8_t h308_rx_timout_cnt = 0; static uint8_t h308_err_cnt = 0; H308.alarm_value = Flash_Get_SysCfg(kAlarmLValueId); // 获取系统报警阈值 LOG_D("报警阈值:%d%LEL", H308.alarm_value); while (1) { ret = rt_sem_take(uart4_rx_ok_sem, 3000); if (ret == RT_EOK) { uint8_t len = lwrb_get_full(&uart4_rx_rb); lwrb_read(&uart4_rx_rb, str, len); rt_memset(&str[len - 2], 0, 2); if (len >= 44) { ret = H308_GetFrameData((const char *)str, len, &H308.Data); LOG_I("str:[%s]", str); if (ret == 0) { H308_CheckData(); } else { h308_err_cnt++; } } else { h308_err_cnt++; LOG_E("(len = %d) < 44, error data:[%s]", len, str); if (h308_err_cnt >= 5) { H308_RST_ON; rt_thread_mdelay(100); H308_RST_OFF; rt_thread_mdelay(10000); h308_err_cnt = 0; } } rt_memset(str, 0, len); if (h308_rx_timout_cnt) { h308_rx_timout_cnt = 0; } } else if (ret == -RT_ETIMEOUT)//这个主要是考虑传感器未焊接好,或者脱落的情况,国标要求30s内反应 3*5 = 15s,符合国标 { h308_rx_timout_cnt++; if (h308_rx_timout_cnt >= 5) { H308_RST_ON; rt_thread_mdelay(100); H308_RST_OFF;//复位一下 h308_rx_timout_cnt = 0; if (H308.detection_flag != kH308Fault) { H308.detection_flag = kH308Fault; Send_Laser_Alarm_Event(kFaultEvent); } } } } } int BSP_H308_Init(void) { rt_pin_mode(H308_PWR_PIN, PIN_MODE_OUTPUT); rt_pin_mode(H308_RST_PIN, PIN_MODE_OUTPUT); H308_RST_OFF; H308_PWR_ON; uart4_rx_ok_sem = rt_sem_create("uart4_rx", 0, RT_IPC_FLAG_FIFO); if (uart4_rx_ok_sem == RT_NULL) { LOG_E("uart4_rx_ok_sem create failed"); } uart4_rx_timer = rt_timer_create("_UART4_RxTimeout", _UART4_RxTimeout, RT_NULL, 200, RT_TIMER_FLAG_PERIODIC); if (uart4_rx_timer == RT_NULL) { LOG_E("uart4_rx_timer create failed"); } UART4_Init(); rt_err_t ret = rt_thread_init(&h308_thread, "h308_thread", h308_thread_entry, RT_NULL, &h308_thread_stack[0], sizeof(h308_thread_stack), H308_THREAD_PRIORITY, H308_THREAD_TIMESLICE); if (ret == RT_EOK) { rt_thread_startup(&h308_thread); } else { LOG_E("rt_thread_init h308_thread Failed"); return ret; } return ret; } INIT_PREV_EXPORT(BSP_H308_Init); void UART4_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); void UART4_IRQHandler(void) { GET_INT_SP(); rt_interrupt_enter(); if (USART_GetITStatus(UART4, USART_IT_RXNE) != RESET) { uint8_t temp = USART_ReceiveData(UART4); lwrb_write(&uart4_rx_rb, &temp, 1); // sensor_rx_count++; rt_timer_start(uart4_rx_timer); } rt_interrupt_leave(); FREE_INT_SP(); } #ifdef TEST_ENABLE static void TEST_H308(int argc, char **argv) { if (argc == 2) { int cmd = atoi(argv[1]); switch (cmd) { case 0: H308_PWR_OFF; LOG_D("H308_PWR_OFF"); break; case 1: H308_PWR_ON; LOG_D("H308_PWR_ON"); break; case 2: H308_RST_OFF; LOG_D("H308_RST_OFF"); break; case 3: H308_RST_ON; LOG_D("H308_RST_ON"); break; default: break; } } else { LOG_E("TEST_H308 --use _cmd_ [mode] 0:PWR_OFF 1:PWR_ON 2:RST_OFF 3:RST_ON"); } } MSH_CMD_EXPORT(TEST_H308, "TEST_H308"); static void TEST_H308_EndOfLife(void) { H308.end_of_life = 1; } MSH_CMD_EXPORT(TEST_H308_EndOfLife, TEST_H308_EndOfLife); #endif