介绍
STM32F103ZET6 拥有12位ADC,是一种逐次逼近型模拟数字转换器。
12bits ADC 代表了 ADC 的转换精度。存在输入参考电压的情况下,ADC 将模拟信号经信号线输入,进行模拟信号的采样,再将采样后的数字信号存放于数据寄存器中,以供软件进行读取(CPU或者DMA方式),存储的数据是经过参考电压比较后,按照12bits 进行换算得到。
ADC输入范围:Vref- ≤ Vin ≤ Vref+
ADC 时钟
ADC 的输入时钟 ADCCLK 不能超过 14MHz(Datasheet规定)它是由PCLK2经分频产生。
转换模式
支持单次转换和连续转换,顾名思义,单次转换就仅仅只进行一次转换,然后就将值写入数据寄存器,连续转换时不间断的进行ADC操作,并将值写入到数据寄存器。
通道描述
ADC有两组通道:规则通道组和注入通道组。
规则通道组:相当于你正常运行的程序。
注入通道组:就相当于中断。在你程序正常执行的时候,中断是可以打断你的执行的。同这个类似,注入通道的转换可以打断规则通道的转换, 在注入通道被转换完成之后,规则通道才得以继续转换。
也就是说,注入通道可以来打断当前正在进行的规则的 ADC 数据转换,暂时理解成为优先级的概念即可。
● 规则通道组:由多达16个转换组成。规则通道和它们的转换顺序在ADC_SQRx寄存器中选择。规则组中转换的总数应写入ADC_SQR1寄存器的L[3:0]位中。
● 注入通道组:由多达4个转换组成。注入通道和它们的转换顺序在ADC_JSQR寄存器中选择。注入组里的转换总数目应写入ADC_JSQR寄存器的L[1:0]位中。
也就是说,在规则通道组,支持 16 路模拟信号同时输入,并进行这些通道的模拟信号转数字信号的采样,注入通道也是一样。
中断描述
● 如果一个规则通道被转换:
─ 转换数据被储存在16位ADC_DR寄存器中
─ EOC(转换结束)标志被设置
─ 如果设置了EOCIE,则产生中断。
● 如果一个注入通道被转换:
─ 转换数据被储存在16位的ADC_DRJ1寄存器中
─ JEOC(注入转换结束)标志被设置
─ 如果设置了JEOCIE位,则产生中断。
中断事件 | 事件标志 | 使能控制位 |
规则组转换结束 | EOC | EOCIE |
注入组转换结束 | JEOC | JEOCIE |
设置了模拟看门狗状态位 | AWD | AWDIE |
通道扫描
此模式用来扫描一组模拟通道。
扫描模式可通过设置 ADC_CR1 寄存器的 SCAN 位来选择。一旦这个位被设置,ADC 扫描所有被 ADC_SQRX 寄存器(对规则通道)或 ADC_JSQR (对注入通道)选中的所有通道。在每个组的每个通道上执行单次转换。在每个转换结束时,同一组的下一个通道被自动转换。如果设置了CONT位,转换不会在选择组的最后一个通道上停止,而是再次从选择组的第一个通道继续转换。
如果设置了DMA位,在每次EOC后,DMA控制器把规则组通道的转换数据传输到SRAM中。而注入通道转换的数据总是存储在ADC_JDRx寄存器中
校准
ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。在校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差。
建议在每次上电后执行一次校准。
启动校准前, ADC 必须处于关电状态 (ADON=’0’) 超过至少两个 ADC 时钟周期。
采样时间
ADC 的转换时间不仅仅和 ADC 的时钟有关,还和采样时间有关,ADC使用若干个ADC_CLK周期对输入电压采样,采样周期数目可以通过 ADC_SMPR1 和 ADC_SMPR2 寄存器中的SMP[2:0]位更改。每个通道可以分别用不同的时间采样。
ADC 的转换时间的计算公式是:Tconv = 采样时间+ 12.5个周期
例如:当ADCCLK=14MHz,采样时间为1.5周期,Tconv = 1.5 + 12.5 = 14周期 = 1μs
环境描述
参考电压中,单板上Vref-直接接到了 GND,Vref+接到了Vcc 3.3V。
单板上,使用分压电阻进行模拟输入,电阻可调,并使用 PC1 端口进行输入
配置过程
配置过程分为三段:
● GPIO 口的配置
● DMA 的配置
● ADC 的配置
GPIO 口的配置
static void SK_ADC1GPIOInit(void) { GPIO_InitTypeDef stGpioInit; /* Enable ADC1 and GPIOC clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE); /* Configure PC.01 as analog input */ stGpioInit.GPIO_Pin = GPIO_Pin_1; stGpioInit.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOC, &stGpioInit); }
DMA 的配置
DMA配置,使用了 DMA1 通道,故配置 DMA1 的相关寄存器:
1. 开启 DMA1 时钟
2. 复位 DMA1
3. 配置外设地址和数据传送的内存地址
4. 数据传送方向为外设-->内存
5. 数据传送大小为 1 个(half word,16bit)
6. 关闭内存和外设地址增长
7. 配置内存数据和外设数据宽度为 16bit
8. 配置循环模式
9. 配置优先级,同时禁用mem2mem
static void SK_ADC1DMAInit(void)
{
DMA_InitTypeDef stDMA_Init;
/* Enable DMA clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* DMA channel1 configuration */
DMA_DeInit(DMA1_Channel1);
stDMA_Init.DMA_PeripheralBaseAddr = ADC1_DR_Address;
stDMA_Init.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue;
stDMA_Init.DMA_DIR = DMA_DIR_PeripheralSRC;
stDMA_Init.DMA_BufferSize = 1;
stDMA_Init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
stDMA_Init.DMA_MemoryInc = DMA_MemoryInc_Disable;
stDMA_Init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
stDMA_Init.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
stDMA_Init.DMA_Mode = DMA_Mode_Circular;
stDMA_Init.DMA_Priority = DMA_Priority_High;
stDMA_Init.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &stDMA_Init);
/* Enable DMA channel1 */
DMA_Cmd(DMA1_Channel1, ENABLE);
}
ADC 的配置
由于测试的应用场景较为简单,很多用法都用不到,故在配置的时候,就没有使能:
比如模拟看门狗,注入转换,双 ADC 等等,这里只使用了最简单的单通道的 ADC
配置流程如下:
1. 首先配置 ADC 时钟,由于 ADC 的时钟最大支持 14MHz,系统主频为 72MHz,分给 PCLK2 也为 72MHz,而 ADC 的分频器支持的分频系数仅为:2/4/6/8,暂时设置成为 8 分频,即 72/8 = 9MHz
2. 配置 ADC 为独立模式(双模式选择中配置)
3. 关闭 SCAN 模式(多路 ADC 使用到,单路就暂时不用)
4. 开启连续转换模式
5. 关闭外部触发,由软件独立触发
6. 数据右对齐
7. 转换通道数目为 1个规则通道
由于这里没有使用到注入通道和外部触发,所以少配置很多寄存器。
8. 配置 ADC 1的 Ch11 的采样时间和规则采样的通道数目
9. 开启 ADC1 的 DMA
10. 开启并唤醒 ADC1
11. 初始化校准寄存器并进行 ADC1 的校准
void SK_ADC1Init(void)
{
ADC_InitTypeDef stADC_Init;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
/// Step 1 : Configure I/O Pin First
SK_ADC1GPIOInit();
/// Step 2 : Configure DMA
SK_ADC1DMAInit();
/// Step 3 : PCLK2 div in 8, ADC CLK => 9Mhz
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
/// Step 4 : Configure Basic function of ADC1
stADC_Init.ADC_Mode = ADC_Mode_Independent;
stADC_Init.ADC_ScanConvMode = DISABLE;
stADC_Init.ADC_ContinuousConvMode = ENABLE;
stADC_Init.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
stADC_Init.ADC_DataAlign = ADC_DataAlign_Right;
stADC_Init.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &stADC_Init);
/// Step 5 : Configure Ch11 sample rate
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5);
/// Step 6 : Enable ADC1 DMA
ADC_DMACmd(ADC1, ENABLE);
/// Step 7 : Enable ADC1
ADC_Cmd(ADC1, ENABLE);
/// Step 8 : Reset Calibration Register
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
/// Step 9 : Start Calibration
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
/// Step 10 : Software trigger ADC1
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
最后别忘了,12 bit 精度对应的是 4096 的颗粒度,即,将得到的数字划分成为 4096 份,转换成为电压的话,就是:
(float)ADC_ConvertedValue/4096*3.3
上一篇:STM32F103ZET6 时钟(2)—— 代码篇
下一篇:STM32F103ZET6 — EXTI
推荐阅读最新更新时间:2024-03-16 16:11