专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

51乘法口诀模拟答题器

作者:佚名   来源:本站原创   点击数:  更新时间:2010年06月02日   【字体:
/*******************************************************************          

* LCD1602显示                                                      *
*【版权】Copyright(C) JAS  All Rights Reserved  *
*【声明】此程序仅用于学习与参考,引用请注明版权和作者信息!        *
*                                                                  *
********************************************************************
*                                                                  *
* 描述:                                                           *
*      F--- 模拟出题控制开关; C--- 输入正确答案;                   *
*      (0-9)--- 有效数字输入;                                      *
*      答题正确,蜂鸣器响4声。                                     *
*                                                                  *
*******************************************************************/
#include < reg51.h >
#include < intrins.h >

#define uchar unsigned char
#define uint  unsigned int

bit  F_in=0,truer;  


sbit LCD_RS = P2^0;             
sbit LCD_RW = P2^1;
sbit LCD_EN = P2^2;

uchar code  cdis1[ ] = {" MULTIPLICATION "}; 
uchar code  cdis2[ ] = {"TABLE: 0*0=00   "};

#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};

sbit BEEP = P3^7;          //蜂鸣器驱动线
uchar  key_buf;            //显示缓存
uchar  temp;
uchar  key,key_num=0;                //键顺序吗

uchar data testdata[] = {0x00,0x00,0x00,0x00};
uchar data in_data[] = {0x01,0x02};

uchar shift ;

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

 延时子程序

**********************************************************/
void delay(uint ms) 

{
   uchar t;
   while(ms--)
   { 
     for(t = 0; t < 120; t++);
   }
}

/*************************************************************/
/*                                                           */
/* 延时 x*0.14ms                                             */
/*                                                           */
/*************************************************************/
void delay0(uchar x)    
{
   unsigned char i;
   while(x--)
   {
     for (i = 0; i<13; i++) {}
   }
}

/*************************************************************/
/*                                                           */
/* 蜂鸣器响一声                                              */
/*                                                           */
/*************************************************************/
void beep()
{
  unsigned char i;
  for (i=0;i<180;i++)
   {
   delay0(6);
   BEEP=!BEEP;       //BEEP取反
   } 
   BEEP=1;           //关闭蜂鸣器
   delay(250);       //延时     
}

/*************************************************************/
/*                                                           */
/*检查LCD忙状态                                              */
/*lcd_busy为1时,忙,等待。lcd-busy为0时,闲,可写指令与数据  */
/*                                                           */
/*************************************************************/ 
bit lcd_busy()
 {                          
    bit result;
    LCD_RS = 0;
    LCD_RW = 1;
    LCD_EN = 1;
    delayNOP();
    result = (bit)(P0&0x80);
    LCD_EN = 0;
    return(result); 
 }

/*******************************************************************/
/*                                                                 */
/*写指令数据到LCD                                                  */
/*RS=L,RW=L,E=高脉冲,D0-D7=指令码。                             */
/*                                                                 */
/*******************************************************************/
void lcd_wcmd(uchar cmd)

{                          
   while(lcd_busy());
    LCD_RS = 0;
    LCD_RW = 0;
    LCD_EN = 0;
    _nop_();
    _nop_(); 
    P0 = cmd;
    delayNOP();
    LCD_EN = 1;
    delayNOP();
    LCD_EN = 0;  
}

/*******************************************************************/
/*                                                                 */
/*写显示数据到LCD                                                  */
/*RS=H,RW=L,E=高脉冲,D0-D7=数据。                               */
/*                                                                 */
/*******************************************************************/
void lcd_wdat(uchar dat)
{                          
   while(lcd_busy());
    LCD_RS = 1;
    LCD_RW = 0;
    LCD_EN = 0;
    P0 = dat;
    delayNOP();
    LCD_EN = 1;
    delayNOP();
    LCD_EN = 0; 
}

/*************************************************************/
/*                                                           */
/*  LCD初始化设定                                            */
/*                                                           */
/*************************************************************/
void lcd_init()
{ 
    delay(15);                   
    lcd_wcmd(0x38);      //16*2显示,5*7点阵,8位数据
    delay(5);
    lcd_wcmd(0x38);         
    delay(5);
    lcd_wcmd(0x38);         
    delay(5);

    lcd_wcmd(0x0c);      //显示开,关光标
    delay(5);
    lcd_wcmd(0x06);      //移动光标
    delay(5);
    lcd_wcmd(0x01);      //清除LCD的显示内容
    delay(5);
}

/*************************************************************/
/*                                                           */
/*  设定显示位置                                             */
/*                                                           */
/*************************************************************/

void lcd_pos(uchar pos)
{                          
  lcd_wcmd(pos | 0x80);  //数据指针=80+地址变量
}

