#include
/******************************************************************
* 自界说Macro
*******************************************************************/
//编码的均为反向编码
#define CLEAR 0x7f //界说清空的反码
#define LED_BEGIN 0x01 // 界说开端时数码管的显现
#define LED_FOUL 0x38 // 犯规后显现字母”F”,数码管编码
#define LED_C 0x31 // 字母”C”的编码
#define LED_L 0x71 // 字母”L”的编码,两个用来在主持人撤销之后显现”CL”–cancel
#define GET 1 // 这个是作为一个函数的参数来混的,便是成功抢答的意思
#define FOUL 0 // 和上面的参数一同混的,犯规—这两个的用法在后边表现
#define READY 0x7e
/******************************************************************
* 自界说数据类型
*******************************************************************/
typedef unsigned char Byte; // 一个字节
typedef unsigned int Word; // 一个字,两个字节
typedef bit Bool; // 仿照布尔型变量
//typedef sbit Port; // 本想用自界说一个端口类型的变量,比较便利,可是这句话步知道为何通不过编译
/******************************************************************
* 界说MAX7219寄存器
*******************************************************************/
#define REG_NO_OP 0x00 // 界说空操作 register
#define DIG_1 0x01 // 界说数码管1 register
#define DIG_2 0x02 // 界说数码管2 register
#define DIG_3 0x03 // 界说数码管3 register
#define DIG_4 0x04 // 界说数码管4 register
#define DIG_5 0x05 // 界说数码管5 register
#define DIG_6 0x06 // 界说数码管6 register
#define DIG_7 0x07 // 界说数码管7 register
#define DIG_8 0x08 // 界说数码管8 register
#define REG_DECODE 0x09 // 界说解码操控 register
#define REG_INTENSITY 0x0a // 界说显现亮度 register
#define REG_SCAN_LIMIT 0x0b // 界说扫描约束 register
#define REG_SHUTDOWN 0x0c // 界说”shutdown”形式 register
#define REG_DISPLAY_TEST 0x0f // 界说”display test”形式 register
#define INTENSITY_MIN 0x00 // 界说最低显现亮度
#define INTENSITY_MAX 0x0f // 界说最高显现亮度
/*********************************************************************
* 界说硬件引脚衔接
**********************************************************************/
sbit DA
sbit LOAD=P2^1; // MAX7219的锁存端口
sbit CLK=P2^2; // MAX7219的时钟端口
//sbit HOST_SWITCH=P0^0; // 主持人开关的接口
sbit HOST_START=P0^0; //主持人按键,用来从头开端的按键 start
sbit HOST_CANCEL=P0^1; //主持人用来撤销抢答的按键 clear
sbit SWITCH1_3=P1^4; // 调理倒计时时刻的拨码开关,下划线前面的号代表开关的序号,下划线后边的号代表该开关的数值
sbit SWITCH2_2=P1^5; // 同上
sbit SWITCH3_2=P1^6; // 同上
sbit SWITCH4_1=P1^7; // 同上
sbit BEEP=P0^7; //界说蜂鸣器端口
sbit LS138_C=P2^4; //界说译码器输入端
sbit LS138_B=P2^5; //同上
sbit LS138_A=P2^6; //同上
sbit LS138_E1=P2^7; //界说译码器使能端
/*********************************************************************
* 界说全局变量
**********************************************************************/
Byte da
Byte da
Byte da
Byte da
Bool da
Bool da
Bool da
Byte da
co
/***********************************************************************
* 共阴极七段数码管显现对应段查询表(数字0-9别离对应co
***********************************************************************/
Byte co
{0x7e,0x30,0x6d,0x79,0x33,0x5b,0x5f,0x70,0x7f,0x7b};
Byte co
{0x01,0x4f,0x12,0x06,0x4c,0x24,0x20,0x0f,0x00,0x04};
/***********************************************************************
* 函数声明
***********************************************************************/
void MAX7219_SendByte (Byte dataout);
void MAX7219_Write (Byte reg_number, Byte dataout);
void MAX7219_DisplayChar(Byte digit, Byte character);
void MAX7219_Clear (void);
void MAX7219_SetBrightness (Byte brightness);
void MAX7219_DisplayTestStart (void);
void MAX7219_DisplayTestStop (void);
void MAX7219_ShutdownStart (void);
void MAX7219_ShutdownStop (void);
void MAX7219_Init (void);
void Delay10ms(void);
Bool GetHostStartKey (void);
Bool GetHostCancelKey (void);
void GetCounter(void);
Byte GetPressed(Byte KeyState);
void IT0_Init(void);
void Timer0_Overflow();
void PressedHandle(Byte keyPressed);
void GetOrFoulHandle(Bool state);
void CancelHandle();
void SPEAKER_count (void); //声明倒计时声响函数
void SPEAKER_start(void); //声明开端抢答声响函数
void SPEAKER_get(void); //声明抢到声响函数
void SPEAKER_foul(void); // 声明犯规声响函数
/***********************************************************************
* MAX7219_SendByte()
*
* 描绘: 向MAX7219传送一个字节的数据
* Arguments : dataout = da
* Returns : none
*************************************************************************/
void MAX7219_SendByte (Byte dataout)
{
Byte i;
for (i=8;i>0;i–)
{
Byte mask=1<<(i-1);//mask是个掩码,取位运用
CLK=0;//MAX7219的位传入是在时钟的上升沿之前,所以在每发一位之前都要变为低电平
if (dataout&mask)
DA
else
DA
CLK=1;//八个bit都传递完成后变为高电平,锁存
}
}
/***********************************************************************
* MAX7219_Write()
*
* 描绘: 向 MAX7219 写指令
* Arguments : reg_number = register to write to
* dataout = da
* Returns : none
未完~
***************************************************************************/
void MAX7219_Write (Byte reg_number, Byte dataout)
{
LOAD=0;//也是锁存上升沿之前的,发这两个字节之前要变为低电平
MAX7219_SendByte(reg_number);//发送寄存器地址
MAX7219_SendByte(dataout);//发送数据
LOAD=1;//变为高电平,锁存
}
/**************************************************************************
* MAX7219_DisplayChar()
*
* 描绘: 使某一位显现一个数字
* Arguments : digit = digit number (0-7)
* character = character to display (0-9, A-Z)
* Returns : none
**************************************************************************/
void MAX7219_DisplayChar(Byte digit, Byte character)
{
MAX7219_Write(digit, character);
}
/**************************************************************************
* MAX7219_Clear()
*
* 描绘: 铲除一切位的显现
* Arguments : none
* Returns : none
***************************************************************************/
void MAX7219_Clear (void)
{
Byte i;
for (i=1; i<=2; i++)
MAX7219_Write(i, CLEAR);//把八个数码管全都清零了,现已写反了^_^
}
/**************************************************************************
* MAX7219_SetBrightness()
*
* 描绘: 设置数码管显现亮度
* Arguments : brightness (0-15)
* Returns : none
***************************************************************************/
void MAX7219_SetBrightness (Byte brightness)
{
brightness &= 0x0f;
MAX7219_Write(REG_INTENSITY, brightness);
}
/**************************************************************************
* MAX7219_DisplayTestStart()
*
* 描绘: 进入 test 形式
* Arguments : none
* Returns : none
***************************************************************************/
void MAX7219_DisplayTestStart (void)
{
MAX7219_Write(REG_DISPLAY_TEST, 1);
}
/**************************************************************************
* MAX7219_DisplayTestStop()
*
* 描绘: 退出 test 形式
* Arguments : none
* Returns : none
***************************************************************************/
void MAX7219_DisplayTestStop (void)
{
MAX7219_Write(REG_DISPLAY_TEST, 0);
}
/**************************************************************************
* MAX7219_ShutdownStart()
*
* 描绘: 进入 shutdown 形式
* Arguments : none
* Returns : none
***************************************************************************/
void MAX7219_ShutdownStart (void)
{
MAX7219_Write(REG_SHUTDOWN, 0);
}
/**************************************************************************
* MAX7219_ShutdownStop()
*
* 描绘: 退出 shutdown 形式
* Arguments : none
* Returns : none
***************************************************************************/
void MAX7219_ShutdownStop (void)
{
MAX7219_Write(REG_SHUTDOWN, 1);
}
/**************************************************************************
* MAX7219_Init()
*
* Description: MAX7219初始化模块; 应该先于其他MAX7219函数而被调用
* Arguments : none
* Returns : none
***************************************************************************/
void MAX7219_Init (void)
{
DA
CLK=1;
LOAD=1;
MAX7219_Write(REG_SCAN_LIMIT,1);//这儿设置的是扫描两个数码管
MAX7219_Write(REG_DECODE, 0x00);
MAX7219_SetBrightness(INTENSITY_MAX);//设置最大亮度显现
MAX7219_DisplayTestStart();
MAX7219_DisplayTestStop();
MAX7219_ShutdownStop();
MAX7219_Clear();
}
/**************************************************************************
* Delay_100us()
*
* 描绘: 延时100us,首要用在消除开关颤动时
* Arguments : none
* Returns : none
***************************************************************************/
void Delay10ms(void)
{
unsigned char i,j;
for(i=20;i>0;i–)
for(j=248;j>0;j–);
}
/**************************************************************************
* GetHostStartKey()
*
* Description: 获得主持人开端按键的键值
* Arguments : none
* Returns : 1–>主持人按键; 0–>主持人未按键
***************************************************************************/
Bool GetHostStartKey (void)
{
if (HOST_START ==1)
return 0;
else
Delay10ms ();//假如发现主持人按键接通,要先延时100us,避免颤动
if (HOST_START==1)
return 0;
else
return 1;//延时时分仍是接通,则判别为该键的确按下
}
/**************************************************************************
* GetHostCancelKey()
*
* Description: 获得主持人撤销按键的键值
* Arguments : none
* Returns : 1–>主持人按键; 0–>主持人未按键
***************************************************************************/
Bool GetHostCancelKey (void)
{
if (HOST_CANCEL ==1)
return 0;
else
Delay10ms ();//假如发现主持人按键接通,要先延时100us,避免颤动
if (HOST_CANCEL ==1)
return 0;
else
return 1;//延时时分仍是接通,则判别为该键的确按下
}
/**************************************************************************
* GetCounter
*
* Description: 获得预先设置的倒计时时刻
* Arguments : none
* Returns : none
***************************************************************************/
void GetCounter(void)
{
beginNum=1;//在一切开关都没有拨动的时分倒计时为1秒,比设置为0秒要好
intrCounter=20;//每一秒对应的中止次数为20次
if (SWITCH1_3==1)
{
beginNum+=3;
}
if (SWITCH2_2==1)
{
beginNum+=2;
}
if (SWITCH3_2==1)
{
beginNum+=2;
}
if (SWITCH4_1==1)
{
beginNum+=1;
}//以上判别句子为判别拨码开关状况
intrCounter=20*beginNum;//核算总扫描次数
}
/**************************************************************************
* GetPressed
*
* Description: 从P1口衔接抢答端的四位来判别抢答状况
* Arguments : Byte KeyState–>P1 state
* Returns : 抢答端的号码 ; 0–>没人抢答
***************************************************************************/
Byte GetPressed(Byte KeyState)
{
Byte key;//记载抢答端的号码
KeyState&=0x0f;//取P1口的低四位
switch (KeyState)
{
case 0x0f: key=0;break;//全高,无人抢答
case 0x0e: key=1;break;//只要P1.1,key1抢答
case 0x0d: key=2;break;//只要P1.2,key2抢答
case 0x0b: key=3;break;//只要P1.3,key3抢答
case 0x07: key=4;break;//只要P1.4,key4抢答
}
/*
switch (KeyState)
{
case 0x00: key=0;break;//全高,无人抢答
case 0x01: key=1;break;//只要P1.0,key1抢答
case 0x02: key=2;break;//只要P1.1,key2抢答
case 0x04: key=3;break;//只要P1.2,key3抢答
case 0x08: key=4;break;//只要P1.3,key4抢答
}
*/
//上面是在用高电平来判别抢答状况时的程序,经证明不知道为何无效
return key;
}
/**************************************************************************
* IT0_Init
*
* Description: 初始化计时器T0的状况
* Arguments : none
* Returns : none
***************************************************************************/
void IT0_Init(void)
{
TMOD=0x01;//设置T0在方法1下作业
TH0=0x3C;
TL0=0xAF;//这两个寄存器存的是计数器的计数开端的值,核算发现这两个值累加至溢出后正好是50ms
ET0=1;//使T0中止能够溢出
EA=1;//敞开总中止
TF0=0;//溢出位清零
TR0=1;//敞开T0
}
/**************************************************************************
* Timer0_Overflow() interrupt 1
*
* Description: 中止溢出服务程序, 选用的是中止方法1, 后边最好不加using挑选寄存器组以免与体系用在主程序的寄存器抵触
* Arguments : none
* Returns : none
***************************************************************************/
void Timer0_Overflow() interrupt 1
{
static Byte second=20;//用20次中止来判别1秒
TH0=0x3C;
TL0=0xAF;
second–;
intrCounter–;
/*
if (second==0)//每隔一秒的操作
{
MAX7219_DisplayChar(DIG_2,co
second=20;//从头赋值每秒计数器
if (intrCounter==0)
{
TR0=0;//封闭T0计数器
isStart=1;//计时完毕,进入正常抢答
//SPEAKER_start();//开端抢答的声响
}
//待显现”0″今后就开端抢答
else
{
//SPEAKER_count();//倒计时声响
}
}
*/
if (second==0)//每隔一秒的操作
{
//if (showNum!=1) SPEAKER_count();//倒计时声响
//else SPEAKER_start();//开端抢答的声响
MAX7219_DisplayChar(DIG_2,co
second=20;//从头赋值每秒计数器
}//待显现”0″今后就开端抢答
if (intrCounter==0)
{
TR0=0;//封闭T0计数器
isStart=1;//计时完毕,进入正常抢答
}
}
/**************************************************************************
* PressedHandle
*
* Description: 按键处理
* Arguments : Byte keyPressed–>按下的按键
* Returns : none
***************************************************************************/
void PressedHandle(Byte keyPressed)
{
MAX7219_Clear();//LED clear
MAX7219_DisplayChar(DIG_2,co
}
/**************************************************************************
* GetOrFoulHandle(Bool state)
*
* Description: 正常抢答或是犯规处理
* Arguments : Bool state–>是GET和FOUL两个宏的取之之一
* Returns : none
***************************************************************************/
void GetOrFoulHandle(Bool state)
{
if (!state)
{
MAX7219_DisplayChar(DIG_1,LED_FOUL);//假如是犯规的话左面的LED要显现”F”,foul
}
}
/**************************************************************************
* CancelHandle()
*
* Description: 处理主持人撤销倒计时
* Arguments : none
* Returns : none
***************************************************************************/
void CancelHandle()
{
MAX7219_DisplayChar(DIG_1,LED_C);
MAX7219_DisplayChar(DIG_2,LED_L);//主持人撤销倒计时之后,两个数码管显现”CL”–>cancel
}
/**************************************************************************
* delayus()
*
* Description: 延时程序
* Arguments : t–>us
* Returns : time delayed
***************************************************************************/
void delayus(unsigned char t )
{
unsigned char j;
for(;t>0;t–)
for(j=19;j>0;j–);
}
/**************************************************************************
* SPEAKER_count/start/foul/get()
*
* Description: speaker发声程序->计数/开端/犯规/抢答 四种声响
* Arguments : none
* Returns : none
***************************************************************************/
void SPEAKER_count(void)
{
unsigned char i;
for (i=0;i<10;i++)
{
BEEP =1; //点亮
delayus(20);
BEEP =0; //平息
delayus(20);
}
}
void SPEAKER_start(void)
{
unsigned char i;
for(i=0;i<200;i++)
{
BEEP =1; //点亮
delayus(10);
BEEP =0; //平息
delayus(10);
}
}
void SPEAKER_foul(void)
{
unsigned char i;
for(i=0;i<250;i++)
{
BEEP =1; //点亮
delayus(15);
BEEP =0; //平息
delayus(17);
}
}
void SPEAKER_get(void)
{
unsigned char i;
for(i=0;i<250;i++)
{
BEEP =1; //点亮
delayus(10);
BEEP =0; //平息
delayus(10);
}
for(i=0;i<250;i++)
{
BEEP =1; //点亮
delayus(20);
BEEP =0; //平息
delayus(20);
}
}
/**************************************************************************
* 主程序
***************************************************************************/
void main()
{
Byte keyPressed,i;//选手按键号码,没有的话为0
Bool hostPressed;//用来记载主持人按键撤销,0为没有动作,1为撤销
number_temp=P1&0xf0;//P1口前次的状况,在调整倒计时时刻的时分用到的
LS138_E1=1; //译码器初始化
MAX7219_Init();//数码管初始化
GetCounter();//获取开端时分设置的倒计时时刻
MAX7219_DisplayChar(DIG_1,co
MAX7219_DisplayChar(DIG_2,READY);//调时刻的时分右位的显现
//while(1);
while(GetHostStartKey()==0)//当主持人没有按键的时分进入循环
{
if (number_temp!=(P1&0xf0))//若调整了倒计时时刻,则P1口状况变了,就要从头设置和显现
{
GetCounter();//获取调整今后的倒计时时刻
MAX7219_DisplayChar(DIG_1,co
number_temp=P1&0xf0;//记载下来现在P1口的状况,以备后边的比较
}
} //当主持人按键今后就完毕调整进入抢答倒计时
MAX7219_DisplayChar(DIG_1,READY);
while(GetHostCancelKey()==0);
MAX7219_DisplayChar(DIG_1,READY);//清空右边一位数码管
MAX7219_DisplayChar(DIG_2,co
for (i=100;i–;i>0)
Delay10ms();//避免后边呈现连读的状况..
//调整好倒计时时刻后,按下start显现”–“,再按下cancel则显现倒计时时刻,此刻能够开端倒计时了.
counterBack=intrCounter;
//这儿原来写的是while(1),写上后就不行了,不知道为何..
while(1)//这儿要用自己加的循环来把程序捆绑在这儿运转
{
showNum=beginNum;//设置要显现的时刻,当然时从倒计时时刻开端
intrCounter=counterBack;//设置总中止的次数
TR0=0;//禁用计时器0
isPressed=0;//记载是否有人按键
isStart=0;//没有开端抢答
while(GetHostStartKey()==0);
IT0_Init();//初始化计时器0, 启用.
MAX7219_DisplayChar(DIG_1,CLEAR);//清空左面一位数码管
MAX7219_DisplayChar(DIG_2,co
while(!isPressed)//假如没有记载到有人按键就进入
{
keyPressed=GetPressed(P1);//查询一下P1口的状况,即按键状况
hostPressed=GetHostCancelKey();
if (!keyPressed&&!hostPressed)//假如没有人按键,就进入下次循环
continue;
else
{
TR0=0;//封闭定时器
isPressed=1;//记载到有人按键,提供条件跳出循环
}
}
if (keyPressed!=0)
{
if (isStart)//假如现已开端抢答
{
PressedHandle(keyPressed);//处理按键,即显现抢答选手号码
GetOrFoulHandle(GET);//处理抢答
LS138_E1=0; //译码器准备作业
switch (keyPressed)
{
case 1: LS138_A=0;LS138_B=0;LS138_C=0;break; //1号成功灯亮
case 2: LS138_A=0;LS138_B=1;LS138_C=0;break; //2号成功灯亮
case 3: LS138_A=1;LS138_B=0;LS138_C=0;break; //3号成功灯亮
case 4: LS138_A=1;LS138_B=1;LS138_C=0;break; //4号成功灯亮
default : break;
}
//SPEAKER_get();//处理抢答
}
else//不然,没有开端抢答
{
PressedHandle(keyPressed);//处理按键,即显现抢答选手号码
GetOrFoulHandle(FOUL);//处理犯规,必需要放在后边,由于显现数字的里边有一个clear
LS138_E1=0; //译码器准备作业
switch (keyPressed)
{
case 1: LS138_A=0;LS138_B=0;LS138_C=1;break; //1号犯规灯亮
case 2: LS138_A=0;LS138_B=1;LS138_C=1;break; //2号犯规灯亮
case 3: LS138_A=1;LS138_B=0;LS138_C=1;break; //3号犯规灯亮
case 4: LS138_A=1;LS138_B=1;LS138_C=1;break; //4号犯规灯亮
default : break;
}
//SPEAKER_foul();//犯规发声
}
}
if (hostPressed==1)
{
CancelHandle();
for (i=100;i–;i>0)
Delay10ms();//避免后边呈现连读的状况..
}
while(GetHostCancelKey()==0);//假如主持人没有按键再次开端,则停在次死循环处
LS138_E1=1; //封闭译码器
MAX7219_DisplayChar(DIG_1,READY);//清空右边一位数码管
MAX7219_DisplayChar(DIG_2,co
//到这儿一次循环完毕
}
}