优化开关机Gamma渐变
This commit is contained in:
@@ -7,6 +7,13 @@ volatile uint8_t Light_Transition_FadeActive;
|
||||
#define LIGHT_FADE_STEP 1U
|
||||
#define BRIGHTNESS_SMOOTH_SHIFT 4U
|
||||
#define BREATH_MIN_OUTPUT 1U
|
||||
#define POWER_FADE_Q12_MAX 4096U
|
||||
#define POWER_FADE_ON_TICKS 140U
|
||||
#define POWER_FADE_OFF_TICKS 160U
|
||||
#define POWER_FADE_ON_STEP (POWER_FADE_Q12_MAX / POWER_FADE_ON_TICKS)
|
||||
#define POWER_FADE_ON_REMAINDER (POWER_FADE_Q12_MAX % POWER_FADE_ON_TICKS)
|
||||
#define POWER_FADE_OFF_STEP (POWER_FADE_Q12_MAX / POWER_FADE_OFF_TICKS)
|
||||
#define POWER_FADE_OFF_REMAINDER (POWER_FADE_Q12_MAX % POWER_FADE_OFF_TICKS)
|
||||
|
||||
/*
|
||||
* Gamma 1.8, mapping APP levels 1..100 to a stable physical range of
|
||||
@@ -26,7 +33,30 @@ static const uint16_t brightness_gamma_q12[100] = {
|
||||
3515U, 3577U, 3640U, 3704U, 3768U, 3832U, 3897U, 3963U, 4029U, 4096U
|
||||
};
|
||||
|
||||
/*
|
||||
* Gamma 1.8 envelope for power-on/off. The transition progress is advanced
|
||||
* independently of the requested brightness, so every turn-on takes about
|
||||
* 700 ms and every turn-off takes about 800 ms. Linear interpolation between
|
||||
* table entries prevents visible 1% steps.
|
||||
*/
|
||||
static const uint16_t power_fade_gamma_q12[101] = {
|
||||
0U, 1U, 4U, 7U, 12U, 19U, 26U, 34U, 43U, 54U,
|
||||
65U, 77U, 90U, 104U, 119U, 135U, 151U, 169U, 187U, 206U,
|
||||
226U, 247U, 268U, 291U, 314U, 338U, 363U, 388U, 414U, 441U,
|
||||
469U, 498U, 527U, 557U, 588U, 619U, 651U, 684U, 718U, 752U,
|
||||
787U, 823U, 859U, 897U, 934U, 973U, 1012U, 1052U, 1093U, 1134U,
|
||||
1176U, 1219U, 1262U, 1306U, 1351U, 1396U, 1442U, 1489U, 1536U, 1585U,
|
||||
1633U, 1682U, 1732U, 1783U, 1834U, 1886U, 1939U, 1992U, 2046U, 2100U,
|
||||
2155U, 2211U, 2268U, 2325U, 2382U, 2440U, 2499U, 2559U, 2619U, 2680U,
|
||||
2741U, 2803U, 2866U, 2929U, 2993U, 3057U, 3122U, 3188U, 3254U, 3321U,
|
||||
3388U, 3456U, 3525U, 3594U, 3664U, 3735U, 3806U, 3877U, 3950U, 4023U,
|
||||
4096U
|
||||
};
|
||||
|
||||
static uint16_t current_brightness_q12;
|
||||
static uint16_t power_fade_progress_q12;
|
||||
static uint16_t power_fade_remainder;
|
||||
static uint8_t power_fade_direction;
|
||||
|
||||
static uint16_t brightness_scale_for_level(uint8_t level)
|
||||
{
|
||||
@@ -71,32 +101,115 @@ static uint16_t approach_target(uint16_t current, uint16_t target)
|
||||
return current;
|
||||
}
|
||||
|
||||
static uint16_t power_fade_scale(uint16_t progress_q12)
|
||||
{
|
||||
uint32_t position;
|
||||
uint16_t index;
|
||||
uint16_t fraction;
|
||||
uint16_t lower;
|
||||
uint16_t upper;
|
||||
|
||||
if(progress_q12 >= POWER_FADE_Q12_MAX) return POWER_FADE_Q12_MAX;
|
||||
|
||||
position = (uint32_t)progress_q12 * 100U;
|
||||
index = (uint16_t)(position >> 12);
|
||||
fraction = (uint16_t)(position & 0x0FFFU);
|
||||
lower = power_fade_gamma_q12[index];
|
||||
upper = power_fade_gamma_q12[index + 1U];
|
||||
|
||||
return (uint16_t)(lower +
|
||||
(((uint32_t)(upper - lower) * fraction + 2048U) >> 12));
|
||||
}
|
||||
|
||||
static void update_power_fade(uint8_t powered_on)
|
||||
{
|
||||
uint16_t step;
|
||||
|
||||
if(powered_on)
|
||||
{
|
||||
if(power_fade_direction != 1U)
|
||||
{
|
||||
power_fade_direction = 1U;
|
||||
power_fade_remainder = 0U;
|
||||
}
|
||||
if(power_fade_progress_q12 >= POWER_FADE_Q12_MAX) return;
|
||||
|
||||
step = POWER_FADE_ON_STEP;
|
||||
power_fade_remainder += POWER_FADE_ON_REMAINDER;
|
||||
if(power_fade_remainder >= POWER_FADE_ON_TICKS)
|
||||
{
|
||||
power_fade_remainder -= POWER_FADE_ON_TICKS;
|
||||
step++;
|
||||
}
|
||||
if(step >= POWER_FADE_Q12_MAX - power_fade_progress_q12)
|
||||
power_fade_progress_q12 = POWER_FADE_Q12_MAX;
|
||||
else
|
||||
power_fade_progress_q12 += step;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(power_fade_direction != 2U)
|
||||
{
|
||||
power_fade_direction = 2U;
|
||||
power_fade_remainder = 0U;
|
||||
}
|
||||
if(power_fade_progress_q12 == 0U) return;
|
||||
|
||||
step = POWER_FADE_OFF_STEP;
|
||||
power_fade_remainder += POWER_FADE_OFF_REMAINDER;
|
||||
if(power_fade_remainder >= POWER_FADE_OFF_TICKS)
|
||||
{
|
||||
power_fade_remainder -= POWER_FADE_OFF_TICKS;
|
||||
step++;
|
||||
}
|
||||
if(step >= power_fade_progress_q12)
|
||||
power_fade_progress_q12 = 0U;
|
||||
else
|
||||
power_fade_progress_q12 -= step;
|
||||
}
|
||||
}
|
||||
|
||||
void Light_Transition_SyncBrightness(uint8_t level)
|
||||
{
|
||||
current_brightness_q12 = brightness_scale_for_level(level);
|
||||
power_fade_progress_q12 =
|
||||
level == 0U ? 0U : POWER_FADE_Q12_MAX;
|
||||
power_fade_remainder = 0U;
|
||||
power_fade_direction = 0U;
|
||||
}
|
||||
|
||||
void Light_Transition_Task(void)
|
||||
{
|
||||
uint8_t target_brightness = 0U;
|
||||
uint8_t powered_on = deviceStatus != POWEROFF;
|
||||
uint16_t target_w;
|
||||
uint16_t target_c;
|
||||
uint16_t target_brightness_scale;
|
||||
uint16_t brightness_scale;
|
||||
uint16_t fade_scale;
|
||||
uint8_t power_transitioning;
|
||||
|
||||
if(deviceStatus != POWEROFF) target_brightness = Brightness;
|
||||
target_brightness_scale = brightness_scale_for_level(target_brightness);
|
||||
/*
|
||||
* Keep APP brightness tracking while off. Power fading is a separate
|
||||
* envelope, so on/off duration does not change with the saved brightness.
|
||||
*/
|
||||
target_brightness_scale = brightness_scale_for_level(Brightness);
|
||||
current_brightness_q12 =
|
||||
approach_brightness_scale(current_brightness_q12,
|
||||
target_brightness_scale);
|
||||
brightness_scale = current_brightness_q12;
|
||||
update_power_fade(powered_on);
|
||||
fade_scale = power_fade_scale(power_fade_progress_q12);
|
||||
brightness_scale = (uint16_t)(
|
||||
((uint32_t)current_brightness_q12 * fade_scale + 2048U) >> 12);
|
||||
power_transitioning =
|
||||
powered_on ? (power_fade_progress_q12 < POWER_FADE_Q12_MAX)
|
||||
: (power_fade_progress_q12 != 0U);
|
||||
|
||||
target_w =
|
||||
(uint16_t)(((uint32_t)W_PWM * brightness_scale + 2048U) >> 12);
|
||||
target_c =
|
||||
(uint16_t)(((uint32_t)C_PWM * brightness_scale + 2048U) >> 12);
|
||||
|
||||
if(Mode == mode1 && target_brightness != 0U)
|
||||
if(Mode == mode1 && powered_on && !power_transitioning)
|
||||
{
|
||||
if(W_PWM != 0U && target_w < BREATH_MIN_OUTPUT)
|
||||
target_w = BREATH_MIN_OUTPUT;
|
||||
@@ -104,7 +217,7 @@ void Light_Transition_Task(void)
|
||||
target_c = BREATH_MIN_OUTPUT;
|
||||
}
|
||||
|
||||
if(Mode == mode2 && deviceStatus != POWEROFF)
|
||||
if((Mode == mode2 && powered_on) || power_transitioning)
|
||||
{
|
||||
W_PWM_duty = target_w;
|
||||
C_PWM_duty = target_c;
|
||||
@@ -116,5 +229,6 @@ void Light_Transition_Task(void)
|
||||
}
|
||||
|
||||
Light_Transition_FadeActive =
|
||||
deviceStatus == POWEROFF && (W_PWM_duty != 0U || C_PWM_duty != 0U);
|
||||
!powered_on && (power_fade_progress_q12 != 0U ||
|
||||
W_PWM_duty != 0U || C_PWM_duty != 0U);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user