1.PWM调光原理
PWM全称为脉宽调制技术,是通过高精度的计数器对方波的占空比进行编码。
就是这个东西,其实很好理解,高电平的时候才会做功,低电平的时候肯定不亮啊,PWM就是调制高电平的占比。(其实一般是低电平才有效,因为会外接一个12V的电源,这么说是方便理解)
2. 线性变化描述
举个例子,假如你洗澡要用1吨水,你不可能1秒钟把这一吨水全部倒下来把。光变化也是这样,一下子变过来你眼睛受不了。所以要在规定时间内,尽量均匀的变化,保证在规定时间内完成变化,又要保证变化的过程尽量平缓,斜率尽量固定或者变化不大。
3. 光调制原理
知道彩虹不,这世界其实只有三种颜色,红绿蓝,学美术的应该知道,这三种颜色可以组合出各种不同的颜色。所以通过控制R(红色),G(绿色),B(蓝色)(red,green,blue的缩写)这三种LED的亮度就可以产生理论上你想要的任何颜色。
有个类似这种的表,网上能查到
4. 线性变化算法描述
设置过渡时间的信号从LIN总线过来,值的范围是0~255(8位数据,相当于unsigned char),单位是20ms,我把这个值设为 time。
LIN总线上还会传入需要设置的R,G,B三种颜色的值,也是8位的,我用到的PWM寄存器的大小也是八位。设置需要变化的大小为val。分析以下几种情况:
time >val ; 也就是说单位时间变化1个值就可以在规定时间完成。多余的时间无所谓的
time < val; 就是说单位时间需要变化多个值。我们把单位时间需要变化的值叫做步径,如果变化1个值其实就是步径为1,设步径为step
2*time>val; 步径为2
。。。
step*time>val;步径为step ,这个过程可以用for循环来实现。
我们可以设置一个20ms的中断,在中断中让PWM的值增加步径,就可以完成LED灯的线性变化啦。
5. 代码
5.1 计算步径
//计算PWM步径
//捎带判断了转换时间
void PWM_Calculate_Step()
{
//如果 要设置的RGB和PWM的值不相等,则需要线性变为需要设置的值
//这部分根据时间设置PWM的线性变化
/*
* 变化值和过渡时间都是一个八位的寄存器
* 设变化值为V
* 过渡时间为T
* 如果 V<T 单位时间变化一个值就来得及
* 如果 V>T 单位时间需要变化多个值,就需要算出步径
* */
//应该在中断里面设置进入 ,退出 中断的条件 也就是 要设置的PWM值和当前值 不相等 在中断服务子程序里面设置退出条件
//
if((TargetTransitionTime != 0)&& ((BnIngrd)||(GrnIngrd)||(RedIngrd))) //如果转换时间不为0,且氛围灯RGB不全为0 不一定这么写啊
{
if(BnIngrd != PWM22H)
{
uint8 B_Difference_Value; //变化值 这个是绝对值
//uint8 B_Step;//Step
uint8 i_B = 0; //for循环变量,注意要从1开始
//uint8 B_Temp; //暂存变化值
//uint8 Forward_or_Back_Flag_B; //正向或逆向变化标志位 1: 正向 0:逆向
if(BnIngrd > PWM22H) //当前值 大于 前面值 要正向调整
{
B_Difference_Value = BnIngrd - PWM22H;
Forward_or_Back_Flag_B = 1; //正向
}
else//(BnIngrd < PWM22H)
{
B_Difference_Value = PWM22H - BnIngrd;
Forward_or_Back_Flag_B = 0; //逆向
}
//B_Temp = B_Difference_Value;
for(;((i_B)*(TargetTransitionTime)) < B_Difference_Value; i_B++)
{
B_Step = i_B;
}
B_Step = i_B;
}
if(GrnIngrd != PWM12L)
{
uint8 G_Difference_Value; //变化值 绝对值
//uint8 G_Step;
uint8 i_G = 0;
//uint8 Forward_or_Back_Flag_B;
if(GrnIngrd > PWM12L)
{
G_Difference_Value = GrnIngrd - PWM12L;
Forward_or_Back_Flag_G = 1;
}
else
{
G_Difference_Value = PWM12L - GrnIngrd;
Forward_or_Back_Flag_G = 0;
}
for(;((TargetTransitionTime)*(i_G)) < G_Difference_Value;i_G++)
{
G_Step = i_G;
}
G_Step = i_G;
}
if(RedIngrd != PWM23H)
{
uint8 R_Difference_Value; //变化值 绝对值
//uint8 R_Step;
uint8 i_R = 0;
//uint8 Forward_or_Back_Flag_R;
if(RedIngrd > PWM23H)
{
R_Difference_Value = RedIngrd - PWM23H;
Forward_or_Back_Flag_R = 1;
}
else
{
R_Difference_Value = PWM23H - RedIngrd;
Forward_or_Back_Flag_R = 0;
}
for(;((TargetTransitionTime)*(i_R)) < R_Difference_Value;i_R++)
{
R_Step = i_R;
}
R_Step = i_R;
}
}
else
{
BnIngrd = PWM22H;
GrnIngrd = PWM12L;
RedIngrd = PWM23H;
}
}
5.2 中断函数
//Interrupt Function Low Enter
void int_fun1() __interrupt (1)
{
//判断R是正步径还是负步径 ,在中断里面自增或自减
if(Forward_or_Back_Flag_R == 1)
{
PWM23H += R_Step;
}
else
{
PWM23H -= R_Step;
}
//执行G的自增或自减操作
if(Forward_or_Back_Flag_G == 1)
{
PWM12L += G_Step;
}
else
{
PWM12L -= G_Step;
}
//执行B的自增或自减操作
if(Forward_or_Back_Flag_B == 1)
{
PWM22H += B_Step;
}
else
{
PWM22H -= B_Step;
}
//如果要设置的值和寄存器里的值相同 ,则退出中断
if((BnIngrd ==PWM22H) && (GrnIngrd == PWM12L) && (RedIngrd == PWM23H))
{
T0IF = 0u; //中断标志位 退出中断
}
}