GD32E230C8+WS2812+TIMER14_CH0+PWM:
提示:pwm
灯光控制:
- WS2812
- PWM
- GD32
参考大佬的代码(链接: link)
1表现问题:
提示:偶发pwm启动,第一个字节数据周期不够。灯光控制随机亮度减弱。导致灯光闪烁。
2解决办法:
解决办法:在发送前多加一个24bit复位数据。
uint16_t Pixel_Buf[Pixel_NUM + Reset_load_time][RGB_DATA_SIZE]; //RGB灯传输数据;多于的2*24bit是刷新用,所有数据=rest+数据+rest;
3 ws2812b.c代码:
展示代码`。
#include "ws2812b.h"
#include "systick.h"
#include "gd32e23x_gpio.h"
//查手册
#define TIMER14_CH0CV_ADDR (TIMER14+0x34) /* CH0 */
#define TIMER14_CH1CV_ADDR (TIMER14+0x38) /* CH1 */
//需要输出的io
#define WS2812_PIN_PORT GPIOA
#define WS2812_PIN_NUM GPIO_PIN_2
/*高低电平的占空比*/
#define CODE_1 (59) //1码定时器计数次数
#define CODE_0 (28) //0码定时器计数次数
#define Pixel_NUM (40) //LED数量
#define Reset_load_time (2) //rest时间
#define RGB_DATA_SIZE (24) //一个灯24bit
uint16_t Pixel_Buf[Pixel_NUM + Reset_load_time][RGB_DATA_SIZE]; //RGB灯传输数据;多于的2*24bit是刷新用,所有数据=rest+数据+rest;
/*LED三原色结构体*/
typedef struct
{
uint8_t R;
uint8_t G;
uint8_t B;
} RGB_Color_TypeDef;
typedef enum
{
RED_COLOR = 0,
GREEN_COLOR,
BLUE_COLOR,
SKY_COLOR,
MAGENTA_COLOR,
YELLOW_COLOR,
WHITE_COLOR,
BLACK_COLOR,
OEANGE_COLOR,
Max_COLOR
} rgb_color;
/*Some Static Colors------------------------------*/
const RGB_Color_TypeDef Color_TypeDef_list[Max_COLOR + 1] =
{
{255, 0, 0}, //RED
{0, 255, 0}, //GREEN
{0, 0, 255}, //BLUE
{0, 255, 255}, //SKY
{255, 0, 255}, //MAGENTA
{255, 255, 0}, //YELLOW
{255, 255, 255}, //WHITE
{0, 0, 0}, //BLACK
{152, 251, 152}, //OEANGE
{255, 165, 0} //TEST
};
//配置pwm定时器
void ws2812_timer_pwm_init(void)
{
timer_oc_parameter_struct timer_ocintpara;
timer_parameter_struct timer_initpara;
rcu_periph_clock_enable(RCU_TIMER14);
timer_deinit(TIMER14);
/* TIMER14 配置 */
timer_initpara.prescaler = 0;//不分频,使用主频72mhz
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 89;//频率周期
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER14, &timer_initpara);
/*TIMER14 配置 PWM mode */
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_HIGH;
timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
/* TINER14_CH0 输出配置 */
timer_channel_output_config(TIMER14, TIMER_CH_0, &timer_ocintpara);
timer_channel_output_pulse_value_config(TIMER14, TIMER_CH_0, 0);
timer_channel_output_mode_config(TIMER14, TIMER_CH_0, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER14, TIMER_CH_0, TIMER_OC_SHADOW_DISABLE);
timer_primary_output_config(TIMER14, ENABLE);
timer_dma_transfer_config(TIMER14, TIMER_DMACFG_DMATA_CH0CV, TIMER_DMACFG_DMATC_4TRANSFER);
timer_dma_enable(TIMER14, TIMER_DMA_UPD);//注意这里需要选择TIMER_DMA_UPD
/* TIMER14 重装载使能 */
timer_auto_reload_shadow_enable(TIMER14);
/* TIMER14 使能 */
timer_enable(TIMER14);
}
//配置dma
static void ws2812_dma_init(void)
{
dma_parameter_struct dma_init_struct;
/* enable DMA clock */
rcu_periph_clock_enable(RCU_DMA);
/* DMA channel1 initialize */
dma_deinit(DMA_CH4);
dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;//内存到外设
dma_init_struct.memory_addr = (uint32_t)Pixel_Buf;//内存数据基地址(LED灯数组)
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;//内存地址自增
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;//存储器数据传输宽度
dma_init_struct.number = (Pixel_NUM + Reset_load_time) * RGB_DATA_SIZE; //dma通道传输数据数量
dma_init_struct.periph_addr = (uint32_t)TIMER14_CH0CV_ADDR;//外设基地址
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;//外设地址自增关闭
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;//外设数据传输宽度
dma_init_struct.priority = DMA_PRIORITY_HIGH;//优先级
dma_init(DMA_CH4, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA_CH4);//dma循环模式禁止
dma_memory_to_memory_disable(DMA_CH4);//存储器到存储器传输禁止
/* enable DMA channel1 */
dma_channel_enable(DMA_CH4);//使能dma通道4
}
//初始化io口
static void ws2812_gpio_init(void)
{
rcu_periph_clock_enable(RCU_GPIOA);
gpio_mode_set(WS2812_PIN_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, WS2812_PIN_NUM);
gpio_output_options_set(WS2812_PIN_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, WS2812_PIN_NUM);
}
//初始化
void ws2812_init(void)
{
ws2812_gpio_init();
ws2812_timer_pwm_init();
ws2812_dma_init();
}
//数据头和尾巴各自加一个reset
static void ws2812_reset_load(void)
{
uint8_t i;
for(i = 0; i < RGB_DATA_SIZE; i++)
{
Pixel_Buf[Pixel_NUM + 1][i] = 0;
Pixel_Buf[0][i] = 0;
}
}
/*
功能:返回传参颜色的结构体
*/
static RGB_Color_TypeDef ws2812_return_color_type(uint8_t color)
{
return Color_TypeDef_list[color];
}
/*
功能:设定单个RGB LED的颜色,把结构体中RGB的24BIT转换为0码和1码
参数:LedId为LED序号,Color:定义的颜色结构体
*/
static void ws2812_rgb_set_color_buf(uint8_t LedId, RGB_Color_TypeDef Color)
{
uint8_t i;
if(LedId > Pixel_NUM)return; //avoid overflow 防止写入ID大于LED总数
for(i = 0; i < 8; i++)
{
Pixel_Buf[LedId][i] = ((Color.G & (1 << (7 - i))) ? (CODE_1) : CODE_0); //数组某一行0~7转化存放G
}
for(i = 8; i < 16; i++)
{
Pixel_Buf[LedId][i] = ((Color.R & (1 << (15 - i))) ? (CODE_1) : CODE_0); //数组某一行8~15转化存放R
}
for(i = 16; i < 24; i++)
{
Pixel_Buf[LedId][i] = ((Color.B & (1 << (23 - i))) ? (CODE_1) : CODE_0); //数组某一行16~23转化存放B
}
}
/*
功能:发送数组
*/
static void ws2812_rgb_send_array(void)
{
while(dma_flag_get(DMA_CH4, DMA_INTF_FTFIF) == RESET);
dma_flag_clear(DMA_CH4, DMA_INTC_FTFIFC);
dma_channel_disable(DMA_CH4);
dma_transfer_number_config(DMA_CH4, (Pixel_NUM + Reset_load_time) * 24);
dma_channel_enable(DMA_CH4);
}
/****************************************************************
彩灯设置函数
n: 第几个灯(设置范围1-LED_NUM)
g: 绿色值 (范围0-255)
r: 红色值 (范围0-255)
b: 蓝色值 (范围0-255)
l: 亮度值 (范围0-100)
例如:WS2812B_Set_Color_Light(2,0,60,80,20);
功能:设置第2颗灯的绿色值0,红色值60,蓝色值80,亮度20
例如:WS2812B_Set_Color_Light(5,RED,50);
功能:设置第5颗灯为红色,亮度50
*****************************************************************/
void WS2812B_Set_Color_Light(uint8_t n, uint16_t color, uint8_t light)
{
RGB_Color_TypeDef breathe_type = {0};
RGB_Color_TypeDef color_type = ws2812_return_color_type(color);
// 计算当前亮度下的颜色值
if(light > 100)
{
light = 100;
}
breathe_type.R = (color_type.R * light) / 100;
breathe_type.G = (color_type.G * light) / 100;
breathe_type.B = (color_type.B * light) / 100;
ws2812_rgb_set_color_buf(n + 1, breathe_type);//此处加1,跳过最开始的reset
}
//调用RGB_SetOne_Color函数,完成对多个LED的颜色设置。
void RGB_SetMore_Color(uint8_t head, uint8_t heal, rgb_color color)
{
uint8_t i = 0;
for(i = head; i <= heal; i++)
{
WS2812B_Set_Color_Light(i, color, 100) ;
}
}
/****************************************************************
彩灯设置生效函数
*****************************************************************/
void WS2812B_Send_All()
{
ws2812_reset_load();
ws2812_rgb_send_array();
}
//百分比亮灯
void WS2812B_Set_percent_Light(uint8_t place, rgb_color COLOR, uint8_t Light)
{
//不亮的灯(黑色)
RGB_SetMore_Color(0, Pixel_NUM, BLACK_COLOR);
//准备数据
for(int i = 0; i <= Pixel_NUM * place / 100; i ++)
{
WS2812B_Set_Color_Light(i, COLOR, Light);
}
//亮灯
WS2812B_Send_All();
}
//单个扫描亮灯
void WS2812B_Set_single_Light(uint8_t place, rgb_color COLOR, uint8_t Light)
{
//不亮的灯(黑色)
RGB_SetMore_Color(0, Pixel_NUM, BLACK_COLOR);
WS2812B_Set_Color_Light(place, COLOR, Light);
//亮灯
WS2812B_Send_All();
}
//测试程序
void WS2812B_Set_TEST_light(uint32_t delays)
{
//百分比跑马
for(uint8_t j = 0; j < BLACK_COLOR; j ++)
{
for(uint8_t i = 0; i <= 100; i ++)
{
WS2812B_Set_percent_Light(i, j, 1);
delay_1ms(delays);
fwdgt_counter_reload();//清除看门狗
}
}
//单个灯跑马
for(uint8_t j = 0; j < BLACK_COLOR; j ++)
{
for(uint8_t i = 0; i <= Pixel_NUM; i ++)
{
WS2812B_Set_single_Light(i, j, i);
delay_1ms(delays);
fwdgt_counter_reload();//清除看门狗
}
}
//交替呼吸
for(uint8_t j = 0; j < BLACK_COLOR; j ++)
{
for(uint8_t i = 0; i <= 100; i++)
{
WS2812B_Set_percent_Light(100, j, i);
delay_1ms(delays);
fwdgt_counter_reload();//清除看门狗
}
for(uint8_t i = 100; i > 0; i--)
{
WS2812B_Set_percent_Light(100, j, i);
delay_1ms(delays * 2);
fwdgt_counter_reload();//清除看门狗
}
}
}
2821

被折叠的 条评论
为什么被折叠?



