STM32的ADC简介_DMA方式的程序设计与实现.doc

上传人:白大夫 文档编号:3273776 上传时间:2019-08-07 格式:DOC 页数:6 大小:27.50KB
返回 下载 相关 举报
STM32的ADC简介_DMA方式的程序设计与实现.doc_第1页
第1页 / 共6页
亲,该文档总共6页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《STM32的ADC简介_DMA方式的程序设计与实现.doc》由会员分享,可在线阅读,更多相关《STM32的ADC简介_DMA方式的程序设计与实现.doc(6页珍藏版)》请在三一文库上搜索。

1、STM32的ADC简介_DMA方式的程序设计与实现ADC简介:ADC(Analog-to-Digital Converter,模/ 数转换器)。也就是将模拟信号转换为数字信号进行处理,在存储或传输时,模数转换器几乎必不可少。STM32在片上集成的ADC外设非常强大,我使用的奋斗开发板是STM32F103VET6,属于增强型的CPU,它有18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次,连续,扫描或间断模式执行,ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。我们以ADC规则通道转换过程来分析,如上图,所有的器件都是围绕中间的模拟至数字转换器部分展开的。它的左

2、端VREF+,VREF- 等ADC参考电压,ADCx_IN0 ADCx_IN15为ADC的输入信号通道,即某些GPIO引脚。输入信号经过这些通道被送到ADC器件,ADC器件需要收到触发信号才开始进行转换,如EXTI外部触发,定时器触发,也可以使用软件触发。ADC部件接受到触发信号后,在ADCCLK时钟的驱动下对输入通道的信号进行采样,并进行模数转换,其中ADCCLK是来自ADC预分频器。ADC部件转换后的数值被保存到一个16位的规则通道数据寄存器(或注入通道数据寄存器)中,我们可以通过CPU指令或DMA把它读到内存(变量),模数转换之后,可以出发DMA请求或者触发ADC转换结束事件,如果配置了

3、模拟看门狗,并且采集的电压大于阈值,会触发看门狗中断。其实对于ADC采样,软件编程主要就是ADC的配置,当然我是基于DMA方式的,所以DMA的配置也是关键!话不多说看代码!主函数:main.c#include printf.h #include adc.h #include stm32f10x.h extern _IO uint16_t ADC_ConvertedValue; float ADC_ConvertedValueLocal; void Delay(_IO uint32_t nCount) for(;nCount !=0;nCount-); int main(void) printf

4、_init(); adc_init(); printf(*This is a ADC test*n); while(1) ADC_ConvertedValueLocal =(float) ADC_ConvertedValue/4096*3.3; printf(The current AD value =0x%04Xn,ADC_ConvertedValue); printf(The current AD value =%f Vn,ADC_ConvertedValueLocal); Delay(0xffffee); return 0; 注意ADC_ConvertedValueLocal保存了由转换

5、值计算出来的电压值,计算公式是:实际电压值=ADC转换值 x LSB ,这里由于我的板子VREF+接的参考电压为3.3V,所以LSB=3.3/4096,STM32的ADC的精度为12位。ADC与DMA配置:adc.c#include adc.h volaTIle uint16_t ADC_ConvertedValue; void adc_init() GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; DMA_InitTypeDef DMA_InitStructure; RCC_AHBPeriphClo

6、ckCmd(RCC_AHBPeriph_DMA1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOCRCC_APB2Periph_ADC1,ENABLE); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN; GPIO_Init(GPIOC,GPIO_InitStructure); DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr = ADC

7、1_DR_Address;/ADC地址 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue; /内存地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; /方向(从外设到内存) DMA_InitStructure.DMA_BufferSize = 1; /传输内容的大小 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; /外设地址固定 DMA_InitStructure.DMA_

8、MemoryInc = DMA_MemoryInc_Disable; /内存地址固定 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord ; /外设数据单位 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord ; /内存数据单位 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular ; /DMA模式:循环传输 DMA_InitStructure.DMA_Priority = D

9、MA_Priority_High ; /优先级:高 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; /禁止内存到内存的传输 DMA_Init(DMA1_Channel1, DMA_InitStructure); /配置DMA1的4通道 DMA_Cmd(DMA1_Channel1,ENABLE); ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; /独立ADC模式 ADC_InitStructure.ADC_ScanConvMode = DISABLE; /禁止扫描方式 ADC_InitStructur

