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。
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_InjectInit()函数,分别初始化规则通道和注入通道。

        第一步:初始化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); // 开启注入通道转换中断
}
  • 重定义HAL_ADC_MspInit()函数,初始化ADC底层引脚并使能ADC时钟和中断。
// 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中断服务函数,函数中调用HAL_ADC_IRQHandler()处理中断请求。
// ADC中断服务函数
void ADC_IRQHandler()
{
	HAL_ADC_IRQHandler(&ADC_Handler);
}
  • 定义两个存储变量,分别用来存储规则通道和注入通道的值。
uint16_t uhADCxConvertedRegValue = 0; // 存储规则通道转换值
uint16_t uhADCxConvertedInjValue = 0; // 存储注入通道转换值
  • 定义注入转换完成回调函数,函数中首先获取ADC转换数字值,然后通过获取的数字值计算出电压值,最后通过串口打印电压值。
// 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);
}
  • 创建Regula_GetData()函数,用来处理规则通道中数据。同样函数中首先获取ADC转换数字值,然后通过获取的数字值计算出电压值,最后返回计算后的电压值。
// 规则通道数据计算
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;
}
  • 主函数main程序如下:

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

        第二步:调用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引脚)。

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
STM32ADC模块中,规则注入(Regular Injection)是指在ADC转换过程中,插入一些额外的采样通道进行转换,以增强ADC的功能和灵活性。 规则注入的实现步骤如下: 1. 配置ADC的规则序列,包括需要转换的通道、转换顺序、采样时间等参数; 2. 配置注入序列,即需要插入的额外采样通道以及插入的位置; 3. 配置注入模式,包括单次注入模式和循环注入模式。 在单次注入模式下,每次触发ADC转换时只转换一次规则序列中的通道和注入序列中的一个通道;在循环注入模式下,每次触发ADC转换时都会转换规则序列中的所有通道和注入序列中的所有通道。 需要注意的是,规则序列和注入序列中的通道不能重复,否则会导致转换错误。 以下是一个示例代码,演示如何使用规则注入功能: ```c ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5); ADC_InjectedChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_239Cycles5); ADC_InjectedChannelConfig(ADC1, ADC_Channel_3, 2, ADC_SampleTime_239Cycles5); ADC_InjectedSequencerLengthConfig(ADC1, 2); //注入序列长度为2 ADC_InjectedSequencerConfig(ADC1, ADC_InjectedChannel_2, ADC_InjectedRank_1, 1); //注入序列中第1个转换为通道2 ADC_InjectedSequencerConfig(ADC1, ADC_InjectedChannel_3, ADC_InjectedRank_2, 1); //注入序列中第2个转换为通道3 ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_T1_TRGO); //使用定时器1触发注入转换 ADC_ExternalTrigConvConfig(ADC1, ADC_ExternalTrigConv_T1_CC1); //使用定时器1触发规则转换 ADC_AutoInjectedConvCmd(ADC1, ENABLE); //开启自动注入转换 ADC_Cmd(ADC1, ENABLE); //开启ADC ``` 以上代码配置了ADC1的规则序列为通道1,注入序列为通道2和通道3,使用定时器1触发转换,开启自动注入转换和ADC模块。在转换过程中,每次规则转换时都会转换通道1,每次注入转换时都会转换通道2和通道3。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奚海蛟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值