dmBot Techical Forum

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 1982|回复: 1

2、STM32 HAL库 ADC

[复制链接]
回帖奖励 10 金钱 回复本帖可获得 1 金钱奖励! 每人限 1 次

67

主题

148

帖子

4万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
42664
发表于 2019-11-29 16:51:14 | 显示全部楼层 |阅读模式

dmBot循迹小车之ADC
1、简介
本例我们来讲解STM32单片机ADC转换,ADC,Analog-to-Digital Converter的缩写,是指模/数转换器或者模拟/数字转换器。其作用是将连续变量的模拟信号转换为离散的数字信号的器件。真实世界的模拟信号,例如温度、压力、声音或者图像等,都是连续信号,计算机无法处理连续的模拟信号,需要将这些连续的信号,转换成离散的数值,以二进制的形式存储。模/数转换器可以实现这个功能,在各种不同的产品中都可以找到它的身影。本节我们以dmBotS1为硬件平台,实例讲解ADC单通道读取、多通道读取[url=]、[/url]DMA的方式读取多通道ADC数据。
       STM32F103CBT6内置的12位ADC是一种逐次逼近型模拟数字转换器。[url=]它[/url] 有多达18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。 ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。注:此部分数据来自于《RM0008Reference manual》的第11章Analog-to-digital converter (ADC)
ADC主要特征:
l  12位分辨率
l 转换结束、注入转换结束和发生模拟看门狗事件时产生中断
l  单次和连续转换模式
l  从通道0到通道n的自动扫描模式
l  自校准
l  内置具有数据一致性的数据对齐
l  采样间隔可以按通道独立编程
l  规则转换和注入转换均有外部触发选项
l  间断模式
l  双重模式(带2个或以上ADC的器件)
l ADC转换时间:─ STM32F103xx增强型产品:外设[url=]时钟[/url]为56MHz时为1μs(时钟为72MHz为1.17μs)
l  ADC供电要求: 2.4V到3.6V
l ADC输入范围: VREF- ≤ VIN ≤ VREF+、
l  规则通道转换期间有DMA请求产生
ADC的参数介绍我们可以了解到,STM32内部集成的ADC结构是逐次逼近型(successiveapproximation analog-to-digital converter)SAR ADC的分辨率一般为8位至16位,具有低功耗、小尺寸等特点。这些特点使该类型ADC具有很宽的应用范围,例如便携/电池供电仪表、笔输入量化器、工业控制和数据/信号采集等。顾名思义,SAR ADC实质上是实现一种二进制搜索算法。所以,当内部电路运行在数兆赫兹(MHz)时,由于逐次逼近算法的缘故,ADC采样速率仅是该数值的几分之一。
1.1、SAR ADC的原理
尽管实现SAR ADC的方式千差万别,但其基本结构非常简单(如图1所示)。模拟输入电压(VIN)由采样/保持电路保持。为实现二进制搜索算法,N位寄存器首先设置在中间刻度(即:100....00,MSB设置为1)。这样,DAC输出(VDAC)被设为VREF/2,VREF是提供给ADC的基准电压。然后,比较判断VIN是小于还是大于VDAC。如果VIN大于VDAC,则比较器输出逻辑高电平或1,N位寄存器的MSB保持为1。相反,如果VIN小于VDAC,则比较器输出逻辑低电平,N位寄存器的MSB清0。随后,SAR控制逻辑移至下一位,并将该位设置为高电平,进行下一次比较。这个过程一直持续到LSB。上述操作结束后,也就完成了转换,N位转换结果储存在寄存器内。


1.png
1简单的NSAR ADC架构
下图给出了一个4位转换示例,y轴(和图中的粗线)表示DAC的输出电压。本例中,第一次比较表明VIN < VDAC。所以,位3置为0。然后DAC被置为01002,并执行第二次比较。由于VIN >VDAC,位2保持为1。DAC置为01102,执行第三次比较。根据比较结果,位1置0,DAC又设置为01012,执行最后一次比较。最后,由于VIN > VDAC,位0确定为1。
2.png
2  SAR工作原理(4ADC为例)
       AR ADC就是通过不断的比较,然后得出电压的近似值,如果ADC12位,那么一次转换过程就是12次比较的过程,通过每次二分比较大小的方式确定待测值的范围。从SAR工作原理可以看出来,最终得到的电压值并非实际测试值,而是一个范围。ADC的精度越高也就是位数越大,这个近似的范围就越小,测量数值和真实值间的差距就越小。
