• STM32CUBEIDE(10)----ADC在DMA模式下扫描多个通道


    概述

    本章STM32CUBEMX配置STM32F103的ADC在DMA模式扫描多个通道,通过串口进行打印。
    最近在弄ST和GD的课程,需要样片的可以加群申请:615061293。

    视频教学

    csdn课程

    课程更加详细。
    https://download.csdn.net/course/detail/35611

    生成例程

    使用STM32CUBEMX生成例程,这里使用NUCLEO-F103RB开发板
    在这里插入图片描述
    查看原理图,PA2和PA3设置为开发板的串口
    在这里插入图片描述
    配置串口。

    在这里插入图片描述
    开启中断。
    在这里插入图片描述
    查看原理图,Arduino的接口A0-A5都是AD口。
    在这里插入图片描述
    ADC通道配置

    ADC1IN0(PA0)IN1(PA1)IN4(PA4)

    ADC1配置。

    在这里插入图片描述

    • ADCs_Common_Settings:
      • Mode:Independent mod 独立 ADC 模式,当使用一个 ADC 时是独立模式,使用两个 ADC 时是双模式,在双模式下还有很多细分模式可选,具体配置 ADC_CR1:DUALMOD 位。
    • ADC_Settings:
      • Data Alignment:
        • Right alignment 转换结果数据右对齐,一般我们选择右对齐模式。
        • Left alignment 转换结果数据左对齐。
      • Scan Conversion Mode:
        • Disabled 禁止扫描模式。如果是单通道 AD 转换使用 DISABLE。
        • Enabled 开启扫描模式。如果是多通道 AD 转换使用 ENABLE。
      • Continuous Conversion Mode:
        • Disabled 单次转换。转换一次后停止需要手动控制才重新启动转换。
        • Enabled 自动连续转换。
      • DiscontinuousConvMode:
        • Disabled 禁止间断模式。这个在需要考虑功耗问题的产品中很有必要,也就是在某个事件触发下,开启转换。
        • Enabled 开启间断模式。
    • ADC_Regular_ConversionMode:
      • Enable Regular Conversions 是否使能规则转换。
      • Number Of Conversion ADC转换通道数目,有几个写几个就行。
      • External Trigger Conversion Source 外部触发选择。这个有多个选择,一般采用软件触发方式。
    • Rank:
      • Channel ADC转换通道
      • Sampling Time 采样周期选择,采样周期越短,ADC 转换数据输出周期就越短但数据精度也越低,采样周期越长,ADC 转换数据输出周期就越长同时数据精度越高。
    • ADC_Injected_ConversionMode:
      • Enable Injected Conversions 是否使能注入转换。注入通道只有在规则通道存在时才会出现。
    • WatchDog:
      • Enable Analog WatchDog Mode 是否使能模拟看门狗中断。当被 ADC 转换的模拟电压低于低阈值或者高于高阈值时,就会产生中断。

    DMA开启。
    在这里插入图片描述

    生成独立的文件。
    在这里插入图片描述

    STM32CUBEIDE配置

    在这里插入图片描述
    若需要打印浮点型,需要勾选下面的选项。
    在这里插入图片描述

    串口重定向

    在main.c中,添加头文件,若不添加会出现 identifier “FILE” is undefined报错。

    /* USER CODE BEGIN Includes */
    #include "stdio.h"
    /* USER CODE END Includes */
    
    • 1
    • 2
    • 3

    函数声明和串口重定向:

    /* USER CODE BEGIN PFP */
    #ifdef __GNUC__									//串口重定向
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
    #else
    #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
    #endif 
    PUTCHAR_PROTOTYPE
    {
        HAL_UART_Transmit(&huart2 , (uint8_t *)&ch, 1, 0xFFFF);
        return ch;
    }
    /* USER CODE END PFP */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    代码

    定义变量,存放采集到的数据。

    /* USER CODE BEGIN 0 */
    uint32_t ADC1_1, ADC1_2,ADC1_3;//采集的三个通道的ADC
    uint32_t ADC1_Value[30];//DMA存放数组
    uint8_t i;
    uint8_t ADC1_Flag;//dma采集完毕中断
    /* USER CODE END 0 */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    使能ADC传输。

      /* USER CODE BEGIN 2 */
      HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ADC1_Value,30);    //使用DMA传输
      /* USER CODE END 2 */
    
    • 1
    • 2
    • 3

    主循环。

      /* USER CODE BEGIN WHILE */
      while (1)
      {
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
    	  if(ADC1_Flag==1)
    	  {
    		  ADC1_Flag=0;
    		  ADC1_1=0;
    		  ADC1_2=0;
    		  ADC1_3=0;
    		  for(i=0;i<30;)
    		  {
    			  ADC1_1+=ADC1_Value[i++];
    			  ADC1_2+=ADC1_Value[i++];
    			  ADC1_3+=ADC1_Value[i++];
    		  }
    		  printf("\n");
    		  printf("adc1_IN0(PA0)=%4.0d,ADC_IN0=%1.4f\r\n",ADC1_1/10,ADC1_1/10*3.3f/4096);
    		  printf("adc1_IN1(PA1)=%4.0d,ADC_IN1=%1.4f\r\n",ADC1_2/10,ADC1_2/10*3.3f/4096);
    		  printf("adc1_IN4(PA4)=%4.0d,ADC_IN2=%1.4f\r\n",ADC1_3/10,ADC1_3/10*3.3f/4096);
    		  HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ADC1_Value,30);    //使用DMA传输
    	  }
    		HAL_Delay(1000);
      }
      /* USER CODE END 3 */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    ADC回调函数。
    DMA传输的时候如果读取内存片段,会有仲裁器的问题,加了一句关闭DMA的语句HAL_ADC_Stop_DMA(&hadc1);

    
    /* USER CODE BEGIN 4 */
    void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
    {
    	if(hadc->Instance == ADC1){
    		ADC1_Flag=1;
    		/*
    		 * DMA传输的时候如果读取内存片段,会有仲裁器的问题,加了一句关闭DMA的语
    
    		 */
    		HAL_ADC_Stop_DMA(&hadc1);
    	}
    }
    /* USER CODE END 4 */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    测试结果

    输入固定电压进行测试。

    ADC1IN0(PA0)IN1(PA1)IN4(PA4)
    输入电压VCC2.0VGND

    Normal下测试结果如下。
    在这里插入图片描述

    若不试用关闭DMA的语句HAL_ADC_Stop_DMA(&hadc1);
    会造成数据错乱。
    在这里插入图片描述

    Circular可以下可以一直进行采集,不需要HAL_ADC_Stop_DMA(&hadc1)都可。
    在这里插入图片描述

    最后

    以上的代码会在Q群里分享。QQ群:615061293。
    或者关注微信公众号『记帖』,持续更新文章和学习资料,可加作者的微信交流学习!
    在这里插入图片描述

  • 相关阅读:
    web缓存—Squid代理服务
    进程的通信 - 邮槽
    MQ篇---第三篇
    爱心html的网页
    全网最全面最深入 剖析华为“五看三定”战略神器中的“五看”(即市场洞察)(长文干货,建议收藏)
    2020华数杯全国大学生数学建模竞赛A题-低温防护服御寒仿真模拟(二)(附带赛题解析&获奖论文及MATLAB代码)
    java毕业设计健民中医药方网设计(附源码、数据库)
    实战二十一:基于KERL模型实现用户购买商品推荐 代码+数据(可作为毕设项目)
    内窥镜系统设计简介
    MySQL是如何保证主从一致的
  • 原文地址:https://blog.csdn.net/qq_24312945/article/details/126036132