江科大--AD单通道&多通道

AD的程序编程步骤如下所示:

第一步,开启RCC时钟,包括ADC和GPIO的时钟。另外这里ADCCLK的分频器,也需要配置一下

第二步,配置GPIO,把需要用的GPIO配置成模拟输入的模式

第三步,选择规则组的输入通道,配置这里的多路开关,把左边的通道接入到右边的规则组列表里。(这个过程就是我们之前说的点菜,把各个通道的菜,列在菜单里)

第四步,就是配置ADC转换器了。在库函数里,是用结构体来配置的,可以配置这一大块电路的参数,包括ADC是单次转换还是连续转换,扫描还是非扫描,有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。

如果需要配置阈值或者检测通道,则会有几个函数用来配置阈值和监测通道。

如果要开启中断,那就在中断输出控制里用ITConfig函数开启对应的中断输出,然后再在NVIC里,配置一下优先级,这样就能触发中断了

那接下来,就是开关控制,调用一下ADC_Cmd函数,开启ADC。

下面在ADC.h库中查看相关库函数的作用:

//用来配置ADCCLK分频器的
//可以对APB2的72Mhz选择不同的分频,输入到ADCCLK
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);

//Delniit恢复初始化配置、Init初始化、Structlnit结构体初始化
void ADC_DeInit(ADC_TypeDef* ADCx);
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);

//ADC Cmd,这个是用于给ADC上电的,也就是PPT这里的开关控制
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);

//DMA Cmd,这个是用于开启DMA输出信号的,如果使用DMA转运数据,那就得调用这个函数
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);

//中断输出控制,用于控制某个中断,能不能通往NVIC
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);

//复位校准、获取复位校准状态、开始校准、获取开始校准状态
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软件开始转换控制,这个就是用于软件触发的函数了
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

//第一个函数是,每隔几个脉冲间断
//第二个函数是,是不是启用间断模式
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

//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);

下面对程序进行编写

AD.C文件注释和程序如下所示:

#include "stm32f10x.h"                  // Device header


void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//6分频--12Mhz
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;  //ADC专属模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//通道采样周期(ADC周期)是55.5,转换周期是固定的12.5==68个周期
	//例如:当ADCCLK=14MHz,采样时间为1.5个ADC周期
	//		TCONV = 1.5 + 12.5 = 14个ADC周期 = 1μs
	
	//规则组通道配置
	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_NbrOfChannel=1;
	ADC_InitStructure.ADC_ScanConvMode=DISABLE;
	ADC_Init(ADC1,&ADC_InitStructure);
	
	ADC_Cmd(ADC1,ENABLE);//开启ADC
	
	
	//校准
	ADC_ResetCalibration(ADC1);//开启复位校准(重置所选ADC校准寄存器)
	//获取复位校准状态(等待复位校准完成),也就是读取这一位
	//如果他是一,那么就一直空循环等待
	//如果变为0,那么说明复位校准完成,跳出等待!
	while (ADC_GetResetCalibrationStatus(ADC1)==SET);
	ADC_StartCalibration(ADC1);//启动校准
	while (ADC_GetCalibrationStatus(ADC1)==SET);
}

uint16_t AD_GetValue(void)
{
	ADC_SoftwareStartConvCmd(ADC1,ENABLE); //启用或禁用所选ADC软件启动转换
	//检查是否设置了指定的ADC标志位,ADC_FLAG_EOC转换结束标志
	while (ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);
	return ADC_GetConversionValue(ADC1); //返回常规通道的最后一次ADCx转换结果数据。
}

main.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:0.00V");
	while (1)
	{
		ADValue=AD_GetValue();
		
		Voltage=(float)ADValue / 4095 * 3.3;//强制类型转换,将0-4096的范围转变为0-3.3
		OLED_ShowNum(1,9,ADValue,4);
		OLED_ShowNum(2,9,Voltage,1);
		OLED_ShowNum(2,11,(uint16_t)(Voltage * 100) % 100,2);//强制类型转换
	}
}
//输出抖动————迟滞比较———设置上阈值和下阈值

下面是关于多通道的程序编写:

由于多通道扫描模式无法手动对数据进行处理(因为每个通道传输完毕,不会单独产生特定的标志位或信号,只有当菜单中的所有通道全部传输完成后才可以出现EOC标志位的变化,此时前面的数据就已经覆盖丢失了),必须借助DMA来避免数据覆盖的问题。

使用单次转换、非扫描模式,在每次触发转换前更换所要触发的通道,之后触发等待读值

uint16_t AD_GetValue(uint8_t ADC_Channel)
{
	//将原本的通道0改为变量参数中的指定通道即可
	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);
}

多通道选择通道0、1、2、3对应于GPIO_Pin_0、1、2、3

总的AD.C和MAIN.C函数如下所示:

#include "stm32f10x.h"                  // Device header


void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//6分频--12Mhz
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;  //ADC专属模式
	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周期)是55.5,转换周期是固定的12.5==68个周期
	//例如:当ADCCLK=14MHz,采样时间为1.5个ADC周期
	//		TCONV = 1.5 + 12.5 = 14个ADC周期 = 1μs

	
	
	//单次转换,非扫描
	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_NbrOfChannel=1;
	ADC_InitStructure.ADC_ScanConvMode=DISABLE;
	ADC_Init(ADC1,&ADC_InitStructure);
	
	ADC_Cmd(ADC1,ENABLE);
	
	
	//校准
	ADC_ResetCalibration(ADC1);//开启复位校准
	while (ADC_GetResetCalibrationStatus(ADC1)==SET);
	//获取复位校准状态(等待复位校准完成),也就是读取这一位
	//如果他是一,那么就一直空循环等待
	//如果变为0,那么说明复位校准完成,跳出等待!
	ADC_StartCalibration(ADC1);//启动校准
	while (ADC_GetCalibrationStatus(ADC1)==SET);
}

uint16_t AD_GetValue(uint8_t ADC_Channel)
{
	//将原本的通道0改为变量参数中的指定通道即可
	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);
}

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

uint16_t AD0,AD1,AD2,AD3;


int main(void)
{
	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(1000);
	}
}
//输出抖动————迟滞比较———设置上阈值和下阈值

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值