1.2、STM32 ADC框图
了解了SAR ADC的工作原理,下面我们通过STM32内部ADC框图来了解一下具体的实现流程。注:该截自《RM0008Reference manual》11.3 ADC functional description Figure22。
3.png
3 ADC内部框图
从STM32 ADC框图我们可以看出,通过Analog MUX(模拟开关)将ADC通道与ADCx_Inx连接至Injected channels/Regular channels,ADC将连进来的模拟型号转换并存入Regulardata register,之后CPU通过Address/data bus访问寄存器中转换好的数值。
       一个ADC只有一个转换器,但是可以通过模拟开关将不同的通道连接到转换器,进行一次模数转换,其过程是分时复用。其中模拟开关连接到转换器的通道可以被分为两组,一组是Injectedchannels注入通道,另一组是Regularchannels规则通道。规则组是按照程序的设定,顺序转换该组内的特定通道序列,从头到尾循环转换。注入通道是在触发信号时,才开始转换,转换完成便结束转换进程,等待下一次触发才会转换。这两种通道可以搭配使用,也可以单独使用。
STM32ADC模式
[url=]l 扫描[/url][W用4] 模式:按照顺序扫描所有通道,对每一个通道进行AD转换。
l  连续模式:若转换序列中只有一个通道,则对该通道转换一次结束后立马开始下一次转换;若序列中有多个通道,则这个通道转换完后立马开始下一个通道的转。
l  单次模式(连续转换disabled):每次开启转换只能转换一次。若要再进行AD转换,需要再次启动转换。
l  间断模式(discontinuous):间断模式只能和单次转换模式一起使用,当序列内有(0,1,2,....,8)9个通道时,若间断数目设为3,使用扫描模式,则第一次转换的通道是(0,1,2).第二次转换的通道是(3,4,5)第三次转换的通道时(6,7,8).记得使用单次换每次转换结束后都需要再开启转换,否则只会转换一次。
1.3、DMA简介
ADC转换之后的数据每次都需要CPU读取、然后处理,当间断读取寄存器转换数据的时候,这种操作不会占用太多的CPU资源,但是当需要连续转换的场景下,CPU就要不停地读取寄存器中的数据,这种操作会占用CPU的一定的运算时间。为了解决这种弊端,可以使用DMA(Directmemory access controller,直接内存访问控制器)技术。直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输,无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源。 我们可以通过下面两组图片直观了解DMA的优点。
4-1.jpg 4-2.png
4 CPU直接访问与DMA访问的区别
1.4、温度传感器:
       从ADC框图我们可以看到,连接ADC的模拟开关除了连接外部ADC通道之外,还将内部的Temp. sensor、VREFINT 信号连接到了ADC,其中Temp. sensor是STM32内部的温度传感器,可以测量STM32内部的温度。在《RM0008Reference manual》的11.10 Temperature sensor 章节,我们可以看到内部温度传感器的参数以及电压值和温度值之间的换算关系。从下图5中可到STM32F1系列内部温度传感器个体间差异较大(高达45℃),本节我们仅介绍读取的过程和转换方法,最终转换出来的温度数据仅具备相对值的参考作用,不能作为绝对值来使用。
5.png
5 STM32内部温度传感器

6.png

图 6 STM32 内部温度传感器特性及温度计算公式

