第30章 ADC—电压采集—零死角玩转STM32-F429系列

CUBEMX配置STM32F407VET6 — ADC配置 STM32CUBEMX + ADC(单通道,双通道DMA)案例应用 :使用ADC采集电压(单通道、单通道+DMA、双通道+DMA),并利用串口打印采集转换后的电压值1.工具IARSTM32CUBEMX开发板STM32F411VET6预备知识参见:STM32】HAL库 STM32CubeMX教程九—ADC2.工程配置2.1 单通道2.1.1系统时钟RCC、SYS配置2.1.2 ADC配置,这里强调2点,使用ADC1——>IN4(通道4),本案例使用F4开发版,在12bit。ADC通道转换一次后,就停止转换。 阅读详情
第30章     ADC—电压采集

全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn

野火视频教程优酷观看网址:http://i.youku.com/firege

 

 

本章参考资料:《STM32F4xx中文参考手册》ADC章节。

学习本章时,配合《STM32F4xx中文参考手册》ADC章节一起阅读,效果会更佳,特别是涉及到寄存器说明的部分。

30.1 ADC简介

STM32F429IGT6有3个ADC,每个ADC有12位、10位、8位和6位可选,每个ADC有16个外部通道。另外还有两个内部ADC源和VBAT通道挂在ADC1上。ADC具有独立模式、双重模式和三重模式,对于不同AD转换要求几乎都有合适的模式可选。ADC功能非常强大,具体的我们在功能框图中分析每个部分的功能。

30.2 ADC功能框图剖析

图 01 单个ADC功能框图

掌握了ADC的功能框图,就可以对ADC有一个整体的把握,在编程的时候可以做到了然如胸,不会一知半解。框图讲解采用从左到右的方式,跟ADC采集数据,转换数据,传输数据的方向大概一致。

1.    ①电压输入范围

ADC输入范围为:VREF- ≤ VIN ≤ VREF+。由VREF-、VREF+ 、VDDA 、VSSA、这四个外部引脚决定。

我们在设计原理图的时候一般把VSSA和VREF-接地,把VREF+和VDDA 接3V3,得到ADC的输入电压范围为:0~3.3V。

如果我们想让输入的电压范围变宽,去到可以测试负电压或者更高的正电压,我们可以在外部加一个电压调理电路,把需要转换的电压抬升或者降压到0~3.3V,这样ADC就可以测量了。

2.    ②输入通道

我们确定好ADC输入电压之后,那么电压怎么输入到ADC?这里我们引入通道的概念,STM32的ADC多达19个通道,其中外部的16个通道就是框图中的ADCx_IN0、ADCx_IN1...ADCx_IN5。这16个通道对应着不同的IO口,具体是哪一个IO口可以从手册查询到。其中ADC1/2/3还有内部通道: ADC1的通道ADC1_IN16连接到内部的VSS,通道ADC1_IN17连接到了内部参考电压VREFINT 连接,通道ADC1_IN18连接到了芯片内部的温度传感器或者备用电源VBAT。ADC2和ADC3的通道16、17、18全部连接到了内部的VSS。

图 02 STM32F429IGT6 ADC 通道

外部的16个通道在转换的时候又分为规则通道和注入通道,其中规则通道最多有16路,注入通道最多有4路。那这两个通道有什么区别?在什么时候使用?

规则通道

规则通道:顾名思意,规则通道就是很规矩的意思,我们平时一般使用的就是这个通道,或者应该说我们用到的都是这个通道,没有什么特别要注意的可讲。

注入通道

注入,可以理解为插入,插队的意思,是一种不安分的通道。它是一种在规则通道转换的时候强行插入要转换的一种。如果在规则通道转换过程中,有注入通道插队,那么就要先转换完注入通道,等注入通道转换完成后,再回到规则通道的转换流程。这点跟中断程序很像,都是不安分的主。所以,注入通道只有在规则通道存在时才会出现。

3.    ③转换顺序
规则序列

规则序列寄存器有3个,分别为SQR3、SQR2、SQR1。SQR3控制着规则序列中的第一个到第六个转换,对应的位为:SQ1[4:0]~SQ6[4:0],第一次转换的是位4:0 SQ1[4:0],如果通道16想第一次转换,那么在SQ1[4:0]写16即可。SQR2控制着规则序列中的第7到第12个转换,对应的位为:SQ7[4:0]~SQ12[4:0],如果通道1想第8个转换,则SQ8[4:0]写1即可。SQR1控制着规则序列中的第13到第16个转换,对应位为:SQ13[4:0]~SQ16[4:0],如果通道6想第10个转换,则SQ10[4:0]写6即可。具体使用多少个通道,由SQR1的位L[3:0]决定,最多16个通道。

图 03 规则序列寄存器

注入序列

注入序列寄存器JSQR只有一个,最多支持4个通道,具体多少个由JSQR的JL[2:0]决定。如果JL的值小于4的话,则JSQR跟SQR决定转换顺序的设置不一样,第一次转换的不是JSQR1[4:0],而是JCQRx[4:0] ,x = (4-JL),跟SQR刚好相反。如果JL=00(1个转换),那么转换的顺序是从JSQR4[4:0]开始,而不是从JSQR1[4:0]开始,这个要注意,编程的时候不要搞错。当JL等于4时,跟SQR一样。

图 04 注入序列寄存器

4.    ④触发源

通道选好了,转换的顺序也设置好了,那接下来就该开始转换了。ADC转换可以由ADC控制寄存器2: ADC_CR2的ADON这个位来控制,写1的时候开始转换,写0的时候停止转换,这个是最简单也是最好理解的开启ADC转换的控制方式,理解起来没啥技术含量。

除了这种庶民式的控制方法,ADC还支持外部事件触发转换,这个触发包括内部定时器触发和外部IO触发。触发源有很多,具体选择哪一种触发源,由ADC控制寄存器2:ADC_CR2的EXTSEL[2:0]和JEXTSEL[2:0]位来控制。EXTSEL[2:0]用于选择规则通道的触发源,JEXTSEL[2:0]用于选择注入通道的触发源。选定好触发源之后,触发源是否要激活,则由ADC控制寄存器2:ADC_CR2的EXTTRIG和JEXTTRIG这两位来激活。

如果使能了外部触发事件,我们还可以通过设置ADC控制寄存器2:ADC_CR2的EXTEN[1:0]和JEXTEN[1:0]来控制触发极性,可以有4种状态,分别是:禁止触发检测、上升沿检测、下降沿检测以及上升沿和下降沿均检测。

5.    ⑤转换时间
ADC时钟

ADC输入时钟ADC_CLK由PCLK2经过分频产生,最大值是36MHz,典型值为30MHz,分频因子由ADC通用控制寄存器ADC_CCR的ADCPRE[1:0]设置,可设置的分频系数有2、4、6和8,注意这里没有1分频。对于STM32F429IGT6我们一般设置PCLK2=HCLK/2=90MHz。所以程序一般使用4分频或者6分频。

采样时间

ADC需要若干个ADC_CLK周期完成对输入的电压进行采样,采样的周期数可通过ADC 采样时间寄存器ADC_SMPR1和ADC_SMPR2中的SMP[2:0]位设置,ADC_SMPR2控制的是通道0~9,ADC_SMPR1控制的是通道10~17。每个通道可以分别用不同的时间采样。其中采样周期最小是3个,即如果我们要达到最快的采样,那么应该设置采样周期为3个周期,这里说的周期就是1/ADC_CLK。

ADC的总转换时间跟ADC的输入时钟和采样时间有关,公式为:

Tconv = 采样时间 + 12个周期

当ADCCLK = 30MHz,即PCLK2为60MHz,ADC时钟为2分频,采样时间设置为3个周期,那么总的转换时为:Tconv = 3 + 12 = 15个周期 =0.5us。

一般我们设置PCLK2=90MHz,经过ADC预分频器能分频到最大的时钟只能是22.5M,采样周期设置为3个周期,算出最短的转换时间为0.6667us,这个才是最常用的。

6.    ⑥数据寄存器

一切准备就绪后,ADC转换后的数据根据转换组的不同,规则组的数据放在ADC_DR寄存器,注入组的数据放在JDRx。如果是使用双重或者三重模式那规矩组的数据是存放在通用规矩寄存器ADC_CDR内的。

规则数据寄存器ADC_DR

ADC规则组数据寄存器ADC_DR只有一个,是一个32位的寄存器,只有低16位有效并且只是用于独立模式存放转换完成数据。因为ADC的最大精度是12位,ADC_DR是16位有效,这样允许ADC存放数据时候选择左对齐或者右对齐,具体是以哪一种方式存放,由ADC_CR2的11位ALIGN设置。假如设置ADC精度为12位,如果设置数据为左对齐,那AD转换完成数据存放在ADC_DR寄存器的[4:15]位内;如果为右对齐,则存放在ADC_DR寄存器的[0:11]位内。

