按键时钟的原理

独立按键的改造

之前的独立按键是什么原理呢?

之前的独立按键是利用时钟中断,不断地返回按键的状态,当按下去的那一刹那就会返回很多次的状态,返回的形式都是一个一个的Bit,当装载这些比特的,字节都是按下去的状态的时候,这个时候就可以判定是按下去了,但是总的来说,这种方式的反应还是很慢的,于是乎我们可以使用下降沿的方式来进行判定,这样的话,只需要一刹那就可以了,这样的话更加灵敏。

思路是什么呢?

首先,我们需要一个变量进行对比,如果是按下去之前的变量是1,按下之后的变量是0的话,那么这样就是一个下降沿,反之就是下降沿。

代码实现

在代码实现中,我们先初始化一些变量,这些变量初始值都是1,表示是按键一开始都是抬起来的。值得一提的是,这样的改变只是将消抖后的status和之前的变量有一个比较,看看是否是上升沿还是下降沿,中间还是需要消抖的,还是需要定时器返回一个status,这个status需要全是0的时候,再和之前的状态进行比较,看看是否是上升沿还是下降沿,只是在getstatus函数中,做出了改变,我们约定1就是下降沿,2就是上升沿,其余的都是0.

u8 Int_Button_GetSW1Status()
{
    // 按键之前的状态为抬起,但此时status为0
    if (s_is_sw1_released && s_sw1_status == 0)
    {
        s_is_sw1_released = 0;
        return 1;
    }
    // 按键之前的状态为按下,但此时status为0xFF
    if (!s_is_sw1_released && s_sw1_status == 0xFF)
    {
        s_is_sw1_released = 1;
        return 2;
    }
    // 什么情况返回0
    return 0;
}

移植显示部分

(1)中介函数返回标志位——想让定时器按时执行某一个函数的功能,并不是一定要将这个函数放入定时器的回调函数中,可以使用中介的方式。也就是我们定义一个中介函数,每当定时器执行这个中介函数的时候,中介函数就会返回一个标志为1(或者是将一个全局变量标志置为1),表示需要执行目标函数了,然后在目标函数中设定条件,只有每当标志为1的时候,才会执行这个函数。标志位返回了之后,再将标志位为0就好了,等待下一次的改变。

设置切换状态的按键

按键状态的切换可以使用标志位来实现,当按下按键的时候,标志位取反,表示进入了不同的状态,这样的话,就可以利用这个标志位当做限制条件,来做很多事情。

但是还有一个要点:如果我想让标志位为1中所产生的一切影响成为现实的话,那就要将这一切的结果写入影响现实的变量中,那么在什么时机写入进去的呢?按下按键,当进入标志位1中可以改变的话时候,那么就尽情的改变,当改变结束想要实现的时候,我们一般都会选择再次按下,这个时候就出现了一种情况,你按下这个按键想要让标志位转换之前,你的标志位是为1的,所以在转换之前,你的标志位为1的话,那么可以设置一下这个条件,在这个if中,将所有的改变写入影响现实的这个变量中就好了。

其他按键的作用

(1)可以利用显示的占空比来达到部分显示闪烁的目的。怎么达到占空比呢?一秒中,我一半时间是亮的,一般时间是暗的,就可以达到闪烁的目的了,闪烁的本质是显示函数的执行(只有进入设定状态的时候才会出现这个),而显示函数不方便进入定时器中,那么可以借助上述我们说的中介函数的方式,有或者是借一下其他人的定时器函数,将自己的变量填进去。比如有一个函数利用外部count使得100ms才使得标志位为1,让目标函数执行一次,那么我们可以直接将标志位放入,让标志位不断地增加,直到增加到10,也就是1s,当0-4的时候,代表亮,5-9的时候代表暗,所以思路要打开。

那怎么让具体的一段变亮和变暗呢?肯定无法直接从显示函数中做手脚,我们可以让变暗的位置直接抹掉,什么是抹掉呢?由于我们LCD上显示的是字符串,如果想让其不显示的话,就是让其所占的位置的暂时变为' '(空格),空格的ASCII码是32。比如str[0] = 32;就是将第一个抹掉了。在抹掉之前,也需要弄一个swich,来判断一下,选择的到底是谁。然后再将相应位置上的元素设置为空格就好了。

(2)按下设定键就暂停画面并且闪烁的原理是:其不让GET函数再次从时钟中获取s_date的数据了,通过标志位的威力,不让其获取了,但是显示功能没有被剥夺,这个时候s_date里面的数据是不变的,这个时候的两个按键就可以通过对s_date的更改,更改之后,再次按下状态键,在状态变化的前面就进行写入,并且将状态转换就可以进入正常的计时了。

(3)在无符号数中,0再减去1的话,就变成255了。为什么呢?底层的运算都是加法器,只要是相同的二进制数,得出的二进制数都是一样的,只不过最后因为不同的数据类型,表现出来的数据是不一样的。比如这里0-1等于多少?我们就按照是char来计算等于-1对吧,现将-1作为char时的二进制数写出来,然后将这段数字作为unsignde char转换出来,就是了。

业务代码的架构

业务代码的话是专门在一个文件夹中执行的,通常的架构是,一个初始化函数,还有一个汇总全部内方法的一个函数,这个函数是暴露在外面的,所有的功能性的函数都是需要写入到里面的。这样的话,就可以具体去写一些功能函数了,写完了之后往总Func函数里面一放入就好了。初始换函数也是很好的,放入一些变量的初值,以及比如时钟的设置之类的。

你可能感兴趣的:(嵌入式,嵌入式硬件,单片机,51单片机)