光电传感单元(STM32学习之ADC+DMA)

目录

1.1  传感器的选择

1.2  传感单元的设计

1.3  原理介绍&代码浅析

1.3.1  ADC简介

1.3.2  ADC的触发

1.3.3  STM32的ADC详细原理

1.3.4  ADC的转换模式

1.3.5  DMA简介

1.3.6  代码浅析


1.1  传感器的选择

        整个跟踪系统中,传感器的选择和设计是最重要的部分,传感器部分选择设计的好坏直接影响跟踪器的跟踪效果。

        对于传感器的选择,可以使用光敏器件将光信号转化为电信号供控制器分析处理;也可以直接使用图像传感器对太阳拍摄来分析太阳的实时位置。由于太阳移动缓慢且不会出现短时间内大幅度光强变化情况,考虑到价格因素,综合分析后决定采用光敏电阻作为感光元件进行设计。

          光敏电阻是用硫化镉或硒化镉等半导体材料制成的特殊电阻器,其工作原理是基于内光电效应。光照愈强,阻值就愈低,随着光照强度的升高,电阻值迅速降低(即光照越强,ADC所采集的数值越低)。亮电阻值可小至1KΩ以下。光敏电阻对光线十分敏感,其在无光照时,呈高阻状态,暗电阻一般可达1.5MΩ。光敏电阻的特殊性能,随着科技的发展将得到极其广泛应用。本装置采用的是GL5516型号的光敏电阻,如图1所示。

光电传感单元(STM32学习之ADC+DMA)_第1张图片 图1    GL5516 光敏电阻题

1.2  传感单元的设计

        由于单晶硅柔性太阳能板的特性,在本系统的设计中,传感单元垂直于太阳光的方向可允许有±5°以内的误差,根据此特点设计传感单元。

        物理结构设计:拟使用四个型号相同的光敏电阻作为基本组件,按矩形的形状进行分布排列。将光伏板与传感器固定到同一个平面,使用时,比较四个光敏电阻接收到的光强信号,哪个信号强就控制电机往该方向转动。

        电路设计:将光敏电阻的正极接入电源正极,与10K电阻串联后再与GND相连。在光敏电阻和保护电阻间引出模拟输入IO口,以供单片机进行ADC采集。在该装置中,光敏电阻用来实时检测太阳的光照强度,串联的电阻起到了保护和分压的功能。

        将以上的物理结构设计和电路设计相结合,即为本系统所采用的光电传感单元——基于挡板的四象限光敏电阻探测器,如图2所示。

图2-1    基于挡板的四象限光敏电阻探测器(正面)

图2-2    基于挡板的四象限光敏电阻探测器(背面)

1.3  原理介绍&代码浅析

1.3.1  ADC简介

        ADC(Analog-Digital Converter)模拟-数字转换器,ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。通过ADC可以对高电平和低电平之间的任意电压进行量化,最终用一个变量来表示。更通俗来说,ADC其实就是一个电压表,把引脚的电压值测出来,放在一个变量里。

        12位逐次逼近型ADC,1us转换时间。(转换时间一般不需要处理,一般AD转换都很快,如果不需要非常高速的转换频率,那转换时间就可以忽略)

        输入电压范围:0~3.3V,转换结果范围:0~4095(2的12次方-1)。

        18个输入通道,可测量16个外部和2个内部信号源。

        规则组和注入组两个转换单元。

        普通的AD转换流程是,启动一次转换、读一次值,以此往复循环;STM32则可以列一个组,一次性启动一个组,连续转换多个值。并且有两个组,一个是用于常规使用的规则组,一个是用于突发事件的注入组。

        规则组虽然可以同时转换16个通道,但数据寄存器只能存一个结果,如果不想之前的结果被覆盖,那在转换完成之后,就要尽快把结果拿走。

        注入组一次性最多可以转换4个通道,并且其数据寄存器有4个,是可以同时存储4个数据的,不用担心被覆盖的问题。

        一般情况下,使用规则组就完全足够了。但在使用规则组时,往往配合DMA进行使用,这样就不需要担心数据被覆盖的问题了。

        模拟看门狗自动监测输入电压范围。

        可以设定好上阈值和下阈值,达到即申请中断,可免去手动if来读值判断

        顺便对DAC的一些补充:

        有ADC自然也有DAC,目前DAC应用最广泛熟知的为PWM,PWM即为DAC的功能(将数字变量转化为模拟电压)。同时,PWM只有完全导通和完全断开两种状态,在这两种状态上都没有功率损耗,因此在直流电机调速这种大功率的应用场景,使用PWM等效模拟量,是比DAC更好的选择,且PWM电路更加简单、常用。目前DAC的应用主要是在波形生成这些领域,比如信号发生器、音频解码芯片等。

