环境安全卫士固件开发

Posted 三明治开发社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了环境安全卫士固件开发相关的知识,希望对你有一定的参考价值。

固件开发

开发环境是在Linux下进行开发的,环境搭建和SDK的拉取可以在涂鸦github上的仓库上进行学习。

该代码是基于1.0.2版本的 SDK 进行开发的,第一次接触soc开发的同学,可以在涂鸦github上的仓库拉取代码进行学习和开发。该代码中的 apps/template-demo 比较简单,可在该代码的基础上进行学习或开发。

本 demo可在github上下载源代码,下载完成源代码后,将代码放入SDK里面的APPS文件夹下。进行编译下载就可以了。编译后的产物中会出现QIO,UA,UG文件其中QIO是生产固件,UA是用户去固件,UG是升级固件。
在这里插入图片描述

本 demo主要是通过3种方式进行获取传感器信息的,分别是串口,adc,检测引脚高低电平。下面将以这三种方式进行简单的介绍。

1.串口类传感器:甲醛,pm2.5

通过阅读甲醛传感器的资料我们可以发现,传感器数据上传格式和计算方法如下:

 /***********************************************************
 *   Function:  get_ch2o_sensor_value
 *   Input:     none
 *   Output:    none
 *   Return:    none
 *   Notice:    得到并上传甲醛的数据
 ***********************************************************/
static VOID get_ch2o_sensor_value(VOID)
{
    UINT_T  buff_ret, find_head_index = 0;
    //甲醛数据高位,低位
    UCHAR_T ch2o_data_high, ch2o_data_low;
    //校验和
    UCHAR_T check_sums = 0x00;    
    //串口数据缓存区
    UCHAR_T ch2o_receive_buffer[CH2O_BUFFER_SIZE];
    //指向甲醛数据头部
    UCHAR_T *p_ch2o_value = NULL;

    memset(ch2o_receive_buffer, 0, sizeof(ch2o_receive_buffer));

    //读取串口数据
    bk_uart_recv(CH2O_SENSOR_UART, ch2o_receive_buffer, CH2O_BUFFER_SIZE, 0xFFFF);

    // for (find_head_index = 0; find_head_index<CH2O_BUFFER_SIZE; find_head_index++) {
    //     PR_NOTICE("ch2o_receive_buffer[%d] = %02x", find_head_index, ch2o_receive_buffer[find_head_index]);
    // }

    //寻找 ch2o 传感器发送过来的头部
    for (find_head_index = 0; find_head_index<CH2O_BUFFER_SIZE; find_head_index++) {
        if (ch2o_receive_buffer[find_head_index] == 0xff && \\
            ch2o_receive_buffer[find_head_index+1] == 0x17 && \\
            ch2o_receive_buffer[find_head_index+2] == 0x04){
            //PR_NOTICE("find head is %d", find_head_index);
            break;
        }
    }

    //本次采集数据不完整
    if (find_head_index > 11) { 
        PR_ERR("ch2o get uart data no complete!");
        return;
    }

    //将指针指向 ch2o 数据中的头部
    p_ch2o_value = ch2o_receive_buffer + find_head_index;

    //检验和,确认读取的数据的准确性
    check_sums = ch2o_check_sum(p_ch2o_value, 9);
    if (check_sums != *(p_ch2o_value + 8)) {
        PR_ERR("ch2o check_sums error");
        return;
    }
    
    ch2o_data_high = *(p_ch2o_value+4);
    ch2o_data_low = *(p_ch2o_value+5);

    gs_air_box.ch2o_value = ch2o_data_high * 256 + ch2o_data_low;

    //PR_NOTICE("ch2o value is : %d .", gs_air_box.ch2o_value);

    //上传 ch2o 数据到涂鸦云
    updata_dp_single(gs_air_box.dp_ch2o_value, PROP_VALUE, gs_air_box.ch2o_value);

    return;
}

校验和的计算方式为:

 /***********************************************************
 *   Function:  ch2o_check_sum
 *   Input:     none
 *   Output:    none
 *   Return:    none
 *   Notice:    甲醛数据校验和
 ***********************************************************/
static UCHAR_T ch2o_check_sum(UCHAR_T *data, UCHAR_T len)
{
    UCHAR_T i, tempq = 0;
    data += 1; //指向data[1]

    for(i=0; i<(len-2); i++)
    {
        tempq += *data;
        data++;
    }

    tempq = (~tempq) + 1;

    return (tempq);
}

