1 Star 0 Fork 4

armku / FN1895E-MCU101

forked from 建伟F4nniu / FN1895E-MCU101 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
MCU020.md 12.36 KB
一键复制 编辑 原始数据 按行查看 历史
建伟F4nniu 提交于 2016-12-23 00:30 . Track 4 files into repository.

#第二十节:依次逐个亮灯并且每次只能亮一个灯的跑马灯程序。

开场白:

上一节讲了先依次逐个亮再依次逐个灭的跑马灯程序。这一节在上一节的基础上,略作修改,继续讲跑马灯程序。我的跑马灯程序看似简单而且重复,其实蕴含着鸿哥的大智慧。它是基于鸿哥的switch状态机思想,领略到了它的简单和精髓,以后任何所谓复杂的工程项目,都不再复杂。要教会大家一个知识点:

  • 通过本跑马灯程序,加深理解鸿哥所有实战项目中switch状态机的思想精髓。

具体内容,请看源代码讲解。

  • (1)硬件平台:基于朱兆祺51单片机学习板。
  • (2)实现功能:第9个至第16个LED灯,依次逐个亮灯并且每次只能亮一个灯。第1至第8个LED灯一直灭。
  • (3)源代码讲解如下:
#include "REG52.H"

#define const_time_level_09_16  300  //第9个至第16个LED跑马灯的速度延时时间

void initial_myself();
void initial_peripheral();
void delay_short(unsigned int uiDelayShort);
void delay_long(unsigned int uiDelaylong);
void led_flicker_09_16(); // 第9个至第16个LED的跑马灯程序,逐个亮并且每次只能亮一个.
void hc595_drive(unsigned char ucLedStatusTemp16_09, unsigned char ucLedStatusTemp08_01);
void led_update();  //LED更新函数
void T0_time();  //定时中断函数


sbit hc595_sh_dr = P2 ^ 3;
sbit hc595_st_dr = P2 ^ 4;
sbit hc595_ds_dr = P2 ^ 5;

unsigned char ucLed_dr1 = 0; //代表16个灯的亮灭状态,0代表灭,1代表亮
unsigned char ucLed_dr2 = 0;
unsigned char ucLed_dr3 = 0;
unsigned char ucLed_dr4 = 0;
unsigned char ucLed_dr5 = 0;
unsigned char ucLed_dr6 = 0;
unsigned char ucLed_dr7 = 0;
unsigned char ucLed_dr8 = 0;
unsigned char ucLed_dr9 = 0;
unsigned char ucLed_dr10 = 0;
unsigned char ucLed_dr11 = 0;
unsigned char ucLed_dr12 = 0;
unsigned char ucLed_dr13 = 0;
unsigned char ucLed_dr14 = 0;
unsigned char ucLed_dr15 = 0;
unsigned char ucLed_dr16 = 0;

unsigned char ucLed_update = 0; //刷新变量。每次更改LED灯的状态都要更新一次。

unsigned char ucLedStep_09_16 = 0; //第9个至第16个LED跑马灯的步骤变量
unsigned int  uiTimeCnt_09_16 = 0; //第9个至第16个LED跑马灯的统计定时中断次数的延时计数器

unsigned char ucLedStatus16_09 = 0; //代表底层74HC595输出状态的中间变量
unsigned char ucLedStatus08_01 = 0; //代表底层74HC595输出状态的中间变量

void main()
{
    initial_myself();
    delay_long(100);
    initial_peripheral();
    while(1)
    {
        led_flicker_09_16(); // 第9个至第16个LED的跑马灯程序,逐个亮并且每次只能亮一个.
        led_update();  //LED更新函数
    }

}


