#include "main.
h"
#include "ssd1306.h"
#include "ssd1306_fonts.h"
#include "stdio.h"
#include <math.h>
/* I2C và Timer ---------------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim3;
/* Private function prototypes ------------------------------------------------*/
void SystemClock_Config(void);
static void MPU_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
static void MX_TIM1_Init(void);
static void MX_TIM3_Init(void);
uint8_t ui_page = 0; // 0 = Main, 1 = Setting
volatile uint8_t button_pressing = 0;
volatile uint32_t button_press_tick = 0;
/* ------------------ LED Param ------------------ */
#define LUMEN_WARM 4000.0f
#define LUMEN_COOL 5100.0f
float max_watt = 120.0f; // Công suất tối đa giả lập
float min_power = 30.0f; // 0% mới = 30% cũ
/* Encoder + Button -----------------------------------------------------------*/
volatile uint8_t button_flag = 0;
volatile float target_power = 50.0f; // %
volatile float target_temp = 30.0f; // %
/* Slider hiển thị mượt */
float slider_power = 50;
float slider_temp = 30;
uint8_t current_select = 0; // 0 = Power, 1 = Temp
char buf[20];
/* ------------------ Button Callback ------------------ */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_2) // Button
{
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET)
{
// Bắt đầu nhấn
button_pressing = 1;
button_press_tick = HAL_GetTick();
}
else
{
// Nhả nút
button_pressing = 0;
uint32_t press_time = HAL_GetTick() - button_press_tick;
if(press_time < 500) // Nhấn ngắn
{
button_flag = 1;
}
else if(press_time >= 1500) // Nhấn giữ >1.5s
{
ui_page = !ui_page; // Đổi trang Main/Setting
}
}
}
}
/* ------------------ Vẽ Slider ------------------ */
void draw_slider(uint8_t x, uint8_t y, uint8_t width, uint8_t height, float
percent, uint8_t selected)
{
if(percent < 0) percent = 0;
if(percent > 100) percent = 100;
SSD1306_COLOR color = White;
uint8_t fill_width = (uint8_t)((percent * (width-2)) / 100.0f);
for(uint8_t i = 0; i < height; i++)
{
if(fill_width > 0)
ssd1306_Line(x + 1, y + i, x + 1 + fill_width, y + i, color);
}
// Viền
ssd1306_Line(x, y, x + width, y, color);
ssd1306_Line(x, y + height, x + width, y + height, color);
ssd1306_Line(x, y, x, y + height, color);
ssd1306_Line(x + width, y, x + width, y + height, color);
if(selected)
{
ssd1306_Line(x-1, y-1, x+width+1, y-1, color);
ssd1306_Line(x-1, y+height+1, x+width+1, y+height+1, color);
ssd1306_Line(x-1, y-1, x-1, y+height+1, color);
ssd1306_Line(x+width+1, y-1, x+width+1, y+height+1, color);
}
}
/* ------------------ Update LED PWM ------------------ */
void update_led_pwm(float slider_power, float slider_temp)
{
/* Nhiệt độ màu từ 2500K -> 6500K */
float cct = 2500.0f + slider_temp * (6500.0f - 2500.0f) / 100.0f;
/* --- Curve studio: slider -> mapped power --- */
float k = 10.0f; // Hệ số log, càng lớn càng mượt vùng thấp
float x = slider_power / 100.0f;
float log_curve = logf(1.0f + k * x) / logf(1.0f + k);
float mapped_power = min_power + log_curve * (100.0f - min_power);
/* Gamma correction */
float gamma_power = powf(mapped_power / 100.0f, 2.2f);
/* --- Pha trộn warm / cool --- */
float warm_ratio = (6500.0f - cct) / (6500.0f - 2500.0f);
float cool_ratio = 1.0f - warm_ratio;
/* Bù quang thông */
float warm_eff = warm_ratio / LUMEN_WARM;
float cool_eff = cool_ratio / LUMEN_COOL;
float sum_eff = warm_eff + cool_eff;
warm_eff /= sum_eff;
cool_eff /= sum_eff;
/* Scale để luôn đạt tổng sáng tối đa */
float scale = 1.0f / fmaxf(warm_eff, cool_eff);
/* PWM duty */
uint16_t period = __HAL_TIM_GET_AUTORELOAD(&htim1);
float max_duty = (float)period;
uint16_t duty_warm = (uint16_t)(gamma_power * warm_eff * scale * max_duty);
uint16_t duty_cool = (uint16_t)(gamma_power * cool_eff * scale * max_duty);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, duty_warm);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, duty_cool);
}
/* ------------------ MAIN ------------------ */
int main(void)
{
MPU_Config();
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
MX_TIM1_Init();
MX_TIM3_Init();
ssd1306_Init();
/* Giao diện khởi động */
ssd1306_Fill(Black);
ssd1306_SetCursor(10, 10);
ssd1306_WriteString("LED STUDIO", Font_11x18, White);
ssd1306_SetCursor(30, 35);
ssd1306_WriteString("v1.0", Font_7x10, White);
ssd1306_UpdateScreen();
HAL_Delay(1500);
/* Start PWM và Encoder */
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
__HAL_TIM_SET_COUNTER(&htim3, 0);
int16_t last_enc = 0;
while(1)
{
/* Xử lý nút nhấn */
if(button_flag)
{
current_select = !current_select;
button_flag = 0;
}
/* Đọc giá trị encoder */
int16_t enc_val = (int16_t)__HAL_TIM_GET_COUNTER(&htim3);
int16_t diff = enc_val - last_enc;
last_enc = enc_val;
/* Mỗi nấc ~0.5% để mượt hơn */
float step = 0.5f * diff;
/* Cập nhật giá trị */
if(current_select == 0)
{
target_power += step;
if(target_power < 0) target_power = 0;
if(target_power > 100) target_power = 100;
}
else
{
target_temp += step;
if(target_temp < 0) target_temp = 0;
if(target_temp > 100) target_temp = 100;
}
/* Slider mượt */
slider_power += (target_power - slider_power) * 0.2f;
slider_temp += (target_temp - slider_temp) * 0.2f;
if (fabsf(slider_power - target_power) < 0.5f)
slider_power = target_power;
if (fabsf(slider_temp - target_temp) < 0.5f)
slider_temp = target_temp;
/* Cập nhật PWM */
update_led_pwm(slider_power, slider_temp);
/* -------- Hiển thị OLED -------- */
ssd1306_Fill(Black);
float cct = 2500.0f + slider_temp * (6500.0f - 2500.0f) / 100.0f;
sprintf(buf, "Power:%3d%%", (int)slider_power);
ssd1306_SetCursor(0, 0);
ssd1306_WriteString(buf, Font_7x10, White);
sprintf(buf, "Temp:%4dK", (int)cct);
ssd1306_SetCursor(0, 10);
ssd1306_WriteString(buf, Font_7x10, White);
/* Hiển thị công suất giả lập theo slider */
int real_power = (int)(max_watt * slider_power / 100.0f + 0.5f);
sprintf(buf, "Load:%3dW", real_power);
ssd1306_SetCursor(0, 20);
ssd1306_WriteString(buf, Font_7x10, White);
draw_slider(10, 35, 108, 8, slider_power, current_select == 0);
draw_slider(10, 50, 108, 8, slider_temp, current_select == 1);
ssd1306_UpdateScreen();
HAL_Delay(10); // ~100FPS mượt
}
}