用户工具

站点工具


adc实验_电源监控
银杏科技有限公司旗下技术文档发布平台
技术支持电话0379-69926675-801
技术支持邮件Gingko@vip.163.com
版本 日期 作者 修改内容
V1.0 2020-07-04 gingko 初次建立

实验九:ADC实验——电源监控

一、 实验目的与意义

  1. 了解STM32 ADC结构。
  2. 了解STM32 ADC特征。
  3. 掌握ADC使用方法。
  4. 掌握STM32 HAL库中ADC属性的配置方法。
  5. 掌握KEIL MDK 集成开发环境使用方法。

二、 实验设备及平台

  1. iCore4 双核心板点击购买
  2. JLINK(或相同功能)仿真器点击购买
  3. Micro USB线缆。
  4. Keil MDK 开发平台。
  5. STM32CubeMX开发平台。
  6. 装有WIN XP(及更高版本)系统的计算机。

三、 实验原理

1、STM32F767 ADC简介

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

2、ADC主要特性

  •  可配置12位、10位、8位或6位分辨率
  •  在转换结束、注入转换结束以及发生模拟看门狗或溢出事件时产生中断
  •  单次和连续转换模式
  •  扫描模式,自动转化通道0到通道n数据
  •  数据对齐以保持内置数据一致性
  •  可独立设置各通道采样时间
  •  外部触发器选项,可为常规转换和注入转换配置极性
  •  不连续采样模式
  •  双重/三重模式(具有2个或更多ADC的器件提供)
  •  双重/三重ADC模式下可配置的DMA数据存储
  •  双重/三重交替模式下可配置的转换间延迟
  •  ADC转换类型(参见数据手册)
  •  ADC电源要求:供电在2.4V到3.6V下可全速运行,供电低至1.8V时为慢速运行
  •  ADC输入范围:VREF–<VIN<VREF+
  •  常规通道转换期间可产生DMA请求

3、ADC框图

4、ADC寄存器介绍

(1)ADC控制寄存器(ADC_CR1和ADC_CR2)

  • ADC_CR1的SCAN位,该位用于设置扫描模式,由软件设置和清除,如果设置为1,则使用扫描模式,如果为0,则关闭扫描模式。在扫描模式下,由ADC_SQRx或ADC_JSQRx寄存器选中的通道被转换。如果设置了EOCIE或JEOCIE,只在最后一个通道转换完毕后才会产生EOC或JEOC中断。ADC_CR1[25:24]用于设置ADC的分辨率,详细的对应关系如图所示:

  • ADC_CR2寄存器的各位描述如图所示:

  • ADON位用于开关AD转换器,而CONT位用于设置是否进行连续转换,SWSTART 位用于开始规则通道的转换。

(2)ADC通用控制寄存器(ADC_CCR)

  • TSVREFE位是内部温度传感器和Vrefint通道使能位,这里我们直接设置为0。ADCPRE[1:0]用于设置ADC输入时钟分频,00~11分别对应2/4/6/8分频,MULTI[4:0]用于多重ADC模式选择。

(3)ADC采样时间寄存器(ADC_SMPR1和ADC_SMPR2),这两个寄存器用于设置通道0~18的采样时间,每个通道占用3个位。 ADC_SMPR1的各位描述如图所示:

  • ADC_SMPR2的各位描述如下图所示:

  • 对于每个要转换的通道,采样时间建议尽量长一点,以获得较高的准确度,但是这样会降低ADC的转换速率。ADC的转换时间可以由以下公式计算:
    • Tcovn=采样时间+12个周期
  • 其中:Tcovn为总转换时间,采样时间是根据每个通道的SMP位的设置来决定的。例如,当ADCCLK=27Mhz的时候,并设置3个周期的采样时间,则得到:Tcovn=3+12=15个周期=0.55us。

(4)ADC状态寄存器(ADC_SR),该寄存器保存了ADC转换时的各种状态。该寄存器的各位描述如图所示:

  • 这里仅介绍将要用到的是EOC位,通过判断该位来决定是否此次规则通道的AD转换已经完成,如果该位位1,则表示转换完成了,就可以从ADC_DR中读取转换结果,否则等待转换完成。
  • 本实验中iCore4的所有电源经过电阻分压或者直接接入STM32的ADC的输出通道内,输入电流经过高端电流检测芯片ZXCT1009F输入到ADC的输入通道内,从而实现电源监控功能。

四、 实验程序

1、 主函数

int main(void)
{
  int i;
  /* MCU 配置*/
  /* 重置所有外围设备,初始化Flash接口和Systick */
  HAL_Init();
  /* 配置系统时钟 */
  SystemClock_Config();
  /* 初始化所有已配置的外围就设备 */
  MX_GPIO_Init();
  MX_ADC3_Init();
  MX_USART6_UART_Init();
 
  usart6.initialize(115200);
  LED_GREEN_ON;
  usart6.printf("\x0c");                //清屏
  usart6.printf("\033[1;32;40m");       //设置终端字体为绿色
  usart6.printf(" Hello, I am iCore4!\r\n");  
  /* 无限循环 */
  while (1)
  {
        LED_GREEN_ON;
        HAL_Delay(500);
        LED_GREEN_OFF;
        //读取ADC
        for(i = 0;i < 5;i ++){
            my_adc.read(i);
        }
        //打印系统供电电压
        usart6.printf(" ");
        usart6.printf("[I] %3.0fmA , ",my_adc.value[0] / 2* 1000.);
        usart6.printf("[V] %4.2fV, ",my_adc.value[1] * 6.);
        usart6.printf("[3.3V] %4.2fV, ",my_adc.value[2] * 2.);
        usart6.printf("[2.5V] %4.2fV,",my_adc.value[3] * 2.);
        usart6.printf("[1.2V] %4.2fV\r",my_adc.value[4]);
  }
}