规则通道可以有16个这么多,可规则数据寄存器只有一个,如果使用多通道转换,那转换的数据就全部都挤在了DR里面,前一个时间点转换的通道数据,就会被下一个时间点的另外一个通道转换的数据覆盖掉,所以当通道转换完成后就应该把数据取走,或者开启DMA模式,把数据传输到内存里面,不然就会造成数据的覆盖。最常用的做法就是开启DMA传输。

如果没有使用DMA传输,我们一般都需要使用ADC状态寄存器ADC_SR获取当前ADC转换的进度状态,进而进行程序控制。

注入数据寄存器ADC_JDRx

ADC注入组最多有4个通道,刚好注入数据寄存器也有4个,每个通道对应着自己的寄存器,不会跟规则寄存器那样产生数据覆盖的问题。ADC_JDRx是32位的,低16位有效,高16位保留,数据同样分为左对齐和右对齐,具体是以哪一种方式存放,由ADC_CR2的11位ALIGN设置。

通用规则数据寄存器ADC_CDR

规则数据寄存器ADC_DR是仅适用于独立模式的,而通用规则数据寄存器ADC_CDR是适用于双重和三重模式的。独立模式就是仅仅适用三个ADC的其中一个,双重模式就是同时使用ADC1和ADC2,而三重模式就是三个ADC同时使用。在双重或者三重模式下一般需要配合DMA数据传输使用。

7.    ⑦中断
转换结束中断

数据转换结束后,可以产生中断,中断分为四种:规则通道转换结束中断,注入转换通道转换结束中断,模拟看门狗中断和溢出中断。其中转换结束中断很好理解,跟我们平时接触的中断一样,有相应的中断标志位和中断使能位,我们还可以根据中断类型写相应配套的中断服务程序。

模拟看门狗中断

当被ADC转换的模拟电压低于低阈值或者高于高阈值时,就会产生中断,前提是我们开启了模拟看门狗中断,其中低阈值和高阈值由ADC_LTR和ADC_HTR设置。例如我们设置高阈值是2.5V,那么模拟电压超过2.5V的时候,就会产生模拟看门狗中断,反之低阈值也一样。

溢出中断

如果发生DMA传输数据丢失,会置位ADC状态寄存器ADC_SR的OVR位,如果同时使能了溢出中断,那在转换结束后会产生一个溢出中断。

DMA请求

规则和注入通道转换结束后,除了产生中断外,还可以产生DMA请求,把转换好的数据直接存储在内存里面。对于独立模式的多通道AD转换使用DMA传输非常有必须要,程序编程简化了很多。对于双重或三重模式使用DMA传输几乎可以说是必要的。有关DMA请求需要配合《STM32F4xx中文参考手册》DMA控制器这一章节来学习。一般我们在使用ADC的时候都会开启DMA传输。

8.    ⑧电压转换

模拟电压经过ADC转换后,是一个相对精度的数字值,如果通过串口以16进制打印出来的话,可读性比较差,那么有时候我们就需要把数字电压转换成模拟电压,也可以跟实际的模拟电压(用万用表测)对比,看看转换是否准确。

我们一般在设计原理图的时候会把ADC的输入电压范围设定在:0~3.3v,如果设置ADC为12位的,那么12位满量程对应的就是3.3V,12位满量程对应的数字值是:2^12。数值0对应的就是0V。如果转换后的数值为  X ,X对应的模拟电压为Y,那么会有这么一个等式成立:  2^12 / 3.3 = X / Y,=> Y = (3.3 * X ) / 2^12。

30.3 ADC初始化结构体详解

标准库函数对每个外设都建立了一个初始化结构体xxx_InitTypeDef(xxx为外设名称),结构体成员用于设置外设工作参数,并由标准库函数xxx_Init()调用这些设定参数进入设置外设相应的寄存器,达到配置外设工作环境的目的。

结构体xxx_InitTypeDef和库函数xxx_Init配合使用是标准库精髓所在,理解了结构体xxx_InitTypeDef每个成员意义基本上就可以对该外设运用自如了。结构体xxx_InitTypeDef定义在stm32f4xx_xxx.h文件中,库函数xxx_Init定义在stm32f4xx_xxx.c文件中,编程时我们可以结合这两个文件内注释使用。

ADC_InitTypeDef结构体

ADC_InitTypeDef结构体定义在stm32f4xx_adc.h文件内,具体定义如下:

1 typedef struct {

2 uint32_t ADC_Resolution; //ADC分辨率选择

3 FunctionalState ADC_ScanConvMode; //ADC扫描选择

4 FunctionalState ADC_ContinuousConvMode; //ADC连续转换模式选择

5 uint32_t ADC_ExternalTrigConvEdge; //ADC外部触发极性

6 uint32_t ADC_ExternalTrigConv; //ADC外部触发选择

7 uint32_t ADC_DataAlign; //输出数据对齐方式

8 uint8_t ADC_NbrOfChannel; //转换通道数目

9 } ADC_InitTypeDef;

ADC_Resolution:配置ADC的分辨率,可选的分辨率有12位、10位、8位和6位。分辨率越高,AD转换数据精度越高,转换时间也越长;分辨率越低,AD转换数据精度越低,转换时间也越短。

ScanConvMode:可选参数为ENABLE和DISABLE,配置是否使用扫描。如果是单通道AD转换使用DISABLE,如果是多通道AD转换使用ENABLE。

ADC_ContinuousConvMode:可选参数为ENABLE和DISABLE,配置是启动自动连续转换还是单次转换。使用ENABLE配置为使能自动连续转换;使用DISABLE配置为单次转换,转换一次后停止需要手动控制才重新启动转换。

ADC_ExternalTrigConvEdge:外部触发极性选择,如果使用外部触发,可以选择触发的极性,可选有禁止触发检测、上升沿触发检测、下降沿触发检测以及上升沿和下降沿均可触发检测。

ADC_ExternalTrigConv:外部触发选择,图 01中列举了很多外部触发条件,可根据项目需求配置触发来源。实际上,我们一般使用软件自动触发。

ADC_DataAlign:转换结果数据对齐模式,可选右对齐ADC_DataAlign_Right或者左对齐ADC_DataAlign_Left。一般我们选择右对齐模式。

ADC_NbrOfChannel:AD转换通道数目。

ADC_CommonInitTypeDef结构体

ADC除了有ADC_InitTypeDef初始化结构体外,还有一个ADC_CommonInitTypeDef通用初始化结构体。ADC_CommonInitTypeDef结构体内容决定三个ADC共用的工作环境,比如模式选择、ADC时钟等等。

ADC_CommonInitTypeDef结构体也是定义在stm32_f4xx.h文件中,具体定义如下:

1 typedef struct {

2 uint32_t ADC_Mode; //ADC模式选择

3 uint32_t ADC_Prescaler; //ADC分频系数

4 uint32_t ADC_DMAAccessMode; //DMA模式配置

5 uint32_t ADC_TwoSamplingDelay; //采样延迟

6 } ADC_InitTypeDef;

ADC_Mode:ADC工作模式选择,有独立模式、双重模式以及三重模式。

ADC_Prescaler:ADC时钟分频系数选择,ADC时钟是有PCLK2分频而来,分频系数决定ADC时钟频率,可选的分频系数为2、4、6和8。ADC最大时钟配置为36MHz。

ADC_DMAAccessMode:DMA模式设置,只有在双重或者三重模式才需要设置,可以设置三种模式,具体可参考参考手册说明。

ADC_TwoSamplingDelay:2个采样阶段之前的延迟,仅适用于双重或三重交错模式。

30.4 独立模式单通道采集实验

STM32的ADC功能繁多,我们设计三个实验尽量完整的展示ADC的功能。首先是比较基础实用的单通道采集,实现开发板上电位器的动触点输出引脚电压的采集并通过串口打印至PC端串口调试助手。单通道采集适用AD转换完成中断,在中断服务函数中读取数据,不使用DMA传输,在多通道采集时才使用DMA传输。

30.4.1 硬件设计

开发板板载一个贴片滑动变阻器,电路设计见图 05。

图 05 开发板电位器部分原理图

贴片滑动变阻器的动触点通过连接至STM32芯片的ADC通道引脚。当我们使用旋转滑动变阻器调节旋钮时,其动触点电压也会随之改变,电压变化范围为0~3.3V,亦是开发板默认的ADC电压采集范围。

30.4.2 软件设计

这里只讲解核心的部分代码,有些变量的设置,头文件的包含等并没有涉及到,完整的代码请参考本章配套的工程。

我们编写两个ADC驱动文件,bsp_adc.h 和 bsp_adc.c,用来存放ADC所用IO引脚的初始化函数以及ADC配置相关函数。

1.    编程要点

