TM32之ADC外设(模拟-数字转换器外设)代码部分三:AD转换之多通道转换,手动连续扫描。

1.因为ADC外设使用连续扫描的模式下,在转换模式的多个菜单中(即多个序列的通道),每扫描完成一个通道的转运无法产生单个通道转换结束的标志位。这样我们就无法使用获得AD转换值的函数:ADC_GetConversionValue及时的获得AD的转换结果,就会出现AD转换时各个通道有可能出现数据覆盖的问题。

2.ADC外设进行多通道扫描的时候一般都会用ADC+DMA来转运数据。因为ADC外设在每个通道转换完成后虽然无法产生中断的标志位,但是会触发DMA请求。这也是ADC以来DMA搬用数据的一大特点。

3.本代码可以尝试使用AD缓缓多通道,使用手动连续扫描。可以达到ADC配合DMA的效果。相当于单次转换,非扫描模式,只是每次转换完成后,自动换成下一个通道。代码部分如下:

//模块一:主函数
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.H"
#include"AD.H"

uint16_t ADTS,ADLS,ADRS;
int main(void)
{
AD_Init();
OLED_Init();//初始化OLED;
OLED_ShowString(1,1,"ADTS:");	
OLED_ShowString(2,1,"ADLS:");	
OLED_ShowString(3,1,"ADRS:");
	
while(1)
 {
	//一次启动4次转换
	ADTS=AD_GetValue(ADC_Channel_0);
	ADLS=AD_GetValue(ADC_Channel_1);
	ADRS=AD_GetValue(ADC_Channel_2);
	 
	OLED_ShowNum(1,6,ADTS,4); 
	OLED_ShowNum(2,6,ADLS,4); 
	OLED_ShowNum(3,6,ADRS,4);
	 
	Delay_ms(100);//转换一个通道只有几微秒,每转运一个通道就暂停一次,再换下一个通道转运
 }
}

//模块二 ADC初始化,获取ADC转换的值(子函数中传递ADC的通道)
#include "stm32f10x.h"                  // Device header
#include "Delay.h"

void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); //开启ADC的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启GPIO的时钟	
	RCC_ADCCLKConfig(RCC_PCLK2_Div8); //配置ADCCLK 逐次比较的时钟 72/8=9MHZ
		
	//初始化GPIOA
	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_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
		
	//用结构体配置ADC	
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//ADC的工作模式
	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的电源

	//ADC的校准
	ADC_ResetCalibration(ADC1); //开启复位校准,将给RSRCAL(reset calibration)寄存器置1
	while(ADC_GetResetCalibrationStatus(ADC1)==SET);  //读取复位校准的标志位,用while并等待开启校准完成,如果等于1就一直等待
	ADC_StartCalibration(ADC1);//开始复位校准
	while (ADC_GetCalibrationStatus(ADC1)==SET);//判断是否校准完成

}


/*若手动实现读取AD多通道,传递ADC_RegularChannelConfig的形参
传递到读取AD的形参中去则对应产生我们指定通道的读取结果
相当于单次转换,非扫描模式,只是每次转换完成后,那个通道自动换成下一个通道*/
uint16_t AD_GetValue(uint8_t ADC_Channel) 
{
	//配置ADC的输入通道,转换的模式里面的序列号和采样频率
	ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_28Cycles5); //同时形参向下传递传给实参
	//如果指定其它序列里的通道则复制上面的函数
		
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//触发ADC转换,使ADC开始转换
	while (ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);//等待转换完成,看ADC的EOC寄存器可知,当EOC=0转换未完成,条件为真。
	/*EOC:转换结束位 (End of conversion) 
	判断规则组的标志位,看是否已经转换完成
	该位由硬件在(规则或注入)通道组转换结束时设置,由软件清除或由读取ADC_DR时清除
	0:转换未完成;
	1:转换完成。
	*/
	return ADC_GetConversionValue(ADC1); 
	//获取ADC_DR(DR数据寄存器)的值,并由上面可以知道ECO会被硬件清0,不需要手动清除标志位了
	//同时返回相应实参传给形参指定通道的AD结果
	
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值