BLE_TYQ_BJQ_CH32V303/applications/main.c

735 lines
25 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @Author: mbw
* @Date: 2024-10-23 17:14:16
* @LastEditors: mbw && 1600520629@qq.com
* @LastEditTime: 2025-06-06 14:00:40
* @FilePath: \ble_bjq_ch303rct6_ml307\applications\main.c
* @Descrt_thread_
*
* Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
*/
#include "ch32v30x.h"
#include <rtthread.h>
#include <rthw.h>
#include "drivers/pin.h"
#include <board.h>
#include "drv_gpio.h"
#include "bsp_emv.h"
#include "bsp_beep.h"
#include "bsp_led.h"
#include "bsp_rtc.h"
#include "bsp_flash.h"
#include "bsp_hr.h"
#include "bsp_mq.h"
#include "bsp_button.h"
#include "bsp_ml307.h"
#include "bsp_adc.h"
#include "bsp_vin_detection.h"
#include "user_sys.h"
#include "bsp_bt.h"
#include "math.h"
#define LOG_TAG "main"
#define LOG_LVL LOG_LVL_DBG
#include <ulog.h>
static rt_uint32_t event_flags[kMaxEventcnt] = {0};
struct rt_event alarm_event;
rt_bool_t is_event_initialized = RT_FALSE; // 是否初始化完成
TsSysControl SysControl;
struct rt_timer work_cnt_timer;
struct rt_timer preheat_timer; // 传统模式需要进行预热,
uint8_t preheat_flag = 0; // 预热时间是否结束标志
uint8_t Calibration_flag = 0; // 查看是否在标定检测状态
void Send_Laser_Alarm_Event(AlarmEvent event_type);
TeCalibrationStatus g_Calibration_status = kNotCalibrated;
static void Set_Event(AlarmEvent event_type)
{
if (event_type < kMaxEventcnt)
{
event_flags[event_type] = (1 << event_type);
}
}
void SYS_EventInit(void)
{
if (!is_event_initialized)
{
if (rt_event_init(&alarm_event, "alarm_event", RT_IPC_FLAG_PRIO) == RT_EOK)
{
for (AlarmEvent event = kPowerOnEvent; event < kMaxEventcnt; event++)
{
Set_Event(event);
}
is_event_initialized = RT_TRUE;
}
else
{
is_event_initialized = RT_FALSE;
LOG_E("Alarm event init failed!");
}
}
}
rt_uint32_t Get_Sys_Event_Flag(AlarmEvent event_type)
{
if (is_event_initialized == RT_TRUE)
{
if (event_type < kMaxEventcnt)
{
return event_flags[event_type];
}
}
return kMaxEventcnt;
}
void Send_Laser_Alarm_Event(AlarmEvent event_type)
{
if (is_event_initialized == RT_TRUE)
{
if (SysControl.status == kPowerDownEvent)
{
LOG_D("掉电模式下不处理其他事件");
}
else
{
LOG_I("Send_Laser_Alarm_Event = %d", event_type);
rt_event_send(&alarm_event, Get_Sys_Event_Flag(event_type));
}
}
else
{
is_event_initialized = RT_FALSE;
LOG_E("Alarm event no init !");
}
}
int _Self_Check_Mode(void)
{
LED_STOP(r);
LED_STOP(g);
LED_STOP(y);
rt_thread_mdelay(500);
LED_CTRL(g, "500,2500", -1);
LED_START(g);
rt_thread_mdelay(1000);
LED_CTRL(y, "500,2500", -1);
LED_START(y);
rt_thread_mdelay(1000);
LED_CTRL(r, "500,2500", -1);
LED_START(r);
rt_thread_mdelay(1000);
BEEP_SELF_CHECK;
return RT_EOK;
}
void Work_Cnt_Timer_Callback(void *parameter)
{
work_duration++;
if (IS_EndOfLife()) // 每小时检测一下是否过期
{
if (Flash_GetNum_Records(kRecordSensoEndOfLife) == 0)
{
Flash_Write_Record(kRecordSensoEndOfLife);
}
Send_Laser_Alarm_Event(kSensorFailureEvent);
}
}
void Preheat_Timer_Callback(void *parameter)
{
LED_STOP(r);
LED_STOP(g);
LED_STOP(y);
LOG_D("预热完成");
preheat_flag = 1;
if (g_Calibration_status == kSysGasCalibStatus)
{
Send_Laser_Alarm_Event(kNormalDetectionEvents);
}
else
{
Send_Laser_Alarm_Event(kCalibrationEvent);
}
}
#define STABLE_THRESHOLD 20 // 20波动视为稳定
uint16_t Get_Stable_Reading(uint8_t cnt, uint32_t timeout_ms)
{
uint32_t start = rt_tick_get();
uint16_t last = Get_Gas_VoltageAdcInt1000x();
uint16_t current;
uint8_t stable_count = 0;
while ((rt_tick_get() - start) < timeout_ms)
{
current = Get_Gas_VoltageAdcInt1000x();
uint16_t diff = fabs(current - last);// 差值
if (diff < STABLE_THRESHOLD)
{
stable_count++;
if (stable_count >= cnt) return current; // 连续n次稳定
}
else
{
stable_count = 0;
}
last = current;
rt_thread_mdelay(300);
}
return 0; // 超时
}
/*标定函数*/
int APP_Calibration_Handle(void)
{
uint16_t gas_calibration_voltage = 0;
// if (Get_Gas_VoltageAdcInt1000x() > 400 && Get_Gas_VoltageAdcInt1000x() < 900)
// {
// LED_OFF(r);
// LED_OFF(g);
// LED_ON(y);
// LOG_D("传感器故障");
// return 0;
// }
if (Get_Gas_VoltageAdcInt1000x() > (MQ_VOLTAGE_ALARM_DEFAULT - 1500) && Get_Gas_VoltageAdcInt1000x() < (MQ_VOLTAGE_ALARM_DEFAULT + 1000))
{
LOG_D("标定开始");
LED_OFF(g);
LED_OFF(y);
LED_OFF(r);
LED_CTRL(y, "200,200", -1);
LED_START(y);
}
else
{
g_Calibration_status = kNotCalibrated;
LOG_D("没有气体,请重新上电标定");
Send_Laser_Alarm_Event(kNotCalibratedEvent);
return 0;
}
Calibration_flag = 1;
uint8_t calibration_buf[2] = {0};
/* 获取10个数据 */
#if 1
uint8_t i = 0;
uint16_t gas_buf[10] = {0};
for (i = 0; i < 10; i++)
{
gas_buf[i] = Get_Gas_VoltageAdcInt1000x();
if (gas_buf[i] == 0)
{
return 0;
}
gas_calibration_voltage += gas_buf[i];
rt_thread_mdelay(500);
}
if (i == 10)
{
gas_calibration_voltage = (uint16_t)(gas_calibration_voltage / 10);
calibration_buf[0] = gas_calibration_voltage & 0xFF; // 低字节
calibration_buf[1] = (gas_calibration_voltage >> 8) & 0xFF; // 高字节
LOG_D("calibration_buf[0] = %X calibration_buf[1] = %X", calibration_buf[0], calibration_buf[1]);
Flash_Sys_Cfg(kAlarmLValueId, calibration_buf, 2);
LOG_D("标定完成");
Calibration_flag = 0;
Flash_Set_Calibration_State(kSysGasCalibStatus);
g_Calibration_status = kSysGasCalibStatus;
Send_Laser_Alarm_Event(kNormalDetectionEvents);
return 0;
}
else
{
LOG_E("标定错误");
return -1;
}
#else
gas_calibration_voltage = Get_Stable_Reading(10, 10000);//10s内连续10次稳定则认为其标定浓度稳定进行标定
if(gas_calibration_voltage == 0)
{
LOG_D("标定超时,标定错误");
Send_Laser_Alarm_Event(kNotCalibratedEvent);
return -1;
}
else
{
calibration_buf[0] = gas_calibration_voltage & 0xFF; // 低字节
calibration_buf[1] = (gas_calibration_voltage >> 8) & 0xFF; // 高字节
LOG_D("calibration_buf[0] = %X calibration_buf[1] = %X", calibration_buf[0], calibration_buf[1]);
Flash_Sys_Cfg(kAlarmLValueId, calibration_buf, 2);
LOG_D("标定完成");
Calibration_flag = 0;
Flash_Set_Calibration_State(kSysGasCalibStatus);
g_Calibration_status = kSysGasCalibStatus;
Send_Laser_Alarm_Event(kNormalDetectionEvents);
return 0;
}
#endif
}
int main(void)
{
// 定义超时时间,单位为毫秒
#define TIMEOUT_MS (3 * 60 * 1000)
#define WORK_TIMER_CNT (1000 * 60 * 60)//按照小时算
if (Get_VIN_VoltageInt1000x() > 10000)
{
SYS_EventInit();
BSP_SYS_Init();
work_duration = Flash_Get_WorkDuration();
LOG_D("工作时长:%d", work_duration);
// 读取历史记录总数
g_Calibration_status = Flash_Get_Calibration_State();
rt_thread_mdelay(10);
}
else
{
LOG_D("欠压复位\r\n");
RCC_ClearFlag();
NVIC_SystemReset(); // 直接重启系统
}
BSP_VIN_Detection_Init();
rt_err_t result = RT_EINVAL;
rt_uint32_t received_event;
TuFlashProductTimeLimitFrame LimitTime;
if (Flash_GetProductTimeLimit(&LimitTime, kExpirationTimeId) == READY)
{
// 计算出 到期时间对应的RTC秒数
Sensor_device.expiration_seconds = DateTime2Seconds(LimitTime.Struct.year,
LimitTime.Struct.month, LimitTime.Struct.day, LimitTime.Struct.hour,
LimitTime.Struct.minute, LimitTime.Struct.second);
LOG_D("h308_expiration_time:%04d-%02d-%02d,%02d:%02d",
LimitTime.Struct.year, LimitTime.Struct.month, LimitTime.Struct.day,
LimitTime.Struct.hour, LimitTime.Struct.minute, LimitTime.Struct.second);
}
rt_timer_init(&work_cnt_timer,
"work_cnt_timer",
Work_Cnt_Timer_Callback,
RT_NULL,
WORK_TIMER_CNT,
RT_TIMER_FLAG_PERIODIC);
rt_timer_start(&work_cnt_timer);
rt_timer_init(&preheat_timer,
"preheat_timer",
Preheat_Timer_Callback,
RT_NULL,
TIMEOUT_MS,
RT_TIMER_FLAG_SOFT_TIMER | RT_TIMER_FLAG_ONE_SHOT);
// 检测上电/掉电复位标志
if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET) // TODO:这块超级电容会造成掉电重启,并且标志是上电复位,只能通过其超级电容造成复位时事件创建失败进行判断,不治本
{
Send_Laser_Alarm_Event(kPowerOnEvent);
}
else
{
Send_Laser_Alarm_Event(kPreheatingEvent); // 这一句的作用是设备不是掉电重启的情况,直接进入预热模式
}
RCC_ClearFlag();
while (1)
{
result = rt_event_recv(&alarm_event,
Get_Sys_Event_Flag(kPowerOnEvent) | // 上电
Get_Sys_Event_Flag(kPowerDownEvent) | // 掉电
Get_Sys_Event_Flag(kPreheatingEvent) | // 预热
Get_Sys_Event_Flag(kNormalDetectionEvents) | // 正常检测
Get_Sys_Event_Flag(kSensorFailureEvent) | // 寿命到期
Get_Sys_Event_Flag(kAlarmEvent) | // 报警
Get_Sys_Event_Flag(kAlarmRcyEvent) | // 报警恢复
Get_Sys_Event_Flag(kSelfCheckEvent) | // 自检
Get_Sys_Event_Flag(kFaultEvent) | // 故障模式
Get_Sys_Event_Flag(kFaultRcyEvent) | // 故障恢复
Get_Sys_Event_Flag(KMuteEvent) | // 消音
Get_Sys_Event_Flag(kCalibrationEvent) | // 标定
Get_Sys_Event_Flag(kNotCalibratedEvent), // 标定
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER, &received_event);
if (result == RT_EOK)
{
if (is_event_initialized == RT_TRUE)
{
if (received_event & Get_Sys_Event_Flag(kPowerOnEvent)) // 上电
{
LOG_D("上电模式");
LOG_D("is_event_initialized :%d", is_event_initialized);
SysControl.status = kPowerOnEvent;
Flash_Write_Record(kRecordPowerOn);
Send_Laser_Alarm_Event(kPreheatingEvent);
}
else if (received_event & Get_Sys_Event_Flag(kPreheatingEvent)) // 预热
{
LOG_D("预热模式");
SysControl.last_status = SysControl.status;
SysControl.status = kPreheatingEvent;
if (SysControl.last_status != kSelfCheckEvent)
{
LED_G_PREAT;
rt_timer_start(&preheat_timer);
}
else
{
LED_STOP(r);
LED_STOP(g);
LED_STOP(y);
LED_CTRL(g, "100,100", -1);
LED_START(g);
}
}
else if (received_event & Get_Sys_Event_Flag(kCalibrationEvent)) // 标定状态
{
LOG_D("标定检测");
SysControl.last_status = SysControl.status;
SysControl.status = kCalibrationEvent;
APP_Calibration_Handle();
}
else if (received_event & Get_Sys_Event_Flag(kNotCalibratedEvent)) // 未标定状态
{
LOG_D("未标定模式");
SysControl.last_status = SysControl.status;
SysControl.status = kNotCalibratedEvent;
LED_STOP(r);
LED_STOP(g);
LED_STOP(y);
LED_ON(r);
}
else if (received_event & Get_Sys_Event_Flag(kNormalDetectionEvents)) // 正常检测
{
SysControl.last_status = SysControl.status;
SysControl.status = kNormalDetectionEvents;
rt_uint16_t voltage = Get_Gas_VoltageAdcInt1000x();
if (Sensor_device.detection_flag == kSensorAlarm)
{
if ((voltage > Sensor_device.alarm_value) && (voltage < MQ_VOLTAGE_HIGH_LIMIT))
{
Send_Laser_Alarm_Event(kAlarmEvent);
}
}
else if (Sensor_device.detection_flag == kSensorFault)
{
if ((voltage < MQ_VOLTAGE_LOW_LIMIT) || (voltage > MQ_VOLTAGE_HIGH_LIMIT))
{
Send_Laser_Alarm_Event(kFaultEvent);
}
}
}
else if (received_event & Get_Sys_Event_Flag(kAlarmExceptionEvent)) // 浓度异常
{
LOG_D("浓度异常模式");
SysControl.last_status = SysControl.status;
SysControl.status = kAlarmExceptionEvent;
LED_R_ALARM;
LOG_D("LED_R_ALARM");
}
else if (received_event & Get_Sys_Event_Flag(kAlarmEvent)) // 报警
{
LOG_D("报警模式");
SysControl.last_status = SysControl.status;
SysControl.status = kAlarmEvent;
LED_R_ALARM;
BEEP_ALARM;
LOG_I("报警机械手动作");
EMV_FORWARD_ON(50);
rt_thread_mdelay(10);
EMV_BACKWARD_ON(50);
Flash_Write_Record(kRecordAlarm); // 写入flash报警信息
if (Flash_Get_Valve_Num())
{
rt_uint8_t mac_addr[6];
Flash_Get_Mac_Addr(mac_addr, 1);
Bt_Valve_Handler(kValveCmdCtr, 1, mac_addr);
if (rt_sem_take(&bt_ctr_sem, 10000) == RT_EOK)
{
LOG_D("电磁阀动作完成");
}
else
{
LOG_E("电磁阀动作失败");
}
}
#if (IOT_MODULE_SWITCH == 1)
Ml307_Send_Event(kMl307AlarmEvent);
#endif
}
else if (received_event & Get_Sys_Event_Flag(kAlarmRcyEvent)) // 报警恢复
{
LOG_D("报警恢复模式");
SysControl.last_status = SysControl.status;
SysControl.status = kAlarmRcyEvent;
Flash_Write_Record(kRecordAlarmRcy);
BEEP_STOP;
#if (IOT_MODULE_SWITCH == 1)
Ml307_Send_Event(kMl307AlarmRcyEvent);
#endif
Send_Laser_Alarm_Event(kNormalDetectionEvents);
}
else if (received_event & Get_Sys_Event_Flag(kFaultEvent)) // 故障
{
LOG_D("故障模式");
SysControl.last_status = SysControl.status;
SysControl.status = kFaultEvent;
Flash_Write_Record(kRecordFault);
LED_Y_FAULT;
#if (IOT_MODULE_SWITCH == 1)
Ml307_Send_Event(kMl307FaultEvent);
#endif
}
else if (received_event & Get_Sys_Event_Flag(kFaultRcyEvent)) // 故障恢复
{
LOG_D("故障恢复模式");
SysControl.last_status = SysControl.status;
SysControl.status = kFaultRcyEvent;
Flash_Write_Record(kRecordFaultRcy);
BEEP_STOP;
Send_Laser_Alarm_Event(kNormalDetectionEvents);
#if (IOT_MODULE_SWITCH == 1)
Ml307_Send_Event(kMl307FaultRcyEvent);
#endif
}
else if (received_event & Get_Sys_Event_Flag(KMuteEvent)) // 消音
{
LOG_D("消音模式");
SysControl.last_status = SysControl.status;
SysControl.status = KMuteEvent;
#if (IOT_MODULE_SWITCH == 1)
Ml307_Send_Event(kMl307SilenceEvent);
#endif
BEEP_STOP;
}
else if (received_event & Get_Sys_Event_Flag(kPowerDownEvent)) // 掉电
{
LOG_D("掉电模式");
SysControl.last_status = SysControl.status;
SysControl.status = kPowerDownEvent;
GAS_POWER_CLOSE;
// 写入掉电记录
Flash_Write_Record(kRecordPowerDown);
Flash_Set_WorkDuration(work_duration); // 写入工作时长
if (Flash_Get_Valve_Num())
{
rt_uint8_t mac_addr[6];
Flash_Get_Mac_Addr(mac_addr, 1);
Bt_Valve_Handler(kValveCmdCtr, 1, mac_addr);
}
#if (IOT_MODULE_SWITCH == 1)
Ml307_Send_Event(kMl307PowerDownEvent);
#endif
if (Flash_Get_Valve_Num())
{
if (rt_sem_take(&bt_ctr_sem, 5000) == RT_EOK)
{
LOG_D("电磁阀动作完成");
}
else
{
LOG_E("电磁阀动作失败");
}
}
rt_uint8_t cnt = 0;
while ((ml307_power_down_flag == 0) && (cnt < 30)) // 等待接收到物联网模组关机完成
{
rt_thread_mdelay(1000);
LOG_D("cnt = %d", cnt);
cnt++;
}
__disable_irq(); // 关闭中断
NVIC_SystemReset(); // 直接重启系统
}
else if (received_event & Get_Sys_Event_Flag(kSelfCheckEvent)) // 自检
{
LOG_D("自检模式");
SysControl.last_status = SysControl.status;
LOG_D("Self Check Mode SysControl.last_status:%d", SysControl.last_status);
SysControl.status = kSelfCheckEvent;
_Self_Check_Mode();
rt_thread_mdelay(5000);
// 第5s关闭电磁阀
LOG_I("自检机械手动作");
EMV_FORWARD_ON(50);
rt_thread_mdelay(10);
EMV_BACKWARD_ON(50);
if (Flash_Get_Valve_Num())
{
rt_uint8_t mac_addr[6] = {0};
Flash_Get_Mac_Addr(mac_addr, 1);
Bt_Valve_Handler(kValveCmdCtr, 1, mac_addr);
if (rt_sem_take(&bt_ctr_sem, 10000) == RT_EOK)
{
LOG_D("电磁阀动作完成");
}
else
{
LOG_E("电磁阀动作失败");
}
}
#if (IOT_MODULE_SWITCH == 1)
Ml307_Send_Event(kMl307SelfCheckEvent);
#endif
LED_STOP(r);
LED_STOP(g);
LED_STOP(y);
if (g_Calibration_status == kSysGasCalibStatus)
{
if (SysControl.last_status == kPreheatingEvent)
{
if (preheat_flag)
{
Send_Laser_Alarm_Event(kNormalDetectionEvents);
}
else
{
Send_Laser_Alarm_Event(kPreheatingEvent);
}
}
else
{
Send_Laser_Alarm_Event(kNormalDetectionEvents);
}
}
else
{
if (preheat_flag)
{
Send_Laser_Alarm_Event(kNotCalibratedEvent);
}
else
{
Send_Laser_Alarm_Event(kPreheatingEvent);
}
}
}
else if (received_event & Get_Sys_Event_Flag(kSensorFailureEvent)) // 失效
{
LOG_D("传感器失效模式");
SysControl.last_status = SysControl.status;
SysControl.status = kSensorFailureEvent;
if (Flash_GetNum_Records(kRecordSensoEndOfLife) == 0)
{
Flash_Write_Record(kRecordSensoEndOfLife);
}
Ml307_Send_Event(kMl307DeviceFailureEvent); // 发送一个失效事件
Send_Laser_Alarm_Event(kNormalDetectionEvents); /// 再返回正常模式继续检测
// LED_Y_END_OF_LIFE;
}
}
}
}
}
#ifdef TEST_ENABLE
static void SYS_Set_RtcProductTime(int argc, char **argv)
{
if (argc == 7)
{
int year = atoi(argv[1]);
int mon = atoi(argv[2]);
int day = atoi(argv[3]);
int hour = atoi(argv[4]);
int min = atoi(argv[5]);
int second = atoi(argv[6]);
RTC_SetTime(2000 + year, mon, day, hour, min, second);
RTC_GetTime();
LOG_D("RTC: %4d-%02d-%02d, %02d:%02d:%02d", RtcDateTime.year, RtcDateTime.month, RtcDateTime.day,
RtcDateTime.hour, RtcDateTime.minute, RtcDateTime.second);
// 设置出厂时间
Flash_SetProductTimeLimit(2000 + year, mon, day, hour, min, second, kFactoryTimeId);
// 到期时间自动 + 5年30天
Set_ExpirationTime(MAX_EXPIRATION_DAYS);
}
else
{
LOG_E("SYS_Set_RtcProductTime --use _cmd_ [2000 + y] [m] [d] [h] [m] [s]");
}
}
MSH_CMD_EXPORT(SYS_Set_RtcProductTime, "SYS_Set_RtcProductTime");
// 测试系统标定值修改
static void TEST_SYS_Calibartion(int argc, char **argv)
{
if (argc == 2)
{
int calibartion_valve = atoi(argv[1]);
uint8_t calibration_buf[2] = {0};
calibration_buf[0] = calibartion_valve & 0xFF; // 低字节
calibration_buf[1] = (calibartion_valve >> 8) & 0xFF; // 高字节
Flash_Sys_Cfg(kAlarmLValueId, calibration_buf, 2);
Flash_Set_Calibration_State(kSysGasCalibStatus);
LOG_D("标定值修改为 = %d", Flash_Get_SysCfg(kAlarmLValueId));
g_Calibration_status = kSysGasCalibStatus;
Send_Laser_Alarm_Event(kNormalDetectionEvents); /// 再返回正常模式继续检测
}
else
{
LOG_E("TEST_SYS_Calibartion 0~4095");
}
}
MSH_CMD_EXPORT(TEST_SYS_Calibartion, "修改系统标定值");
static void SYS_SW_Version(void)
{
COMPILE_TIME;
rt_kprintf("JT-DT-YD4N02A Software version: V%02X\r\n", (uint8_t)Flash_Get_SysCfg(kSwVerId));
}
MSH_CMD_EXPORT(SYS_SW_Version, "软件版本和编译时间");
#endif