void led_update()  //LED更新函数
{

    if(ucLed_update == 1)
    {
        ucLed_update = 0; //及时清零,让它产生只更新一次的效果,避免一直更新。

        if(ucLed_dr1 == 1)
        {
            ucLedStatus08_01 = ucLedStatus08_01 | 0x01;
        }
        else
        {
            ucLedStatus08_01 = ucLedStatus08_01 & 0xfe;
        }

        if(ucLed_dr2 == 1)
        {
            ucLedStatus08_01 = ucLedStatus08_01 | 0x02;
        }
        else
        {
            ucLedStatus08_01 = ucLedStatus08_01 & 0xfd;
        }

        if(ucLed_dr3 == 1)
        {
            ucLedStatus08_01 = ucLedStatus08_01 | 0x04;
        }
        else
        {
            ucLedStatus08_01 = ucLedStatus08_01 & 0xfb;
        }

        if(ucLed_dr4 == 1)
        {
            ucLedStatus08_01 = ucLedStatus08_01 | 0x08;
        }
        else
        {
            ucLedStatus08_01 = ucLedStatus08_01 & 0xf7;
        }


        if(ucLed_dr5 == 1)
        {
            ucLedStatus08_01 = ucLedStatus08_01 | 0x10;
        }
        else
        {
            ucLedStatus08_01 = ucLedStatus08_01 & 0xef;
        }


        if(ucLed_dr6 == 1)
        {
            ucLedStatus08_01 = ucLedStatus08_01 | 0x20;
        }
        else
        {
            ucLedStatus08_01 = ucLedStatus08_01 & 0xdf;
        }


        if(ucLed_dr7 == 1)
        {
            ucLedStatus08_01 = ucLedStatus08_01 | 0x40;
        }
        else
        {
            ucLedStatus08_01 = ucLedStatus08_01 & 0xbf;
        }


        if(ucLed_dr8 == 1)
        {
            ucLedStatus08_01 = ucLedStatus08_01 | 0x80;
        }
        else
        {
            ucLedStatus08_01 = ucLedStatus08_01 & 0x7f;
        }

        if(ucLed_dr9 == 1)
        {
            ucLedStatus16_09 = ucLedStatus16_09 | 0x01;
        }
        else
        {
            ucLedStatus16_09 = ucLedStatus16_09 & 0xfe;
        }

        if(ucLed_dr10 == 1)
        {
            ucLedStatus16_09 = ucLedStatus16_09 | 0x02;
        }
        else
        {
            ucLedStatus16_09 = ucLedStatus16_09 & 0xfd;
        }

        if(ucLed_dr11 == 1)
        {
            ucLedStatus16_09 = ucLedStatus16_09 | 0x04;
        }
        else
        {
            ucLedStatus16_09 = ucLedStatus16_09 & 0xfb;
        }

        if(ucLed_dr12 == 1)
        {
            ucLedStatus16_09 = ucLedStatus16_09 | 0x08;
        }
        else
        {
            ucLedStatus16_09 = ucLedStatus16_09 & 0xf7;
        }


        if(ucLed_dr13 == 1)
        {
            ucLedStatus16_09 = ucLedStatus16_09 | 0x10;
        }
        else
        {
            ucLedStatus16_09 = ucLedStatus16_09 & 0xef;
        }


        if(ucLed_dr14 == 1)
        {
            ucLedStatus16_09 = ucLedStatus16_09 | 0x20;
        }
        else
        {
            ucLedStatus16_09 = ucLedStatus16_09 & 0xdf;
        }


        if(ucLed_dr15 == 1)
        {
            ucLedStatus16_09 = ucLedStatus16_09 | 0x40;
        }
        else
        {
            ucLedStatus16_09 = ucLedStatus16_09 & 0xbf;
        }


        if(ucLed_dr16 == 1)
        {
            ucLedStatus16_09 = ucLedStatus16_09 | 0x80;
        }
        else
        {
            ucLedStatus16_09 = ucLedStatus16_09 & 0x7f;
        }

        hc595_drive(ucLedStatus16_09, ucLedStatus08_01); //74HC595底层驱动函数

    }
}

void hc595_drive(unsigned char ucLedStatusTemp16_09, unsigned char ucLedStatusTemp08_01)
{
    unsigned char i;
    unsigned char ucTempData;
    hc595_sh_dr = 0;
    hc595_st_dr = 0;

    ucTempData = ucLedStatusTemp16_09; //先送高8位
    for(i = 0; i < 8; i++)
    {
        if(ucTempData >= 0x80)hc595_ds_dr = 1;
        else hc595_ds_dr = 0;

        hc595_sh_dr = 0;   //SH引脚的上升沿把数据送入寄存器
        delay_short(15);
        hc595_sh_dr = 1;
        delay_short(15);

        ucTempData = ucTempData << 1;
    }

    ucTempData = ucLedStatusTemp08_01; //再先送低8位
    for(i = 0; i < 8; i++)
    {
        if(ucTempData >= 0x80)hc595_ds_dr = 1;
        else hc595_ds_dr = 0;

        hc595_sh_dr = 0;   //SH引脚的上升沿把数据送入寄存器
        delay_short(15);
        hc595_sh_dr = 1;
        delay_short(15);

        ucTempData = ucTempData << 1;
    }

    hc595_st_dr = 0; //ST引脚把两个寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来
    delay_short(15);
    hc595_st_dr = 1;
    delay_short(15);

    hc595_sh_dr = 0;  //拉低,抗干扰就增强
    hc595_st_dr = 0;
    hc595_ds_dr = 0;

}

