如何对IO口进行高效滤波?
扫描二维码
随时随地手机看文章
typedef enum
{
KEY_LEVEL_DOWN, // 假设低电平为按下
KEY_LEVEL_UP,
}KeyLevelTypedef;
KeyLevelTypedef get_key_level()
{
return (KeyLevelTypedef)HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);
}
// V0.1
void key_scan()
{ // 欢迎关注:鱼鹰谈单片机
if(get_key_level() == KEY_LEVEL_DOWN)
{
HAL_Delay(20); // 假设抖动时间 20 ms
if(get_key_level() == KEY_LEVEL_DOWN)
{
key_flag = 1;// 按键按下标志位
}
}
}
typedef enum
{
KEY_STATE_IDLE, // 按键空闲
KEY_STATE_DOWN, // 按键按下
KEY_STATE_FINISH, // 按键处理完成(由应用程序设置)
}KeyStateTypedef;
KeyStateTypedef key_state;
KeyLevelTypedef key_last_level; // 上次电平状态
// V1.0
// 函数调用周期 20 ms(如何实现应该不需要再说明了吧)
void key_scan()
{ // 欢迎关注:鱼鹰谈单片机
KeyLevelTypedef temp; // 可不可以不使用这个中间变量?
temp = get_key_level();
if(temp != key_last_level){
key_last_level = temp;
return;
}
// 当运行到这里,说明电平已经稳定下来了
if(temp == KEY_LEVEL_DOWN){
if(key_state == KEY_STATE_IDLE){
// 确保曾经释放过按键,这样可以保证在按下时不会不停设置该标志位
key_state = KEY_STATE_DOWN;// 按键按下标志位
}
}
else{
if(key_state == KEY_STATE_FINISH){ // 防止多线程情况下同时修改
key_state = KEY_STATE_IDLE; // 释放按键
}
}
}
typedef enum
{
LEVEL_LOW, //
LEVEL_HIGH,
}LevelTypedef;
typedef struct
{
uint32_t last_time; // 上次时间
LevelTypedef last_level; // 上次电平状态
}FilterParaTypedef;
// V2.0
// para 滤波变量,level 当前检测电平状态, time 当前时间戳,单位 1 ms, stable_time希望电平稳定的时间
uint8_t filter(FilterParaTypedef *para, LevelTypedef level, uint32_t time, uint32_t stable_time)
{ // 欢迎关注:鱼鹰谈单片机
if(level != para->last_level){
para->last_level = level; // 更新当前电平状态
para->last_time = time; // 更新电平变化的时刻
return 0; // 电平未稳定
}
if(time - para->last_time > stable_time){ // 这两个条件可以放在一起进行 && 判断吗?
return 1; // 需要上报
}
return 0; // 电平稳定时间不够长
}
typedef enum
{
LEVEL_LOW, //
LEVEL_HIGH,
}LevelTypedef;
typedef struct
{
uint32_t last_time; // 上次时间
LevelTypedef last_level; // 上次电平状态
LevelTypedef last_stable_level; // 上次稳定的电平状态
}FilterParaTypedef;
// V2.0
// para 滤波变量,level 当前检测电平状态, time 当前时间戳,单位 1 ms, stable_time希望电平稳定的时间
uint8_t filter(FilterParaTypedef *para, LevelTypedef level, uint32_t time, uint32_t stable_time)
{ // 欢迎关注:鱼鹰谈单片机
if(level != para->last_level){
para->last_level = level; // 更新当前电平状态
para->last_time = time; // 更新电平变化的时刻
return 0; // 电平未稳定
}
if(time - para->last_time > stable_time){ // 这两个条件可以放在一起进行 && 判断吗?
if(level != para->last_stable_level)
{ // 电平稳定时间够长且电平发生了变化
para->last_stable_level = level;
return 1; // 需要上报
}
}
return 0; // 电平稳定时间不够长
}
typedef struct
{
uint32_t last_time; // 上次时间
LevelTypedef last_stable_level; // 上次稳定的电平状态
}FilterParaTypedef;
// V2.5
// para 滤波变量,level 当前检测电平状态, time 当前时间戳,单位 1 ms, stable_time希望电平稳定的时间
uint8_t filter(FilterParaTypedef *para, LevelTypedef level, uint32_t time, uint32_t stable_time)
{ // 欢迎关注:鱼鹰谈单片机
if(level != para->last_stable_level){
if(time - para->last_time > stable_time)
{
para->last_stable_level = level; // 如果这次电平稳定时间足够长,那么记录这次稳定的电平
return 1; // 上报
}
return 0; // 不上报,同时不更新时间戳(稳定时间不够)
}
para->last_time = time; // 不断更新电平稳定时间,保存电平稳定时的时间戳
return 0; // 不上报
}
FilterParaTypedef FilterPara;
void task(void *parameter)
{
while(1)
{
LevelTypedef temp = (LevelTypedef)HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);
if(filter(&FilterPara, temp, rt_tick_get(), 100))
{
rt_kprintf("stable level is %u\n",temp);
}
rt_thread_delay(5);
}
}
// V3.0
// para 滤波变量,level 当前检测电平状态, time 当前时间戳,单位 1 ms, stable_time希望电平稳定的时间
uint8_t filter(FilterParaTypedef *para, LevelTypedef level, uint32_t time, uint32_t stable_time)
{ // 欢迎关注:鱼鹰谈单片机
if(level != para->last_stable_level){
if(time - para->last_time > stable_time)
{
para->last_stable_level = level; // 如果这次电平稳定时间足够长,那么记录这次稳定的电平
if(level == LEVEL_HIGH) // LEVEL_HIGH 可以作为 para 的成员变量参数传入,方便适应其他电平
{
return 1; // 上报
}
}
return 0; // 不上报,同时不更新时间戳(稳定时间不够)
}
para->last_time = time; // 不断更新电平稳定时间,保存电平稳定时的时间戳
return 0; // 不上报
}
// V3.1
// para 滤波变量,level 当前检测电平状态, time 当前时间戳,单位 1 ms, stable_time希望电平稳定的时间
uint8_t filter(FilterParaTypedef *para, LevelTypedef level, uint32_t time, uint32_t stable_time)
{ // 欢迎关注:鱼鹰谈单片机
if(level != para->last_stable_level){
if(level != LEVEL_HIGH) // LEVEL_HIGH 可以作为 para 的成员变量参数传入,方便适应其他电平
{
para->last_stable_level = level; // 快速切换状态
// para->last_time = time; // 是否有必要同时更新时间戳呢?
}
else if(time - para->last_time > stable_time)
{
para->last_stable_level = level; // 如果这次电平稳定时间足够长,那么记录这次稳定的电平
if(level == LEVEL_HIGH) // LEVEL_HIGH 可以作为 para 的成员变量参数传入,方便适应其他电平
{
return 1; // 上报
}
}
return 0; // 不上报,同时不更新时间戳(稳定时间不够)
}
para->last_time = time; // 不断更新电平稳定时间,保存电平稳定时的时间戳
return 0; // 不上报
}
typedef enum
{
LEVEL_LOW, //
LEVEL_HIGH,
}LevelTypedef;
typedef struct
{
uint32_t last_time; // 上次时间
LevelTypedef last_stable_level; // 上次稳定的电平状态
LevelTypedef filter_level; // 希望滤波的电平
}FilterParaTypedef;
// V3.2
// para 滤波变量,level 当前检测电平状态, time 当前时间戳,单位 1 ms, stable_time希望电平稳定的时间
uint8_t filter(FilterParaTypedef *para, LevelTypedef level, uint32_t time, uint32_t stable_time)
{ // 欢迎关注:鱼鹰谈单片机
if(level != para->last_stable_level){
if(level != para->filter_level) // LEVEL_HIGH 可以作为 para 的成员变量参数传入,方便适应其他电平
{
para->last_stable_level = level; // 快速切换状态
// para->last_time = time; // 是否有必要同时更新时间戳呢?
}
else if(time - para->last_time > stable_time)
{
para->last_stable_level = level; // 如果这次电平稳定时间足够长,那么记录这次稳定的电平
if(level == para->filter_level) // LEVEL_HIGH 可以作为 para 的成员变量参数传入,方便适应其他电平
{
return 1; // 上报
}
}
return 0; // 不上报,同时不更新时间戳(稳定时间不够)
}
para->last_time = time; // 不断更新电平稳定时间,保存电平稳定时的时间戳
return 0; // 不上报
}
原创不易,欢迎转发、留言、点赞、分享给你的朋友,感谢您的支持!
长按识别二维码关注获取更多内容
免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!