学习目标

  • 了解ADC开发流程
  • 掌握采样方式
  • 能够使用ADC进行芯片内部通道进行采样
  • 能够使用ADC对外部电路进行采样

    学习内容

    GD32F4的ADC

    特点:

  • 16个外部模拟输入通道;

  • 1个内部温度传感通道(VSENSE);
  • 1个内部参考电压输入通道(VREFINT);
  • 1个外部监测电池VBAT供电引脚输入通道。

ADC开发流程

042.png

  1. ADC配置
  2. ADC采样

    ADC配置

    GPIO配置
    主要配置GPIO的模式和引脚信息,如果ADC采样需要通过引脚进行,则需要配置。
    主频配置
    采样的频率配置。
    1. adc_clock_config(ADC_ADCCK_PCLK2_DIV8);
    分辨率和数据对齐配置
    分辨率为采样精度,可选为12位,10位,8位,6位。
    不同分辨率,取值精度范围不同:
    *
    左对齐与右对齐,表示的是采样的数据,如何存储到寄存器的。我们获取的是寄存器存储的值。详见《GD32F4xx_User_Manual_Rev2.8_CN.pdf》14.4.7
    043.png
    044.png
    045.png
    046.png
    047.png
    048.png
    049.png
    050.png
    规则配置
    规则包含:
  • 常规规则
  • 插入规则

模式配置

Continuous Mode(连续模式)
定义:在连续模式下,一旦 ADC 被启动,它会不断地对选定的通道进行采样和转换,直到显式停止。
用途:这个模式适用于需要持续监测某个信号的场合,比如读取一个模拟传感器的持续输出。
特点:一旦开始,ADC 会连续不断地进行转换操作,无需每次转换都重新启动。
Scan Mode(扫描模式)
定义:在扫描模式下,ADC 按照预设的顺序自动扫描多个通道,并对每个通道进行一次采样和转换。
用途:这个模式适用于需要周期性地监测多个通道(例如多个传感器)的场合。
特点:ADC 在一系列通道上进行顺序采样,每个通道都被转换一次,然后整个序列可以重复进行,如果结合连续模式使用。

  • 扫描模式
  • 运行模式:连续or单次
  • 插入序列自动转换模式

我们这里的模式并非是多选一的结构,而是多选多,自由搭配方式

模式 开启 关闭
扫描模式
连续模式
插入序列自动转换模式

校准ADC
  1. // 校准ADC
  2. adc_calibration_enable(ADC0);

ADC采样

  1. 数据转换操作。这个是ADC电路实现的,我们主要是去触发它进行数据转换。
  2. 转换状态。电路在转换过程中,会修改相应寄存器状态。我们可以通过判断寄存器状态来知道转换的进度。
  3. 数据读取。转换完成后,我们去相应的寄存器读取数据。

    需求:采样芯片温度

    读取芯片的温度。芯片内置温度采样电路,可以通过ADC进行采样。

    初始化

    1. static void ADC_config() {
    2. /******************** ADC config **********************/
    3. // 配置时钟
    4. rcu_periph_clock_enable(RCU_ADC0);
    5. // 重置
    6. adc_deinit();
    7. // 配置主频
    8. adc_clock_config(ADC_ADCCK_PCLK2_DIV8);
    9. ////////// 采样配置
    10. adc_resolution_config(ADC0, ADC_RESOLUTION_12B); // 分辨率
    11. adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);// 数据右对齐
    12. //////////// 规则配置
    13. adc_channel_16_to_18(ADC_TEMP_VREF_CHANNEL_SWITCH, ENABLE);
    14. // 配置通道和通道数量
    15. adc_routine_channel_config(ADC0, 0, ADC_CHANNEL_16, ADC_SAMPLETIME_15);
    16. adc_channel_length_config(ADC0, ADC_ROUTINE_CHANNEL, 1);
    17. /////////// 模式配置
    18. adc_special_function_config(ADC0, ADC_SCAN_MODE, DISABLE);// 取消扫描模式
    19. adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, DISABLE);//取消连续模式
    20. // 打开ADC
    21. adc_enable(ADC0);
    22. // 校准ADC
    23. adc_calibration_enable(ADC0);
    24. delay_1ms(100);
    25. }

    获取采样

    1. static void ADC_get() {
    2. // 触发ADC采样
    3. adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);
    4. // 等待ADC采样并且转化完成
    5. while(RESET == adc_flag_get(ADC0, ADC_FLAG_EOC));
    6. adc_flag_clear(ADC0, ADC_FLAG_EOC);
    7. // 获取采样结果数据
    8. uint16_t value = adc_routine_data_read(ADC0);
    9. // 将ADC结果转化为温度值
    10. float temperature = ((1.4 - 3.3 * value / 4096 )/ 4.4) * 1000 + 25;
    11. printf("value: %d %f\r\n", value, temperature);
    12. }
  • 通过软触发调用adc进行采样。
  • adc的规则通道为常规通道,通过adc_routine_data_read读取数据

