29. ADC 您所在的位置:网站首页 stm32adc内部参考电压怎么设置 29. ADC

29. ADC

2024-05-10 02:40| 来源: 网络整理| 查看: 265

29.6.2. 代码分析¶

ADC宏定义

代码清单:ADC-11 多通道ADC相关宏定义(bsp_adc.h文件)¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21//引脚定义 #define RHEOSTAT_ADC_PIN GPIO_PIN_4 #define RHEOSTAT_ADC_GPIO_PORT GPIOA #define RHEOSTAT_ADC_GPIO_CLK_ENABLE() __GPIOA_CLK_ENABLE() // ADC_MASTER序号宏定义 #define RHEOSTAT_ADC_MASTER ADC1 #define RHEOSTAT_ADC_MASTER_CLK_ENABLE() __ADC1_CLK_ENABLE() #define RHEOSTAT_ADC_MASTER_CHANNEL ADC_CHANNEL_18 // ADC_SLAVE序号宏定义 #define RHEOSTAT_ADC_SLAVE ADC2 #define RHEOSTAT_ADC_SLAVE_CLK_ENABLE() __ADC2_CLK_ENABLE() #define RHEOSTAT_ADC_SLAVE_CHANNEL ADC_CHANNEL_18 //DMA时钟使能 #define RHEOSTAT_ADC_DMA_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE(); #define RHEOSTAT_ADC_DMA_Base DMA1_Stream1 #define RHEOSTAT_ADC_DMA_Request DMA_REQUEST_ADC1 //DMA中断服务函数 #define RHEOSTAT_ADC_DMA_IRQHandler DMA1_Stream1_IRQHandler

双重ADC需要使用通用规则数据寄存器ADC_CDR,这点跟独立模式不同。定义光敏电阻的引脚作为三重ADC的模拟输入。

ADC GPIO初始化函数

代码清单:ADC-12 ADC GPIO初始化¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14static void ADC_GPIO_Mode_Config(void) { /* 定义一个GPIO_InitTypeDef类型的结构体 */ GPIO_InitTypeDef GPIO_InitStruct; /* 使能ADC引脚的时钟 */ RHEOSTAT_ADC_GPIO_CLK_ENABLE(); GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Pin = RHEOSTAT_ADC_PIN; /* 配置为模拟输入,不需要上拉电阻 */ HAL_GPIO_Init(RHEOSTAT_ADC_GPIO_PORT, &GPIO_InitStruct); }

使用到GPIO时候都必须开启对应的GPIO时钟,GPIO用于AD转换功能必须配置为模拟输入模式。

配置双重ADC交替模式

