STM32-嵌入式学习笔记06-ADC的使用

简介: STM32-嵌入式学习笔记06-ADC的使用

写在前面


做为信号类电赛菜鸡弟弟coder选手,ADC简直就是这部分的核心输出(貌似也确实和游戏ADC类似哈哈哈),丰富的配置ADC的配置过51系列ADC(应该算是外设ADC),msp430系列ADC,FPGA系列ADC(必然外设),STM32ADC今天也配置下吧。目前只是最简版本,后面有机会更新,不同模式下的ADC。

开发环境


  1. STM32F103RB系列芯片(蓝桥杯开发板可直接用)
  2. keil5

实现功能


ADC使用单次的连续转换,启用滴答定时器确保ADC的电压值可以在200ms的刷新率下进行刷新,并在TFT屏幕上进行显示

STM32 ADC简介


image.png

对于任何数字系统来说,没有ADC(模拟到数字转换器),外部的电压我们就没办法测量,模数转换、数模转换对于任何的测量电子系统来说都是必不可少的东西。举个不太恰当的例子,这就相当于人要和狗狗交流,人(主控)不懂狗的语言(模拟输入)需要狗叫翻译器(模数转换器),把信息翻译进来(板内处理)后,然后再用狗叫模拟机给叫给它听(数模转换)。

这里我参考书中的一些内容来大致解释下在STM32中ADC大致是怎样的情况。

  1. STM32 拥有 1~3 个 ADC(STM32F101/102 系列只有 1 个 ADC),这些 ADC可以独立使用,也可以使用双重模式(提高采样率)。
  2. STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器。它有 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行。
  3. ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。
  4. 模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
  5. STM32F103 系列最少都拥有 2 个 ADC。
  6. STM32 的 ADC 最大的转换速率为 1Mhz,也就是转换时间为 1us(在 ADCCLK=14M,采样周期为 1.5 个 ADC 时钟下得到),不要让 ADC 的时钟超过 14M,否则将导致结果准确度下降。
  7. STM32 将 ADC 的转换分为 2 个通道组:规则通道组和注入通道组。规则通道相当于你正常运行的程序,而注入通道呢,就相当于中断。在你程序正常执行的时候,中断是可以打断你的执行的。同这个类似,注入通道的转换可以打断规则通道的转换, 在注入通道被转换完成之后,规则通道才得以继续转换。

ADC通道对应关系


image.png

开发指南中的基本把ADC中的所有要配置的东西包含在内了,对于库函数开发来说,配置好具体的结构体,用好库函数,基本这部分也算掌握了。给出ADC初始化结构体大家品一品。

typedef struct
{
  uint32_t ADC_Mode;                      /*!< Configures the ADC to operate in independent or
                                               dual mode. 
                                               This parameter can be a value of ADC_mode */
  FunctionalState ADC_ScanConvMode;       /*!< Specifies whether the conversion is performed in
                                               Scan (multichannels) or Single (one channel) mode.
                                               This parameter can be set to ENABLE or DISABLE */
  FunctionalState ADC_ContinuousConvMode; /*!< Specifies whether the conversion is performed in
                                               Continuous or Single mode.
                                               This parameter can be set to ENABLE or DISABLE. */
  uint32_t ADC_ExternalTrigConv;          /*!< Defines the external trigger used to start the analog
                                               to digital conversion of regular channels. This parameter
                                               can be a value of @ref ADC_external_trigger_sources_for_regular_channels_conversion */
  uint32_t ADC_DataAlign;                 /*!< Specifies whether the ADC data alignment is left or right.
                                               This parameter can be a value of @ref ADC_data_align */
  uint8_t ADC_NbrOfChannel;               /*!< Specifies the number of ADC channels that will be converted
                                               using the sequencer for regular channel group.
                                               This parameter must range from 1 to 16. */
}ADC_InitTypeDef;

ADC配置函数


void ADC_Config(void)
{
  ADC_InitTypeDef  ADC_InitStructure;
  GPIO_InitTypeDef GPIO_InitStruct;
  #时钟的使能
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  //配置gpio管脚
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 ;  
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN ; 
  GPIO_Init(GPIOB, &GPIO_InitStruct);
  //配置ADC结构体参数
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//单独工作
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;//不使能扫描转换
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//使能连续转换,因为程序简单这里不需要每次测量都单独使能了
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//不使用外部中断
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据位对齐设置,一般设置右对齐,方便计算
  ADC_InitStructure.ADC_NbrOfChannel = 1;//通道长度,这里就使能了一个,所以为1
  ADC_Init(ADC1, &ADC_InitStructure);//结构体配置完成,使用函数初始化,保存我们的配置
  ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_13Cycles5);//设置ADC的通道和采样时钟,具体参数见头文件的定义
}

ADC配置完毕。

使能 ADC并校准


在设置完了ADC结构体的信息后,我们就使能 AD 转换器,执行复位校准和 AD 校准,这两步

是必须的!不校准将导致结果很不准确。这就和买东西上称前要清零,谁也不想吃亏对吧哈哈哈。

  ADC_Cmd(ADC1, ENABLE);//使能我们使用的ADC1
    //启用ADC1复位校准寄存器,保证ADC能正常使用,先复位 
    ADC_ResetCalibration(ADC1);
    //检查ADC1复位校准寄存器的结束
    while(ADC_GetResetCalibrationStatus(ADC1));
    //开始ADC1校准
    ADC_StartCalibration(ADC1);
    //检查ADC1校准结束
    while(ADC_GetCalibrationStatus(ADC1));
    //启动ADC1软件转换
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);

