找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1356|回复: 14
打印 上一主题 下一主题
收起左侧

51单片机内部两路ADC采集

[复制链接]
跳转到指定楼层
楼主
ID:350682 发表于 2024-11-5 23:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
请问一下,用了一块国产的51单片机CA51F005,内部有12个通道的ADC,但是好像不能同时使能两个通道,现在我需要用一路AD去检测按键(两个按键,通过电压识别),一路AD检测电池电压,按键的检测是在定时器里面实现的,定时10ms,电压检测直接在主函数的while循环中,现在遇到一个问题,另个功能同时使用的话,按键电压检测到了,但是不去做相应的处理(处理在while循环中,在定时器中根据按键状态,写了一个标志位,然后根据标志位在while中处理)。调试运行的时候,每次停止运行,程序就都停在等待AD转换完成这里。
  1. void ADC_Init(void)
  2. {
  3.         KEY_GPIO_ADC_SET(); //设置IO为ADC功能
  4.         BAT_GPIO_ADC_SET();
  5.         ADCON = AST(0) | ADIE(0) | HTME(7) | VSEL(ADC_REF_VDD);                //设置ADC参考电压
  6.         ADOPC = GAIN(NO_AMP);
  7. }

  8. float read_adc(unsigned char adc_ch)
  9. {
  10.         unsigned int AD_Value;
  11.         ADCFGL = ACKD(7) | ADCALE(1) | ADCHS(adc_ch);        //选择ADC通道
  12.         ADCON |= AST(1);   //启动ADC转换
  13.         while(!(ADCON & ADIF));//等待转换完成
  14.         ADCON |= ADIF;         //清除中断标志
  15.         AD_Value = ADCDH*256 + ADCDL;                                                //读取AD值
  16.         AD_Value >>= 4;       
  17.        
  18.         VDD_Voltage = ((double)AD_Value*3.0)/4095;
  19.        
  20.         return VDD_Voltage;
  21. }
复制代码

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:1133081 发表于 2024-11-6 06:28 | 只看该作者
不论MCU内部有多少个ADC通道,AD转换电路只有一套,通过选择开关实现多路AD转换。多路AD转换必须轮流执行。编程时一定要等待前一次转换结束后才能执行下一次转换。楼主在主函数和中断中分别使用AD转换,发生冲突是大概率事件。
回复

使用道具 举报

板凳
ID:350682 发表于 2024-11-6 09:14 | 只看该作者
WL0123 发表于 2024-11-6 06:28
不论MCU内部有多少个ADC通道,AD转换电路只有一套,通过选择开关实现多路AD转换。多路AD转换必须轮流执行。 ...

啊这,该怎样解决这个问题?
回复

使用道具 举报

地板
ID:857072 发表于 2024-11-6 09:48 来自触屏版 | 只看该作者
互锁呗,在开始读ad做一个标记读完了取消标记,然后每次读adc值之前查看这个标记 如果这个标记被占用了 说明有其他地方在用 就不要读了
回复

使用道具 举报

5#
ID:1109793 发表于 2024-11-6 10:04 | 只看该作者
该ADC不支持中断吗?
回复

使用道具 举报

6#
ID:624769 发表于 2024-11-6 10:43 | 只看该作者
要什么定时器啊? ADC闲着也是闲着, 读完按键读电压,读完电压读电池,周而复始的读,把读到的值分别存到  KeyValue, VoltValue, 两个变量, 最多就是你定时中断每 10ms 去 keyValue 里面读最新数据就好了。
回复

使用道具 举报

7#
ID:350682 发表于 2024-11-7 10:49 | 只看该作者
188610329 发表于 2024-11-6 10:43
要什么定时器啊? ADC闲着也是闲着, 读完按键读电压,读完电压读电池,周而复始的读,把读到的值分别存到   ...

因为要扫描按键,我设置的10ms扫描一次,扫描按键前要读ADC判断是哪一个按键。我要实现按键的单击、长按和双击
回复

使用道具 举报

8#
ID:350682 发表于 2024-11-7 10:51 | 只看该作者
xiaobendan001 发表于 2024-11-6 10:04
该ADC不支持中断吗?

支持,只是不需要用中断吧,不熟悉51,所以问题一大堆
回复

使用道具 举报

9#
ID:350682 发表于 2024-11-7 10:52 | 只看该作者
a185980800 发表于 2024-11-6 09:48
互锁呗,在开始读ad做一个标记读完了取消标记,然后每次读adc值之前查看这个标记 如果这个标记被占用了 说 ...

