| **银杏科技有限公司旗下技术文档发布平台** |||| |技术支持电话|**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– 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; } ==== 五、 实验步骤 ==== - 把仿真器与iCore4的SWD调试口相连(直接相连或者通过转接器相连); - 把iCore4通过Micro USB线与计算机相连,为iCore4供电; - 打开Keil MDK 开发环境,并打开本实验工程; - 烧写程序到iCore4上; - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。 ==== 六、 实验现象 ==== * 串口一直向终端输出输入电源的数据。 {{ :icore4:icore4_arm_hal_9_9.png?direct |}}