欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

抢答器及计算器的讲解

程序员文章站 2022-06-09 11:18:14
...

单片机内容回顾


矩阵键盘

>原理图

抢答器及计算器的讲解

>原理

行列扫描:
1.高四位全部输出低电平,低四位输出高电平。当接收到的数据,低四位不全为高电平时,说明有按键按下,然后通过接收的数据值,判断是哪一列有按键按下。
2.高四位输出高电平,低四位输出低电平,然后根据接收到的高四位的值判断是哪那一行有按键按下。

>实现代码

/*******************************************************************************
* 函 数 名         : KeyDown
* 函数功能         : 检测有按键按下并读取键值
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void KeyDown(void)
{
    char a=0;
    GPIO_KEY=0x0f;
    if(GPIO_KEY!=0x0f)//读取按键是否按下
    {
        delay(1000);//延时10ms进行消抖
        if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
        {   
            //测试列
            GPIO_KEY=0X0F;
            switch(GPIO_KEY)
            {
                case(0X07): KeyValue=0;break;
                case(0X0b): KeyValue=1;break;
                case(0X0d): KeyValue=2;break;
                case(0X0e): KeyValue=3;break;
            }
            //测试行
            GPIO_KEY=0XF0;
            switch(GPIO_KEY)
            {
                case(0X70): KeyValue=KeyValue;break;
                case(0Xb0): KeyValue=KeyValue+4;break;
                case(0Xd0): KeyValue=KeyValue+8;break;
                case(0Xe0): KeyValue=KeyValue+12;break;
            }
            while((a<50)&&(GPIO_KEY!=0xf0))  //检测按键松手检测
            {
                delay(1000);
                a++;
            }
        }
    }
}

外部中断

>中断的作用

如果没有中断系统,就只能由 CPU 按照程序编写的先后次序,对各个外设,进行巡回检查与处理。这就是查询式工作方式,貌似公平,实际效率却不高。如果有了中断系统,整个计算机系统,就具有了应付突发事件的处理能力。这就是中断式工作方式。

>中断的概念

抢答器及计算器的讲解
抢答器及计算器的讲解

>外部中断基本流程

抢答器及计算器的讲解
抢答器及计算器的讲解
抢答器及计算器的讲解

(P3.2)可由IT0(TCON.0)选择其为低电平有效还是下降沿有效。当CPU检测到P3.2引脚上出现有效的中断信号时,中断标志IE0(TCON.1)置1,向CPU申请中断。

>实现代码

void Int0Init()
{
    //设置INT0
    IT0=1;//跳变沿出发方式(下降沿)
    EX0=1;//打开INT0的中断允许。    
    EA=1;//打开总中断    
}

void Int0() interrupt 0     //外部中断0的中断函数
{
    //中断发生时进行的操作
}

LCD1602

>原理图及功能指令

抢答器及计算器的讲解

清屏指令
抢答器及计算器的讲解
<1> 清除液晶显示器,即将 DDRAM 的内容全部填入”空白”的 ASCII码 20H;
<2> 光标归位,即将光标撤回液晶显示屏的左上方;
进入模式设置指令
抢答器及计算器的讲解
I/D 0=写入新数据后光标左移 1=写入新数据后光标右移
S 0=写入新数据后显示屏不移动 1=写入新数据后显示屏整体右移 1 个字符
显示开关控制指令
抢答器及计算器的讲解
D 0=显示功能关 1=显示功能开
C 0=无光标 1=有光标
B 0=光标闪烁 1=光标不闪烁
功能设定指令
抢答器及计算器的讲解
DL 0=数据总线为4 位 1=数据总线为 8 位
N 0=显示1 行 1=显示 2 行
F 0=5×7点阵/每字符 1=5×10 点阵/每字符
DDRAM地址
写入显示地址时要求最高位 D7恒定为高电平 1 所以实际写入的数据应该是 01000000B(40H)
+10000000B(80H)=11000000B(C0H)。
抢答器及计算器的讲解

>基本代码

void wrc(u8 command) //LCD1602写入指令
{
    delay(1000);
    rs=0;
    rw=0;
    e=0;
    P0=command;
    e=1;
    delay(10);
    e=0;
}

void wrd(u8 dat)    //LCD1602写入数据
{
    delay(1000);
    rs=1;
    rw=0;
    e=0;
    P0=dat;
    e=1;
    delay(10);
    e=0;
}

void lcdinitial()
{
    delay(1000);
    wrc(0x01); //清屏
    wrc(0x06); //写入数据后光标右移,显示屏不移动
    wrc(0x0c); //显示开,无光标,不闪烁
    wrc(0x38); //八线数据总位,显示两行,5*7显示
}

抢答器代码

分析
利用外部中断实现每一次的开局
用矩阵键盘获取抢答者输入的信息
静态数码管输出抢答序号

#include "reg52.h"           

typedef unsigned int u16;     
typedef unsigned char u8;

#define GPIO_KEY P1  //获取矩阵键盘按键值

int KeyValue,flag;    //flag为标志变量
u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
                  0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//共阴数码管表

void delay(u16 i)
{
    while(i--); 
}

void Int0Init()  //外部中断初始化
{
    //设置INT0
    IT0=1;//跳变沿出发方式(下降沿)
    EX0=1;//打开INT0的中断允许。    
    EA=1;//打开总中断    
}

void KeyDown(void)
{
    char a=0;
    GPIO_KEY=0x0f;
    if(GPIO_KEY!=0x0f)//读取按键是否按下
    {
        delay(1000);//延时10ms进行消抖
        if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
        {   
            //测试列
            GPIO_KEY=0X0F;
            switch(GPIO_KEY)
            {
                case(0X07): KeyValue=0;break;
                case(0X0b): KeyValue=1;break;
                case(0X0d): KeyValue=2;break;
                case(0X0e): KeyValue=3;break;
            }
            //测试行
            GPIO_KEY=0XF0;
            switch(GPIO_KEY)
            {
                case(0X70): KeyValue=KeyValue;flag=0;break;
                case(0Xb0): KeyValue=KeyValue+4;flag=0;break;
                case(0Xd0): KeyValue=KeyValue+8;flag=0;break;
                case(0Xe0): KeyValue=KeyValue+12;flag=0;break;
            }
            while((a<50)&&(GPIO_KEY!=0xf0))  //检测按键松手检测
            {
                delay(1000);
                a++;
            }
        }
    }
}
void keypros()
{
    while(flag)
    {
        KeyDown();
        if(!flag){
            P0=~smgduan[KeyValue];
        }
    }
}

void main()    
{
     Int0Init();
     flag=0;
    while(1)
    {       
         if(flag)
         {
         keypros();
        }
    }       
}

void Int0() interrupt 0     //外部中断0的中断函数
{
     P0=0xff;
     flag=1;
}

计算器代码

运行图片

抢答器及计算器的讲解
抢答器及计算器的讲解

键盘按键对应设计
1 2 3 +
4 5 6 –
7 8 9 *
C 0 = /
LCD显示:
第一行为算式 3*6
第二行为结果 =18
运算范围:
仅支持两个正整数的运算,结果可为负数,范围可达十位数
流程
不断扫描矩阵键盘,设立标志变量识别按键按下
对按下的按键分类:数字,运算符,清除,等号
将运算结果显示在LCD1602上

#include "reg52.h"           

typedef unsigned int u16;    //0-65535     
typedef unsigned char u8;    //0-255
typedef unsigned long u32;   //0- 2^32-1

sbit rs=P2^6;            //lcd1602特殊位定义
sbit rw=P2^5;
sbit e=P2^7;

#define GPIO_KEY P1  //获取矩阵键盘按键值

int KeyValue,flag,t;    //flag为标志变量
u32 a,b,num=0;         //储存运算过程变量
long answer;

void delay(u16 i)
{
    while(i--); 
}

void KeyDown(void)
{
    char a=0;
    GPIO_KEY=0x0f;
    if(GPIO_KEY!=0x0f)//读取按键是否按下
    {
        delay(1000);//延时10ms进行消抖
        if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
        {   
            //测试列
            GPIO_KEY=0X0F;
            switch(GPIO_KEY)
            {
                case(0X07): KeyValue=0;break;
                case(0X0b): KeyValue=1;break;
                case(0X0d): KeyValue=2;break;
                case(0X0e): KeyValue=3;break;
            }
            //测试行
            GPIO_KEY=0XF0;
            switch(GPIO_KEY)
            {
                case(0X70): KeyValue=KeyValue;flag=0;break;
                case(0Xb0): KeyValue=KeyValue+4;flag=0;break;
                case(0Xd0): KeyValue=KeyValue+8;flag=0;break;
                case(0Xe0): KeyValue=KeyValue+12;flag=0;break;
            }
            while((a<50)&&(GPIO_KEY!=0xf0))  //检测按键松手检测
            {
                delay(1000);
                a++;
            }
        }
    }
}

void wrc(u8 command) //LCD1602写入指令
{
    delay(1000);
    rs=0;
    rw=0;
    e=0;
    P0=command;
    e=1;
    delay(10);
    e=0;
}

void wrd(u8 dat)    //LCD1602写入数据
{
    delay(1000);
    rs=1;
    rw=0;
    e=0;
    P0=dat;
    e=1;
    delay(10);
    e=0;
}

void display(long i)
{
    int j=0;
    u8 a[10];      //储存从结果中分离出的数字
    wrc(0x80+0x40);   //光标移至第二行
    wrd('=');
    if(i<0)    
   {
     wrd('-');
     i=-i;
   }
    while(i)       
    {
        a[j]=i%10;   //将结果从最低位分裂出来
        i=i/10;    
        j++;
    }
    for(j=j-1;j>=0;j--)   //从最高位开始显示
    {
        wrd(a[j]+'0');    
    }
}

void lcdinitial()
{
    delay(1000);
    wrc(0x01); //清屏
    wrc(0x06); //写入数据后光标右移,显示屏不移动
    wrc(0x0c); //显示开,无光标,不闪烁
    wrc(0x38); //八线数据总位,显示两行,5*7显示
}

void calcupros(){
    while(1)
    {
       KeyDown();
       if(!flag)
         {
             switch(KeyValue)
             {
                case(0):num=num*10+1;wrd('1');break;     //数字显示
                case(1):num=num*10+2;wrd('2');break;
                case(2):num=num*10+3;wrd('3');break;
                case(4):num=num*10+4;wrd('4');break;
                case(5):num=num*10+5;wrd('5');break;
                case(6):num=num*10+6;wrd('6');break;
                case(8):num=num*10+7;wrd('7');break;
                case(9):num=num*10+8;wrd('8');break;
                case(10):num=num*10+9;wrd('9');break;
                case(13):num=num*10+0;wrd('0');break;
                case(3):a=num;num=0;wrd('+');t=1;break;    //为运算符添加标志变量
                case(7):a=num;num=0;wrd('-');t=2;break;
                case(11):a=num;num=0;wrd('*');t=3;break;
                case(15):a=num;num=0;wrd('/');t=4;break;
                case(14):b=num;num=0;
                  switch(t)
                  {
                    case(1):answer=a+b;display(answer);break;   //对不同的运算符计算
                    case(2):answer=a-b;display(answer);break;
                    case(3):answer=a*b;display(answer);break;
                    case(4):answer=a/b;display(answer);break;
                  }
                  break;
                case(12):
                lcdinitial();
                wrc(0x00+0x80);
                a=0;b=0;num=0;answer=0;         
             }
            flag=1;
        }
    }

}

void main()    
{

   flag=1;
   lcdinitial();     //LCD初始化
   wrc(0x00+0x80);

    while(1)
    {       
         calcupros();  //核心处理函数
    }       
}

相关标签: 培训