xianfajushi 发表于 2025-4-21 14:28 按键比较多,不可能同时。 而且读取时间间隔也必须越小越好,比如纳秒级别。 否则就只能是对每个按键引入中断,在中断里面固定证据。然后再判定,这样会好一些。 再不行就只有纯硬件了。 |
xiaobendan001 发表于 2025-4-19 15:28 如果整组判断就不会出现因程序造成的不公平问题。 |
以下是对该程序的问题分析及修改建议: ### 一、程序问题分析 1. **按键检测与消抖** - 在`key1`和`key2`函数中,按键检测部分虽然有简单的延时消抖(`delay10ms()` ),但不够完善。对于按键释放的检测没有处理,可能导致按键误触发。比如在`key1`函数中,当检测到`S12`按键按下并进行一系列操作后,没有等待按键释放就继续检测其他按键,可能会在按键还未完全释放时再次检测到按键按下,造成逻辑混乱。 - `switch`语句中对端口数据的处理逻辑有误。在`switch(P3&&0xff)`和`switch(P2&&0xff)`中,这种写法不能准确获取端口的实际电平状态。应该直接使用`P3`和`P2`进行判断,即`switch(P3)`和`switch(P2)` 。 2. **定时器相关问题** - 在`timer0`中断函数中,只对倒计时进行了处理,没有对定时时间到且无人抢答的情况进行全面处理。当`qdtime`减为0时,应该禁止后续的抢答操作,而当前代码没有相关设置。 - `count`变量用于计数中断次数以实现倒计时,但在初始化时没有清零,可能导致初始倒计时不准确。 3. **数码管显示问题** - `shumaxs`函数中,数码管位选逻辑存在问题。在给不同位数码管赋值时,位选信号没有及时关闭,可能会导致数码管显示混乱。比如在给高位数码管赋值后,没有关闭其位选信号就给低位数码管赋值,会使数码管显示出现重叠或错误的现象。 - 数码管显示程序没有考虑到不同情况下显示的切换逻辑。例如,在无人抢答定时时间到的情况下,应该显示特定的标识(如“00” ),但当前代码在这种情况下显示处理不够完善。 4. **抢答逻辑问题** - 选手抢答标记数组`S`的使用逻辑有误。在`key1`函数中,每次检测到抢答开始(`S12`按下 )就将所有选手的标记位归零,这会导致之前已经按下抢答按钮的选手标记被清除,无法实现优先锁存的功能。 - 没有对多个选手同时抢答的情况进行处理。当多个选手同时按下抢答按钮时,当前代码不能准确判断并锁存最先抢答的选手编号。 ### 二、修改建议 1. **按键检测与消抖改进** - 在`key1`和`key2`函数中,完善按键检测逻辑,增加按键释放检测。例如,在检测到按键按下并进行操作后,添加一个循环等待按键释放: ```c while(S12 == 1); // 等待S12按键释放 ``` - 修正`switch`语句中对端口数据的判断方式,直接使用端口值进行判断,如: ```c switch(P3) { case 0x7f: num_mark = 1; LED1 = 0; break; case 0xbf: num_mark = 2; LED2 = 0; break; // 其他case语句类似 } switch(P2) { case 0x7f: num_mark = 9; LED9 = 0; break; case 0xbf: num_mark = 10; LED10 = 0; break; } ``` 2. **定时器相关改进** - 在`timer0`中断函数中,当`qdtime`减为0时,添加禁止抢答的逻辑,例如设置一个标志位: ```c if(count == 20) { count = 0; qdtime--; if(qdtime == 0) { // 设置禁止抢答标志位,比如定义一个全局变量 no_answer_flag = 1; no_answer_flag = 1; } } ``` - 在初始化时,将`count`变量清零: ```c void Timer0_init (void) { TMOD = 0x01; TH0 = 0x3c; TL0 = 0xb0; ET0 = 1; EA = 1; count = 0; // 初始化count为0 // TR0 = 0; } ``` 3. **数码管显示改进** - 在`shumaxs`函数中,修改数码管位选逻辑,确保在给一位数码管赋值后及时关闭其位选信号,再给下一位数码管赋值: ```c void shumaxs(int n, uchar m) { int sj1, sj2, dw1, dw2; P0 = 0xff; P1 = 0x00; delay(50); sj1 = n / 10; sj2 = n % 10; dw1 = m / 10; dw2 = m % 10; P0 = LED[sj1]; smg_we4 = 1; delay(20); smg_we4 = 0; // 关闭位选信号 P0 = LED[sj2]; smg_we3 = 1; delay(20); smg_we3 = 0; P0 = LED[dw1]; smg_we2 = 1; delay(20); smg_we2 = 0; P0 = LED[dw2]; smg_we1 = 1; delay(20); smg_we1 = 0; } ``` - 在主程序和相关函数中,完善不同情况下数码管显示的逻辑。例如,在无人抢答定时时间到的情况下,修改`shumaxs`函数的调用参数以显示“00”: ```c if((qdtime == 0) && (num_mark == 0)) { TR0 = 0; shumaxs(0, 0); // 显示00 BEEP2(); } ``` 4. **抢答逻辑改进** - 修正选手抢答标记数组`S`的使用逻辑。在检测到有选手抢答后,只修改该选手对应的标记位,而不是将所有标记位归零。例如: ```c if(S1 == 0) { S[1] = 0; num_mark = 1; LED1 = 0; } else if(S2 == 0) { S[2] = 0; num_mark = 2; LED2 = 0; } // 其他选手类似 ``` - 增加对多个选手同时抢答的处理逻辑。可以记录最早检测到的抢答选手编号,例如在检测到有选手抢答时,记录当前时间(通过定时器计数值等方式 ),比较不同选手抢答时的时间,优先锁存时间最早的选手编号。 通过以上修改,可以在一定程度上解决程序中存在的问题,使其更符合抢答器的功能要求。在实际调试过程中,还需要进一步根据具体现象进行优化和调整。 |
这种按键判定方式有问题,假设同一时刻有多个按键按下,那么接P3高位的就优先被判定,然而事实上极大可能是相对低位的按键先按下,只是在你读取之前,相对高位的按键也按下了,此时你读到的是2个位为0的数据,但是你在先判定了高位的就是后按下的那个之后便不再理会相对低位的那个开关了,虽然这个时间很短,参赛者只能认倒霉,但是这种情况还是极有可能的。 |
当时提出用锁存器也是一个办法,现在看来从软件上能解决,那是要重写这个程序。 |
622323wjl 发表于 2025-4-17 15:44 这个帖子也翻找出来了,许多年了未知题主还关注不,看看我当时回复挺搞笑的,不知道怎么想的!电路图中数码管没错,代码用阻塞不是很好选择,虽然是独立按键,但是整组使用时可以不单独定义,整组判断可对应一个按键操作,赋值255判断是否不等于255就有按键按下,特定值对应一个按键,另外2个按键可独立定义,按键写中断不是很好选择,尤其还有阻塞参与其中,按键要求尽量快判断结束,不影响数码管显示时间。 |
你好! 从你描述的情况来看,程序对应要求的错误还很多; 只能根据你的要求,把程序分功能模块逐段调试。 |
xianfajushi 发表于 2020-1-2 08:36 好的,谢谢 |
51hei**1140 发表于 2020-1-1 20:48 好的,谢谢! |
用蛋骗鸡直接驱动数码管出现的问题,必须要用三极管或锁存器驱动数码管,你这是常见的驱动设计问题 |
你好! 从你描述的情况来看,程序对应要求的错误还很多; 只能根据你的要求,把程序分功能模块逐段调试。 |