/*******************************************************************
* 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(); } } } /*********************************************************/
上一篇:基于51单片机的ds18B20温度程序
下一篇:基于STC12C5A32S2单片机设计的交通灯
推荐阅读最新更新时间:2024-03-16 13:11