1.3.2  ADC的触发

        对于STM32的ADC,触发ADC开始转换的信号有两种,一种是软件触发,即在程序里手动调用一条代码;另一种是硬件触发,即特定的触发源,这些触发源主要来自定时器,有定时器的各个通道,还有TRGO定时器主模式的输出。把TIM3定时为1ms,并且把TIM3的更新事件选择为TRGO输出,然后在ADC这里,选择开始触发信号为TIM3的TRGO,这样TIM3的更新事件就能通过硬件自动触发ADC转换了。

        ADCCLK<最大14MHz,所以ADC预分频器只能选择6分频(12M)或者8分频(9M)。

1.3.3  STM32的ADC详细原理

        要弄清STM32的ADC,具体看江协科技的STM32教程中 P21 [7-1]ADC模数转换器https://www.bilibili.com/video/BV1th411z7sn?p=21&vd_source=b4d125df2ebf1ab26fbed06ba725ac39的讲解。讲得太清晰太棒了!!

        ADC的输入通道:

光电传感单元(STM32学习之ADC+DMA)_第2张图片

1.3.4  ADC的转换模式

        单次转换,非扫描模式

        触发一次,转换一次,转换完成后产生标志位

        需要再次触发才能再次进行转换

        连续转换,非扫描模式

        触发一次,开始转换,每次转换完成后不需再次触发即可再次进行转换

        转换完成一次产生一次标志位,若需要读取数据,直接在数据寄存器里读取即可

        单次转换,扫描模式

        触发一次,完成一系列通道的转换后才产生标志位。(初始化时,还应设置 通道数目)

        需要再次触发才能再次进行一轮转换

        扫描模式下,为防止数据被覆盖,就需要用DMA及时将数据挪走

        连续转换,扫描模式

        即在“单次转换,扫描模式”模式下变为 每次转换完成后不需再次触发即可再次进行转换,同样的,为防止数据被覆盖,就需要用DMA及时将数据挪走。

在扫描模式下,还有一个“间断模式”,作用是,在扫描过程中,每隔几个转换,就暂停一次,需要再次触发才能继续。

         数据对齐

       由于寄存器是16位的,而ADC所采集的数据最大为12位的,因此需要进行数据对齐。

        一般用右对齐,因为左对齐相当于左移4位,二进制中左移4位相当于×2,得到的数据会比实际大16倍。

1.3.5  DMA简介

        DMA(Direct Memory Access)直接存储器存取,它主要是用来协助CPU,完成数据转运的工作。

        DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源。

        12个独立可配置的通道:DMA1(7个通道),DMA2(5个通道)

        每个通道都支持软件触发和特定的硬件触发。

        更多对STM32的DMA的详细讲解,移步到江协科技的STM32教程中 P23 [8-1]DMA直接存储器存取https://www.bilibili.com/video/BV1th411z7sn?p=23&vd_source=b4d125df2ebf1ab26fbed06ba725ac39

1.3.6  代码浅析

        本系统采用了ADC连续扫描模式+DMA来实现对4个光敏电阻进行实时的数据采集。

        每一句代码后面都有注释解释清楚这一步是干嘛的。

uint16_t AD_Value[4];

