/******************************************************************* * LCD1602顯示 * *【版權(quán)】Copyright(C) JAS All Rights Reserved * *【聲明】此程序僅用于學(xué)習(xí)與參考,引用請(qǐng)注明版權(quán)和作者信息! * * * ******************************************************************** * * * 描述: * * F--- 模擬出題控制開(kāi)關(guān); C--- 輸入正確答案; * * (0-9)--- 有效數(shù)字輸入; * * 答題正確,蜂鳴器響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; //蜂鳴器驅(qū)動(dòng)線 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 ; /********************************************************** 延時(shí)子程序 **********************************************************/ void delay(uint ms) { uchar t; while(ms--) { for(t = 0; t < 120; t++); } } /*************************************************************/ /* */ /* 延時(shí) 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; //關(guān)閉蜂鳴器 delay(250); //延時(shí) } /*************************************************************/ /* */ /*檢查L(zhǎng)CD忙狀態(tài) */ /*lcd_busy為1時(shí),忙,等待。lcd-busy為0時(shí),閑,可寫(xiě)指令與數(shù)據(jù) */ /* */ /*************************************************************/ bit lcd_busy() { bit result; LCD_RS = 0; LCD_RW = 1; LCD_EN = 1; delayNOP(); result = (bit)(P0&0x80); LCD_EN = 0; return(result); } /*******************************************************************/ /* */ /*寫(xiě)指令數(shù)據(jù)到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; } /*******************************************************************/ /* */ /*寫(xiě)顯示數(shù)據(jù)到LCD */ /*RS=H,RW=L,E=高脈沖,D0-D7=數(shù)據(jù)。 */ /* */ /*******************************************************************/ 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初始化設(shè)定 */ /* */ /*************************************************************/ void lcd_init() { delay(15); lcd_wcmd(0x38); //16*2顯示,5*7點(diǎn)陣,8位數(shù)據(jù) delay(5); lcd_wcmd(0x38); delay(5); lcd_wcmd(0x38); delay(5); lcd_wcmd(0x0c); //顯示開(kāi),關(guān)光標(biāo) delay(5); lcd_wcmd(0x06); //移動(dòng)光標(biāo) delay(5); lcd_wcmd(0x01); //清除LCD的顯示內(nèi)容 delay(5); } /*************************************************************/ /* */ /* 設(shè)定顯示位置 */ /* */ /*************************************************************/ void lcd_pos(uchar pos) { lcd_wcmd(pos | 0x80); //數(shù)據(jù)指針=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(); } } /********************************************************** 隨機(jī)出題函數(shù) **********************************************************/ void rubric() { uchar num1,num2,temp1; TR1=0; temp1=TL1; //取T1當(dāng)前的計(jì)數(shù)值 temp1=~temp1; //取反得到對(duì)應(yīng)的題號(hào) num2=temp1/9; //就題目分成9組 num2++; //將組號(hào)0~8轉(zhuǎn)換為被乘數(shù)1~9 testdata[3]=num2+0x30; //保存被乘數(shù) num1=temp1%9; num1++; //將組號(hào)0~8轉(zhuǎn)換為乘數(shù)1~9。 testdata[2]=num1+0x30; //保存乘數(shù) temp1=num2*num1; //計(jì)算乘積 testdata[1]=temp1/10+0x30; //乘積的高位 testdata[0]=temp1%10+0x30; //乘積的低位 TR1=1; } /********************************************************** 鍵入正確答案函數(shù) **********************************************************/ 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]); } /********************************************************** 鍵入答案函數(shù) **********************************************************/ void key_input() { if(testdata[1]==0x30) //先判斷十位數(shù)是否為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; //轉(zhuǎn)換為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; //轉(zhuǎn)換為ASCII碼 in_data[0]=key_buf; //輸入乘積低位 lcd_pos(0x4c); lcd_wdat(in_data[0]); //顯示乘積低位 key_num=0; } } } /********************************************************** 數(shù)據(jù)比較函數(shù) **********************************************************/ void datacomp() { if(testdata[1]-in_data[1]==0) //比較乘積高位 { if(testdata[0]-in_data[0]==0) //比較乘積低位 { beep(); //計(jì)算正確蜂鳴器響3聲 beep(); beep(); truer=1; //比較正確 F_in=0; //可以重新出題 } else truer=0; //比較錯(cuò)誤 } else truer=0; //比較錯(cuò)誤 if(truer==0) { lcd_pos(0x4B); //清除錯(cuò)誤答案 lcd_wdat(0x20); lcd_wdat(0x3f); F_in=1; //禁止重新出題 } } /********************************************************** 主函數(shù) **********************************************************/ main() { uchar m; lcd_init(); //初始化LCD lcd_pos(0x00); //設(shè)置顯示位置為第一行 for(m=0;m<16;m++) lcd_wdat(cdis1 -); lcd_pos(0x40); //設(shè)置顯示位置為第二行 for(m=0;m<16;m++) lcd_wdat(cdis2 -); TMOD=0x21; //將T1設(shè)置為8位自動(dòng)重裝工作方式。 TH1=175; //對(duì)T1定時(shí)常數(shù)進(jìn)行預(yù)置。 TL1=175; TR1=1; //啟動(dòng)T1。 while(1) { keydown(); if(key_buf==0x0f) //F 鍵為模擬出題開(kāi)關(guān) { rubric(); lcd_pos(0x47); lcd_wdat(testdata[3]); //顯示被乘數(shù) lcd_pos(0x49); lcd_wdat(testdata[2]); //顯示乘數(shù) lcd_pos(0x4B); lcd_wdat(0x20); lcd_wdat(0x3f); //顯示 ? key_buf=0x00; F_in=1; //出題目完畢標(biāo)志 } while(F_in==1) { key_input(); datacomp(); } } } /*********************************************************/