1)    初始化配置ADC目标引脚为模拟输入模式;

2)    使能ADC时钟;

3)    配置通用ADC为独立模式,采样4分频;

4)    设置目标ADC为12位分辨率,1通道的连续转换,不需要外部触发;

5)    设置ADC转换通道顺序及采样时间;

6)    配置使能ADC转换完成中断,在中断内读取转换完数据;

7)    启动ADC转换;

8)    使能软件触发ADC转换。

ADC转换结果数据使用中断方式读取,这里没有使用DMA进行数据传输。

2.    代码分析
ADC宏定义

代码清单 01 ADC宏定义

1 #define Rheostat_ADC_IRQ ADC_IRQn

2 #define Rheostat_ADC_INT_FUNCTION ADC_IRQHandler

3

4 #define RHEOSTAT_ADC_GPIO_PORT GPIOC

5 #define RHEOSTAT_ADC_GPIO_PIN GPIO_Pin_3

6 #define RHEOSTAT_ADC_GPIO_CLK RCC_AHB1Periph_GPIOC

7

8 #define RHEOSTAT_ADC ADC1

9 #define RHEOSTAT_ADC_CLK RCC_APB2Periph_ADC1

10 #define RHEOSTAT_ADC_CHANNEL ADC_Channel_13

使用宏定义引脚信息方便硬件电路改动时程序移植。

ADC GPIO初始化函数

代码清单 02 ADC GPIO初始化

1 static void Rheostat_ADC_GPIO_Config(void)

2 {

3 GPIO_InitTypeDef GPIO_InitStructure;

4

5 // 使能 GPIO 时钟

6 RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK, ENABLE);

7

8 // 配置 IO

9 GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN;

10 // 配置为模拟输入

11 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

12 // 不上拉不下拉

13 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;

14 GPIO_Init(RHEOSTAT_ADC_GPIO_PORT, &GPIO_InitStructure);

15 }

使用到GPIO时候都必须开启对应的GPIO时钟,GPIO用于AD转换功能必须配置为模拟输入模式。

配置ADC工作模式

代码清单 03 ADC工作模式配置

1 static void Rheostat_ADC_Mode_Config(void)

2 {

3 ADC_InitTypeDef ADC_InitStructure;

4 ADC_CommonInitTypeDef ADC_CommonInitStructure;

5

6 // 开启ADC时钟

7 RCC_APB2PeriphClockCmd(RHEOSTAT_ADC_CLK , ENABLE);

8

9 // -------------------ADC Common 结构体参数初始化--------------------

10 // 独立ADC模式

11 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;

12 // 时钟为fpclk x分频

13 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;

14 // 禁止DMA直接访问模式

15 ADC_CommonInitStructure.ADC_DMAAccessMode=ADC_DMAAccessMode_Disabled;

16 // 采样时间间隔

17 ADC_CommonInitStructure.ADC_TwoSamplingDelay=

18 ADC_TwoSamplingDelay_10Cycles;

19 ADC_CommonInit(&ADC_CommonInitStructure);

20

21 // -------------------ADC Init 结构体参数初始化---------------------

22 // ADC 分辨率

23 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

24 // 禁止扫描模式,多通道采集才需要

25 ADC_InitStructure.ADC_ScanConvMode = DISABLE;

26 // 连续转换

27 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

28 //禁止外部边沿触发

29 ADC_InitStructure.ADC_ExternalTrigConvEdge =

30 ADC_ExternalTrigConvEdge_None;

31 //使用软件触发,外部触发不用配置,注释掉即可

32 //ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_T1_CC1;

33 //数据右对齐

34 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

35 //转换通道 1个

36 ADC_InitStructure.ADC_NbrOfConversion = 1;

37 ADC_Init(RHEOSTAT_ADC, &ADC_InitStructure);

38 //------------------------------------------------------------------

39 // 配置 ADC 通道转换顺序为1,第一个转换,采样时间为56个时钟周期

40 ADC_RegularChannelConfig(RHEOSTAT_ADC, RHEOSTAT_ADC_CHANNEL,

41 1, ADC_SampleTime_56Cycles);

42

43 // ADC 转换结束产生中断,在中断服务程序中读取转换值

44 ADC_ITConfig(RHEOSTAT_ADC, ADC_IT_EOC, ENABLE);

45 // 使能ADC

46 ADC_Cmd(RHEOSTAT_ADC, ENABLE);

47 //开始adc转换,软件触发

48 ADC_SoftwareStartConv(RHEOSTAT_ADC);

49 }

首先,使用ADC_InitTypeDef和ADC_CommonInitTypeDef结构体分别定义一个ADC初始化和ADC通用类型变量,这两个结构体我们之前已经有详细讲解。

我们调用RCC_APB2PeriphClockCmd()开启ADC时钟。

接下来我们使用ADC_CommonInitTypeDef结构体变量ADC_CommonInitStructure来配置ADC为独立模式、分频系数为4、不需要设置DMA模式、20个周期的采样延迟,并调用ADC_CommonInit函数完成ADC通用工作环境配置。

我们使用ADC_InitTypeDef结构体变量ADC_InitStructure来配置ADC1为12位分辨率、单通道采集不需要扫描、启动连续转换、使用内部软件触发无需外部触发事件、使用右对齐数据格式、转换通道为1,并调用ADC_Init函数完成ADC1工作环境配置。

ADC_RegularChannelConfig函数用来绑定ADC通道转换顺序和时间。它接收4个形参,第一个形参选择ADC外设,可为ADC1、ADC2或ADC3;第二个形参通道选择,总共可选18个通道;第三个形参为转换顺序,可选为1到16;第四个形参为采样周期选择,采样周期越短,ADC转换数据输出周期就越短但数据精度也越低,采样周期越长,ADC转换数据输出周期就越长同时数据精度越高。PC3对应ADC通道ADC_Channel_13,这里我们选择ADC_SampleTime_56Cycles即56周期的采样时间。

利用ADC转换完成中断可以非常方便的保证我们读取到的数据是转换完成后的数据而不用担心该数据可能是ADC正在转换时"不稳定"的数据。我们使用ADC_ITConfig函数使能ADC转换完成中断,并在中断服务函数中读取转换结果数据。

ADC_Cmd函数控制ADC转换启动和停止。

最后,如果使用软件触发需要调用ADC_SoftwareStartConvCmd函数进行使能配置。

ADC中断配置

代码清单 04 ADC中断配置

1 static void Rheostat_ADC_NVIC_Config(void)

2 {

3 NVIC_InitTypeDef NVIC_InitStructure;

4

5 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

6

7 NVIC_InitStructure.NVIC_IRQChannel = Rheostat_ADC_IRQ;

8 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

9 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

10 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

11

12 NVIC_Init(&NVIC_InitStructure);

13 }

在Rheostat_ADC_NVIC_Config函数中我们配置了ADC转换完成中断,使用中断同时需要配置中断源和中断优先级。

ADC中断服务函数

代码清单 05 ADC中断服务函数

1 void ADC_IRQHandler(void)

2 {

3 if (ADC_GetITStatus(RHEOSTAT_ADC,ADC_IT_EOC)==SET) {

4 // 读取ADC的转换值

5 ADC_ConvertedValue = ADC_GetConversionValue(RHEOSTAT_ADC);

6

7 }

8 ADC_ClearITPendingBit(RHEOSTAT_ADC,ADC_IT_EOC);

9

10 }

中断服务函数一般定义在stm32f4xx_it.c文件内,我们只使能了ADC转换完成中断,在ADC转换完成后就会进入中断服务函数,我们在中断服务函数内直接读取ADC转换结果保存在变量ADC_ConvertedValue(在main.c中定义)中。

ADC_GetConversionValue函数是获取ADC转换结果值的库函数,只有一个形参为ADC外设,可选为ADC1、ADC2或ADC3,该函数还返回一个16位的ADC转换结果值。

主函数

代码清单 06 主函数

1 int main(void)

2 {

3 /*初始化USART1*/

4 Debug_USART_Config();

5

6 /* 初始化滑动变阻器用到的DAC,ADC采集完成会产生ADC中断,

7 在stm32f4xx_it.c文件中的中断服务函数更新ADC_ConvertedValue的值 */

8 Rheostat_Init();

9

10 printf("\r\n ----这是一个ADC实验(NO DMA传输)----\r\n");

11

12

13 while (1) {

14 Delay(0xffffee);

15 printf("\r\n The current AD value = 0x%04X \r\n",

16 ADC_ConvertedValue);

17 printf("\r\n The current AD value = %f V \r\n",ADC_Vol);

18

19 ADC_Vol =(float)(ADC_ConvertedValue*3.3/4096); // 读取转换的AD值

20

21 }

22 }

主函数先调用USARTx_Config函数配置调试串口相关参数,函数定义在bsp_debug_usart.c文件中。

