PWM实现呼吸灯以及对其的一些思考(一)(STM32F429)

脉冲宽度调制(Pulse Width Modulation,PWM)这个东西学过数电的都知道,它其实就是一种脉冲宽度调制的技术。首先介绍一下什么是PWM。如下图

PWM波形是脉冲波形,发出的信号只有两个状态,高(开)低(关)。其中,从一个上升(下降)沿到下一个上升(下降)沿称作一个周期(T),频率便是f = 1/T.(f:Hz,T:s.)还有一个概念就是占空比,其实也很简单,就如上图Duty Cycle = tw1/(tw1+tw2).

说清楚PWM是什么了,该说一下这玩意儿有什么用,其实很简单,用它做DAC,数字转模拟量。是不是很神奇,一堆高低电平竟然可以模拟出任意的电压值(理论上)。那这个电压值是怎么计算的呢?这就要说一下平均电压的概念,就是在一个周期内,平均值=高电平的电压值×占空比。其实完整的是这样的:

平均值=高电平的电压值×占空比 + 低电平的电压值×(1-占空比),不过一般低电平的电压值一般是0,所以就忽略了。

在示波器中,那个方波永远是那个方波(一般测量方法),但是电压表上测就会反映出模拟的电压值。差不多是这样的

 

视频中我的信号频率是50Hz,振幅是5V,这个 信号在±5V之间跳来跳去,所以我使用第二个公式,在占空比为50%时电压表测的电压差不多是0V,占空比往大变的时候,电压表的电压正向变化,反之往小变化。于是就可以这样理解,在这个方波中携带了一个电压的信息,那个如果我们把这个电压信息提取出来不就是DAC了?。于是电路就成了这样

可见加了一个滤波器后示波器的波形一下就变了,变成了一个直溜溜的的直线。是不是很神奇

这个在生活中的应用很多,最常见的就是手机充电器,原理这个差不多,基本一样。

BB了这么长时间,都在说PWM,好像一直没有说LED的事,所以现在我说一下LED,这也是我的思考部分。LED大家不陌生,中文名字应该是发光二极管,那么问题来了,既然叫发光二极管,那么它就是二极管,二极管的性质它也应该有,那么有一个矛盾,二极管只有达到了导通电压才导通,而且一旦电压超了,二极管就击穿了,所以按照正常思维,用pwm调节LED亮度就相当于调节LED两边的电压就是不对的。因为LED的电压容限小,按照这个想法亮度的调节幅度应该很小,然而并非如此。

同时,我用一节干电池(1.5v)驱动LED,发现并不能使LED亮,但两节就可以,但已经是比较亮了,所以理论上发光二极管只有达到导通调节才发光的这个条件是对的,那么用PWM调节会是怎么样的?下一篇文章继续

仿真文件下载

https://pan.baidu.com/s/1Rb5rivicrpyLJwvwCr30uA

提取码:zmoc

 关注微信公众号有更多好玩的东西

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是基于STM32F429使用PWM实现两个呼吸灯的示例代码: ```c #include "stm32f4xx.h" #define LED1_Pin GPIO_Pin_13 #define LED1_GPIO_Port GPIOD #define LED2_Pin GPIO_Pin_14 #define LED2_GPIO_Port GPIOD TIM_HandleTypeDef htim; TIM_OC_InitTypeDef sConfig; void SystemClock_Config(void); void GPIO_Init(void); void PWM_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); GPIO_Init(); PWM_Init(); while (1) { for (int i = 0; i < 1000; i++) { __HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_1, i); __HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_2, 1000 - i); HAL_Delay(1); } for (int i = 1000; i > 0; i--) { __HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_1, i); __HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_2, 1000 - i); HAL_Delay(1); } } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 25; RCC_OscInitStruct.PLL.PLLN = 336; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 7; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { Error_Handler(); } PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART3 | RCC_PERIPHCLK_CLK48; PeriphClkInit.PLLSAI.PLLSAIN = 192; PeriphClkInit.PLLSAI.PLLSAIQ = 4; PeriphClkInit.PLLSAI.PLLSAIP = RCC_PLLSAIP_DIV4; PeriphClkInit.PLLSAIDivQ = 1; PeriphClkInit.Clk48ClockSelection = RCC_CLK48CLKSOURCE_PLLSAIP; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); } } void GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOD_CLK_ENABLE(); GPIO_InitStruct.Pin = LED1_Pin | LED2_Pin; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF2_TIM4; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); } void PWM_Init(void) { __HAL_RCC_TIM4_CLK_ENABLE(); htim.Instance = TIM4; htim.Init.Period = 1000; htim.Init.Prescaler = 83; htim.Init.CounterMode = TIM_COUNTERMODE_UP; htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&htim); sConfig.OCMode = TIM_OCMODE_PWM1; sConfig.OCPolarity = TIM_OCPOLARITY_HIGH; sConfig.OCFastMode = TIM_OCFAST_DISABLE; sConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH; sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET; sConfig.OCIdleState = TIM_OCIDLESTATE_RESET; sConfig.Pulse = 0; HAL_TIM_PWM_ConfigChannel(&htim, &sConfig, TIM_CHANNEL_1); HAL_TIM_PWM_ConfigChannel(&htim, &sConfig, TIM_CHANNEL_2); HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_2); } ``` 在上面的代码中,使用了TIM4定时器作为PWM输出,使用了GPIOD的13和14号引脚作为PWM输出引脚。在main函数中,使用了一个for循环,通过改变PWM输出的比例来实现呼吸灯效果。具体的实现方式是,先从0到1000改变PWM输出的比例,然后再从1000到0改变PWM输出的比例,循环不断。使用HAL_Delay函数来控制呼吸灯的速度。 需要注意的是,上面的代码中使用了定时器TIM4的PWM输出,因此需要在GPIO初始化函数中将13和14号引脚设置为GPIO_MODE_AF_PP模式,并且Alternate参数设置为GPIO_AF2_TIM4,表示这两个引脚将被连接到TIM4定时器的PWM输出管脚上。 在PWM初始化函数中,设置了定时器的基本参数,包括周期、预分频器、计数模式等。然后使用HAL_TIM_PWM_ConfigChannel函数配置PWM通道的参数,包括PWM模式、输出极性、脉冲宽度等,最后使用HAL_TIM_PWM_Start函数启动PWM输出。 以上就是基于STM32F429使用PWM实现两个呼吸灯的示例代码,可以根据自己的需求进行调整。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值