/* 注释一:
* 以下程序,看似简单而且重复,其实蕴含着鸿哥的大智慧。
* 它是基于鸿哥的switch状态机思想,领略到了它的简单和精髓,
* 以后任何所谓复杂的工程项目,都不再复杂。
*/
void led_flicker_09_16() //第9个至第16个LED的跑马灯程序,逐个亮并且每次只能亮一个.
{
    switch(ucLedStep_09_16)
    {
    case 0:
        if(uiTimeCnt_09_16 >= const_time_level_09_16) //时间到
        {
            uiTimeCnt_09_16 = 0; //时间计数器清零

            ucLed_dr16 = 0; //第16个灭
            ucLed_dr9 = 1; //第9个亮

            ucLed_update = 1; //更新显示
            ucLedStep_09_16 = 1; //切换到下一个步骤
        }
        break;
    case 1:
        if(uiTimeCnt_09_16 >= const_time_level_09_16) //时间到
        {
            uiTimeCnt_09_16 = 0; //时间计数器清零

            ucLed_dr9 = 0; //第9个灭
            ucLed_dr10 = 1; //第10个亮

            ucLed_update = 1; //更新显示
            ucLedStep_09_16 = 2; //切换到下一个步骤
        }
        break;
    case 2:
        if(uiTimeCnt_09_16 >= const_time_level_09_16) //时间到
        {
            uiTimeCnt_09_16 = 0; //时间计数器清零

            ucLed_dr10 = 0; //第10个灭
            ucLed_dr11 = 1; //第11个亮

            ucLed_update = 1; //更新显示
            ucLedStep_09_16 = 3; //切换到下一个步骤
        }
        break;
    case 3:
        if(uiTimeCnt_09_16 >= const_time_level_09_16) //时间到
        {
            uiTimeCnt_09_16 = 0; //时间计数器清零

            ucLed_dr11 = 0; //第11个灭
            ucLed_dr12 = 1; //第12个亮

            ucLed_update = 1; //更新显示
            ucLedStep_09_16 = 4; //切换到下一个步骤
        }
        break;
    case 4:
        if(uiTimeCnt_09_16 >= const_time_level_09_16) //时间到
        {
            uiTimeCnt_09_16 = 0; //时间计数器清零

            ucLed_dr12 = 0; //第12个灭
            ucLed_dr13 = 1; //第13个亮

            ucLed_update = 1; //更新显示
            ucLedStep_09_16 = 5; //切换到下一个步骤
        }
        break;
    case 5:
        if(uiTimeCnt_09_16 >= const_time_level_09_16) //时间到
        {
            uiTimeCnt_09_16 = 0; //时间计数器清零

            ucLed_dr13 = 0; //第13个灭
            ucLed_dr14 = 1; //第14个亮

            ucLed_update = 1; //更新显示
            ucLedStep_09_16 = 6; //切换到下一个步骤
        }
        break;
    case 6:
        if(uiTimeCnt_09_16 >= const_time_level_09_16) //时间到
        {
            uiTimeCnt_09_16 = 0; //时间计数器清零

            ucLed_dr14 = 0; //第14个灭
            ucLed_dr15 = 1; //第15个亮

            ucLed_update = 1; //更新显示
            ucLedStep_09_16 = 7; //切换到下一个步骤
        }
        break;
    case 7:
        if(uiTimeCnt_09_16 >= const_time_level_09_16) //时间到
        {
            uiTimeCnt_09_16 = 0; //时间计数器清零

            ucLed_dr15 = 0; //第15个灭
            ucLed_dr16 = 1; //第16个亮

            ucLed_update = 1; //更新显示
            ucLedStep_09_16 = 0; //返回到开始处,重新开始新的一次循环
        }
        break;

    }

}


void T0_time() interrupt 1
{
    TF0 = 0; //清除中断标志
    TR0 = 0; //关中断

    if(uiTimeCnt_09_16 < 0xffff) //设定这个条件,防止uiTimeCnt超范围。
    {
        uiTimeCnt_09_16++;  //累加定时中断的次数,
    }

    TH0 = 0xf8; //重装初始值(65535-2000)=63535=0xf82f
    TL0 = 0x2f;
    TR0 = 1; //开中断
}

void delay_short(unsigned int uiDelayShort)
{
    unsigned int i;
    for(i = 0; i < uiDelayShort; i++)
    {
        ;   //一个分号相当于执行一条空语句
    }
}

void delay_long(unsigned int uiDelayLong)
{
    unsigned int i;
    unsigned int j;
    for(i = 0; i < uiDelayLong; i++)
    {
        for(j = 0; j < 500; j++) //内嵌循环的空指令数量
        {
            ; //一个分号相当于执行一条空语句
        }
    }
}


void initial_myself()  //第一区 初始化单片机
{

    TMOD = 0x01; //设置定时器0为工作方式1


    TH0 = 0xf8; //重装初始值(65535-2000)=63535=0xf82f
    TL0 = 0x2f;


}

void initial_peripheral() //第二区 初始化外围
{
    EA = 1;   //开总中断
    ET0 = 1;  //允许定时中断
    TR0 = 1;  //启动定时中断

}

总结陈词:

上一节和这一节讲了两种不同的跑马灯程序,如果要让这两种不同的跑马灯程序都能各自独立运行,就涉及到多任务并行处理的程序框架。没错,下一节就讲多任务并行处理这方面的知识,欲知详情,请听下回分解-----多任务并行处理两路跑马灯。

(未完待续,下节更精彩,不要走开哦)

C
1
https://gitee.com/armku/FN1895E-MCU101.git
git@gitee.com:armku/FN1895E-MCU101.git
armku
FN1895E-MCU101
FN1895E-MCU101
master

搜索帮助