单片机交流
直播中

他在笑

9年用户 718经验值
擅长:可编程逻辑 电源/新能源 制造/封装
私信 关注
[问答]

如何利用51单片机实现LED灯闪烁?

如何利用51单片机实现LED灯闪烁?

回帖(1)

陈佳敏

2021-10-18 14:38:27
本人为软件工程专业,接触计算机硬件学习较少,以一个嵌入式非专业角度,入门学习。对于一个要求红黑树都要能敲出来的专业,对于这种面向寄存器编程,是比较简单的,大家可以很快入门(写代码而言,想外设学习,自己组装硬件还学专业地学习电子相关知识)如有错误请见谅。使用普中51-单核-A2学习。本学习笔记适合人员:计算机相关专业、或者有熟练的C语言编程学习经历的勇士!
单片机针脚

      C51系列单片机有4*8=32个针脚。p0,p1,p2,p3四个寄存器,每个寄存器大小为8位,干什么用的呢?这些针脚只有两种状态即0(低电平)与1(高电平)。我们可以通过写程序,通过编译器生成CPU的一条条指令,烧录到里面去。我们通过对针脚的高低电平进行逻辑判断,再通过一系列状态对针脚状态做出改变。
      举一个例子,比如查看某个针脚状态,读到了1,可以假想(另一个针脚上连着电机),我们改变针脚状态,让电机转起来。
      总之完单片机编程玩的就是寄存器,我们也可以称它为针脚编程。为什么使用C语言写的呢,而写我们好像都是用的一个叫做keil的软件。其实我们的C语言代码没有跑在单片机上,CPU认识的东西叫做指令集,其实就是一串串0-1编码。一条条执行,跑了起来,keil就是做其中的转换的一个编译软件,将我们写的C语言单片机代码转换为CPU可以认识的一条条指令。有人肯定想问:我们不用C语言不行吗,当然可以,如果你能写一个自己的编程语言,做这样的转换,也许下一个革命的人就是你呢。





那个银亮色的晶振什么鬼

      人们都说单片机的心藏是那个叫晶振的东西,晶振有什么用呢。上面我们提到,CPU认识需要执行一条一条的指令,但机器怎么知道一条条执行呢,我们可以傻瓜式想想,晶振发出脉冲信号,没发一次单片机就会执行一条或多条指令。我们后面会学到单片的中断、定时器,晶振每隔固定时间发出信号,那么我们就可以利用它来知道经过了多长时间。管它什么鬼呢,把硬件交给搞硬件的,我们先专心写我们的面向针脚编程吧。

C51程序界的Hello World
#include


void main()
{
        P2=0xFE;        //1111 1110
        while(1)
        {
               
        }
}


      我们通过控制寄存器存储的值,来改变针脚的状态,后面为什么有一个while(1){}呢,单片机程序与我们现在windows、Linux C程序不同,电脑上的程序运行一次就结束了。单片机如果程序运行完后、它会从头再来。所以我们让单片机卡死在哪里就好了。


LED灯闪烁实现
      怎样实现延时呢?没错我们可以暴力解决,让它运行一段循环不就行了嘛。我们可以使用stc-isp软件来生成延时代码片段。我们要知道,晶振就像一个定时的东西,每隔一个固定的时间片段就会发出脉冲信号,让我们的单片机CPU指令,一条条执行(形象地描述,原理太复杂了,恐怕要读一整本计算机组成原理)


#include
#include


void Delay500ms()                //@12.000MHz
{
        unsigned char i, j, k;


        _nop_();
        i = 4;
        j = 205;
        k = 187;
        do
        {
                do
                {
                        while (--k);
                } while (--j);
        } while (--i);
}




void main()
{
        while(1)
        {
                P2=0xFE;        //1111 1110
                Delay500ms();
                P2=0xFF;        //1111 1111
                Delay500ms();
        }
}


      我们改变的个针脚的状态,交替执行,转态变化 0__1__0__1__0__1…,这样不就闪烁起来了吗。


LED流水灯实现
      流水灯这不过,是一排灯按照按顺序点亮,灭掉,下一个点亮,灭掉…而已。我们按一定的逻辑来控制一个寄存器的位的状态就好了。


#include
#include


void Delay500ms()                //@12.000MHz
{
        unsigned char i, j, k;


        _nop_();
        i = 4;
        j = 205;
        k = 187;
        do
        {
                do
                {
                        while (--k);
                } while (--j);
        } while (--i);
}




