ADC外设

文章目录

  • ADC
    • ADC结构
    • 初始化流程
      • 初始化(无DMA)
      • 初始化(带DMA)
    • 标准库函数使用模板
      • ADC初始化函数(无DMA)
      • ADC_DMA数据转运函数
      • ADC_NVIC中断函数
      • 软件触发ADC
      • 外部硬件件触发ADC
      • 配置规则组通道
      • 配置注入组通道
      • 配置模拟看门狗
      • 配置规则组间断模式
      • 获取ADC转换数据
      • ADC标志位函数
      • ADC自检校准
      • ADC初始化函数(带DMA)
      • 内部温度和电压ADC传感器
    • 流程图

ADC

ADC(Analog-Digital Converter)模数转换器。
12位逐次逼近型ADC,1us转换时间。
输入电压范围:0 ~ 3.3V,转换结果范围:0 ~ 4095。
18个输入通道,可测量16个外部和2个内部通道。
规则组和注入组两个转换单元。
模拟看门狗自动监测输入电压范围。

STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道

ADC结构

ADC外设_第1张图片

ADC1_INx:16个外部通道(GPIO口,见引脚定义表)。
注入组和规则组触发:由硬件触发ADC转换。(软件SWSTART触发未体现)
ADCCLK:ADC的RCC时钟信号(最大14MHz预分频只可选6或8)。
EOC信号:转换完成后。(注入组和规则组均会产生)
JEOC信号:注入组转换完成后。(仅注入组会产生)
模拟看门狗:超出阈值将产生AWD信号。

规则组数据寄存器:只可存放1个数据。
注入组数据寄存器:可存放4个数据。
规则组:一次可选16个通道。(可自动扫描)
注入组:一次可选4个通道。(无DMA请求,产生中断)
转换时间:采样时间(可配置) + 12.5 个周期

ADC1、2、3的18个通道对应的GPIO口:
ADC外设_第2张图片
ADC外设_第3张图片

单/多通道:每次选择一/多个通道。
单次/连续转换:产生EOC信号后停止/继续转换。
非扫描/扫描模式:菜单列表使用一/多个通道。
DMA/中断:实现数据的自动读取。
ADC1和ADC2的中断映射在同一个中断向量上,而ADC3的中断有自己的中断向量

扫描模式:ADC扫描所有被规则通道或注入通道选中的所有通道。在每个组的每个通道上执行单次转换。在每个转换结束时,同一组的下一个通道被自动转换。
连续转换模式:转换不会在组的最后一个通道上停止,而是再次从组的第一个通道继续转换。
DMA:在每次EOC信号后,DMA控制器把规则组通道的转换数据传输到内存中。而注入组的通道转换的数据总是存储在组入组的寄存器中。
间断模式:不是中断,是每转换完几个(0~8)通道就停一下。
触发注入:外部注入触发,启动注入组转换(会打断正在转换的其他通道)。
自动注入:在规则组通道转换之后,注入组通道被自动转换。
ADC外设_第4张图片

初始化流程

初始化(无DMA)

  • RCC:开启ADCx和GPIO时钟
  • GPIO初始化:同前(配置为GPIO_Mode_AIN)
  • 配置ADCCLK预分频:RCC_ADCCLKConfig() 6分频 -> 12MHz,8分频 -> 9MHz
  • 选择规则组输入通道:ADC_RegularChannelConfig()
  • ADC初始化结构体:ADC_InitTypeDef
    • ADC_Mode:工作模式(单/双ADC模式…)
    • ADC_DataAlign:数字对齐(右对齐)
    • ADC_ExternalTrigConv:外部触发源/软件触发选择
    • ADC_ContinuousConvMode:连续/单次转换模式
    • ADC_ScanConvMode:扫描/非扫描模式
    • ADC_NbrOfChannel:总使用通道数
  • 使能ADC:ADC_Cmd()
  • 校准ADC:先使能后校准

初始化(带DMA)

  • RCC:开启ADCx、DMAx和GPIOx时钟
  • ADC初始化
  • DMA初始化:注意硬件通道
  • DMA使能:DMA_Cmd()注意硬件通道一致
  • 开启ADC的DMA输出:ADC_DMACmd()
  • 使能并校准ADC:ADC_Cmd()

标准库函数使用模板

ADC初始化函数(无DMA)

void AD_Init(void)  //单通道,非扫描模式
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//开启ADC1时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//分频6 -> 12MHz,8 -> 9MHz
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, 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 = 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);
	
	//ADC_SoftwareStartConvCmd(ADC1, ENABLE);//若为连续转换则在此软件触发一次,之后就能自动转换
}

uint16_t AD_GetValue(void)
{
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件触发(连续转换模式无需)
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//等待转换结束(连续转换模式无需)
	return ADC_GetConversionValue(ADC1);//得到数据(连续转换模式时仅需此函数即可)
}

ADC_DMA数据转运函数

/* ADC_DMACmd                     使能DMA数据转运
* @ param1  选择ADCx
* @ param2  使能/失能
* @ retval  None
*/
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);

ADC_NVIC中断函数

/* ADC_ITConfig                   使能ADC中断
* @ param1  选择ADCx
* @ param2  ADC中断的信号源选择
* @ param3  使能/失能
* @ retval  None
*/
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);

/* ADC_GetITStatus                获得中断标志位
* @ param1  选择ADCx
* @ param2  ADC中断的信号源选择
* @ retval  SET/RESET
*/
ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT);

/* ADC_ClearITPendingBit          清除中断标志位
* @ param1  选择ADCx
* @ param2  ADC中断的信号源选择
* @ retval  None
*/
void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT);

