如何對(duì)IO口進(jìn)行高效濾波?
typedef enum
{
KEY_LEVEL_DOWN, // 假設(shè)低電平為按下
KEY_LEVEL_UP,
}KeyLevelTypedef;
KeyLevelTypedef get_key_level()
{
return (KeyLevelTypedef)HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);
}
// V0.1
void key_scan()
{ // 歡迎關(guān)注:魚鷹談單片機(jī)
if(get_key_level() == KEY_LEVEL_DOWN)
{
HAL_Delay(20); // 假設(shè)抖動(dòng)時(shí)間 20 ms
if(get_key_level() == KEY_LEVEL_DOWN)
{
key_flag = 1;// 按鍵按下標(biāo)志位
}
}
}
typedef enum
{
KEY_STATE_IDLE, // 按鍵空閑
KEY_STATE_DOWN, // 按鍵按下
KEY_STATE_FINISH, // 按鍵處理完成(由應(yīng)用程序設(shè)置)
}KeyStateTypedef;
KeyStateTypedef key_state;
KeyLevelTypedef key_last_level; // 上次電平狀態(tài)
// V1.0
// 函數(shù)調(diào)用周期 20 ms(如何實(shí)現(xiàn)應(yīng)該不需要再說明了吧)
void key_scan()
{ // 歡迎關(guān)注:魚鷹談單片機(jī)
KeyLevelTypedef temp; // 可不可以不使用這個(gè)中間變量?
temp = get_key_level();
if(temp != key_last_level){
key_last_level = temp;
return;
}
// 當(dāng)運(yùn)行到這里,說明電平已經(jīng)穩(wěn)定下來了
if(temp == KEY_LEVEL_DOWN){
if(key_state == KEY_STATE_IDLE){
// 確保曾經(jīng)釋放過按鍵,這樣可以保證在按下時(shí)不會(huì)不停設(shè)置該標(biāo)志位
key_state = KEY_STATE_DOWN;// 按鍵按下標(biāo)志位
}
}
else{
if(key_state == KEY_STATE_FINISH){ // 防止多線程情況下同時(shí)修改
key_state = KEY_STATE_IDLE; // 釋放按鍵
}
}
}
typedef enum
{
LEVEL_LOW, //
LEVEL_HIGH,
}LevelTypedef;
typedef struct
{
uint32_t last_time; // 上次時(shí)間
????LevelTypedef?last_level;?//?上次電平狀態(tài)
}FilterParaTypedef;
// V2.0
// para 濾波變量,level 當(dāng)前檢測電平狀態(tài), time 當(dāng)前時(shí)間戳,單位 1 ms, stable_time希望電平穩(wěn)定的時(shí)間
uint8_t filter(FilterParaTypedef *para, LevelTypedef level, uint32_t time, uint32_t stable_time)
{ // 歡迎關(guān)注:魚鷹談單片機(jī)
if(level != para->last_level){
para->last_level = level; // 更新當(dāng)前電平狀態(tài)
para->last_time = time; // 更新電平變化的時(shí)刻
return 0; // 電平未穩(wěn)定
}
if(time - para->last_time > stable_time){ // 這兩個(gè)條件可以放在一起進(jìn)行 && 判斷嗎?
return 1; // 需要上報(bào)
???}
return 0; // 電平穩(wěn)定時(shí)間不夠長
}
typedef enum
{
LEVEL_LOW, //
LEVEL_HIGH,
}LevelTypedef;
typedef struct
{
uint32_t last_time; // 上次時(shí)間
LevelTypedef last_level; // 上次電平狀態(tài)
LevelTypedef last_stable_level; // 上次穩(wěn)定的電平狀態(tài)
}FilterParaTypedef;
// V2.0
// para 濾波變量,level 當(dāng)前檢測電平狀態(tài), time 當(dāng)前時(shí)間戳,單位 1 ms, stable_time希望電平穩(wěn)定的時(shí)間
uint8_t filter(FilterParaTypedef *para, LevelTypedef level, uint32_t time, uint32_t stable_time)
{ // 歡迎關(guān)注:魚鷹談單片機(jī)
if(level != para->last_level){
para->last_level = level; // 更新當(dāng)前電平狀態(tài)
para->last_time = time; // 更新電平變化的時(shí)刻
return 0; // 電平未穩(wěn)定
}
if(time - para->last_time > stable_time){ // 這兩個(gè)條件可以放在一起進(jìn)行 && 判斷嗎?
if(level != para->last_stable_level)
{ // 電平穩(wěn)定時(shí)間夠長且電平發(fā)生了變化
para->last_stable_level = level;
return 1; // 需要上報(bào)
}
}
return 0; // 電平穩(wěn)定時(shí)間不夠長
}
typedef struct
{
uint32_t last_time; // 上次時(shí)間
LevelTypedef last_stable_level; // 上次穩(wěn)定的電平狀態(tài)
}FilterParaTypedef;
// V2.5
// para 濾波變量,level 當(dāng)前檢測電平狀態(tài), time 當(dāng)前時(shí)間戳,單位 1 ms, stable_time希望電平穩(wěn)定的時(shí)間
uint8_t filter(FilterParaTypedef *para, LevelTypedef level, uint32_t time, uint32_t stable_time)
{ // 歡迎關(guān)注:魚鷹談單片機(jī)
if(level != para->last_stable_level){
if(time - para->last_time > stable_time)
{
para->last_stable_level = level; // 如果這次電平穩(wěn)定時(shí)間足夠長,那么記錄這次穩(wěn)定的電平
return 1; // 上報(bào)
}
return 0; // 不上報(bào),同時(shí)不更新時(shí)間戳(穩(wěn)定時(shí)間不夠)
}
para->last_time = time; // 不斷更新電平穩(wěn)定時(shí)間,保存電平穩(wěn)定時(shí)的時(shí)間戳
return 0; // 不上報(bào)
}
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 當(dāng)前檢測電平狀態(tài), time 當(dāng)前時(shí)間戳,單位 1 ms, stable_time希望電平穩(wěn)定的時(shí)間
uint8_t filter(FilterParaTypedef *para, LevelTypedef level, uint32_t time, uint32_t stable_time)
{ // 歡迎關(guān)注:魚鷹談單片機(jī)
if(level != para->last_stable_level){
if(time - para->last_time > stable_time)
{
para->last_stable_level = level; // 如果這次電平穩(wěn)定時(shí)間足夠長,那么記錄這次穩(wěn)定的電平
if(level == LEVEL_HIGH) // LEVEL_HIGH 可以作為 para 的成員變量參數(shù)傳入,方便適應(yīng)其他電平
{
return 1; // 上報(bào)
}
}
return 0; // 不上報(bào),同時(shí)不更新時(shí)間戳(穩(wěn)定時(shí)間不夠)
}
para->last_time = time; // 不斷更新電平穩(wěn)定時(shí)間,保存電平穩(wěn)定時(shí)的時(shí)間戳
return 0; // 不上報(bào)
}
// V3.1
// para 濾波變量,level 當(dāng)前檢測電平狀態(tài), time 當(dāng)前時(shí)間戳,單位 1 ms, stable_time希望電平穩(wěn)定的時(shí)間
uint8_t filter(FilterParaTypedef *para, LevelTypedef level, uint32_t time, uint32_t stable_time)
{ // 歡迎關(guān)注:魚鷹談單片機(jī)
if(level != para->last_stable_level){
if(level != LEVEL_HIGH) // LEVEL_HIGH 可以作為 para 的成員變量參數(shù)傳入,方便適應(yīng)其他電平
{
para->last_stable_level = level; // 快速切換狀態(tài)
// para->last_time = time; // 是否有必要同時(shí)更新時(shí)間戳呢?
}
else if(time - para->last_time > stable_time)
{
para->last_stable_level = level; // 如果這次電平穩(wěn)定時(shí)間足夠長,那么記錄這次穩(wěn)定的電平
if(level == LEVEL_HIGH) // LEVEL_HIGH 可以作為 para 的成員變量參數(shù)傳入,方便適應(yīng)其他電平
{
return 1; // 上報(bào)
}
}
return 0; // 不上報(bào),同時(shí)不更新時(shí)間戳(穩(wěn)定時(shí)間不夠)
}
para->last_time = time; // 不斷更新電平穩(wěn)定時(shí)間,保存電平穩(wěn)定時(shí)的時(shí)間戳
return 0; // 不上報(bào)
}
typedef enum
{
LEVEL_LOW, //
LEVEL_HIGH,
}LevelTypedef;
typedef struct
{
uint32_t last_time; // 上次時(shí)間
LevelTypedef last_stable_level; // 上次穩(wěn)定的電平狀態(tài)
LevelTypedef filter_level; // 希望濾波的電平
}FilterParaTypedef;
// V3.2
// para 濾波變量,level 當(dāng)前檢測電平狀態(tài), time 當(dāng)前時(shí)間戳,單位 1 ms, stable_time希望電平穩(wěn)定的時(shí)間
uint8_t filter(FilterParaTypedef *para, LevelTypedef level, uint32_t time, uint32_t stable_time)
{ // 歡迎關(guān)注:魚鷹談單片機(jī)
if(level != para->last_stable_level){
if(level != para->filter_level) // LEVEL_HIGH 可以作為 para 的成員變量參數(shù)傳入,方便適應(yīng)其他電平
{
para->last_stable_level = level; // 快速切換狀態(tài)
// para->last_time = time; // 是否有必要同時(shí)更新時(shí)間戳呢?
}
else if(time - para->last_time > stable_time)
{
para->last_stable_level = level; // 如果這次電平穩(wěn)定時(shí)間足夠長,那么記錄這次穩(wěn)定的電平
if(level == para->filter_level) // LEVEL_HIGH 可以作為 para 的成員變量參數(shù)傳入,方便適應(yīng)其他電平
{
return 1; // 上報(bào)
}
}
return 0; // 不上報(bào),同時(shí)不更新時(shí)間戳(穩(wěn)定時(shí)間不夠)
}
para->last_time = time; // 不斷更新電平穩(wěn)定時(shí)間,保存電平穩(wěn)定時(shí)的時(shí)間戳
return 0; // 不上報(bào)
}
原創(chuàng)不易,歡迎轉(zhuǎn)發(fā)、留言、點(diǎn)贊、分享給你的朋友,感謝您的支持!
長按識(shí)別二維碼關(guān)注獲取更多內(nèi)容
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場,如有問題,請(qǐng)聯(lián)系我們,謝謝!