接下来调用Rheostat _Init函数进行ADC初始化配置并启动ADC。Rheostat _Init函数是定义在bsp_adc.c文件中,它只是简单的分别调用Rheostat_ADC_GPIO_Config ()、Rheostat_ADC_Mode_Config ()和Rheostat_ADC_NVIC_Config()。

Delay函数只是一个简单的延时函数。

在ADC中断服务函数中我们把AD转换结果保存在变量ADC_ConvertedValue中,根据我们之前的分析可以非常清楚的计算出对应的电位器动触点的电压值。

最后就是把相关数据打印至串口调试助手。

30.4.3 下载验证

用USB线连接开发板"USB TO UART"接口跟电脑,在电脑端打开串口调试助手,把编译好的程序下载到开发板。在串口调试助手可看到不断有数据从开发板传输过来,此时我们旋转电位器改变其电阻值,那么对应的数据也会有变化。

30.5 独立模式多通道采集实验

30.5.1 硬件设计

开发板已通过排针接口把部分ADC通道引脚引出,我们可以根据需要选择使用。实际使用时候必须注意保存ADC引脚是单独使用的,不可能与其他模块电路共用同一引脚。

30.5.2 软件设计

这里只讲解核心的部分代码,有些变量的设置,头文件的包含等并没有涉及到,完整的代码请参考本章配套的工程。

跟单通道例程一样,我们编写两个ADC驱动文件,bsp_adc.h 和 bsp_adc.c,用来存放ADC所用IO引脚的初始化函数以及ADC配置相关函数,实际上这两个文件跟单通道实验的文件是非常相似的。

1.    编程要点

1)    初始化配置ADC目标引脚为模拟输入模式;

2)    使能ADC时钟和DMA时钟;

3)    配置DMA从ADC规矩数据寄存器传输数据到我们指定的存储区;

4)    配置通用ADC为独立模式,采样4分频;

5)    设置ADC为12位分辨率,启动扫描,连续转换,不需要外部触发;

6)    设置ADC转换通道顺序及采样时间;

7)    使能DMA请求,DMA在AD转换完自动传输数据到指定的存储区;

8)    启动ADC转换;

9)    使能软件触发ADC转换。

ADC转换结果数据使用DMA方式传输至指定的存储区,这样取代单通道实验使用中断服务的读取方法。实际上,多通道ADC采集一般使用DMA数据传输方式更加高效方便。

2.    代码分析
ADC宏定义

代码清单 07 多通道ADC相关宏定义

1 //转换的通道个数

2 #define RHEOSTAT_NOFCHANEL 4

3

4 #define RHEOSTAT_ADC_DR_ADDR ((u32)ADC3+0x4c)

5 #define RHEOSTAT_ADC_GPIO_PORT GPIOF

6 #define RHEOSTAT_ADC_GPIO_CLK RCC_AHB1Periph_GPIOF

7 #define RHEOSTAT_ADC ADC3

8 #define RHEOSTAT_ADC_CLK RCC_APB2Periph_ADC3

9

10 #define RHEOSTAT_ADC_GPIO_PIN1 GPIO_Pin_6

11 #define RHEOSTAT_ADC_CHANNEL1 ADC_Channel_4

12

13 #define RHEOSTAT_ADC_GPIO_PIN2 GPIO_Pin_7

14 #define RHEOSTAT_ADC_CHANNEL2 ADC_Channel_5

15

16 #define RHEOSTAT_ADC_GPIO_PIN3 GPIO_Pin_8

17 #define RHEOSTAT_ADC_CHANNEL3 ADC_Channel_6

18

19 #define RHEOSTAT_ADC_GPIO_PIN4 GPIO_Pin_9

20 #define RHEOSTAT_ADC_CHANNEL4 ADC_Channel_7

21

22 // DMA2 数据流0 通道2

23 #define RHEOSTAT_ADC_DMA_CLK RCC_AHB1Periph_DMA2

24 #define RHEOSTAT_ADC_DMA_CHANNEL DMA_Channel_2

25 #define RHEOSTAT_ADC_DMA_STREAM DMA2_Stream0

定义4个通道进行多通道ADC实验,并且定义DMA相关配置。

ADC GPIO初始化函数

代码清单 08 ADC GPIO初始化

1 static void Rheostat_ADC_GPIO_Config(void)

2 {

3 GPIO_InitTypeDef GPIO_InitStructure;

4

5 // 使能 GPIO 时钟

6 RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK, ENABLE);

7

8 // 配置 IO

9 GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN1 |

10 RHEOSTAT_ADC_GPIO_PIN2 |

11 RHEOSTAT_ADC_GPIO_PIN3 |

12 RHEOSTAT_ADC_GPIO_PIN4;

13 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

14 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //不上拉不下拉

15 GPIO_Init(RHEOSTAT_ADC_GPIO_PORT, &GPIO_InitStructure);

16 }

使用到GPIO时候都必须开启对应的GPIO时钟,GPIO用于AD转换功能必须配置为模拟输入模式。

配置ADC工作模式

代码清单 09 ADC工作模式配置

1 static void Rheostat_ADC_Mode_Config(void)

2 {

3 DMA_InitTypeDef DMA_InitStructure;

4 ADC_InitTypeDef ADC_InitStructure;

5 ADC_CommonInitTypeDef ADC_CommonInitStructure;

6

7 // 开启ADC时钟

8 RCC_APB2PeriphClockCmd(RHEOSTAT_ADC_CLK , ENABLE);

9 // 开启DMA时钟

10 RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_DMA_CLK, ENABLE);

11

12 // ------------------DMA Init 结构体参数初始化------------------------

13 // 选择 DMA 通道,通道存在于数据流中

14 DMA_InitStructure.DMA_Channel = RHEOSTAT_ADC_DMA_CHANNEL;

15

16 // 外设基址为:ADC 数据寄存器地址

17 DMA_InitStructure.DMA_PeripheralBaseAddr = RHEOSTAT_ADC_DR_ADDR;

18 // 存储器地址

19 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ADC_ConvertedValue;

20

21 // 数据传输方向为外设到存储器

22 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

23 // 缓冲区大小,指一次传输的数据项

24 DMA_InitStructure.DMA_BufferSize = RHEOSTAT_NOFCHANEL;

25

26 // 外设寄存器只有一个,地址不用递增

27 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

28 // 存储器地址递增

29 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

30 //DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;

31

32 // // 外设数据大小为半字,即两个字节

33 DMA_InitStructure.DMA_PeripheralDataSize =

34 DMA_PeripheralDataSize_HalfWord;

35 // 存储器数据大小也为半字,跟外设数据大小相同

36 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

37

38 // 循环传输模式

39 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

40 // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响

41 DMA_InitStructure.DMA_Priority = DMA_Priority_High;

42

43 // 禁止DMA FIFO ,使用直连模式

44 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;

45 // FIFO 阈值大小,FIFO模式禁止时,这个不用配置

46 DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;

47

48 // 存储器突发单次传输

49 DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

50 // 外设突发单次传输

51 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

52

53 //初始化DMA数据流,流相当于一个大的管道,管道里面有很多通道

54 DMA_Init(RHEOSTAT_ADC_DMA_STREAM, &DMA_InitStructure);

55

56 // 使能DMA数据流

57 DMA_Cmd(RHEOSTAT_ADC_DMA_STREAM, ENABLE);

58

59 // -------------------ADC Common 结构体参数初始化--------------------

60 // 独立ADC模式

61 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;

62 // 时钟为fpclk x分频

63 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;

64 // 禁止DMA直接访问模式

65 ADC_CommonInitStructure.ADC_DMAAccessMode=ADC_DMAAccessMode_Disabled;

66 // 采样时间间隔

67 ADC_CommonInitStructure.ADC_TwoSamplingDelay =

68 ADC_TwoSamplingDelay_10Cycles;

69 ADC_CommonInit(&ADC_CommonInitStructure);

70

71 // -------------------ADC Init 结构体参数初始化---------------------

72 // ADC 分辨率

73 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

74 // 开启扫描模式

75 ADC_InitStructure.ADC_ScanConvMode = ENABLE;

76 // 连续转换

77 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

78 //禁止外部边沿触发

79 ADC_InitStructure.ADC_ExternalTrigConvEdge =

80 ADC_ExternalTrigConvEdge_None;

81 //使用软件触发,外部触发不用配置,注释掉即可

82 //ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_T1_CC1;

83 //数据右对齐

84 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

85 //转换通道 x个

86 ADC_InitStructure.ADC_NbrOfConversion = RHEOSTAT_NOFCHANEL;

87 ADC_Init(RHEOSTAT_ADC, &ADC_InitStructure);

88 //------------------------------------------------------------------

89

90 // 配置 ADC 通道转换顺序和采样时间周期

