当前位置:   article > 正文

stm32标准库和HAL库的对比学习8.《学习adc模数转换器和DMA》

stm32标准库和HAL库的对比学习8.《学习adc模数转换器和DMA》

        本人是大一的学生,学习了一段时间的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进行校准

  1. void adcinit()
  2. {
  3. RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  5. RCC_ADCCLKConfig(RCC_PCLK2_Div6);//开启分频数,adc最高的是12m所以是6分频
  6. GPIO_InitTypeDef GPIO_Initstructure;
  7. GPIO_Initstructure.GPIO_Pin=GPIO_Pin_0;
  8. GPIO_Initstructure.GPIO_Speed=GPIO_Speed_50MHz;
  9. GPIO_Initstructure.GPIO_Mode=GPIO_Mode_AIN;//模拟输入
  10. GPIO_Init(GPIOA,&GPIO_Initstructure);
  11. //规则组输入通道
  12. ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//Rank是规则组序列器的次序,sample time是采样时间
  13. // ADC_RegularChannelConfig(ADC1,ADC_Channel_0,2,ADC_SampleTime_55Cycles5);想要多通道采样就这样加就可以了
  14. ADC_InitTypeDef ADC_Initstructure;
  15. ADC_Initstructure.ADC_ContinuousConvMode=DISABLE;//连续模式开启
  16. ADC_Initstructure.ADC_Mode=ADC_Mode_Independent; //配置是单adc还是双adc
  17. ADC_Initstructure.ADC_DataAlign=ADC_DataAlign_Right;//数据对其模式
  18. ADC_Initstructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//不使用外部触发,使用内部
  19. ADC_Initstructure.ADC_ScanConvMode=DISABLE;//扫描模式
  20. ADC_Initstructure.ADC_NbrOfChannel=1;//通道数目
  21. ADC_Init(ADC1,&ADC_Initstructure);
  22. ADC_Cmd(ADC1,ENABLE);
  23. //校准步骤
  24. ADC_ResetCalibration(ADC1);//复位校准置1
  25. while(ADC_GetResetCalibrationStatus(ADC1)==SET);//等待校准完成,硬件复位0
  26. ADC_StartCalibration(ADC1);//开启校准
  27. while(ADC_GetCalibrationStatus(ADC1)==SET);//等待校准完成
  28. }

获取ADC的寄存器数值

  1. uint16_t ADC_GET(void)//软件触发转换——转换完成等待ECO置1——读取数据寄存器
  2. {
  3. ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发转换
  4. while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);//转换完成等待ECO置1,自动清除
  5. //等待时间15行,定义了55.5+固定转换周期12.5,68周期,第7行6分频12mhz,时间计算1/12m*68
  6. return ADC_GetConversionValue(ADC1);
  7. }

这样ADC就定义完成了

用DMA实现多通道的ADC

