涂鸦智能烧水壶软件实现之TS02N触摸按键驱动

Posted 三明治开发社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了涂鸦智能烧水壶软件实现之TS02N触摸按键驱动相关的知识,希望对你有一定的参考价值。


前言

本文主要内容是实现烧水壶的触摸按键驱动,触摸按键芯片选用TS02N。


一、智能烧水壶按键功能设定

  • 智能烧水壶的按键功能设定如下,实现功能之前,我们首先要实现按键采集芯片的驱动。
功能说明
煮沸触摸按键1,触发方式:轻触。默认煮沸。
触摸按键控制煮沸键 按下开启,再按关闭
app控制:煮沸
保温键触摸按键1,触发方式:轻触
轻触进入默认的自来水模式下的55度保温模式,按下开启,再按关闭
长按5s进入配网模式
不操作,app也无操作,默认凉白开模式

二、按键采集的方案制定

1.硬件电路图

  • 按键采集电路如下:

在这里插入图片描述

  • TS02N使用说明

     输入P1\\P2:低电平触发

     P1触发后OUT1输出低电平

     P2触发后OUT2输出低电平

    通信引脚设定:

OUT1	| P7	煮沸键
OUT2	| P8	保温键

2.嵌入式方案设定

为了后期的程序扩展,采用回调函数注册的方式实现按键控制。

1.按键按下时,按键指示灯亮,按键松开,按键指示灯灭;按一次按键蜂鸣器响一下
2.可以使用注册函数直接注册所用IO口,以及注册按键按下触发的回调函数
3.可以设置长按时间,配置按键长按触发的回调函数

三、功能实现

1.代码实现

  • 在之前开发的基础上增加程序,增加ts02n_key.c文件和其头文件,目前整个工程的文件结构如下:
├── src	
|    ├── tuya_drive
|    |  	└── b3950
|    |    		└── b3950.c           //温度传感器驱动相关
|    |  	└── gpio_control
|    |    		└── gpio_control.c           //gpio 控制相关
|    |  	└── ts02n_key
|    |    		└── ts02n_key.c           //按键驱动
|    |  	└── timer
|    |    		└── timer.c           //定时器相关
|    ├── tuya_device.c             //应用层入口文件
|    └── kettle_app.c            //智能烧水壶主要应用文件
|
├── include				//头文件目录
|    ├── tuya_drive_h
|    |  	└── b3950_h
|    |    		└── b3950.h   
|    |  	└── gpio_control_h
|    |    		└── gpio_control.h          
|    |  	└── ts02n_key_h
|    |    		└── ts02n_key.h           //按键驱动
|    |  	└── timer_h
|    |    		└── timer.h           //定时器相关   
|    ├── tuya_device.h                
|    └── kettle_app.h       
|
└── output              //编译产物

ts02n_key.c中函数实现如下:主要内容是实现扫描函数,根据传入的配置参数进行初始化

/*使用时只需要通过ts02n_key_init(TS02N_KEY_DEF_S* user_key_def)函数进行注册,注册后会自动开启一个定时扫描任务去采集按键信息,按键触发后也会自动调用注册的回调函数*/
typedef VOID(* KEY_CALLBACK)();
typedef struct {   // user define
    unsigned int key_pin1; //ts02n CH1 PIN
    unsigned int key_pin2; //ts02n CH2 PIN
    KEY_CALLBACK key1_cb;  //normal press key1 callback function
    KEY_CALLBACK key2_cb;  //normal press key2 callback function
    KEY_CALLBACK key1_long_press_cb;  //normal press key1 callback function
    KEY_CALLBACK key2_long_press_cb;  //normal press key2 callback function
    KEY_CALLBACK key1_Low_level_cb;  //Key1 low level process callback function
    KEY_CALLBACK key2_Low_level_cb;  //Key2 low level process callback function
    unsigned int long_time_set; //long press key time set
    unsigned int scan_time; //Scan cycle set   unit: ms

}TS02N_KEY_DEF_S;

typedef struct {
    unsigned int down_time; //记录按键按下的时间
    unsigned char status;   

}KEY_PRESS_STATUS_S;

typedef struct {
    TS02N_KEY_DEF_S* ts02n_def_s;//用户注册的相关信息,回调函数,pin口等
    KEY_PRESS_STATUS_S key_status;
}TS02N_KEY_MANAGE_S;
/* Private function prototypes -----------------------------------------------*/
static int key_scan();
static void key_timer_cb();

/* Private variables ---------------------------------------------------------*/
static TIMER_ID key_timer;
static TS02N_KEY_MANAGE_S *key_mag = NULL; 
enum KEY_STAT_E{
    KEY1_UP = 0,
    KEY1_DOWN,
    KEY1_FINISH,
    KEY2_UP,
    KEY2_DOWN,
    KEY2_FINISH,
};