91 ADC_RegularChannelConfig(RHEOSTAT_ADC, RHEOSTAT_ADC_CHANNEL1,

92 1, ADC_SampleTime_56Cycles);

93 ADC_RegularChannelConfig(RHEOSTAT_ADC, RHEOSTAT_ADC_CHANNEL2,

94 2, ADC_SampleTime_56Cycles);

95 ADC_RegularChannelConfig(RHEOSTAT_ADC, RHEOSTAT_ADC_CHANNEL3,

96 3, ADC_SampleTime_56Cycles);

97 ADC_RegularChannelConfig(RHEOSTAT_ADC, RHEOSTAT_ADC_CHANNEL4,

98 4, ADC_SampleTime_56Cycles);

99 // 使能DMA请求 after last transfer (Single-ADC mode)

100 ADC_DMARequestAfterLastTransferCmd(RHEOSTAT_ADC, ENABLE);

101 // 使能ADC DMA

102 ADC_DMACmd(RHEOSTAT_ADC, ENABLE);

103 // 使能ADC

104 ADC_Cmd(RHEOSTAT_ADC, ENABLE);

105 //开始adc转换,软件触发

106 ADC_SoftwareStartConv(RHEOSTAT_ADC);

107 }

首先,我们使用了DMA_InitTypeDef定义了一个DMA初始化类型变量,该结构体内容我们在DMA篇已经做了非常详细的讲解;另外还使用ADC_InitTypeDef和ADC_CommonInitTypeDef结构体分别定义一个ADC初始化和ADC通用类型变量,这两个结构体我们之前已经有详细讲解。

调用RCC_APB2PeriphClockCmd()开启ADC时钟以及RCC_AHB1PeriphClockCmd()开启DMA时钟。

我们需要对DMA进行必要的配置。首先设置外设基地址就是ADC的规则数据寄存器地址;存储器的地址就是我们指定的数据存储区空间,ADC_ConvertedValue是我们定义的一个全局数组名,它是一个无符号16位含有4个元素的整数数组;ADC规则转换对应只有一个数据寄存器所以地址不能递增,而我们定义的存储区是专门用来存放不同通道数据的,所以需要自动地址递增。ADC的规则数据寄存器只有低16位有效,实际存放的数据只有12位而已,所以设置数据大小为半字大小。ADC配置为连续转换模式DMA也设置为循环传输模式。设置好DMA相关参数后就使能DMA的ADC通道。

接下来我们使用ADC_CommonInitTypeDef结构体变量ADC_CommonInitStructure来配置ADC为独立模式、分频系数为4、不需要设置DMA模式、20个周期的采样延迟,并调用ADC_CommonInit函数完成ADC通用工作环境配置。

我们使用ADC_InitTypeDef结构体变量ADC_InitStructure来配置ADC1为12位分辨率、使能扫描模式、启动连续转换、使用内部软件触发无需外部触发事件、使用右对齐数据格式、转换通道为4,并调用ADC_Init函数完成ADC3工作环境配置。

ADC_RegularChannelConfig函数用来绑定ADC通道转换顺序和采样时间。分别绑定四个ADC通道引脚并设置相应的转换顺序。

ADC_DMARequestAfterLastTransferCmd函数控制是否使能ADC的DMA请求,如果使能请求,并调用ADC_DMACmd函数使能DMA,则在ADC转换完成后就请求DMA实现数据传输。

ADC_Cmd函数控制ADC转换启动和停止。

最后,如果使用软件触发需要调用ADC_SoftwareStartConvCmd函数进行使能配置。

主函数

代码清单 010 主函数

1 int main(void)

2 {

3 /*初始化USART1*/

4 Debug_USART_Config();

5

6 /* 初始化滑动变阻器用到的DAC

7 ,ADC数据采集完成后直接由DMA运输数据到ADC_ConvertedValue变量

8 DMA直接改变ADC_ConvertedValue的值*/

9 Rheostat_Init();

10

11 printf("\r\n ----这是一个ADC实验(多通道采集)----\r\n");

12

13 while (1) {

14 Delay(0xffffff);

15 ADC_ConvertedValueLocal[0]=(float)(ADC_ConvertedValue[0]*3.3/4096);

16 ADC_ConvertedValueLocal[1]=(float)(ADC_ConvertedValue[1]*3.3/4096);

17 ADC_ConvertedValueLocal[2]=(float)(ADC_ConvertedValue[2]*3.3/4096);

18 ADC_ConvertedValueLocal[3]=(float)(ADC_ConvertedValue[3]*3.3/4096);

19

20 printf("\r\n CH1_PF6 value = %fV\r\n",ADC_ConvertedValueLocal[0]);

21 printf("\r\n CH2_PF7 value = %fV\r\n",ADC_ConvertedValueLocal[1]);

22 printf("\r\n CH3_PF8 value = %fV\r\n",ADC_ConvertedValueLocal[2]);

23 printf("\r\n CH4_PF9 value = %fV\r\n",ADC_ConvertedValueLocal[3]);

24

25 printf("\r\n");

26 }

27 }

主函数先调用USARTx_Config函数配置调试串口相关参数,函数定义在bsp_debug_usart.c文件中。

接下来调用Rheostat_Init函数进行ADC初始化配置并启动ADC。Rheostat_Init函数是定义在bsp_adc.c文件中,它只是简单的分别调用Rheostat_ADC_GPIO_Config()和Rheostat_ADC_Mode_Config ()。

Delay函数只是一个简单的延时函数。

我们配置了DMA数据传输所以它会自动把ADC转换完成后数据保存到数组ADC_ConvertedValue内,我们只要直接使用数组就可以了。经过简单地计算就可以得到每个通道对应的实际电压。

最后就是把相关数据打印至串口调试助手。

30.5.3 下载验证

将待测电压通过杜邦线接在对应引脚上,用USB线连接开发板"USB TO UART"接口跟电脑,在电脑端打开串口调试助手,把编译好的程序下载到开发板。在串口调试助手可看到不断有数据从开发板传输过来,此时我们改变输入电压值,那么对应的数据也会有变化。

30.6 三重ADC交替模式采集实验

AD转换包括采样阶段和转换阶段,在采样阶段才对通道数据进行采集;而在转换阶段只是将采集到的数据进行转换为数字量输出,此刻通道数据变化不会改变转换结果。独立模式的ADC采集需要在一个通道采集并且转换完成后才会进行下一个通道的采集。双重或者三重ADC的机制使用两个或以上ADC同时采样两个或以上不同通道的数据或者使用两个或以上ADC交叉采集同一通道的数据。双重或者三重ADC模式较独立模式一个最大的优势就是转换速度快。

我们这里只介绍三重ADC交替模式,关于双重或者三重ADC的其他模式与之类似,可以参考三重ADC交替模式使用。三重ADC交替模式是针对同一通道的使用三个ADC交叉采集,就是在ADC1采样完等几个时钟周期后ADC2开始采样,此时ADC1处在转换阶段,当ADC2采样完成再等几个时钟周期后ADC3就进行采样此时ADC1和ADC2处在转换阶段,如果ADC3采样完成并且ADC1已经转换完成那么就可以准备下一轮的循环,这样充分利用转换阶段时间达到增快采样速度的效果。AD转换过程见图 06,利用ADC的转换阶段时间另外一个ADC进行采样,而不用像独立模式必须等待采样和转换结束后才进行下一次采样及转换。

图 06 三重ADC交叉模式

30.6.1 硬件设计

三重ADC交叉模式是针对同一个通道的ADC采集模式,这种情况跟00小节的单通道实验非常类似,只是同时使用三个ADC对同一通道进行采集,所以电路设计与之相同即可,具体可参考图 05。

30.6.2 软件设计

这里只讲解核心的部分代码,有些变量的设置,头文件的包含等并没有涉及到,完整的代码请参考本章配套的工程。

跟单通道例程一样,我们编写两个ADC驱动文件,bsp_adc.h 和 bsp_adc.c,用来存放ADC所用IO引脚的初始化函数以及ADC配置相关函数,实际上这两个文件跟单通道实验的文件非常相似。

1.    编程要点

1)    初始化配置ADC目标引脚为模拟输入模式;

2)    使能ADC1、ADC2、ADC3以及DMA时钟;

3)    配置DMA控制将ADC通用规矩数据寄存器数据转存到指定存储区;

4)    配置通用ADC为三重ADC交替模式,采样4分频,使用DMA模式2;

5)    设置ADC1、ADC2和ADC3为12位分辨率,禁用扫描,连续转换,不需要外部触发;

6)    设置ADC1、ADC2和ADC3转换通道顺序及采样时间;

7)    使能ADC1的 DMA请求,在ADC转换完后自动请求DMA进行数据传输;

8)    启动ADC1、ADC2和ADC3转换;

9)    使能软件触发ADC转换。