代码清单:ADC-13 双重ADC交替模式配置(bsp_adc.c文件)¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119static void ADC_Mode_Config(void) { ADC_ChannelConfTypeDef ADC_Config; RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit; /* 配置ADC3时钟源 */ /* HSE Frequency(Hz) = 25000000 */ /* PLL_M = 5 */ /* PLL_N = 160 */ /* PLL_P = 25 */ /* PLL_Q = 2 */ /* PLL_R = 2 */ /* ADC_ker_clk = 32000000 */ RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; RCC_PeriphClkInit.PLL2.PLL2FRACN = 0; RCC_PeriphClkInit.PLL2.PLL2M = 5; RCC_PeriphClkInit.PLL2.PLL2N = 160; RCC_PeriphClkInit.PLL2.PLL2P = 25; RCC_PeriphClkInit.PLL2.PLL2Q = 2; RCC_PeriphClkInit.PLL2.PLL2R = 2; RCC_PeriphClkInit.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_2; RCC_PeriphClkInit.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE; RCC_PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_PLL2; HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit); /* 使能ADC时钟 */ RHEOSTAT_ADC_MASTER_CLK_ENABLE(); /* 使能DMA时钟 */ RHEOSTAT_ADC_DMA_CLK_ENABLE(); /* 使能ADC_SLAVE时钟 */ RHEOSTAT_ADC_SLAVE_CLK_ENABLE(); //选择DMA1的Stream1 hdma_adc.Instance = RHEOSTAT_ADC_DMA_Base; //ADC1的DMA请求 hdma_adc.Init.Request = RHEOSTAT_ADC_DMA_Request; //传输方向:外设-》内存 hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY; //外设地址不自增 hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE; //内存地址不自增 hdma_adc.Init.MemInc = DMA_PINC_DISABLE; //外设数据宽度:半字 hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; //内存数据宽度:半字 hdma_adc.Init.MemDataAlignment = DMA_PDATAALIGN_WORD; //DMA循环传输 hdma_adc.Init.Mode = DMA_CIRCULAR; //DMA的软件优先级:低 hdma_adc.Init.Priority = DMA_PRIORITY_LOW; //FIFO模式关闭 hdma_adc.Init.FIFOMode = DMA_FIFOMODE_DISABLE; //DMA初始化 HAL_DMA_Init(&hdma_adc); //hdma_adc和ADC_Handle.DMA_Handle链接 __HAL_LINKDMA(&ADC_Handle,DMA_Handle,hdma_adc); ADC_Handle.Instance = RHEOSTAT_ADC_MASTER; //使能Boost模式。1.5.0hal库中已经取消这个配置参数 //ADC_Handle.Init.BoostMode = ENABLE; //ADC时钟1分频 ADC_Handle.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; //使能连续转换模式 ADC_Handle.Init.ContinuousConvMode = ENABLE; //数据存放在数据寄存器中 ADC_Handle.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR; //关闭不连续转换模式 ADC_Handle.Init.DiscontinuousConvMode = DISABLE; //单次转换 ADC_Handle.Init.EOCSelection = ADC_EOC_SINGLE_CONV; //软件触发 ADC_Handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; //关闭低功耗自动等待 ADC_Handle.Init.LowPowerAutoWait = DISABLE; //数据溢出时,覆盖写入 ADC_Handle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; //不使能过采样模式 ADC_Handle.Init.OversamplingMode = DISABLE; //分辨率为:16bit ADC_Handle.Init.Resolution = ADC_RESOLUTION_16B; //不使能多通道扫描 ADC_Handle.Init.ScanConvMode = DISABLE; //初始化 ADC_MASTER HAL_ADC_Init(&ADC_Handle); //初始化 ADC_SLAVE ADC_SLAVE_Handle.Instance = RHEOSTAT_ADC_SLAVE; ADC_SLAVE_Handle.Init = ADC_Handle.Init; HAL_ADC_Init(&ADC_SLAVE_Handle); //使用通道18 ADC_Config.Channel = RHEOSTAT_ADC_MASTER_CHANNEL; //转换顺序为1 ADC_Config.Rank = ADC_REGULAR_RANK_1; //采样周期为64.5个周期 ADC_Config.SamplingTime = ADC_SAMPLETIME_64CYCLES_5; //不使用差分输入的功能 ADC_Config.SingleDiff = ADC_SINGLE_ENDED ; //设置ADC选择的偏移量 ADC_Config.offsetNUmber = ADC_OFFSET_NONE; //配置ADC_MASTER通道 HAL_ADC_ConfigChannel(&ADC_Handle, &ADC_Config); //配置ADC_SLAVE通道 HAL_ADC_ConfigChannel(&ADC_SLAVE_Handle, &ADC_Config); //使能ADC1、2 ADC_Enable(&ADC_Handle); ADC_Enable(&ADC_SLAVE_Handle); //数据格式 ADC_multimode.DualModeData = ADC_DUALMODEDATAFORMAT_32_10_BITS; //双重ADC交替模式 ADC_multimode.Mode = ADC_DUALMODE_INTERL; //ADC_MASTER和ADC_SLAVE采样间隔3个ADC时钟 ADC_multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_3CYCLES; //ADC双重模式配置初始化 HAL_ADCEx_MultiModeConfigChannel(&ADC_Handle, &ADC_multimode); //使能DMA HAL_ADCEx_MultiModeStart_DMA(&ADC_Handle, (uint32_t*)&ADC_ConvertedValue, 1); }

首先,我们使用了DMA_HandleTypeDef定义了一个DMA初始化类型变量,该结构体内容我们在DMA篇已经做了非常详细的讲解; 另外还使用ADC_HandleTypeDef和ADC_ChannelConfTypeDef结构体分别定义一个ADC初始化和ADC通道配置变量,这两个结构体我们之前已经有详细讲解。

调用RHEOSTAT_ADC_DMA_CLK_ENABLE (),RHEOSTAT_ADC_MASTER_CLK_ENABLE ()和RHEOSTAT_ADC_SLAVE_CLK_ENABLE()函数开启ADC时钟以及开启DMA时钟。

我们需要对DMA进行必要的配置。首先设置外设基地址就是ADC的通用规则数据寄存器地址;存储器的地址就是我们指定的数据存储区空间,ADC_ConvertedValue是我们定义的一个全局变量名, 它是一个无符号32位的整型数据;ADC规则转换对应只有一个数据寄存器所以地址不能递增,我们指定的存储区也需要递增地址。ADC的通用规则数据寄存器是32位有效,我们配置DMA模式, 设置数据大小为字大小。ADC配置为连续转换模式,DMA也设置为循环传输模式。设置好DMA相关参数后就使能DMA的ADC通道。

