找回密码
 立即注册
查看: 30|回复: 5

ADC按键按下后无法保留值

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:7
  • 最近打卡:2025-05-02 00:25:35
已绑定手机

4

主题

19

回帖

84

积分

注册会员

积分
84
发表于 昨天 21:51 | 显示全部楼层 |阅读模式
手头用Ai8051U做ADC按键实验。希望按下按键后,数码管显示按键值,无按键按下时保留之前按键的值。代码如下。

目前的问题是虽然按下后能够正常显示按键值,但是一旦松开,按键值便归零。理解是之前的值无法存在静态变量key_num中,不知道原因是什么,还望达人指教。

main文件
  1. void main(void)
  2. {
  3.     //<<AICUBE_USER_MAIN_INITIAL_BEGIN>>
  4.     static u8 key_num;
  5.     //<<AICUBE_USER_MAIN_INITIAL_END>>
  6.     SYS_Init();
  7.     while (1)
  8.     {
  9.         WDT_Clear();                    //清看门狗定时器
  10.         //<<AICUBE_USER_MAIN_LOOP_BEGIN>>
  11.                 key_num=adc_key_scan();
  12.                 if(key_num!=0x10)
  13.                         digit_num(key_num);
  14.         //<<AICUBE_USER_MAIN_LOOP_END>>
  15.     }
  16. }
复制代码
ADC文件
  1. void ADC_Init(void)
  2. {
  3.     ADC_SetClockDivider(15);            //设置ADC时钟
  4.     ADC_ResultRightAlign();             //设置ADC结果右对齐(12位结果)
  5.     ADC_SetRepeat16Times();             //ADC自动重复转换16次并取平均值
  6.     ADC_SetCSSetupCycles(0);            //设置ADC通道选择建立时间
  7.     ADC_SetCSHoldCycles(1);             //设置ADC通道选择保持时间
  8.     ADC_SetSampleDutyCycles(9);         //设置ADC通道采样时间
  9.     ADC_DisableETR();                   //禁止ADC外部触发功能
  10.     ADC_ActiveChannel(0);               //选择ADC通道
  11.     ADC_Enable();                       //使能ADC功能
  12.     //<<AICUBE_USER_ADC_INITIAL_BEGIN>>
  13.     P1M0 &= ~0x01; P1M1 |= 0x01;   //P10高阻输入
  14.     //<<AICUBE_USER_ADC_INITIAL_END>>
  15. }
  16. ////////////////////////////////////////
  17. // 获取ADC转换结果函数
  18. // 入口参数: ch (ADC通道选择)
  19. // 函数返回: ADC转换结果
  20. ////////////////////////////////////////
  21. uint16_t ADC_Convert(uint8_t ch)
  22. {
  23.     uint16_t res;                       //定义保存ADC结果的变量
  24.     ADC_ActiveChannel(ch);              //选择ADC通道
  25.     ADC_Start();                        //开始ADC转换
  26.     while (!ADC_CheckFlag());           //等待ADC转换完成
  27.     ADC_ClearFlag();                    //清除ADC转换完成中断标志
  28.     res = ADC_ReadResult();             //读取ADC转换结果
  29.     return res;                         //返回ADC结果
  30. }
  31. //<<AICUBE_USER_FUNCTION_IMPLEMENT_BEGIN>>
  32. u8 adc_key_scan(void)
  33. {
  34.         u8 key_num=0x10,i;
  35.         u8 error=128;
  36.         u16 adc_val=ADC_Convert(0);
  37.        
  38.         for(i=0;i<16;i++)
  39.         {
  40.                 if(adc_val>256*(i+1)-error && adc_val<256*(i+1)+error)
  41.                 {
  42.                         key_num=i;
  43.                         break;
  44.                 }                       
  45.         }
  46.         return key_num;
  47. }
复制代码


回复

使用道具 举报 送花

3

主题

1160

回帖

1031

积分

等待验证会员

积分
1031
发表于 昨天 21:53 | 显示全部楼层
针对ADC按键值无法保留的问题,结合代码和硬件设计分析如下:

一、问题定位分析
1.1 变量作用域与更新逻辑
代码中keynum被定义为静态局部变量,但其作用域仅存在于main()函数的一次调用周期内。虽然static关键字使其生命周期延长,但每次进入循环时都会重新执行keynum=adckeyscan(),导致无按键时keynum被强制覆盖为0x10(假设此时adckeyscan()返回0x10)。此时digitnum(keynum)仅在有按键时更新显示,无按键时数码管失去刷新信号,可能显示残留值或归零。

1.2 ADC按键扫描逻辑
问题可能源于adckeyscan()函数的返回值逻辑:
预期行为:无按键时返回无效值(如0x10),有按键时返回实际键值。
实际现象:无按键时可能返回0或错误值,导致keynum被错误覆盖。

1.3 数码管刷新机制
数码管需持续刷新以维持显示。若仅在检测到按键时调用digitnum(),则无按键时显示内容可能因未刷新而丢失。建议采用独立于按键检测的持续刷新机制。