ADC转换结果数据使用DMA方式传输至指定的存储区,这样取代单通道实验使用中断服务的读取方法。

2.    代码分析
ADC宏定义

代码清单 011 多通道ADC相关宏定义

1 #define RHEOSTAT_ADC_CDR_ADDR ((uint32_t)0x40012308)

2

3 #define RHEOSTAT_ADC_GPIO_PORT GPIOC

4 #define RHEOSTAT_ADC_GPIO_PIN GPIO_Pin_3

5 #define RHEOSTAT_ADC_GPIO_CLK RCC_AHB1Periph_GPIOC

6

7 #define RHEOSTAT_ADC1 ADC1

8 #define RHEOSTAT_ADC1_CLK RCC_APB2Periph_ADC1

9 #define RHEOSTAT_ADC2 ADC2

10 #define RHEOSTAT_ADC2_CLK RCC_APB2Periph_ADC2

11 #define RHEOSTAT_ADC3 ADC3

12 #define RHEOSTAT_ADC3_CLK RCC_APB2Periph_ADC3

13 #define RHEOSTAT_ADC_CHANNEL ADC_Channel_13

14

15 #define RHEOSTAT_ADC_DMA_CLK RCC_AHB1Periph_DMA2

16 #define RHEOSTAT_ADC_DMA_CHANNEL DMA_Channel_0

17 #define RHEOSTAT_ADC_DMA_STREAM DMA2_Stream0

双重或者三重ADC需要使用通用规则数据寄存器ADC_CDR,这点跟独立模式不同。定义电位器动触点引脚作为三重ADC的模拟输入。

ADC GPIO初始化函数

代码清单 012 ADC GPIO初始化

1 static void Rheostat_ADC_GPIO_Config(void)

2 {

3 GPIO_InitTypeDef GPIO_InitStructure;

4

5 // 使能 GPIO 时钟

6 RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK, ENABLE);

7

8 // 配置 IO

9 GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN;

10 // 配置为模拟输入

11 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

12 // 不上拉不下拉

13 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;

14 GPIO_Init(RHEOSTAT_ADC_GPIO_PORT, &GPIO_InitStructure);

15 }

使用到GPIO时候都必须开启对应的GPIO时钟,GPIO用于AD转换功能必须配置为模拟输入模式。

配置三重ADC交替模式

代码清单 013 三重ADC交替模式配置

1 static void Rheostat_ADC_Mode_Config(void)

2 {

3 DMA_InitTypeDef DMA_InitStructure;

4 ADC_InitTypeDef ADC_InitStructure;

5 ADC_CommonInitTypeDef ADC_CommonInitStructure;

6

7 // 开启ADC时钟

8 RCC_APB2PeriphClockCmd(RHEOSTAT_ADC1_CLK , ENABLE);

9 RCC_APB2PeriphClockCmd(RHEOSTAT_ADC2_CLK , ENABLE);

10 RCC_APB2PeriphClockCmd(RHEOSTAT_ADC3_CLK , ENABLE);

11

12 // ------------------DMA Init 结构体参数初始化-----------------------

13 // ADC1使用DMA2,数据流0,通道0,这个是手册固定死的

14 // 开启DMA时钟

15 RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_DMA_CLK, ENABLE);

16 // 外设基址为:ADC 数据寄存器地址

17 DMA_InitStructure.DMA_PeripheralBaseAddr = RHEOSTAT_ADC_CDR_ADDR;

18 // 存储器地址,实际上就是一个内部SRAM的变量

19 DMA_InitStructure.DMA_Memory0BaseAddr = (u32)ADC_ConvertedValue;

20 // 数据传输方向为外设到存储器

21 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

22 // 缓冲区大小为3,缓冲区的大小应该等于存储器的大小

23 DMA_InitStructure.DMA_BufferSize = 3;

24 // 外设寄存器只有一个,地址不用递增

25 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

26 // 存储器地址自动递增

27 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

28 // // 外设数据大小为字,即四个字节

29 DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Word;

30 // 存储器数据大小也为字,跟外设数据大小相同

31 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;

32 // 循环传输模式

33 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

34 // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响

35 DMA_InitStructure.DMA_Priority = DMA_Priority_High;

36 // 禁止DMA FIFO ,使用直连模式

37 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;

38 // FIFO 大小,FIFO模式禁止时,这个不用配置

39 DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;

40 DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

41 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

42 // 选择 DMA 通道,通道存在于流中

43 DMA_InitStructure.DMA_Channel = RHEOSTAT_ADC_DMA_CHANNEL;

44 //初始化DMA流,流相当于一个大的管道,管道里面有很多通道

45 DMA_Init(RHEOSTAT_ADC_DMA_STREAM, &DMA_InitStructure);

46 // 使能DMA流

47 DMA_Cmd(RHEOSTAT_ADC_DMA_STREAM, ENABLE);

48

49 // -------------------ADC Common 结构体参数初始化--------------------

50 // 三重ADC交替模式

51 ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_Interl;

52 // 时钟为fpclk2 4分频

53 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;

54 // 禁止DMA直接访问模式

55 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2;

56 // 采样时间间隔

57 ADC_CommonInitStructure.ADC_TwoSamplingDelay =

58 ADC_TwoSamplingDelay_10Cycles;

59 ADC_CommonInit(&ADC_CommonInitStructure);

60

61 // -------------------ADC Init 结构体参数初始化----------------------

62 // ADC 分辨率

63 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

64 // 禁止扫描模式,多通道采集才需要

65 ADC_InitStructure.ADC_ScanConvMode = DISABLE;

66 // 连续转换

67 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

68 //禁止外部边沿触发

69 ADC_InitStructure.ADC_ExternalTrigConvEdge =

70 ADC_ExternalTrigConvEdge_None;

71 //使用软件触发,外部触发不用配置,注释掉即可

72 //ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_T1_CC1;

73 //数据右对齐

74 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

75 //转换通道 1个

76 ADC_InitStructure.ADC_NbrOfConversion = 1;

77 ADC_Init(RHEOSTAT_ADC1, &ADC_InitStructure);

78 // 配置 ADC 通道转换顺序为1,第一个转换,采样时间为3个时钟周期

79 ADC_RegularChannelConfig(RHEOSTAT_ADC1, RHEOSTAT_ADC_CHANNEL,

80 1, ADC_SampleTime_3Cycles);

81 //------------------------------------------------------------------

82 ADC_Init(RHEOSTAT_ADC2, &ADC_InitStructure);

83 // 配置 ADC 通道转换顺序为1,第一个转换,采样时间为3个时钟周期

84 ADC_RegularChannelConfig(RHEOSTAT_ADC2, RHEOSTAT_ADC_CHANNEL,

85 1, ADC_SampleTime_3Cycles);

86 //------------------------------------------------------------------

87 ADC_Init(RHEOSTAT_ADC3, &ADC_InitStructure);

88 // 配置 ADC 通道转换顺序为1,第一个转换,采样时间为3个时钟周期

89 ADC_RegularChannelConfig(RHEOSTAT_ADC3, RHEOSTAT_ADC_CHANNEL,

90 1, ADC_SampleTime_3Cycles);

91

92 // 使能DMA请求 after last transfer (multi-ADC mode)

93 ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);

94 // 使能ADC DMA

95 ADC_DMACmd(RHEOSTAT_ADC1, ENABLE);

96 // 使能ADC

97 ADC_Cmd(RHEOSTAT_ADC1, ENABLE);

98 ADC_Cmd(RHEOSTAT_ADC2, ENABLE);

99 ADC_Cmd(RHEOSTAT_ADC3, ENABLE);

100

101 //开始adc转换,软件触发

102 ADC_SoftwareStartConv(RHEOSTAT_ADC1);

103 ADC_SoftwareStartConv(RHEOSTAT_ADC2);

104 ADC_SoftwareStartConv(RHEOSTAT_ADC3);

105 }

首先,我们使用了DMA_InitTypeDef定义了一个DMA初始化类型变量,该结构体内容我们在DMA篇已经做了非常详细的讲解;另外还使用ADC_InitTypeDef和ADC_CommonInitTypeDef结构体分别定义一个ADC初始化和ADC通用类型变量,这两个结构体我们之前已经有详细讲解。

调用RCC_APB2PeriphClockCmd()开启ADC时钟以及RCC_AHB1PeriphClockCmd()开启DMA时钟。

我们需要对DMA进行必要的配置。首先设置外设基地址就是ADC的通用规则数据寄存器地址;存储器的地址就是我们指定的数据存储区空间,ADC_ConvertedValue是我们定义的一个全局数组名,它是一个无符号32位有三个元素的整数数字;ADC规则转换对应只有一个数据寄存器所以地址不能递增,我们指定的存储区也需要递增地址。ADC的通用规则数据寄存器是32位有效,我们配置ADC为DMA模式2,设置数据大小为字大小。ADC配置为连续转换模式DMA也设置为循环传输模式。设置好DMA相关参数后就使能DMA的ADC通道。

