#include <absacc.h rel='nofollow' onclick='return false;'>
#include <reg51.h>
/*////////////////////////////*/
/*/ 常量定义 /*/
/*////////////////////////////*/
/* 定时器初值 */
#define count1_H 0xf4 /* ~ 300Hz , ! notice: crystal 11.0592MHz */
#define count1_L 0x00
/* 数码管段驱动寄存器地址 */
#define ADDR_8SEG XBYTE[0x2000]
/* 数码管位驱动和指示灯驱动寄存器地址 */
#define ADDR_SEL XBYTE[0x4000]
/* 按键 */
sbit KEY1= P1^0;
sbit KEY2= P1^1;
sbit KEY3= P1^2;
sbit KEY4= P1^3;
sbit OUT1= P3^2;
sbit OUT2= P3^3;
/*////////////////////////////*/
/*/ 变量定义 /*/
/*////////////////////////////*/
/* 定时器初值 */
unsigned char count0_high_H;
unsigned char count0_high_L;
unsigned char count0_low_H;
unsigned char count0_low_L;
/* 消抖基础频率计数器 */
unsigned int count_100Hz;
/* 消抖溢出标志 */
bit flag_100Hz;
/* 按键按下标志 */
bit key_down;
/* 按键按下确认标志 */
bit key_pushed;
/* 按键按下存储器 */
unsigned char first_key_pushed;
/* 按键按下确认存储器 */
unsigned char second_key_pushed;
/* 按键重复计数器 */
unsigned int count_2Hz;
/* 数码管扫描驱动指针,为测试外部存储器(U3 6264),特使用xdata类型 */
unsigned char xdata digi_scaner;
/* 数码管位驱动和指示灯驱动信号输出缓存,定义了一个可位寻址的变量 */
unsigned char bdata output_sel;
sbit led_1 = output_sel^5;
sbit led_2 = output_sel^6;
sbit led_3 = output_sel^7;
sbit led_4 = output_sel^4;
/* 输出电压 */
unsigned char Vo;
/* 输出电压,十进制显示 */
unsigned char digi[2];
/* 当前的占空比 */
unsigned char pulse_width;
/* 系统工作状态 */
/* 0-输出;1-第一位输入;2-第二位输入 */
unsigned char system_type;
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
/*////////////////////////////*/
/*/ 函数定义 /*/
/*////////////////////////////*/
/**** 7段数码显示译码
参数:
DATA: 需要显示的数字或符号;
返回值: 7段译码结果 ( D7~0 = PGFEDCBA )
*****/
unsigned char NUMTOSEG7(unsigned char DATA)
{ unsigned char AA;
switch (DATA)
{ case 0: AA=0xc0;break; /* ‘0’*/
case 1: AA=0xf9;break; /* ‘1’*/
case 2: AA=0xa4;break; /* ‘2’*/
case 3: AA=0xb0;break; /* ‘3’*/
case 4: AA=0x99;break; /* ‘4’*/
case 5: AA=0x92;break; /* ‘5’*/
case 6: AA=0x82;break; /* ‘6’*/
case 7: AA=0xf8;break; /* ‘7’*/
case 8: AA=0x80;break; /* ‘8’*/
case 9: AA=0x90;break; /* ‘9’*/
case 10: AA=0x88;break; /* ‘A’*/
case 11: AA=0x83;break; /* ‘B’*/
case 12: AA=0xc6;break; /* ‘C’*/
case 13: AA=0xa1;break; /* ‘D’*/
case 14: AA=0x86;break; /* ‘E’*/
case 15: AA=0x8e;break; /* ‘F’*/
case '-':AA=0xbf;break; /* 破折号 */
case '_':AA=0xf7;break; /* 下划线 */
case ' ':AA=0xff;break; /* 消隐 */
case '.':AA=0x7f;break; /* 小数点 */
default: AA=0xff;
}
return(AA);
}
/**** T0时钟中断服务程序*****/
/**** 提供矩形波基础频率、占空比调整*****/
time0()interrupt 1 using 0
{
/* 本中断优先级最高,因此采用关中断 */
EA = 0;
if(OUT1 == 1)
{
/* 重新对计数器赋初值(低电平持续周期),并启动定时计数 */
TH0 = count0_low_H;
TL0 = count0_low_L;
TR0 = 1;
OUT1 = 0;
}else if(OUT1 == 0)
{
/* 重新对计数器赋初值(高电平持续周期),并启动定时计数 */
TH0 = count0_high_H;
TL0 = count0_high_L;
TR0 = 1;
OUT1 = 1;\
}
/* 开中断 */
EA = 1;
}
/**** T1时钟中断服务程序*****/
/**** 提供矩形波基础频率、占空比调整、数码管刷新和输入消抖频率 ****/
timer1() interrupt 3 using 1
{
ET1=0; /*定时器1关中断*/
/* 重新对计数器赋初值,并启动定时计数 */
TH1 = count1_H;
TL1 = count1_L;
TR1 = 1;
count_100Hz++;
if(count_100Hz >= 6) /*消抖抽样频率为50Hz */
{
flag_100Hz = 1;
count_100Hz = 0;
}
/* 检测到按键被按下(0)时,相应的指示灯亮(0) */
if (KEY1==0) led_1 = 0;
if (KEY2==0) led_2 = 0;
if (KEY3==0) led_3 = 0;
if (KEY4==0) led_4 = 0;
/*扫描数码管,每个管扫描频率约为60Hz*/
if (++digi_scaner>=6) digi_scaner = 1;
switch (digi_scaner)
{
case 1: /* 驱动第一个数码管 */
output_sel |= 0x01;
ADDR_8SEG = NUMTOSEG7(system_type); /*输出到锁存器U5*/
break;
case 2: /* 驱动第二个数码管 */
output_sel |= 0x02;
ADDR_8SEG = NUMTOSEG7('-'); /*输出到锁存器U5*/
break;
case 3: /* 驱动第三个数码管 */
output_sel |= 0x04;
ADDR_8SEG = NUMTOSEG7(digi[1]); /*输出到锁存器U5*/
break;
case 4: /* 第三个数码管显示小数点 */
if(Vo < 100) /* 输出10V时不现显示小数点 */
{
output_sel |= 0x04;
ADDR_8SEG = NUMTOSEG7('.'); /*输出到锁存器U5*/
}
break;
case 5: /* 驱动第四个数码管 */
output_sel |= 0x08;
ADDR_8SEG = NUMTOSEG7(digi[0]); /*输出到锁存器U5*/
break;
}
ADDR_SEL = output_sel; /*输出到锁存器U6(在电路图中找)*/
ET1=1; /*定时器1开中断*/
}
/* 数字显示 */
void display(unsigned int num)
{
if(num == 0) /* 显示消隐 */
{
digi[1] = ' ';
digi[0] = ' ';
}else
{
if(num < 100)
{
digi[1] = num / 10;
digi[0] = num % 10;
}else
{
digi[1] = num / 100;
digi[0] = num % 100 % 10;
}
}
}
/* 输入输出函数关系 */
void translate(void)
{
unsigned char temp;
unsigned int x_hi;
unsigned int x_low;
/* 占空比与输出电压的关系 */
pulse_width = Vo;
/* 计数器0的初值与占空比的关系 */
temp = 0x0300 * pulse_width / 0x0019; //高电平的计数次数
x_hi = 0xffff - temp + 1; //高电平计数初值
x_low = 0xffff - (0x0c00 - temp) + 1; //低电平技术初值
count0_high_H = x_hi / 0x0100;
count0_high_L = x_hi - count0_high_H * 0x0100;
count0_low_H = x_low / 0x0100;
count0_low_L = x_low - count0_low_H * 0x0100;
}
/* 按键消抖 */
unsigned int keyDown(void)
{
if(count_100Hz) //到达抽样点
{
count_100Hz = 0;
if(!key_down) //没有按键被按下时
{
first_key_pushed = 0; //按键按下存储器清零
/* 扫描按键看是否有被按下 */
if(KEY1) first_key_pushed = 1;
if(KEY2) first_key_pushed = 2;
if(KEY3) first_key_pushed = 3;
if(KEY4) first_key_pushed = 4;
if(first_key_pushed) key_down = 1;
}else //有按键被按下时
{
second_key_pushed = 0; //按键按下确认存储器清零
/* 重新扫描按键看是否有被按下 */
if(KEY1) second_key_pushed = 1;
if(KEY2) second_key_pushed = 2;
if(KEY3) second_key_pushed = 3;
if(KEY4) second_key_pushed = 4;
if(first_key_pushed == second_key_pushed) key_pushed = 1; //两次扫描结果相同,确认按键被按下
else //两次扫描结果不同,为按键抖动或者按键松开(松开时没有消抖,第一次检测到0就为松开)
{
key_down = 0;
key_pushed = 0;
}
}
/* 没有案按键被按下,按键重复计数器清零(为保证第一次按下响应迅速,清零值为8) */
if(!key_pushed)count_2Hz = 8;
else count_2Hz++;
/* 按键重复计数器溢出,函数返回当前有效按键代码 */
if(count_2Hz >= 9)
{
count_2Hz = 0;
return second_key_pushed;
}
}
return 0; //没有按键被确认按下时返回 0
}
/* 按键处理 */
void keyProcess(void)
{
unsigned int key;
key = keyDown();
switch(key)
{
case 1: //按键1(系统状态改变)
if(system_type > 0 && system_type < 3) //系统在输入状态,转为输出状态
{
system_type = 0;
translate();
}
else system_type = 1; //系统在输出状态,转为输入状态
break;
case 2: //按键2(输出上升)
if(system_type == 1) //系统在第一位输入状态
{
if(Vo <= 90)Vo += 10;
}
if(system_type == 2) //系统在第二位输入状态
{
if(Vo <= 99)Vo += 1;
}
display(Vo);
break;
case 3: //按键3(输出下降)
if(system_type == 1) //系统在第一位输入状态
{
if(Vo >= 10)Vo -= 10;
}
if(system_type == 2) //系统在第二位输入状态
{
if(Vo >= 1)Vo -= 1;
}
display(Vo);
break;
case 4: //按键4(第一位输入和第二位输入的切换)
if(system_type == 1)system_type = 2;
else if(system_type == 2)system_type = 1;
break;
default:br