10、e.ADC_ConTInuousConvMode = ENABLE;/开启连续转换模式 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; /不使用外部触发转换 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; /采集数据右对齐 ADC_InitStructure.ADC_NbrOfChannel = 1; /要转换的通道数目 ADC_Init(ADC1, ADC_InitStructure); RCC_ADCCLKConfig(RCC_PCLK2_D

11、iv8);/配置ADC时钟,为PCLK2的8分频,即9Hz ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTIme_55Cycles5);/配置ADC1通道11为55.5个采样周期 ADC_DMACmd(ADC1,ENABLE); ADC_Cmd(ADC1,ENABLE); ADC_ResetCalibration(ADC1);/复位校准寄存器 while(ADC_GetResetCalibrationStatus(ADC1);/等待校准寄存器复位完成 ADC_StartCalibration(ADC1);/ADC校准

12、while(ADC_GetCalibrationStatus(ADC1);/等待校准完成 ADC_SoftwareStartConvCmd(ADC1, ENABLE);/由于没有采用外部触发,所以使用软件触发ADC转换 ADC配置还是比较简单的,毕竟只配置了单通道,还是分析一下吧!这里我是把ADC1的通道11使用的GPIO引脚PC1配置成模拟输入模式,在作为ADC的输入时,必须使用模拟输入。对于ADC通道,每个ADC通道对应一个GPIO引脚端口,GPIO的引脚在设为模拟输入模式后可用于模拟电压的输入。STM32F103VET6有三个ADC,这三个ADC公用16个外部通道。DMA的整体配置为:使

13、用DMA1的通道1,数据从ADC外设的数据寄存器(ADC1_DR_Address)转移到内存(ADC_ConvertedValue变量),内存外设地址都固定,每次传输的大小为半字(16位),使用DMA循环传输模式。DMA传输的外设地址,也就是ADC1的地址为0x40012400+0x4c,这个地址可查STM32 datasheet获得,如图;这里ADC预分频器的输入为高速外设时钟(PCLK2),使用RCC_ADCCLKConfig()库函数来设置ADC预分频的分频值,PCLK2常用时钟为72MHz,而ADCCLK必须小于14MHz,所以这里ADCCLK为PCLK2的6分频,即12MHz,而我的

14、程序中只是随便设为8分频,9MHz,若希望ADC以最高频率14MHz运行,可以把PCLK2设置为56MHz,然后再4分频得到ACCLK。ADC的转换时间不仅与ADC的时钟有关,还与采样周期有关。每个ADC通道可以设置为不同的采样周期。STM32的ADC采样时间计算公式为:T=采样周期+12.5个周期公式中的采样周期就是函数中配置的ADC_SampleTime,而后边加上的12.5个周期为固定值,则ADC1通道11的转换时间为T=(55.5+12.5) x 1/9=7.56us。补充:在adc.c文件中定义了ADC_ConvertedValue变量,要注意这个变量是由关键字volatile修饰的

15、,volatile的作用是让编译器不要去优化这个变量,这样每次用到这个变量时都要回到相应变量的内存中去取值,而如果不使用volatile进行修饰的话,ADC_ConvertedValue变量在被访问的时候可能会直接从CPU的寄存器中取出(因为之前该变量被访问过,也就是说之前就从内存中取出ADC_ConvertedValue的值保存到某个CPU寄存器中),之所以直接从寄存器中去取值而不去内存中取值,这是编译器优化代码的结果(访问CPU寄存器比访问内存快得多)。这里的CPU寄存器指R0,R1等CPU通用寄存器,用于CPU运算及暂存数据,不是指外设中的寄存器。因为ADC_ConvertedValue这个变量值随时都会被DMA控制器改变的,所以用volatile来修饰它,确保每次读取到的都是实时ADC转换值。adc.h:#ifndef _adc_H #define _adc_H #include stm32f10x.h #include stm32f10x_dma.h #include stm32f10x_adc.h #define ADC1_DR_Address (uint32_t)0x4001244c); void adc_init(void); #endif效果图:由于我的开发板没有滑动变阻器,所以我就将电压的输入端接入通用IO口的3V引脚。如图:

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1