从《RM0008 Reference manual》的11.10 Temperature sensor节([url=]如上图[/url]6所示[W用5] ),从手[W用6] 册可以得出温度传感器的转换公式Temperature (in °C)= {(V25 - VSENSE) / Avg_Slope } + 25,其中V25、Avg_Slope参数可以从STM32F103的数据手册的5.3.21 Temperature sensor characteristics章节如下图所示中查到,需要注意的是Avg_Slope参数的单位是是mV/℃,实际计算的时候需要转换为V/℃。实际计算公式如下所示:
temperature=(1000*(1.43- 3.3*ADC_VALE/4096)/4.3)+2  
其中ADC_VALE是实际电压值
7.png
7 温度传感器特性
1.5、dmBot ADC硬件介绍
从原理图的红外对管检测电路可以看出,ADC1_CH0、ADC1_CH1、ADC1_CH2、ADC1_CH3、ADC1_CH4在硬件上与红外对管的输出相连接,本节我们用这几个通道以及ADC1_CH16(与内部温度传感器相连) 来示例ADC的操作。
8.png
8 红外对管检测电路
9.png
9 ADC通道与PCBA位置对应关系
1.6红外对管原理
红外对管在结构上由一个红外发射管,和一个红外接收管成对存在,因此叫红外对管。红外发射管工作在940nm附近(不同的管子可能有所不同,具体参数以数据手册中的参数为准,此处仅以dmBot中所用到的ITR2000为例说明),该频段属于红外光,且是不可见光,可以借助手机摄像头观察红外灯是否[W用7] 工作,因摄像头的感光范围与人眼不同,摄像头[url=]有可以对红外波段感光[/url][W用8] 。这个特性也是摄像头在漆黑的夜里可以拍摄黑白照片的原因(需红外灯补光)。红外接收管是一个对红外光谱敏感的器件,当接收到红外光时,接收管正向导通。红外光照的强度不同,红外接收管的导通程度不同,光照越强,流过红外接收管的电流越大,此时ADC采集节点上的电压越低。我们实际测试的时候可以使用反光的物体在红外对光正下方测试,根据靠近的远近不同可以观察ADC采集到的数值变化。
10.png
10 光谱图
11-1.png 11-2.png
11红外亮灭对比图
1.7、ADC数值与实际电压的关系
STM32内部集成ADC的精度是12bit,参考电压是3.3V。12bit所能表示的数值范围是0~4095,也就是ADC的数值是0的时候,所对应的电压是0V;ADC的数值是4095的时候,所对应的电压是3.3V,且这两者之前存在线性关系,因此可以推导出u=adc*3.3/4095.
2、软件实现
       本节我们以三种方式实现ADC的采集,这三种分别是:单通道ADC采集、多通道ADC采集和DMA多通道ADC采集。
2.1、单通道ADC采集
采样步骤:
l  配置ADC通道
l  配置规则组通道
l  开始ADC转换
l  等待转换完成并读取寄存器值
2.1.1、STM32CuBeMX配置
此处省略配置主控芯片,具体步骤可参考上一讲。
2.1.1.1、配置时钟
选中RCC,在右侧窗口的High Speed Clock(HSE)菜单中选择Crystal/Ceramic Resonator,此时右侧仿真图中的晶振管脚自动被选中(此选项为外部高速时钟,下一个选项Low Speed Clock为32.768KHz晶振配置,Master Clock Output为配置特定管脚晶振输出)
12.png
12配置HSE时钟管脚
2.1.1.2、配置时钟树:
选中Clock Configuration界面,我们的dmBot使用的12MHz无源晶振,因此在时钟频率窗口输入12,并在HCLK(MHz)窗口填入72并按下回车键,此时软件将自动配置时钟树(芯片最大运行频率是72MHz,因此HCLK输入的是72,关于时钟树的详细介绍读者可以查阅《RM0008 Reference manual》中的第七章Low-, medium-,high- and XL-density reset and clock control (RCC))。注:STM32F103CBTx容量属于Medium-density。
13.png
13配置时钟树
2.1.1.3、配置SWD调试接口
在Pinout&Configuration页面选择System Core中的SYS,在右边选择框的Debug窗口选择Serial Wire,右侧Pinout view就会自动选中SWCLK和SWDIO管脚。
14.png
14配置SWD调试接口
2.1.1.4、配置ADC
在Pinout&Configuration页面选择Analog中的ADC1,在右侧ADC1Mode Configuration中勾选IN0,并在ParameterSettings中配置ADC的相关模式,此处我们仅读取一个通道的ADC值,因此Mode选择独立模式。
15.png
15 ADC配置
2.1.1.5、生成工程
选择Project Manager页面,在Project Name栏输入工程名称:dmBot-ADC-single,在Project Location栏选择功能存放位置;在Toolchain/IDE栏选择MDK-ARM V5(此处我们以MDK为例介绍,其余类似);此时工程配置工作已完成,仅需点击右上角GENERATE CODE旋钮,稍等片刻即可生成一个新的工程,在稍后的弹出窗选择OpenProject(需提前安装好MDK5软件,才能正确打开工程文件)。
16.png
16 生成工程
2.1.2、修改工程代码
首先我们在main.c文件中申请变量adc用于保存ADC转换过后的数值,其次在while循环中启动ADC1采集HAL_ADC_Start(&hadc1),然后等待ADC转换完成,等转换完成后使用HAL_ADC_GetValue(&hadc1);读取ADC寄存器中的数据。
while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
    HAL_ADC_Start(&hadc1);                            //开始AD采集
    HAL_ADC_PollForConversion(&hadc1,HAL_MAX_DELAY); //等待ADC转换完成,第一个参数是ADC,第二个参数超时时间
    adc = HAL_ADC_GetValue(&hadc1);                   //读取转换后的数据
    HAL_Delay(100);                                   //mS延时
  }
  /* USER CODE END 3 */