enum KEY_PRESS_STAT{
    KEY1_NORMAL_PRESS = 0,
    KEY2_NORMAL_PRESS, 
    KEY1_LONG_PRESS,
    KEY2_LONG_PRESS,
    NO_KEY_PRESS,
};

/* Private functions ---------------------------------------------------------*/
/**
 * @Function: ts02n_key_init
 * @Description: key init 
 * @Input: none
 * @Output: none
 * @Return: none
 * @Others: 
 */
int ts02n_key_init(TS02N_KEY_DEF_S* user_key_def)
{
    int op_ret = 0;
    key_mag = (TS02N_KEY_MANAGE_S *)Malloc(SIZEOF(TS02N_KEY_MANAGE_S));
    memset(key_mag, 0, SIZEOF(TS02N_KEY_MANAGE_S));
    //No callback function is registered    key init err
    if((user_key_def->key1_cb == NULL) && (user_key_def->key2_cb == NULL) && \\
    (user_key_def->key1_long_press_cb == NULL) && (user_key_def->key2_long_press_cb == NULL)){
        return KEY_INIT_ERR;
    }
    //key pin init 
    tuya_pin_init(user_key_def->key_pin1, TUYA_PIN_MODE_IN_PU);
    tuya_pin_init(user_key_def->key_pin2, TUYA_PIN_MODE_IN_PU);
    //get user define
    key_mag->ts02n_def_s = user_key_def;
    //creat key scan handle timer
    op_ret = sys_add_timer(key_timer_cb,NULL,&key_timer);
    if(op_ret != KEY_INIT_OK) {
        return KEY_INIT_ERR;
        PR_ERR("add timer err");
    }
    op_ret = sys_start_timer(key_timer,key_mag->ts02n_def_s->scan_time,TIMER_CYCLE);
    if(op_ret != KEY_INIT_OK) {
        return KEY_INIT_ERR;
        PR_ERR("start timer err");
    }

}
/**
 * @Function: key_timer_cb
 * @Description: Timing key scan processing function
 * @Input: none
 * @Output: none
 * @Return: none
 * @Others: 
 */
static void key_timer_cb()
{
    int ret = -1;
    //get key press status
    ret = key_scan();
    switch (ret) {
    
    case KEY1_NORMAL_PRESS: {
        key_mag->ts02n_def_s->key1_cb();
    }
    break;

    case KEY1_LONG_PRESS: {
        key_mag->ts02n_def_s->key1_long_press_cb();
    }
    break;

    case KEY2_NORMAL_PRESS: {
        key_mag->ts02n_def_s->key2_cb();
    }
    break;

    case KEY2_LONG_PRESS: {
        key_mag->ts02n_def_s->key2_long_press_cb();
    }
    break;
    default:
    break;
    }
}
/**
 * @Function: key_scan
 * @Description: key scan handle function
 * @Input: none
 * @Output: none
 * @Return: none
 * @Others: 
 */
static int key_scan()
{
    if((tuya_pin_read(key_mag->ts02n_def_s->key_pin1) == 0) && (tuya_pin_read(key_mag->ts02n_def_s->key_pin2) == 0 )) {
        return NO_KEY_PRESS;
    }
    if(tuya_pin_read(key_mag->ts02n_def_s->key_pin1) == 0 ) {

        key_mag->ts02n_def_s->key1_Low_level_cb();
        key_mag->key_status.status = KEY1_DOWN;
        key_mag->key_status.down_time += key_mag->ts02n_def_s->scan_time;
        if(key_mag->key_status.down_time >= key_mag->ts02n_def_s->long_time_set) {
            key_mag->key_status.status = KEY1_FINISH;
        }
    }else {
        if(key_mag->key_status.status == KEY1_DOWN) {
            key_mag->key_status.status = KEY1_FINISH;
        }
    }

    if(tuya_pin_read(key_mag->ts02n_def_s->key_pin2) == 0 ) {

        key_mag->ts02n_def_s->key2_Low_level_cb();
        key_mag->key_status.status = KEY2_DOWN;
        key_mag->key_status.down_time += key_mag->ts02n_def_s->scan_time;
        if(key_mag->key_status.down_time >= key_mag->ts02n_def_s->long_time_set) {
            key_mag->key_status.status = KEY2_FINISH;
        }
    }else {
        if(key_mag->key_status.status == KEY2_DOWN) {
            key_mag->key_status.status = KEY2_FINISH;
        }
    }

    switch (key_mag->key_status.status) {
    
    case (KEY1_FINISH): {
        if(key_mag->key_status.down_time >= key_mag->ts02n_def_s->long_time_set) {
            PR_DEBUG("key_pin1 long press");
            key_mag->key_status.down_time = 0;
            key_mag->key_status.status = KEY1_UP;
            return KEY1_LONG_PRESS;
        }else {
            key_mag->key_status.status = KEY1_UP;
            key_mag->key_status.down_time = 0;
            PR_DEBUG("key_pin1 press");
            return KEY1_NORMAL_PRESS;
        }
    }
    break;

    case (KEY2_FINISH): {
        if(key_mag->key_status.down_time >= key_mag->ts02n_def_s->long_time_set) {
            PR_DEBUG("key_pin2 long press");
            key_mag->key_status.down_time = 0;
            key_mag->key_status.status = KEY2_UP;
            return KEY2_LONG_PRESS;
        }else {
            key_mag->key_status.status = KEY2_UP;
            key_mag->key_status.down_time = 0;
            PR_DEBUG("key_pin2 press");
            return KEY2_NORMAL_PRESS;
        }
    }
    break;
    default:
        return NO_KEY_PRESS;
    break;

    }

}
  • kettle_app.c文件中初始化按键,并注册回调函数,其中一些设置烧水壶状态的函数可以先不看,后面文章会说明
