嵌入式驱动程序(1)IO口模拟PWM(呼吸灯)
程序员文章站
2022-06-28 13:15:05
市面上有很多产品都是都运用到了PWM的功能,比方说动态变化各种颜色的背光灯,渐明渐暗的呼吸灯等产品。PWM就是在固定的周期内,改变IO口高电平和低电平的维持时间。其中 占空比 = 高电平时间/周期时间。通过调节占空比,就可以改变led灯的亮度,通过控制三色灯的不同亮度(权重)来实现不同颜色的显示。如果led灯不停的高低电平切换。我们看到的不应该是一直在闪烁的灯吗?其实不是的,有一种现象叫做视觉暂留:人眼在观察景物时,光信号传入大脑神经,需经过一段短暂的时间,光的作用结束后,视觉形象并不立即消失,这种残留...
市面上有很多产品都是都运用到了PWM的功能,比方说动态变化各种颜色的背光灯,渐明渐暗的呼吸灯等产品。
PWM就是在固定的周期内,改变IO口高电平和低电平的维持时间。其中 占空比 = 高电平时间/周期时间。通过调节占空比,就可以改变led灯的亮度,通过控制三色灯的不同亮度(权重)来实现不同颜色的显示。
如果led灯不停的高低电平切换。我们看到的不应该是一直在闪烁的灯吗?其实不是的,有一种现象叫做视觉暂留:人眼在观察景物时,光信号传入大脑神经,需经过一段短暂的时间,光的作用结束后,视觉形象并不立即消失,这种残留的视觉称“后像”。物体在快速运动时, 当人眼所看到的影像消失后,人眼仍能继续保留其影像0.1-0.4秒左右的图像,同样的道理,在led亮起来的时候,然后让led短暂时间的熄灭,再亮起来,因为之前led亮的后像还没有消失,再次衔接led亮的动作,人眼就感觉不出led有过熄灭的动作。如果熄灭的时间超过了残留的后像时间人眼就会感觉到led闪烁。
但是物理上led灯的确有过短暂的时间熄灭过,这就会导致led看起来亮度没有一直亮着的led灯亮。
有些嵌入式芯片没有集成PWM功能,那么我们可以通过普通IO口模拟PWM功能。本文通过STM32硬件资源,通过普通IO口模拟PWM功能。代码也可以很容易移植到其他硬件平台。
1. 需要的资源
- 普通IO口
- 一个定时器中断,满足固定时间执行一次的调节(这里我们设置成100us)
2. 定义结构体
typedef struct
{
unsigned char Cycle; /* 周期计时 周期 = 每次执行的中断时间*0xff */
unsigned char Duty; /* 当前占空比 */
void (*IO_HIGH)(void); /* 高电平函数 */
void (*IO_LOW)(void); /* 低电平函数 */
}PWM_CONFIG;
3. 函数功能
/*
*********************************************************************************************************
* 函 数 名: PWM_Control
* 形 参: pwm
* 返 回 值: 无
* 功能说明: 周期计数Cycle从1到0xff,依次递增计时,每循环一次也就是一次周期完成,
当设置的当前占空比大于等于当前的周期计数的时候,IO设置成高电平,否则设置成低电平。
比方说,Duty设置成0x40,则Cycle 在[1,0x40]这范围内是高电平,[0x41,0xff]这范围内是低电平
*********************************************************************************************************
*/
void PWM_Control(PWM_CONFIG pwm)
{
if(pwm.Duty >= pwm.Cycle)
pwm.IO_HIGH();
else
pwm.IO_LOW();
if(++pwm.Cycle > 0xff)
pwm.Cycle = 1;
}
/*
*********************************************************************************************************
* 函 数 名: PWM_Handler
* 形 参: 无
* 返 回 值: 无
* 功能说明: 将函数放在定时器中断里面,比方说100us的定时中断函数中,保证每100us调用一次
*********************************************************************************************************
*/
void PWM_Handler(void)
{
PWM_Control(pwm_red_config);
PWM_Control(pwm_green_config);
PWM_Control(pwm_blue_config);
}
/*
*********************************************************************************************************
* 函 数 名: PWM_SetColor
* 形 参: red,红色占空比;green,绿色占空比;blue,蓝色占空比
* 返 回 值: 无
* 功能说明: 通过设置每个灯的占空比,来设置三色灯的颜色
*********************************************************************************************************
*/
void PWM_SetColor(unsigned char red, unsigned char green, unsigned char blue)
{
pwm_red_config.Duty = red;
pwm_green_config.Duty = green;
pwm_blue_config.Duty = blue;
}
/*
*********************************************************************************************************
* 函 数 名: PWM_Init
* 形 参: 无
* 返 回 值: 无
* 功能说明: PWM的IO配置,初始化函数
*********************************************************************************************************
*/
void PWM_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;//定义GPIO结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//使能GPIOC的时钟
GPIO_InitStruct.GPIO_Pin = LED_R_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED_R_PORT,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = LED_G_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED_G_PORT,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = LED_B_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED_B_PORT,&GPIO_InitStruct);
}
4. RGB颜色对照表
通过调用函数PWM_SetColor
,改变三个参数的占空比就可以实现,不同的颜色。可以参考RGB颜色对照表
5. 建议
- 周期可以根据实际需要更改,这里我们设置的是100us*0xff
- 实际运用中将三色灯,一直导通按理说应该是白色灯,但是实际情况可能会偏向其中一个颜色。比方说颜色偏红色,就把红的那一路通过加电阻减小电流或者软件调占空比减小,建议是在三色灯每个IO口串联一个电阻,用来调整亮度。
- 如果实际产品是和音频有关的注意走线,防止PWM对模拟信号的干扰。
6. 代码下载
io口模拟PWM驱动程序提取码:ihaf
我的个人博客网址:一个点的频率 希望大家关注一下,谢谢!!!
本文地址:https://blog.csdn.net/weixin_49467863/article/details/108184398