218.png
219.png

完整代码

  1. #include "gd32f4xx.h"
  2. #include "systick.h"
  3. #include <stdio.h>
  4. #include "main.h"
  5. #include "Usart0.h"
  6. void Usart0_recv(uint8_t *data, uint32_t len) {
  7. printf("recv: %s\r\n", data);
  8. }
  9. static void ADC_config() {
  10. /****************** GPIO config *********************/
  11. // 1. 时钟初始化
  12. rcu_periph_clock_enable(RCU_GPIOE);
  13. // 2. 配置GPIO 输入输出模式
  14. gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);
  15. // 3. 配置GPIO 模式的操作方式
  16. gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_3);
  17. /******************** ADC config **********************/
  18. // 配置时钟
  19. rcu_periph_clock_enable(RCU_ADC0);
  20. // 重置
  21. adc_deinit();
  22. // 配置主频
  23. adc_clock_config(ADC_ADCCK_PCLK2_DIV8);
  24. ////////// 采样配置
  25. adc_resolution_config(ADC0, ADC_RESOLUTION_12B); // 分辨率
  26. adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);// 数据右对齐
  27. //////////// 规则配置
  28. adc_channel_16_to_18(ADC_TEMP_VREF_CHANNEL_SWITCH, ENABLE);
  29. // 配置通道和通道数量
  30. adc_routine_channel_config(ADC0, 0, ADC_CHANNEL_16, ADC_SAMPLETIME_15);
  31. adc_channel_length_config(ADC0, ADC_ROUTINE_CHANNEL, 1);
  32. /////////// 模式配置
  33. adc_special_function_config(ADC0, ADC_SCAN_MODE, DISABLE);// 取消扫描模式
  34. adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, DISABLE);//取消连续模式
  35. // 打开ADC
  36. adc_enable(ADC0);
  37. // 校准ADC
  38. adc_calibration_enable(ADC0);
  39. delay_1ms(100);
  40. }
  41. static void ADC_get() {
  42. adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);
  43. while(RESET == adc_flag_get(ADC0, ADC_FLAG_EOC));
  44. adc_flag_clear(ADC0, ADC_FLAG_EOC);
  45. uint16_t value = adc_routine_data_read(ADC0);
  46. float temperature = ((1.4 - 3.3 * value / 4096 )/ 4.4) * 1000 + 25;
  47. printf("temp: %d %f\r\n", value, temperature);
  48. }
  49. int main(void)
  50. {
  51. // 系统时钟初始化
  52. systick_config();
  53. Usart0_init();
  54. ADC_config();
  55. while(1) {
  56. ADC_get();
  57. delay_1ms(1000);
  58. }
  59. }

单次运行模式

051.png

  • 每次采样,都需要触发

需求:电位器

221.png222.png

