用户工具

站点工具


adc实验_电源监控

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

后一修订版
前一修订版
adc实验_电源监控 [2019/11/29 09:52]
zhangzheng 创建
adc实验_电源监控 [2022/03/22 10:18] (当前版本)
sean
行 1: 行 1:
-[[http://www.cnblogs.com/xiaomagee/p/5029104.html]]+|  **银杏科技有限公司旗下技术文档发布平台** ​ |||| 
 +|技术支持电话|**0379-69926675-801**||| 
 +|技术支持邮件|Gingko@vip.163.com||| 
 +^  版本 ​ ^  日期 ​ ^  作者 ​ ^  修改内容 ​ ^ 
 +|  V1.0  |  2020-07-04 ​ |  gingko ​ |  初次建立 ​ |  
 + 
 +===== 实验九:ADC实验——电源监控 ===== 
 + 
 +==== 一、 实验目的与意义 ==== 
 + 
 +  - 了解STM32 ADC结构。 
 +  - 了解STM32 ADC特征。 
 +  - 掌握ADC使用方法。 
 +  - 掌握STM32 HAL库中ADC属性的配置方法。 
 +  - 掌握KEIL MDK 集成开发环境使用方法。 
 +==== 二、 实验设备及平台 ==== 
 + 
 +  - iCore4 双核心板[[https://item.taobao.com/item.htm?​spm=a1z10.1-c-s.w4004-22598974120.15.5923532fsFrHiE&​id=551864196684|点击购买]]。 
 +  - JLINK(或相同功能)仿真器[[https:​//item.taobao.com/​item.htm?​id=554869837940|点击购买]]。 
 +  - Micro USB线缆。 
 +  - Keil MDK 开发平台。 
 +  - STM32CubeMX开发平台。 
 +  - 装有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框图 === 
 +{{ :​icore4:​icore4_arm_hal_9_1.png?​direct |}} 
 +=== 4、ADC寄存器介绍 === 
 +(1)ADC控制寄存器(ADC_CR1和ADC_CR2) 
 +{{ :​icore4:​icore4_arm_hal_9_2.png?​direct |}} 
 +  * ADC_CR1的SCAN位,该位用于设置扫描模式,由软件设置和清除,如果设置为1,则使用扫描模式,如果为0,则关闭扫描模式。在扫描模式下,由ADC_SQRx或ADC_JSQRx寄存器选中的通道被转换。如果设置了EOCIE或JEOCIE,只在最后一个通道转换完毕后才会产生EOC或JEOC中断。ADC_CR1[25:​24]用于设置ADC的分辨率,详细的对应关系如图所示: 
 +{{ :​icore4:​icore4_arm_hal_9_3.png?​direct |}} 
 +  * ADC_CR2寄存器的各位描述如图所示: 
 +{{ :​icore4:​icore4_arm_hal_9_4.png?​direct |}} 
 +  * ADON位用于开关AD转换器,而CONT位用于设置是否进行连续转换,SWSTART 位用于开始规则通道的转换。 
 +(2)ADC通用控制寄存器(ADC_CCR) 
 +{{ :​icore4:​icore4_arm_hal_9_5.png?​direct |}} 
 +  * 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的各位描述如图所示: 
 +{{ :​icore4:​icore4_arm_hal_9_6.png?​direct |}} 
 +  * ADC_SMPR2的各位描述如下图所示: 
 +{{ :​icore4:​icore4_arm_hal_9_7.png?​direct |}} 
 +  * 对于每个要转换的通道,采样时间建议尽量长一点,以获得较高的准确度,但是这样会降低ADC的转换速率。ADC的转换时间可以由以下公式计算: 
 +    * **Tcovn=采样时间+12个周期** 
 +  * 其中:Tcovn为总转换时间,采样时间是根据每个通道的SMP位的设置来决定的。例如,当ADCCLK=27Mhz的时候,并设置3个周期的采样时间,则得到:Tcovn=3+12=15个周期=0.55us。 
 +(4)ADC状态寄存器(ADC_SR),该寄存器保存了ADC转换时的各种状态。该寄存器的各位描述如图所示: 
 +{{ :​icore4:​icore4_arm_hal_9_8.png?​direct |}} 
 +  * 这里仅介绍将要用到的是EOC位,通过判断该位来决定是否此次规则通道的AD转换已经完成,如果该位位1,则表示转换完成了,就可以从ADC_DR中读取转换结果,否则等待转换完成。 
 +  * 本实验中iCore4的所有电源经过电阻分压或者直接接入STM32的ADC的输出通道内,输入电流经过高端电流检测芯片ZXCT1009F输入到ADC的输入通道内,从而实现电源监控功能。 
 +==== 四、 实验程序 ==== 
 + 
 +=== 1、 主函数 === 
 +<code c> 
 +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]);​ 
 +  } 
 +
 + 
 +</​code>​ 
 +=== 2、 初始化ADC === 
 +  * 在HAL库中,初始化ADC是通过函数HAL_ADC_Init来实现的,该函数声明为: 
 +<code c> 
 +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;​ 
 +</​code>​ 
 +  * 该结构体定义和其他外设比较类似,我们着重看第二个成员变量Init含义,它是结构体ADC_InitTypeDef 类型,结构体ADC_InitTypeDef 定义为: 
 +<code c> 
 +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;​ 
 +</​code>​ 
 +=== 3、 ADC3初始化函数 === 
 +<code c> 
 +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__);​ 
 +  } 
 +
 +</​code>​ 
 +  * 此部分代码中MX_ADC3_Init函数调用函数HAL_ADC_Init初始化 ADC13相关参数。 
 +=== 4、 读取通道值 === 
 +<code c> 
 +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; ​  
 +
 + 
 +</​code>​ 
 +==== 五、 实验步骤 ==== 
 +  - 把仿真器与iCore4的SWD调试口相连(直接相连或者通过转接器相连); 
 +  - 把iCore4通过Micro USB线与计算机相连,为iCore4供电; 
 +  - 打开Keil MDK 开发环境,并打开本实验工程; 
 +  - 烧写程序到iCore4上; 
 +  - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。 
 +==== 六、 实验现象 ==== 
 + 
 +  * 串口一直向终端输出输入电源的数据。 
 +{{ :​icore4:​icore4_arm_hal_9_9.png?​direct |}} 
adc实验_电源监控.1574992339.txt.gz · 最后更改: 2019/11/29 09:52 由 zhangzheng