赞
踩
更多交流欢迎关注作者抖音号:81849645041
掌握ARM Cortex-M 系列芯片外设ADC注入模式的工作原理,通过配置STM32F407的ADC来分别测出规则通道和注入通道的电压值。
配置ADC1通道4(PA4)工作在规则通道,配置ADC1通道5(PA5)工作在注入通道,其中通道5的注入模式选择定时器触发,每一秒触发一次,并通过串口打印出测得电压值。通道4选择连续转换并且每500ms打印一次,因此当规则通道打印两次数据的时候,注入通道打印一次数据。
MDK5 开发环境。
STM32F4xx HAL库。
STM32F407 开发板。
STM32F4xx 参考手册。
STM32F407 开发板电路原理图。
串口调试助手软件。
USB转TTL模块。
- static void TIM1_Config(void)
- {
- __TIM1_CLK_ENABLE(); // 使能定时器1时钟
-
- TIM_HandleTypeDef TIM_Handle; // 定时器初始化结构体变量
- TIM_OC_InitTypeDef TIM_OC_Handle; // 定时器输出初始化结构体变量
-
- // 定时器初始化
- TIM_Handle.Channel = HAL_TIM_ACTIVE_CHANNEL_4; // 通道4
- TIM_Handle.Instance = TIM1; // 选择定时器1
- TIM_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟1分频
- TIM_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
- TIM_Handle.Init.Period = 10000 - 1; // 自动重装载值
- TIM_Handle.Init.Prescaler = 16800 - 1; // 预分频系数
- HAL_TIM_PWM_Init(&TIM_Handle); // 初始化定时器
-
- // 定时器输出PWM初始化
- TIM_OC_Handle.OCMode = TIM_OCMODE_PWM1; // 模式选择PWM1
- TIM_OC_Handle.OCPolarity = TIM_OCPOLARITY_LOW; // 输出比较极性为低
- TIM_OC_Handle.Pulse = 5000; // 设置比较值,此值用来确定占空比,默认比较值为自动重装载值的一半,即占空比为50%
- HAL_TIM_PWM_ConfigChannel(&TIM_Handle, &TIM_OC_Handle, TIM_CHANNEL_4); // 配置PWM输出
-
- HAL_TIM_PWM_Start(&TIM_Handle, TIM_CHANNEL_4); // 开始PWM输出
- }
第一步:初始化ADC规则通道4,为连续转换模式且使用软件触发。
第二步:初始化注入通道5,为定时器1通道4的上升沿触发。
第三步:调用TIM1_Config()函数,初始化定时器,并开启ADC通道转换。
- // ADC规则/注入通道初始化
- void ADC_InjectInit(void)
- {
- // 初始化ADC
- ADC_Handler.Instance = ADC1;
- ADC_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8; // 4分频,ADCCLK = PCLK2/4 =84/4=21MHZ
- ADC_Handler.Init.Resolution = ADC_RESOLUTION_12B; // 12位模式
- ADC_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; //右对齐
- ADC_Handler.Init.ScanConvMode = DISABLE; // 不扫描模式
- ADC_Handler.Init.EOCSelection = DISABLE; // 开启EOC转换一次中断
- ADC_Handler.Init.ContinuousConvMode = ENABLE; // 开启连续转换
- ADC_Handler.Init.NbrOfConversion = 1; // 1个转换在规则序列
- ADC_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 使用软件触发
- ADC_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; // 使用软件触发
- HAL_ADC_Init(&ADC_Handler); // 初始化
-
- ADC_ChannelConfTypeDef ADC_ChanneConf; // 规则通道初始化结构体
- ADC_InjectionConfTypeDef sConfigInjected; // 注入通道初始化结构体
-
- // 规则通道初始化
- ADC_ChanneConf.Channel = ADC_CHANNEL_4; // 通道4
- ADC_ChanneConf.Rank = 1; // 第一个采样
- ADC_ChanneConf.SamplingTime = ADC_SAMPLETIME_480CYCLES; // 周期采样时间
- HAL_ADC_ConfigChannel(&ADC_Handler, &ADC_ChanneConf); // 初始化规则通道
-
- // 注入通道初始化
- sConfigInjected.InjectedNbrOfConversion = 1; // 注入通道转换个数
- sConfigInjected.InjectedChannel = ADC_CHANNEL_5; // 通道5
- sConfigInjected.InjectedRank = 1; // 注入通道执行顺序
- sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_56CYCLES; // 注入采样周期
- sConfigInjected.InjectedOffset = 0;
- sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING; // 使用上升沿触发
- sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_CC4; // 使用定时器1通道4触发
- sConfigInjected.AutoInjectedConv = DISABLE; // 不启用常规通道转换1次后注入自动转换
- sConfigInjected.InjectedDiscontinuousConvMode = DISABLE; // 不启用注入通道连续转换
- HAL_ADCEx_InjectedConfigChannel(&ADC_Handler, &sConfigInjected);
-
- TIM1_Config(); // 定时器初始化
-
- HAL_ADC_Start_IT(&ADC_Handler); // 开启ADC中断
-
- HAL_ADCEx_InjectedStart_IT(&ADC_Handler); // 开启注入通道转换中断
- }
- // ADC底层引脚重定义
- void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
- {
- GPIO_InitTypeDef GPIO_Initure;
-
- __HAL_RCC_ADC1_CLK_ENABLE(); // 使能ADC1时钟
- __HAL_RCC_GPIOA_CLK_ENABLE(); // 开启GPIOA时钟
-
- GPIO_Initure.Pin = GPIO_PIN_4|GPIO_PIN_5; // PA4 PA5
- GPIO_Initure.Mode = GPIO_MODE_ANALOG; // 模拟
- GPIO_Initure.Pull = GPIO_NOPULL; // 浮空
- HAL_GPIO_Init(GPIOA, &GPIO_Initure);
-
- HAL_NVIC_SetPriority(ADC_IRQn, 0, 0); // 设置ADC中断优先级
- HAL_NVIC_EnableIRQ(ADC_IRQn); // 使能ADC
- }
- // ADC中断服务函数
- void ADC_IRQHandler()
- {
- HAL_ADC_IRQHandler(&ADC_Handler);
- }
- uint16_t uhADCxConvertedRegValue = 0; // 存储规则通道转换值
- uint16_t uhADCxConvertedInjValue = 0; // 存储注入通道转换值
- // ADC注入通道转换值
- void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
- {
- float adc_voltage = 0.0f;
- uhADCxConvertedInjValue = HAL_ADCEx_InjectedGetValue(AdcHandle, ADC_INJECTED_RANK_1); // 获取ADC数字值
- adc_voltage = uhADCxConvertedInjValue * 3.3f / 4095; // 计算电压值
- printf("Inject adc_voltage: %.2f\r\n", adc_voltage);
- }
- // 规则通道数据计算
- float Regula_GetData(void)
- {
- float adc_voltage = 0.0f;
- uhADCxConvertedRegValue = HAL_ADC_GetValue(&ADC_Handler); // 获取ADC数字值
- adc_voltage = uhADCxConvertedRegValue * 3.3f / 4095; // 计算电压值
- return adc_voltage;
- }
第一步:初始化系统时钟和串口。
第二步:调用ADC_InjectInit()函数初始化ADC两个通道。
第三步:在while()循环中获取规则通道转换电压值,使用printf将电压值通过串口每隔500ms打印出来。
- int main()
- {
- CLOCK_Init(); // 时钟初始化
- UART_Init(); // 串口初始化
-
- ADC_InjectInit(); // 注入模式初始化
-
- while(1)
- {
- printf("Regulation adc_voltage: %.2f\r\n", Regula_GetData());
- HAL_Delay(500);
- }
- }
将程序下载到开发板中,可以看到注入通道数据每隔1秒钟打印一次,规则通道500ms打印一次,当规则通道打印两次数据的时候,注入通道打印一次数据。(此时规则通道4连接的3.3v引脚,注入通道5连接的GND引脚)。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。