PM2.5的获取方法和甲醛的很相似,这里不再过多介绍。

2.ADC类传感器:燃气传感器,烟雾传感器

相关资料
由于在WB3S上只要一个ADC,所以我们这里用RS2255 芯片进行复用,引脚选择如下:

A(PWM0/GPIOA_6)B(PWM1/GPIOA_7)ON CHANNEL(S)
00A0
01A1
10A2
11A3

ADC初始化:

/* ADC */
#define ADC_DATA_LEN    4
static  tuya_adc_dev_t  tuya_adc;

static VOID adc_init(VOID)
{
    tuya_adc.priv.pData = Malloc(ADC_DATA_LEN * sizeof(USHORT_T)); //这里一直使用tuya_adc,所有后面就没有释放该空间
    memset(tuya_adc.priv.pData, 0, ADC_DATA_LEN*sizeof(USHORT_T));
    tuya_adc.priv.data_buff_size = ADC_DATA_LEN; //设置数据缓存个数
}

ADC采集:

 /***********************************************************
 *   Function:  get_adc_value
 *   Input:     none
 *   Output:    adc_value : 采集到的 adc 值
 *   Return:    none
 *   Notice:    得到 adc 采集的电压值
 ***********************************************************/
VOID get_adc_value(OUT USHORT_T* adc_value) 
{
    INT_T ret;

    if (adc_value == NULL) {
        PR_ERR("pm25_adc_value is NULL");
        return;
    }
    memset(tuya_adc.priv.pData, 0, ADC_DATA_LEN*sizeof(USHORT_T));
    ret = tuya_hal_adc_init(&tuya_adc);
    if (ret != OPRT_OK) {
        PR_ERR("ADC init error : %d ", ret);
        return;
    }

    ret = ret = tuya_hal_adc_value_get(ADC_DATA_LEN, adc_value); 
    if (ret != OPRT_OK) {
        PR_ERR("ADC get value error : %d ", ret);
    }

    tuya_hal_adc_finalize(&tuya_adc);
    return;
}

烟雾传感器,数据获取:

/* 烟雾传感器 */
#define SMOKE_ALARM_LIM 1.0

/***********************************************************
 *   Function:  get_smoke_sensor_value
 *   Input:     none
 *   Output:    none
 *   Return:    none
 *   Notice:    得到并上传烟雾的数据,A1
 ***********************************************************/
static VOID get_smoke_sensor_value(VOID)
{
    USHORT_T    smoke_adc_value;
    FLOAT_T     smoke_volt; 

    //复用 adc 到 A1 
    tuya_gpio_write(RS2255_A, FALSE);
    tuya_gpio_write(RS2255_B, TRUE);

    tuya_hal_system_sleep(500);

    //得到烟雾传感器 ad 值
    get_adc_value(&smoke_adc_value);
    //PR_NOTICE("smoke_adc_value : %d ", smoke_adc_value);

    //计算实际电压值
    smoke_volt = (smoke_adc_value / 4095.0) * 2.4 * 2;
    //PR_NOTICE("smoke_volt : %lf ", smoke_volt);

    //判断是否到报警门限值
    if (smoke_volt >= SMOKE_ALARM_LIM) {
        gs_air_box.smoke_state = ALARM;
    } else {
        gs_air_box.smoke_state = NORMAL;
    }

    //上传数据
    updata_dp_single(gs_air_box.dp_smoke_state, PROP_ENUM, gs_air_box.smoke_state);

    //PR_NOTICE("get smoke value, updata...");
    return;
}

燃气传感器和烟雾相似,这里就不再过多介绍。

3.检测引脚高低电平获取状态:火焰传感器

火焰传感器,检测到火焰后断开220v电源,重启后220v通电,防止发生意外情况。

 /***********************************************************
 *   Function:  get_smoke_sensor_value
 *   Input:     none
 *   Output:    none
 *   Return:    none
 *   Notice:    得到并上传火焰的数据
 ***********************************************************/
static VOID get_flame_sensor_value(VOID)
{
    if (FALSE == tuya_gpio_read(FLAME_SENSOR_PIN)) {
        gs_air_box.flame_state = ALARM;
        /* 检测到火焰,拉低220V控制引脚,断电 */
        tuya_gpio_write(POWER_OFF_220V_PIN, FALSE);
    } else {
        gs_air_box.flame_state = NORMAL;
    }

    updata_dp_single(gs_air_box.dp_flame_state, PROP_ENUM, gs_air_box.flame_state);

    return;
}