TS02N_KEY_DEF_S kettle_key_def_s = {
    .key_pin1 = TY_GPIOA_8,
    .key_pin2 = TY_GPIOA_7,
    .key1_cb = key1_cb_fun,
    .key2_cb = key2_cb_fun,
    .key1_long_press_cb = NULL,
    .key2_long_press_cb = key2_long_press_cb_fun,
    .key1_Low_level_cb = key1_Low_level_cb_fun,
    .key2_Low_level_cb = key2_Low_level_cb_fun,
    .long_time_set = 5000,
    .scan_time = 100,
};
VOID_T kettle_init()
{
    b3950_init();
    thread_init();
    kettle_gpio_init();
    ts02n_key_init(&kettle_key_def_s);//注册按键并初始化
}

//煮沸键按下再松开后触发
void key1_cb_fun()
{   
    //Button press prompt
    led1_set(OFF);
    buzzer_flag = 1;
    //Button press prompt
    
    if(get_kettle_work_status() == boil) { //if current status is boil, close boiling 
        set_kettle_work_status(nature);
        set_dp_boil_value(FALSE);
        report_one_dp_status(DP_BOIL);
    }else {
        set_kettle_work_status(boil);
        set_dp_boil_value(TRUE);
        report_one_dp_status(DP_BOIL);
    }



}
//保温键按下再松开后触发
void key2_cb_fun()
{
    //Button press prompt
    led2_set(OFF);
    buzzer_flag = 1;
    //Button press prompt
    if(get_kettle_work_status() == keep_warm_mode1) {//if current status is keep_warm_mode1,turn off insulation function
        set_kettle_work_status(nature);
        set_dp_keep_warm_switch(0);
        report_one_dp_status(DP_KEEP_WARM);
    }else {
        set_kettle_work_status(keep_warm_mode1);
        //tap water warm mode :1.boil -> 2.keep warm
        set_kettle_keep_warm_temper(Default_Warm_Temperature);
        set_dp_keep_warm_switch(1);
        report_one_dp_status(DP_KEEP_WARM);
        report_one_dp_status(DP_TEMP_SET);
    }



}
//保温键长按5s触发,进行配网模式
void key2_long_press_cb_fun()
{

    led2_set(OFF);
    tuya_iot_wf_gw_unactive();
    buzzer_flag = 1;

}
//按键按下时触发
void key1_Low_level_cb_fun()
{
    PR_DEBUG("key1_Low_level_cb");
    led1_set(ON);
    if(buzzer_flag) {
        timer_init();//蜂鸣器响一下
        buzzer_flag = 0;
    }
    
}
//按键按下时触发
void key2_Low_level_cb_fun()
{
    led2_set(ON);
    PR_DEBUG("key2_Low_level_cb");
    if(buzzer_flag) {
        timer_init();//蜂鸣器响一下
        buzzer_flag = 0;
    }
}

  • 此时智能烧水壶的按键驱动功能已经实现了,其他功能实现请见后续文章。

技术支持

您可以通过以下方法获得涂鸦的支持:

以上是关于涂鸦智能烧水壶软件实现之TS02N触摸按键驱动的主要内容,如果未能解决你的问题,请参考以下文章

涂鸦智能烧水壶软件实现之温度采集和过温报警功能

涂鸦智能烧水壶软件实现之云端控制(完结)

智能烧水壶-FAQ

涂鸦智能烧水壶之嵌入式系统创建

涂鸦智能暖风机软件实现之暖风机外设驱动实现

涂鸦智能暖风机软件实现之利用TC309实现触摸按键控制功能