一、user_app.c
void* state_off(LightSwitcher* self,Event e)
{
if(e == BUTTON_PRESSED)
{
return state_on;
}
return state_off;
}
void* state_on(LightSwitcher* self,Event e)
{
if(e==BUTTON_PRESSED)
{
return state_off;
}
return state_on;
}
void feed(LightSwitcher* self,Event e)
{
self->current_state = self->current_state(self,e);
}
void init_light_switcher(LightSwitcher* self)
{
self->current_state = state_off;
}
LightSwitcher switcher;
u8 button_event =0;
//**gy_button**//
void gy_button_1ms_timer(/*u32 count*/void)
{
static u8 gy_button_count = 0;//延时消抖计数
if(gy_button_press == gy_button_read())//如果按键按下
{
if(gy_button_count == GY_BUTTON_PRESS_COUNT_MAX)
{
#if(GY_DEV_TYPE == GY_DEV_1005 || GY_DEV_TYPE == GY_DEV_1006 || GY_DEV_TYPE == GY_DEV_1007)
gy_factory_reset_ready();
#else
/*factory_reset();
show_factory_reset();
start_reboot();*/
#endif
//LOG_USER_MSG_INFO(0,0,"button_press",0);
button_event=1;
if(button_event)
{
button_event=0;
feed(&switcher,BUTTON_PRESSED);
//LOG_USER_MSG_INFO(0,0,"button_press",0);
//feed();
}
}
gy_button_count++;
}
else if(gy_button_release == gy_button_read())//如果按键抬起
{
if(gy_button_count)
{
//LOG_USER_MSG_INFO(0,0,"gy_button_count",0);
gy_button_count = 0;
}
}
}
二、user_app.h
typedef enum{
BUTTON_PRESSED,
BUTTON_RELEASE,
}Event;
typedef struct LightSwitcher LightSwitcher;
typedef void* (*State)(LightSwitcher*,Event);
struct LightSwitcher{
State current_state;
};
void* state_on(LightSwitcher* self,Event e);
void* state_off(LightSwitcher* self,Event e);
void init_light_switcher(LightSwitcher* self);
void feed(LightSwitcher* self,Event e);
三、通用代码
在泰凌微8258环境下,结合提供的状态机代码实现按键控制LED开关的步骤如下:
1. 硬件配置及头文件引入
#include "proj/mcu/config.h"
#include "vendor/common/gpio.h"
#include "vendor/common/uart.h"
#define LED_PIN GPIO_PD5 // 假设LED连接在PD5
#define BUTTON_PIN GPIO_PD6 // 假设按键连接在PD6
#define DEBOUNCE_DELAY_MS 50 // 去抖动延时
typedef enum {
BUTTON_PRESSED,
BUTTON_RELEASED
} Event;
typedef struct LightSwitcher {
void* (*current_state)(struct LightSwitcher*, Event);
} LightSwitcher;
volatile bool button_event = false;
volatile u32 button_press_time = 0;
2. GPIO及中断初始化
void gpio_init() {
// LED配置为输出,初始熄灭
gpio_set_output(LED_PIN);
gpio_write(LED_PIN, 0);
// 按键配置为输入,启用内部上拉
gpio_set_input(BUTTON_PIN);
gpio_enable_pullup(BUTTON_PIN);
// 配置下降沿中断(按键按下时拉低电平)
gpio_set_interrupt(BUTTON_PIN, POL_FALLING);
}
// 中断服务函数(在SDK的irq_handler.c中添加)
void button_isr(void) {
static u32 last_time = 0;
u32 now = clock_time();
if ((now - last_time) > DEBOUNCE_DELAY_MS * 1000) { // clock_time单位是微秒
button_event = true;
last_time = now;
}
}
3. 修改状态机控制LED
void* state_off(LightSwitcher* self, Event e) {
if (e == BUTTON_PRESSED) {
gpio_write(LED_PIN, 1); // 点亮LED
return state_on;
}
return state_off;
}
void* state_on(LightSwitcher* self, Event e) {
if (e == BUTTON_PRESSED) {
gpio_write(LED_PIN, 0); // 熄灭LED
return state_off;
}
return state_on;
}
void feed(LightSwitcher* self, Event e) {
if (self->current_state) {
self->current_state = self->current_state(self, e);
}
}
void init_light_switcher(LightSwitcher* self) {
self->current_state = state_off;
}
4. 主函数整合逻辑
int main() {
LightSwitcher switcher;
cpu_wakeup_init();
gpio_init();
init_light_switcher(&switcher);
while(1) {
if (button_event) {
button_event = false;
feed(&switcher, BUTTON_PRESSED);
}
sleep_us(1000); // 低功耗处理
}
return 0;
}
关键点说明:
-
GPIO配置:
-
LED引脚设为输出模式并初始置低
-
按键引脚启用内部上拉,配置下降沿中断
-
-
去抖动处理:
-
在中断中记录时间戳,通过时间差过滤抖动
-
使用
clock_time()
获取系统时间(单位微秒)
-
-
状态机改进:
-
在状态转换时直接操作GPIO电平
-
BUTTON_PRESSED
事件触发状态切换
-
-
低功耗优化:
-
主循环中使用
sleep_us()
降低功耗 -
实际开发中可结合TLSR芯片的休眠模式
-
注意事项:
根据实际硬件连接修改LED_PIN和BUTTON_PIN定义
确保SDK中已启用GPIO中断功能
若使用硬件消抖,可适当减小软件去抖时间
生产代码建议添加看门狗处理
该方案实现了:
-
按键按下→LED状态翻转
-
硬件消抖+软件二次验证
-
低功耗待机设计
-
清晰的状态机维护逻辑