PS上述部分可以直接键入init函数中,也可以自己定义函数调用。

读取 ADC 值


这里比较简单,就使用了读取电压转换值的函数,然后把结果进行了数学转换为真实电压即可。

这里的0XFFF是右对齐除的精度。

v_value=ADC_GetConversionValue(ADC1)*3.30/0xfff;

main.c


下面在加上显示我们的这个ADC的demo就算完了,这里我思路大致就是在TFT屏幕上进行电压值的显示,然后我用了滴答定时器,让ADC的电压值可以在200ms的刷新率下进行刷新。

#include "stm32f10x.h"
#include <stdio.h>
#include "lcd.h"
uint32_t timingdelay = 0;
char ADC_Flag;
void delayms(uint16_t n);
void ADC_Config(void);
float v_value;
uint8_t  buf[20];
int main(void)
{
  STM3210B_LCD_Init();
  ADC_Config();
  SysTick_Config(SystemCoreClock/1000);
  LCD_SetTextColor(Yellow);
  LCD_SetBackColor(Magenta);
  LCD_Clear(Magenta);
  LCD_DisplayStringLine(Line0, "      ADC-DEMO      ");
  LCD_DisplayStringLine(Line1, "====================");
  LCD_DisplayStringLine(Line3, "                    ");
  while(1)
  { 
     if(ADC_Flag==1)
     {
        ADC_Flag = 0;
       v_value=ADC_GetConversionValue(ADC1)*3.30/0xfff;
       sprintf(buf,"ADC Value:%.3f",v_value);
       LCD_DisplayStringLine(Line3,buf);
     }
  }
}
void ADC_Config(void)
{
  ADC_InitTypeDef  ADC_InitStructure;
  GPIO_InitTypeDef GPIO_InitStruct;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 ;  
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN ; 
  GPIO_Init(GPIOB, &GPIO_InitStruct);
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.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);
  ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_13Cycles5);
  ADC_Cmd(ADC1, ENABLE);
  /* Enable ADC1 reset calibration register */   
  ADC_ResetCalibration(ADC1);
  /* Check the end of ADC1 reset calibration register */
  while(ADC_GetResetCalibrationStatus(ADC1));
  /* Start ADC1 calibration */
  ADC_StartCalibration(ADC1);
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC1));
  /* Start ADC1 Software Conversion */ 
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
void delayms(uint16_t n)
{
  timingdelay = n;
    while(timingdelay!=0);
}

滴答定时器的模块只需要在 stm32f10x_it 中写上:

void SysTick_Handler(void)
{
  timingdelay--;
  if(++MS == 200){
    MS = 0;
    ADC_Flag = 1;
  }
}

记得外部调用的定义变量

extern uint32_t timingdelay;
uint16_t MS=0;
extern char ADC_Flag;

Reference


  1. STM32 开发指南 V1.3 3 正点原子
  2. STM32F10x固件库中文解释 V2.0
目录
相关文章
|
8月前
|
物联网 开发者 智能硬件
STM32:引领嵌入式系统新时代的微控制器
STM32:引领嵌入式系统新时代的微控制器
|
缓存 Java C语言
嵌入式 LVGL移植到STM32F4
嵌入式 LVGL移植到STM32F4
|
8月前
|
传感器
STM32标准库ADC和DMA知识点总结-1
STM32标准库ADC和DMA知识点总结
|
6月前
|
传感器 编解码 IDE
STM32CubeMX ADC采集光照和电压
STM32CubeMX ADC采集光照和电压
311 3
|
7月前
|
Web App开发 传感器 Linux
【嵌入式软件工程师面经】STM32单片机
【嵌入式软件工程师面经】STM32单片机
176 1
|
6月前
|
传感器 编解码 API
【STM32开发入门】温湿度监测系统实战:SPI LCD显示、HAL库应用、GPIO配置、UART中断接收、ADC采集与串口通信全解析
SPI(Serial Peripheral Interface)是一种同步串行通信接口,常用于微控制器与外围设备间的数据传输。SPI LCD是指使用SPI接口与微控制器通信的液晶显示屏。这类LCD通常具有较少的引脚(通常4个:MISO、MOSI、SCK和SS),因此在引脚资源有限的系统中非常有用。通过SPI协议,微控制器可以向LCD发送命令和数据,控制显示内容和模式。
229 0
|
7月前
|
移动开发
技术好文:stm32寄存器版学习笔记06输入捕获(ETR脉冲计数)
技术好文:stm32寄存器版学习笔记06输入捕获(ETR脉冲计数)
306 0
|
8月前
|
传感器 数据采集 物联网
基于STM32的光敏传感器数据采集系统-嵌入式系统与设计课程设计2
基于STM32的光敏传感器数据采集系统-嵌入式系统与设计课程设计
827 0
|
7月前
|
存储 数据安全/隐私保护 芯片
【STM32】详解嵌入式中FLASH闪存的特性和代码示例
【STM32】详解嵌入式中FLASH闪存的特性和代码示例