2、 初始化ADC

  • 在HAL库中,初始化ADC是通过函数HAL_ADC_Init来实现的,该函数声明为:
typedef struct
{
  ADC_TypeDef           *Instance;        //ADC1/ADC2/ADC3
  ADC_InitTypeDef       Init;             //初始化结构体变量
  __IO uint32_t         NbrOfCurrentConversionRank;//当前转换序列
  DMA_HandleTypeDef             *DMA_Handle;       //DMA方式使用 
  HAL_LockTypeDef               Lock;           //ADC锁定对象
  __IO uint32_t                 State;           //ADC通讯状态
  __IO uint32_t                 ErrorCode;      //ADC错误代码
}ADC_HandleTypeDef;
  • 该结构体定义和其他外设比较类似,我们着重看第二个成员变量Init含义,它是结构体ADC_InitTypeDef 类型,结构体ADC_InitTypeDef 定义为:
typedef struct
{
  uint32_t ClockPrescaler;    //时钟分频系数2/4/6/8分频
  uint32_t Resolution;        //分辨率12/10/8/6 位
  uint32_t DataAlign;         //对齐方式,左对齐还是右对齐
  uint32_t ScanConvMode;      //扫描模式
  uint32_t EOCSelection;      //EOC标志是否设置
  uint32_t ContinuousConvMode;  //开启连续转换模式或者单次转换模式
  uint32_t NbrOfConversion;     //规则序列中有多少个转换
  uint32_t DiscontinuousConvMode; //不连续采样模式
  uint32_t NbrOfDiscConversion;  //不连续采样通道数
  uint32_t ExternalTrigConv;     //外部触发方式
  uint32_t ExternalTrigConvEdge; //外部触发边沿
  uint32_t DMAContinuousRequests; //开启 DMA 请求连续模式或者单独模式
 }ADC_InitTypeDef;

3、 ADC3初始化函数

void MX_ADC3_Init(void)
{
  ADC_ChannelConfTypeDef sConfig;
  /**配置ADC的全局功能(时钟,分辨率,数据对齐和转换次数)*/
  hadc3.Instance = ADC3;
  hadc3.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;//4分频
  hadc3.Init.Resolution = ADC_RESOLUTION_12B;// 12 位模式
  hadc3.Init.ScanConvMode = DISABLE; //非扫描模式
  hadc3.Init.ContinuousConvMode = DISABLE; //关闭连续转换
  hadc3.Init.DiscontinuousConvMode = DISABLE; //禁止不连续采样模式
  hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; 
  //使用软件触发
  hadc3.Init.ExternalTrigConv = ADC_SOFTWARE_START; //软件触发
  hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT; //右对齐
  hadc3.Init.NbrOfConversion = 1; //1 个转换在规则序列中
  hadc3.Init.DMAContinuousRequests = DISABLE; //关闭DMA请求
  hadc3.Init.EOCSelection = ADC_EOC_SINGLE_CONV; //EOC中断
  if (HAL_ADC_Init(&hadc3) != HAL_OK) //初始化ADC3
  {
    _Error_Handler(__FILE__, __LINE__);
  }
    /*为选定的ADC常规通道配置其在定序器中的相应等级及其采样时间 */
  sConfig.Channel = ADC_CHANNEL_7; //通道
  sConfig.Rank = 1; //第1个序列,序列1
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; //采样时间
  if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK) //通道配置
  {
    _Error_Handler(__FILE__, __LINE__);
  }
}
  • 此部分代码中MX_ADC3_Init函数调用函数HAL_ADC_Init初始化 ADC13相关参数。

4、 读取通道值

int read_adc(int channel)
{
    int i,k;
    unsigned long int temp[20] = {0};
    unsigned long int value;
    unsigned short int data[100];
    ADC_ChannelConfTypeDef channel_config;
    unsigned char channel_remap[5] = {ADC_CHANNEL_7,ADC_CHANNEL_12,ADC_CHANNEL_4,ADC_CHANNEL_5,ADC_CHANNEL_6};
 
    channel_config.Channel = channel_remap[channel];
    channel_config.Offset = 0;
    channel_config.Rank = 1;
    channel_config.SamplingTime = ADC_SAMPLETIME_480CYCLES;
 
    for(k = 0;k < 20;k++){
        for(i = 0;i < 100;i ++){
            HAL_ADC_ConfigChannel(&hadc3,&channel_config);
            HAL_ADC_Start(&hadc3);
            while(!__HAL_ADC_GET_FLAG(&hadc3,ADC_FLAG_EOC));
            data[i] = HAL_ADC_GetValue(&hadc3);
        }
        sort(data,100);
        for(i = 40;i < 60;i++){
            temp[k] += data[i];
        }
        temp[k] = temp[k] / 20;
    }
    value = 0;
    for(k = 0;k < 20;k++){//获取平均值,用来提高准确度
        value += temp[k]; 
    }
    value /= 20;
    my_adc.value[channel] = value * ADC_REF / 4096; 
    return value;  
}

五、 实验步骤

  1. 把仿真器与iCore4的SWD调试口相连(直接相连或者通过转接器相连);
  2. 把iCore4通过Micro USB线与计算机相连,为iCore4供电;
  3. 打开Keil MDK 开发环境,并打开本实验工程;
  4. 烧写程序到iCore4上;
  5. 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。

六、 实验现象

  • 串口一直向终端输出输入电源的数据。

adc实验_电源监控.txt · 最后更改: 2022/03/22 10:18 由 sean