题目:裁定控制器
## 项目相关要求
程序功能: 利用实验开发板,完成“彩灯控制器” 功能的程序设计与调试。
所用到的相关知识
流水灯,数码管的动态显示,定时器,独立按键
项目分析
本次项目主要分成三个部分,第一部分:四种模式的流水灯,该部分使四个自定义函数来实现。第二部分:数码管的显示,分为左右两边,左边为运行模式的选择。右边为流水间隔。第三部分:独立按键的控制,分别使用s7,s6,s5,s4来控制不同的功能。 整个项目实现的主要思想:先将实现四种流水灯模式,并将四种模式封装成四个函数,方便调用。定义count,和sum变量,count用来计数,即中断次数,用来实现流水灯的时间间隔。sum用来记录流转间隔,初始为400ms,即sum = 8,每加100ms,sum加2,最多为24,即1200ms。定义mod:记录模式,默认为第一种模式、stop_start:记录启动/暂停状态(0为暂停,1为启动)、run_time:1为"运行模式" 2为 “流转间隔” 3其他数码管全灭(默认为全灭)。每当按下s7时,便让TR1在0和1之间来回替换,以达到暂停和开始的效果,并使用stop_start来记录每次的状态。当按下s6时,依次切换三种状态,即运行状态、流水间隔状态、数码管全灭状态,并使用run_time来记录。s3,s4必须要在run_time等于1或者2才由效果。当按下s3时,并且run_time等于1时,让mod减一,但是mod最小为1,当run_time等于2时让sum减2(即减100ms),最小为8(即400ms)。s4同理。最后显示流水灯和数码管,流水灯根据mod来实现不同的模式;数码管根据run_time来动态显示不同的效果。
相关代码
#include<reg52.h>
#include<intrins.h>
void Delay1ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
void Delay10ms() //@11.0592MHz
{
unsigned char i, j;
i = 108;
j = 145;
do
{
while (--j);
} while (--i);
}
unsigned char code t[4]={0x7e,0xbd,0xdb,0xe7};
unsigned char code duan[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//控制数码管的段线
sbit s7=P3^0;
sbit s6=P3^1;
sbit s5=P3^2;
sbit s4=P3^3;
int count = 0;
int sum = 8;//记录流转间隔,初始为400ms,即sum = 8,每加100ms,sum加2,最多为24
int mod = 1;//记录模式,默认为第一种模式
int a = 0xfe;
int b = 0x7f;
int i = 3;//中间往两边走的下标
int j = 0;//两边往中间的下标
int stop_start = 0;//记录启动/暂停状态(0为暂停,1为启动)
int run_time = 0;//1为"运行模式" 2为 "流转间隔" 3其他数码管全灭(默认为全灭)
int ge,shi,bai,qian;
int shu = 0;
//灯模式
void mod1(){//左往右
count=0;
P2=0x80;
P0=a;
a=_crol_(a,1);
}
void mod2(){//右往左
count=0;
P2=0x80;
P0=b;
b=_cror_(b,1);
}
void mod3(){//两边往中间走
count=0;
P2=0x80;
P0=t[j];
j++;
if(j == 4){
j = 0;
}
}
void mod4(){//中间往两边走
count=0;
P2=0x80;
P0=t[i];
i--;
if(i < 0){
i = 3;
}
}
void main(){
P2=0xa0;P0=0x00;//关闭蜂鸣器
P2 = 0xc0;//刚开始关闭数码管
P0 = 0x00;
P2 = 0xe0;
P0 = 0xff;
P2 = 0x80;P0 = 0xff;//刚开始关闭灯
TMOD=0x10;
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
EA=1;//总中断
ET1=1;//中断原的中断允许位
TR1=0;//启动定时器(默认为停止)
while(1){
if(s7==0){//启动或者停止流水灯流转
Delay10ms();//消除抖动
if(s7==0){
count = 0;
if(stop_start == 0){//如果为暂停状态,则让其开始
stop_start = 1;
TR1=1;
while(s7==0){TR1=1;};//判断是否松开
TR1=1;
}else{
stop_start = 0;
TR1=0;
while(s7==0){TR1=0;};//判断是否松开
TR1=0;
}
}
}
if(s6==0){//可切换选择"运行模式",或者"流转间隔"
Delay10ms();//消除抖动
if(s6==0){
count = 0;
if(run_time == 1){
run_time = 2;
while(s6==0){};//判断是否松开
}else if(run_time == 2){
run_time = 3;
while(s6==0){};//判断是否松开
}else{//关闭所以数码管
run_time = 1;
while(s6==0){};//判断是否松开
}
}
}
//s5,s4在运行模式或者流转间隔模式下才其作用
if(run_time == 1 || run_time == 2){
if(s5==0){//加键,在运行模式时模式加一,但是不能超过,在流转间隔时时间加100ms,最多到1200
Delay10ms();//消除抖动
if(s5==0){
count = 0;
if(run_time == 1){
if(mod < 4){//判断是否到边界
mod++;
}
}
else if(run_time == 2){
if(sum < 24){//判断是否到边界
sum += 2;
}
}
while(s5==0){};//判断是否松开
}
}
if(s4==0){//减,在运行模式时模式减一,但是不能为0,在流转间隔时时间减100,最少到400
Delay10ms();//消除抖动
if(s4==0){
count = 0;
if(run_time == 1){
if(mod > 1){//判断是否到边界
mod--;
}
}
if(run_time == 2){
if(sum > 8){//判断是否到边界
sum -= 2;
}
}
while(s4==0){};//判断是否松开
}
}
}
//显示灯
switch(mod){
case 1:
if(count == sum){
mod1();
}
break;
case 2:
if(count == sum){
mod2();
}
break;
case 3:
if(count == sum){
mod3();
}
break;
case 4:
if(count == sum){
mod4();
}
break;
}
//显示数码管
if(run_time == 3){
P2 = 0xc0;
P0 = 0x00;
P2 = 0xe0;
P0 = 0xff;
}else{
if(run_time == 1){//运行模式1
shu = sum*50;//计算毫秒
qian = shu/1000;
bai = shu%1000/100;
shi = shu%100/10;
ge = shu%10;
//显示模式
P2 = 0x00;P0 = 0x00;//消隐
P2 = 0xc0;P0 = 0x02;
P2 = 0x00;P0 = 0xff;//消隐
P2 = 0xe0;P0 = duan[1];
Delay1ms();
//显示两个横杠
P2 = 0x00;P0 = 0x00;//消隐
P2 = 0xc0;P0 = 0x01;
P2 = 0x00;P0 = 0xff;//消隐
P2 = 0xe0;P0 = 0xbf;
Delay1ms();
P2 = 0x00;P0 = 0x00;//消隐
P2 = 0xc0;P0 = 0x04;
P2 = 0x00;P0 = 0xff;//消隐
P2 = 0xe0;P0 = 0xbf;
Delay1ms();
//显示数字
P2 = 0x00;P0 = 0x00;//消隐
P2 = 0xc0;P0 = 0x10;
P2 = 0x00;P0 = 0xff;//消隐
P2 = 0xe0;P0 = duan[qian];
Delay1ms();
P2 = 0x00;P0 = 0x00;//消隐
P2 = 0xc0;P0 = 0x20;
P2 = 0x00;P0 = 0xff;//消隐
P2 = 0xe0;P0 = duan[bai];
Delay1ms();
P2 = 0x00;P0 = 0x00;//消隐
P2 = 0xc0;P0 = 0x40;
P2 = 0x00;P0 = 0xff;//消隐
P2 = 0xe0;P0 = duan[shi];
Delay1ms();
P2 = 0x00;P0 = 0x00;//消隐
P2 = 0xc0;P0 = 0x80;
P2 = 0x00;P0 = 0xff;//消隐
P2 = 0xe0;P0 = duan[ge];
Delay1ms();
}else if(run_time == 2){//运行模式2
shu = sum*50;//计算毫秒
qian = shu/1000;
bai = shu%1000/100;
shi = shu%100/10;
ge = shu%10;
//显示模式
P2 = 0x00;P0 = 0x00;//消隐
P2 = 0xc0;P0 = 0x02;
P2 = 0x00;P0 = 0xff;//消隐
P2 = 0xe0;P0 = duan[2];
Delay1ms();
P2 = 0x00;P0 = 0x00;//消隐
P2 = 0xc0;P0 = 0x10;
P2 = 0x00;P0 = 0xff;//消隐
P2 = 0xe0;P0 = duan[qian];
Delay1ms();
//显示两个横杠
P2 = 0x00;P0 = 0x00;//消隐
P2 = 0xc0;P0 = 0x01;
P2 = 0x00;P0 = 0xff;//消隐
P2 = 0xe0;P0 = 0xbf;
Delay1ms();
P2 = 0x00;P0 = 0x00;//消隐
P2 = 0xc0;P0 = 0x04;
P2 = 0x00;P0 = 0xff;//消隐
P2 = 0xe0;P0 = 0xbf;
Delay1ms();
//显示数字
P2 = 0x00;P0 = 0x00;//消隐
P2 = 0xc0;P0 = 0x20;
P2 = 0x00;P0 = 0xff;//消隐
P2 = 0xe0;P0 = duan[bai];
Delay1ms();
P2 = 0x00;P0 = 0x00;//消隐
P2 = 0xc0;P0 = 0x40;
P2 = 0x00;P0 = 0xff;//消隐
P2 = 0xe0;P0 = duan[shi];
Delay1ms();
P2 = 0x00;P0 = 0x00;//消隐
P2 = 0xc0;P0 = 0x80;
P2 = 0x00;P0 = 0xff;//消隐
P2 = 0xe0;P0 = duan[ge];
Delay1ms();
}
}
}
}
void time0() interrupt 3{
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
count++;//记录中断次数
}
效果图
模式1(可以调整跳转模式):
模式2(可以调整跳转速度):
总结以及遇到的问题
仿真时,当我们通过按键来对流水灯进行控制,按下按键时,有时候流水会卡住,再按下其他按键,流水灯没有反应,有时候直接出现按键失灵的情况(该问题在仿真时会出现,在使用开发板时不知道会不会出现)。解决问题办法:每当按下任何一个按键时,都让用于中断计数的变量从新0开始计数,便能解决所遇到的问题。
存在的问题:每次调整模式或者调整速度时,会停顿一下,该问题暂时未解决,还请大家多多指教。出现原因:每当按下任何一个按键时,都让用于中断计数的变量从新0开始计数(如果在开发板上,不会出现卡住或者按键失灵问题,则不存在该问题)
本次实验由于疫情原因,只能在家里面使用仿真来做,因为仿真时会出现一些问题。使用开发板可能不会出现上述的问题。