当前位置:   article > 正文

ADC-注入模式_adc注入模式

adc注入模式

更多交流欢迎关注作者抖音号:81849645041

目标

        掌握ARM Cortex-M 系列芯片外设ADC注入模式的工作原理,通过配置STM32F407的ADC来分别测出规则通道和注入通道的电压值。

原理

        配置ADC1通道4(PA4)工作在规则通道,配置ADC1通道5(PA5)工作在注入通道,其中通道5的注入模式选择定时器触发,每一秒触发一次,并通过串口打印出测得电压值。通道4选择连续转换并且每500ms打印一次,因此当规则通道打印两次数据的时候,注入通道打印一次数据。

准备

        MDK5 开发环境。

        STM32F4xx HAL库。

        STM32F407 开发板。

        STM32F4xx 参考手册。

        STM32F407 开发板电路原理图。

        串口调试助手软件。

        USB转TTL模块。

步骤

  • 首先创建TIM1_Config()函数,初始化触发定时器和PWM,函数中配置定时器周期为1秒,且PWM的比较值为5000。
  1. static void TIM1_Config(void)
  2. {
  3. __TIM1_CLK_ENABLE(); // 使能定时器1时钟
  4. TIM_HandleTypeDef TIM_Handle; // 定时器初始化结构体变量
  5. TIM_OC_InitTypeDef TIM_OC_Handle; // 定时器输出初始化结构体变量
  6. // 定时器初始化
  7. TIM_Handle.Channel = HAL_TIM_ACTIVE_CHANNEL_4; // 通道4
  8. TIM_Handle.Instance = TIM1; // 选择定时器1
  9. TIM_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟1分频
  10. TIM_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
  11. TIM_Handle.Init.Period = 10000 - 1; // 自动重装载值
  12. TIM_Handle.Init.Prescaler = 16800 - 1; // 预分频系数
  13. HAL_TIM_PWM_Init(&TIM_Handle); // 初始化定时器
  14. // 定时器输出PWM初始化
  15. TIM_OC_Handle.OCMode = TIM_OCMODE_PWM1; // 模式选择PWM1
  16. TIM_OC_Handle.OCPolarity = TIM_OCPOLARITY_LOW; // 输出比较极性为低
  17. TIM_OC_Handle.Pulse = 5000; // 设置比较值,此值用来确定占空比,默认比较值为自动重装载值的一半,即占空比为50%
  18. HAL_TIM_PWM_ConfigChannel(&TIM_Handle, &TIM_OC_Handle, TIM_CHANNEL_4); // 配置PWM输出
  19. HAL_TIM_PWM_Start(&TIM_Handle, TIM_CHANNEL_4); // 开始PWM输出
  20. }
  • 创建ADC_InjectInit()函数,分别初始化规则通道和注入通道。

        第一步:初始化ADC规则通道4,为连续转换模式且使用软件触发。

        第二步:初始化注入通道5,为定时器1通道4的上升沿触发。

        第三步:调用TIM1_Config()函数,初始化定时器,并开启ADC通道转换。

  1. // ADC规则/注入通道初始化
  2. void ADC_InjectInit(void)
  3. {
  4. // 初始化ADC
  5. ADC_Handler.Instance = ADC1;
  6. ADC_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8; // 4分频,ADCCLK = PCLK2/4 =84/4=21MHZ
  7. ADC_Handler.Init.Resolution = ADC_RESOLUTION_12B; // 12位模式
  8. ADC_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; //右对齐
  9. ADC_Handler.Init.ScanConvMode = DISABLE; // 不扫描模式
  10. ADC_Handler.Init.EOCSelection = DISABLE; // 开启EOC转换一次中断
  11. ADC_Handler.Init.ContinuousConvMode = ENABLE; // 开启连续转换
  12. ADC_Handler.Init.NbrOfConversion = 1; // 1个转换在规则序列
  13. ADC_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 使用软件触发
  14. ADC_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; // 使用软件触发
  15. HAL_ADC_Init(&ADC_Handler); // 初始化
  16. ADC_ChannelConfTypeDef ADC_ChanneConf; // 规则通道初始化结构体
  17. ADC_InjectionConfTypeDef sConfigInjected; // 注入通道初始化结构体
  18. // 规则通道初始化
  19. ADC_ChanneConf.Channel = ADC_CHANNEL_4; // 通道4
  20. ADC_ChanneConf.Rank = 1; // 第一个采样
  21. ADC_ChanneConf.SamplingTime = ADC_SAMPLETIME_480CYCLES; // 周期采样时间
  22. HAL_ADC_ConfigChannel(&ADC_Handler, &ADC_ChanneConf); // 初始化规则通道
  23. // 注入通道初始化
  24. sConfigInjected.InjectedNbrOfConversion = 1; // 注入通道转换个数
  25. sConfigInjected.InjectedChannel = ADC_CHANNEL_5; // 通道5
  26. sConfigInjected.InjectedRank = 1; // 注入通道执行顺序
  27. sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_56CYCLES; // 注入采样周期
  28. sConfigInjected.InjectedOffset = 0;
  29. sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING; // 使用上升沿触发
  30. sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_CC4; // 使用定时器1通道4触发
  31. sConfigInjected.AutoInjectedConv = DISABLE; // 不启用常规通道转换1次后注入自动转换
  32. sConfigInjected.InjectedDiscontinuousConvMode = DISABLE; // 不启用注入通道连续转换
  33. HAL_ADCEx_InjectedConfigChannel(&ADC_Handler, &sConfigInjected);
  34. TIM1_Config(); // 定时器初始化
  35. HAL_ADC_Start_IT(&ADC_Handler); // 开启ADC中断
  36. HAL_ADCEx_InjectedStart_IT(&ADC_Handler); // 开启注入通道转换中断
  37. }
  • 重定义HAL_ADC_MspInit()函数,初始化ADC底层引脚并使能ADC时钟和中断。
  1. // ADC底层引脚重定义
  2. void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
  3. {
  4. GPIO_InitTypeDef GPIO_Initure;
  5. __HAL_RCC_ADC1_CLK_ENABLE(); // 使能ADC1时钟
  6. __HAL_RCC_GPIOA_CLK_ENABLE(); // 开启GPIOA时钟
  7. GPIO_Initure.Pin = GPIO_PIN_4|GPIO_PIN_5; // PA4 PA5
  8. GPIO_Initure.Mode = GPIO_MODE_ANALOG; // 模拟
  9. GPIO_Initure.Pull = GPIO_NOPULL; // 浮空
  10. HAL_GPIO_Init(GPIOA, &GPIO_Initure);
  11. HAL_NVIC_SetPriority(ADC_IRQn, 0, 0); // 设置ADC中断优先级
  12. HAL_NVIC_EnableIRQ(ADC_IRQn); // 使能ADC
  13. }
  • 定义ADC中断服务函数,函数中调用HAL_ADC_IRQHandler()处理中断请求。
  1. // ADC中断服务函数
  2. void ADC_IRQHandler()
  3. {
  4. HAL_ADC_IRQHandler(&ADC_Handler);
  5. }
  • 定义两个存储变量,分别用来存储规则通道和注入通道的值。
  1. uint16_t uhADCxConvertedRegValue = 0; // 存储规则通道转换值
  2. uint16_t uhADCxConvertedInjValue = 0; // 存储注入通道转换值
  • 定义注入转换完成回调函数,函数中首先获取ADC转换数字值,然后通过获取的数字值计算出电压值,最后通过串口打印电压值。
  1. // ADC注入通道转换值
  2. void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
  3. {
  4. float adc_voltage = 0.0f;
  5. uhADCxConvertedInjValue = HAL_ADCEx_InjectedGetValue(AdcHandle, ADC_INJECTED_RANK_1); // 获取ADC数字值
  6. adc_voltage = uhADCxConvertedInjValue * 3.3f / 4095; // 计算电压值
  7. printf("Inject adc_voltage: %.2f\r\n", adc_voltage);
  8. }
  • 创建Regula_GetData()函数,用来处理规则通道中数据。同样函数中首先获取ADC转换数字值,然后通过获取的数字值计算出电压值,最后返回计算后的电压值。
  1. // 规则通道数据计算
  2. float Regula_GetData(void)
  3. {
  4. float adc_voltage = 0.0f;
  5. uhADCxConvertedRegValue = HAL_ADC_GetValue(&ADC_Handler); // 获取ADC数字值
  6. adc_voltage = uhADCxConvertedRegValue * 3.3f / 4095; // 计算电压值
  7. return adc_voltage;
  8. }
  • 主函数main程序如下:

        第一步:初始化系统时钟和串口。

        第二步:调用ADC_InjectInit()函数初始化ADC两个通道。

        第三步:在while()循环中获取规则通道转换电压值,使用printf将电压值通过串口每隔500ms打印出来。

  1. int main()
  2. {
  3. CLOCK_Init(); // 时钟初始化
  4. UART_Init(); // 串口初始化
  5. ADC_InjectInit(); // 注入模式初始化
  6. while(1)
  7. {
  8. printf("Regulation adc_voltage: %.2f\r\n", Regula_GetData());
  9. HAL_Delay(500);
  10. }
  11. }

现象

        将程序下载到开发板中,可以看到注入通道数据每隔1秒钟打印一次,规则通道500ms打印一次,当规则通道打印两次数据的时候,注入通道打印一次数据。(此时规则通道4连接的3.3v引脚,注入通道5连接的GND引脚)。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/126009
推荐阅读
相关标签
  

闽ICP备14008679号