这会不会影响我读按键呀,我10ms扫描一次按键状态
回复

使用道具 举报

10#
ID:624769 发表于 2024-11-7 15:35 | 只看该作者
piscest_x 发表于 2024-11-7 10:49
因为要扫描按键,我设置的10ms扫描一次,扫描按键前要读ADC判断是哪一个按键。我要实现按键的单击、长按 ...

你ADC 就在主循环里 反复 读键值/电压,  键值存到 变量 A1,  电压存到 变量 A2,  
你定时器 每10ms 中断一次,去读 变量A1 知道最近一次的 结果 来判断 长按,短按,和双击 不就行了?
回复

使用道具 举报

11#
ID:350682 发表于 2024-11-7 21:26 | 只看该作者
188610329 发表于 2024-11-7 15:35
你ADC 就在主循环里 反复 读键值/电压,  键值存到 变量 A1,  电压存到 变量 A2,  
你定时器 每10ms 中 ...

现在放在主函数是可以了,但是单击识别按键不灵敏,按下按键不是每次都能精确识别。
  1. void TIMER0_ISR (void) interrupt 1 //定时10ms
  2. {
  3.         TH0  = TH_VAL;                //高8位装初值
  4.         TL0  = TL_VAL;                //低8位装初值

  5.         key1_readStatus();
  6.         key2_readStatus();
  7.         if(key1_event == SINGLE_KEY)       //单击
  8.         {
  9.                 key1_single_flag = 1;
  10.         }
  11.         else if(key1_event == DOUBLE_KEY)  //双击
  12.         {
  13.                 key1_double_flag = 1;
  14.         }
  15.         else if(key1_event == LONG_KEY)   //长按
  16.         {
  17.                 key1_long_flag = 1;
  18.         }
  19.         /****************************************/
  20.         if(key2_event == SINGLE_KEY)       //单击
  21.         {
  22.                 key2_single_flag = 1;
  23.         }
  24.         else if(key2_event == DOUBLE_KEY)  //双击
  25.         {
  26.                 key2_double_flag = 1;
  27.         }
  28.         else if(key2_event == LONG_KEY)   //长按
  29.         {
  30.                 key2_long_flag = 1;
  31.         }
  32. }
复制代码


这是定时器里面的处理
回复

使用道具 举报