根据江科大的图进行配置

  1. //memory是存储器,peripheralinc是初始
  2. ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //规则组序列1的位置,配置为通道0
  3. ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5); //规则组序列2的位置,配置为通道1
  4. ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5); //规则组序列3的位置,配置为通道2
  5. ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5); //规则组序列4的位置,配置为通道3
  6. /*ADC初始化*/
  7. ADC_InitTypeDef ADC_InitStructure; //定义结构体变量
  8. ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,选择独立模式,即单独使用ADC1
  9. ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,选择右对齐
  10. ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发,使用软件触发,不需要外部触发
  11. ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续转换,使能,每转换一次规则组序列后立刻开始下一次转换
  12. ADC_InitStructure.ADC_ScanConvMode = ENABLE; //扫描模式,使能,扫描规则组的序列,扫描数量由ADC_NbrOfChannel确定
  13. ADC_InitStructure.ADC_NbrOfChannel = 4; //通道数,为4,扫描规则组的前4个通道
  14. ADC_Init(ADC1, &ADC_InitStructure); //将结构体变量交给ADC_Init,配置ADC1
  15. /*DMA初始化*/
  16. DMA_InitTypeDef DMA_InitStructure; //定义结构体变量
  17. DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; //外设基地址,给定形参AddrA
  18. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据宽度,选择半字,对应16为的ADC数据寄存器
  19. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址自增,选择失能,始终以ADC数据寄存器为源
  20. DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value; //存储器基地址,给定存放AD转换结果的全局数组AD_Value
  21. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //存储器数据宽度,选择半字,与源数据宽度对应
  22. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器地址自增,选择使能,每次转运后,数组移到下一个位置
  23. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,选择由外设到存储器,ADC数据寄存器转到数组
  24. DMA_InitStructure.DMA_BufferSize = 4; //转运的数据大小(转运次数),与ADC通道数一致
  25. DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //模式,选择循环模式,与ADC的连续转换一致
  26. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //存储器到存储器,选择失能,数据由ADC外设触发转运到存储器
  27. DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级,选择中等
  28. DMA_Init(DMA1_Channel1, &DMA_InitStructure); //将结构体变量交给DMA_Init,配置DMA1的通道1
  29. /*DMA和ADC使能*/
  30. DMA_Cmd(DMA1_Channel1, ENABLE); //DMA1的通道1使能
  31. ADC_DMACmd(ADC1, ENABLE); //ADC1触发DMA1的信号使能
  32. ADC_Cmd(ADC1, ENABLE); //ADC1使能
  33. /*ADC校准*/
  34. ADC_ResetCalibration(ADC1); //固定流程,内部有电路会自动执行校准
  35. while (ADC_GetResetCalibrationStatus(ADC1) == SET);
  36. ADC_StartCalibration(ADC1);
  37. while (ADC_GetCalibrationStatus(ADC1) == SET);
  38. /*ADC触发*/
  39. ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发ADC开始工作,由于ADC处于连续转换模式,故触发一次后ADC就可以一直连续不断地工作

 先开多几个通道

初始化ADC

初始化DMA

开启各个开关

校准ADC

然后AD_Value就被数值了ADC的数值

HAL库的实现

根据标准库的步骤定义

开启RCC

开启ADC

这些选项也是和标准库的定义是一样的

先开启adc的校准

  1. HAL_ADCEx_Calibration_Start(&hadc1);//adc的校准
  2. HAL_ADCEx_Calibration_Start(&hadc2);
  1. HAL_ADC_Start(&hadc1);//软件开启adc
  2. HAL_ADC_PollForConversion(&hadc1,HAL_MAX_DELAY);//轮询等待ADC转换完成
  3. DAT[0]=HAL_ADC_GetValue(&hadc1);//DAT获取adc的值
  4. HAL_ADC_Stop(&hadc1);//关闭ADC
  5. // HAL_ADC_Start(&hadc2);//软件开启adc
  6. // HAL_ADC_PollForConversion(&hadc2,HAL_MAX_DELAY);//轮询等待ADC转换完成
  7. // DAT[0]=HAL_ADC_GetValue(&hadc2);//DAT获取adc的值
  8. // HAL_ADC_Stop(&hadc2);//关闭ADC

这样使用ADC,获取adc的值,这样的方法是两个ADC获取两个输入的值

用这种方法可以输出电压值

  1. sprintf(get,"adc:%f",DAT[0]/4095*3.3);
  2. HAL_UART_Transmit(&huart1,(uint8_t*)get,strlen(get),100);
  3. HAL_Delay(1000);

这种方法是一个ADC获取两个通道的值

  1. for(i=0;i<2;i++)
  2. {
  3. HAL_ADC_Start(&hadc1);//软件开启adc
  4. HAL_ADC_PollForConversion(&hadc1,HAL_MAX_DELAY);//轮询等待ADC转换完成
  5. DAT[i]=HAL_ADC_GetValue(&hadc1);//DAT获取adc的值
  6. }
  7. HAL_ADC_Stop(&hadc1);//关闭ADC
  8. sprintf(get1,"adc1:%f",DAT[0]/4095*3.3);
  9. sprintf(get2,"adc2:%f",DAT[1]/4095*3.3);
  10. HAL_UART_Transmit(&huart1,(uint8_t*)get1,strlen(get1),100);
  11. HAL_UART_Transmit(&huart1,(uint8_t*)get2,strlen(get2),100);
  12. HAL_Delay(1000);

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号