赞
踩
本人是大一的学生,学习了一段时间的stm32,此系列博客为个人的学习笔记,方便个人复习,如有错误或问题,非常非常欢迎大家来大力指正。
HAL库的知识参考阿熊话太多的教程,标准库参考江科大的教材。本视频的部分图也来自阿熊和江科大视频中的图片,代码也是参考他们的大家如果要学习强烈推荐他们的视频
模数转换器,顾名思义是将模拟电压(不断变化的电压值,转化为数字变量)abc为电压转化为数值,dac为数字转化为电压(是dc调光的原理吗???)
有几个属性:分辨率一般是用几位AD值来说明,位数越高量化结果越精细
转换时间,从开始到转换完成的时间
输入电压范围和输出结果范围
还有模拟看门狗检测电压范围
逐次逼近型ADC:
这个ADC原理图供参考,原理和stm32的一样
in0-7是输入通道(stm32有18个),地址锁存和译码是是输入通道和锁存信号去选择哪个通道。DAC通过数字转换电压输出一个参考电压,与输入的电压进行比较。DAC调整电压到和输入电压近似相等,输入电压就是那个数值(使用二分法进行比较,位数多少次,比较多少次)
ADC的基本流程:注入组是一次去采集4个,然后4个结果可以同时获取。规则组是可以一次去采集16个
ADC引脚与通道的关系
ADC的4种模式,了解一下
因为寄存器16位,数据12位有数据对齐,用右对齐
标准库的实现:
还是一样开启GPIO和ADC的RCC
然后配置ADC的时钟,进行分频
定义GPIO的属性
定义ADC的通道
定义ADC的属性
对ADC进行校准
- void adcinit()
- {
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
-
- RCC_ADCCLKConfig(RCC_PCLK2_Div6);//开启分频数,adc最高的是12m所以是6分频
-
- GPIO_InitTypeDef GPIO_Initstructure;
- GPIO_Initstructure.GPIO_Pin=GPIO_Pin_0;
- GPIO_Initstructure.GPIO_Speed=GPIO_Speed_50MHz;
- GPIO_Initstructure.GPIO_Mode=GPIO_Mode_AIN;//模拟输入
- GPIO_Init(GPIOA,&GPIO_Initstructure);
- //规则组输入通道
- ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//Rank是规则组序列器的次序,sample time是采样时间
- // ADC_RegularChannelConfig(ADC1,ADC_Channel_0,2,ADC_SampleTime_55Cycles5);想要多通道采样就这样加就可以了
- ADC_InitTypeDef ADC_Initstructure;
- ADC_Initstructure.ADC_ContinuousConvMode=DISABLE;//连续模式开启
- ADC_Initstructure.ADC_Mode=ADC_Mode_Independent; //配置是单adc还是双adc
- ADC_Initstructure.ADC_DataAlign=ADC_DataAlign_Right;//数据对其模式
- ADC_Initstructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//不使用外部触发,使用内部
- ADC_Initstructure.ADC_ScanConvMode=DISABLE;//扫描模式
- ADC_Initstructure.ADC_NbrOfChannel=1;//通道数目
- ADC_Init(ADC1,&ADC_Initstructure);
- ADC_Cmd(ADC1,ENABLE);
- //校准步骤
- ADC_ResetCalibration(ADC1);//复位校准置1
- while(ADC_GetResetCalibrationStatus(ADC1)==SET);//等待校准完成,硬件复位0
- ADC_StartCalibration(ADC1);//开启校准
- while(ADC_GetCalibrationStatus(ADC1)==SET);//等待校准完成
- }
获取ADC的寄存器数值
- uint16_t ADC_GET(void)//软件触发转换——转换完成等待ECO置1——读取数据寄存器
- {
- ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发转换
- while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);//转换完成等待ECO置1,自动清除
- //等待时间15行,定义了55.5+固定转换周期12.5,68周期,第7行6分频12mhz,时间计算1/12m*68
- return ADC_GetConversionValue(ADC1);
- }
这样ADC就定义完成了
用DMA实现多通道的ADC
根据江科大的图进行配置
- //memory是存储器,peripheralinc是初始
- ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //规则组序列1的位置,配置为通道0
- ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5); //规则组序列2的位置,配置为通道1
- ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5); //规则组序列3的位置,配置为通道2
- ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5); //规则组序列4的位置,配置为通道3
-
- /*ADC初始化*/
- ADC_InitTypeDef ADC_InitStructure; //定义结构体变量
- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,选择独立模式,即单独使用ADC1
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,选择右对齐
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发,使用软件触发,不需要外部触发
- ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续转换,使能,每转换一次规则组序列后立刻开始下一次转换
- ADC_InitStructure.ADC_ScanConvMode = ENABLE; //扫描模式,使能,扫描规则组的序列,扫描数量由ADC_NbrOfChannel确定
- ADC_InitStructure.ADC_NbrOfChannel = 4; //通道数,为4,扫描规则组的前4个通道
- ADC_Init(ADC1, &ADC_InitStructure); //将结构体变量交给ADC_Init,配置ADC1
-
- /*DMA初始化*/
- DMA_InitTypeDef DMA_InitStructure; //定义结构体变量
- DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; //外设基地址,给定形参AddrA
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据宽度,选择半字,对应16为的ADC数据寄存器
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址自增,选择失能,始终以ADC数据寄存器为源
- DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value; //存储器基地址,给定存放AD转换结果的全局数组AD_Value
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //存储器数据宽度,选择半字,与源数据宽度对应
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器地址自增,选择使能,每次转运后,数组移到下一个位置
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,选择由外设到存储器,ADC数据寄存器转到数组
- DMA_InitStructure.DMA_BufferSize = 4; //转运的数据大小(转运次数),与ADC通道数一致
- DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //模式,选择循环模式,与ADC的连续转换一致
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //存储器到存储器,选择失能,数据由ADC外设触发转运到存储器
- DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级,选择中等
- DMA_Init(DMA1_Channel1, &DMA_InitStructure); //将结构体变量交给DMA_Init,配置DMA1的通道1
-
- /*DMA和ADC使能*/
- DMA_Cmd(DMA1_Channel1, ENABLE); //DMA1的通道1使能
- ADC_DMACmd(ADC1, ENABLE); //ADC1触发DMA1的信号使能
- ADC_Cmd(ADC1, ENABLE); //ADC1使能
-
- /*ADC校准*/
- ADC_ResetCalibration(ADC1); //固定流程,内部有电路会自动执行校准
- while (ADC_GetResetCalibrationStatus(ADC1) == SET);
- ADC_StartCalibration(ADC1);
- while (ADC_GetCalibrationStatus(ADC1) == SET);
-
- /*ADC触发*/
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发ADC开始工作,由于ADC处于连续转换模式,故触发一次后ADC就可以一直连续不断地工作
先开多几个通道
初始化ADC
初始化DMA
开启各个开关
校准ADC
然后AD_Value就被数值了ADC的数值
HAL库的实现
根据标准库的步骤定义
开启RCC
开启ADC
这些选项也是和标准库的定义是一样的
先开启adc的校准
- HAL_ADCEx_Calibration_Start(&hadc1);//adc的校准
- HAL_ADCEx_Calibration_Start(&hadc2);
- HAL_ADC_Start(&hadc1);//软件开启adc
- HAL_ADC_PollForConversion(&hadc1,HAL_MAX_DELAY);//轮询等待ADC转换完成
- DAT[0]=HAL_ADC_GetValue(&hadc1);//DAT获取adc的值
- HAL_ADC_Stop(&hadc1);//关闭ADC
-
- // HAL_ADC_Start(&hadc2);//软件开启adc
- // HAL_ADC_PollForConversion(&hadc2,HAL_MAX_DELAY);//轮询等待ADC转换完成
- // DAT[0]=HAL_ADC_GetValue(&hadc2);//DAT获取adc的值
- // HAL_ADC_Stop(&hadc2);//关闭ADC
-
这样使用ADC,获取adc的值,这样的方法是两个ADC获取两个输入的值
用这种方法可以输出电压值
- sprintf(get,"adc:%f",DAT[0]/4095*3.3);
- HAL_UART_Transmit(&huart1,(uint8_t*)get,strlen(get),100);
- HAL_Delay(1000);
这种方法是一个ADC获取两个通道的值
- for(i=0;i<2;i++)
- {
- HAL_ADC_Start(&hadc1);//软件开启adc
- HAL_ADC_PollForConversion(&hadc1,HAL_MAX_DELAY);//轮询等待ADC转换完成
- DAT[i]=HAL_ADC_GetValue(&hadc1);//DAT获取adc的值
-
- }
- HAL_ADC_Stop(&hadc1);//关闭ADC
-
- sprintf(get1,"adc1:%f",DAT[0]/4095*3.3);
- sprintf(get2,"adc2:%f",DAT[1]/4095*3.3);
- HAL_UART_Transmit(&huart1,(uint8_t*)get1,strlen(get1),100);
- HAL_UART_Transmit(&huart1,(uint8_t*)get2,strlen(get2),100);
- HAL_Delay(1000);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。