基于AT89S51的单片机无线双显示抢答器C代码

发布者:painter最新更新时间:2017-01-07 来源: eefocus关键字:AT89S51  单片机  无线双显示  抢答器 手机看文章 扫描二维码
随时随地手机看文章

#include

#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


//下面是给上位机发送的指令,对应的是cmdID

#define _STRING_READY_ 9//调整好抢答倒计时,准备开始抢答

#define _STRING_START_ 8//读秒结束,抢答开始

#define _STRING_CANCEL_ 7//取消抢答

#define _CHANGE_TIME_ 6//每次读秒

//发送1--4的指令代表抢答端的序号


//因为在板子上面采用的是12M的晶振,仿真时候采用的是11.0529M的晶振,为了方便不同时候编译方便,这里与后面的条件编译一起使程序修改参数比较方便

//#define CLOCK_FREQUENCY_12M 1


/******************************************************************

*    自定义数据类型

*******************************************************************/

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 DATA=P2^0;               // MAX7219的数据口

sbit LOAD=P2^1;               // MAX7219的锁存端口

sbit CLK=P2^2;                // MAX7219的时钟端口


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;            //定义蜂鸣器端口


#ifdef USE_SOUND       //可以通过define来选择要不要使用仿真时候的声音

sbit LS138_C=P2^4;       //定义译码器输入端

sbit LS138_B=P2^5;       //同上                  

sbit LS138_A=P2^6;       //同上

sbit LS138_E1=P2^7;       //定义译码器使能端

#endif


/*********************************************************************

*    定义全局变量

**********************************************************************/

Byte data intrCounter; // 计时器中断次数

Byte data beginNum;    // 开始倒计时的时间

Byte data counterBack;  // 将中断次数放在里面以备后用

Byte data showNum;     // 数码管正在显示的时间

Bool data isStart;     // 是否开始抢答  

Bool data isFoul;      // 是否犯规

Bool data isPressed;   // 是否有抢答的键按下

Byte data number_temp; // 用来记录P1口上次状态的一个变量

Bool data needResetTimes;//记录是否需要重设Timer0的溢出次数


code unsigned char C51BOX2[3] _at_ 0x43; //使用C51Box时候防止程序跑丢


/***********************************************************************

*   共阴极七段数码管显示对应段查询表(数字0-9分别对应code_table[0]-[9])

***********************************************************************/

Byte code code_table_zheng[10]=

{0x7e,0x30,0x6d,0x79,0x33,0x5b,0x5f,0x70,0x7f,0x7b};


Byte code code_table[10]=

{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);

Byte GetPressedWireless(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);   //  声明犯规声音函数

void initialSerial();

void sendNumber(int number);//串口发送数字,这里发送的是CommandID

void sendString(unsigned char *string);//串口发送字符串


/***********************************************************************

* MAX7219_SendByte()

*

* 描述: 向MAX7219传送一个字节的数据

* Arguments : dataout = data to send

* 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)

            DATA=1;

        else

            DATA=0;

        CLK=1;//八个bit都传递完成后变为高电平,锁存

    }

}


/***********************************************************************

* MAX7219_Write()

*

* 描述: 向 MAX7219 写命令

* Arguments : reg_number = register to write to

* dataout = data to write to MAX7219

* 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)

{

    DATA=1;

    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: 从P2口连接抢答端的四位来判断抢答情况

* Arguments : Byte KeyState-->P2 state

* Returns : 抢答端的号码 ; 0-->没人抢答

***************************************************************************/

Byte GetPressed(Byte KeyState)