接下来我们使用ADC_HandleTypeDef结构体变量ADC_InitStructure来配置ADC1为16位分辨率、不使用扫描模式、启动连续转换、使用内部软件触发无需外部触发事件、 使用右对齐数据格式、转换通道为1,并调用ADC_Init函数完成ADC1工作环境配置。ADC2使用与ADC1相同配 置即可。

ADC_ChannelConfTypeDef函数用来绑定ADC通道转换顺序和采样时间。绑定ADC通道引脚并设置相应的转换顺序。

接下来我们使用ADC_MultiModeTypeDef结构体变量ADC_multimode来配置ADC为双重ADC交替模式、3个周期的采样延迟、数据格式选择32位数据格式。

HAL_ADC_Start函数控制ADC转换启动。

HAL_ADCEx_MultiModeConfigChannel函数控制是否使能ADC的DMA请求,如果使能请求,并调用HAL_ADCEx_MultiModeStart_DMA函数使能DMA, 则在ADC转换完成后就请求DMA实现数据传输。双重模式只需使能ADC1的DMA通道,并且转换后的结果放在ADC1和ADC2的公共数据寄存器CDR中, 主ADC的转换结果放在CDR的低16位,从ADC的转换结果放在CDR的高16位。

主函数

代码清单:ADC-14 主函数¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38int main(void) { /* 系统时钟初始化成480MHz */ SystemClock_Config(); /* 默认不配置 MPU,若需要更高性能,当配置 MPU 后,使用 DMA 时需注意 Cache 与 内存内容一致性的问题, 具体注意事项请参考配套教程的 MPU 配置相关章节 */ // Board_MPU_Config(0, MPU_Normal_WT, 0xD0000000, MPU_32MB); // Board_MPU_Config(1, MPU_Normal_WT, 0x24000000, MPU_512KB); SCB_EnableICache(); // 使能指令 Cache // SCB_EnableDCache(); // 使能数据 Cache /* 配置串口1为:115200 8-N-1 */ DEBUG_USART_Config(); /* ADC初始化子程序 */ ADC_Init(); while (1) { Delay(0xffffee); //双ADC交替采样:ADC_MASTER的采样值存放在低16位; // ADC_SLAVE的采样值存放在高16位; ADC_ConvertedValueLocal[0] = (uint16_t)ADC_ConvertedValue; ADC_ConvertedValueLocal[1] = (uint16_t)((ADC_ConvertedValue&0xFFFF0000)>>16); ADC_vol[0] =(float)((uint16_t)ADC_ConvertedValueLocal[0]*3.3/65536); ADC_vol[1] =(float)((uint16_t)ADC_ConvertedValueLocal[1]*3.3/65536); printf("\r\n The current AD value = 0x%08X \r\n", ADC_ConvertedValueLocal[0]); printf("\r\n The current AD value = 0x%08X \r\n", ADC_ConvertedValueLocal[1]); //读取转换的AD值 printf("\r\n The current ADC1 value = %f V \r\n",ADC_vol[0]); printf("\r\n The current ADC2 value = %f V \r\n",ADC_vol[1]); } }

主函数先初始化系统时钟,然后开启指令和数据cache,再调用DEBUG_USART_Config()函数配置调试串口相关参数,函数定义在bsp_debug_usart.c文件中。

接下来调用ADC_Init()函数进行ADC初始化配置并启动ADC。ADC_Init()函数是定义在bsp_adc.c文件中,它只是简单的分别调用ADC_GPIO_Mode_Config()和ADC_Mode_Config()。

Delay函数只是一个简单的延时函数。

我们配置了DMA数据传输所以它会自动把ADC转换完成后数据保存到数组变量ADC_ConvertedValue内,根据数据存放规则,ADC_ConvertedValue低16位存放ADC1数据、 高16位存放ADC2数据,我们可以根据需要提取出对应ADC的转换结果数据。经过简单地计算就可以得到每个ADC对应的实际电压。

最后就是把相关数据打印至串口调试助手。

29.6.2.1. 下载验证¶

保证开发板相关硬件连接正确,用USB线连接开发板“USB TO UART”接口跟电脑,在电脑端打开串口调试助手,把编译好的程序下载到开发板。 在串口调试助手可看到不断有数据从开发板传输过来,此时我们旋转电位器改变其电阻值,那么对应的数据也会有变化。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有