接下来我们使用ADC_CommonInitTypeDef结构体变量ADC_CommonInitStructure来配置ADC为三重ADC交替模式、分频系数为4、需要设置DMA模式2、10个周期的采样延迟,并调用ADC_CommonInit函数完成ADC通用工作环境配置。

我们使用ADC_InitTypeDef结构体变量ADC_InitStructure来配置ADC1为12位分辨率、不使用扫描模式、启动连续转换、使用内部软件触发无需外部触发事件、使用右对齐数据格式、转换通道为1,并调用ADC_Init函数完成ADC1工作环境配置。ADC2和ADC3使用与ADC1相同配置即可。

ADC_RegularChannelConfig函数用来绑定ADC通道转换顺序和采样时间。绑定ADC通道引脚并设置相应的转换顺序。

ADC_MultiModeDMARequestAfterLastTransferCmd函数控制是否使能ADC的DMA请求,如果使能请求,并调用ADC_DMACmd函数使能DMA,则在ADC转换完成后就请求DMA实现数据传输。三重模式只需使能ADC1的DMA通道。

ADC_Cmd函数控制ADC转换启动和停止。

最后,如果使用软件触发需要调用ADC_SoftwareStartConvCmd函数进行使能配置。

主函数

代码清单 014 主函数

1 int main(void)

2 {

3 /*初始化USART1*/

4 Debug_USART_Config();

5

6 /*

7 初始化滑动变阻器用到的DAC,ADC数据采集完成后直接由DMA运输数据到

8 ADC_ConvertedValue变量DMA直接改变ADC_ConvertedValue的值*/

9 Rheostat_Init();

10

11 printf("\r\n ----这是一个ADC实验(DMA传输)----\r\n");

12

13 while (1) {

14 Delay(0xffffee);

15 ADC_ConvertedValueLocal[0] =

16 (float)((uint16_t)ADC_ConvertedValue[0]*3.3/4096);

17 ADC_ConvertedValueLocal[1] =

18 (float)((uint16_t)ADC_ConvertedValue[2]*3.3/4096);

19 ADC_ConvertedValueLocal[2] =

20 (float)((uint16_t)ADC_ConvertedValue[1]*3.3/4096);

21 printf("\r\n The current AD value = 0x%08X \r\n",

22 ADC_ConvertedValue[0]);

23 printf("\r\n The current AD value = 0x%08X \r\n",

24 ADC_ConvertedValue[1]);

25 printf("\r\n The current AD value = 0x%08X \r\n",

26 ADC_ConvertedValue[2]);

27 printf("\r\n The current ADC1 value = %f V \r\n",

28 ADC_ConvertedValueLocal[0]);

29 printf("\r\n The current ADC2 value = %f V \r\n",

30 ADC_ConvertedValueLocal[1]);

31 printf("\r\n The current ADC3 value = %f V \r\n",

32 ADC_ConvertedValueLocal[2]);

33 }

34 }

主函数先调用USARTx_Config函数配置调试串口相关参数,函数定义在bsp_debug_usart.c文件中。

接下来调用Rheostat_Init函数进行ADC初始化配置并启动ADC。Rheostat_Init函数是定义在bsp_adc.c文件中,它只是简单的分别调用Rheostat_ADC_GPIO_Config()和Rheostat_ADC_Mode_Config ()。

Delay函数只是一个简单的延时函数。

我们配置了DMA数据传输所以它会自动把ADC转换完成后数据保存到数组变量ADC_ConvertedValue内,根据DMA模式2的数据存放规则,ADC_ConvertedValue[0]的低16位存放ADC1数据、高16位存放ADC2数据,ADC_ConvertedValue[1]的低16位存放ADC3数据、高16位存放ADC1数据,ADC_ConvertedValue[2]的低16位存放ADC2数据、高16位存放ADC3数据,我们可以根据需要提取出对应ADC的转换结果数据。经过简单地计算就可以得到每个ADC对应的实际电压。

最后就是把相关数据打印至串口调试助手。

30.6.3 下载验证

保证开发板相关硬件连接正确,用USB线连接开发板"USB TO UART"接口跟电脑,在电脑端打开串口调试助手,把编译好的程序下载到开发板。在串口调试助手可看到不断有数据从开发板传输过来,此时我们旋转电位器改变其电阻值,那么对应的数据也会有变化。

30.7 每课一问

1、如果设置ADC分辨率为6、8或者10位时,输入电压值如何计算?

2、根据独立模式单通道采集实验设计实现相同功能,要求使用外部硬件触发转换方式。

3、编写一个双重ADC交替模式程序,实现类似三重ADC交替模式实验功能,要求使用DMA模式2实现程序功能。

 

STM32-单通道ADC采集(DMA读取)实验 实验要求:通过ADC1通道1(PA1)采集电位器的电压,并显示ADC转换的数字量和换算后的电压值。 阅读详情

相关推荐

STM32-独立模式多通道ADC采集

ADC介绍可参考DMS介绍:● 12个独立的可配置的通道(请求):DMA1有7个通道,DMA2有5个通道● 每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发。这些功能通过软件来配置。● 在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推)。● 独立数据源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。● 支持循环的缓冲器管理。...

jx5631833的博客 5946

STM32之ADC采集

一、什么是ADC采集? adc电路就是指模数转换电路。也就是将模拟信号变为数字信号。一般用在数据采集方面。 ADC,Analog-to-Digital Converter的缩写,指模/数转换器或者模拟/数字转换器。是指将连续变量的模拟信号转换为离散的数字信号的器件。真实世界的模拟信号,例如温度、压力、声音或者图像等,需要转换成更容易储存、处理和发射的数字形式。模/数转换器可以实现这个功能,在各种不同的产品中都可以找到它的身影。 典型的模拟数字转换器将模拟信号转换为表示一定比例电压值的数字信号。然而,有一些模

qq_33931978的博客 1万+

使用TouchGFX在STM32F429上进行LED控制和显示ADC值

在本文中,我们将讨论如何使用STM32F429微控制器和TouchGFX图形库进行LED控制和显示ADC(模数转换器)值的简单应用。这是一个简单的例子,演示了如何使用TouchGFX在STM32F429上进行LED控制和显示ADC值。您可以根据需要扩展和改进该应用程序,添加该应用程序,添加更多的功能和界面元素。请注意,本文提供的代码示例仅用于演示目的,可能需要根据您的具体硬件和软件配置进行适当的修改和调整。通过按下按钮,您应该能够控制LED的开关状态,并在界面上显示ADC的值。步骤6:构建和烧录应用程序。

ZwcCsharp的博客 494

stm32之adc采样部分的电路图讲解

采样部分的电路图 结构 主要的功能包含下面三个 1、滤波 因为我采样的都是期望的是直流的信号,因此,此处进行将高频的噪声进行一定的滤波 2、 电压调理 由于stm32的电压输入范围是0-2v。 而输入的电压的范围都是在10v,因此首先进行发反向的电压调理,随后,加入一个反向器进行再将电压反相回来。 3、电压调整 选择的是一个可调的电阻,以防止输入电压的变化范围改变。 具体的参数 输入电压的范围分别是5V,10V,10V, 因此进行一定的降压即可。 选择的运放是UA741CD ...

scottar的博客 3万+

CubeMX软件使用从入门到精通STM32F429系列--5ADC模拟电压采集

CubeM设置

二毛的博客 4008

Databricks Genie:语义编译器架构与企业级智能解析实践

语义层是现代数据平台实现自然语言查询的核心基础,其本质是将业务术语映射为可执行、可治理的数据契约。原理上依赖结构化元数据、值字典与数据血缘三支柱协同,通过分层AI代理(如Intent Parsing、Retriever、Verifier)实现意图识别→语义对齐→安全执行的闭环。技术价值在于降低SQL使用门槛的同时保障审计性、一致性和权限可控性,适用于销售运营、财务分析等一线业务场景。本文深入解析Databricks Genie作为典型语义编译器的落地逻辑,涵盖Unity Catalog知识注入、七层Agen

weixin_29053695的博客 337

STM32F429第二十八篇之ADC

前言 STM32F429的ADC为12位逐次逼近的模数转换器。该ADC具有19个复用通道,其中16个通道用于外部测量,两个内部源和VBAT通道。AD转换的结果存在一个16位的数据寄存器中,可以选择为左对齐或者右对齐。 ...

我想想的博客 7698

mtk-drm初始化

mtk-drm初始化走读

zhexingsunba的博客 4932

STM32 ADC 多通道16路电压采集

