你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F7实现ADC采集(软件触发+DMA传输)

[复制链接]
STMCU小助手 发布时间:2021-12-12 21:25
前面完成了STM32F7实现ADC采集(软件触发+轮询),但轮询的时候CPU得不到释放,在此基础上,这里实现DMA的传输。
由STM32F7的中文参考手册可以知道,ADC可以使用DMA2的数据流0:

20200419132332456.png


使用CubeMX配置DMA:
20200419132658526.png


adc.c内容如下:

  1. #include "adc.h"
  2. #include "delay.h"

  3. ADC_HandleTypeDef ADC1_Handler;//ADC句柄
  4. DMA_HandleTypeDef ADC1DMA_Handler;
  5. ADC_ChannelConfTypeDef ADC1_ChanConf;

  6. uint16_t buffer[128];

  7. /*下面的函数写完才发现没有用*/
  8. //void ADC1DMA_CpltCallback(struct __DMA_HandleTypeDef *hdma)
  9. //{
  10. //    printf("DMA transfer complete\r\n");
  11. //}
  12. //void ADC1DMA_HalfCpltCallback(struct __DMA_HandleTypeDef *hdma)
  13. //{
  14. //    printf("DMA Half transfer complete\r\n");
  15. //}
  16. //void ADC1DMA_M1CpltCallback(struct __DMA_HandleTypeDef *hdma)
  17. //{
  18. //    printf("DMA transfer complete Memory1\r\n");
  19. //}
  20. //void ADC1DMA_M1HalfCpltCallback(struct __DMA_HandleTypeDef *hdma)
  21. //{
  22. //    printf("DMA transfer Half complete Memory1\r\n");
  23. //}
  24. //void ADC1DMA_ErrorCallback(struct __DMA_HandleTypeDef *hdma)
  25. //{
  26. //    printf("DMA transfer error\r\n");
  27. //}
  28. //void ADC1DMA_XferAbortCallback(struct __DMA_HandleTypeDef *hdma)
  29. //{
  30. //    printf("DMA transfer Abort \r\n");
  31. //}


  32. //初始化ADC
  33. //ch: ADC_channels
  34. //通道值 0~16取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
  35. void MY_ADC_Init(void)
  36. {
  37.     __HAL_RCC_DMA2_CLK_ENABLE();
  38.     HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
  39.     HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);

  40.     ADC1DMA_Handler.Instance = DMA2_Stream0;
  41.     ADC1DMA_Handler.Init.Channel = DMA_CHANNEL_0;
  42.     ADC1DMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY;
  43.     ADC1DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;               //外设非增量模式
  44.     ADC1DMA_Handler.Init.MemInc = DMA_MINC_ENABLE;                   //存储器增量模式
  45.     ADC1DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设数据长度:16位
  46.     ADC1DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //存储器数据长度:16位
  47.     ADC1DMA_Handler.Init.Mode = DMA_NORMAL;                          //传输一次就结束
  48.     ADC1DMA_Handler.Init.Priority = DMA_PRIORITY_LOW;             //中等优先级
  49.     ADC1DMA_Handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE;            /* 禁止FIFO*/
  50.     /*自己增加中断回调函数*/
  51. //    ADC1DMA_Handler.XferCpltCallback = ADC1DMA_CpltCallback;
  52. //    ADC1DMA_Handler.XferHalfCpltCallback = ADC1DMA_HalfCpltCallback;
  53. //    ADC1DMA_Handler.XferM1CpltCallback = ADC1DMA_M1CpltCallback;
  54. //    ADC1DMA_Handler.XferM1HalfCpltCallback = ADC1DMA_M1HalfCpltCallback;
  55. //    ADC1DMA_Handler.XferErrorCallback = ADC1DMA_ErrorCallback;
  56. //    ADC1DMA_Handler.XferAbortCallback = ADC1DMA_XferAbortCallback;
  57.     /*最后发现并没有什么用*/
  58.     HAL_DMA_Init(&ADC1DMA_Handler);

  59.     __HAL_LINKDMA(&ADC1_Handler, DMA_Handle, ADC1DMA_Handler);                //将DMA与ADC联系起来


  60.     ADC1_Handler.Instance = ADC1;
  61.     ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ
  62.     ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B;           //12位模式
  63.     ADC1_Handler.Init.ScanConvMode = DISABLE;                    //非扫描模式
  64.     ADC1_Handler.Init.ContinuousConvMode = DISABLE;              //关闭连续转换
  65.     ADC1_Handler.Init.DiscontinuousConvMode = DISABLE;           //禁止不连续采样模式
  66.     ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发
  67.     ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START;     //软件触发
  68.     ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT;           //右对齐
  69.     ADC1_Handler.Init.NbrOfConversion = 1;                       //1个转换在规则序列中 也就是只转换规则序列1
  70.     ADC1_Handler.Init.DMAContinuousRequests = DISABLE;           //关闭DMA请求
  71.     ADC1_Handler.Init.EOCSelection = ADC_EOC_SINGLE_CONV;        
  72.     HAL_ADC_Init(&ADC1_Handler);

  73.     ADC1_ChanConf.Channel = ADC_CHANNEL_5;                                 //通道
  74.     ADC1_ChanConf.Rank = 1;                                     //1个序列
  75.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间
  76.     ADC1_ChanConf.Offset = 0;
  77.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置

  78.     HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 1);

  79. }

  80. //ADC底层驱动,引脚配置,时钟使能
  81. //此函数会被HAL_ADC_Init()调用
  82. //hadc:ADC句柄
  83. void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
  84. {
  85.     GPIO_InitTypeDef GPIO_Initure;
  86.     __HAL_RCC_ADC1_CLK_ENABLE();            //使能ADC1时钟
  87.     __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟

  88.     GPIO_Initure.Pin = GPIO_PIN_5;          //PA5
  89.     GPIO_Initure.Mode = GPIO_MODE_ANALOG;   //模拟
  90.     GPIO_Initure.Pull = GPIO_NOPULL;        //不带上下拉
  91.     HAL_GPIO_Init(GPIOA, &GPIO_Initure);
  92. }

  93. void DMA2_Stream0_IRQHandler(void)
  94. {
  95.     HAL_DMA_IRQHandler(&ADC1DMA_Handler);
  96. }

  97. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
  98. {
  99.         printf("DMA transfer complete\r\n");
  100. }
  101. void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)
  102. {
  103.         printf("DMA Half transfer complete\r\n");
  104. }

  105. void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
  106. {
  107.         printf("DMA transfer error\r\n");
  108. }
