编程语言应用

首页 » 常识 » 常识 » C语言中实现边沿函数算法及应用,这是抛弃
TUhjnbcbe - 2021/8/14 19:57:00

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

?那么什么情况下我们才会使用或必须使用边沿信号呢?边沿信号我们又如何获取呢?

如图1,任何一个开关信号(或数字信号)都可以分解成4个状态:①高电平②低电平③上升沿④下降沿。

图1:开关信号

?在PLC编程里,上升沿指令和下降沿指令可以直接调用;那么对于单片机的C语言编程,又如何实现边沿信号的判断呢?因为早期做过PLC编程的缘故,受PLC编程思路的影响,对C语言编程急需简单而高效的边沿函数,于是痛定思痛,编写了以下上升沿函数和下降沿函数,使用方便、简单暴力。

/*************************************************上升沿函数*************************************************/u8Posedge(u8Old_Value,u8m){  staticu8New_Value[];  u8_PLS[];  _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),则该函数返回值会发生混乱;具体应用下面会附上实例。

/************************************************下降沿函数************************************************/u8Negedge(u8Old_Value,u8m){  staticu8New_Value[];  u8_PLF[];  _PLF[m]=~Old_Value(~Old_Value^New_Value[m]);  New_Value[m]=~Old_Value;  return(_PLF[m]);}

下降沿函数的原理与上升沿函数完全一样,只需把Old_Value值取反即可。

?应用实例讲解:

①以下为按键短按长按计数为例(单片机使用的是STM32F系列的)。

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==)Cnt_Code=0;//Cnt_Code值范围1--}}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=;}}}

是不是发现了一个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_Voltage14,0)==1)//电池电压大于14V{  Flag_OVP=1;            //过压标志置位}if(Posedge(Battery_Voltage14,1)==1)//电池电压小于14V{  Flag_OVP=0;            //过压标志复位}

上面代码的上升沿函数Posedge(Battery_Voltage14,0)中判断语句的假值→真值也可以作为上升沿来使用,是不是很妙。

以上的两种用法只是上升沿函数和下降沿函数最为普遍的用法,运用熟练后,可以自由发挥,另外,以上变量的数据类型我都定义为u8(unsignedchar),因为我的STM32的标准库里没有布尔类型(bool)的定义,我也一直没使用过布尔类型。变量定义如下:

u8i;//按钮长按间隔计数u8Cnt_Code;//参数码u8Flag_OVP;//过压标志u8Flag_1ms;//1ms标志

?要点:

①上升沿函数和下降沿函数的返回值都为1,且在当前扫描周期内有效,下一个周期就变为0了,所以可以理解为其输出了一个脉冲;

②按键消抖的常用方法是延时判断,其实用边沿函数处理开关信号完全不用消抖,直接调用即可;如果主函数有实时性要求较高的扫描程序存在,延时函数的弊病就出来了,ta会严重影响扫描周期。

③用于只需要执行一次的指令(非保持),如加一减一、移位、交换、存储,以及一个变量受制于多个条件等,如果不用上升沿或者下降沿,那么代码在每个周期都会被执行一次,于是就不能达到理想效果;

来源:电卤药丸

推荐

1
查看完整版本: C语言中实现边沿函数算法及应用,这是抛弃