下面介绍一种利用STM32单片机制作的16路多通道ADC采集电路图和源程序。采用USB接口与电脑连接,实则USB转串口方式,所以上位机可以用串口作为接口。电路图中利用LM324作为电压跟随器,起到保护单片机引脚的作用。直接在电脑USB取点,省去外接电源麻烦,实测耗电电流不到20ma. 1.主控电路图:2. USB转串口电路图3.LM324电压跟随器电路图4.滤波电路图5.16路接口电路图6.电源电路

ambizxzh的博客 3万+

Unity 接入 Steam 平台

Unity 接入 steam sdk 的登录和应用内购买功能

MarinaTsang的博客 3904

Python爬取拼多多商品数据保姆级教程(附源码及效果图)

本文介绍了使用Python爬取拼多多商品数据的完整教程。通过DrissionPage库模拟浏览器操作,利用正则表达式提取嵌入在HTML中的商品数据(关键步骤是从window.rawData变量获取),解析后转换为结构化数据并导出Excel。教程包含八大步骤:环境配置、浏览器初始化、网络监听、搜索模拟、数据提取(核心是正则匹配JSON)、数据验证、字段解析和Excel导出,最后提供了封装好的函数可直接调用。该方法特别适合课程作业或毕业设计获取电商数据,能爬取商品名称、价格、销量等关键信息,处理了价格单位转换等

weixin_46449236的博客 2077

ADC相关电路的总结及提高ADC采样精度的方法(以STM32F系列为例)

以STM32F系列为例对ADC相关电路的总结,包括:ADC基本原理简介,ADC准确性指标,ADC经典结构图,提高ADC采样精度的方法

粉色挖掘机的博客 3万+

MRI多序列,多中心数据集预处理--使用FSL-Flirt 配准数据

FLIRT(FMRIB 的线性图像配准工具)是用于线性(仿射)模态内和模态间脑图像配准的全自动稳健且准确的工具。 什么是配准 在这两张图片上,很容易看出它们没有对齐,左边相对右边倾斜,虽然我们人类视觉系统还是能把对应的解剖关系连系在一起,但是我们使用计算机分析时确不能够 因此,我们希望相同的解剖结构对齐,用坐标表示的话,希望他们在相同的坐标上。如下图 对齐这些解剖结构的过程就叫做配准(register) 因此,配准的目的也是使相同的解剖结构在同一个位置,便于分析。可以将CT和MRI配准,看同一结构在两个

Tina姐的博客 1万+

STM32使用ADC+DMA进行多通道模拟量采集 (踩坑及傻瓜式解析)

STM32使用ADC+DMA进行多通道模拟量采集 (踩坑及通俗解析) ​ 利用STM32的片上外设可采集多个模拟量(如传感器数值),并在嵌入式程序中使用。如果只使用了一个通道,用时令ADC转换而后读取DR寄存器即可。多通道时,可利用ADC+DMA可实时,有序的转存多通道数据至程序内存(数组),用时可随时访问并索引到对应通道。 CubeMX配置 时钟配置如下: ​ 原先经常忽视时钟的信息,这里注意一下ADC1,2,3的时钟频率,其于ADC采样时间有关。如果时钟配置的很高,那么选择1.5Cycles可能不

tpytpytpy的博客 2万+

使用 DEM 模拟金属烧结过程

了解离散元素法 (DEM) 如何彻底改变烧结工艺,提高制造业的效率和精度。

jkh920184196的博客 1127

Comsol单层焊缝焊接数值模拟:温度场与应力场全流程解析

在工程制造领域,有限元模拟是研究焊接热-力行为、优化工艺参数的重要工具。焊接过程涉及强烈的局部加热和快速冷却,材料经历复杂的非线性和相变,必须通过瞬态分析和热-力顺序耦合,才能准确捕捉移动热源作用下的温度演化与应力塑性积累。这一技术广泛应用于压力容器、船舶结构、车辆制造等场景,用以预测残余应力与变形、评估冷裂纹风险,并为工艺设计提供定量支撑。焊接数值模拟能否真正指导实践,关键在于热源校核、随温度变化的材料参数、合理的边界条件与网格策略。单层焊缝作为焊接模拟的基础模型,涵盖了移动热源加载、熔池形成、高温软化与

weixin_30444111的博客 221

STM32——ADC采集

目录 ADC简介 ADC主要特征 ADC功能框图 ADC引脚 电压输入范围 通道选择 单次转换模式 连续转换模式 转换顺序 规则序列 注入序列 触发源 转换时间 中断 转换结束中断 模拟看门狗中断 DMA请求 代码讲解 宏定义: ADC简介 12位ADC是一种逐次逼近型模拟数字转换器,它有多达18个通道,可以测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行.ADC的结果可以是左对齐或者是右对齐方式存储在16位数据寄存器中。 .

qq_43460068的博客 3万+

手把手教你用Zynq-7100 FPGA实现100Mbps OOK信号定时同步(含完整Verilog代码)

本文详细介绍了如何在Zynq-7100 FPGA平台上实现100Mbps OOK信号的定时同步,涵盖插值算法、Gardner定时误差检测等关键技术。通过完整的Verilog代码和优化技巧,解决了50MHz外部时钟条件下的400MHz采样率同步挑战,为无线通信系统设计提供实用解决方案。

weixin_42522374的博客 301

STM32笔记_10(ADC—电压采集)

STM32f103 系列有3 个 ADC,精度为12 位,每个 ADC 最多有16 个外部通道。其中 ADC1 和ADC2 都有 16 个外部通道, ADC3 根据 CPU 引脚的不同通道数也不同,一般都有 8 个外部通道。

weixin_58038211的博客 6841

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

stm32f429vref怎么接_STM32如何通过内部VREF得到实际的VDDA值

/****************************************************/// 程序用途:用来测试通过内部基准电压计算外部VDDA的值// 程序作者:孟瑞生// 微信公众号:科技老顽童/****************************************************/#include "stm32f0xx.h"#include "stdio...

weixin_39948309的博客 1228

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

基于Cubemx的STM32F429多重adc采样DMA传输配置,定时器触发采样率可调,最高可到7.2MHz采样率~

最后补充一些细节部分吧:首先,并不是任意的采样率都可以通过这个多重adc实现!因为我们假定定时器触发频率是f1,而由数据手册可知,adc1采样后经过固定时间 t(假定这个t对应频率是f2,f2=1/t)后触发adc2采样,再经过时间 t 触发adc3采样,直到下一次定时器触发,才重新开始这个过程。那么你很容易发现,其实一旦f1远小于f2,就容易变成短时间采集三个点的情况(那其实跟一次只采一个点也没多大区别)!只有当f1和f2相等时,才能够实现每个采样点的间隔是相同的,才是一个好的采样方式!

m0_66643298的博客 5275

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

STM32 ADC原理介绍&电压电流采集原理

STM32内置逐次逼近型(SAR)ADC采用12位分辨率,通过DAC和比较器逐位逼近输入电压实现模数转换,量程默认0-3.3V(由VREF+决定),支持外接调理电路扩展测量范围。其核心参数包含0.8mV理论精度、受Nyquist定理约束的采样频率(≥2倍信号频率),以及由采样时间(可编程)和12.5时钟周期组成的转换时间。实际应用中需注意参考电压稳定性问题,可通过内部VREFINT校准或外接高精度基准源优化精度,配合电阻分压/采样电阻电路可实现宽范围电压/电流测量,建议采用RC滤波和软件校准消除噪声干扰。

cccnz的博客 1万+

STM32内部ADC采集mv信号

STM32内部ADC采样毫伏信号

qq_39649731的博客 4178

STM32单片机ADC采集

STM32单片机ADC采集STM32单片机ADC采集reference STM32单片机ADC采集 模拟信号:电压值随着时间是连续变化的 优点:可以精确地表示事物变化的过程,缺点:容易受到噪声的干扰,有误差 数字信号:抗干扰能力强 采样频率: ADC精度: 工程项目结构: 其中画红色方框部分为重要函数实现功能 ADC.c: #include "ADC/ADC.h" #include "DELAY/Delay.h" /** * 功能:初始化ADC1_IN9 * 参数:None * 返回值:

嵌入式与人工智能 8539

STM32 ADC高速采样(你的ADC采样电路设计对了吗)

这个问题在于,ADC本身有一定的输入阻抗,但阻抗并不高,有些甚至只有几kΩ。这样直接接入信号,ADC的输入阻抗就会起到分压的作用。如下图,ADC的输入阻抗Rz和R2并联后再和R1分压,因此实际分压比就和设计的完全不同了,采样到的值自然会和设计值差别很大。所以输入信号应该要做适当的处理。

world9999的博客 1万+
上一篇: 第29章 电容触摸屏—触摸画板—零死角玩转STM32-F429系列
下一篇: 第31章 TIM—基本定时器—零死角玩转STM32-F429系列
0木木0
博客等级 码龄17年 458粉丝 58原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值