初始化

  1. static void ADC_config() {
  2. /****************** GPIO config *********************/
  3. // 1. 时钟初始化
  4. rcu_periph_clock_enable(RCU_GPIOA);
  5. // 2. 配置GPIO 输入输出模式
  6. gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0);
  7. /******************** ADC config **********************/
  8. // 配置时钟
  9. rcu_periph_clock_enable(RCU_ADC0);
  10. // 重置
  11. adc_deinit();
  12. // 配置主频
  13. adc_clock_config(ADC_ADCCK_PCLK2_DIV8);
  14. ////////// 采样配置
  15. adc_resolution_config(ADC0, ADC_RESOLUTION_12B); // 分辨率
  16. adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);// 数据右对齐
  17. //////////// 规则配置
  18. // 配置通道和通道数量
  19. adc_routine_channel_config(ADC0, 0, ADC_CHANNEL_0, ADC_SAMPLETIME_15);
  20. adc_channel_length_config(ADC0, ADC_ROUTINE_CHANNEL, 1);
  21. /////////// 模式配置
  22. adc_special_function_config(ADC0, ADC_SCAN_MODE, DISABLE);// 取消扫描模式
  23. adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, DISABLE);//取消连续模式
  24. // 打开ADC
  25. adc_enable(ADC0);
  26. // 校准ADC
  27. adc_calibration_enable(ADC0);
  28. delay_1ms(100);
  29. }
  • GPIO初始化,PA0初始化为模拟数据采集类型。

    获取采样

    1. static void ADC_get() {
    2. adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);
    3. while(RESET == adc_flag_get(ADC0, ADC_FLAG_EOC));
    4. adc_flag_clear(ADC0, ADC_FLAG_EOC);
    5. uint16_t value = adc_routine_data_read(ADC0);
    6. float vol = value * 3.3 / 4096;
    7. printf("value: %d %f\r\n", value, vol);
    8. }
  • 通过软触发调用adc进行采样。

  • adc的规则通道为常规通道,通过adc_routine_data_read读取数据

    完整代码

    ```c

    include “gd32f4xx.h”

    include “systick.h”

    include

    include “main.h”

    include “Usart0.h”

// PA0: 电位器

void Usart0_recv(uint8_t *data, uint32_t len) { printf(“recv: %s\r\n”, data); }

static void ADC_config() { /** GPIO config */ // 1. 时钟初始化 rcu_periph_clock_enable(RCU_GPIOA); // 2. 配置GPIO 输入输出模式 gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0);

  1. /******************** ADC config **********************/
  2. // 配置时钟
  3. rcu_periph_clock_enable(RCU_ADC0);
  4. // 重置
  5. adc_deinit();
  6. // 配置主频
  7. adc_clock_config(ADC_ADCCK_PCLK2_DIV8);
  8. ////////// 采样配置
  9. adc_resolution_config(ADC0, ADC_RESOLUTION_12B); // 分辨率
  10. adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);// 数据右对齐
  11. //////////// 规则配置
  12. // 配置通道和通道数量
  13. adc_routine_channel_config(ADC0, 0, ADC_CHANNEL_0, ADC_SAMPLETIME_15);
  14. adc_channel_length_config(ADC0, ADC_ROUTINE_CHANNEL, 1);
  15. /////////// 模式配置
  16. adc_special_function_config(ADC0, ADC_SCAN_MODE, DISABLE);// 取消扫描模式
  17. adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, DISABLE);//取消连续模式
  18. // 打开ADC
  19. adc_enable(ADC0);
  20. // 校准ADC
  21. adc_calibration_enable(ADC0);
  22. delay_1ms(100);

}

static void ADC_get() { adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);

  1. while(RESET == adc_flag_get(ADC0, ADC_FLAG_EOC));
  2. adc_flag_clear(ADC0, ADC_FLAG_EOC);
  3. uint16_t value = adc_routine_data_read(ADC0);
  4. float vol = value * 3.3 / 4096;
  5. printf("value: %d %f\r\n", value, vol);

}

int main(void) { // 系统时钟初始化 systick_config(); Usart0_init(); ADC_config();

  1. while(1) {
  2. ADC_get();
  3. delay_1ms(1000);
  4. }

}

  1. <a name="bcPJU"></a>
  2. ### 多通道采样
  3. 需要同时采样芯片内部的温度和外部电位器的电压。
  4. <a name="aL05f"></a>
  5. #### 初始化
  6. ```c
  7. static void ADC_config() {
  8. /****************** GPIO config *********************/
  9. // 1. 时钟初始化
  10. rcu_periph_clock_enable(RCU_GPIOA);
  11. // 2. 配置GPIO 输入输出模式
  12. gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0);
  13. /******************** ADC config **********************/
  14. // 配置时钟
  15. rcu_periph_clock_enable(RCU_ADC0);
  16. // 重置
  17. adc_deinit();
  18. // 配置主频
  19. adc_clock_config(ADC_ADCCK_PCLK2_DIV8);
  20. ////////// 采样配置
  21. adc_resolution_config(ADC0, ADC_RESOLUTION_12B); // 分辨率
  22. adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);// 数据右对齐
  23. /////////// 模式配置
  24. adc_special_function_config(ADC0, ADC_SCAN_MODE, DISABLE);// 扫描模式
  25. adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, DISABLE);//取消连续模式
  26. // 打开ADC
  27. adc_enable(ADC0);
  28. // 校准ADC
  29. adc_calibration_enable(ADC0);
  30. delay_1ms(100);
  31. }

