ADC代码部分
本文最后更新于18天前,其中的信息可能已经有所发展或是发生改变。

AD单通道&AD多通道应用程序示例

ADC 常用库函数

  • ADC的RCC时钟配置函数

该配置函数定义存放在stm32f10x_rcc.h文件中,用来配置ADCCLK分频器。它可以对APB2的72MHz时钟选择2、4、6、8分频,输出到ADCCLK。 void RCC_ADCCLKConfig(uint32_t RCC_PCLK2) // 恢复ADC缺省配置

// 恢复ADC缺省配置
void ADC_DeInit(ADC_TypeDef* ADCx);
// ADC初始化
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
// ADC配置结构体初始化
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);
 
// ADC上电工作函数,即开关控制函数
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
 
// ADC开启DMA输出信号
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);
 
// ADC中断输出控制函数
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);
 
// 下面4个函数用于ADC工作前的校准操作,在ADC初始化完成后依次调用即可
// ADC复位校准
void ADC_ResetCalibration(ADC_TypeDef* ADCx);
// ADC获取复位校准状态
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
// ADC开始校准
void ADC_StartCalibration(ADC_TypeDef* ADCx);
// ADC获取开始校准状态
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);
 
// ADC软件触发转换,给CR2的SWSTART置1(开始转换后立即自动清0)
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
// ADC获取软件触发状态,获取CR2的SWSTART(开始转换规则通道)位
// 不能用它判断转换是否结束,一般不用,了解即可
FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);
 
// ADC规则组通道配置,给转换序列的每个位置填写指定的通道
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
 
// ADC外部触发转换控制(是否允许外部触发转换)
void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
 
// ADC获取转换值,获取AD转换的数据寄存器
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
 
// ADC获取双模式转换值,读取双ADC模式下ADC的转换结果
uint32_t ADC_GetDualModeConversionValue(void);
 
// ADC温度传感器、内部参考电压控制,开启内部的两个转换通道
void ADC_TempSensorVrefintCmd(FunctionalState NewState);
 
// 下面的函数与操作标志位寄存器状态有关
// ADC获取标志位状态,可通过获取EOC标志位判断转换是否结束
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
// 清除标志位
void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
// 获取中断标志位
ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT);
// 清除中断挂起位
void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT);
  • 模拟看门狗配置(本节暂不涉及,需要可以了解)
// 对模拟看门狗进行配置
// 是否启动模拟看门狗
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);
  • 注入组相关配置函数(本节暂不涉及,需要可以了解)
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);
void ADC_InjectedChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
void ADC_InjectedSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t Length);
void ADC_SetInjectedOffset(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint16_t Offset);
uint16_t ADC_GetInjectedConversionValue(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel);
  • ADC间断模式配置
// 下面两个函数用来配置STM32中ADC的间断模式
// 配置每隔几个通道间断依次
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);
// 开启间断模式
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

ADC单通道

AD.c

#include "stm32f10x.h"                  // Device header

/**
  * @brief  ADC初始化函数(单次转换非扫描实现多通道转换,软件触发,且这里不使用模拟看门狗和中断)
  * @param  无
  * @retval 无
  */
void AD_Init(void)
{
//配置时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);

//配置GPIO	
	GPIO_InitTypeDef GPIO_Initstructure;
	GPIO_Initstructure.GPIO_Mode = GPIO_Mode_AIN; //在AIN模式下,GPIO口是无效的, 断开GPIO,防止GPIO口的输入输出对模拟电压造成干扰,AIN模式就是ADC的专属模式
	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);//ADC1,选择通道0,选择序列1,设置采样时间就是55.5个ADCCLK的周期
    /*
    如果你还想在序列列2的位置与入其他的通道,那就复制一下这个代码,把这个序列数改成2,然后指定你想要的通道,比如通道3/通道8/通道10,
    如果还想继续填充菜单,那就再复制,修改序列和通道,这样就可以了
    ADC_RegularChannelConfig(ADC1,ADC_Channel_3,2,ADC_SampleTime_55Cycles5);
    */