{

    Byte key;//记录抢答端的号码

    KeyState&=0xf0;//取P1口的低四位

    

    switch (KeyState)

    {

        case 0xf0: key=0;break;//全高,无人抢答

        case 0xe0: key=1;break;//只有P1.1,key1抢答

        case 0xd0: key=2;break;//只有P1.2,key2抢答

        case 0xb0: key=3;break;//只有P1.3,key3抢答

        case 0x70: 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;    

}


/**************************************************************************

* GetPressedWireless

*

* Description: P2口的高四位于Pt2272接受模块相连,该方法用来判断无线抢答序号

* Arguments : Byte KeyState-->P2 state

* Returns : 抢答端的号码 ; 0-->没人抢答

***************************************************************************/

Byte GetPressedWireless(Byte KeyState)

{

    Byte key;//记录抢答端的号码

    KeyState&=0xf0;//取P2口的高四位

    

    /*

    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 0x10: key=1;break;//只有P1.0,key1抢答

        case 0x20: key=2;break;//只有P1.1,key2抢答

        case 0x40: key=3;break;//只有P1.2,key3抢答

        case 0x80: key=4;break;//只有P1.3,key4抢答

    }

    return key;    

}


/**************************************************************************

* IT0_Init

*

* Description: 初始化计时器T0的状态

* Arguments : none

* Returns : none

***************************************************************************/

void IT0_Init(void)

{

    TMOD=0x21;//设置T0在方式1下工作,同时还要保证T1,也就是波特率所学的定时器的正常工作


    #ifdef CLOCK_FREQUENCY_12M//对使用哪种晶振进行条件编译

    TH0=0x3C;//12M晶振时的装入值

    TL0=0xAF;

    #else

    TH0=0x4C;//11.0529M晶振时装入值

    TL0=0x00;

    #endif


    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 times=20;//溢出次数,用20次中断来判断1秒

    //这里存在重大bug,到由于有相应而停止Timer0后,再次启用时,这里的second没有回归原值


    if (needResetTimes==1)

    {

        times=20;

        needResetTimes=0;//已重设,不需要再次重新设置溢出次数

    }


    #ifdef CLOCK_FREQUENCY_12M//对使用哪种晶振进行条件编译

    TH0=0x3C;//12M晶振时的装入值

    TL0=0xAF;//这两个寄存器存的是计数器的计数开始的值,计算发现这两个值累加至溢出后正好是50ms

    #else

    TH0=0x4C;//11.0529M晶振时装入值

    TL0=0x00;//同理,这两个寄存器存的是计数器的计数开始的值,计算发现这两个值累加至溢出后正好是50ms

    #endif


    times--;

    intrCounter--;


    /* 原来使用的方法

    if (times==0)//每隔一秒的操作

    {

        MAX7219_DisplayChar(DIG_2,code_table[--showNum]); //要避免用上面的会造成显示"0"后面一秒钟,才进入开始

        times=20;//重新赋值每秒计数器

        if (intrCounter==0)

        {

            TR0=0;//关闭T0计数器

            isStart=1;//计时结束,进入正常抢答

            //SPEAKER_start();//开始抢答的声音

        }

        //待显示"0"以后就开始抢答

        else

        {

            //SPEAKER_count();//倒计时声音        

        }

    }

    */


    if (times==0)//每隔一秒的操作

    {

        //if (showNum!=1) SPEAKER_count();//倒计时声音

        //else SPEAKER_start();//开始抢答的声音

        MAX7219_DisplayChar(DIG_2,code_table[--showNum]);//显示数字

        sendNumber(_CHANGE_TIME_);//给上位机发送要显示数字的命令

        times=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,code_table[keyPressed]);//在右侧数码管显示抢答选手号码,此时没有去判断是否犯规

    

    //给上位机发抢答选手的号码

    sendNumber(keyPressed);

}


/**************************************************************************

* 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);

    }

}


/**************************************************************************

* initialSerial()

*

* Description: 初始化串口

* Arguments : none

* Returns : none

***************************************************************************/

void initialSerial()

{

    EA=0;//关闭所有中断

    TMOD=0x21;//设置T1定时器的工作模式:方式2;同时保证T0的工作模式正常.这儿太重要了

    TH1=0xFA;

    TL1=0xFA;

    PCON=0x80;//设置SMOD=1

    SCON=0x50;//选择工作方式1,即为UART

    TR1=1;//设置好定时器并打开定时器,定好波特率9600bit/s

}


/**************************************************************************

* sendNumber(int number)

*

* Description: 通过串口发送一位数字

* Arguments : number->要发送的数字

* Returns : none

***************************************************************************/

void sendNumber(int number)

{

    TI=0;

    SBUF=number+48;

    while(!TI);

    TI=0;

}


/**************************************************************************

* sendString(unsigned char *string)

*

* Description: 通过串口发送字符串

* Arguments : 要发送的字符串的头指针

* Returns : none

***************************************************************************/

void sendString(unsigned char *string)

{

    do

    {

        SBUF=*string;

        while(!TI);

        TI=0;

        string++;

    }while(*(string-1)!='\0');

}




/**************************************************************************

* 主程序

***************************************************************************/

void main()

{    

    //P1=0xff;

    Byte keyPressed,i;//选手按键号码,没有的话为0    

    Bool hostPressed;//用来记录主持人按键取消,0为没有动作,1为取消

    Byte buf[10];//设置发送缓冲区

    number_temp=P1&0xf0;//P1口上次的状态,在调整倒计时时间的时候用到的    

    

    #ifdef USE_SOUND

    LS138_E1=1;         //译码器初始化

    #endif


    needResetTimes=0;//不需要重新设置溢出次数

    

    MAX7219_Init();//数码管初始化

    initialSerial();//初始化串口发送

    

    GetCounter();//获取开始时候设置的倒计时时间    

    MAX7219_DisplayChar(DIG_1,code_table[beginNum]);//显示开始时设置的倒计时时间,在左位设置     

    MAX7219_DisplayChar(DIG_2,READY);//调时间的时候右位的显示

    

    while(GetHostStartKey()==0)//当主持人没有按键的时候进入循环

    {

        if (number_temp!=(P1&0xf0))//若调整了倒计时时间,则P1口状态变了,就要重新设置和显示

        {

            GetCounter();//获取调整以后的倒计时时间

            MAX7219_DisplayChar(DIG_1,code_table[beginNum]);//显示调整以后的倒计时时间

            number_temp=P1&0xf0;//记录下来现在P1口的状态,以备后面的比较

        }            

    }    //当主持人按键以后就结束调整进入抢答倒计时

    sendNumber(beginNum);


    MAX7219_DisplayChar(DIG_1,READY);

    while(GetHostCancelKey()==0);

    

    sendNumber(_STRING_READY_);//发送调节完毕准备抢答的命令;


    //调整好倒计时时间后,按下start显示"--",再按下cancel则显示倒计时时间,此时可以开始倒计时了.

    MAX7219_DisplayChar(DIG_1,READY);//清空右边一位数码管

    MAX7219_DisplayChar(DIG_2,code_table[beginNum]);

    for (i=100;i--;i>0)

        Delay10ms();//防止后面出现连读的情况..

 

    counterBack=intrCounter; //备份要中断的总次数

    while(1)//这里要用自己加的循环来把程序束缚在这里运行

    {

        showNum=beginNum;//设置要显示的时间,当然时从倒计时时间开始

        intrCounter=counterBack;//设置总中断的次数

        TR0=0;//禁用计时器0

        isPressed=0;//记录是否有人按键

        isStart=0;//没有开始抢答

        while(GetHostStartKey()==0);


        //给上位机发送开始倒计时的指令

        sendNumber(_STRING_START_);


        needResetTimes=1;//Timer0已经是第二轮开始,需要重新设置溢出次数

        IT0_Init();//初始化计时器0, 启用.


        MAX7219_DisplayChar(DIG_1,CLEAR);//清空左边一位数码管

        while(!isPressed)//如果没有记录到有人按键就进入

        {

            keyPressed=GetPressed(P2);//查询一下P2口的状态,即按键情况,P2口的后四位作为抢答端输入,有线时候使用

            //keyPressed=GetPressedWireless(P2);//查询一下P2口的状态,即按键情况,无线使用

            hostPressed=GetHostCancelKey();

            if (!keyPressed&&!hostPressed)//如果没有人按键,就进入下次循环

                continue;

            else

            {

                TR0=0;//关闭定时器

                isPressed=1;//记录到有人按键,提供条件跳出循环

            }

        }


        if (keyPressed!=0)

        {

            if (isStart)//如果已经开始抢答

            {

                PressedHandle(keyPressed);//处理按键,即显示抢答选手号码

                GetOrFoulHandle(GET);//处理抢答


                #ifdef USE_SOUND//对是否使用扬声器进行条件编译

                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;

                }

                #endif

            }    

                                                  

            else//否则,没有开始抢答 

            {    

                PressedHandle(keyPressed);//处理按键,即显示抢答选手号码

                GetOrFoulHandle(FOUL);//处理犯规,必须要放在后面,因为显示数字的里面有一个clear


                #ifdef USE_SOUND//对是否使用扬声器进行条件编译

                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;

                }

                #endif

            }

        }


        if (hostPressed==1)

        {

            CancelHandle();

            //向上位机发送主持人取消的指令

            sendNumber(_STRING_CANCEL_);

            for (i=100;i--;i>0)

                Delay10ms();//防止后面出现连读的情况..        

        }

        while(GetHostCancelKey()==0);//如果主持人没有按键再次开始,则停在次死循环处

         

        #ifdef USE_SOUND//对是否使用扬声器进行条件编译

        LS138_E1=1;        //关闭译码器

        #endif


        MAX7219_DisplayChar(DIG_1,READY);//清空右边一位数码管

        MAX7219_DisplayChar(DIG_2,code_table[beginNum]);//左位显示设置的倒计时时间


        //给上位机发送重新开始倒计时的指令

        sendNumber(_STRING_READY_);


         //到这里一次循环结束

    }

}    


