mechray 发表于 昨天 21:51

ADC按键按下后无法保留值

手头用Ai8051U做ADC按键实验。希望按下按键后,数码管显示按键值,无按键按下时保留之前按键的值。代码如下。

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

main文件
void main(void)
{
    //<<AICUBE_USER_MAIN_INITIAL_BEGIN>>
    static u8 key_num;
    //<<AICUBE_USER_MAIN_INITIAL_END>>

    SYS_Init();

    while (1)
    {
      WDT_Clear();                  //清看门狗定时器

      //<<AICUBE_USER_MAIN_LOOP_BEGIN>>
                key_num=adc_key_scan();
                if(key_num!=0x10)
                        digit_num(key_num);

      //<<AICUBE_USER_MAIN_LOOP_END>>
    }
}ADC文件
void ADC_Init(void)
{
    ADC_SetClockDivider(15);            //设置ADC时钟
    ADC_ResultRightAlign();             //设置ADC结果右对齐(12位结果)
    ADC_SetRepeat16Times();             //ADC自动重复转换16次并取平均值

    ADC_SetCSSetupCycles(0);            //设置ADC通道选择建立时间
    ADC_SetCSHoldCycles(1);             //设置ADC通道选择保持时间
    ADC_SetSampleDutyCycles(9);         //设置ADC通道采样时间

    ADC_DisableETR();                   //禁止ADC外部触发功能

    ADC_ActiveChannel(0);               //选择ADC通道
    ADC_Enable();                     //使能ADC功能

    //<<AICUBE_USER_ADC_INITIAL_BEGIN>>
    P1M0 &= ~0x01; P1M1 |= 0x01;   //P10高阻输入
    //<<AICUBE_USER_ADC_INITIAL_END>>
}

////////////////////////////////////////
// 获取ADC转换结果函数
// 入口参数: ch (ADC通道选择)
// 函数返回: ADC转换结果
////////////////////////////////////////
uint16_t ADC_Convert(uint8_t ch)
{
    uint16_t res;                     //定义保存ADC结果的变量

    ADC_ActiveChannel(ch);            //选择ADC通道
    ADC_Start();                        //开始ADC转换
    while (!ADC_CheckFlag());         //等待ADC转换完成
    ADC_ClearFlag();                  //清除ADC转换完成中断标志
    res = ADC_ReadResult();             //读取ADC转换结果

    return res;                         //返回ADC结果
}


//<<AICUBE_USER_FUNCTION_IMPLEMENT_BEGIN>>

u8 adc_key_scan(void)
{
        u8 key_num=0x10,i;
        u8 error=128;
        u16 adc_val=ADC_Convert(0);
       
        for(i=0;i<16;i++)
        {
                if(adc_val>256*(i+1)-error && adc_val<256*(i+1)+error)
                {
                        key_num=i;
                        break;
                }                       
        }
        return key_num;
}

国芯人工智能 发表于 昨天 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更新逻辑,使其仅在检测到有效按键时更新:
c
void main(void)
{
    static u8 keynum = 0;   // 初始化为默认值
    u8 currentkey;

    SYSInit();

    while (1)
    {
      WDTClear();
      currentkey = adckeyscan();

      if (currentkey != 0x10)   // 仅当检测到有效按键时更新keynum
      {
            keynum = currentkey;
      }

      digitnum(keynum);      // 持续刷新显示当前键值
    }
}

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

示例修正代码片段:
c
u8 adckeyscan(void)
{
    u16 adcval = ADCRead(KEYCHANNEL);// 假设KEYCHANNEL为按键ADC通道
    if (adcval < THRESHOLDLOW)          // 低于阈值视为无按键
    {
      return 0x10;
    }
    else
    {
      return (adcval - THRESHOLDLOW) / STEP;// 计算键值
    }
}

2.3 增加去抖动处理
在ADC按键扫描中增加软件去抖动,避免误判:
c
u8 adckeyscan(void)
{
    static u8 debouncecnt = 0;
    u16 adcval = ADCRead(KEYCHANNEL);

    if (adcval < THRESHOLDLOW)
    {
      debouncecnt = 0;
      return 0x10;                // 无按键
    }
    else
    {
      if (debouncecnt < DEBOUNCEMAX)
      {
            debouncecnt++;
            return 0x10;            // 去抖动期间仍返回无效值
      }
      else
      {
            return calculatekey(adcval);// 返回稳定键值
      }
    }
}

三、硬件配置建议
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扫描逻辑,并增加去抖动处理,可确保数码管稳定显示最后一次有效按键值。建议通过上述分步调试方法验证硬件和软件行为,确保系统鲁棒性。

[本文内容由国芯人工智能辅助生成,仅供参考]

神农鼎 发表于 4 小时前

2个 深圳大学 ADC 的实验程序

梁工 发表于 3 小时前

这是你的程序逻辑问题。
你应该检测按键按下的动作,有按下就更新显示键值,
释放或无按下动作都不更新显示就可以了,简单的逻辑处理。
你可以参考官方的学习板例子。
页: [1]
查看完整版本: ADC按键按下后无法保留值