【STM32】STM32CUBEMX + ADC(单通道,双通道DMA)

2023-11-04

STM32CUBEMX + ADC(单通道,双通道DMA)

案例应用 :使用ADC采集电压(单通道、单通道+DMA、双通道+DMA),并利用串口打印采集转换后的电压值

1.工具

2.工程配置

2.1 单通道

2.1.1系统时钟RCC、SYS配置
在这里插入图片描述
2.1.2 ADC配置,这里强调2点,

  • 使用ADC1——>IN4(通道4),本案例使用F4开发版,在12bit分辨率下,最小转换时间为15周期(最小转换时间 > 采样时间,具体可以百度),本案例转换时间为 15/16M = 0.937us

    (F4)最小转换时间:

    ​ 12bit——>15周期

    ​ 10bit——>13周期

    ​ 8bit——>11周期

    ​ 6bit——> 9周期
    在这里插入图片描述

  • 注入模式,可以这样理解:把注入模式看作为中断,若果有注入,注入优先(相较于规则),完成之后在继续规则模式
    在这里插入图片描述
    2.1.3 配置工程文件名、路径、ToolChain/IDE——>GENERATE CODE ,完成之后打开项目

​ 重定义printf函数具体见:【STM32】STM32CUBEMX+UART串口调试,循环接受发送数据

  • main.c

    #include "main.h"
    #include "adc.h"
    #include "usart.h"
    #include "gpio.h"
    #include "stdio.h"
    void SystemClock_Config(void);
    
    uint32_t ADC_Value;
    
    int main(void)
    {
      HAL_Init();
      SystemClock_Config();
    
      MX_GPIO_Init();
      MX_ADC1_Init();
      MX_USART2_UART_Init();
     
      printf("start\r\n");
      while (1)
      {
         HAL_ADC_Start(&hadc1);     //启动ADC转换
         HAL_ADC_PollForConversion(&hadc1, 50);   //等待转换完成,50为最大等待时间,单位为ms
    
         if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
        {
          ADC_Value = HAL_ADC_GetValue(&hadc1);   //获取AD值
    
          printf("ADC1 Reading : %d \r\n",ADC_Value);//采样的值
          printf("PA4 True Voltage value : %.4f \r\n",ADC_Value*3.3f/4096);
              //转化后的电压值
          }
              HAL_Delay(1000);
      }
    }
    
    

    2.2 单通道+DMA

    2.2.1 STM32CUBEMX配置与单通道大致一样,需要修改的见下图(开启DMA请求,并在DMA配置中添加ADC1
    在这里插入图片描述

    ——>注意:DMA配置里要选择 Mode选择Circular,Data Width选择 Word,(如果是HalfWord,则会将采集到的数值进行合并,范围超出2^12 = 4096)
    在这里插入图片描述

2.2.2 配置工程文件名、路径、ToolChain/IDE——>GENERATE CODE ,完成之后打开项目

  • main.c
#include "main.h"
#include "adc.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"
#include "stdio.h"

void SystemClock_Config(void);

uint32_t ADC_Value[100];
uint8_t i;
float ad1 = 0;

int main(void)
{ 
  HAL_Init();
  SystemClock_Config();

  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_USART2_UART_Init();
  //开启ADC_DMA采集
  HAL_ADC_Start_DMA(&hadc1, ADC_Value, 100);//DMA自动把对应的通道值放入ADC_Value数组内
  
  while (1)
  {
    //数据处理 与 DMA存值 不同步 ,在这里判断下转换是否完成,完成则进行数据处理
     if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
     {          
	          for(i = 0; i < 100; i++)//数据处理 与 DMA存值 不同步  
	          {
	                ad1 += ADC_Value[i];       
	          }  
                       ad1 /=  100.0;
                       printf("PA4 Reading Vol Value: %.4f \r\n", ad1*3.3f/4096);
                       HAL_Delay(500);
	
     }
    
  }
  /* USER CODE END 3 */
}

DMA:搬运数据思想
将一块内存的数据搬到另外一块内存,(注意内存可位于系统内部,也可位于外部设备,其实就是一块地址,形象的可理解为buf[], 某个寄存器等。)
在搬运的时候,1次搬运的数据大小必须是2的n次方(n= 0,1…),只要设置好相应外设的dma映射通道号(这一部分是由hardware designer设计的),以及其他相应配置,并使能DMA功能, 它就自动开始搬运了,(内存到内存这种方式是相对较快的)。

2.3 多通道+DMA

2.3.1 STM32CUBEMX配置与单通道+DMA大致一样,需要修改的见下图(2个通道IN4、IN6, 开启连续扫描模式;并注意Rank下选择不同的通道,不配置默认通道 相同,我刚开始没有配置,结果2个引脚采集的值一样,浪费了半天时间找原因…)
在这里插入图片描述
在这里插入图片描述

2.3.2 配置工程文件名、路径、ToolChain/IDE——>GENERATE CODE ,完成之后打开项目

  • main.c

    #include "main.h"
    #include "adc.h"
    #include "dma.h"
    #include "usart.h"
    #include "gpio.h"
    #include "stdio.h"
    
     uint32_t ADC_1 = 0, ADC_2 = 0;
     uint32_t ADC_Value[100];
     uint8_t i;
    
    int main(void)
    {
      HAL_Init();
    
      SystemClock_Config();
    
      MX_GPIO_Init();
      MX_DMA_Init();
      MX_ADC1_Init();
      MX_USART2_UART_Init();
    
      HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_Value, 100);//100数据量
      printf("ADC Sampling start\r\n");
    
      while (1)
      {
         
          HAL_Delay(500);//这里不加延时,采集输出值第一次为0 
          for(i=0; i<100;)
         {
          ADC_1 = ADC_Value[i++];   
          ADC_2 = ADC_Value[i++];
         }
          printf("double channel ADC test\r\n");
          printf("ADC_1 = %1.4f\r\n", ADC_1*3.3f/4096);
          printf("ADC_2 = %1.4f\r\n", ADC_2*3.3f/4096);
    
      }
      
    
    
    }
    

