[APM32E0] APM32E030的ADC驱动

[复制链接]
215|7
口天土立口 发表于 2025-9-15 17:24 | 显示全部楼层 |阅读模式
2315668c7daab522c4.png

APM32E030为12位ADC,同时有16个外部通道和2个内部通道。

ADC驱动代码如下:
  1. /*
  2. *  PA0 -> ADC_IN0
  3. *  PA1 -> ADC_IN1
  4. *  PA2 -> ADC_IN2
  5. *  PA3 -> ADC_IN3
  6. *  PA4 -> ADC_IN4
  7. *  PA5 -> ADC_IN5
  8. *  PA6 -> ADC_IN6
  9. *  PA7 -> ADC_IN7
  10. *  PB0 -> ADC_IN8
  11. *  PB1 -> ADC_IN9
  12. *  PC0 -> ADC_IN10
  13. *  PC1 -> ADC_IN11
  14. *  PC2 -> ADC_IN12
  15. *  PC3 -> ADC_IN13
  16. *  PC4 -> ADC_IN14
  17. *  PC5 -> ADC_IN15
  18. */
  19. typedef struct {
  20.     GPIO_T      *port;           
  21.     uint16_t    pin;
  22.     uint32_t    AHBPeriph;
  23.     uint32_t    adc_channel;
  24. } adc_ch_info_t;
  25. /* ADC信息 */
  26. static adc_ch_info_t adc_ch_info[] = {
  27.     {GPIOA,     GPIO_PIN_0,    RCM_AHB_PERIPH_GPIOA,    ADC_CHANNEL_0 },
  28.     {GPIOA,     GPIO_PIN_1,    RCM_AHB_PERIPH_GPIOA,    ADC_CHANNEL_1 },
  29.     {GPIOA,     GPIO_PIN_2,    RCM_AHB_PERIPH_GPIOA,    ADC_CHANNEL_2 },
  30.     {GPIOA,     GPIO_PIN_3,    RCM_AHB_PERIPH_GPIOA,    ADC_CHANNEL_3 },
  31.     {GPIOA,     GPIO_PIN_4,    RCM_AHB_PERIPH_GPIOA,    ADC_CHANNEL_4 },
  32.     {GPIOA,     GPIO_PIN_5,    RCM_AHB_PERIPH_GPIOA,    ADC_CHANNEL_5 },
  33.     {GPIOA,     GPIO_PIN_6,    RCM_AHB_PERIPH_GPIOA,    ADC_CHANNEL_6 },
  34.     {GPIOA,     GPIO_PIN_7,    RCM_AHB_PERIPH_GPIOA,    ADC_CHANNEL_7 },
  35.     {GPIOB,     GPIO_PIN_0,    RCM_AHB_PERIPH_GPIOB,    ADC_CHANNEL_8 },
  36.     {GPIOB,     GPIO_PIN_1,    RCM_AHB_PERIPH_GPIOB,    ADC_CHANNEL_9 },
  37.     {GPIOC,     GPIO_PIN_0,    RCM_AHB_PERIPH_GPIOC,    ADC_CHANNEL_10 },
  38.     {GPIOC,     GPIO_PIN_1,    RCM_AHB_PERIPH_GPIOC,    ADC_CHANNEL_11 },
  39.     {GPIOC,     GPIO_PIN_2,    RCM_AHB_PERIPH_GPIOC,    ADC_CHANNEL_12 },
  40.     {GPIOC,     GPIO_PIN_3,    RCM_AHB_PERIPH_GPIOC,    ADC_CHANNEL_13 },
  41.     {GPIOC,     GPIO_PIN_4,    RCM_AHB_PERIPH_GPIOC,    ADC_CHANNEL_14 },
  42.     {GPIOC,     GPIO_PIN_5,    RCM_AHB_PERIPH_GPIOC,    ADC_CHANNEL_15 },
  43.     {NULL,     0,               0,                      ADC_CHANNEL_16 },
  44.     {NULL,     0,               0,                      ADC_CHANNEL_17 },
  45. };
  1. /*
  2. * [url=/u/brief]@brief[/url]       引脚初始化
  3. *
  4. * @param       ch: 通道
  5. *
  6. * @retval      None
  7. *
  8. */
  9. void bsp_adc_gpio_init(enum ADC_CH ch)
  10. {
  11.         GPIO_Config_T gpioConfig;
  12.    
  13.     if ((ch < ADC_CH_NUM) && (adc_ch_info[ch].port != NULL)) {
  14.         RCM_EnableAHBPeriphClock(adc_ch_info[ch].AHBPeriph);
  15.         GPIO_ConfigStructInit(&gpioConfig);
  16.         gpioConfig.pin     = adc_ch_info[ch].pin;
  17.         gpioConfig.mode    = GPIO_MODE_AN;
  18.         gpioConfig.outtype = GPIO_OUT_TYPE_PP;
  19.         gpioConfig.speed   = GPIO_SPEED_50MHz;
  20.         gpioConfig.pupd    = GPIO_PUPD_NO;
  21.         GPIO_Config(adc_ch_info[ch].port, &gpioConfig);
  22.     }
  23. }
  1. /*
  2. * @brief       ADC初始化
  3. *
  4. * @param       ch: 通道
  5.                 multi: 是否连续采样
  6. *
  7. * @retval      None
  8. *
  9. */
  10. void bsp_adc_init(enum ADC_CH ch, uint8_t multi)
  11. {
  12.     ADC_Config_T adcConfig;
  13.    
  14.     if (ch < ADC_CH_NUM) {   
  15.         RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
  16.         
  17.         /* ADC Configuration */
  18.         ADC_Reset();
  19.         ADC_ConfigStructInit(&adcConfig);
  20.         /* Set resolution*/
  21.         adcConfig.resolution = ADC_RESOLUTION_12B;
  22.         /* Set dataAlign*/
  23.         adcConfig.dataAlign  = ADC_DATA_ALIGN_RIGHT;
  24.         /* Set scanDir*/
  25.         adcConfig.scanDir    = ADC_SCAN_DIR_UPWARD;
  26.         if (multi == 0) {
  27.             /* Set convMode continous*/
  28.             adcConfig.convMode   = ADC_CONVERSION_SINGLE;
  29.         } else {
  30.             adcConfig.convMode   = ADC_CONVERSION_CONTINUOUS;
  31.         }
  32.         /* Set extTrigConv*/
  33.         adcConfig.extTrigConv  = ADC_EXT_TRIG_CONV_TRG0;
  34.         /* Set TrigEdge*/
  35.         adcConfig.extTrigEdge    = ADC_EXT_TRIG_EDGE_NONE;
  36.         ADC_Config(&adcConfig);
  37.         if (ch == ADC_CH16) {
  38.             ADC_EnableTempSensor();
  39.         } else if (ch == ADC_CH17) {
  40.             ADC_EnableVrefint();
  41.         }
  42.         ADC_ConfigChannel(adc_ch_info[ch].adc_channel, ADC_SAMPLE_TIME_41_5);
  43.         /* Calibration*/
  44.         ADC_ReadCalibrationFactor();
  45.         /* Enable ADC*/
  46.         ADC_Enable();   
  47.     }
  48. }
  1. /*
  2. * @brief       ADC启动
  3. *
  4. * @param       None
  5. *
  6. * @retval      None
  7. *
  8. */
  9. void bsp_adc_start(void)
  10. {
  11.     /* Wait until ADC is ready */
  12.     while (!ADC_ReadStatusFlag(ADC_FLAG_ADRDY));
  13.     ADC_StartConversion();
  14. }
  1. /*
  2. * @brief       ADC停止
  3. *
  4. * @param       None
  5. *
  6. * @retval      None
  7. *
  8. */
  9. void bsp_adc_stop(void)
  10. {
  11.     ADC_StopConversion();
  12. }
  1. /*
  2. * @brief       ADC值获取
  3. *
  4. * @param       None
  5. *
  6. * @retval      AD值
  7. *
  8. */
  9. uint16_t bsp_adc_get_value(void)
  10. {
  11.     while (ADC_ReadStatusFlag(ADC_FLAG_CC) == RESET);
  12.     ADC_ClearStatusFlag(ADC_FLAG_CC);
  13.     return ADC_ReadConversionValue();
  14. }
  1. enum ADC_CH {
  2.     ADC_CH0,
  3.     ADC_CH1,
  4.     ADC_CH2,
  5.     ADC_CH3,
  6.     ADC_CH4,
  7.     ADC_CH5,
  8.     ADC_CH6,
  9.     ADC_CH7,
  10.     ADC_CH8,
  11.     ADC_CH9,
  12.     ADC_CH10,
  13.     ADC_CH11,
  14.     ADC_CH12,
  15.     ADC_CH13,
  16.     ADC_CH14,
  17.     ADC_CH15,
  18.     ADC_CH16,
  19.     ADC_CH17,
  20.    
  21.     ADC_CH_NUM
  22. };