//用结构体初始化ADC
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;					//ADC工作模式,配置ADC是工作在独立模式,还是双ADC模式
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;				//数据对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//外部触发转换选择,即触发控制的触发源,外部触发None,就是不使用外部触发,也就是使用内部软件触发的意思,本小节使用使用软件触发,
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;					//连续转换模式,这个可以选择是连续转换还是单次转换
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;						//扫描转换模式,这个可以选择是扫描模式还是非扫描模式
	ADC_InitStructure.ADC_NbrOfChannel = 1;								//通道数目,这个是指定在扫描模式下,总共会用到几个通道,在非扫描的模式下,无论写多少数目,最终都是只有序列1的位置有效。
	ADC_Init(ADC1,&ADC_InitStructure);
//中断和模拟看门狗,你如果需要的话,可以在这里继续配置

//开启ADC电源
	ADC_Cmd(ADC1,ENABLE);

//ADC校准
    /*
    第一步,调用第一个函数,复位校准。void ADC_ResetCalibration(ADC_TypeDef* ADCx);
    第二步,调用第二个函数,等待复位校准完成 FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
    第三步,调用第三个函数,开始校准  void ADC_StartCalibration(ADC_TypeDef* ADCx);
    第四步,调用第四个函数,等待校准完成 FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);
    */
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1)==SET) ;
    //获取的标志位和是否校准完成是怎样的对应关系
    //返回值说明是,ADC复位校准寄存器的状态,SET或RESET. 它获取的就是CR2寄存器里的RSTCAL标志位,该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。
    //软件置该位为1,那硬件就会开始复位校准,当复位校准完成后,该位就会由硬件自动清0,
    //所以在读取这一位的时候,如果它是1,那就需要一直空循环等待
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1)==SET) ;
}

/**
  * @brief  ADC结果读取函数(单次转换非扫描实现多通道转换,软件触发)
  * @param  无
  * @retval 转换之后的结果
  */
uint16_t AD_GetValue(void) //按单次转换,非扫描模式进行
{
    //首先,软件触发转换。然后等待转换完成,也就是等待EOC标志位置1。最后,读取ADC数据寄存器
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);							//软件触发转换的函数
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
    /*
    返回值的标志位SET、RESET和转换是否完成的对应关系是怎样的呢
    手册寄存器描述,状态寄存器里,有EOC转换结束标志位。
    获取的就是这个EOC标志位,硬件在(规则或注入)通道组转换结束时设置,
    这一位由软件清除或由读取ADC_DR时清除.
    一般EOC标志位置1,我们就会来读取数据.
    通道的采样周期是55.5,转换周期是固定的12.5。共68个周期,
    前边配置的ADCCLK是72MHz的6分频,就是12MHz,12MHz进行68个周期,转换才能完成 1/12M*68≈5.6us。
    */
	return ADC_GetConversionValue(ADC1);
}

单通道连续转换,非扫描模式  
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
改为 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
连续转换仅需要在最始触发一次就行,    
所以将 软件触发转换 ADC_SoftwareStartConvCmd(ADC1,ENABLE);改到初始化的最后,
在初始化完成之后,触发一次就行了 这时,内部的ADC就会一次接着一次地、连续不断地 对我们指定的通道0进行转换,转换结果放在数据寄存器里,转换结果放在数据寄存器里 此时数据寄存器会不断地刷新最新的转换结果 所以在获取AD值时,不需要判断标志位了
删除while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);

main.c 主.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"


uint16_t ADValue;
float Voltage;

int main(void)
{
	OLED_Init();
	AD_Init();
	
	OLED_ShowString(1,1,"ADValue:");
	OLED_ShowString(2,1,"Voltage:00.00V");
	
	while (1)
	{
		ADValue = AD_GetValue();
		Voltage = (float)ADValue/4095 * 3.3;				// 整数除以小数会舍弃小数部分

		OLED_ShowNum(1,9,ADValue,4);
		OLED_ShowNum(2,9,Voltage,2);							// 显示整数部分
		OLED_ShowNum(2,12,(uint16_t)(Voltage * 100) % 100,2);	// 显示小数部分
		
		Delay_ms(100);
	}
}

ADC 多通道转换

AD.c

#include "stm32f10x.h"                  // Device header
 
/**
  * @brief  ADC初始化函数(单次转换非扫描实现多通道转换,软件触发,且这里不使用模拟看门狗和中断)
  * @param  无
  * @retval 无
  */
