本篇文章主要介绍ADC模数转换器及DMA转运,这也是Stm32中比较重要的部分,值得大家学习。
ADC简介
ADC(Analog-Digital Converter)模拟-数字转换器
ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁
12位逐次逼近型ADC,1us转换时间
输入电压范围:0~3.3V,转换结果范围:0~4095
18个输入通道,可测量16个外部和2个内部信号源
规则组和注入组两个转换单元
模拟看门狗自动监测输入电压范围
STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道
逐次逼近型ADC

ADC框图

ADC基本结构

注意:规则组可以采集16路通道,但是只能保持一路通道采集信息,一般配合DMA转运进行使用;而注入组AD数据寄存器完全可以将它能采集到的4路通道信息同时保存。
转换模式
根据选择单次转换还是连续转换,扫描还是非扫描,有以下4种转换模式:
- 单次转换,非扫描模式
- 连续转换,非扫描模式
- 单次转换,扫描模式
- 连续转换,扫描模式
如果不扫描,则只检测第一个通道(指定的),如果扫描,则会按照指定的顺序对通道进行检测,在检测完成之后,会将EOC置1;如果选择的是单次转换,在一次转换完成后就停止,直至下一次发送检测指令,选择连续,则会一直检测下去。
当然,在扫描模式下,还有间断模式,详见STM32参考手册。
ADC触发源
下表是STM32C8T6中ADC1和ADC2用于规则通道的外部触发:
触发源 |
类型 |
EXTSEL[2:0] |
TIM1_CC1事件 |
来自片上定时器的内部信号 |
000 |
TIM1_CC2事件 |
来自片上定时器的内部信号 |
001 |
TIM1_CC3事件 |
来自片上定时器的内部信号 |
010 |
TIM2_CC2事件 |
来自片上定时器的内部信号 |
011 |
TIM3_TRGO事件 |
来自片上定时器的内部信号 |
100 |
TIM4_CC4事件 |
来自片上定时器的内部信号 |
101 |
EXTI线11/TIM8_TRGO事件 |
外部引脚/来自片上定时器的内部信号 |
110 |
SWSTART |
软件控制位 |
111 |
数据对齐
- 数据右对齐:

- 数据左对齐:

选择左对齐的好处:可以选择取出高八位,降低精度。
转换时间
校准
ADC外围硬件电路设计

代码演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
void AD_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while (ADC_GetResetCalibrationStatus(ADC1) == SET); ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1) == SET); } uint16_t AD_GetValue(uint8_t ADC_Channel) { ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5); ADC_SoftwareStartConvCmd(ADC1, ENABLE); while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); return ADC_GetConversionValue(ADC1); }
|
DMA简介
DMA(Direct Memory Access)直接存储器存取
DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源
12个独立可配置的通道: DMA1(7个通道), DMA2(5个通道)
每个通道都支持软件触发和特定的硬件触发
STM32F103C8T6 DMA资源:DMA1(7个通道)
存储器映像

DMA框图

DMA基本结构

DMA请求

数据转运+DMA

DMA转运一轮后必须 关闭 DMA后再开启。
代码演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint16_t Size) { MyDMA_Size = Size; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_InitTypeDef DMA_InitStructure; DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; DMA_InitStructure.DMA_MemoryBaseAddr = AddrB; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = Size; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_M2M = DMA_M2M_Enable; DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; DMA_Init(DMA1_Channel1, &DMA_InitStructure); DMA_Cmd(DMA1_Channel1, DISABLE); }
void MyDMA_Transfer(void) { DMA_Cmd(DMA1_Channel1, DISABLE); DMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size); DMA_Cmd(DMA1_Channel1, ENABLE); while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET); DMA_ClearFlag(DMA1_FLAG_TC1); }
|
ADC扫描模式+DMA

代码演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
#include "stm32f10x.h"
uint16_t AD_Value[4];
void AD_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5); ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_NbrOfChannel = 4; ADC_Init(ADC1, &ADC_InitStructure); DMA_InitTypeDef DMA_InitStructure; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 4; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; DMA_Init(DMA1_Channel1, &DMA_InitStructure); DMA_Cmd(DMA1_Channel1, ENABLE); ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while (ADC_GetResetCalibrationStatus(ADC1) == SET); ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1) == SET); ADC_SoftwareStartConvCmd(ADC1, ENABLE); }
|
END