/**
******************************************************************************
* @file main.c
* @author MCU Application Team
* @brief Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) Puya Semiconductor Co.
* All rights reserved.</center></h2>
*
* <h2><center>© Copyright (c) 2016 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "string.h"
#include "py32f002b_it.h"
#include "py32f002b_hal_tim.h"
#include <stdio.h>
#include <stdlib.h> // for abs()
EXTI_HandleTypeDef exti_handle;
UART_HandleTypeDef UartHandle;
TIM_HandleTypeDef TimHandle;
TIM_HandleTypeDef TimHandle14;
TIM_OC_InitTypeDef sConfigOC = {0}; // 定义并初始化sConfigOC
// 红外协议参数
#define NEC_HEADER_HIGH 9000 // 9ms引导码高电平
#define NEC_HEADER_LOW 4500 // 4.5ms引导码低电平
#define NEC_BIT_HIGH 3900 // 调整为实际测量的约3900us
#define NEC_BIT_ONE_LOW 3900 // 调整为实际测量的约3900us
#define NEC_BIT_ZERO_LOW 3900 // 调整为实际测量的约3900us
/* 容差范围 */
#define NEC_HEADER_TOLERANCE 1000 // 引导码容差1ms
#define NEC_BIT_TOLERANCE 500 // 数据位容差500us
#define IR_MAX_PULSE_CNT 100
/* Private define ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
volatile uint32_t timer1_overflow_count = 0; // TIM1溢出计数
/* Private user code ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
// 系统时钟频率(根据配置为24MHz)
#define SYSTEM_CLOCK_FREQ 24000000
// 定义红外遥控按键对应的功能
#define KEY_POWER 0x01
#define KEY_ON 0xc0
#define KEY_OFF 0x40
#define KEY_RED 0x20
#define KEY_GREEN 0xA0
#define KEY_BLUE 0x60
#define KEY_WHITE 0xE0
#define KEY_FLASH 0xD0
#define KEY_SMOOTH 0xC8
#define KEY_YELLOW 0x06
#define KEY_CYAN 0x07
#define KEY_MAGENTA 0x08
#define KEY_BRIGHT_UP 0x00
#define KEY_BRIGHT_DN 0x80
#define KEY_MODE_NEXT 0x0B
#define KEY_TIMER 0x28
#define KEY_SPEED_UP 0xA8
#define KEY_SPEED_DOWN 0x68
#define KEY_WARM 0x30
#define PWM_MAX 1000 // 满占空比
#define FADE_STEP 5 // 渐变步进
#define FADE_DELAY 10 // 每步延时(ms)
#define BLUE_CHANNEL TIM_CHANNEL_1
#define GREEN_CHANNEL TIM_CHANNEL_2
#define RED_CHANNEL TIM_CHANNEL_3
#define WHITE_CHANNEL TIM_CHANNEL_4
// LED引脚定义
#define LED_RED_PIN GPIO_PIN_5
#define LED_GREEN_PIN GPIO_PIN_3
#define LED_BLUE_PIN GPIO_PIN_4
#define LED_WHITE_PIN GPIO_PIN_1
#define LED_ALL_PINS (LED_RED_PIN | LED_GREEN_PIN | LED_BLUE_PIN)
// 白光呼吸灯参数
#define WARM_BRIGHTNESS_LEVELS 3 // 三种亮度等级
#define WARM_MODE 7 // 白光呼吸模式标识
uint8_t warm_brightness_level = 0; // 亮度等级(0-2对应3种亮度)
uint16_t breath_speed = 20; // 呼吸速度(ms/步,值越小越快)
// 三种亮度等级的最大亮度(0-100)
const uint8_t warm_max_brightness[WARM_BRIGHTNESS_LEVELS] = {70, 40, 0};
// 全局变量
uint8_t ir_data[4] = {0}; // 红外数据缓冲区
uint8_t ir_data_len = 0; // 数据长度
uint8_t ir_repeat_flag = 0; // 重复码标志
uint8_t ir_last_cmd = 0; // 上一次命令
uint32_t last_int_time = 0; // 上一次中断时间戳
uint8_t decode_state = 0; // 解码状态机
uint8_t current_mode = 0; // 0-静态颜色, 1-呼吸模式, 2-颜色渐变
uint8_t current_brightness = 100; // 亮度0-100 (百分比)
uint8_t color_r = 0; // 当前红色分量(0-100%)
uint8_t color_g = 0; // 当前绿色分量(0-100%)
uint8_t color_b = 0; // 当前蓝色分量(0-100%)
uint8_t color_w = 0; //当前白色分量
uint8_t keep_color = 0; //保存当前灯的状态
// 定时器相关变量
// 定时器相关变量
typedef enum {
TIMER_IDLE = 0,
TIMER_SETTING,
TIMER_GRADIENT,
TIMER_RUNNING,
TIMER_EXPIRED
} TimerState_t;
TimerState_t timer_state = TIMER_IDLE;
uint32_t timer_end_time = 0;
uint8_t timer_duration = 0; // 定时时长(小时)
uint32_t gradient_start_time = 0;
uint8_t gradient_steps = 0;
// 保存定时前的状态
uint8_t pre_timer_mode = 0;
uint8_t pre_timer_r = 0, pre_timer_g = 0, pre_timer_b = 0, pre_timer_w = 0;
uint8_t saved_r = 0, saved_g = 0, saved_b = 0, saved_w = 0;
// 全局呼吸参数
uint8_t breath_direction = 1; // 1=渐亮,0=渐暗
uint16_t breath_period = 4000; // 完整呼吸周期(ms)
uint32_t last_breath_time = 0; // 上次呼吸更新时间
uint8_t breath_step_interval = 20;// 步进间隔(ms)
// 函数声明
void led_extinct(void);
void APP_GpioConfig(void);
void APP_SystemClockConfig(void);
void IR_ProcessCommand(void);
void IR_ProcessRepeat(void);
void set_led_color(uint8_t r, uint8_t g, uint8_t b, uint8_t w);
void set_led_brightness(uint8_t brightness);
void next_mode(void);
void update_leds(void);
void led_off(void);
void IR_Decode(uint32_t duration, uint8_t level);
void TIM14_Init(void);
uint32_t IR_GetMicroseconds(void);
// 4组七彩跳变组合(每组7种颜色,包含R/G/B/W分量)
const uint16_t color_groups[4][7][4] = {
// 第1组:基础彩虹色
{
{1000, 0, 0, 0}, // 红
{1000, 647, 0, 0}, // 橙
{1000, 1000, 0, 0}, // 黄
{0, 1000, 0, 0}, // 绿
{0, 1000, 1000, 0}, // 青
{0, 0, 1000, 0}, // 蓝
{1000, 0, 1000, 0} // 紫
},
// 第2组:高饱和混合色
{
{1000, 300, 300, 0}, // 粉
{300, 1000, 300, 0}, // 绿蓝
{300, 300, 1000, 0}, // 靛蓝
{1000, 1000, 300, 0}, // 金黄
{1000, 300, 1000, 0}, // 洋红
{300, 1000, 1000, 0}, // 青绿
{500, 500, 500, 0} // 灰
},
// 第3组:低饱和柔和色
{
{500, 200, 200, 300}, // 淡红
{500, 400, 200, 300}, // 淡橙
{500, 500, 200, 300}, // 淡黄
{200, 500, 200, 300}, // 淡绿
{200, 500, 500, 300}, // 淡青
{200, 200, 500, 300}, // 淡蓝
{500, 200, 500, 300} // 淡紫
},
// 第4组:含白色混合色
{
{1000, 0, 0, 300}, // 红+白
{1000, 600, 0, 300}, // 橙+白
{1000, 1000, 0, 300}, // 黄+白
{0, 1000, 0, 300}, // 绿+白
{0, 1000, 1000, 300}, // 青+白
{0, 0, 1000, 300}, // 蓝+白
{800, 800, 800, 500} // 全白
}
};
// 4组七彩渐变颜色组合(每组7种颜色,用于渐变过渡)
const uint8_t gradient_groups[4][7][4] = {
// 第1组:标准彩虹渐变
{
{100, 0, 0, 0}, // 红
{100, 50, 0, 0}, // 橙
{100, 100, 0, 0}, // 黄
{0, 100, 0, 0}, // 绿
{0, 100, 100, 0}, // 青
{0, 0, 100, 0}, // 蓝
{100, 0, 100, 0} // 紫
},
// 第2组:高饱和渐变
{
{100, 30, 30, 0}, // 粉
{30, 100, 30, 0}, // 绿蓝
{30, 30, 100, 0}, // 靛蓝
{100, 100, 30, 0}, // 金黄
{100, 30, 100, 0}, // 洋红
{30, 100, 100, 0}, // 青绿
{50, 50, 50, 0} // 灰
},
// 第3组:柔和渐变(含白色)
{
{80, 20, 20, 20}, // 淡红
{80, 60, 20, 20}, // 淡橙
{80, 80, 20, 20}, // 淡黄
{20, 80, 20, 20}, // 淡绿
{20, 80, 80, 20}, // 淡青
{20, 20, 80, 20}, // 淡蓝
{80, 20, 80, 20} // 淡紫
},
// 第4组:暖色渐变
{
{100, 20, 0, 10}, // 暖红
{100, 60, 0, 10}, // 暖橙
{100, 100, 20, 10}, // 暖黄
{60, 100, 0, 10}, // 暖绿
{20, 80, 40, 10}, // 暖青
{0, 40, 80, 10}, // 暖蓝
{60, 20, 80, 10} // 暖紫
}
};
// 渐变模式全局变量
uint8_t current_gradient_group = 0; // 当前渐变组索引(0-3)
uint8_t gradient_step = 0; // 组内渐变步骤(0-100)
uint8_t gradient_from_idx = 0; // 起始颜色索引
uint8_t gradient_to_idx = 1; // 目标颜色索引
// 新增全局变量跟踪当前组和组内颜色
uint8_t current_color_group = 0; // 当前组索引(0-3)
static uint8_t group_step_idx = 0; // 当前组内颜色索引(0-6)
// 6组三色跳变组合 (每组3种颜色,每种颜色包含R/G/B/W分量)
const uint8_t jump_color_groups[6][3][4] = {
// 第1组:红→绿→蓝
{{100,0,0,0}, {0,100,0,0}, {0,0,100,0}},
// 第2组:黄→青→紫
{{100,100,0,0}, {0,100,100,0}, {100,0,100,0}},
// 第3组:橙→绿蓝→粉
{{100,50,0,0}, {0,50,100,0}, {100,30,70,0}},
// 第4组:暖白→冷白→中性白
{{80,40,10,30}, {10,40,80,50}, {40,40,40,80}},
// 第5组:深红→深绿→深蓝
{{50,0,0,0}, {0,50,0,0}, {0,0,50,0}},
// 第6组:红+白→绿+白→蓝+白
{{100,0,0,50}, {0,100,0,50}, {0,0,100,50}}
};
uint8_t jump_group_index = 0; // 当前组合索引(0-5)
uint8_t current_jump_color = 0; // 当前组内颜色索引(0-2)
uint32_t jump_timer = 0; // 跳变计时器
uint16_t jump_interval = 800; // 每组颜色停留时间(ms)
/**
* @brief TIM1初始化,配置为1MHz计数(1us计数一次)
* @retval None
*/
/*int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&UartHandle, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}*/
typedef enum {
RAINBOW_STOP = 0,
RAINBOW_RUN
} RainbowState_t;
// 全局变量
static uint16_t cur[4] = {0}; // 当前占空比
static uint32_t last_tick = 0;
void delay_us(uint32_t us)
{
uint32_t tickstart = IR_GetMicroseconds();
while ((IR_GetMicroseconds() - tickstart) < us);
}
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&UartHandle, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
//配置计数器
void TIM14_Init(void)
{
__HAL_RCC_TIM14_CLK_ENABLE();
// 对于24MHz的系统时钟,分频到1MHz
TimHandle14.Instance = TIM14;
TimHandle14.Init.Prescaler = 24 - 1; // 24分频得到1MHz
TimHandle14.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle14.Init.Period = 0xffff; // 16位计数器
TimHandle14.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
TimHandle14.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
if (HAL_TIM_Base_Init(&TimHandle14) != HAL_OK)
{
APP_ErrorHandler();
}
// 清空计数器
__HAL_TIM_SET_COUNTER(&TimHandle14, 0);
// 启动定时器
HAL_TIM_Base_Start(&TimHandle14);
HAL_NVIC_SetPriority(TIM14_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(TIM14_IRQn);
}
//配置pwm发生器
void APP_TimPwmConfig(void)
{
__HAL_RCC_TIM1_CLK_ENABLE();
// 对于24MHz的系统时钟,分频到1MHz
TimHandle.Instance = TIM1;
TimHandle.Init.Prescaler = 24 - 1; // 24分频得到1MHz
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.Period = 1000-1; // 重载值
TimHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
TimHandle.Init.RepetitionCounter = 0;
TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
{
APP_ErrorHandler();
}
// 清空计数器
__HAL_TIM_SET_COUNTER(&TimHandle, 0);
// 启动定时器
HAL_TIM_Base_Start(&TimHandle);
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
/* OCN channel output high level effective */
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
/* Idle state OC1N output low level */
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
/* Idle state OC1 output low level*/
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.Pulse = 0;
/* Channel 1 configuration */
if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
APP_ErrorHandler();
}
sConfigOC.Pulse = 0;
/* Channel 2 configuration */
if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
APP_ErrorHandler();
}
sConfigOC.Pulse = 0;
/* Channel 3 configuration */
if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
APP_ErrorHandler();
}
sConfigOC.Pulse = 0;
/* Channel 4 configuration */
if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
{
APP_ErrorHandler();
}
HAL_TIM_PWM_Start(&TimHandle, RED_CHANNEL);
HAL_TIM_PWM_Start(&TimHandle, GREEN_CHANNEL);
HAL_TIM_PWM_Start(&TimHandle, BLUE_CHANNEL);
HAL_TIM_PWM_Start(&TimHandle, WHITE_CHANNEL);
__HAL_TIM_SET_COMPARE(&TimHandle, TIM_CHANNEL_1,1000); // 设置红色通道占空比
__HAL_TIM_SET_COMPARE(&TimHandle, TIM_CHANNEL_2,1000); // 设置绿色通道占空比
__HAL_TIM_SET_COMPARE(&TimHandle, TIM_CHANNEL_3, 1000); // 设置蓝色通道占空比
__HAL_TIM_SET_COMPARE(&TimHandle, TIM_CHANNEL_4, 1000); // 设置白色通道占空比
__HAL_TIM_MOE_ENABLE(&TimHandle);
}
// 设置RGB颜色
void set_rgb_color(uint16_t r, uint16_t g, uint16_t b) {
__HAL_TIM_SET_COMPARE(&TimHandle, RED_CHANNEL, r);
__HAL_TIM_SET_COMPARE(&TimHandle, GREEN_CHANNEL, g);
__HAL_TIM_SET_COMPARE(&TimHandle, BLUE_CHANNEL, b);
}
/**
* @brief TIM14更新中断处理函数
* @retval None
*/
void TIM14_IRQHandler(void)
{
// 只处理更新中断
if (__HAL_TIM_GET_FLAG(&TimHandle14, TIM_FLAG_UPDATE))
{
__HAL_TIM_CLEAR_FLAG(&TimHandle14, TIM_FLAG_UPDATE);
timer1_overflow_count++;
}
}
uint32_t millis(void)
{ return timer1_overflow_count; }
/**
* @brief 获取当前微秒数(使用TIM1实现)
* @retval 当前时间(us)
*/
uint32_t IR_GetMicroseconds(void)
{
uint32_t time;
do {
time = __HAL_TIM_GET_COUNTER(&TimHandle14);
} while(time != __HAL_TIM_GET_COUNTER(&TimHandle14));
return time;
}
// 计算两个时间点之间的差值
uint32_t Calculate_Duration(uint32_t current, uint32_t last)
{
if(current >= last) {
return current - last;
} else {
// 处理计数器溢出
return (0xFFFF - last) + current + 1;
}
}
void LED_Init(void)
{
// 1. 使能LED所在GPIO端口的时钟(根据实际端口修改)
__HAL_RCC_GPIOA_CLK_ENABLE(); // 若LED接GPIOA,则使能GPIOA时钟
// 2. 定义GPIO初始化结构体
GPIO_InitTypeDef GPIO_InitStruct;
// 3. 配置LED引脚参数
GPIO_InitStruct.Pin = GPIO_PIN_1; // 选择LED引脚
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出(适合驱动LED)
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上下拉(根据硬件电路决定)
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速模式(LED无需高速切换)
// 4. 初始化GPIO
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 5. 初始状态:关闭LED(根据硬件电路决定高低电平)
// 假设LED为高电平点亮:初始输出低电平=关闭
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1, GPIO_PIN_SET);
}
/**
* @brief EXTI中断服务函数(双边沿触发)
* @retval None
*/
void EXTI0_1_IRQHandler(void)
{
static uint32_t last_edge_time = 0;
static uint8_t last_pin_state = 1;
static uint8_t is_first_edge = 1; // 使用uint8_t代替bool
if (__HAL_GPIO_EXTI_GET_FLAG(GPIO_PIN_0) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_FLAG(GPIO_PIN_0);
uint32_t current_time = IR_GetMicroseconds();
uint8_t current_pin_state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);
if (is_first_edge)
{
is_first_edge = 0; // 使用0代替false
last_edge_time = current_time;
last_pin_state = current_pin_state;
printf("First edge: level=%d\n", current_pin_state);
return;
}
if (current_pin_state != last_pin_state) // 确认电平真的变化了
{
uint32_t duration = Calculate_Duration(current_time, last_edge_time);
// 过滤掉可能的噪声脉冲
if (duration >= 100) // 最小100us
{
IR_Decode(duration, current_pin_state);
}
last_edge_time = current_time;
last_pin_state = current_pin_state;
}
}
}
void Test_Timer_Accuracy(void)
{
uint32_t start, end, elapsed;
printf("Timer accuracy test:\r\n");
start = IR_GetMicroseconds();
HAL_Delay(1000); // 延时1秒
end = IR_GetMicroseconds();
elapsed = end - start;
printf("1000ms delay = %lu us\r\n", elapsed);
}
/**
* @brief 红外解码状态机
* @param duration: 脉冲持续时间(us)
* @param level_type: 电平类型 (1=高电平结束, 0=低电平结束)
* @retval None
*/
#define NEC_TOLERANCE 300
void IR_Decode(uint32_t duration, uint8_t level_type)
{
static uint8_t state = 0;
static uint8_t bit_index = 0;
static uint8_t data[4] = {0};
switch (state) {
case 0: // 等待引导码高电平
if (level_type == 1 && abs(duration - 9000) < NEC_TOLERANCE) {
state = 1;
}
break;
case 1: // 等待引导码低电平
if (level_type == 0 && abs(duration - 4500) < NEC_TOLERANCE) {
memset(data, 0, 4);
bit_index = 0;
state = 2;
} else if (level_type == 0 && abs(duration - 2250) < NEC_TOLERANCE) {
// 重复码
IR_ProcessRepeat();
state = 0;
} else {
state = 0;
}
break;
case 2: // 等待位高电平(560us)
if (level_type == 1 && abs(duration - 560) < NEC_TOLERANCE) {
state = 3;
} else {
state = 0;
}
break;
case 3: // 等待位低电平(判断逻辑0或1)
if (level_type == 0) {
if (abs(duration - 560) < NEC_TOLERANCE) {
// 逻辑0,不设置位
} else if (abs(duration - 1690) < NEC_TOLERANCE) {
// 逻辑1,设置位
data[bit_index / 8] |= (1 << (7 - (bit_index % 8)));
} else {
state = 0;
return;
}
bit_index++;
if (bit_index >= 32) {
memcpy(ir_data, data, 4);
IR_ProcessCommand();
state = 0;
} else {
state = 2;
}
}
break;
default:
state = 0;
break;
}
}
//串口
void MX_USART1_UART_Init(uint32_t bound)
{
UartHandle.Instance = USART1;
UartHandle.Init.BaudRate = bound;
UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
UartHandle.Init.StopBits = UART_STOPBITS_1;
UartHandle.Init.Parity = UART_PARITY_NONE;
UartHandle.Init.Mode = UART_MODE_TX_RX;
UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&UartHandle) != HAL_OK)
{
APP_ErrorHandler();
}
// 使能接收中断
__HAL_UART_ENABLE_IT(&UartHandle, UART_IT_RXNE);
}
void HAL_UART_spInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(huart->Instance==USART1)
{
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_USART1_CLK_ENABLE();
// -> USART_TX
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = DEBUG_USART_TX_AF;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// -> USART_RX
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Alternate = DEBUG_USART_RX_AF;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// 配置USART1中断
HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
}
// 白光呼吸任务函数
void warm_breath_task(void) {
if (keep_color != WARM_MODE) return;
static uint8_t direction = 1; // 1=渐暗, 0=渐亮
static uint8_t brightness = 0; // 0=最亮, 100=最暗
static uint32_t last_update = 0;
static uint8_t initialized = 0; // 用于初始化亮度
// 检查是否到达更新时间
if (HAL_GetTick() - last_update < breath_speed)
return;
last_update = HAL_GetTick();
// 获取当前亮度级别的最大值
const uint8_t max_bright = warm_max_brightness[warm_brightness_level];
// 初始化亮度为当前级别的最大值
if (!initialized) {
brightness = max_bright;
initialized = 1;
}
if (direction) {
// 渐暗 (亮度值增加)
if (brightness < 100) { // 最大亮度为100
brightness++;
} else {
direction = 0; // 切换为渐亮
}
} else {
// 渐亮 (亮度值减小)
if (brightness > max_bright) {
brightness--;
} else {
direction = 1; // 切换为渐暗
}
}
// 设置白灯亮度(RGB关闭)
set_led_color(100, 100, 100, brightness);
printf("速率:%d ms, 亮度:%d\n", breath_speed, brightness);
}
static void rgbw_fade_task(void)
{
if (keep_color != 1) {
return;
}
// 根据当前组索引获取目标颜色
const uint16_t *tar = color_groups[current_color_group][group_step_idx];
uint8_t done = 1;
for (uint8_t ch = 0; ch < 4; ch++) {
if (cur[ch] < tar[ch]) {
cur[ch] += 5; // 步进递增
if (cur[ch] > tar[ch]) cur[ch] = tar[ch];
done = 0;
} else if (cur[ch] > tar[ch]) {
cur[ch] -= 5; // 步进递减
if (cur[ch] < tar[ch]) cur[ch] = tar[ch];
done = 0;
}
}
// 设置当前颜色(转换为0-100范围)
set_led_color(
cur[0] / 10,
cur[1] / 10,
cur[2] / 10,
cur[3] / 10
);
// 颜色切换条件:当前颜色已到达目标,且停留时间超过1秒
if (done && (HAL_GetTick() - last_tick > 1000)) {
// 切换到组内下一种颜色(0-6循环)
group_step_idx = (group_step_idx + 1) % 7;
last_tick = HAL_GetTick();
}
}
// 多组七彩渐变函数
void multi_group_gradient(uint8_t speed)
{
// 从当前组获取起始色和目标色
const uint8_t *from = gradient_groups[current_gradient_group][gradient_from_idx];
const uint8_t *to = gradient_groups[current_gradient_group][gradient_to_idx];
// 计算当前步骤的RGBW值(线性插值)
uint8_t current_r = from[0] + (to[0] - from[0]) * gradient_step / 100;
uint8_t current_g = from[1] + (to[1] - from[1]) * gradient_step / 100;
uint8_t current_b = from[2] + (to[2] - from[2]) * gradient_step / 100;
uint8_t current_w = from[3] + (to[3] - from[3]) * gradient_step / 100;
// 设置当前颜色
set_led_color(current_r, current_g, current_b, current_w);
// 步骤递增
gradient_step++;
if (gradient_step > 100)
{
gradient_step = 0;
// 切换到组内下一对颜色(循环7种颜色)
gradient_from_idx = gradient_to_idx;
gradient_to_idx = (gradient_to_idx + 1) % 7;
}
// 控制渐变速度
HAL_Delay(speed);
}
// 更新渐变任务调用
void gradient_task(void)
{
multi_group_gradient(30); // 调用多组渐变函数,速度30ms
}
// 三色跳变任务函数(在main循环中调用)
void color_jump_task(void)
{
// 仅在跳变模式(keep_color=6)下执行
if (keep_color != 6) return;
// 检查是否到达跳变时间
if (HAL_GetTick() - jump_timer >= jump_interval)
{
// 切换到组内下一种颜色
current_jump_color = (current_jump_color + 1) % 3;
// 设置当前颜色
set_led_color(
jump_color_groups[jump_group_index][current_jump_color][0],
jump_color_groups[jump_group_index][current_jump_color][1],
jump_color_groups[jump_group_index][current_jump_color][2],
jump_color_groups[jump_group_index][current_jump_color][3]
);
// 重置计时器
jump_timer = HAL_GetTick();
}
}
void reset_timer(void) {
timer_state = TIMER_IDLE;
timer_duration = 0;
timer_end_time = 0;
printf("定时器已重置\n");
}
// 添加定时器状态处理函数
void timer_task(void)
{
switch (timer_state) {
case TIMER_GRADIENT:
// 显示红绿蓝渐变效果
if (HAL_GetTick() - gradient_start_time > 500) { // 每100ms更新一次
gradient_start_time = HAL_GetTick();
switch (gradient_steps) {
case 0: // 红色
set_led_color(0, 100, 100, 100);
break;
case 1: // 绿色
set_led_color(100, 0, 100, 100);
break;
case 2: // 蓝色
set_led_color(100, 100, 0, 100);
break;
case 3: // 恢复原状态
// 启动定时器
timer_state = TIMER_RUNNING;
timer_end_time = HAL_GetTick() + (timer_duration * 3600000); // 转换为毫秒
printf("定时器启动,将在 %d 小时后关灯\n", timer_duration);
// 恢复原状态
keep_color = pre_timer_mode;
set_led_color(pre_timer_r, pre_timer_g, pre_timer_b, pre_timer_w);
return;
}
gradient_steps++;
}
break;
case TIMER_RUNNING:
// 检查是否到达定时结束时间
if (HAL_GetTick() >= timer_end_time) {
timer_state = TIMER_EXPIRED;
printf("定时结束,关闭灯光\n");
// 关闭所有灯光
led_off();
}
break;
case TIMER_EXPIRED:
// 5秒后自动重置定时器
if (HAL_GetTick() - timer_end_time > 5000) {
timer_state = TIMER_IDLE;
printf("定时器已重置,可重新设置\n");
}
break;
default:
break;
}
}
/**
* @brief Main program.
* @retval int
*/
int main(void)
{
HAL_Init();
APP_SystemClockConfig();
__HAL_RCC_USART1_CLK_ENABLE(); // 确保USART1时钟先使能
MX_USART1_UART_Init(115200);
HAL_UART_spInit(&UartHandle);
// HAL_Delay(100);
//串口初始化
// HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_1);
// 初始化TIM1用于微秒级计时
TIM14_Init();
// 初始化GPIO和EXTI
APP_GpioConfig();
APP_TimPwmConfig();
// 测试定时器精度
// Test_Timer_Accuracy();
// 初始化LED
LED_Init();
current_gradient_group = 0;
gradient_from_idx = 0;
gradient_to_idx = 1;
gradient_step = 0;
// 初始化为第1组第一种颜色
current_color_group = 0;
group_step_idx = 0;
// 初始化当前占空比数组
memcpy(cur, color_groups[0][0], sizeof(cur));
// 初始关闭LED
set_led_color(0, 0, 0, 0);
printf("holle world\r\n");
//light_seven();
//set_led_color(0, 0, 0, 0); // 初始关闭所有LED
while (1)
{
// 处理定时器任务
timer_task();
// 如果定时器处于渐变状态,跳过其他任务
if (timer_state != TIMER_GRADIENT && timer_state != TIMER_EXPIRED) {
// 原有模式处理...
if (keep_color == 0) {
gradient_task(); // 渐变
} else if (keep_color == 1) {
rgbw_fade_task(); // 跳变
} else if (keep_color == 6) {
color_jump_task(); // 三色跳变
} else if (keep_color == WARM_MODE) {
warm_breath_task(); // 白光呼吸
}
}
}
}
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&UartHandle);
}
static void APP_SystemClockConfig(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_24MHz;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSISYS;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
}
static void APP_GpioConfig(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
// 配置红,绿,蓝引脚
GPIO_InitStruct.Pin = LED_ALL_PINS;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM1; //复用为TIM1
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//配置白引脚
GPIO_InitStruct.Pin = LED_WHITE_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF3_TIM1; //复用为TIM1
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// 配置红外接收引脚(PA0)为双边沿触发
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置外部中断
HAL_NVIC_SetPriority(EXTI0_1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
}
/**
* @brief 设置LED颜色
* @param r: 红色分量 (0-100)
* @param g: 绿色分量 (0-100)
* @param b: 蓝色分量 (0-100)
* @param w: 白色分量 (0-100)
* @retval None
*/
void set_led_color(uint8_t r, uint8_t g, uint8_t b, uint8_t w)
{
color_r = r; color_g = g; color_b = b; color_w = w;
uint16_t rr = (uint16_t)r * PWM_MAX / 100 ;
uint16_t gg = (uint16_t)g * PWM_MAX / 100 ;
uint16_t bb = (uint16_t)b * PWM_MAX / 100 ;
uint16_t ww = (uint16_t)w * PWM_MAX / 100 ;
// uint16_t ww = PWM_MAX - (uint16_t)w * PWM_MAX / 100 ; // 反转计算
__HAL_TIM_SET_COMPARE(&TimHandle, RED_CHANNEL, rr);
__HAL_TIM_SET_COMPARE(&TimHandle, GREEN_CHANNEL, gg);
__HAL_TIM_SET_COMPARE(&TimHandle, BLUE_CHANNEL, bb);
__HAL_TIM_SET_COMPARE(&TimHandle, WHITE_CHANNEL, ww);
}
// 12种DIY颜色(每组4种,共3组)
static const uint8_t diy_colors[4][4][4] = {
// R组(KEY_RED)
{
{100, 0, 0, 0}, // 纯红
{100, 30, 0, 0}, // 红橙
{100, 0, 30, 0}, // 红紫
{100, 50, 0, 0} // 深红
},
// G组(KEY_GREEN)
{
{0, 100, 0, 0}, // 纯绿
{30, 100, 0, 0}, // 黄绿
{0, 100, 30, 0}, // 青绿
{50, 100, 0, 0} // 草绿
},
// B组(KEY_BLUE)
{
{0, 0, 100, 0}, // 纯蓝
{30, 0, 100, 0}, // 紫蓝
{0, 30, 100, 0}, // 天蓝
{0, 0, 100, 50} // 冰蓝
},
{
{100, 100, 100, 0}, // 纯蓝
{71, 84, 100, 45}, // 暖白 - 偏黄红色调
{44,68, 100, 88}, // 正白 - 均衡色调
}
};
static uint8_t color_index[4] = {0}; // 每组当前颜色索引
/**
* @brief 关闭所有LED
* @retval None
*/
void led_off(void)
{
HAL_TIM_PWM_Stop(&TimHandle, RED_CHANNEL);
HAL_TIM_PWM_Stop(&TimHandle, GREEN_CHANNEL);
HAL_TIM_PWM_Stop(&TimHandle, BLUE_CHANNEL);
HAL_TIM_PWM_Stop(&TimHandle, WHITE_CHANNEL);
//HAL_TIM_Base_Start(&TimHandle);
}
void led_extinct(void)
{
set_led_color(100,100,100,100);
}
void three_color (void)
{
led_off();
HAL_TIM_PWM_Start(&TimHandle, RED_CHANNEL);
led_off();
HAL_TIM_PWM_Start(&TimHandle, GREEN_CHANNEL);
}
/**
* @brief 处理解码后的指令
* @retval None
*/
void IR_ProcessCommand(void)
{
// 如果定时器处于渐变状态,忽略所有按键
if (timer_state == TIMER_GRADIENT) {
printf("渐变中,忽略按键\n");
return;
}
// 如果定时器已到期,只响应KEY_ON
if (timer_state == TIMER_EXPIRED && ir_data[2] != KEY_ON) {
printf("灯光已关闭,请按ON键开启\n");
return; // 忽略其他按键
}
ir_last_cmd = ir_data[2]; // 保存命令
// 打印完整的NEC协议数据帧
printf("\r\n=== IR Code Received ===\r\n");
printf("Address: 0x%02X%02X\r\n", ir_data[0], ir_data[1]);
printf("Command: 0x%02X\r\n", ir_data[2]);
printf("Cmd Inverse: 0x%02X\r\n", ir_data[3]);
printf("=====================\r\n");
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_1);
// 验证命令码和其反码是否匹配
if(ir_data[2] != (uint8_t)(~ir_data[3])) {
printf("Warning: Command verification failed!\r\n");
return;
}
switch (ir_last_cmd) {
case KEY_OFF:
// 保存当前颜色
saved_r = color_r;
saved_g = color_g;
saved_b = color_b;
saved_w = color_w ;
led_off();
led_extinct();
break;
case KEY_ON:
// 如果定时器已到期,恢复定时前的状态
if (timer_state == TIMER_EXPIRED) {
timer_state = TIMER_IDLE;
// 恢复PWM输出
HAL_TIM_PWM_Start(&TimHandle, RED_CHANNEL);
HAL_TIM_PWM_Start(&TimHandle, GREEN_CHANNEL);
HAL_TIM_PWM_Start(&TimHandle, BLUE_CHANNEL);
HAL_TIM_PWM_Start(&TimHandle, WHITE_CHANNEL);
// 恢复之前的状态
keep_color = pre_timer_mode;
set_led_color(pre_timer_r, pre_timer_g, pre_timer_b, pre_timer_w);
printf("恢复定时前状态\n");
} else {
// 正常处理KEY_ON
HAL_TIM_PWM_Start(&TimHandle, RED_CHANNEL);
HAL_TIM_PWM_Start(&TimHandle, GREEN_CHANNEL);
HAL_TIM_PWM_Start(&TimHandle, BLUE_CHANNEL);
HAL_TIM_PWM_Start(&TimHandle, WHITE_CHANNEL);
set_led_color(saved_r, saved_g, saved_b, saved_w);
}
break;
case KEY_RED:
keep_color =2;
//led_extinct();
set_led_color(0, 100, 100, 100);
break;
case KEY_FLASH:
// 切换到下一组,第5次按回归第1组(0-3循环)
current_color_group = (current_color_group + 1) % 4;
// 重置组内颜色索引,从第一种颜色开始
group_step_idx = 0;
// 立即切换到新组的第一种颜色
set_led_color(
color_groups[current_color_group][group_step_idx][0] / 10, // 转换为0-100范围
color_groups[current_color_group][group_step_idx][1] / 10,
color_groups[current_color_group][group_step_idx][2] / 10,
color_groups[current_color_group][group_step_idx][3] / 10
);
// 重置跳变计时器
last_tick = HAL_GetTick();
// 打印当前组信息
printf("切换到七彩跳变组合 %d/4\r\n", current_color_group + 1);
// 激活七彩跳变模式
keep_color = 1;
break;
case KEY_GREEN:
keep_color =3;
led_extinct();
//HAL_TIM_PWM_Start(&TimHandle, GREEN_CHANNEL);
set_led_color(100, 0, 100, 100);
break;
case KEY_BLUE:
keep_color =4;
led_extinct();
//HAL_TIM_PWM_Start(&TimHandle, BLUE_CHANNEL);
set_led_color(100, 100, 0, 100);
break;
case KEY_WHITE:
keep_color =5;
led_extinct();
//HAL_TIM_PWM_Start(&TimHandle, WHITE_CHANNEL);
set_led_color(100, 100, 100, 0);
break;
case KEY_BRIGHT_UP:
switch(keep_color) {
case 2: // 当前为红色
color_r = (color_r < 5) ? 0 : color_r - 5;
break;
case 3: // 当前为绿色
color_g = (color_g < 5) ? 0 : color_g - 5;
break;
case 4: // 当前为蓝色
color_b = (color_b < 5) ? 0 : color_b - 5;
break;
case 5: // 当前为白色
color_w = (color_w < 5) ? 0 : color_w - 5;
break;
}
set_led_color(color_r, color_g, color_b, color_w); // 刷新显示
break;
case KEY_BRIGHT_DN:
switch(keep_color) {
case 2: // 当前为红色
color_r = (color_r + 15 > 90) ? 90 : color_r + 15;
break;
case 3: // 当前为绿色
color_g = (color_g + 15 > 90) ? 90 : color_g + 15;
break;
case 4: // 当前为蓝色
color_b = (color_b + 15 > 90) ? 90 : color_b + 15;
break;
case 5: // 当前为白色
color_w = (color_w + 15 > 90) ? 90: color_w + 15;
break;
}
set_led_color(color_r, color_g, color_b, color_w); // 刷新显示
break;
case KEY_WARM:
// 切换到白光呼吸模式
keep_color = 7;
// 循环切换三种亮度等级
warm_brightness_level = (warm_brightness_level + 1) % WARM_BRIGHTNESS_LEVELS;
printf("白光呼吸模式: 亮度等级 %d/%d (最大亮度 %d%%)\r\n",
warm_brightness_level + 1, WARM_BRIGHTNESS_LEVELS,
warm_max_brightness[warm_brightness_level]);
break;
case KEY_TIMER:
// 允许在空闲、渐变结束或定时结束状态下设置定时
if (timer_state == TIMER_IDLE || timer_state == TIMER_EXPIRED) {
printf("定时按键被按下\n");
// 重置定时器状态
timer_state = TIMER_SETTING;
timer_duration = 0; // 重置定时时长
// 增加定时时长(2小时步进,循环0-12小时)
timer_duration = (timer_duration + 2) % 14;
if (timer_duration == 0) timer_duration = 2; // 跳过0小时
// 保存当前灯光状态(仅在未过期时)
if (timer_state != TIMER_EXPIRED) {
pre_timer_mode = keep_color;
pre_timer_r = color_r;
pre_timer_g = color_g;
pre_timer_b = color_b;
pre_timer_w = color_w;
}
// 进入渐变显示状态
timer_state = TIMER_GRADIENT;
gradient_start_time = HAL_GetTick();
gradient_steps = 0; // 重置渐变步骤计数器
printf("定时设置: %d小时后关灯\n", timer_duration);
}
break;
case KEY_SPEED_UP:
breath_speed = (breath_speed > 5) ? breath_speed - 5 : 5;
printf("呼吸加快: %d ms\n", breath_speed);
break;
case KEY_SPEED_DOWN:
printf("11111111111\r\n");
breath_speed = (breath_speed < 100) ? breath_speed + 10 : 100;
printf("呼吸加快: %d ms\n", breath_speed);
break;
case KEY_SMOOTH:
// 切换到下一组渐变,第5次按回归第1组(0-3循环)
current_gradient_group = (current_gradient_group + 1) % 4;
// 重置渐变参数,从新组第1种颜色开始
gradient_from_idx = 0;
gradient_to_idx = 1;
gradient_step = 0;
// 立即显示新组的起始颜色
set_led_color(
gradient_groups[current_gradient_group][0][0],
gradient_groups[current_gradient_group][0][1],
gradient_groups[current_gradient_group][0][2],
gradient_groups[current_gradient_group][0][3]
);
// 打印当前组信息
printf("切换到七彩渐变组合 %d/4\r\n", current_gradient_group + 1);
// 激活渐变模式
keep_color = 0;
break;
case KEY_MAGENTA:
// 切换到下一组组合,第7次按回归第1组
jump_group_index = (jump_group_index + 1) % 6;
// 重置当前组内颜色索引,从第一种颜色开始
current_jump_color = 0;
// 立即切换到新组的第一种颜色
set_led_color(
jump_color_groups[jump_group_index][current_jump_color][0],
jump_color_groups[jump_group_index][current_jump_color][1],
jump_color_groups[jump_group_index][current_jump_color][2],
jump_color_groups[jump_group_index][current_jump_color][3]
);
// 重置计时器
jump_timer = HAL_GetTick();
// 打印当前组合信息
printf("切换到三色跳变组合 %d/6\r\n", jump_group_index + 1);
// 激活跳变模式
keep_color = 6;
break;
default:
// 未知命令
break;
}
}
/**
* @brief 处理重复码
* @retval None
*/
void IR_ProcessRepeat(void)
{
ir_last_cmd = ir_data[2]; // 保存命令
printf("Command: 0x%02X\r\n", ir_data[2]);
static uint32_t last_repeat_time = 0;
if (HAL_GetTick() - last_repeat_time < 500) return;
last_repeat_time = HAL_GetTick();
switch (ir_last_cmd) {
case KEY_RED:
color_index[0] = (color_index[0] + 1) % 4;
set_led_color(
diy_colors[0][color_index[0]][0],
diy_colors[0][color_index[0]][1],
diy_colors[0][color_index[0]][2],
diy_colors[0][color_index[0]][3]
);
break;
case KEY_GREEN:
color_index[1] = (color_index[1] + 1) % 4;
set_led_color(
diy_colors[1][color_index[1]][0],
diy_colors[1][color_index[1]][1],
diy_colors[1][color_index[1]][2],
diy_colors[1][color_index[1]][3]
);
break;
case KEY_BLUE:
color_index[2] = (color_index[2] + 1) % 4;
set_led_color(
diy_colors[2][color_index[2]][0],
diy_colors[2][color_index[2]][1],
diy_colors[2][color_index[2]][2],
diy_colors[2][color_index[2]][3]
);
break;
case KEY_WHITE:
color_index[3] = (color_index[3] + 1) % 4;
set_led_color(
diy_colors[3][color_index[3]][0],
diy_colors[3][color_index[3]][1],
diy_colors[3][color_index[3]][2],
diy_colors[3][color_index[3]][3]
);
break;
default:
break;
}
}
/**
* @brief Error executing function.
* @param None
* @retval None
*/
void APP_ErrorHandler(void)
{
while (1)
{
}
}
为什么我使用定时按键只能定时一次
最新发布