KT24-1110_65E-HA-651B/cpu/br25/ledc_test.c
2024-11-10 18:44:17 +08:00

444 lines
19 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#if 0
#include "system/includes.h"
#include "audio_spectrum.h"
#define LED_NUM_MAX (18 * 6)
static u8 led_rgb_val_buf[24 * LED_NUM_MAX] __attribute__((aligned(4)));
void led_spi_init(void);
void led_spi_send_rgbbuf_isr(u8 *rgb_buf, u16 led_num);
void led_spi_rgb_to_24byte(u8 r, u8 g, u8 b, u8 *buf, int idx);
/***********************************************************************************************
* 接口替换区
***********************************************************************************************/
#define led_init() led_spi_init()
#define led_rgb_to_buf(r,g,b,buf,idx) led_spi_rgb_to_24byte(r,g,b,buf,idx)
#define led_send_rgbbuf(buf,num) led_spi_send_rgbbuf_isr(buf,num)
/***********************************************************************************************
******** **
r: * * *
* * *
******* ********
** ********
g: * * *
* * *
******* ********
****** ********
b: * * *
* * *
******* ****
* 流水灯控制驱动原理:
*1. 每个模式都会一个周期 ***********
*2. 以一个灯为例,一个模式周期内,又分三个颜色,即每个颜色各有各的周期。 * *
*3. 最核心的思维是:一个灯的三个颜色的地位是相等的,灯与灯之间,每个灯的地位是相等。 * *
*4. 每个颜色在一个周期里分为几个阶段:最暗到最亮,最亮维持,最亮到最暗,最暗维持 ******** *******
*5. 颜色之间可以存在相位差,
*6. 灯与灯之间的计数值可以存在相位差
***********************************************************************************************/
struct led_rgb_t {
u8 mode_idx; //灯亮的模式号
u8 div_sec_num; //一条灯带分几段
u8 sec_led_num; //每段灯带几个灯
u8 cnt_freq; //CNT多久加一次单位10ms这个值越大灯变化越慢
u8 rgb_val_max[3]; //可配置某颜色值的最大值一般是255
u8 rgb_val_min[3]; //可配置某颜色值的最大值一般是0
int cnt[3]; //单个灯颜色的变化计数值cnt的初值就是三个颜色的相位差。
int next_cnt_dir[3]; //同个颜色灯与灯之间的传递方向和传递间隔, 下一个灯的cnt是上一个灯的cnt+next_cnt_dir
int next_sec_cnt_phase[3]; //同个颜色段与段之间的相位差,即下一段灯带的颜色cnt初始值是上一段灯带的cnt+next_sec_cnt_phase
int cnt_unit[3]; //CNT加一次加多少这个值越大灯变化越快CNT加到最大周期值后又从0开始加
int cnt_max_prd[3]; //一个颜色的整个模式的周期, 不管CNT怎么加都映射在这个周期里即cnt %= cnt_max_prd
int pu_cnt_start[3]; //一个周期内,颜色值上升开始的时间,即这个颜色开始亮了
int pu_cnt_end[3]; //一个周期内,颜色值上升结束的时间,即颜色值达到最大值
int keep_cnt_start[3]; //一个周期内,颜色值维持最大的开始时间,一般为颜色值上升结束的时间
int keep_cnt_end[3]; //一个周期内,颜色值维持最大的结束时间
int pd_cnt_start[3]; //一个周期内,颜色值下降开始的时间,一般为颜色值维持最大的结束时间
int pd_cnt_end[3]; //一个周期内颜色值下降结束的时间即颜色值没有为0了
};
static struct led_rgb_t mode0_led_rgb = {
.mode_idx = 0,
.div_sec_num = 6,
.sec_led_num = 18,
.cnt_freq = 1,
//r:
.rgb_val_max[ 0] = 255, .rgb_val_min[ 0] = 0,
.cnt[ 0] = 0, .next_cnt_dir[ 0] = -10,
.cnt_unit[ 0] = 1, .cnt_max_prd[ 0] = 90,
.pu_cnt_start[ 0] = 0, .pu_cnt_end[ 0] = 30,
.keep_cnt_start[0] = 30, .keep_cnt_end[ 0] = 30,
.pd_cnt_start[ 0] = 30, .pd_cnt_end[ 0] = 60,
//g:
.rgb_val_max[ 1] = 255, .rgb_val_min[ 1] = 0,
.cnt[ 1] = 30, .next_cnt_dir[ 1] = -10,
.cnt_unit[ 1] = 1, .cnt_max_prd[ 1] = 90,
.pu_cnt_start[ 1] = 0, .pu_cnt_end[ 1] = 30,
.keep_cnt_start[1] = 30, .keep_cnt_end[ 1] = 30,
.pd_cnt_start[ 1] = 30, .pd_cnt_end[ 1] = 60,
//b:
.rgb_val_max[ 2] = 255, .rgb_val_min[ 2] = 0,
.cnt[ 2] = 60, .next_cnt_dir[ 2] = -10,
.cnt_unit[ 2] = 1, .cnt_max_prd[ 2] = 90,
.pu_cnt_start[ 2] = 0, .pu_cnt_end[ 2] = 30,
.keep_cnt_start[2] = 30, .keep_cnt_end[ 2] = 30,
.pd_cnt_start[ 2] = 30, .pd_cnt_end[ 2] = 60,
};
static struct led_rgb_t mode1_led_rgb = {
.mode_idx = 1,
.div_sec_num = 6,
.sec_led_num = 18,
.cnt_freq = 1,
//r:
.rgb_val_max[ 0] = 255, .rgb_val_min[ 0] = 0,
.cnt[ 0] = 0, .next_cnt_dir[ 0] = 6,
.cnt_unit[ 0] = 1, .cnt_max_prd[ 0] = 108,
.pu_cnt_start[ 0] = 0, .pu_cnt_end[ 0] = 0,
.keep_cnt_start[0] = 0, .keep_cnt_end[ 0] = 54,
.pd_cnt_start[ 0] = 54, .pd_cnt_end[ 0] = 54,
//g:
.rgb_val_max[ 1] = 255, .rgb_val_min[ 1] = 0,
.cnt[ 1] = 36, .next_cnt_dir[ 1] = 6,
.cnt_unit[ 1] = 1, .cnt_max_prd[ 1] = 108,
.pu_cnt_start[ 1] = 0, .pu_cnt_end[ 1] = 0,
.keep_cnt_start[1] = 0, .keep_cnt_end[ 1] = 54,
.pd_cnt_start[ 1] = 54, .pd_cnt_end[ 1] = 54,
//b:
.rgb_val_max[ 2] = 255, .rgb_val_min[ 2] = 0,
.cnt[ 2] = 72, .next_cnt_dir[ 2] = 6,
.cnt_unit[ 2] = 1, .cnt_max_prd[ 2] = 108,
.pu_cnt_start[ 2] = 0, .pu_cnt_end[ 2] = 0,
.keep_cnt_start[2] = 0, .keep_cnt_end[ 2] = 54,
.pd_cnt_start[ 2] = 54, .pd_cnt_end[ 2] = 54,
};
static struct led_rgb_t mode2_led_rgb = {
.mode_idx = 2,
.div_sec_num = 6,
.sec_led_num = 18,
.cnt_freq = 1,
//r:
.rgb_val_max[ 0] = 255, .rgb_val_min[ 0] = 0,
.cnt[ 0] = 0, .next_cnt_dir[ 0] = -5,
.cnt_unit[ 0] = 1, .cnt_max_prd[ 0] = 90,
.pu_cnt_start[ 0] = 0, .pu_cnt_end[ 0] = 0,
.keep_cnt_start[0] = 0, .keep_cnt_end[ 0] = 30,
.pd_cnt_start[ 0] = 30, .pd_cnt_end[ 0] = 30,
//g:
.rgb_val_max[ 1] = 255, .rgb_val_min[ 1] = 0,
.cnt[ 1] = 30, .next_cnt_dir[ 1] = -5,
.cnt_unit[ 1] = 1, .cnt_max_prd[ 1] = 90,
.pu_cnt_start[ 1] = 0, .pu_cnt_end[ 1] = 0,
.keep_cnt_start[1] = 0, .keep_cnt_end[ 1] = 30,
.pd_cnt_start[ 1] = 30, .pd_cnt_end[ 1] = 30,
//b:
.rgb_val_max[ 2] = 255, .rgb_val_min[ 2] = 0,
.cnt[ 2] = 60, .next_cnt_dir[ 2] = -5,
.cnt_unit[ 2] = 1, .cnt_max_prd[ 2] = 90,
.pu_cnt_start[ 2] = 0, .pu_cnt_end[ 2] = 0,
.keep_cnt_start[2] = 0, .keep_cnt_end[ 2] = 30,
.pd_cnt_start[ 2] = 30, .pd_cnt_end[ 2] = 30,
};
static struct led_rgb_t mode3_led_rgb = {
.mode_idx = 3,
.div_sec_num = 6,
.sec_led_num = 18,
.cnt_freq = 1,
//r:
.rgb_val_max[ 0] = 255, .rgb_val_min[ 0] = 0,
.cnt[ 0] = 0, .next_cnt_dir[ 0] = 2,
.cnt_unit[ 0] = 1, .cnt_max_prd[ 0] = 108,
.pu_cnt_start[ 0] = 0, .pu_cnt_end[ 0] = 0,
.keep_cnt_start[0] = 0, .keep_cnt_end[ 0] = 36,
.pd_cnt_start[ 0] = 36, .pd_cnt_end[ 0] = 36,
//g:
.rgb_val_max[ 1] = 255, .rgb_val_min[ 1] = 0,
.cnt[ 1] = 36, .next_cnt_dir[ 1] = 2,
.cnt_unit[ 1] = 1, .cnt_max_prd[ 1] = 108,
.pu_cnt_start[ 1] = 0, .pu_cnt_end[ 1] = 0,
.keep_cnt_start[1] = 0, .keep_cnt_end[ 1] = 36,
.pd_cnt_start[ 1] = 36, .pd_cnt_end[ 1] = 36,
//b:
.rgb_val_max[ 2] = 255, .rgb_val_min[ 2] = 0,
.cnt[ 2] = 72, .next_cnt_dir[ 2] = 2,
.cnt_unit[ 2] = 1, .cnt_max_prd[ 2] = 108,
.pu_cnt_start[ 2] = 0, .pu_cnt_end[ 2] = 0,
.keep_cnt_start[2] = 0, .keep_cnt_end[ 2] = 36,
.pd_cnt_start[ 2] = 36, .pd_cnt_end[ 2] = 36,
};
static struct led_rgb_t mode4_led_rgb = {
.mode_idx = 4,
.div_sec_num = 6,
.sec_led_num = 18,
.cnt_freq = 1,
//r:
.rgb_val_max[ 0] = 255, .rgb_val_min[ 0] = 0,
.cnt[ 0] = 0, .next_cnt_dir[ 0] = -12,
.cnt_unit[ 0] = 1, .cnt_max_prd[ 0] = 108,
.pu_cnt_start[ 0] = 0, .pu_cnt_end[ 0] = 12,
.keep_cnt_start[0] = 12, .keep_cnt_end[ 0] = 24,
.pd_cnt_start[ 0] = 24, .pd_cnt_end[ 0] = 36,
//g:
.rgb_val_max[ 1] = 255, .rgb_val_min[ 1] = 0,
.cnt[ 1] = 36, .next_cnt_dir[ 1] = -12,
.cnt_unit[ 1] = 1, .cnt_max_prd[ 1] = 108,
.pu_cnt_start[ 1] = 0, .pu_cnt_end[ 1] = 12,
.keep_cnt_start[1] = 12, .keep_cnt_end[ 1] = 24,
.pd_cnt_start[ 1] = 24, .pd_cnt_end[ 1] = 36,
//b:
.rgb_val_max[ 2] = 255, .rgb_val_min[ 2] = 0,
.cnt[ 2] = 72, .next_cnt_dir[ 2] = -12,
.cnt_unit[ 2] = 1, .cnt_max_prd[ 2] = 108,
.pu_cnt_start[ 2] = 0, .pu_cnt_end[ 2] = 12,
.keep_cnt_start[2] = 12, .keep_cnt_end[ 2] = 24,
.pd_cnt_start[ 2] = 24, .pd_cnt_end[ 2] = 36,
};
static struct led_rgb_t mode5_led_rgb = {
.mode_idx = 5,
.div_sec_num = 6,
.sec_led_num = 18,
.cnt_freq = 1,
//r:
.rgb_val_max[ 0] = 255, .rgb_val_min[ 0] = 0,
.cnt[ 0] = 0, .next_cnt_dir[ 0] = 2,
.cnt_unit[ 0] = 1, .cnt_max_prd[ 0] = 108,
.pu_cnt_start[ 0] = 0, .pu_cnt_end[ 0] = 0,
.keep_cnt_start[0] = 0, .keep_cnt_end[ 0] = 2,
.pd_cnt_start[ 0] = 2, .pd_cnt_end[ 0] = 2,
//g:
.rgb_val_max[ 1] = 255, .rgb_val_min[ 1] = 0,
.cnt[ 1] = 36, .next_cnt_dir[ 1] = 2,
.cnt_unit[ 1] = 1, .cnt_max_prd[ 1] = 108,
.pu_cnt_start[ 1] = 0, .pu_cnt_end[ 1] = 0,
.keep_cnt_start[1] = 0, .keep_cnt_end[ 1] = 2,
.pd_cnt_start[ 1] = 2, .pd_cnt_end[ 1] = 2,
//b:
.rgb_val_max[ 2] = 255, .rgb_val_min[ 2] = 0,
.cnt[ 2] = 72, .next_cnt_dir[ 2] = 2,
.cnt_unit[ 2] = 1, .cnt_max_prd[ 2] = 108,
.pu_cnt_start[ 2] = 0, .pu_cnt_end[ 2] = 0,
.keep_cnt_start[2] = 0, .keep_cnt_end[ 2] = 2,
.pd_cnt_start[ 2] = 2, .pd_cnt_end[ 2] = 2,
};
static struct led_rgb_t mode6_led_rgb = {
.mode_idx = 6,
.div_sec_num = 4,
.sec_led_num = 6,
.cnt_freq = 1,
//r:
.rgb_val_max[ 0] = 255, .rgb_val_min[ 0] = 200,
.cnt[ 0] = 0, .next_cnt_dir[ 0] = -18,
.cnt_unit[ 0] = 1, .cnt_max_prd[ 0] = 48,
.pu_cnt_start[ 0] = 0, .pu_cnt_end[ 0] = 0,
.keep_cnt_start[0] = 0, .keep_cnt_end[ 0] = 24,
.pd_cnt_start[ 0] = 24, .pd_cnt_end[ 0] = 24,
.next_sec_cnt_phase[0] = 18,
//g:
.rgb_val_max[ 1] = 128, .rgb_val_min[ 1] = 32,
.cnt[ 1] = 0, .next_cnt_dir[ 1] = 18,
.cnt_unit[ 1] = 0, .cnt_max_prd[ 1] = 108,
.pu_cnt_start[ 1] = 0, .pu_cnt_end[ 1] = 0,
.keep_cnt_start[1] = 0, .keep_cnt_end[ 1] = 1,
.pd_cnt_start[ 1] = 1, .pd_cnt_end[ 1] = 108,
};
static struct led_rgb_t mode7_led_rgb = {
.mode_idx = 7,
.div_sec_num = 6,
.sec_led_num = 18,
.cnt_freq = 1,
//r:
.rgb_val_max[ 0] = 255, .rgb_val_min[ 0] = 255,
};
struct led_rgb_t *led_rgb_table[] = {
&mode0_led_rgb,//流水灯
&mode1_led_rgb,//流水灯
&mode2_led_rgb,//流水灯
&mode3_led_rgb,//流水灯
&mode4_led_rgb,//流水灯
&mode5_led_rgb,//流水灯
&mode6_led_rgb,//用于4X6火焰效果
&mode7_led_rgb,//用于显示播歌的频点能量
};
extern spectrum_fft_hdl *spec_hdl;
static short db_data_old[32];
static short led_on_table[32];
/*
* @brief 获取频谱能量,板级头文件要定义音频的宏#define AUDIO_SPECTRUM_CONFIG 1 //频响能量值获取接口
* @param p 音频接口的结构体参数
*/
void led_get_spectrum(void *p)
{
spectrum_fft_hdl *hdl = p;
if (hdl) {
u8 db_num = audio_spectrum_fft_get_num(hdl);//获取频谱个数
short *db_data = audio_spectrum_fft_get_val(hdl);//获取存储频谱值得地址
if (!db_data) {
return;
}
for (int i = 0; i < db_num; i++) {
if (i < 32) {
led_on_table[i] = db_data[i] - db_data_old[i];
db_data_old[i] = db_data[i];
}
}
}
}
/*
* @brief 一段灯带亮灯的数量
* @param led_rgb 该模式结构体参数
* @param sec_num 第几段灯带
* @return 可以亮灯的数量
*/
int get_led_sec_on_num(struct led_rgb_t *led_rgb, int sec_num)
{
int on_num = led_rgb->sec_led_num;
switch (led_rgb->mode_idx) {
case 0:
break;
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
if (spec_hdl) {
short sum0 = 0;
short sum1 = 0;
int tmp = 32 / led_rgb->div_sec_num;
for (short i = 0; i < tmp; i ++) {
sum0 += led_on_table[i + sec_num * tmp];
sum1 += db_data_old[i + sec_num * tmp];
}
sum0 /= 5;
sum1 /= 5;
short num = ((sum1 * led_rgb->sec_led_num / 90) + sum0);
if (num < 0) {
num = 0;
}
on_num = num % led_rgb->sec_led_num;
}
break;
}
return on_num;
}
/*
* @brief 约束CNT值在周期值内
* @param led_rgb 该模式结构体参数
* @param colour 颜色号0,红色 1,绿色 2,蓝色
* @param cnt 颜色对应的计数值
* @return 映射后的值
*/
int get_map_cnt(struct led_rgb_t *led_rgb, int colour, int cnt)
{
if (led_rgb->cnt_max_prd[colour] == 0) {
return 0;
}
while (cnt < 0) {
cnt += led_rgb->cnt_max_prd[colour];
}
cnt %= led_rgb->cnt_max_prd[colour];
return cnt;
}
/*
* @brief 将CNT值转换为RGB值
* @param led_rgb 该模式结构体参数
* @param colour 颜色号0,红色 1,绿色 2,蓝色
* @param cnt 颜色对应的计数值
* @return 对应的颜色亮度值
*/
u8 led_cnt_to_rgb_val(struct led_rgb_t *led_rgb, int colour, int cnt)
{
u8 rgb_val = led_rgb->rgb_val_min[colour];
int tmp_cnt = 0;
int i = colour;
int rgb_val_delta = led_rgb->rgb_val_max[i] - led_rgb->rgb_val_min[i];
if ((led_rgb->pu_cnt_start[i] <= cnt) && (cnt < led_rgb->pu_cnt_end[i])) { //递增区间
tmp_cnt = cnt - led_rgb->pu_cnt_start[i] + 1;
rgb_val = led_rgb->rgb_val_min[i] + (tmp_cnt * rgb_val_delta / (led_rgb->pu_cnt_end[i] - led_rgb->pu_cnt_start[i]));
} else if ((led_rgb->keep_cnt_start[i] <= cnt) && (cnt < led_rgb->keep_cnt_end[i])) { //高维持区间
rgb_val = led_rgb->rgb_val_max[i];
} else if ((led_rgb->pd_cnt_start[i] <= cnt) && (cnt < led_rgb->pd_cnt_end[i])) { //递减区间
tmp_cnt = led_rgb->pd_cnt_end[i] - cnt - 1;
rgb_val = led_rgb->rgb_val_min[i] + (tmp_cnt * rgb_val_delta / (led_rgb->pd_cnt_end[i] - led_rgb->pd_cnt_start[i]));
}
return rgb_val;
}
/*
* @brief 更新RGB的DMA buf数据并发送出去更新灯带
* @param led_rgb 该模式结构体参数
* @param cnt 基础节拍计数值
*/
void led_rgb_upgrade(struct led_rgb_t *led_rgb, int cnt)
{
u8 r_val = 0;
u8 g_val = 0;
u8 b_val = 0;
if ((cnt % led_rgb->cnt_freq) == 0) {
led_rgb->cnt[0] = get_map_cnt(led_rgb, 0, led_rgb->cnt[0] + led_rgb->cnt_unit[0]);
led_rgb->cnt[1] = get_map_cnt(led_rgb, 1, led_rgb->cnt[1] + led_rgb->cnt_unit[1]);
led_rgb->cnt[2] = get_map_cnt(led_rgb, 2, led_rgb->cnt[2] + led_rgb->cnt_unit[2]);
for (int i = 0; i < led_rgb->div_sec_num; i ++) {
int led_on_num = get_led_sec_on_num(led_rgb, i);
for (int j = 0; j < led_rgb->sec_led_num; j ++) {
r_val = led_cnt_to_rgb_val(led_rgb, 0, get_map_cnt(led_rgb, 0, led_rgb->cnt[0] + (i * led_rgb->next_sec_cnt_phase[0] + j) * led_rgb->next_cnt_dir[0]));
g_val = led_cnt_to_rgb_val(led_rgb, 1, get_map_cnt(led_rgb, 1, led_rgb->cnt[1] + (i * led_rgb->next_sec_cnt_phase[1] + j) * led_rgb->next_cnt_dir[1]));
b_val = led_cnt_to_rgb_val(led_rgb, 2, get_map_cnt(led_rgb, 2, led_rgb->cnt[2] + (i * led_rgb->next_sec_cnt_phase[2] + j) * led_rgb->next_cnt_dir[2]));
if (j >= led_on_num) {
r_val = 0;
g_val = 0;
b_val = 0;
}
led_rgb_to_buf(r_val, g_val, b_val, led_rgb_val_buf, i * led_rgb->sec_led_num + j);
}
}
led_send_rgbbuf(led_rgb_val_buf, led_rgb->div_sec_num * led_rgb->sec_led_num);
}
}
/*
* @brief 定时轮询各模式
*/
void led_rgb_scan(void *priv)
{
static u32 step_cnt = 0;
static u32 mode_idx = 0;
static struct led_rgb_t *led_rgb = NULL;
if ((step_cnt % 800) == 0) { //8s
step_cnt = 0;
led_rgb = led_rgb_table[mode_idx];
mode_idx ++;
if (mode_idx >= (sizeof(led_rgb_table) / 4)) {
mode_idx = 0;
}
}
led_rgb_upgrade(led_rgb, step_cnt);
step_cnt ++;
}
void my_led_test(void)
{
printf("****************** led test *******************\n");
led_init();
sys_timer_add(NULL, led_rgb_scan, 10);
sys_timer_add(spec_hdl, led_get_spectrum, 100);//定期获取能量值
}
#endif