复制代码

注意,代码里注释的部分是,虽然我们在对DMA初始化的时候,我将DMA相应的回调函数参数都设置好了,但初始化完成之后,其中有三个函数并没有指向我们设置的函数,而是指向了具有__weak属性的三个函数。

20200419141009399.png


这是因为在进行ADC初始化的时候,重写了ADC使用的DMA的回调函数。

20200419141507473.png


所以最终是直接重写三个函数就行了,不用再去设置。

main函数中也不需要去调用,直接打印数据就可以了。

  1. #include "sys.h"
  2. #include "delay.h"
  3. #include "usart.h"

  4. #include "adc.h"

  5. extern ADC_HandleTypeDef ADC1_Handler;//ADC句柄
  6. extern uint16_t buffer[128];

  7. void show()
  8. {
  9.     int i;
  10.     printf("\r\ndata:");
  11.     for (i = 0; i < 128; i++)
  12.     {
  13.         if (i % 16 == 0) printf("\r\n");
  14.         printf("%6d", buffer<i>);

  15.   </i>  }
  16.     printf("\r\n");
  17. }


  18. int main(void)
  19. {
  20.     Cache_Enable();                 //打开L1-Cache
  21.     HAL_Init();                     //初始化HAL库
  22.     Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz
  23.     delay_init(216);                //延时初始化
  24.     uart_init(115200);              //串口初始化

  25.     printf("start\r\n");
  26.     MY_ADC_Init();                  //初始化ADC1通道5

  27.     while (1)
  28.     {
  29.         show();
  30.         delay_ms(1000);
  31.     }
  32. }
复制代码

实际打印结果如图:

20200419142446515.png


当我们需要进行多个通道采集的时候,先修改CubeMX配置,改为扫描模式,修改规则通道的转换数目,修改相应的Rank内容:

20200419142957395.png


生成完代码后,启动函数长度修改位转换长度:

  1. HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 2);
复制代码