17.png
17 定义变量
18.png
18 添加ADC读取代码
2.1.3、编译
点击编译按钮file:///C:/Users/64482/AppData/Local/Temp/msohtmlclip1/01/clip_image040.jpg,主界面Build Output窗口输出编译log信息,其中0 Error(s), 0 Warning(s)表示工程没有错误和警告,并生成了可烧录文件dmBot-ADC-single.axf
Build started: Project: dmBot-ADC-single
*** Using Compiler 'V5.06 update 6 (build 750)',folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
Build target 'dmBot-ADC-single'
"dmBot-ADC-single\dmBot-ADC-single.axf"- 0 Error(s), 0 Warning(s).
Build Time Elapsed: 00:00:01
19.png
19 编译工程
20.png
20 编译输出log
2.1.4、配置下载
仿真器的选择可以根据实际情况自行配置,此处仅以J-link OB为例介绍。在Debug选项选择J-Link/J-trace Coxtex,并在Settings子页面选择SW接口。
21.png
21 配置仿真器选项
22.png
图22 配置SWD下载模式
23.png
23 配置下载后复位运行模式
2.1.5、软件[url=]调试[/url][W用9]
打开软件工程之后,单击工具栏中的file:///C:/Users/64482/AppData/Local/Temp/msohtmlclip1/01/clip_image052.jpg调试按钮,此时IDE会进入调试界面,点击工具栏中的file:///C:/Users/64482/AppData/Local/Temp/msohtmlclip1/01/clip_image054.jpg运行按钮,[W用9] 这样程序就已经在单片机中运行了,我们可以设置断点、单步运行,也可以查看变量的数值、外设寄存器的实时参数配置、单片机内部Flash中的数据。本节仅用到查看变量数值的功能,仅以此功能为例进行介绍,其余功能后续陆续讲解,读者也可以自行搜索相关资料学习。
24.png
24 IDE仿真界面
在仿真器的界面选中一个需要查看的变量,点击鼠标右键,在弹出的对话框中选择“Add ‘adc’ to …”,并选中子选项卡中的Watch1,此时在右侧的Watch1中便会出现所选的变量。默认情况下该变量以16进制的形式显示,可以通过选中Watch1中变量右键单击鼠标,在弹出的页面取消勾选Hexadecimal Display,即可以十进制的形式显示变量数值。如果调试界面发现Watch窗口中的变量没有发生变化,此时会有两种可能:
[url=]第一[/url][W用10] 、该变量是一个局部变量,只有在变量引用的地方打断点,且程序运行到该点的时候数值才会发生变化;
第二、IDE中没有勾选实时更新数据选项。选择工具栏中的View菜单、并在下拉选项中勾选Periodic Window Update即可。
25.png
25 实时监控某个变量
26.png
26变量显示进制修改
27.png
27 勾选实时更新数据选项
在仿真界面,通过使用反光的物体(不要使用黑色物体,黑色物体会吸光,镜子效果最佳)在红外对管U3正下方慢慢靠近,就可以看到adc变量数值不断变化。
2.2、多通道ADC采集
采样过程:
l  配置ADC通道
l  配置规则组通道
l  开始ADC转换
l  等待转换完成并读取寄存器值
由于HAL配置SQR3寄存器采用的|=运算,因此不能直接使用HAL_ADC_ConfigChannel函数切换通道,需要直接操作寄存器或者修改此函数来解决单个通道切换的问题。具体的跳转方式:MX_ADC1_Init();->if (HAL_ADC_ConfigChannel(&hadc1,&sConfig) != HAL_OK)->HAL_ADC_MspInit(hadc);->MODIFY_REG(hadc->Instance->SQR3, ADC_SQR3_RK(ADC_SQR3_SQ1,sConfig->Rank),               ADC_SQR3_RK(sConfig->Channel,sConfig->Rank) );-> #defineMODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))。
为了查看程序引用关系,我们经常需要用到跳转功能,下面简要介绍一下如何跳转到程序的声明位置。首先要确保工程被编译过(刚生工程不能跳转,需要编译一次),并且browseinformation选项被勾选。选中需要跳转的函数,右键单击鼠标,在弹出的选项卡中点击“GoTo Definition Of xxx”即可跳转到函数的声明处,查看函数的具体实现。[url=]注:某些函数可能是以函数库的形式出现,我们就无法看到函数的具体实现细节。[/url][W用11]
28-1.png 28-2.png
28 函数跳转过程
2.2.1、STM32CuBeMX配置
此处省略芯片选取、时钟配置、工程生成等步骤,仅给出与单通道ADC采集不同的操作。
2.2.1.1、配置ADC
此处选择IN0、IN1、IN2以及TemperatureSensor Channel,四个通道为例讲解多通道ADC采集。
29.png
29 ADC配置界面
2.2.2、修改工程代码
在main.c文件中定义一个16bit的数组,用来存储上述四个通道的ADC转换数值。
int16_t adc_ch[4];
在main函数的while循环中添加以下代码,
/* USER CODE BEGIN3 */
    hadc1.Instance->SQR3 = ADC_CHANNEL_0;  //设置通道
   HAL_ADC_Start(&hadc1);                   //开始ADC转换
   HAL_ADC_PollForConversion(&hadc1,20);     //等待转换完成
   adc_ch[0] = HAL_ADC_GetValue(&hadc1);     //读取ADC转换后的数值
   hadc1.Instance->SQR3 = ADC_CHANNEL_1;
   HAL_ADC_Start(&hadc1);
   HAL_ADC_PollForConversion(&hadc1,20);
   adc_ch[1] = HAL_ADC_GetValue(&hadc1);
   
   hadc1.Instance->SQR3 = ADC_CHANNEL_2;
   HAL_ADC_Start(&hadc1);
   HAL_ADC_PollForConversion(&hadc1,20);
   adc_ch[2] = HAL_ADC_GetValue(&hadc1);
   
   hadc1.Instance->SQR3 = ADC_CHANNEL_TEMPSENSOR;
   HAL_Delay(10);
   HAL_ADC_Start(&hadc1);
   HAL_ADC_PollForConversion(&hadc1,20);
   adc_ch[3] = HAL_ADC_GetValue(&hadc1);
              