void AD_Init(void)
{
	// 1. RCC开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);	// ADCCLK = 72MHz / 6 = 12MHz
	
	// 2. 配置GPIO
	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);
	
	// 3. 将指定的GPIO端口接入规则组列表中
	/*	这里要在每一次转换前都更改转换列表中要转换的GPIO端口	*/
	
	// 4. 配置ADC
	ADC_InitTypeDef ADC_InitStruct;
	ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;						// ADC模式(独立模式或双ADC模式):独立模式						
	ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;					// ADC数据对齐:右对齐
	ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	// ADC外部触发源选择:不使用外部源触发(这里使用软件触发)
	ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;					// ADC连续转换模式:单次转换
	ADC_InitStruct.ADC_ScanConvMode = DISABLE;							// ADC扫描模式:非扫描
	ADC_InitStruct.ADC_NbrOfChannel = 1;								// 扫描模式下通道的数量
	ADC_Init(ADC1, &ADC_InitStruct);
	
	/*	中断和模拟看门狗在此配置	*/
	
	// 5. 开关控制
	ADC_Cmd(ADC1, ENABLE);
	
	// 6. 对ADC进行校准
	ADC_ResetCalibration(ADC1);								// 复位校准
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);		// 等待复位校准完成
	ADC_StartCalibration(ADC1);								// 开始校准
	while (ADC_GetCalibrationStatus(ADC1) == SET);			// 等待校准完成
}
 
/**
  * @brief  ADC结果读取函数(单次转换非扫描实现多通道转换,软件触发)
  * @param  无
  * @retval 转换之后的结果
  */
uint16_t AD_GetValue(uint8_t ADC_Channel)
{
	ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);	// 把通道作为参数填入序列1中,通道的采样周期是55.5个ADCCLK的周期
	
	// 1. 软件触发开启转换
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	
	// 2. 等待转换完成(获取标志位状态,等待EOC标志位置1)
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);		// 转换未完成则等待(55.5T + 12.5T = 68T,结果大概为5.6us)
	
	// 3. 读取ADC数据寄存器并返回
	return ADC_GetConversionValue(ADC1);	// 读取之后会自动清除EOC标志位
}
 
 

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
 
uint16_t AD0, AD1, AD2, AD3;
 
int main()
{
	OLED_Init();
	AD_Init();
	
	OLED_ShowString(1, 1, "AD0:");
	OLED_ShowString(2, 1, "AD1:");
	OLED_ShowString(3, 1, "AD2:");
	OLED_ShowString(4, 1, "AD3:");
 
	
	while(1)
	{
		AD0 = AD_GetValue(ADC_Channel_0);
		AD1 = AD_GetValue(ADC_Channel_1);
		AD2 = AD_GetValue(ADC_Channel_2);
		AD3 = AD_GetValue(ADC_Channel_3);
		
		OLED_ShowNum(1, 5, AD0, 4);
		OLED_ShowNum(2, 5, AD1, 4);
		OLED_ShowNum(3, 5, AD2, 4);
		OLED_ShowNum(4, 5, AD3, 4);
 
		Delay_ms(100);
	}
}
 

点击数:4

    暂无评论

    发送评论 编辑评论

    
    				
    |´・ω・)ノ
    ヾ(≧∇≦*)ゝ
    (☆ω☆)
    (╯‵□′)╯︵┴─┴
     ̄﹃ ̄
    (/ω\)
    ∠( ᐛ 」∠)_
    (๑•̀ㅁ•́ฅ)
    →_→
    ୧(๑•̀⌄•́๑)૭
    ٩(ˊᗜˋ*)و
    (ノ°ο°)ノ
    (´இ皿இ`)
    ⌇●﹏●⌇
    (ฅ´ω`ฅ)
    (╯°A°)╯︵○○○
    φ( ̄∇ ̄o)
    ヾ(´・ ・`。)ノ"
    ( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
    (ó﹏ò。)
    Σ(っ °Д °;)っ
    ( ,,´・ω・)ノ"(´っω・`。)
    ╮(╯▽╰)╭
    o(*////▽////*)q
    >﹏<
    ( ๑´•ω•) "(ㆆᴗㆆ)
    😂
    😀
    😅
    😊
    🙂
    🙃
    😌
    😍
    😘
    😜
    😝
    😏
    😒
    🙄
    😳
    😡
    😔
    😫
    😱
    😭
    💩
    👻
    🙌
    🖕
    👍
    👫
    👬
    👭
    🌚
    🌝
    🙈
    💊
    😶
    🙏
    🍦
    🍉
    😣
    Source: github.com/k4yt3x/flowerhd
    颜文字
    Emoji
    小恐龙
    花!
    上一篇