测试代码如下:
  1. enum ADC_CH adc_ch = ADC_CH1;
  2. uint16_t adc_ch_value;

  3. // 应用初始化
  4. void app_init(void)
  5. {
  6.     bsp_adc_gpio_init(adc_ch);
  7.     bsp_adc_init(adc_ch, 1);
  8.     bsp_adc_start();
  9. }

  10. // 应用任务
  11. void app_task(void)
  12. {
  13.     adc_ch_value = bsp_adc_get_value();
  14. }


详细代码, 请查看附件:
Poll.zip (2.35 MB, 下载次数: 1)




评论

APM32E030的ADC驱动实现需综合考虑硬件资源配置、软件时序控制及系统级性能优化  发表于 2025-9-17 09:18
风暴之眸 发表于 2025-9-16 09:49 | 显示全部楼层
楼主这个ADC info table制作的真是方便。
dffzh 发表于 2025-9-16 14:02 | 显示全部楼层
这个结构体类型的adc_ch_info驱动表定义的不错,搭配上结构体确实很方便,很多外置芯片的驱动代码在绑定总线通信时,也是用类似结构体绑定到MCU的总线上。
 楼主| 口天土立口 发表于 2025-9-16 14:20 | 显示全部楼层
dffzh 发表于 2025-9-16 14:02
这个结构体类型的adc_ch_info驱动表定义的不错,搭配上结构体确实很方便,很多外置芯片的驱动代码在绑定总 ...

目的是保持总体代码框架不变,更改引脚只需更改信息表即可,最小化更改,同时代码的冗余度降低。但缺点是初始化效率会有一定幅度的降低,而大部分的应用场景是能接受的。在合理的执行效率下,可以选择一个更方便的代码维护风格,减少代码维护出错。

评论

一般应用足够了呢。  发表于 2025-9-17 09:02
tpgf 发表于 2025-9-17 09:18 | 显示全部楼层
若采用实时操作系统,需先在菜单配置中勾选ADC设备支持并指定具体实例
xpdzsj 发表于 2025-9-18 06:14 | 显示全部楼层
类似Hal的风格
您需要登录后才可以回帖 登录 | 注册

本版积分规则

19

主题

44

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部