/*************************************************************
                                                          
 键扫描子程序                                             
                                                          
*************************************************************/
void  keyscan(void)
{ 
    P1=0x0F;                 //低四位输入  
    delay(1);
 temp=P1;                 //读P1口 
    temp=temp&0x0F;
    temp=~(temp|0xF0);
    if(temp==1)
        key=0;
    else if(temp==2)
        key=1;
    else if(temp==4)
        key=2;
    else if(temp==8)
        key=3;
    else
        key=16;
        
    P1=0xF0;                //高四位输入
    delay(1);
 temp=P1;                //读P1口       
    temp=temp&0xF0;
    temp=~((temp>>4)|0xF0);
    if(temp==1)
        key=key+0;
    else if(temp==2)
        key=key+4;
    else if(temp==4)
        key=key+8;
    else if(temp==8)
        key=key+12;
    else
        key=16;
     
     key_buf = key;              //键值入显示缓存
     key_buf = key_buf & 0x0f;
}

/*************************************************************
                                                          
 判断键是否按下                                             
                                                         
*************************************************************/
 void  keydown(void)
 {  
   P1=0xF0;
 while(P1==0xf0);
 {
   keyscan();
   beep();
    }
 }

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

  随机出题函数

**********************************************************/
void  rubric()
{
   uchar  num1,num2,temp1;

   TR1=0;
   temp1=TL1;                   //取T1当前的计数值
   temp1=~temp1;                //取反得到对应的题号
   num2=temp1/9;                //就题目分成9组
   num2++;                      //将组号0~8转换为被乘数1~9
   testdata[3]=num2+0x30;       //保存被乘数
   num1=temp1%9;              
   num1++;                      //将组号0~8转换为乘数1~9。
   testdata[2]=num1+0x30;       //保存乘数

   temp1=num2*num1;             //计算乘积
   testdata[1]=temp1/10+0x30;   //乘积的高位
   testdata[0]=temp1%10+0x30;   //乘积的低位
   TR1=1;   
} 

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

  键入正确答案函数

**********************************************************/
void  right()
{
   if(testdata[1]==0x30)
   {
   testdata[1]=0x20;
   }

   lcd_pos(0x4b);
   in_data[1]=testdata[1];
   in_data[0]=testdata[0];
   lcd_wdat(in_data[1]);
   lcd_wdat(in_data[0]);
}

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

  键入答案函数

**********************************************************/
void  key_input()
{ 
   if(testdata[1]==0x30)        //先判断十位数是否为0
   {       
     in_data[1]=0x30;           
  key_num=1;
   }
   else
   {
     keydown();
  if(key_buf==0x0c)          //C 键显示正确答案
  {
    right();
       key_num=0;
     }
     if(key_buf<10)
     {          
       key_buf=key_buf+0x30; //转换为ASCII码
       in_data[1]=key_buf;      //输入乘积高位
       lcd_pos(0x4b);
       lcd_wdat(in_data[1]);    //显示乘积高位
       lcd_wdat(0x20);
    key_num=1;
     }
   }

   if(key_num==1)
   {
     keydown();
     if(key_buf==0x0c)          //C 键显示正确答案
  {
       right();
    key_num=0;
  }
     if(key_buf<10)
     {            
       key_buf=key_buf+0x30;    //转换为ASCII码
       in_data[0]=key_buf;      //输入乘积低位
       lcd_pos(0x4c);
       lcd_wdat(in_data[0]);    //显示乘积低位
    key_num=0;
     }         
   }
}
/**********************************************************

  数据比较函数

**********************************************************/
void  datacomp()
{
   if(testdata[1]-in_data[1]==0)    //比较乘积高位
   {
      if(testdata[0]-in_data[0]==0) //比较乘积低位
   {
      beep();                //计算正确蜂鸣器响3声
   beep();
   beep();
   truer=1;               //比较正确
         F_in=0;                //可以重新出题
   }
      else  truer=0;            //比较错误
   }
   else  truer=0;               //比较错误
  
   if(truer==0)          
   {
     lcd_pos(0x4B);             //清除错误答案
     lcd_wdat(0x20);
  lcd_wdat(0x3f);
  F_in=1;                    //禁止重新出题
   }
}

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

  主函数

**********************************************************/
main()
{
   uchar  m;
   lcd_init();                  //初始化LCD             
        
   lcd_pos(0x00);               //设置显示位置为第一行
   for(m=0;m<16;m++)
   lcd_wdat(cdis1

-);

   lcd_pos(0x40);               //设置显示位置为第二行     
   for(m=0;m<16;m++)
   lcd_wdat(cdis2

-);

   TMOD=0x21;                 //将T1设置为8位自动重装工作方式。
   TH1=175;                     //对T1定时常数进行预置。
   TL1=175;
   TR1=1;                       //启动T1。

   while(1)                
   {
     keydown();
     if(key_buf==0x0f)          //F 键为模拟出题开关
  {
    rubric();
    lcd_pos(0x47); 
       lcd_wdat(testdata[3]);   //显示被乘数
       lcd_pos(0x49); 
       lcd_wdat(testdata[2]);   //显示乘数

       lcd_pos(0x4B);
       lcd_wdat(0x20);
       lcd_wdat(0x3f);          //显示 ?
    key_buf=0x00;
    F_in=1;                  //出题目完毕标志
  }
     
     while(F_in==1)
  {
    key_input();
       datacomp();
  }
   } 
}

/*********************************************************/
关闭窗口

相关文章