Ayb_ice 发表于 2025-1-20 08:31:31

不需要1ms调用一次,也没有必要在中断中调用

冬不拉 发表于 2025-6-2 07:33:31

学习按键扫描程序

zhaoyun189911 发表于 3 天前

这段检测案件的程序 做成一个函数放到定时器里面可以不? 为什么放主循环?
是放主循环好还是放在定时器里面好

乘风飞扬 发表于 昨天 09:30

zhaoyun189911 发表于 2025-6-14 16:06
这段检测案件的程序 做成一个函数放到定时器里面可以不? 为什么放主循环?
是放主循环好还是放在定时器里 ...

最好放在主循环里,中断里面尽量不要放太多程序,避免影响其他中断的响应速度。

神农鼎 发表于 昨天 10:23











#include <AI8051U.H>                                        //包含AI8051U的头文件
#include "ai_usb.h"                                                //使用usb所需要包含的头文件
#include "intrins.h"


bit        keyok;                                                //按键按下标志
unsigned char keycode;                        //定义变量,保存按键键码
unsigned char debounce;                        //按键去抖动

void Delay1ms(void)                                //@40.000MHz
{
        unsigned long edata        i;

        _nop_();
        _nop_();
        _nop_();
        i =        9998UL;
        while (i) i--;
}

void DelayXms(int n)                        //延时函数
{
        while (n--)
                Delay1ms();
}

void DelayXus(int n)                //@40.000MHz
{
        unsigned long edata        i;

        while (n--)
        {
                i =        8UL;
                while (i) i--;
        }
}

void BootLogo(void)                                //开机画面
{
        P0 = 0x00;                                        //8个LED全部点亮
        DelayXms(200);                                //延时200ms
        P0 = 0xff;                                        //8个LED全部熄灭
        DelayXms(200);                                //延时200ms
        P0 = 0x00;                                        //8个LED全部点亮
        DelayXms(200);                                //延时200ms
        P0 = 0xff;                                        //8个LED全部熄灭
        DelayXms(200);                                //延时200ms
        P0 = 0x00;                                        //8个LED全部点亮
        DelayXms(200);                                //延时200ms
        P0 = 0xff;                                        //8个LED全部熄灭
        DelayXms(200);                                //延时200ms
}

void DetectTemp(void)                        //检测当前温度
{
}

void ControlTemp(void)                        //控制当前温度
{
}

void OtherEvent(void)                        //其他事件
{
        DelayXms(10);                                //假定其他事件处理时间为10ms
}

void Beep(int tone)                                //蜂鸣器程序
{                                                                //实验箱上的是无源蜂鸣器,需要持续输出高低电平蜂鸣器才会发声
        int        i;
       
        for        (i = 0;        i <        50;        i++)
        {
                P50        = 1;                                //打开蜂鸣器控制三极管
                DelayXus(tone);                        //延时(修改延时时间可改变蜂鸣器的音调)
                P50        = 0;                                //关闭蜂鸣器控制三极管
                DelayXus(tone);                        //延时
        }
}

void KeyEvents(void)                        //执行有效按键对应的任务
{
        if (keyok)                                        //判断按键按下标志
        {
                keyok =        0;                                //清除标志
               
                switch (keycode)                //处理不同的按键键码
                {
                case 0:        Beep(956); break;//Key0事件,使用蜂鸣器发Do
                                 //这里的参数为956,即产生一个低电平和高电平均为956us的方波
                                 //得到的方波频率为1000000/(956+956)=523Hz
                                 //即为高8度的Do的频率(261.6Hz*2)
                case 1:        Beep(851); break;//Key1事件,使用蜂鸣器发Re
                                 //这里的参数为851,即产生一个低电平和高电平均为851us的方波
                                 //得到的方波频率为1000000/(851+851)=587Hz
                                 //即为高8度的Re的频率(293.6Hz*2)
                case 2:        Beep(758); break;//Key2事件,使用蜂鸣器发Mi
                                 //这里的参数为758,即产生一个低电平和高电平均为758us的方波
                                 //得到的方波频率为1000000/(758+758)=660Hz
                                 //即为高8度的Do的频率(329.6Hz*2)
                case 3:        Beep(716); break;//Key3事件,使用蜂鸣器发Fa
                                 //这里的参数为716,即产生一个低电平和高电平均为716us的方波
                                 //得到的方波频率为1000000/(716+716)=698Hz
                                 //即为高8度的Do的频率(349.2Hz*2)
                case 4:        Beep(638); break;//Key4事件,使用蜂鸣器发So
                                 //这里的参数为638,即产生一个低电平和高电平均为638us的方波
                                 //得到的方波频率为1000000/(638+638)=784Hz
                                 //即为高8度的Do的频率(392Hz*2)
                case 5:        Beep(568); break;//Key5事件,使用蜂鸣器发La
                                 //这里的参数为568,即产生一个低电平和高电平均为568us的方波
                                 //得到的方波频率为1000000/(568+568)=880Hz
                                 //即为高8度的Do的频率(440Hz*2)
                case 6:        Beep(506); break;//Key6事件,使用蜂鸣器发Si
                                 //这里的参数为506,即产生一个低电平和高电平均为506us的方波
                                 //得到的方波频率为1000000/(506+506)=988Hz
                                 //即为高8度的Do的频率(493.8Hz*2)
                case 7:        Beep(478); break;//Key7事件,使用蜂鸣器发Do
                                 //这里的参数为478,即产生一个低电平和高电平均为478us的方波
                                 //得到的方波频率为1000000/(478+478)=1046Hz
                                 //即为高两个8度的Do的频率(261.6Hz*2*2)
                }
        }
}