二、解决方案
2.1 优化变量更新逻辑
修改keynum更新逻辑,使其仅在检测到有效按键时更新:
  1. c
  2. void main(void)
  3. {
  4.     static u8 keynum = 0;     // 初始化为默认值
  5.     u8 currentkey;
  6.     SYSInit();
  7.     while (1)
  8.     {
  9.         WDTClear();
  10.         currentkey = adckeyscan();
  11.         if (currentkey != 0x10)   // 仅当检测到有效按键时更新keynum
  12.         {
  13.             keynum = currentkey;
  14.         }
  15.         digitnum(keynum);        // 持续刷新显示当前键值
  16.     }
  17. }
复制代码

2.2 验证ADC按键扫描函数
检查adckeyscan()的返回值逻辑:
无按键时:应返回明确的无效标识(如0x10),而非0或其他可能与实际键值冲突的值。
按键按下时:返回正确的键值(如0x00~0x0F)。

示例修正代码片段:
  1. c
  2. u8 adckeyscan(void)
  3. {
  4.     u16 adcval = ADCRead(KEYCHANNEL);  // 假设KEYCHANNEL为按键ADC通道
  5.     if (adcval < THRESHOLDLOW)          // 低于阈值视为无按键
  6.     {
  7.         return 0x10;
  8.     }
  9.     else
  10.     {
  11.         return (adcval - THRESHOLDLOW) / STEP;  // 计算键值
  12.     }
  13. }
复制代码

2.3 增加去抖动处理
在ADC按键扫描中增加软件去抖动,避免误判:
  1. c
  2. u8 adckeyscan(void)
  3. {
  4.     static u8 debouncecnt = 0;
  5.     u16 adcval = ADCRead(KEYCHANNEL);
  6.     if (adcval < THRESHOLDLOW)
  7.     {
  8.         debouncecnt = 0;
  9.         return 0x10;                // 无按键
  10.     }
  11.     else
  12.     {
  13.         if (debouncecnt < DEBOUNCEMAX)
  14.         {
  15.             debouncecnt++;
  16.             return 0x10;            // 去抖动期间仍返回无效值
  17.         }
  18.         else
  19.         {
  20.             return calculatekey(adcval);  // 返回稳定键值
  21.         }
  22.     }
  23. }
复制代码

三、硬件配置建议
1. ADC参考电压稳定性  
   确保VREF引脚连接稳定电源,避免电压波动导致ADC值漂移。

2. 按键分压网络设计  
   采用电阻分压网络时,需确保不同按键对应的ADC值间隔足够大(建议>50 LSB),避免阈值重叠。

3. 抗干扰设计  
在ADC输入引脚添加0.1μF滤波电容。
若MCU支持,启用内部参考电压(如1.25V或2.5V)以提高抗干扰能力。

四、调试方法
1. ADC原始值打印  
   通过串口输出ADC原始值,验证按键按下/释放时的实际电压是否稳定。

2. 断点调试  
   在adckeyscan()中设置断点,观察无按键时返回值是否为0x10。

3. 静态变量监控  
   使用调试工具监控keynum的值,确认其在无按键时是否被错误覆盖。

五、总结
问题根源在于按键值更新逻辑与显示刷新机制未解耦,且adckeyscan()可能未正确返回无效键标识。通过分离键值更新与显示刷新、优化ADC扫描逻辑,并增加去抖动处理,可确保数码管稳定显示最后一次有效按键值。建议通过上述分步调试方法验证硬件和软件行为,确保系统鲁棒性。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:55
  • 最近打卡:2025-05-02 08:32:59

718

主题

1万

回帖

1万

积分

管理员

积分
15630
发表于 12 小时前 | 显示全部楼层
2个 深圳大学 ADC 的实验程序

Project-实战数码管 ADC按键扫描.zip

41.39 KB, 下载次数: 2

Project-实战数码管 ADC测温.zip

40.29 KB, 下载次数: 1

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:51
  • 最近打卡:2025-05-02 10:07:51

73

主题

5883

回帖

1万

积分

超级版主

积分
12079
发表于 10 小时前 | 显示全部楼层
这是你的程序逻辑问题。
你应该检测按键按下的动作,有按下就更新显示键值,

释放或无按下动作都不更新显示就可以了,简单的逻辑处理。
你可以参考官方的学习板例子。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:424
  • 最近打卡:2025-05-02 14:37:11
已绑定手机

77

主题

4849

回帖

8382

积分

超级版主

DebugLab

积分
8382
发表于 6 小时前 | 显示全部楼层
按下后更新键值,松开不做操作
声明一个是否按下的标志位来判断
DebugLab
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:7
  • 最近打卡:2025-05-02 00:25:35
已绑定手机

4

主题

19

回帖

84

积分

注册会员

积分
84
发表于 5 小时前 | 显示全部楼层
终于搞定了。我将ADC转换函数加入到定时器中断,使其间隔100ms运行一次就好了(至少要间隔50ms)。猜想是ADC转换需要一定的时间,如果两次转换函数间隔时间太近,会对全局变量存储结果产生影响,导致其无法存储上一次按下的值。(但仅仅是猜想,不知道准确的原因如何描述)
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-2 20:54 , Processed in 0.131373 second(s), 89 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表