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会严重影响扫描周期。

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

声明:

本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/338454.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

服务器系统装驱动精灵,云服务器安装驱动精灵

云服务器安装驱动精灵 内容精选换一换您可以选择在云服务器上安装一个或多个应用。如需在云服务器上安装其他应用&#xff0c;请参考如下操作进行添加。暂时仅允许支持VR应用的云服务器安装VR应用。暂时仅允许支持3D应用的云服务器安装3D应用。暂时仅允许支持VR应用的云服务器有…

注入器 过检测_连云港管道检测服务

连云港管道检测服务 管道稀释淤泥施工时应采用专业高压水车将两个检查井注入室内灌水&#xff0c;并使用挖泥机将检查井中的污泥与排污管混合&#xff0c;以稀释污泥为目的. 如果是手工作业应与机械作业配合以不断搅拌污泥&#xff0c;直到将其稀释到水中为止.管道吸污。 公司备…

lock.lock_HibernateCascadeType.LOCK陷阱

lock.lock介绍 引入了Hibernate 显式锁定支持以及Cascade Types之后 &#xff0c;就该分析CascadeType.LOCK行为了。 Hibernate锁定请求触发内部LockEvent 。 关联的DefaultLockEventListener可以将锁定请求级联到锁定实体子级。 由于CascadeType.ALL也包括CascadeType.LOCK …

浅谈面向对象思想下的 C 语言