temperature=(1000*(1.43- 3.3*adc_ch[3]/4096)/4.3)+25; //将电压值转换成温度值
30.png
30 添加ADC读取代码
2.2.3、仿真
仿真步骤与上述相同,此处不再赘述,仅展示不同处。运行仿真后,可以看到不同通道间数值的变化如下图所示。
31.png
图 31 仿真界面  

2.3、DMA多通道ADC采集图
采样过程:
l  配置ADC通道
l  配置规则组通道
l  配置DMA内存地址
l  开始ADC转换
2.3.1、STM32cubeMX配置
此处我们勾选IN0~IN5以及Temperature Sensor Channel七个通道,并一次设置7个规则组。在DMA Settings选项卡中单击DMA Request下方并选择ADC1,其余选项可以按照默认配置即可。
32.png
32 ADC通道配置
33.png
33 规则组配置
34.png
34 DMA 配置
2.3.2、修改工程代码
在main.c文件中定义一个16bit的数组,用来存储上述四个通道的ADC转换数值。
int16_t adc_ch[7;
由于采用DMA的方式采集,因此没必要在main函数的while循环中添加代码,仅在ADC初始化函数中配置DMA内存地址即可。
  /* USER CODE BEGIN ADC1_Init 2 */
   HAL_ADC_Start_DMA(&hadc1,(uint32_t*)adc_ch, 7);  //配置DMA内存地址adc_ch,以及内存长度
    HAL_ADC_Start(&hadc1);                        //开始ADC转换
  /* USER CODE END ADC1_Init 2 */
35.png
35 配置DMA地址程序
2.3.3、仿真结果
点击仿真按钮,并开始仿真,可以在右侧的变量栏中看到ADC的数值不断变化,这就是DMA神奇的地方,它可以直接将ADC转换后的数值拷贝到预先设定的内存中,不占用CPU的运算资源。
36.png
36 仿真结果
至此本节结束,下期再见。



附录:原理图


21.png








cubemx配置文件、生成的软件工程及PDF文档下载链接:
链接:https://pan.baidu.com/s/1iJTDzrHIT8qI7LlSn5r30Q
提取码:0z0k

网盘内容.png



回复

使用道具 举报

67

主题

148

帖子

4万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
42664
 楼主| 发表于 2019-11-29 16:51:15 | 显示全部楼层
如果大家发现连接无法打开请留言,我这边重新做。
回复

使用道具 举报

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

本版积分规则

QQ|Archiver|手机版|小黑屋|dmBot Inc. ( 粤ICP备19140833号-1 )

GMT+8, 2024-5-20 23:53 , Processed in 0.030448 second(s), 26 queries .

Powered by dmBot!

© 2001-2029 dmBot Inc.

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