用_crol_函數實現LED流水燈的調試過程


#include "reg52.h"
#include "intrins.h"
typedef unsigned int u16;
typedef unsigned char u8;
#define led P2
u16 ret;

void delay(u16 i)
{
    while(i--)
    {};
}

void main(void)
{

    

    while(1)
    {
       led=0xfe;                //D1亮 ,其它燈不亮
       delay(60000);
       
       _crol_(led,1);            //0xFD  D2亮,其它不亮 
       delay(60000);
    
    }

}

我最開始的代碼大概是上面這個樣子的,我的預期是先是D1亮,然后是D1滅,D2亮,結果是始終是D1亮。百思不得其解,於是開始了漫長的調試。

感覺問題應該出在_crol_這個函數的前后,F9下了兩個斷點

 

ctrl+F5開啟調試

在watch中添加P2這個寄存器,led是P2的別名,因為我們想看它的值。

 

F10步過_crol_函數之后發現P2的值更本沒有改變,P2的值初始化是0xFF,然后經過我們的賦值,它是0xFE,經過_crol_它的值還是0xFE, 這就很奇怪了,然后我就想着是不是這個函數有什么問題

於是定義了一個變量ret來接受_crol_函數的返回值,並把ret也作為watch的對象,看一下它的值是怎么變化的。

經過調試發現最后ret的值正好是0xFD,所以_crol_的返回值才是我們要的結果。

_crol_(led,1)並不會修改led的值,它是把led的值復制一份,然后修改之后把這個結果以返回值的方式存放起來。

 

所以產生這個問題的原因是沒有閱讀_crol_的官方文檔,不知道被操作數的結果是以什么形式返回的。

這里是_crol_函數的官方解釋:

http://www.keil.com/support/man/docs/c51/c51__crol_.htm?_ga=2.234590429.235304523.1557741929-1916941500.1557741929

 

 

 

#include "reg52.h"
#include "intrins.h"
typedef unsigned int u16;
typedef unsigned char u8;
#define led P2


void delay(u16 i)
{
    while(i--)
    {};
}

void main(void)
{

    

    while(1)
    {
       led=0xfe;                //D1亮 ,其它燈不亮
       delay(60000);
       
       led=_crol_(led,1);        //0xFD  D2亮,其它不亮 
       delay(60000);

       led=_crol_(led,1);       //D3亮
       delay(60000);

       led=_crol_(led,1);       //D4亮
       delay(60000);

       led=_crol_(led,1);       //D5亮
       delay(60000);

       led=_crol_(led,1);       //D6亮
       delay(60000);

       led=_crol_(led,1);       //D7亮
       delay(60000);

       led=_crol_(led,1);       //D8亮
       delay(60000);

       //讓D7開始亮 一直到D1

       led=_cror_(led,1);      //D7亮
       delay(60000);

       led=_cror_(led,1);      //D6亮
       delay(60000);

       led=_cror_(led,1);      //D5亮
       delay(60000);

       led=_cror_(led,1);      //D4亮
       delay(60000);

       led=_cror_(led,1);      //D3亮
       delay(60000);

       led=_cror_(led,1);      //D2亮
       delay(60000);
    
    }

}

 

這個程序的while循環最后一點代碼要解釋一下當D2亮起之后,P2的位狀態是1111 1101,然后delay一下,然后就到了循環開始的部分了,這里讓led初始化fe了,所以第一個燈又亮了,

也就是每循環一次,led就被初始化一次。

這個代碼是可以繼續優化的,D2到D8亮起來用的是同樣的代碼,我們可以放在一個for循環里面 D7到D2也可以放在一個for循環里面。

比如for (i=0;i<7;i++)

{

  led=_crol(led,1);

}

 for (i=0;i<6;i++)

{

  led=_cror(led,1);

}

 

這里有個很重要的點,就是為什么我們可以通過循環右移和循環左移來控制燈的亮滅?

其實就是從原理圖來的,我們看下圖再說。

有圖可知,P2的第0位控制D1,等等等 P2的第7位控制D8,而且只需要將P2的第0位設置位低電平就可以讓D1亮起來,設置高電平就可以讓D1滅了。

 

P2是什么它是一個寄存器的名字,它有8個位,從第0位到第7位

根據流水燈的定義,先讓D1亮起來,那么此時需要P2的值是1111 1110 然后需要D2亮起來,此時需要P2的值是1111 1101,然后需要D3亮起來,此時需要P2的值是1111 1110

.。。。需要D8亮起來,需要P2的值是0111 1111

從1111 1101 到1111 1101 到1111 1011 再到0111 1111 是不是發現就是0的位置向左移動了?_crol_就有這種功能啊。

 

_crol_的實現是這樣的,它叫做循環左移,你把1111 1110  左移一位之后 ,那么新生成的那個數是1111110X,最末尾的這個X是多少呢?就是1111 11110 最高位被擠出去的那一位,然后補回到了1111110X的最低位,也就是最后的結果是1111 1101  ,循環左移,這個循環很重要。

我畫了一張圖解釋這個過程,循環右移也是一樣的。

 

C語言中還有左移和右移的操作,能不能用在這里呢?

 

      while(1)
          {
            
             P2=0xFE; //1111 1110
             delay(60000);
             P2=P2<<1;
             delay(60000);
             P2=P2<<1;
             delay(60000);



          }                  

 

 

 

 

從0xFE(1111 1110)每次左移一位的結果

1111 1100
1111 1000

可以看出左移運算符是把高位擠出去之后,新生成的數的低位是用0填充的,並不能滿足我們流水燈的定義。

所以最符號我們要求的就是循環左移函數和循環右移函數。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM