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
最好放在主循环里,中断里面尽量不要放太多程序,避免影响其他中断的响应速度。 ...
收到感谢