STM32f103 系列有 3 个 ADC,精度为12 位,每个 ADC 最多有 16 个外部通道。其中ADC1和ADC2 都有 16 个外部通道,ADC3根据CPU 引脚的不同通道数也不同,一般都有8 个外部通道。ADC 的模式非常多,功能非常强大。
ADC 输入范围为:V REF- ≤ V IN ≤ V REF+ ,一般把 V SSA 和 V REF- 接地,把 V REF+ 和 V DDA 接3V3,得到ADC 的输入电压范围为:0~3.3V。
通道:
注入通道:
注入,可以理解为插入,插队的意思,是一种不安分的通道。它是一种在规则通道转换的时候强行插入要转换的一种。如果在规则通道转换过程中,有注入通道插队,那么就要先转换完注入通道,等注入通道转换完成后,再回到规则通道的转换流程。这点跟中断程序很像,都是不安分的主。所以,注入通道只有在规则通道存在时才会出现。
转换顺序:规则序列:
规则序列寄存器有 3 个,分别为 SQR3、SQR2、SQR1。
SQR3 控制着规则序列中的第一个到第六个转换,对应的位为:SQ1[4:0]~SQ6[4:0],第一次转换的是位 4:0 SQ1[4:0],如果通道 16想第一次转换,那么在 SQ1[4:0]写 16即可。
注入序列
注入序列寄存器 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 一样。
触发源:
ADC 转换可以由ADC 控制寄存器 2: ADC_CR2 的 ADON 这个位来控制,写 1 的时候开始转换,写 0 的时候停止转换。
ADC 还支持触发转换,这个触发包括内部定时器触发和外部 IO 触发。触发源有很多,具体选择哪一种触发源,由 ADC 控制寄存器 2:ADC_CR2 的
EXTSEL[2:0]和 JEXTSEL[2:0]位来控制。EXTSEL[2:0]用于选择规则通道的触发源,JEXTSEL[2:0]用于选择注入通道的触发源。选定好触发源之后,触发源是否要激活,则由ADC 控制寄存器 2:ADC_CR2 的 EXTTRIG 和 JEXTTRIG 这两位来激活。其中 ADC3 的规则转换和注入转换的触发源与 ADC1/2 的有所不同,在框图上已经表示出来。
转换时间:
ADC时钟:
ADC 输入时钟 ADC_CLK 由 PCLK2 经过分频产生,最大是 14M,分频因子由 RCC时钟配置寄存器 RCC_CFGR 的位 15:14 ADCPRE[1:0]设置,可以是 2/4/6/8 分频,注意这里没有 1 分频。一般我们设置 PCLK2=HCLK=72M。
采样时间:
ADC 使用若干个 ADC_CLK 周期对输入的电压进行采样,采样的周期数可通过 ADC采样时间寄存器 ADC_SMPR1 和 ADC_SMPR2 中的 SMP[2:0]位设置,ADC_SMPR2 控制的是通道0~9,ADC_SMPR1 控制的是通道 10~17。
数据寄存器:
规则数据寄存器:
ADC 规则组数据寄存器 ADC_DR 只有一个,是一个 32 位的寄存器,低 16 位在单 ADC时使用,高 16 位是在 ADC1 中双模式下保存 ADC2 转换的规则数据,双模式就是 ADC1 和ADC2同时使用。
注入数据寄存器:
DMA:
规则和注入通道转换结束后,除了产生中断外,还可以产生 DMA 请求,把转换好的数据直接存储在内存里面。要注意的是只有 ADC1 和 ADC3 可以产生 DMA 请求。
ADC_InitTypeDef结构体
1 typedef struct
2 {
3 uint32_t ADC_Mode; // ADC 工作模式选择
4 FunctionalState ADC_ScanConvMode;
6 FunctionalState ADC_ContinuousConvMode; // ADC 单次转换或者连续转换选择
7 uint32_t ADC_ExternalTrigConv; // ADC 转换触发信号选择
8 uint32_t ADC_DataAlign; // ADC 数据寄存器对齐格式,右对齐ADC_DataAlign_Right 或者左对齐 ADC_DataAlign_Left。一般我们选择右对齐模式。
9 uint8_t ADC_NbrOfChannel; // ADC 采集通道数
10 } ADC_InitTypeDef;
主要配置代码:
#define ADC_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ADC_CLK RCC_APB2Periph_ADC1
#define ADC_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ADC_GPIO_CLK RCC_APB2Periph_GPIOC
#define ADC_PORT GPIOC
#define NOFCHANEL 6
#define ADC_PIN1 GPIO_Pin_0
#define ADC_CHANNEL1 ADC_Channel_10
#define ADC_PIN2 GPIO_Pin_1
#define ADC_CHANNEL2 ADC_Channel_11
#define ADC_PIN3 GPIO_Pin_2
#define ADC_CHANNEL3 ADC_Channel_12
#define ADC_PIN4 GPIO_Pin_3
#define ADC_CHANNEL4 ADC_Channel_13
#define ADC_PIN5 GPIO_Pin_4
#define ADC_CHANNEL5 ADC_Channel_14
#define ADC_PIN6 GPIO_Pin_5
#define ADC_CHANNEL6 ADC_Channel_15
// ADC1 对应 DMA1通道1,ADC3对应DMA2通道5,ADC2没有DMA功能
#define ADC_x ADC1
#define ADC_DMA_CHANNEL DMA1_Channel1
#define ADC_DMA_CLK RCC_AHBPeriph_DMA1
static void ADCx_Mode_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
// 打开DMA时钟
RCC_AHBPeriphClockCmd(ADC_DMA_CLK, ENABLE);
// 打开ADC时钟
ADC_APBxClock_FUN ( ADC_CLK, ENABLE );
// 复位DMA控制器
DMA_DeInit(ADC_DMA_CHANNEL);
// 配置 DMA 初始化结构体
// 外设基址为:ADC 数据寄存器地址
DMA_InitStructure.DMA_PeripheralBaseAddr = ( u32 ) ( & ( ADC_x->DR ) );
// 存储器地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_ConvertedValue;
// 数据源来自外设
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
// 缓冲区大小,应该等于数据目的地的大小
DMA_InitStructure.DMA_BufferSize = NOFCHANEL;
// 外设寄存器只有一个,地址不用递增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
// 存储器地址递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
// 外设数据大小为半字,即两个字节
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
// 内存数据大小也为半字,跟外设数据大小相同
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
// 循环传输模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
// DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
// 禁止存储器到存储器模式,因为是从外设到存储器
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
// 初始化DMA
DMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure);
// 使能 DMA 通道
DMA_Cmd(ADC_DMA_CHANNEL , ENABLE);
// ADC 模式配置
// 只使用一个ADC,属于单模式
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
// 扫描模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE ;
// 连续转换模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
// 不用外部触发转换,软件开启即可
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
// 转换结果右对齐
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
// 转换通道个数
ADC_InitStructure.ADC_NbrOfChannel = NOFCHANEL;
// 初始化ADC
ADC_Init(ADC_x, &ADC_InitStructure);
// 配置ADC时钟N狿CLK2的8分频,即9MHz
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
// 配置ADC 通道的转换顺序和采样时间
ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL1, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL2, 2, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL3, 3, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL4, 4, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL5, 5, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL6, 6, ADC_SampleTime_55Cycles5);
// 使能ADC DMA 请求
ADC_DMACmd(ADC_x, ENABLE);
// 开启ADC ,并开始转换
ADC_Cmd(ADC_x, ENABLE);
// 初始化ADC 校准寄存器
ADC_ResetCalibration(ADC_x);
// 等待校准寄存器初始化完成
while(ADC_GetResetCalibrationStatus(ADC_x));
// ADC开始校准
ADC_StartCalibration(ADC_x);
// 等待校准完成
while(ADC_GetCalibrationStatus(ADC_x));
// 由于没有采用外部触发,所以使用软件触发ADC转换
ADC_SoftwareStartConvCmd(ADC_x, ENABLE);
}
参考《零死角玩转stm32f103》
上一篇:STM32ADC单次转换实例
下一篇:STM32F407ADC多通道+定时器触发+DMA模式设置
推荐阅读最新更新时间:2024-03-16 16:15
设计资源 培训 开发板 精华推荐
- 微灵医疗李骁健:脑机接口技术正在开启意识与AI融合的新纪元
- USB Type-C® 和 USB Power Delivery:专为扩展功率范围和电池供电型系统而设计
- 景昱医疗耿东:脑机接口DBS治疗技术已实现国产替代
- 首都医科大学王长明:针对癫痫的数字疗法已进入使用阶段
- 非常见问题解答第223期:如何在没有软启动方程的情况下测量和确定软启动时序?
- 兆易创新GD25/55全系列车规级SPI NOR Flash荣获ISO 26262 ASIL D功能安全认证证书
- 新型IsoVu™ 隔离电流探头:为电流测量带来全新维度
- 英飞凌推出简化电机控制开发的ModusToolbox™电机套件
- 意法半导体IO-Link执行器电路板为工业监控和设备厂商带来一站式参考设计
- Melexis采用无磁芯技术缩小电流感测装置尺寸