12#
ID:350682 发表于 2024-11-7 21:27 | 只看该作者
188610329 发表于 2024-11-7 15:35
你ADC 就在主循环里 反复 读键值/电压,  键值存到 变量 A1,  电压存到 变量 A2,  
你定时器 每10ms 中 ...
  1. void key1_readStatus(void)
  2. {
  3.         switch(key1_state)
  4.         {
  5.                 case KEY_STATUS_0:               //无按键按下
  6.                         if(key1_flag)                  //如果按键1按下
  7.                         {
  8.                                 key1_state = KEY_STATUS_1;    //进入下一状态:消抖
  9.                                 key1_event = NO_KEY;          //第一次按键按下,事件为空
  10.                         }
  11.                         else
  12.                         {
  13.                                 key1_state = KEY_STATUS_0;    //回到无按键状态或者第二次按下前状态
  14.                                 key1_event = NO_KEY;
  15.                         }
  16.                         break;
  17.                 case KEY_STATUS_1:               /* 消抖 */
  18.                         if(key1_flag)                  //如果按键1按下
  19.                         {
  20.                                 key1_state = KEY_STATUS_2;    //进入下一状态:继续按下
  21.                                 key1_event = NO_KEY;
  22.                         }
  23.                         else
  24.                         {
  25.                                 key1_state = KEY_STATUS_0;    //回到初始状态
  26.                                 key1_event = NO_KEY;
  27.                         }
  28.                         break;
  29.                 case KEY_STATUS_2:              /* 确认按下 */
  30.                         if(key1_flag && key1_count >= KEY_LONG_TIME)
  31.                         {
  32.                                 key1_state = KEY_STATUS_3;   //进入下一状态:长按
  33.                                 key1_event = NO_KEY;
  34.                                 key1_count = 0;
  35.                         }
  36.                         else if(key1_flag && key1_count < KEY_LONG_TIME)
  37.                         {
  38.                                 key1_count++;
  39.                                 key1_state = KEY_STATUS_2;   //进入下一状态:确认按下
  40.                                 key1_event = NO_KEY;
  41.                         }
  42.                         else
  43.                         {
  44.                                 key1_count = 0;
  45.                                 key1_state = KEY_STATUS_4;   //进入下一状态:等待第二次按下
  46.                                 key1_event = NO_KEY;
  47.                         }
  48.                         break;
  49.                 case KEY_STATUS_3:              //长按状态
  50.                         if(key1_flag)
  51.                         {
  52.                                 key1_state = KEY_STATUS_3;   //一直等待按键放开
  53.                                 key1_event = NO_KEY;
  54.                                 key1_count = 0;
  55.                         }
  56.                         else
  57.                         {
  58.                                 key1_state = KEY_STATUS_0;
  59.                                 key1_event = LONG_KEY;
  60.                                 key1_count = 0;
  61.                         }
  62.                         break;
  63.                 case KEY_STATUS_4:               /* 等待第二次按下 */
  64.                         if(!key1_flag&&key1_count>=KEY_WAIT_TIME) //如果按键松开,且时间大于等待第二次按下的时间
  65.                         {
  66.                                 key1_count = 0;
  67.                                 key1_state = KEY_STATUS_0;
  68.                                 key1_event = SINGLE_KEY;           //判定为单击
  69.                         }
  70.                         else if(!key1_flag&&key1_count<KEY_WAIT_TIME)
  71.                         {
  72.                                 key1_count++;
  73.                                 key1_state = KEY_STATUS_4;         //继续等待
  74.                                 key1_event = NO_KEY;
  75.                         }
  76.                         else
  77.                         {
  78.                                 key1_count = 0;
  79.                                 key1_state = KEY_STATUS_5;         //第二次按下,且时间未到
  80.                                 key1_event = NO_KEY;
  81.                         }
  82.                         break;
  83.                 case KEY_STATUS_5:                    /* 第二次按下 */
  84.                         if(key1_flag && key1_count >= KEY_LONG_TIME)
  85.                         {
  86.                                 key1_state = KEY_STATUS_3;         //第二次按下,时间大于长按时间
  87.                                 key1_event = SINGLE_KEY;           //先响应单击
  88.                                 key1_count = 0;
  89.                         }
  90.                         else if(key1_flag && key1_count < KEY_LONG_TIME)
  91.                         {
  92.                                 key1_count++;
  93.                                 key1_state = KEY_STATUS_5;         //等待按键松开
  94.                                 key1_event = NO_KEY;
  95.                         }
  96.                         else
  97.                         {
  98.                                 key1_count = 0;
  99.                                 key1_state = KEY_STATUS_0;         //等待按键松开
  100.                                 key1_event = DOUBLE_KEY;           //判定为双击
  101.                         }
  102.                         break;
  103.                 default:break;
  104.         }
  105. }
复制代码

这个是识别按键状态
回复

使用道具 举报

13#
ID:350682 发表于 2024-11-7 21:32 | 只看该作者
188610329 发表于 2024-11-7 15:35
你ADC 就在主循环里 反复 读键值/电压,  键值存到 变量 A1,  电压存到 变量 A2,  
你定时器 每10ms 中 ...
  1. void key_scan(void)
  2. {
  3.         float key_press;
  4.         key_press = read_adc(8);
  5.         if(key_press >=0&&key_press<1.0) //按键1
  6.         {
  7.                 key1_flag = 1;
  8.                 key2_flag = 0;
  9.         }
  10.         else if(key_press >=1.45&&key_press <1.65) //按键2
  11.         {
  12.                 key2_flag = 1;
  13.                 key1_flag = 0;
  14.         }
  15.         else if(key_press >2.9) //无按键
  16.         {
  17.                 key1_flag = 0;
  18.                 key2_flag = 0;
  19.         }
  20. }
复制代码

这个是识别按键的,我放在主函数while循环里面了,然后最后的处理也在while 循环里面
  1. while(1)
  2. {
  3.         key_scan();//读取电压,判断是那个按键按下
  4.         if(key1_double_flag)   //双击旋转屏幕
  5.         {
  6.                 key1_double_flag = 0;
  7.                 something();
  8.         }
  9.         else if(key1_long_flag)//长按当前通道清零
  10.         {
  11.                 key1_long_flag = 0;
  12.                something();
  13.         }
  14. }
复制代码
回复

使用道具 举报

14#
ID:1135890 发表于 2024-11-8 15:14 | 只看该作者
您好,锦锐单片机为您服务,您在开发的是CA51F005T3 TSSOP20的型号,技术问题可以联系我,我安排FAE协助您。
回复

使用道具 举报

15#
ID:1135890 发表于 2024-11-8 16:46 | 只看该作者

您们好,锦锐单片机为您服务。

有需要请私信我安排FAE
回复

使用道具 举报

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

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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