如何使用OO思维方式面向对象(object Oriented&#xff0c;简称&#xff1a;OO)在于用“找对象”的方式去规划和描述问题。一、怎样“找对象” &#xff08;思维过程&#xff09;“对象”是具有共性的一个群体。以 L298N 控制马达的官方推荐方法为例&#xff0c;控制的共性在于&…

我的世界服务器里怎么无限随机传送,我的世界随机传送插件使用教程 权限指令分享...

导读&#xff1a;在我的世界中玩家可以利用随机传送插件来进行传送人物质与设定点&#xff0c;那么随意传送插件该如何使用呢、下面小编我就来教教各位&#xff0c;我的世界随意传送插件使用教程。什么是RandomLocationRandomLocation让你传送到预设区域的随机位置。可以通过命…

热敏电阻温度特性曲线_NTC热敏电阻如何选型

什么是NTCNTC 热敏电阻是负温度系数的电阻&#xff0c;其特性是电阻值随着温度的升高而呈下降趋势。这个与PTC或者PT100等正温度系数的热敏电阻相反。NTC 热敏电阻NTC的阻值-温度对应曲线如下图所示(100K为例&#xff0c;B值3950)。NTC 热敏电阻R-T曲线下面介绍选型原则。2.根据…

如何使用C语言的面向对象?

我们都知道&#xff0c;C 才是面向对象的语言&#xff0c;但是C语言是否能使用面向对象的功能?(1)继承性typedef struct _parent{int data_parent;}Parent;typedef struct _Child{struct _parent parent;int data_child;}Child;在设计C语言继承性的时候&#xff0c;我们需要做…

t3软件怎么生成报表_临沂用友畅捷通T3财务通软件财税一体化

用友T3财税通针对财税一体化的发展趋势&#xff0c;在用友通上海财税专版的基础上&#xff0c;经过完善和提高。同时加入了税务核算功能、所得税汇算功能。 财税通财务软件的财税同步处理&#xff0c;可将事后税务处理的汇总涉税数据工作化整为零&#xff0c;分解到日常凭证填制…

每日干货丨C语言知识总结----循环结构

介绍循环结构可以看成是一个条件判断语句和一个向回 转向语句 的组合。另外&#xff0c;循环结构的三个要素&#xff1a;循环变量、 循环体 和循环终止条件. &#xff0c;循环结构在 程序框图 中是利用判断框来表示&#xff0c;判断框内写上条件&#xff0c;两个出口分别对应着…

apache hadoop_使用Apache Hadoop计算PageRanks

apache hadoop目前&#xff0c;我正在接受Coursera的培训“ 挖掘海量数据集 ”。 我对MapReduce和Apache Hadoop感兴趣已有一段时间了&#xff0c;通过本课程&#xff0c;我希望对何时以及如何MapReduce可以帮助解决一些现实世界中的业务问题有更多的了解&#xff08;我在这里介…

730阵列卡支持多大硬盘_凯捷月销破2万,配6座头等舱空间,到底有多舒服?试驾了才知道...

能够在还未上市的前一个月&#xff0c;就以预售的方式卖出超过2万台&#xff0c;上汽通用五菱在乘用车市场之中的号召力可见一斑。过去我们都将五菱视为商务领域的铭牌&#xff0c;包括宏光、荣光、之光等等家族&#xff0c;都在各自细分市场占据着最顶端位置。如今&#xff0c…

C语言循环嵌套

在C语言中&#xff0c;if-else、while、do-while、for 都可以相互嵌套。所谓嵌套&#xff08;Nest&#xff09;&#xff0c;就是一条语句里面还有另一条语句&#xff0c;例如 for 里面还有 for&#xff0c;while 里面还有 while&#xff0c;或者 for 里面有 while&#xff0c;w…

rem 前端字体_web前端入门到实战:一次搞懂CSS字体单位:px、em、rem和%

对于绘图和印刷而言&#xff0c;“单位”相当重要&#xff0c;然而在网页排版里&#xff0c;单位也是同样具有重要性&#xff0c;在CSS3普及以来&#xff0c;更支持了一些方便好用的单位&#xff08;px、em、rem…等&#xff09;&#xff0c;这篇文章将整理这些常用的CSS单位&a…

jvmti_JVMTI标记如何影响GC暂停

jvmti这篇文章分析了为什么Plumbr Agents在某些情况下以及如何延长GC暂停的时间。 对基本问题进行故障诊断揭示了有关在GC暂停期间如何处理JVMTI标记的有趣见解。 发现问题 我们的一位客户抱怨说&#xff0c;附加了Plumbr代理后&#xff0c;应用程序的响应速度明显降低。 通过…

C语言-使用goto语句从循环中跳出

实例代码// //实现功能&#xff1a;使用goto语句从循环中跳出 //#include "stdio.h"#define EXIT 0void show_Menu(){printf("菜单选项:\t");printf("1&#xff1a;显示\t");printf("2&#xff1a;添加\t");printf("3&#xff1a…

装饰器模式java_Java 8的装饰器模式

装饰器模式java在最近的一篇文章中&#xff0c;我描述了装饰器模式如何挽救了我的一天。 我给出了一个小代码段&#xff0c;其中包含创建装饰器的最简单方法&#xff0c;但承诺Java 8会有更好的方法。 这里是&#xff1a; 用Java 8装饰 HyperlinkListener listener this::ch…

C语言-反转字符串

实例代码// //实现功能&#xff1a;输入一个字符串&#xff0c;然后将该字符串反向输出 //#include "stdio.h" #include "string.h"#define N 50void convert_str(char str[N]);void convert_str(char str[N]){int j;char temp;for (int i 0; i < strl…

信捷步进指令的使用_步进电机驱动器的模式

步进电动机和步进电动机驱动器构成步进电机驱动系统。步进电动机驱动系统的性能&#xff0c;不但取决于步进电动机自身的性能&#xff0c;也取决于步进电动机驱动器的优劣。对步进电动机驱动器的研究几乎是与步进电动机的研究同步进行的。步进电机驱动器有三种基本的步进电机驱…

C语言灵魂篇|指针作为函数返回值

C语言允许函数的返回值是一个指针&#xff08;地址&#xff09;&#xff0c;我们将这样的函数称为指针函数。下面的例子定义了一个函数 strlong()&#xff0c;用来返回两个字符串中较长的一个&#xff1a;#include #includechar *strlong(char *str1, char *str2){ if(strlen(s…

css 样式尾部带感叹号是什么意思_CSS书写规范

推荐大家看看百度FEX前端团队和腾讯AlloyTeam前端团队的CSS代码规范。fex-team/styleguide​github.comCode Guide by AlloyTeam​alloyteam.github.io1. 样式属性顺序单个样式规则下的属性在书写时&#xff0c;应按功能进行分组&#xff0c;组之间需要有一个空行。同时要以Pos…