原题要求如下:
1. 用16盏以上的LED小灯,实现至少4种彩灯灯光效果(不含全部点亮,全部熄灭);
2. 可以用输入按钮在几种灯光效果间切换;
3. 可以通过按钮暂停彩灯效果,使小灯全亮,再次按下相同按钮后继续之前的效果;
4. 增加自动在几种效果间切换的功能,并设置一个按钮可以在自动模式和手动模式间切换;
5. 使用定时中断延时。
我的最终作品如下:
(为方便演示,速度已调快一倍处理)
一共有十钟灯光效果,分别是:
顺时针流水灯、逆时针流水灯、交替闪烁、顺时针对角灯、逆时针对角灯、顺时针逐个点亮、顺时针逐个熄灭、逆时针逐个点亮、逆时针逐个熄灭、二进制加法。
程序代码如下:
代码太长,已被折叠。点击展开查看
- /**************************************************************************************************
- 模块名称:51单片机彩灯控制器
- 模块功能:实现十种循环彩灯控制
- 编写人员:mengkun (http://mkblog.cn)
- 编写日期:2016/12/18
- **************************************************************************************************/
- #include <reg51.h>
- #define false 0
- #define true 1
- #define uchar unsigned char
- #define uint unsigned int
- sbit pause_key = P3^0; //暂停按钮
- sbit auto_key = P3^1; //手动模式的效果切换
- sbit change_key = P3^2; //手动模式效果切换
- sbit pauseLed = P3^6; //暂停、启动指示灯
- sbit autoLed = P3^7; //自动、手动模式指示灯
- int ledCode[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //led段码(单个显示)
- int ledCode2[8]={0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00}; //led段码(半显示半灭)
- int disCode[10]={0x03,0x9f,0x25,0x0d,0x99,0x49,0x41,0x1f,0x01,0x09}; //数码管段码 0~9
- void displayLed(void); //显示led的主函数
- void keyScan(void); //键盘扫描处理函数
- void Delay10ms(unsigned int n); //延时10ms
- bit isPause = false; //是否暂停
- bit isAuto = true; //是否自动运行
- bit isChange = false; //是否要切换下一个效果
- uchar time; //计时满0.5s
- uchar types; //第几种灯光显示方案
- uint counts; //灯光的第几个
- /*******************************************************************************
- * 函 数 名 : T0_INT
- * 函数功能 : T0定时器中断函数
- * 输 入 : 无
- * 输 出 : 无
- *******************************************************************************/
- void T0_INT(void) interrupt 1
- {
- TL0= (65536-50000)/256;
- TH0= (65536-50000)%256;
- time ++;
- if(time >= 10) //定时时间:0.5s
- {
- time=0;
- if(isChange == true) //可以变换下一种显示效果了
- {
- counts = 0;
- types++; //显示下一种效果
- if(types > 9) types = 0;
- P0 = disCode[types]; //更新数码管显示
- isChange = false;
- }
- displayLed();
- counts++;
- }
- }
- /*******************************************************************************
- * 函 数 名 : main
- * 函数功能 : 主函数
- * 输 入 : 无
- * 输 出 : 无
- *******************************************************************************/
- void main(void)
- {
- TMOD=0x61; //0110 0001 //方式一
- TL0= (65536-50000)/256; //50ms
- TH0= (65536-50000)%256;
- TR0=1; //开启T0
- ET0=1; //T0中断允许
- EA=1; //总中断开启
- time = 0; //定时器时间扩种(0.5s)
- counts = 0; //灯光的第几次
- types = 0; //灯光显示模式
- pauseLed = 0; //暂停指示灯灭
- P0 = disCode[types]; //更新数码管显示
- while(1)
- {
- keyScan(); //键盘扫描及处理
- }
- }
- /*******************************************************************************
- * 函 数 名 : keyScan
- * 函数功能 : 键盘扫描处理
- * 输 入 : 无
- * 输 出 : 无
- *******************************************************************************/
- void keyScan(void)
- {
- if(pause_key == 0) //按下了暂停按钮
- {
- Delay10ms(1);
- if(pause_key == 0)
- {
- isPause = ~isPause;
- pauseLed = isPause;
- if(isPause == true)
- {
- ET0=0; //关闭T0中断
- P0 = 0xfd; //数码管显示 “-”
- P1 = 0x00; //所有的灯都亮起来
- P2 = 0x00;
- }else{
- ET0=1; //T0中断允许
- P0 = disCode[types]; //更新数码管显示
- displayLed();
- }
- while(pause_key == 0); //防止按键重复检测
- }
- }
- if(auto_key == 0) //自动、手动切换按键按下
- {
- Delay10ms(1);
- if(auto_key == 0)
- {
- isAuto = ~isAuto;
- autoLed = isAuto;
- }
- while(auto_key == 0); //防止按键重复检测
- }
- if(change_key == 0 && isAuto == false) //手动模式,并且效果切换按下
- {
- Delay10ms(1);
- if(change_key == 0)
- {
- isChange = true;
- }
- while(change_key == 0); //防止按键重复检测
- }
- }
- /*******************************************************************************
- * 函 数 名 : displayLed
- * 函数功能 : 显示led灯
- * 输 入 : (全局变量 )types:显示效果;counts:当前效果下的第几次
- * 输 出 : 无
- *******************************************************************************/
- void displayLed(void)
- {
- switch(types)
- {
- case 0: //顺时针旋转led灯
- {
- if(counts >= 16) counts = 0;
- if(counts >=15)
- {
- if(isAuto == true) isChange = true;
- }
- if(counts <8)
- {
- P1 = 0xff;
- P2 = ledCode[7-counts];
- }
- else
- {
- P1 = ledCode[15-counts];
- P2 = 0xff;
- }
- break;
- }
- case 1: //逆时针旋转LED灯
- {
- if(counts >= 16) counts = 0;
- if(counts >=15)
- {
- if(isAuto == true) isChange = true;
- }
- if(counts <8)
- {
- P1 = ledCode[counts];
- P2 = 0xff;
- }
- else
- {
- P1 = 0xff;
- P2 = ledCode[counts-8];
- }
- break;
- }
- case 2: //交叉替换
- {
- if(counts >= 16) counts = 0;
- if(counts >=15)
- {
- if(isAuto == true) isChange = true;
- }
- if(counts % 2 == 0) //偶数
- {
- P1=0xaa;
- P2=0xaa;
- }
- else
- {
- P1=0x55;
- P2=0x55;
- }
- break;
- }
- case 3: //对角顺时针
- {
- if(counts >= 8) counts = 0;
- if(counts >=7)
- {
- if(isAuto == true) isChange = true;
- }
- P1 = ledCode[7 - counts];
- P2 = ledCode[7 - counts];
- break;
- }
- case 4: //对角逆时针
- {
- if(counts >= 8) counts = 0;
- if(counts >=7)
- {
- if(isAuto == true) isChange = true;
- }
- P1 = ledCode[counts];
- P2 = ledCode[counts];
- break;
- }
- case 5: //顺时针逐个点亮
- {
- if(counts >= 17) counts = 0;
- if(counts <8)
- {
- P1 = ~ledCode2[7 - counts];
- P2 = 0xff;
- }
- else if(counts <16)
- {
- P1 = 0x00;
- P2 = ~ledCode2[15 - counts];
- }
- else //全亮
- {
- P1 = 0x00;
- P2 = 0x00;
- if(isAuto == true) isChange = true;
- }
- break;
- }
- case 6: //顺时针逐个又灭掉
- {
- if(counts >= 17) counts = 0;
- if(counts <8)
- {
- P1 = ledCode2[7 - counts];
- P2 = 0x00;
- }
- else if(counts <16)
- {
- P1 = 0xff;
- P2 = ledCode2[15 - counts];
- }
- else //全灭
- {
- P1 = 0xff;
- P2 = 0xff;
- if(isAuto == true) isChange = true;
- }
- break;
- }
- case 7: //逆时针逐个点亮
- {
- if(counts >= 17) counts = 0;
- if(counts <8)
- {
- P1 = 0xff;
- P2 = ledCode2[counts];
- }
- else if(counts <16)
- {
- P1 = ledCode2[counts - 7];
- P2 = 0x00;
- }
- else //全亮
- {
- P1 = 0x00;
- P2 = 0x00;
- if(isAuto == true) isChange = true;
- }
- break;
- }
- case 8: //逆时针逐个灭掉
- {
- if(counts >= 17) counts = 0;
- if(counts <8)
- {
- P1 = 0x00;
- P2 = ~ledCode2[counts];
- }
- else if(counts <16)
- {
- P1 = ~ledCode2[counts - 7];
- P2 = 0xff;
- }
- else //全亮
- {
- P1 = 0xff;
- P2 = 0xff;
- if(isAuto == true) isChange = true;
- }
- break;
- }
- case 9: //二进制加法
- {
- if(counts >= 255) counts = 0;
- if(counts == 254 && isAuto == true) isChange = true;
- P1 = ~counts;
- P2 = ~counts;
- break;
- }
- default:
- types = 0;
- P0 = disCode[types]; //更新数码管显示
- }
- }
- /*******************************************************************************
- * 函 数 名 : Delay10ms (多个)
- * 函数功能 : 延时函数,延时n*10ms
- * 输 入 : n-延时次数
- * 输 出 : 无
- *******************************************************************************/
- void Delay10ms(unsigned int n)
- {
- unsigned char a, b;
- for (; n>0; n--)
- {
- for (b=38; b>0; b--)
- {
- for (a=130; a>0; a--);
- }
- }
- }
完整proteus仿真图如下:
(可点击查看大图)
程序和仿真图打包下载:
下载地址本文作者为mengkun,转载请注明。
+1甲乙
加一
学习+1
前来学习
前来学习=w=
前来学习
看看大神作品
这个学习下
不错
初值应该是65536-10000这样才是50ms
@小天师C51单片机时钟频率为12MHz,65536-10000 是 10ms,不是 50ms。文中的代码无误。 [流汗]
感觉好厉害的样子
下载下来研究一下
是VC++的徒弟
@宁仔VC++我不会 [微笑]
@宁仔这篇文章里的C语言是C51,是运行在单片机中的,与C++是两个概念。如果你要学C51,推荐去看郭天祥的教程,网上资源很多。
你QQ多少 我不会改API
@宁仔这个太基础了……自己想办法尝试吧,不难的 [晕]
@mengkun你收徒弟吗?
@宁仔没时间,不收。如果你要学习html技术的话,推荐你去看李炎恢的视屏教程(传送门 http://www.ycku.com/xhtml/)我之前就是照着这个一步步学过来的。
好厉害
@宁仔过奖了 [得意]
@mengkun那个音乐网源码是你开发的吗?
@宁仔是的,详见 http://mkblog.cn/203/