4.设备初始化:

启动时,先对环境安全卫士相关的外设和引脚进行初始化设置,创建信号量,传感器预热,预热完成后释放信号量,开始采集。

 /***********************************************************
 *   Function:  air_box_device_init
 *   Input:     none
 *   Output:    none
 *   Return:    none
 *   Notice:    环境安全卫士设备初始化
 ***********************************************************/
VOID air_box_device_init(VOID)
{
    INT_T opRet = OPRT_OK;

    /* 火焰传感器相关外设初始化 */
    tuya_gpio_inout_set(FLAME_SENSOR_PIN, TRUE);
    tuya_gpio_inout_set(POWER_OFF_220V_PIN, FALSE);
    /* 启动时,拉高220V控制引脚,通电 */
    tuya_gpio_write(POWER_OFF_220V_PIN, TRUE);

    /* ADC 复用,相关引脚初始化 */ 
    tuya_gpio_inout_set(RS2255_A, FALSE);
    tuya_gpio_inout_set(RS2255_B, FALSE);
    adc_init();

    /* 甲醛传感器使用 uart2 接收数据,在函数 app_init() 里面已经修改完成波特率 */
    
    /* pm2.5 传感器 串口 初始化 */
    ty_uart_init(PM25_SENSOR_UART, TYU_RATE_9600, TYWL_8B, TYP_NONE, TYS_STOPBIT1, (PM25_BUFFER_SIZE * SIZEOF(UCHAR_T)), TRUE);

    /* 创建信号量 */
    opRet = tuya_hal_semaphore_create_init(&preheat_semaphore, 0, 1);
    if (opRet != OPRT_OK) {
        PR_ERR("creat preheat semaphore error : %d", opRet);
    }

    /* 预热 60s 后释放信号量,开始采集传感器数据 */
    opSocSWTimerStart(preheat_timer, SENSOR_PREHEAT_TIME, preheat_semaphore_post_task); 

    tuya_hal_thread_create(NULL, "acquire sensor data", 512*4, TRD_PRIO_2, acquire_data_task, NULL);
}

预热完成释放信号量:

VOID preheat_semaphore_post_task(VOID)
{
    //预热完成,释放信号量
    tuya_hal_semaphore_post(preheat_semaphore);
    //关闭预热软件定时器
    opSocSWTimerStop(preheat_timer);

    //预热完成,上传预热完成数据到涂鸦云
    gs_air_box.preheat_state = false;
    updata_dp_single(gs_air_box.dp_preheat, PROP_BOOL, gs_air_box.preheat_state);
}

传感器采集数据任务轮询函数:

 /***********************************************************
 *   Function:  acquire_data_task
 *   Input:     none
 *   Output:    none
 *   Return:    none
 *   Notice:    获取传感器数据任务
 ***********************************************************/
VOID acquire_data_task(VOID)
{
    //等待预热完成
    tuya_hal_semaphore_wait(preheat_semaphore);

    while (1) {
        get_ch2o_sensor_value();
        get_flame_sensor_value();
        get_gas_sensor_value();
        get_pm25_sensor_value();
        get_smoke_sensor_value();
        tuya_hal_system_sleep(500);
    }
}

整机演示

1.实时显示当前空气状况

烧录授权完成后,设备就可以正常配网了。连接WiFi,打开蓝牙,按照配网流程成功配网后,即可使用app控制设备。已经配网成功的设备,可长按按键再次进入配网模式。

环境安全卫士APP显示界面:

app

2.报警

当烟雾,燃气或者火焰三者中有一种的浓度大于设定值,则app会显示报警状态,并且断开220V电压。

img

至此,我们已经成功完成多功能环境安全卫士的开发。

以上是关于环境安全卫士固件开发的主要内容,如果未能解决你的问题,请参考以下文章

环境安全卫士电路设计

Qt仿360安全卫士界面(自定义阴影边框类)

Qt仿360安全卫士界面(自定义阴影边框类)

Qt仿360安全卫士界面(自定义阴影边框类)

Qt仿360安全卫士界面(自定义阴影边框类)

20145221高其&20145326蔡馨熠《信息安全系统设计基础》实验二 固件设计