void ScanKey(void)                                //检测按键状态
{
        unsigned char key;                        //按键扫描键码
       
        key        = 0xff;                                        //初始化扫描变量
        P0 = 0xff;                                        //P0输出输出高使能内部若上拉,准备读取按键状态
        P06        = 0; P07 = 1;                        //准备扫描第1行
        _nop_();                                        //等待2个nop再读取按键状态
        _nop_();
        if (!P00) key =        0;                        //检查第1行第1列按键是否被按下
        else if        (!P01) key = 1;                //检查第1行第2列按键是否被按下
        else if        (!P02) key = 2;                //检查第1行第3列按键是否被按下
        else if        (!P03) key = 3;                //检查第1行第4列按键是否被按下
        else                                                //如果第一行没有按键按下则扫描下一行
        {
                P07        = 0;                                //准备扫描第2行
                P06        = 1;
                _nop_();                                //等待2个nop再读取按键状态
                _nop_();
                if (!P00) key =        4;                //检查第2行第1列按键是否被按下
                else if        (!P01) key = 5;        //检查第2行第2列按键是否被按下
                else if        (!P02) key = 6;        //检查第2行第3列按键是否被按下
                else if        (!P03) key = 7;        //检查第2行第4列按键是否被按下
        }
        P0 = 0xff;                                        //恢复P0口状态
       
        if (key        != keycode)                        //判断按键状态是否有变化
        {
                keycode        = key;                        //保存键码
                debounce = 5;                        //初始化去抖动变量
        }
        else
        {
                if (debounce !=        0)                //是否
                {
                        if (--debounce == 0)//判断去抖动是否已经完成
                        {
                                if (keycode        != 0xff) //判断是松开按键还是按下按键,键码为0表示是松开按键,非0为按下按键
                                {
                                        keyok =        1;        //设置按键按下标志
                                        printf_usb("Key%d被按下\r\n", keycode);
                                }
                        }
                }
        }
}

void main(void)
{
        EAXFR =        1;                                        //允许访问扩展的特殊寄存器,XFR
        WTST = 0;                                        //设置取程序代码等待时间,赋值为 0 表示不等待,程序以最快速度运行
        CKCON =        0;                                        //设置访问片内的xdata速度,赋值为 0        表示用最快速度访问,不增加额外的等待时间
        P0M0 = 0x00; P0M1 =        0x00;        //设置 P0 口为准双向口模式
        P1M0 = 0x00; P1M1 =        0x00;        //设置 P1 口为准双向口模式
        P2M0 = 0x00; P2M1 =        0x00;        //设置 P2 口为准双向口模式
        P3M0 = 0x00; P3M1 =        0x00;        //设置 P3 口为准双向口模式
        P4M0 = 0x00; P4M1 =        0x00;        //设置 P4 口为准双向口模式
        P5M0 = 0x01; P5M1 =        0x00;        //设置 P5.0        口为强推挽,        其他设置为准双向口模式
        P6M0 = 0x00; P6M1 =        0x00;        //设置 P6 口为准双向口模式
        P7M0 = 0x00; P7M1 =        0x00;        //设置 P7 口为准双向口模式
        keycode        = 0xff;                                //初始化键码(0~7为有效键码,0xff为无效键码)
        keyok =        0;                                        //初始化按键标志

        usb_init();                                        //USB 接口配置
        EA = 1;                                                //打开总中断

        P50        = 0;                                        //关闭蜂鸣器
        P40        = 0;                                        //打开LED部分的供电
        BootLogo();                                        //显示开机画面,        8个LED同时闪烁3次

        while(1)
        {                                                        //假定整个主循环的执行时间为10ms左右
                ScanKey();                                //按键扫描
                KeyEvents();                        //按键事件处理
          
                DetectTemp();                        //温度检查任务
                ControlTemp();                        //温度控制任务
                OtherEvent();                        //其他事件
        }
}


zhaoyun189911 发表于 昨天 22:58

乘风飞扬 发表于 2025-6-16 09:30
最好放在主循环里,中断里面尽量不要放太多程序,避免影响其他中断的响应速度。 ...

收到感谢
页: 1 2 [3]
查看完整版本: [分享]简单的按键扫描程序