练习内容:
示例代码:
/*头文件声明区*/
#include <STC15F2K60S2.H>
#include <stdio.h>
#include <intrins.h>
/*变量声明区*/
unsigned char flag = 0;//要求2LED流水灯按键标志位
unsigned char flag1 = 0;//赋值为2数码管正计时,赋值为3数码管倒计时,赋值为4按键每按下一次加一0-9的循环
unsigned char count = 0;
int k1=0;
code unsigned char Seg_Table[] = {0xc0,0xf9,0xa4, 0xb0,0x99,0x92,0x82, 0xf8,0x80,0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e };//共阳数码管段码表,这个code是把这个数据存放在另一个区,可以存放较大的数据
/*延时函数*/
void Delay500ms() //@11.0592MHz,延时500ms
{
unsigned char i, j, k;
// _nop_();//这个复制过来的函数需要加相应的头文件,这里用不到可以删掉,不然会报错
// _nop_();
i = 22;
j = 3;
k = 227;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay10ms() //@11.0592MHz,延时10ms
{
unsigned char i, j;
i = 108;
j = 145;
do
{
while (--j);
} while (--i);
}
void Delay2ms() //@11.0592MHz,延时2ms
{
unsigned char i, j;
_nop_();
_nop_();
i = 22;
j = 128;
do
{
while (--j);
} while (--i);
}
void Latch(unsigned char Yn,unsigned char value)//锁存器函数,使用锁存器可以调用这个函数
{
if(Yn < 4 || Yn > 7)//判断锁存器是否合法,这里实际只用到了Y4—Y7
{
return;//关闭所以不返回值
}
P0 = value;
P2 = P2 & 0x1f |(Yn << 5);//打开锁存器7,想打开哪一个锁存器就修改到对应的值
P2 = P2 & 0x1f;
}
void SEG(unsigned char wei,unsigned char duan)//数码管显示函数
{
Latch(7,Seg_Table[duan]);
Latch(6,0x01<< (wei - 1));
Delay2ms();
}
void Timer0()//定时器
{
AUXR &= 0x7f;//12T模式
TMOD &= 0xf0;//16位自动重装载模式
TH0 = (65536-46083) / 255;//计时50ms
TL0 = (65536-46083) % 255;
TF0 = 0;
TR0 = 1;
EA = 1;
ET0 = 1;
}
void LED_dalay1()//实现流水灯两种方式循环
{
int i;
P0 = 0x10;
P2 = P2 & 0x1f | 0x80;//打开锁存器
//0000 0001 << 1 = 0000 0010
for(i=0;i<8;i++)
{
if(flag == 0)
{
P0 = ~(0x01 << i);//每次循环亮一个灯
Delay500ms();
}
if(flag == 1)
{
P0 = (0x01 << i);//每次循环灭一个灯
Delay500ms();
}
}
}
void LED_dalay2()//LED闪烁的两种方式,可以注释掉另一种方式进行使用
{
int i;
P0 = 0x10;
P2 = P2 & 0x1f | 0x80;//打开锁存器
//0000 0001 << 1 = 0000 0010
for(i=0;i<8;i++)
{
//0101 0101奇数亮
P0 =0x55;
Delay500ms();
// //1010 1010偶数亮
// P0 =0xaa;
// Delay500ms();
}
}
void scan()//按键控制函数
{
if(P33 == 0)
{
Delay10ms();
if(P33 == 0)//确定按下S4按键
{
flag = 0;
}
}
if(P32 == 0)
{
Delay10ms();
if(P32 == 0)//确定按下S5按键
{
flag = 1;
flag1 = 4;//要求4按键标志位
k1=k1+1;
if(k1>9)k1=0;
SEG(1,k1);
Delay500ms();
}
}
if(P31 == 0)
{
Delay10ms();
if(P31 == 0)//确定按下S6按键
{
//SEG(1,2);
flag1 = 2;//数码管正计时
}
}
if(P30 == 0)
{
Delay10ms();
if(P30 == 0)//确定按下S7按键
{
//SEG(1,9);
flag1 = 3;//数码管倒计时
}
}
}
void Timer_server() interrupt 1//定时器中断服务函数
{
count++;
if(count == 20)//计时1s
{
count = 0;
}
}
void main()
{
// //1111 1110
// //P0 = 0xfe;
// //P27 = 1;P26 = 0;P25 = 0;
// P0 = 0x10;//0001 0000 低电平点亮,灯呈现的状态
// //X & 0 = 1;
// //X | 1 = 1;与0为0,或1为1
// //0001 1111 0x1f
// //1000 0000 0x80
// P2 = P2 & 0x1f | 0x80;
Latch(5,P0 & ~(5 << 4));//拉低P06和P04关闭,蜂鸣器和L10提示灯关闭
Timer0();
while(1)
{
scan();
// //LED_dalay2();
// //LED_dalay1();
if(flag1 == 2)
{
int k;
Delay500ms();
for(k=0;k<10;k++)
{
SEG(1,k);
Delay500ms();
}
}
if(flag1 == 4)
{
// int k;//这部分放在这里实际会一直循环显示达不到效果,放到按键控制函数
// k=k+1;
// SEG(1,k);
// Delay500ms();
}
if(flag1 == 3)
{
int k;
for(k=9;k>=0;k--)
{
SEG(1,k);
Delay500ms();
}
}
}
}
问题记录:
问题1:
问题2:
这个else会抢占运行,从而使后面运行的代码出现逻辑问题,每次显示5之后才开始9-0的循环倒计时,实际不应该出现这个5,与预期显示9-0的倒计时效果不一致。
问题3:
k1=k1+1;
if(k1>9) k1=0;
正确的使用判断为:先+,后判断;就可以实现k1大于9之后就等于0的循环;显示的数码管断码就为0。
if(k1>9) k1=0;
k1=k1+1;
先判断,后+;就会一直加到>9则为10->显示A;才会触发k1=0,按下+1显示1一直循环。这样会出现判断有误,此处错误的现象为0的显示为A,实际想要呈现的效果为按下每次加一0-9的循环。
关于这个定时器的使用:
结合这些资料可以看出定时器的代码编写,以及这个定时器初值计算为什么是减去46083这个值。也可以用STC软件直接生成c代码使用,这里简略介绍一下使用方法。