0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

什么情况下我们才会使用边沿信号?

GReq_mcu168 来源:电卤药丸 作者:电卤药丸 2021-05-03 10:14 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

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

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

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

a8e9b718-a10a-11eb-8b86-12bb97331649.png

图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只加1

i++; //以下为SW2按键长按计数间隔50ms

if(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只减1

i++; //以下为SW2按键长按计数间隔50ms

if(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留下的痛!

文章出处:【微信公众号:玩转单片机】欢迎添加关注!文章转载请注明出处。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • plc
    plc
    +关注

    关注

    5045

    文章

    14441

    浏览量

    483556
  • C语言
    +关注

    关注

    183

    文章

    7642

    浏览量

    144605

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

文章出处:【微信号:mcu168,微信公众号:硬件攻城狮】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    E203 test_mode信号是干啥用的?

    最近在研究E203的RTL代码,有一个信号是test_mode,开源代码里面给了个常量0。 请教一各位大佬,这个信号是干啥用的?在什么情况下接0,
    发表于 11-11 06:51

    高扇出信号线优化技巧(

    该属性会将每个驱动程序的扇出限制告知工具,并通过指示布局器了解扇出限制来指引该工具对高扇出的负载进行分配。此属性可同时应用于 FF 与 LUT 驱动程序。当 MAX_FANOUT 值小于约束的信号线的实际扇出时,将对该信号线进行寄存器复制评估。值得注意的是,仅当时序会得到
    的头像 发表于 08-28 10:47 1525次阅读
    高扇出<b class='flag-5'>信号</b>线优化技巧(<b class='flag-5'>下</b>)

    请问DTU的设备号都在什么情况下需要填写,填写的规则是什么?

    DTU的设备号都在什么情况下需要填写,填写的规则是什么?
    发表于 08-07 07:50

    DS1232LPS-2+T&amp;R,在什么情况下,5脚RST会一直输出高电平?

    DS1232LPS-2+T&R,这款芯片在什么情况下,5脚RST会一直输出高电平?(正常时序是上电有个400多ms的高电平后,一直处于低电平,如果7脚没有及时喂狗,会触发复位,也就是重复400多ms的高电平后,一直处于低电平)
    发表于 04-18 07:51

    DLPC350管角FAULT_STATUS是什么含义,什么样的情况下这个指示灯会亮?

    ,这个指示灯会亮,具体是在什么情况下,这个指示灯会亮呢?或者说在哪些情况下,这个指示灯会亮。 帮忙解答,感谢。
    发表于 02-26 08:20

    DLPA3000 ILLUM_HSIDE_DRIVE ILLUM_LSIDE_DRIVE这二个脚外置MOS是什么情况下可以用?

    ILLUM_HSIDE_DRIVEILLUM_LSIDE_DRIVE这二个脚外置MOS是什么情况下可以用
    发表于 02-21 06:00

    ads1256有没有办法在不换ad的情况下采集10路信号

    在使用ads1256,但是发现需要采集10路信号,有没有办法在不换ad的情况下采集10路信号
    发表于 01-22 07:36

    ADS5474模数转换器的VCM和VREF引脚在什么情况下使用?

    是什么?在什么情况下使用?文档上有张图表明两个时钟引脚在内部通过两个1000欧电阻接到2.4V电压,这个2.4V是不是就是VREF? 此外,信号输入规定是2.2VPP,共模电压设置为3.1V或是0V是不是都行?
    发表于 01-13 08:04

    ADS1115未接传感器的通道会不时的出现数值,这是什么情况

    最近做了块AD采样的板子,在其中1路接传感器,其他3路不接传感器的情况下,接传感器的读数正常,而未接传感器的通道会不时的出现数值。这是什么情况?怎么解决?望大家给点意见
    发表于 01-09 06:47

    MSP430F4250的四种模式分别是在什么情况下使用呢?

    我是一名初学者,看了书知道MSP430F4250的AD转换模式有四种,我想知道这四种转化模式有什么区别,分别应该在什么情况下使用。各位高手能否为我解答哈,在下不胜感激。因为是初学者,有很多东西都不知道,能尽量详细就尽量哈,谢谢了。
    发表于 01-06 06:16

    ldc1614EVM评估版背面的没焊电容时用来干嘛的?在什么情况下使用?

    请教一个关于ldc1614EVM的问题,评估版背面的没焊电容时用来干嘛的?在什么情况下使用?
    发表于 01-02 08:23

    ADS1278数据输出引脚Dout1有脉冲输出是什么情况

    ADS1278配置成SPI TDM模式,CLK时钟24MHz,在SCLK没给时钟的情况下,用示波器观察Dout1管脚就不规则脉冲输出,宽度大约6us,周期不定。另外DRDY有规律性脉冲输出,宽度大约50ns,间隔60us,请问这是什么情况
    发表于 12-31 06:12

    ADS5401满量程情况下,模拟信号的输入范围远超过了参考电压的范围,为什么?

    我在设计过程中遇到一个问题,ADC满量程情况下,模拟信号的输入范围远超过了参考电压的范围, 1. 如设置参考电压为1V的情况下,转换输出满量程-127~127(我只取ADC的高8位,低4位不要)所
    发表于 12-30 08:34

    LM98620的offset寄存器值什么情况下起作用?

    我想问下LM98620 的offset寄存器值什么情况下起作用?我是通过FPGA设置的,6个C_OFFS_XX寄存器和6个F_OFFS_XX都设置了,但是波形没有整体抬升或者下降。 另外,我在
    发表于 12-23 07:48

    DAC8820将数字信号转换为模拟信号的这段时间,芯片的输出是什么情况

    我想问一DAC8820如何输出的问题,在DAC将数字信号转换为模拟信号的这段时间,芯片的输出是什么情况,芯片内部是否存在类似模拟开关的结构,只有数字转换好了才能输出?
    发表于 12-18 06:26