修改后的ADC完整代码如下:

  1. #include "adc.h"
  2. #include "delay.h"

  3. ADC_HandleTypeDef ADC1_Handler;//ADC句柄
  4. DMA_HandleTypeDef ADC1DMA_Handler;
  5. ADC_ChannelConfTypeDef ADC1_ChanConf;

  6. uint16_t buffer[128];


  7. //初始化ADC
  8. //ch: ADC_channels
  9. //通道值 0~16取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
  10. void MY_ADC_Init(void)
  11. {
  12.     __HAL_RCC_DMA2_CLK_ENABLE();
  13.     HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
  14.     HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);

  15.     ADC1DMA_Handler.Instance = DMA2_Stream0;
  16.     ADC1DMA_Handler.Init.Channel = DMA_CHANNEL_0;
  17.     ADC1DMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY;
  18.     ADC1DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;               //外设非增量模式
  19.     ADC1DMA_Handler.Init.MemInc = DMA_MINC_ENABLE;                   //存储器增量模式
  20.     ADC1DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设数据长度:16位
  21.     ADC1DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //存储器数据长度:16位
  22.     ADC1DMA_Handler.Init.Mode = DMA_NORMAL;                          //传输一次就结束
  23.     ADC1DMA_Handler.Init.Priority = DMA_PRIORITY_LOW;             //中等优先级
  24.     ADC1DMA_Handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE;            /* 禁止FIFO*/

  25.     HAL_DMA_Init(&ADC1DMA_Handler);

  26.     __HAL_LINKDMA(&ADC1_Handler, DMA_Handle, ADC1DMA_Handler);                //将DMA与ADC联系起来


  27.     ADC1_Handler.Instance = ADC1;
  28.     ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ
  29.     ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B;           //12位模式
  30.     ADC1_Handler.Init.ScanConvMode = ENABLE;                    //非扫描模式
  31.     ADC1_Handler.Init.ContinuousConvMode = DISABLE;              //关闭连续转换
  32.     ADC1_Handler.Init.DiscontinuousConvMode = DISABLE;           //禁止不连续采样模式
  33.     ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发
  34.     ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START;     //软件触发
  35.     ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT;           //右对齐
  36.     ADC1_Handler.Init.NbrOfConversion = 2;                       //1个转换在规则序列中 也就是只转换规则序列1
  37.     ADC1_Handler.Init.DMAContinuousRequests = DISABLE;           //关闭DMA请求
  38.     ADC1_Handler.Init.EOCSelection = ADC_EOC_SINGLE_CONV;        
  39.     HAL_ADC_Init(&ADC1_Handler);

  40.     ADC1_ChanConf.Channel = ADC_CHANNEL_5;                                 //通道
  41.     ADC1_ChanConf.Rank = 1;                                     //序列1
  42.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间
  43.     ADC1_ChanConf.Offset = 0;
  44.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置

  45.     ADC1_ChanConf.Channel = ADC_CHANNEL_6;                                 //通道
  46.     ADC1_ChanConf.Rank = 2;                                     //序列2
  47.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间
  48.     ADC1_ChanConf.Offset = 0;
  49.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置

  50.     HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 2);

  51. }

  52. //ADC底层驱动,引脚配置,时钟使能
  53. //此函数会被HAL_ADC_Init()调用
  54. //hadc:ADC句柄
  55. void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
  56. {
  57.     GPIO_InitTypeDef GPIO_Initure;
  58.     __HAL_RCC_ADC1_CLK_ENABLE();            //使能ADC1时钟
  59.     __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟

  60.     GPIO_Initure.Pin = GPIO_PIN_5|GPIO_PIN_6;          //PA5
  61.     GPIO_Initure.Mode = GPIO_MODE_ANALOG;   //模拟
  62.     GPIO_Initure.Pull = GPIO_NOPULL;        //不带上下拉
  63.     HAL_GPIO_Init(GPIOA, &GPIO_Initure);
  64. }

  65. void DMA2_Stream0_IRQHandler(void)
  66. {
  67.     HAL_DMA_IRQHandler(&ADC1DMA_Handler);
  68. }

  69. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
  70. {
  71.         printf("DMA transfer complete\r\n");
  72. }
  73. void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)
  74. {
  75.         printf("DMA Half transfer complete\r\n");
  76. }

  77. void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
  78. {
  79.         printf("DMA transfer error\r\n");
  80. }
复制代码

效果如图:

20200419143301632.png





收藏 评论0 发布时间:2021-12-12 21:25

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版