[STM32 HAL] 控制LED灯闪烁频率

TIM简介

TIM外设,是用来产生定时事件的。在内部构造上 如下图。
TIM系统框架图

但关键部件只有 [输入时钟脉冲]->[计数器CNT]->[捕获比较寄存器]
常用的寄存器

  • Prescaler(PSC)预分频寄存器:对输入到TIM外设时钟频率进行分频,比如该TIM挂在在APB2上,APB2的时钟频率为72MHz,如果设置PSC寄存器值为72-1,那么那么进入TIM外设的内部的时钟频率为1MHz,CNT寄存器也就是对1这1MHz的脉冲进行计数。该寄存器可通过__HAL_TIM_SET_PRESCALER(__HANDLE__, __PRESC__)进行修改
  • Counter(CNT)寄存器: 用来计数当前收到的脉冲数。使用__HAL_TIM_SET_COUNTER(__HANDLE__, __COUNTER__)修改
  • CCR寄存器(capture/compare register):在输入捕获,和输出比较中有不同的作用。以PWM波生成为例,该寄存器可用来设置PWM波的占空比。使用__HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__)来进行设置
  • ARR寄存器(AutoReload Register): 在本例中,当CNT寄存器中的值达到ARR中的值时,自动将CNT值清零。也就是用来限制CNT的计数范围。使用__HAL_TIM_SET_AUTORELOAD(__HANDLE__, __AUTORELOAD__)进行设置。
    从下图可以看出TIM生成PWM的工作过程。TIM最核心的就是CNT和ARR了,CNT不断的计数,计的是进入TIM的脉冲数,也就是经过PSC分频后的时钟脉冲数;CNT一旦到达ARR的值就会归零,再次开始计数。这就是基本TIM的作用了。如果TIM的某个通道还启用PWM功能,那么就会有CCR寄存器被派上用场,时刻监视着CNT值,根据CNT值和CCR值的比较,更改通道的对应引脚的电平状态。
    在这里插入图片描述

STM32CubeMX配置

对于本次例题。我们直接将CCR值设置为ARR的一半,也就是PWM的占空比50%
将LED灯所在引脚的模式设置为TIM。
设置LED灯所在引脚模式为TIM
配置该TIM 通道为PWM波输出方式。只需要启动Activated即可(左侧TIM16图标变成绿色),主要的参数可以在程序中通过上述的代码设置。
在这里插入图片描述

代码编写
double LED_freq=1;//全局变量,用于保存当前LED闪烁频率值
void LED_blink(double freq)
{
	uint16_t freq_arr=10e3/freq;
	__HAL_TIM_SET_PRESCALER(&htim1, 7200 - 1) //将进入TIM的频率设为10KHz
	__HAL_TIM_SET_AUTORELOAD(&htim1,freq_arr);
	__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,freq_arr/2);
	htim1.Instance->EGR=TIM_EGR_UG; //立即使配置生效
}

#define KEY_UP 1
#define KEY_DOWN 2
#define KEY_NONE 0
uint8_t read_button()
{
	if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==0||HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==0)
	{
		HAL_Delay(20);//延时消抖
		if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==0)
		{
			HAL_Delay(500);
			return KEY_UP;
		}
		if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==0)
		{
			HAL_Delay(500);
			return KEY_DOWN;
		}
	}
	else
		if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==1&&HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==1)
			return KEY_NONE;
	return KEY_NONE;
}

主循环

 /* USER CODE BEGIN 2 */
  HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);//启用TIM定时器
  LED_blink(1);
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	switch(read_button())
	{
	case KEY_UP:
		++LED_freq;
		LED_blink(LED_freq);
		printf("Freq=%.2f\r\n",LED_freq);
			break;
	case KEY_DOWN:
		--LED_freq;
		LED_blink(LED_freq);
		printf("Freq=%.2f\r\n",LED_freq);
			break;
		default:
			break;
    }

项目文件下载地址

好的,下面是使用STM32和Keil5实现使用电位器控制LED呼吸闪烁频率的代码: ``` #include "stm32f10x.h" #define LED_PIN GPIO_Pin_8 #define LED_PORT GPIOA #define POT_ADC_CHANNEL ADC_Channel_0 uint16_t adc_value; float freq = 0.2; void LED_Init(void); void ADC_Init(void); float get_freq(void); int main(void) { LED_Init(); ADC_Init(); while(1) { freq = get_freq(); TIM_SetAutoreload(TIM2, (uint16_t)(50000 / freq) - 1); //设置TIM2的自动重载值,用于控制LED呼吸频率 if(TIM_GetCounter(TIM2) < 25000 / freq) { LED_PORT->BSRR = LED_PIN; //LED亮 } else { LED_PORT->BRR = LED_PIN; //LED灭 } } } void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = LED_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(LED_PORT, &GPIO_InitStructure); } void ADC_Init(void) { ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); ADC_RegularChannelConfig(ADC1, POT_ADC_CHANNEL, 1, ADC_SampleTime_28Cycles5); ADC_Cmd(ADC1, ENABLE); } float get_freq(void) { ADC_SoftwareStartConvCmd(ADC1, ENABLE); while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); adc_value = ADC_GetConversionValue(ADC1); return (adc_value / 4096.0 * 19.8 + 0.2); } ``` 这段代码主要是通过ADC采集电位器的模拟信号,计算出频率,然后将频率设置为TIM2的自动重载值,用于控制LED呼吸频率。其中,LED初始化函数LED_Init()用于初始化LED引脚,ADC初始化函数ADC_Init()用于初始化ADC模块,get_freq()函数用于计算频率。在主函数中,通过判断TIM2计数器的值来控制LED的亮灭。 希望对您有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值