获取采样

  1. static void ADC_get_temperature() {
  2. // 配置通道
  3. adc_routine_channel_config(ADC0, 0, ADC_CHANNEL_16, ADC_SAMPLETIME_15);
  4. // 触发转换
  5. adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);
  6. while(RESET == adc_flag_get(ADC0, ADC_FLAG_EOC));
  7. adc_flag_clear(ADC0, ADC_FLAG_EOC);
  8. uint16_t value = adc_routine_data_read(ADC0);
  9. float temperature = ((1.4 - 3.3 * value / 4096 )/ 4.4) + 25;
  10. printf("temp: %d %f\r\n", value, temperature);
  11. }
  12. static void ADC_get_vol() {
  13. // 配置通道
  14. adc_routine_channel_config(ADC0, 0, ADC_CHANNEL_0, ADC_SAMPLETIME_15);
  15. // 触发转换
  16. adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);
  17. while(RESET == adc_flag_get(ADC0, ADC_FLAG_EOC));
  18. adc_flag_clear(ADC0, ADC_FLAG_EOC);
  19. uint16_t value = adc_routine_data_read(ADC0);
  20. float vol = value * 3.3 / 4096;
  21. printf("vol: %d %f\r\n", value, vol);
  22. }

触发采样时配置通,获取采样结果。

完整代码

  1. #include "gd32f4xx.h"
  2. #include "systick.h"
  3. #include <stdio.h>
  4. #include "main.h"
  5. #include "Usart0.h"
  6. void Usart0_recv(uint8_t *data, uint32_t len) {
  7. printf("recv: %s\r\n", data);
  8. adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);
  9. }
  10. static void ADC_config() {
  11. /****************** GPIO config *********************/
  12. // 1. 时钟初始化
  13. rcu_periph_clock_enable(RCU_GPIOA);
  14. // 2. 配置GPIO 输入输出模式
  15. gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0);
  16. /******************** ADC config **********************/
  17. // 配置时钟
  18. rcu_periph_clock_enable(RCU_ADC0);
  19. // 重置
  20. adc_deinit();
  21. // 配置主频
  22. adc_clock_config(ADC_ADCCK_PCLK2_DIV8);
  23. ////////// 采样配置
  24. adc_resolution_config(ADC0, ADC_RESOLUTION_12B); // 分辨率
  25. adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);// 数据右对齐
  26. /////////// 模式配置
  27. adc_special_function_config(ADC0, ADC_SCAN_MODE, DISABLE);// 扫描模式
  28. adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, DISABLE);//取消连续模式
  29. // 打开ADC
  30. adc_enable(ADC0);
  31. // 校准ADC
  32. adc_calibration_enable(ADC0);
  33. delay_1ms(100);
  34. }
  35. static void ADC_get_temperature() {
  36. // 配置通道
  37. adc_routine_channel_config(ADC0, 0, ADC_CHANNEL_16, ADC_SAMPLETIME_15);
  38. // 触发转换
  39. adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);
  40. while(RESET == adc_flag_get(ADC0, ADC_FLAG_EOC));
  41. adc_flag_clear(ADC0, ADC_FLAG_EOC);
  42. uint16_t value = adc_routine_data_read(ADC0);
  43. float temperature = ((1.4 - 3.3 * value / 4096 )/ 4.4) + 25;
  44. printf("temp: %d %f\r\n", value, temperature);
  45. }
  46. static void ADC_get_vol() {
  47. // 配置通道
  48. adc_routine_channel_config(ADC0, 0, ADC_CHANNEL_0, ADC_SAMPLETIME_15);
  49. // 触发转换
  50. adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);
  51. while(RESET == adc_flag_get(ADC0, ADC_FLAG_EOC));
  52. adc_flag_clear(ADC0, ADC_FLAG_EOC);
  53. uint16_t value = adc_routine_data_read(ADC0);
  54. float vol = value * 3.3 / 4096;
  55. printf("vol: %d %f\r\n", value, vol);
  56. }
  57. int main(void)
  58. {
  59. // 系统时钟初始化
  60. systick_config();
  61. Usart0_init();
  62. ADC_config();
  63. while(1) {
  64. ADC_get_temperature();
  65. ADC_get_vol();
  66. delay_1ms(1000);
  67. }
  68. }

多通道采样DMA

现在需要采样数据,采集多路数据,采用DMA的方式帮助我们搬运数据

初始化

  1. static void ADC_config() {
  2. /****************** GPIO config *********************/
  3. // 1. 时钟初始化
  4. rcu_periph_clock_enable(RCU_GPIOA);
  5. // 2. 配置GPIO 输入输出模式
  6. gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0);
  7. /******************** ADC config **********************/
  8. // 配置时钟
  9. rcu_periph_clock_enable(RCU_ADC0);
  10. // 重置
  11. adc_deinit();
  12. // 配置主频
  13. adc_clock_config(ADC_ADCCK_PCLK2_DIV8);
  14. ////////// 采样配置
  15. adc_resolution_config(ADC0, ADC_RESOLUTION_12B); // 分辨率
  16. adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);// 数据右对齐
  17. //////////// 规则配置
  18. // 配置通道和通道数量
  19. adc_routine_channel_config(ADC0, 0, ADC_CHANNEL_16, ADC_SAMPLETIME_15);
  20. adc_routine_channel_config(ADC0, 1, ADC_CHANNEL_0, ADC_SAMPLETIME_15);
  21. adc_channel_length_config(ADC0, ADC_ROUTINE_CHANNEL, 2);
  22. /////////// 模式配置
  23. adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);// 扫描模式
  24. adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);//取消连续模式
  25. // DMA
  26. adc_dma_request_after_last_enable(ADC0);
  27. adc_dma_mode_enable(ADC0);
  28. // 打开ADC
  29. adc_enable(ADC0);
  30. // 校准ADC
  31. adc_calibration_enable(ADC0);
  32. delay_1ms(100);
  33. // 触发采样
  34. adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);
  35. }
  • ADC初始化,需要配置DMA模式开启

    1. uint16_t buff[2] = {0};
    2. static void DMA_config() {
    3. uint32_t dmax = DMA1;
    4. uint32_t dmax_rcu = RCU_DMA1;
    5. uint32_t dmax_ch = DMA_CH0;
    6. uint32_t damx_sub = DMA_SUBPERI0;
    7. uint32_t dmax_dirction = DMA_PERIPH_TO_MEMORY;
    8. uint32_t dmax_src = (uint32_t)(&ADC_RDATA(ADC0));
    9. uint32_t dmax_src_inc = DMA_PERIPH_INCREASE_DISABLE;
    10. uint32_t dmax_src_width = DMA_PERIPH_WIDTH_16BIT;
    11. uint32_t dmax_src_len = 2;
    12. uint32_t dmax_dst = (uint32_t)(buff);
    13. uint32_t dmax_dst_inc = DMA_MEMORY_INCREASE_ENABLE;
    14. /**************** DMA p2m *******************/
    15. // 时钟
    16. rcu_periph_clock_enable(dmax_rcu);
    17. // 重置dma
    18. dma_deinit(dmax, dmax_ch);
    19. //////// dma 配置
    20. dma_single_data_parameter_struct dsdps;
    21. dma_single_data_para_struct_init(&dsdps);
    22. // 方向
    23. dsdps.direction = DMA_PERIPH_TO_MEMORY;
    24. // 内存: dst
    25. dsdps.memory0_addr = dmax_dst;
    26. dsdps.memory_inc = dmax_dst_inc;
    27. // 外设: src
    28. dsdps.periph_addr = dmax_src;
    29. dsdps.periph_inc = dmax_src_inc;
    30. // 数据长度
    31. dsdps.number = dmax_src_len;
    32. // dst数据宽度
    33. dsdps.periph_memory_width = dmax_src_width;
    34. // 传输优先级
    35. dsdps.priority = DMA_PRIORITY_ULTRA_HIGH;
    36. dma_single_data_mode_init(dmax, dmax_ch, &dsdps);
    37. //////// 配置 dma 子连接
    38. dma_channel_subperipheral_select(dmax, dmax_ch, damx_sub);
    39. dma_circulation_enable(dmax, dmax_ch);
    40. // 默认开启接收
    41. dma_flag_clear(dmax, dmax_ch, DMA_FLAG_FTF);
    42. dma_channel_enable(dmax, dmax_ch);
    43. }
  • 开启循环模式,dma会自动进行数据搬运。

    采样数据获取

    1. static void ADC_get() {
    2. uint16_t value = buff[0];
    3. float temperature = ((1.4 - 3.3 * value / 4096 )/ 4.4) + 25;
    4. printf("temp: 0x%04X %f\r\n", value, temperature);
    5. value = buff[1];
    6. float vol = value * 3.3 / 4096;
    7. printf("vol: 0x%04X %f\r\n", value, vol);
    8. buff[0] = 0;
    9. buff[1] = 0;
    10. }
  • 使用了DMA后,就不必去ADC寄存器中取数据,可以直接到内存中获取。

    运行模式

    连续运行模式

    052.png
    连续运行模式,只需要触发一次采样,ADC后续会自动帮助进行采样。
    对应的配置为:

    1. adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);//连续模式

    扫描模式

    054.png
    扫描模式,是在多个通道需要同时采样的情况下使用的,确保每个通道都能够获得数据。
    如果是多个通道采样时,不配置扫描模式,则只会读取第一个序列的数据:
    055.png

    连续运行+扫描模式

    image.png

    完整代码

    ```c

    include “gd32f4xx.h”

    include “systick.h”

    include

    include “main.h”

    include “Usart0.h”

void Usart0_recv(uint8_t *data, uint32_t len) { printf(“recv: %s\r\n”, data);

  1. adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);

}

static void ADC_config() { /** GPIO config */ // 1. 时钟初始化 rcu_periph_clock_enable(RCU_GPIOA); // 2. 配置GPIO 输入输出模式 gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0);

  1. // 1. 时钟初始化
  2. rcu_periph_clock_enable(RCU_GPIOA);
  3. // 2. 配置GPIO 输入输出模式
  4. gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1);
  5. /******************** ADC config **********************/
  6. // 配置时钟
  7. rcu_periph_clock_enable(RCU_ADC0);
  8. // 重置
  9. adc_deinit();
  10. // 配置主频
  11. adc_clock_config(ADC_ADCCK_PCLK2_DIV8);
  12. ////////// 采样配置
  13. adc_resolution_config(ADC0, ADC_RESOLUTION_12B); // 分辨率
  14. adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);// 数据右对齐
  15. //////////// 规则配置
  16. // 配置通道和通道数量
  17. adc_routine_channel_config(ADC0, 0, ADC_CHANNEL_16, ADC_SAMPLETIME_15);
  18. adc_routine_channel_config(ADC0, 1, ADC_CHANNEL_0, ADC_SAMPLETIME_15);
  19. adc_routine_channel_config(ADC0, 2, ADC_CHANNEL_1, ADC_SAMPLETIME_15);
  20. adc_channel_length_config(ADC0, ADC_ROUTINE_CHANNEL, 3);
  21. /////////// 模式配置
  22. adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);// 扫描模式
  23. adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);//取消连续模式
  24. // DMA
  25. adc_dma_request_after_last_enable(ADC0);
  26. adc_dma_mode_enable(ADC0);
  27. // 打开ADC
  28. adc_enable(ADC0);
  29. // 校准ADC
  30. adc_calibration_enable(ADC0);
  31. delay_1ms(100);
  32. // 触发采样
  33. adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);

}

uint16_t buff[2] = {0};

static void DMA_config() { uint32_t dmax = DMA1; uint32_t dmax_rcu = RCU_DMA1; uint32_t dmax_ch = DMA_CH0; uint32_t damx_sub = DMA_SUBPERI0;

  1. uint32_t dmax_dirction = DMA_PERIPH_TO_MEMORY;
  2. uint32_t dmax_src = (uint32_t)(&ADC_RDATA(ADC0));
  3. uint32_t dmax_src_inc = DMA_PERIPH_INCREASE_DISABLE;
  4. uint32_t dmax_src_width = DMA_PERIPH_WIDTH_16BIT;
  5. uint32_t dmax_src_len = 3;
  6. uint32_t dmax_dst = (uint32_t)(buff);
  7. uint32_t dmax_dst_inc = DMA_MEMORY_INCREASE_ENABLE;
  8. /**************** DMA p2m *******************/
  9. // 时钟
  10. rcu_periph_clock_enable(dmax_rcu);
  11. // 重置dma
  12. dma_deinit(dmax, dmax_ch);
  13. //////// dma 配置
  14. dma_single_data_parameter_struct dsdps;
  15. dma_single_data_para_struct_init(&dsdps);
  16. // 方向
  17. dsdps.direction = DMA_PERIPH_TO_MEMORY;
  18. // 内存: dst
  19. dsdps.memory0_addr = dmax_dst;
  20. dsdps.memory_inc = dmax_dst_inc;
  21. // 外设: src
  22. dsdps.periph_addr = dmax_src;
  23. dsdps.periph_inc = dmax_src_inc;
  24. // 数据长度
  25. dsdps.number = dmax_src_len;
  26. // dst数据宽度
  27. dsdps.periph_memory_width = dmax_src_width;
  28. // 传输优先级
  29. dsdps.priority = DMA_PRIORITY_ULTRA_HIGH;
  30. dma_single_data_mode_init(dmax, dmax_ch, &dsdps);
  31. //////// 配置 dma 子连接
  32. dma_channel_subperipheral_select(dmax, dmax_ch, damx_sub);
  33. dma_circulation_enable(dmax, dmax_ch);
  34. // 默认开启接收
  35. dma_flag_clear(dmax, dmax_ch, DMA_FLAG_FTF);
  36. dma_channel_enable(dmax, dmax_ch);

}

static void ADC_get() { uint16_t value = buff[0]; float temperature = ((1.4 - 3.3 * value / 4096 )/ 4.4) + 25; printf(“temp: 0x%04X %f\r\n”, value, temperature);

  1. value = buff[1];
  2. float vol = value * 3.3 / 4096;
  3. printf("vol: 0x%04X %f\r\n", value, vol);
  4. buff[0] = 0;
  5. buff[1] = 0;

}

int main(void) { // 系统时钟初始化 systick_config(); Usart0_init(); ADC_config(); DMA_config();

  1. while(1) {
  2. ADC_get();
  3. delay_1ms(1000);
  4. }

} ```

练习题

  1. 使用ADC进行采样芯片温度
  2. 使用ADC进行采样电位器
  3. 使用ADC进行采样NTC温度