函数HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length);//第三个参数我还是不明白,但是支持数据量,库函数这样解释:
在这里插入图片描述
很多人说是数据量,不是长度,我很纳闷(数据量分2种情况:

1.单通道 1次将采集的length个数据存放到存储区,然后执行下一次采集存放,
2.多通道 1次将采集的length个数据存放到存储区,然后执行下一次采集存放,length应为
通道数的倍数 保证每个通道的数据量持平

如有不同见解可留言

ADC单通道采集:STM32CUBEMX+ADC采集,STM32F411VET6, IAR

ADC单通道+DMA采集:STM32CUBEMX+ADC单通道+DMA采集,STM32F411VET6, IAR

ADC多通道+DMA采集:STM32CUBEMX+ADC双通道+DMA采集,STM32F411VET6, IAR

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【STM32】STM32CUBEMX + ADC(单通道,双通道DMA) 的相关文章

  • WCF RIA 服务 - 加载多个实体

    我正在寻找一种模式来解决以下问题 我认为这很常见 我正在使用 WCF RIA 服务在初始加载时将多个实体返回给客户端 我希望两个实体异步加载 以免锁定 UI 并且我想利用 RIA 服务来执行此操作 我的解决方案如下 似乎有效 这种方法会遇到
  • 秒表有最长运行时间吗?

    多久可以Stopwatch在 NET 中运行 如果达到该限制 它会回绕到负数还是从 0 重新开始 Stopwatch Elapsed返回一个TimeSpan From MSDN https learn microsoft com en us
  • 不支持将数据直接绑定到存储查询(DbSet、DbQuery、DbSqlQuery)

    正在编码视觉工作室2012并使用实体模型作为我的数据层 但是 当页面尝试加载时 上面提到的标题 我使用 Linq 语句的下拉控件往往会引发未处理的异常 下面是我的代码 using AdventureWorksEntities dw new
  • 查找c中结构元素的偏移量

    struct a struct b int i float j x struct c int k float l y z 谁能解释一下如何找到偏移量int k这样我们就可以找到地址int i Use offsetof 找到从开始处的偏移量z
  • Asp.NET WebApi 中类似文件名称的路由

    是否可以在 ASP NET Web API 路由配置中添加一条路由 以允许处理看起来有点像文件名的 URL 我尝试添加以下条目WebApiConfig Register 但这不起作用 使用 URIapi foo 0de7ebfa 3a55
  • 为什么当实例化新的游戏对象时,它没有向它们添加标签? [复制]

    这个问题在这里已经有答案了 using System Collections using System Collections Generic using UnityEngine public class Test MonoBehaviou
  • 从Web API同步调用外部api

    我需要从我的 Web API 2 控制器调用外部 api 类似于此处的要求 使用 HttpClient 从 Web API 操作调用外部 HTTP 服务 https stackoverflow com questions 13222998
  • 如何使用 ICU 解析汉字数字字符?

    我正在编写一个使用 ICU 来解析由汉字数字字符组成的 Unicode 字符串的函数 并希望返回该字符串的整数值 五 gt 5 三十一 gt 31 五千九百七十二 gt 5972 我将区域设置设置为 Locale getJapan 并使用
  • Clang 3.1 + libc++ 编译错误

    我已经构建并安装了 在前缀下 alt LLVM Clang trunk 2012 年 4 月 23 日 在 Ubuntu 12 04 上成功使用 GCC 4 6 然后使用此 Clang 构建的 libc 当我想使用它时我必须同时提供 lc
  • 将 VSIX 功能添加到 C# 类库

    我有一个现有的单文件生成器 位于 C 类库中 如何将 VSIX 项目级功能添加到此项目 最终目标是编译我的类库项目并获得 VSIX 我实际上是在回答我自己的问题 这与Visual Studio 2017 中的单文件生成器更改 https s
  • C# 中通过 Process.Kill() 终止的进程的退出代码

    如果在我的 C 应用程序中 我正在创建一个可以正常终止或开始行为异常的子进程 在这种情况下 我通过调用 Process Kill 来终止它 但是 我想知道该进程是否已退出通常情况下 我知道我可以获得终止进程的错误代码 但是正常的退出代码是什
  • 将多个表映射到实体框架中的单个实体类

    我正在开发一个旧数据库 该数据库有 2 个具有 1 1 关系的表 目前 我为每个定义的表定义了一种类型 1Test 1Result 我想将这些特定的表合并到一个类中 当前的类型如下所示 public class Result public
  • 如何序列化/反序列化自定义数据集

    我有一个 winforms 应用程序 它使用强类型的自定义数据集来保存数据进行处理 它由数据库中的数据填充 我有一个用户控件 它接受任何自定义数据集并在数据网格中显示内容 这用于测试和调试 为了使控件可重用 我将自定义数据集视为普通的 Sy
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • 如何查看网络连接状态是否发生变化?

    我正在编写一个应用程序 用于检查计算机是否连接到某个特定网络 并为我们的用户带来一些魔力 该应用程序将在后台运行并执行检查是否用户请求 托盘中的菜单 我还希望应用程序能够自动检查用户是否从有线更改为无线 或者断开连接并连接到新网络 并执行魔
  • 链接器错误:已定义

    我尝试在 Microsoft Visual Studio 2012 中编译我的 Visual C 项目 使用 MFC 但出现以下错误 error LNK2005 void cdecl operator new unsigned int 2
  • 对现有视频添加水印

    我正在寻找一种用 C 在视频上加水印的方法 就像在上面写文字一样 图片或文字标签 我该怎么做 谢谢 您可以使用 Nreco 视频转换器 代码看起来像 NReco VideoConverter FFMpegConverter wrap new
  • 通过指向其基址的指针删除 POD 对象是否安全?

    事实上 我正在考虑那些微不足道的可破坏物体 而不仅仅是POD http en wikipedia org wiki Plain old data structure 我不确定 POD 是否可以有基类 当我读到这个解释时is triviall
  • cmake 将标头包含到每个源文件中

    其实我有一个简单的问题 但找不到答案 也许你可以给我指一个副本 所以 问题是 是否可以告诉 cmake 指示编译器在每个源文件的开头自动包含一些头文件 这样就不需要放置 include foo h 了 谢谢 CMake 没有针对此特定用例的
  • IEnumreable 动态和 lambda

    我想在 a 上使用 lambda 表达式IEnumerable

随机推荐