判断两个键同时按下,这里是两个方向键

本文介绍了如何使用Delphi中的GetKeyboardState函数来判断用户是否同时按下上键和左键,通过设置键盘状态变量并进行逻辑判断,实现特定功能的触发。

原文:http://hi.baidu.com/gezhou/blog/item/4bf712b326cc94a2d8335af0.html

使用GetKeyboardState来判断键盘按键状态,判断用户是否同时按下上键和左键

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
var
k :TKeyboardState;
begin
GetKeyboardState(k);
if ((k[vk_up]=128)or(k[vk_up]=129)) and
    ((k[vk_left]=128)or(k[vk_left]=129)) then
    self.Caption := FormatDateTime('yyyy-MM-dd hh:nn:ss',now);
end;


Delphi 判断按键状态

调用GetKeyState(nVirtKey:integer)函数,可以判断是否按下了Alt、Ctrl、Shift键,如果函数返回值<0则表示按下了。
参数:
nVirtKey
    指定一个键。如果指定字母或数字键,nVirtKey 必须为该字符的 ASCII 码值。如:判断‘a’键是否按下使用GetKeyState(65),65是字符‘a’的ASCII码值,关于字符的ASCII码值请参考有关资料。Alt、Ctrl、Shift键使用下面的常量,而不使用ASCII码值。

VK_SHIFT
Shift键

VK_CONTROL
Ctrl键

VK_MENU
Alt键
例子:
function Shift_down():boolean;
//判断是否按下shift键,如果按下返回True,否则返回False
begin

if GetKeyState(VK_SHIFT)<0 then Result:=True else Result:=False;
end;

function Alt_down():boolean;
//判断是否按下Alt键,如果按下返回True,否则返回False
begin

if GetKeyState(VK_MENU)<0 then Result:=True else Result:=False;
end;

function Ctrl_down():boolean;
//判断是否按下Ctrl键,如果按下返回True,否则返回False
begin

if GetKeyState(VK_CONTROL)<0 then Result:=True else Result:=False;
end;

要在 **51单片机**(如 STC15F2K60S2)中实现“**同时按下两个点亮 LED**”,关在于: > ✅ 正确读取 I/O 口电平状态 > ✅ 判断是否两个引脚都为低电平(机械按通常为低有效) > ✅ 避免使用抽象编号做逻辑判断 > ✅ 加入软件消抖以防止误触发 --- ## ✅ 一、目标功能 - 按 S4 接 P3.0,S5 接 P3.1 - 当 **S4 和 S5 同时被按下** 时,点亮一个 LED(例如接在 P4.4) - 其他情况 LED 熄灭 --- ## ✅ 二、完整可运行代码(带消抖) ```c #include <STC15F2K60S2.H> // 宏定义数码管/LED控制(根据你的开发板调整) #define Y4C(x) {P0=x; P2=P2&0x1f|0x80; P2=0x1f;} #define LED_PORT P4 // 假设 LED 接在 P4 口 sbit LED = P4^4; // 定义 LED 引脚(可根据实际修改) // 全局变量 unsigned char cnt_key = 0; // 毫秒计数器,用于消抖 /*定时器0初始化:1ms中断*/ void Timer0_Init(void) { AUXR &= 0x7F; // 12T 模式 TMOD &= 0xF0; TL0 = 0x18; // 1ms @ 12MHz TH0 = 0xFC; TF0 = 0; TR0 = 1; ET0 = 1; // 使能中断 } /*系统初始化*/ void System_Init() { P3 |= 0x0f; // 给 P3.0~P3.3 上拉电阻(按需要上拉) LED_PORT = 0xFF; // 初始关闭所有LED Timer0_Init(); EA = 1; // 开总中断 } /*按扫描 + 组合处理*/ void Key_Process() { static unsigned char key_old = 0; unsigned char key_current; if (cnt_key < 20) return; // 每20ms检测一次,防抖 cnt_key = 0; // 读取当前按状态(低4位) key_current = P3 & 0x0f; // 【核心】判断 S4(P3.0) 和 S5(P3.1) 是否同时按下 // 注意:按按下时为低电平 → bit0 和 bit1 都应为 0 if ((key_current & 0x03) == 0x00) // 即 bit0==0 && bit1==0 { LED = 0; // LED 亮(假设低电平点亮) } else { LED = 1; // LED 灭 } key_old = key_current; // 更新旧状态(可用于上升沿检测等扩展) } /*主函数*/ void main() { System_Init(); while (1) { Key_Process(); // 循环检测按 } } /*定时器中断服务函数:每1ms进入一次*/ void Timer0_Isr(void) interrupt 1 { if (cnt_key < 20) cnt_key++; // 累计到20ms再允许检测 } ``` --- ## 🔍 三、代码解释 ### 1. `P3 |= 0x0f` - 给 P3.0 ~ P3.3 设置内部上拉电阻 - 没有按按下时为高电平(1) - 按下时通过外部接地变为低电平(0) ### 2. `(key_current & 0x03) == 0x00` - `0x03` 是二进制 `0000_0011`,只保留 bit0 和 bit1 - 如果这两个位都是 0 → 表示 S4 和 S5 都被按下 - 这是判断同时按下”的核心条件 ### 3. 消抖机制 - 使用定时器每 1ms 中断一次 - `cnt_key` 计数到 20(即 20ms)才允许检测一次按 - 有效避免机械抖动导致的误判 ### 4. LED 控制 - 假设 LED 接在 P4.4,且低电平点亮 - 你可以改成任意 IO 或控制多个 LED --- ## 🛠 四、硬件连接建议 | 名称 | 连接方式 | |------|----------| | S4 | 一端接 P3.0,另一端接地 | | S5 | 一端接 P3.1,另一端接地 | | LED | 正极接 VCC,负极经限流电阻接 P4.4(共阳极) | > ⚠️ 若你的 LED 是高电平点亮,则交换 `LED=0` 和 `LED=1` --- ## ✅ 五、进阶改进:仅在“刚同时按下”时触发一次 如果你想让 LED **只在“刚刚同时按下”的瞬间点亮并保持**(而不是一直检测),可以用边沿检测: ```c static unsigned char key_old = 0; unsigned char key_current = P3 & 0x0f; unsigned char both_pressed_now = ((key_current & 0x03) == 0x00); unsigned char both_pressed_prev = ((key_old & 0x03) == 0x00); // 下降沿:从“非全按”到“全按” if (!both_pressed_prev && both_pressed_now) { LED = !LED; // 切换LED状态 } key_old = key_current; ``` 这样就实现了“双组合切换LED”。 --- ## ✅ 六、常见问题排查 | 问题 | 解决方法 | |------|-----------| | 按无反应 | 检查 P3 是否开启了上拉(`P3|=0x0f`) | | 单按也触发 | 条件写成 `(key & 0x03)==0` 才行,不能只判断其中一个 | | 抖动严重 | 延长消抖时间至 20~50ms | | LED 不亮 | 检查电路是共阳还是共阴,IO 方向是否正确 | --- ## ✅ 总结 要实现“同时按下两个点亮 LED”,关是: > 🔑 使用原始 I/O 值进行位掩码判断,不要用 switch 转换后的编号! ```c if ((P3 & 0x03) == 0x00) { LED = 0; // 亮 } else { LED = 1; // 灭 } ``` 加上定时器消抖,即可稳定工作。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值