void main()
{
        while(1)
        {
                P2=0xFE;//1111 1110
                Delay500ms();
                P2=0xFD;//1111 1101
                Delay500ms();
                P2=0xFB;//1111 1011
                Delay500ms();
                P2=0xF7;//1111 0111
                Delay500ms();
                P2=0xEF;//1110 1111
                Delay500ms();
                P2=0xDF;//1101 1111
                Delay500ms();
                P2=0xBF;//1011 1111
                Delay500ms();
                P2=0x7F;//0111 1111
                Delay500ms();
        }
}


      虽然这是一种傻瓜式流水灯,但我们能实现功能就好了。就像做实物一样,不管用了什么技术,就像有一个网站,java做服务端,C++做服务端。做为一个使用者,谁会没事关注这些东西呢。


延时函数可复用
      我们不能需要用到多长时间的延时,都去创建一个函数吧,为何不把延时函数加个参数,来实现呢


#include


void Delay1ms(unsigned int xms);                //@12.000MHz


void main()
{
        while(1)
        {
                P2=0xFE;//1111 1110
                Delay1ms(1000);
                P2=0xFD;//1111 1101
                Delay1ms(1000);
                P2=0xFB;//1111 1011
                Delay1ms(100);
                P2=0xF7;//1111 0111
                Delay1ms(100);
                P2=0xEF;//1110 1111
                Delay1ms(100);
                P2=0xDF;//1101 1111
                Delay1ms(100);
                P2=0xBF;//1011 1111
                Delay1ms(100);
                P2=0x7F;//0111 1111
                Delay1ms(100);
        }
}


void Delay1ms(unsigned int xms)                //@12.000MHz
{
        unsigned char i, j;
        while(xms)
        {
                i = 2;
                j = 239;
                do
                {
                        while (--j);
                } while (--i);
                xms--;
        }
}


使用按键
      如果一个开关一边接到了针脚上,另一端接上1(高电平),当我们地的开关闭合时,那么针脚状态就是1,开关断开,则是0 ,我们可以去检测针脚状态来进行逻辑控制


#include


void main()
{
        while(1)
        {
                if(P3_1==0 || P3_0==0)        //如果K1按键或K2按键按下
                {
                        P2_0=0;                //LED1输出0,点亮
                }
                else
                {
                        P2_0=1;                //LED1输出1,熄灭
                }
        }
}


使用按键保存状态
#include


void Delay(unsigned int xms)
{
        unsigned char i, j;
        while(xms)
        {
                i = 2;
                j = 239;
                do
                {
                        while (--j);
                } while (--i);
                xms--;
        }
}


void main()
{
        while(1)
        {
                if(P3_1==0)                        //如果K1按键按下
                {
                /*
                1          /1
                          /
                         /
                   0----/0
                */
                        Delay(20);                //消除下坡上坡影响
                        while(P3_1==0);        //松手检测
                        Delay(20);                //延时消抖
                       
                        P2_0=~P2_0;                //LED1取反
                }
        }
}


利用左移右移
      左移:右边补0,例:00000001<<3 -> 00000010;按位左移运算符。左操作数按位左移右操作数指定的位数(在低位补 0)。左移运算符,num << 1,相当于 num 乘以 2(每左移一位就相当于乘以一个 2)。
      按位右移运算符。左操作数按位右移右操作数指定的位数(如果该数为正数,则高位补 0 ,若为负数,则高位补 1)。右移运算符,num >> 1,相当于 num 除以 2(每右移一位相当于除以一个 2)。


#include
void Delay(unsigned int xms);


unsigned char LEDNum;


void main()
{
        P2=~0x01;                                //上电默认LED1点亮
        while(1)
        {
                if(P3_1==0)                        //如果K1按键按下
                {
                        Delay(20);
                        while(P3_1==0);
                        Delay(20);
                        LEDNum++;                //LEDNum自增
                        if(LEDNum>=8)        //限制LEDNum自增范围
                                LEDNum=0;
                        P2=~(0x01<                 }
                if(P3_0==0)                        //如果K2按键按下
                {
                        Delay(20);
                        while(P3_0==0);
                        Delay(20);
                        if(LEDNum==0)        //LEDNum减到0后变为7
                                LEDNum=7;
                        else                        //LEDNum未减到0,自减
                                LEDNum--;
                        P2=~(0x01<                 }
        }
}








void Delay(unsigned int xms)
{
        unsigned char i, j;
        while(xms--)
        {
                i = 2;
                j = 239;
                do
                {
                        while (--j);
                } while (--i);
        }
}
举报

更多回帖

发帖
×
20
完善资料,
赚取积分