void My_ADC_Init(void)
{ 	
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF | RCC_APB2Periph_ADC3 , ENABLE );			//使能GPIOF时钟和ADC3通道时钟
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);										//使能 DMA2 时钟
	
	//用于配置ADCCLK分频器
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);														//设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M	
 	    
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_9 | GPIO_Pin_8 | GPIO_Pin_7;		//PF7、8、9、10 作为模拟通道输入引脚  
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;											//模拟输入 模式
	GPIO_Init(GPIOF, &GPIO_InitStructure);	

	ADC_DeInit(ADC3);																		//复位ADC3,将外设 ADC3 的全部寄存器重设为缺省值
	DMA_DeInit(DMA2_Channel5);
	
	ADC_RegularChannelConfig(ADC3, ADC_Channel_5, 1, ADC_SampleTime_55Cycles5 );			//选择规则组的输入通道
	ADC_RegularChannelConfig(ADC3, ADC_Channel_6, 2, ADC_SampleTime_55Cycles5 );
	ADC_RegularChannelConfig(ADC3, ADC_Channel_7, 3, ADC_SampleTime_55Cycles5 );
	ADC_RegularChannelConfig(ADC3, ADC_Channel_8, 4, ADC_SampleTime_55Cycles5 );

	ADC_InitTypeDef ADC_InitStructure; 
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;										//ADC工作模式:ADC3工作在独立模式
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;											//模数转换工作在扫描模式
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;										//模数转换工作在连续转换模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;						//转换由软件而不是外部触发启动
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;									//ADC数据右对齐
	ADC_InitStructure.ADC_NbrOfChannel = 4;													//顺序进行规则转换的ADC通道的数目
	ADC_Init(ADC3, &ADC_InitStructure);														//根据ADC_InitStruct中指定的参数初始化外设ADC3的寄存器   

	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC3->DR;							//DMA 外设 ADC 基地址,为ADC_DR的地址0x4001244C
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;								//DMA 内存基地址,可理解为转存的目的地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;										//数据传输方向:外设到内存,即外设站点是源
	DMA_InitStructure.DMA_BufferSize = 4;													//传输数量,因为4个ADC通道,所以传输4次
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;						//外设地址不变(不自增),始终转运同一个位置的数据
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;									//内存地址寄存器递增
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;				//数据宽度为 16 位,半字
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;						//数据宽度为 16 位,半字
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;											//工作在循环模式
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;									//DM 通道拥有中优先级
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;											//非内存到内存传输,不使用软件触发;这里需要硬件触发,触发源为ADC3。
	DMA_Init(DMA2_Channel5, &DMA_InitStructure);											//初始化 DMA 的通道,这里若使用硬件触发,则需要注意所使用的硬件源对应哪个通道

	DMA_Cmd(DMA2_Channel5,ENABLE);															//使能指定的DMA2_Channel5
	ADC_DMACmd(ADC3,ENABLE);																//使能ADC到DMA的输出	
	ADC_Cmd(ADC3, ENABLE);																	//使能指定的ADC3
	
	ADC_ResetCalibration(ADC3);																//使能复位校准  	 
	while(ADC_GetResetCalibrationStatus(ADC3));												//等待复位校准结束
	ADC_StartCalibration(ADC3);																//开启AD校准
	while(ADC_GetCalibrationStatus(ADC3));													//等待校准结束
 
	ADC_SoftwareStartConvCmd(ADC3, ENABLE);													//使能指定的ADC3的软件转换启动功能(连续转换模式只需触发一次即可)

}				  

        整个过程仅需完成初始化,不需要程序手动进行操作,即可随时读取最新的ADC所采集的数据,节省软件资源,实现硬件自动化,这是STM32的一大特色之一。外设之间互相连接,互相合作,在完成简单且繁琐的工作时,不需要CPU统一调度,外设之间就会相互配合自动完成这些繁琐的工作。

你可能感兴趣的:(基于物联网的智慧光伏跟踪系统,STM32学习,stm32,单片机)