软件触发ADC

/* ADC_SoftwareStartConvCmd      使能软件触发
* @ param1  选择ADCx
* @ param2  使能/失能
* @ retval  None
*/
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

/* ADC_GetSoftwareStartConvStatus     获取软件触发的ADC开始转换状态
* @ param1  选择ADCx
* @ retval  SET/RESET
*/
FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);

外部硬件件触发ADC

/* ADC_ExternalTrigConvCmd      使能外部硬件触发
* @ param1  选择ADCx
* @ param2  使能/失能
* @ retval  None
*/
void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

配置规则组通道

/* ADC_RegularChannelConfig
* @ param1  选择 ADCx
* @ param2  选择通道(0 ~ 16)
* @ param2  选择通道的排名
* @ param2  选择该通道 ADC 转换的时间
* @ retval  None
*/
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);

配置注入组通道

//自动注入
void ADC_AutoInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

//间断模式
void ADC_InjectedDiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

//外部硬件触发通道配置
void ADC_ExternalTrigInjectedConvConfig(ADC_TypeDef* ADCx, uint32_t ADC_ExternalTrigInjecConv);

//外部硬件触发使能
void ADC_ExternalTrigInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

//软件触发使能
void ADC_SoftwareStartInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

//获取软件触发标志位
FlagStatus ADC_GetSoftwareStartInjectedConvCmdStatus(ADC_TypeDef* ADCx);

/* ADC_InjectedChannelConfig             注入组通道选择
* @ param1  选择ADCx
* @ param2  选择通道(0 ~ 16)
* @ param2  选择通道的排名
* @ param2  选择该通道 ADC 转换的时间
* @ retval  None
*/
void ADC_InjectedChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);

/* ADC_InjectedSequencerLengthConfig      配置注入组菜单序列长度
* @ param1  选择ADCx
* @ param2  注入组菜单序列长度
* @ retval  None
*/
void ADC_InjectedSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t Length);

/* ADC_SetInjectedOffset      设置注入组通道的转换偏移值
* @ param1  选择ADCx
* @ param2  注入组通道选择
* @ param3  偏移值(即平衡误差)
* @ retval  None
*/
void ADC_SetInjectedOffset(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint16_t Offset);

配置模拟看门狗

void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog);
void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold);
void ADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel);

配置规则组间断模式

/* ADC_DiscModeChannelCountConfig     配置间断模式
* @ param1  选择ADCx
* @ param2  选择通道个数
* @ retval  None
*/
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

获取ADC转换数据

uint16_t AD_GetValue(void)
{
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件触发(连续转换模式无需)
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//等待转换结束(连续转换模式无需)
	return ADC_GetConversionValue(ADC1);//得到数据(连续转换模式时仅需此函数即可)
}

/* ADC_GetConversionValue      规则组ADC数据(从寄存器中获取最后一次的值)
* @ param1  选择ADCx
* @ retval  None
*/
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);

/* ADC_GetInjectedConversionValue      注入组ADC数据
* @ param1  选择ADCx
* @ param2  注入组通道选择
* @ retval  None
*/
uint16_t ADC_GetInjectedConversionValue(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel);

/* ADC_GetDualModeConversionValue      双ADC模式
* @ retval  None
*/
uint32_t ADC_GetDualModeConversionValue(void);

ADC标志位函数

FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);

ADC自检校准

ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);

ADC初始化函数(带DMA)

uint16_t AD_Value[4];//.h中声明 exturn 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);
}

内部温度和电压ADC传感器

/* ADC_TempSensorVrefintCmd
* @ param1  使能/失能
* @ retval  None
*/
void ADC_TempSensorVrefintCmd(FunctionalState NewState);```

流程图


								   2				EOC/JEOC
							 +---------------------------->+----+
	  ADC基本结构			 |           +----------+      |中断|   +----+
							 |EOC/JEOC   |模拟看门狗  |     |输出+-->|NVIC|
							 |           +-----+----+      |控制|   +----+
	+----+16 +--+     +------+----+            |---------->+----+
	|GPIO+-->|  |     | AD转换器  |   +--------+--------+
	+----+   |  |     |           |   |  AD数据寄存器    |
			 |  | 16  |           | 1 |                |
	+----+   |  +-----+-->规则组--+---+->规则组结果 X 1   |
	|温度 +-->|  |     |           |   |                |
	+----+   |  | 4   |           | 4 |                 |
 	   		 |  +-----+-->注入组--+---+->注入组结果 X 4   |
	+----+   |  |     |           |   |                 |
	|VREF+-->|  |     +-----------+   +-----------------+
	+----+   +--+        ^     ^
                         |     |
                   START |     |CLOCK
                 +-------++   ++--+
                 |触发选择 |   |RCC|
                 +--------+   +---+


                                     ------ BY Flier

2023.9.4

Reference:江协科技、《stm32f10x用户手册》、《stm32库开发实战指南教程》

文章目录

  • ADC
    • ADC结构
    • 初始化流程
      • 初始化(无DMA)
      • 初始化(带DMA)
    • 标准库函数使用模板
      • ADC初始化函数(无DMA)
      • ADC_DMA数据转运函数
      • ADC_NVIC中断函数
      • 软件触发ADC
      • 外部硬件件触发ADC
      • 配置规则组通道
      • 配置注入组通道
      • 配置模拟看门狗
      • 配置规则组间断模式
      • 获取ADC转换数据
      • ADC标志位函数
      • ADC自检校准
      • ADC初始化函数(带DMA)
      • 内部温度和电压ADC传感器
    • 流程图

你可能感兴趣的:(#,标准库,单片机,stm32,嵌入式硬件)