日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C语言中实现边沿函数算法及应用,这是抛弃PLC留下的痛!

發布時間:2023/12/2 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言中实现边沿函数算法及应用,这是抛弃PLC留下的痛! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

很多從事PLC編程的朋友都知道,不管是什么品牌的PLC,都有上升沿和下降沿指令。

?那么什么情況下我們才會使用或必須使用邊沿信號呢?邊沿信號我們又如何獲取呢?

如圖1,任何一個開關信號(或數字信號)都可以分解成4個狀態:①高電平 ②低電平 ③上升沿 ④下降沿。

圖1:開關信號

?在PLC編程里,上升沿指令和下降沿指令可以直接調用;那么對于單片機的C語言編程,又如何實現邊沿信號的判斷呢?因為早期做過PLC編程的緣故,受PLC編程思路的影響,對C語言編程急需簡單而高效的邊沿函數,于是痛定思痛,編寫了以下上升沿函數和下降沿函數,使用方便、簡單暴力。

/*************************************************上升沿函數 *************************************************/ u8 Posedge(u8 Old_Value,u8 m) {static u8 New_Value[100];u8 _PLS[100];_PLS[m] = Old_Value & (Old_Value ^ New_Value[m]);New_Value[m] = Old_Value;return(_PLS[m]); }

?上升沿函數的邏輯原理是:

第一次進入函數:

①Old_Value從0→1;(此時New_Value[m]初始值為0)

②_PLS[m] = Old_Value & (Old_Value ^ New_Value[m])的運算結果為1(括號里異或運算為1);

③New_Value[m])= Old_Value被賦值為1;

④返回_PLS[m]值為1。

第二次及以后進入函數:

①New_Value[m]保持為1(因為被定義了static類型,第二次調用不會被清0);

②_PLS[m] = Old_Value & (Old_Value ^ New_Value[m])的運算結果為0(括號里異或運算為0);

③New_Value[m])= Old_Value仍然被賦值為1;

④返回_PLS[m]值為0。

⑤Old_Value從1→0,運算結果為0,返回值也為0;

?所以上升沿函數只在變量0→1變化時返回值為1。

另外形參m的取值范圍是0~99,是為了區分不同Old_Value的實參,如果不同的實參用相同的m值(比如0),則該函數返回值會發生混亂;具體應用下面會附上實例。

/************************************************下降沿函數 ************************************************/ u8 Negedge(u8 Old_Value,u8 m) {static u8 New_Value[100];u8 _PLF[100];_PLF[m] = ~Old_Value & (~Old_Value ^ New_Value[m]);New_Value[m] = ~Old_Value;return(_PLF[m]); }

下降沿函數的原理與上升沿函數完全一樣,只需把Old_Value值取反即可。

?應用實例講解:

①以下為按鍵短按長按計數為例(單片機使用的是STM32F103系列的)。

if(Flag_1ms) //在1ms掃描周期內 {Flag_1ms = 0;if(SW1_IN == 0) //SW1按鍵長按,參數碼Cnt_Code以50ms間隔遞增{if(Negedge(SW1_IN,0) == 1) Cnt_Code++; //SW1按鍵短按,Cnt_Code只加1i++; //以下為SW2按鍵長按計數間隔50msif(i == 50) //取經驗值50{i = 0;Cnt_Code++;if(Cnt_Code == 101) Cnt_Code = 0; //Cnt_Code值范圍1--100}} if(SW2_IN == 0) //SW2按鍵長按,參數碼Cnt_Code以50ms間隔遞減{if(Negedge(SW2_IN,1) == 1) Cnt_Code--; //SW1按鍵短按,Cnt_Code只減1i++; //以下為SW2按鍵長按計數間隔50msif(i == 50) //取經驗值50{i = 0;Cnt_Code--;if(Cnt_Code == 0) Cnt_Code = 100;}} }

是不是發現了一個bug,本人沒有做按鍵的消抖處理,別急,用邊沿函數處理開關信號完全不需要消抖處理,是不是很簡單省事!

if(Negedge(SW1_IN,0) == 1) Cnt_Code++;

上面代碼表示SW1按鍵按下時,函數Negedge(SW1_IN,0)返回值為1,if條件語句判斷為真,在1ms周期內Cnt_Code加1;

if(Negedge(SW2_IN,1) == 1) Cnt_Code--;

邏輯同上,但注意括號(SW2_IN,1)內不是0,而是1,是為了避免與前一個下降沿函數在調用時有沖突。

②電池過壓保護程序

if(Posedge(Battery_Voltage > 14 ,0) == 1)//電池電壓大于14V {Flag_OVP = 1; //過壓標志置位 } if(Posedge(Battery_Voltage < 14 ,1) == 1)//電池電壓小于14V {Flag_OVP = 0; //過壓標志復位 }

上面代碼的上升沿函數Posedge(Battery_Voltage > 14 ,0) 中判斷語句的假值→真值也可以作為上升沿來使用,是不是很妙。

以上的兩種用法只是上升沿函數和下降沿函數最為普遍的用法,運用熟練后,可以自由發揮,另外,以上變量的數據類型我都定義為u8(unsigned char),因為我的STM32的標準庫里沒有布爾類型(bool)的定義,我也一直沒使用過布爾類型。變量定義如下:

u8 i; //按鈕長按間隔計數 u8 Cnt_Code;//參數碼 u8 Flag_OVP;//過壓標志 u8 Flag_1ms;//1ms標志

?要點:

①上升沿函數和下降沿函數的返回值都為1,且在當前掃描周期內有效,下一個周期就變為0了,所以可以理解為其輸出了一個脈沖;

②按鍵消抖的常用方法是延時判斷,其實用邊沿函數處理開關信號完全不用消抖,直接調用即可;如果主函數有實時性要求較高的掃描程序存在,延時函數的弊病就出來了,ta會嚴重影響掃描周期。

③用于只需要執行一次的指令(非保持),如加一減一、移位、交換、存儲,以及一個變量受制于多個條件等,如果不用上升沿或者下降沿,那么代碼在每個周期都會被執行一次,于是就不能達到理想效果;

聲明:

本文于網絡整理,版權歸原作者所有,如來源信息有誤或侵犯權益,請聯系我們刪除或授權事宜。

總結

以上是生活随笔為你收集整理的C语言中实现边沿函数算法及应用,这是抛弃PLC留下的痛!的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。