关键字:AT89S51  单片机  无线双显示  抢答器 引用地址:基于AT89S51的单片机无线双显示抢答器C代码

上一篇:基于AT89S51的单片机无线双显示抢答器简要说明
下一篇:增强型51单片机定时器2与串行通讯应用

推荐阅读最新更新时间:2024-03-16 15:29

基于单片机的线阵CCD实时检测系统的开发
摘要:分析了线阵CCD用于实时检测系统的特点和要求,介绍了一种基于AT89C2051单片机的线阵CCD实时检测系统的设计方案。本方案电路结构简单可靠,信号处理灵活检当,有一定的通用性和启发性。 关键词:CCD 单片机 驱动 检测系统 CCD(Charge Coupled Devices)电荷耦合器件应用系统的关键技术在于CCD驱动时序的产生和输出信号的采集与处理。目前驱动主要有直接数字电路驱动、EPROM驱动、专用IC驱动、复杂的CPLD驱动等常用的驱动方法,但是它们存在着逻辑设计较为复杂、调试困难、柔性较差等缺点。在数据采集和处理方面,大多数都经过差动放大、采样保持、A/D转换,再通过总线或采集卡等接口与PC机相连。这种系
[单片机]
基于MSP430系列单片机的常用程序编写总结
前一段时间一直在用TI公司的MSP430系列的单片机,总结了点430常用的程序框架。 a.循环低功耗、中断服务程序唤醒 void main() { 关闭开门狗; 初始化时钟; 初始化端口; 初始化屏幕; 其他外围必要的初始化; 开中断; while(1) { 进入低功耗模式; 执行某函数; } } 中断函数1 { 退出低功耗; 中断服务程序; } 例如: 1 #pragma vector= ADC 12_VECTOR 2 __in te rrupt void ADC12ISR (void) //AD转换中断服务程序 3 { 4 sta TI c unsigned char index = 0; 5 LPM3_EXIT; 6
[单片机]
基于MSP430系列<font color='red'>单片机</font>的常用程序编写总结
单片机键盘去抖程序
用单片机或ARM做的产品经常会遇到有键盘输入的产品,而键盘输入有一个绕不过去的问题就是:键盘去抖。见下图 当按键开关闭合或者断开时各有一段电平不稳定的时期,按键开关在闭合时不会马上就稳定的接通,在断开时也不会一下子彻底断开,而是在闭合和断开的瞬间伴随了一连串的电平抖动。这种抖动一般都在10ms左右。为了确保程序对按键的一次闭合或者一次断开只响应一次,必须进行按键的去抖处理。当检测到按键状态变化时,不是立即去响应动作,而是先等待闭合或断开稳定后再进行处理。 按键去抖方法可分为硬件去抖和软件去抖,硬件去抖不在本文的讨论中,本文只讨论软件去抖。 一般的软件去抖就是程序在检测到按键闭合或断开时调用一段延时子程序(在C语言中叫函
[单片机]
<font color='red'>单片机</font>键盘去抖程序
AT89S51单片机的内部硬件结构组成及特点介绍
AT89S51单片机的片内硬件组成结构如图2-1所示。它把那些作为控制应用所必需的基本功能部件都集成在一个尺寸有限的集成电路芯片上,具有如下功能部件和特性: (1)8位微处理器(CPU)。 (2)数据存储器(128B RAM)。 (3)程序存储器(4KB FLASH ROM)。 (4)4个8位可编程并行I/O口(PO口、Pl口、P2口和P3口)。 (5)1个全双工的异步串行口。 (6)2个可编程的16位定时器/计数器。 (7)1个看门狗定时器。 (8)中断系统具有5个中断源、5个中断向量。 (9)特殊功能寄存器(SFR) 26个。 (10)低功耗节电模式有空闲模式和掉电模式,且具有掉电模式下的中断恢复模式。 (11)3个程序加密锁
[单片机]
<font color='red'>AT89S51</font><font color='red'>单片机</font>的内部硬件结构组成及特点介绍
意法半导体的微控制器和功率半导体获丰田普锐斯采用
意法半导体的芯片与汽车厂商的软件系统相互搭配,实现了高能效的电压转换和低散热特性,进而协助动力控制单元微型化 意法半导体(STMicroelectronics,简称ST;纽约证券交易所代码:STM)宣布其32位微控制器和功率MOSFET获丰田汽车(Toyota)采用,用于开发新一代普税斯的DC-DC转换器。新一代普税斯是第四代混合动力汽车。 DC-DC转换器是被称作混合动力汽车(hybrid electric vehicle)心脏的动力控制单元的基本组件,还被用于逆变器和可变电压系统(variable-voltage system)。新一代普税斯的DC-DC转换器设计采用意法半导体的32位车用微控制器,用于
[汽车电子]
学51单片机-指令周期与LED闪烁
之前讲了如何点亮LED,包括硬件电路和程序,今天说一下如何让LED闪烁。单片机控制LED闪烁有两种方法,一种是软件延时,另一种是定时器中断。因为涉及到单片机指令集的问题,还有一些简单的C语言,今天只讲第一种。 先说指令集,早期的51单片机都是复杂指令集,因为沿用的习惯现在用的STC89C52单片机也是复杂指令集,和复杂指令集对应的,就是精简指令集,常见的有AVR和430单片机。 这两种指令集的区别是啥?最明显的就是一条指令执行的时间,举个例子:51单片机和AVR单片机都外接一个12M的晶体,一个时钟周期是1/12M=1/12US,执行一条单周期指令(多周期指令不考虑)需要多少时间? 51单
[单片机]
学51<font color='red'>单片机</font>-指令周期与LED闪烁
C51单片机在电机转速测量仿真系统中的设计
单片机电机转速测量系统仿真系统采用单片机中T1计数器对转速脉冲进行计数。定时器T1 工作于外部事件计数方式,对转速脉冲计数; T0 工作于定时器方式。每到1 s 读1 次计数值,此值即为脉冲信号的频率,根据式( 1) 可计算出电机的转速。转速检测装置的软件系统主要包括: 测速主程序、数据处理子程序和显示子程序。单片机上电后,系统进入准备状态。首先进行初始化,然后读取脉冲数据进行运算,将转速显示在LCD上。需要这款仿真及C语言程序的爱好者可从文章配图左上角网址上了解。 该单片机电机转速测量系统仿真仿真采用测频法“M法”测量电机转速。即在一定测量时间T内,测量脉冲发生器(替代输入脉冲)产生的脉冲数m1来测量转速,计算式如下:n=
[单片机]
C51<font color='red'>单片机</font>在电机转速测量仿真系统中的设计
超低功耗无线 MCU:玩转睡眠模式
支持蓝牙低功耗 (LE) 的设计可让设备长时间处于非工作状态,因此,您可能需要选用具有超低功耗睡眠模式的高能效无线微控制器 (MCU),这对于优化整体系统性能至关重要。 设计人员应当仔细选择采用蓝牙低功耗技术的 MCU 的规格,确定超低功耗的真正含义。这不是对照数据表确定最低电流消耗值,针对应用寻求最佳解决方案并非易事。睡眠模式(又称低功耗模式或休眠模式)不仅意味着低电流, 还需考虑以下几个因素: • 电流消耗 • 唤醒源 • 保留内存 • 唤醒时间 • 能够读取外部传感器 电流消耗 睡眠模式下电流消耗少当然很好;并且越少越好,但设计人员还必须考虑睡眠模式期间的可用功能。为实现睡眠模式下最低功耗,除了硬件需要单个唤
[嵌入式]
超低功耗<font color='red'>无线</font> <font color='red'>MCU</font>:玩转睡眠模式
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved