OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 241|回复: 1

《M144Z-M3最小系统板使用指南——STM32F103版》第三十五章 多通道ADC采集(DMA读取)实验

[复制链接]

1070

主题

1081

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4443
金钱
4443
注册时间
2019-5-8
在线时间
1199 小时
发表于 2024-4-29 14:13:37 | 显示全部楼层 |阅读模式
本帖最后由 正点原子运营 于 2024-4-29 14:13 编辑

第三十五章 多通道ADC采集(DMA读取)实验
1)实验平台:正点原子 M144Z-M3 STM32F103最小系统板

2) 章节摘自【正点原子】M144Z-M3最小系统板使用指南——STM32F103版


4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boar ... _mini_sysboard.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)正点原子STM32技术交流QQ群:725095144

155537c2odj87vz1z9vj6l.jpg

155537nfqovl2gg9faaol9.png

本章介绍STM32F103的DMA进行多通道的ADC采集。通过本章的学习,读者将学习到DMA、ADC的使用。
本章分为如下几个小节:
35.1 硬件设计
35.2 程序设计
35.3 下载验证

35.1 硬件设计
35.1.1 例程功能
1. LCD上不断刷新显示PA5和PA6引脚输入电压采样的数字量和模拟量。
2. LED0闪烁,提示程序正在运行

35.1.2 硬件资源
1. LED
       LED0 - PB5
2. 正点原子2.8/3.5/4.3/7/10寸TFTLCD模块
3. ADC1
       Channel5 - PA5
       Channel6 - PA6
4. DMA1
       Channel1

35.1.3 原理图
本章实验使用的ADC1为STM32F103的片上资源,因此没有对应的连接原理图。

35.2 程序设计
35.2.1 HAL库的ADC驱动
本章实验与上一章实验中对ADC的操作十分类似,不过本章实验是配置、使能和读取ADC1的Channel5和Channel6,因此请见第35.2.1小节中HAL库的ADC驱动的相关内容。

35.2.2 ADC驱动
本章实验的ADC驱动主要负责向应用层提供ADC的初始化和启动ADC的DMA采集函数,同时实现了DMA的中断回调函数。本章实验中,ADC的驱动代码包括adc.c和adc.h两个文件。
ADC驱动中,对DMA、GPIO、ADC的相关宏定义,如下所示:
  1. #define ADC_NCH_DMA_ADCX   ADC1
  2. #define ADC_NCH_DMA_ADCX_CLK_ENABLE()  \
  3.     do {                                \
  4.    __HAL_RCC_ADC1_CLK_ENABLE();        \
  5.     }while (0)
  6. #define ADC_NCH_DMA_ADCX_CH_NUM        2
  7. #define ADC_NCH_DMA_ADCX_CHA           ADC_CHANNEL_5
  8. #define ADC_NCH_DMA_ADCX_CHA_GPIO_PORT GPIOA
  9. #define ADC_NCH_DMA_ADCX_CHA_GPIO_PIN  GPIO_PIN_5
  10. #define ADC_NCH_DMA_ADCX_CHA_GPIO_CLK_ENABLE() \
  11.     do {                                        \
  12.    __HAL_RCC_GPIOA_CLK_ENABLE();               \
  13.     }while (0)
  14. #define ADC_NCH_DMA_ADCX_CHB           ADC_CHANNEL_6
  15. #define ADC_NCH_DMA_ADCX_CHB_GPIO_PORT GPIOA
  16. #define ADC_NCH_DMA_ADCX_CHB_GPIO_PIN  GPIO_PIN_6
  17. #define ADC_NCH_DMA_ADCX_CHB_GPIO_CLK_ENABLE() \
  18.     do {                                        \
  19.    __HAL_RCC_GPIOA_CLK_ENABLE();               \
  20.     }while (0)
  21. #define ADC_NCH_DMA_ADCX_DMACX DMA1_Channel1
  22. #define ADC_NCH_DMA_ADCX_DMA_CLK_ENABLE()  \
  23.     do {                                    \
  24.    __HAL_RCC_DMA1_CLK_ENABLE();            \
  25.     }while (0)
  26. #define ADC_NCH_DMA_ADCX_DMACX_IRQn        DMA1_Stream1_IRQn
  27. #define ADC_NCH_DMA_ADCX_DMACX_IRQHandler  DMA1_Stream1_IRQHandler
复制代码
ADC驱动中,ADC的初始化函数,如下所示:
  1. /**
  2. *@brief   初始化多通道ADC DMA读取
  3. *@param   memory_base: 读取目标内存基地址
  4. *@retval  无
  5. */
  6. voidadc_nch_dma_init(uint32_t memory_base)
  7. {
  8.     /* 配置ADC */
  9.    g_adc_nch_dma_handle.Instance = ADC_NCH_DMA_ADCX;
  10.    g_adc_nch_dma_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  11.    g_adc_nch_dma_handle.Init.ScanConvMode = ENABLE;
  12.    g_adc_nch_dma_handle.Init.ContinuousConvMode = ENABLE;
  13.    g_adc_nch_dma_handle.Init.NbrOfConversion = ADC_NCH_DMA_ADCX_CH_NUM;
  14.    g_adc_nch_dma_handle.Init.DiscontinuousConvMode = DISABLE;
  15.    g_adc_nch_dma_handle.Init.NbrOfDiscConversion = 1;
  16.    g_adc_nch_dma_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  17.    HAL_ADC_Init(&g_adc_nch_dma_handle);
  18.    
  19.    g_adc_nch_dma_memory_base = memory_base;
  20. }
  21. /**
  22. *@brief   HAL库ADC初始化MSP函数
  23. *@param   hadc: ADC句柄
  24. *@retval  无
  25. */
  26. voidHAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
  27. {
  28.    GPIO_InitTypeDef gpio_init_struct = {0};
  29.    
  30.     if (hadc->Instance == ADC_NCH_DMA_ADCX)
  31.     {
  32.          ADC_NCH_DMA_ADCX_CLK_ENABLE();
  33.          ADC_NCH_DMA_ADCX_CHA_GPIO_CLK_ENABLE();
  34.          ADC_NCH_DMA_ADCX_CHB_GPIO_CLK_ENABLE();
  35.          ADC_NCH_DMA_ADCX_DMA_CLK_ENABLE();
  36.          
  37.          /* 初始化ADC采样引脚 */
  38.          gpio_init_struct.Pin = ADC_NCH_DMA_ADCX_CHA_GPIO_PIN;
  39.          gpio_init_struct.Mode = GPIO_MODE_ANALOG;
  40.          gpio_init_struct.Pull = GPIO_NOPULL;
  41.          gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
  42.          HAL_GPIO_Init(ADC_NCH_DMA_ADCX_CHA_GPIO_PORT, &gpio_init_struct);
  43.          
  44.          gpio_init_struct.Pin = ADC_NCH_DMA_ADCX_CHB_GPIO_PIN;
  45.          gpio_init_struct.Mode = GPIO_MODE_ANALOG;
  46.          gpio_init_struct.Pull = GPIO_NOPULL;
  47.          gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
  48.          HAL_GPIO_Init(ADC_NCH_DMA_ADCX_CHB_GPIO_PORT, &gpio_init_struct);
  49.          
  50.          /* 配置DMA */
  51.          g_adc_nch_dma_dma_handle.Instance =ADC_NCH_DMA_ADCX_DMACX;
  52.          g_adc_nch_dma_dma_handle.Init.Direction =DMA_PERIPH_TO_MEMORY;
  53.          g_adc_nch_dma_dma_handle.Init.PeriphInc = DMA_PINC_DISABLE;
  54.          g_adc_nch_dma_dma_handle.Init.MemInc = DMA_MINC_ENABLE;
  55.          g_adc_nch_dma_dma_handle.Init.PeriphDataAlignment=
  56.                                                          DMA_PDATAALIGN_HALFWORD;
  57.          g_adc_nch_dma_dma_handle.Init.MemDataAlignment =DMA_MDATAALIGN_HALFWORD;
  58.          g_adc_nch_dma_dma_handle.Init.Mode = DMA_NORMAL;
  59.          g_adc_nch_dma_dma_handle.Init.Priority =DMA_PRIORITY_VERY_HIGH;
  60.          HAL_DMA_Init(&g_adc_nch_dma_dma_handle);
  61.          
  62.          __HAL_LINKDMA(  &g_adc_nch_dma_handle,
  63.                          DMA_Handle,
  64.                          g_adc_nch_dma_dma_handle);
  65.          
  66.          HAL_NVIC_SetPriority(ADC_NCH_DMA_ADCX_DMACX_IRQn, 0, 0);
  67.          HAL_NVIC_EnableIRQ(ADC_NCH_DMA_ADCX_DMACX_IRQn);
  68.     }
  69. }
复制代码
从上面的代码中可以看出,本章实验的ADC初始化与上一章实验中的ADC初始化步骤基本一致,不过本章实验的ADC初始化函数中配置了ADC1的Channel5和Channel6。
ADC驱动中,启动ADC的DMA采集的函数和ADC转换完成回调函数均与上一章实验中的函数一致,请见第35.2.2小节中的相关内容。

35.2.3 实验应用代码
本章实验的应用代码,如下所示:
  1. #define ADC_NCH_DMA_BUF_SIZE (50 *ADC_NCH_DMA_ADCX_CH_NUM)
  2. uint16_t g_adc_nch_dma_buf[ADC_NCH_DMA_BUF_SIZE];
  3. extern uint8_t g_adc_nch_dma_sta;
  4. int main(void)
  5. {
  6.     uint16_t adc_result[ADC_NCH_DMA_ADCX_CH_NUM];
  7.     uint16_t voltage;
  8.     uint16_t index;
  9.     uint32_t result_sum;
  10.     uint8_t ch_index;
  11.    
  12.    HAL_Init();                                     /* 初始化HAL库 */
  13.    sys_stm32_clock_init(RCC_PLL_MUL9);             /* 配置时钟,72MHz */
  14.    delay_init(72);                                 /* 初始化延时 */
  15.    usart_init(115200);                             /* 初始化串口 */
  16.    led_init();                                     /* 初始化LED */
  17.    lcd_init();                                     /* 初始化LCD */
  18.    adc_nch_dma_init((uint32_t)g_adc_nch_dma_buf); /* 初始化多通道ADC DMA读取 */
  19.    
  20.    lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
  21.    lcd_show_string(30, 70, 200, 16, 16, "ADC NCH DMATEST", RED);
  22.    lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
  23.    
  24.    lcd_show_string(30, 110, 200, 16, 16, "ADC1_CH5_VAL:0", BLUE);
  25.    lcd_show_string(30, 130, 200, 16, 16, "ADC1_CH5_VOL:0.000V", BLUE);
  26.    lcd_show_string(30, 150, 200, 16, 16, "ADC1_CH6_VAL:0", BLUE);
  27.    lcd_show_string(30, 170, 200, 16, 16, "ADC1_CH6_VOL:0.000V", BLUE);
  28.    
  29.     /* 开启多通道ADC DMA读取 */
  30.    adc_nch_dma_enable(ADC_NCH_DMA_BUF_SIZE);
  31.    
  32.     while (1)
  33.     {
  34.          if (g_adc_nch_dma_sta == 1)
  35.          {
  36.              g_adc_nch_dma_sta = 0;
  37.             
  38.              for (ch_index=0; ch_index<ADC_NCH_DMA_ADCX_CH_NUM; ch_index++)
  39.              {
  40.                  /* 对DMA读取的多个ADC数据进行均值滤波 */
  41.                  for (result_sum = 0, index=0;
  42.                      index<(ADC_NCH_DMA_BUF_SIZE / ADC_NCH_DMA_ADCX_CH_NUM);
  43.                      index++)
  44.                  {
  45.                      result_sum +=
  46.                          g_adc_nch_dma_buf[(ADC_NCH_DMA_ADCX_CH_NUM* index) +
  47.                                              ch_index];
  48.                  }
  49.                  adc_result[ch_index] =
  50.                      result_sum /
  51.                      (ADC_NCH_DMA_BUF_SIZE / ADC_NCH_DMA_ADCX_CH_NUM);
  52.              }
  53.             
  54.              /* 计算实际电压值(扩大1000倍) */
  55.              voltage = (adc_result[0] * 3300) / 4095;
  56.              lcd_show_xnum(134, 110, adc_result[0], 5, 16, 0, BLUE);
  57.              lcd_show_xnum(134, 130, voltage / 1000, 1, 16, 0, BLUE);
  58.              lcd_show_xnum(150, 130, voltage % 1000, 3, 16, 0x80, BLUE);
  59.             
  60.              /* 计算实际电压值(扩大1000倍) */
  61.              lcd_show_xnum(134, 150, adc_result[1], 5, 16, 0, BLUE);
  62.              voltage = (adc_result[1] * 3300) / 4095;
  63.              lcd_show_xnum(134, 170, voltage / 1000, 1, 16, 0, BLUE);
  64.              lcd_show_xnum(150, 170, voltage % 1000, 3, 16, 0x80, BLUE);
  65.             
  66.              adc_nch_dma_enable(ADC_NCH_DMA_BUF_SIZE);
  67.          }
  68.          
  69.          LED0_TOGGLE();
  70.          
  71.          delay_ms(100);
  72.     }
  73. }
复制代码
本章实验的应用代码与上一章实验中的引用代码基本一致,只不过本章实验要处理的是2个ADC通道的数据,因此DMA传输的目的存储器容量的定义变大了,随后便可在DMA传输完成后,采用与上一章实验一样的处理方式处理ADC采集并转换后的数据,最后将每个通道采集到电压的数字量和模拟量显示置LCD上。

35.3 下载验证
在完成编译和烧录操作后,可以看到LCD上不断地刷新显示ADC1的Channel5和Channel6(PA5引脚和PA6引脚)采集到电压的数字量和模拟量,此时可以通过杜邦线给PA5和PA6中的任意一个或多个引脚接入不同的电压值(注意共地,且输入电压不能超过3.3V,否则可能损坏开发板),可以看到LCD上显示的电压数字量和模拟量也随之改变。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

1

帖子

0

精华

初级会员

Rank: 2

积分
103
金钱
103
注册时间
2020-5-11
在线时间
33 小时
发表于 3 天前 | 显示全部楼层
资料程序源码怎么没有找到:第三十五章 多通道ADC采集(DMA读取)实验???
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-6-7 21:36

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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