#include "at89x52.h"
#include <math.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
uchar code acLEDCS[]={0x0e,0x0d,0x0b,0x07}; /* 位选地址码,“0”有效,位选接的是P2口高4位 */
uchar code acLedSegCode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c};/* 段码 */
uchar acLED[4]; /* 显示缓冲区 */
char cScanIndex; /* 位选指针0~3 */
uchar cKeyCode; /* 键值 */
uint nDelayKey; /* 键盘延时变量,为定时中断间隔时间的整数倍 */
uchar cKeySec; /* 按键长按几秒 */
bit bPush; /* 是否按键标志 */
char cMode; /* 显示方式变量,0~3对应4种方式 */
/* 联合变量(大名2字节,小名2*1字节保存在同一物理空间),可用于定时器初值计算,控制中断周期 */
union UniT
{
uint T;
uchar t[2];
}idata uT;
uchar freq = 50, num=0;
uchar idata dat[128];
uchar i = 0;
/************************* 数码管显示函数 ***************************/
void display()
{
if(cMode == 0)
acLED[0] = 0x01; /* LED显示第1位 */
else if(cMode == 1)
acLED[0] = 0x03; /* LED显示第1位 */
else if(cMode == 2)
acLED[0] = 0x07; /* LED显示第1位 */
else if(cMode == 3)
acLED[0] = 0x0f; /* LED显示第1位 */
acLED[1] = 0x40;/* LED显示第2位 */
acLED[2] = acLedSegCode[freq/10%10]; /* LED显示第3位 */
acLED[3] = acLedSegCode[freq%10]; /* LED显示第4位 */
}
/******************** 按键处理程序 ******************/
void DisposeKEY()
{
switch(cKeyCode)
{
case 6: /* 例如:KeyADD */
if(freq <= 99)
freq++;
break;
case 5: /* 例如:KeySUB */
if(freq)
freq--;
break;
case 3: /* 例如:KeyMode */
if(bPush==0)
{
cMode++;
cMode %= 4; /* 假设有4种显示状态 */
bPush = 1; /* 如果没松键就不会再改变显示方式 */
}
break;
}
if(cMode == 0)
{
for(i = 0; i < 64; i++)
{
dat[i]=255;
dat[i+64]=0;
}
}
else if(cMode == 1)
{
for(i=0;i<128;i++)
{
dat[i]=i*2;
}
}
else if(cMode == 2)
{
for(i=0;i<64;i++)
{
dat[i]=i*4;
dat[i+64]=255-dat[i];
}
}
else if(cMode == 3)
{
for(i=0;i<128;i++)
{
dat[i]=127*sin(3.14159265359*i/64)+128;
}
}
display();
cKeyCode = 0;
uT.T=12-22118400/12/freq/128;
TL0=uT.t[1];
TH0=uT.t[0];
}
/************************** 主函数 *****************************/
void main(void)
{
/**************** 定时器初始化 *******************/
TMOD= 0x11;
TH1 = -18; /* 16位定时器,晶振22.1184M,22118400/12/256 = 7200 = 18*400 每秒钟溢出400次,每2.5ms中断一次*/
TR1 = 1;
ET1 = 1;
TR0 = 1;
ET0 = 1;
EA = 1; /* 开总中断 */
uT.T=25-22118400/12/freq/128;
TL0=uT.t[1];
TH0=uT.t[0];
for(i = 0; i < 64; i++)
{
dat[i]=255;
dat[i+64]=0;
}
display(); /* 显示初始界面 */
while(1)
{
if(cKeyCode)
{
DisposeKEY(); /* 响应按键操作 */
}
}
}
/****************** 多任务时序控制时钟中断 *********************/
void IntTimer() interrupt 3
{
TH1 = -18; /* 重装初值,保证每2.5ms中断一次*/
P0 = 0; // 清段选再送位选(消影)
P2_4 = 0;
/*********************** 定时扫描独立按键 ************************/
if((P2 & 0x07) != 0x07) // 判断是否有按键动作,P22、P21、P20没有按键时为高电平(逻辑1)
{
nDelayKey++;
if((nDelayKey == 4 || nDelayKey % 128 == 0) && bPush == 0) // 延时削颤10ms,每160ms连加连减
{
cKeyCode = P2 & 0x07;// 取键值P20、P21、P22
}
if(nDelayKey % 400 == 0)
{ cKeySec++;
}
}
/***********************************************/
else // 松键,清按键相关变量
{
nDelayKey = 0;
cKeyCode = 0;
cKeySec = 0;
bPush = 0;
P2_4 = 1;
}
//*************************显示刷新******************
P2 = acLEDCS[cScanIndex]|0x10; /* 送位选数据 */
P0 = acLED[cScanIndex++]; /* 送显示数据,位选指针移位 */
cScanIndex &= 3; /* 位选指针回位 */
}
void IntTimer0() interrupt 1
{
TR0=0;
TL0=uT.t[1];
TH0=uT.t[0];
TR0=1;
P1=dat[num];
num++;
num&=127;
}