手头有这种LED装饰照明灯条
主控芯片是GS8206,驱动7颗非RGB LED灯,工作电压24V。
查了一下资料:
GS8206是一颗3通道,带断点续传及内控花样的LED恒流驱动芯片。
芯片内置7805,工作电压:5V-24V
默认17.5mA 恒流输出,最小输出电流11mA
GS82xx点光源系列芯片可任意串联,无限连接
GS8206采用拓展式归零码作为信号传输方式,可逐通道控制输出电流,并无限级联。串行数据频率800kHz。
GS8206和WS2812都可以用归零码驱动,原理上是一样的,所有决定用Mini-F5265-OB+WS2812驱动方式实现驱动。
一、归零码
GS8206可以做级联,每个GS8206有3通道输出,VDH最高电压24V.图中control部分是要实现部分,接入SDI,归零码协议。
GS8206 采用拓展归零码数据传输方式,单通道 8bits 数据,每颗 IC 支持 3 通道显示。传输数据经过内部滤波,支持数据防抖动功能。拓展型归零码兼容普通归零码,因此适用于市面上大多数归零码控制。
单码采用 1:3 的占空比,标准 800kHz 传输速度,最高可达 1MHz。每级数据整形转发,芯片间数据延时<0.7us,满足实际动态效果需求。
二、SPI实现归零码
这部分与WS2812驱动基本一致,所以完全不用重复制造轮子。
科学上网并不容易,应该是从这个地址下载的WS2812驱动:https://github.com/libdriver/...
其中实现方式SPI。
其中发一帧数据(也就是一个0或一个1)的实现函数
static void a_ws2812b_write_one_frame(uint32_t rgb, uint8_t temp[48])
{
uint8_t r, g, b;
uint8_t i, j;
uint32_t c, point;
const uint16_t one_code = 0xFFF8U;
const uint16_t zero_code = 0xE000U;
r = (uint8_t)((rgb >> 16) & 0xFF); /* set red */
g = (uint8_t)((rgb >> 8) & 0xFF); /* set green */
b = (uint8_t)((rgb >> 0) & 0xFF); /* set blue */
c = ((uint32_t)(g) << 16) | ((uint32_t)(r) << 8) | b; /* set color */
memset(temp, 0, sizeof(uint8_t) * 30); /* clear the temp buffer */
point = 0; /* clear point */
for (i = 0; i < 24; i++) /* set 24 bit */
{
if (((c >> (23 - i)) & 0x01) != 0) /* if bit 1 */
{
for (j = 0; j < 16; j ++) /* 16 bit */
{
if (((one_code >> (15 - j)) & 0x01) != 0) /* if one code */
{
temp[point / 8] |= 1 << (7 - (point % 8)); /* set bit 1 */
}
else
{
temp[point / 8] |= 0 << (7 - (point % 8)); /* set bit 0 */
}
point = point + 1; /* point++ */
}
}
else /* if bit 0 */
{
for (j = 0; j < 16; j ++) /* 16 bit */
{
if (((zero_code >> (15 - j)) & 0x01) != 0) /* if zero code */
{
temp[point / 8] |= 1 << (7 - (point % 8)); /* set bit 1 */
}
else
{
temp[point / 8] |= 0 << (7 - (point % 8)); /* set bit 0 */
}
point = point + 1; /* point++ */
}
}
}
}
在函数中用1个字节对应归零码中的一个0码或1码。
其中:
0码的数值表达是:zero_code = 0xE000U;化成二进制就是1110000000000000
对应:
也就前面3个1表示高电平,后面13个0为低电平。
1码的数值表达是:one_code = 0xFFF8U;化成二进制就是1111111111111000
对应:
也就前面13个1表示高电平,后面3个0为低电平。
上面并没有精确地匹配1/4T和3/4T,但应该是在误差允许范围,实际效果没有影响。
发送多个数据的函数如下:
uint8_t ws2812b_write(ws2812b_handle_t *handle, uint32_t *rgb, uint32_t len, uint8_t *temp, uint32_t temp_len)
{
uint32_t i, bit_size;
if (handle == NULL) /* check handle */
{
return 2; /* return error */
}
if (handle->inited != 1) /* check handle initialization */
{
return 3; /* return error */
}
if (rgb == NULL) /* check rgb */
{
handle->debug_print("ws2812b: rgb is null.\n"); /* rgb is null */
return 4; /* return error */
}
if (temp == NULL) /* check temp */
{
handle->debug_print("ws2812b: temp is null.\n"); /* temp is null */
return 5; /* return error */
}
bit_size = WS2812B_EACH_RESET_BIT_FRAME_LEN * len; /* set the bit size */
bit_size = bit_size / 8; /* set the bit size */
if (bit_size > temp_len) /* check temp length */
{
handle->debug_print("ws2812b: temp buffer is too small and "
"size will be %d.\n", bit_size); /* temp buffer is too small*/
return 5; /* return error */
}
for (i = 0; i < bit_size; i++) /* set the reset frame */
{
temp[i] = 0x00; /* set 0x00 */
}
if (handle->spi_write_cmd(temp, (uint16_t)bit_size) != 0) /* write command */
{
handle->debug_print("ws2812b: write command failed.\n"); /* write command failed */
return 1; /* return error */
}
bit_size = 24 * 16 * len ; /* set the bit size */
bit_size = bit_size / 8; /* set the bit size */
if (bit_size > temp_len) /* check temp length */
{
handle->debug_print("ws2812b: temp buffer is too small and "
"size will be %d.\n", bit_size); /* temp buffer is too small*/
return 6; /* return error */
}
for (i = 0; i < len; i++) /* set the color frame */
{
a_ws2812b_write_one_frame(rgb[i], &temp[i * 48]); /* set color */
}
if (handle->spi_write_cmd(temp, (uint16_t)bit_size) != 0) /* write command */
{
handle->debug_print("ws2812b: write command failed.\n"); /* write command failed */
return 1; /* return error */
}
return 0; /* success return 0 */
}
归零码的思想是驱动RGB灯的,RGB是一个83=24位的数据,而SPI表示归零码每两个字节对应一个0码或1码,也就是说SPI需要传2416个位才能标识一个RGB数值。
三、SPI配置
uint8_t spi_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
SPI_InitTypeDef SPI_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
SPI_StructInit(&SPI_InitStruct);
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_DataWidth = 8;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI1, &SPI_InitStruct);
SPI_BiDirectionalLineConfig(SPI1, SPI_Enable_RX);
SPI_BiDirectionalLineConfig(SPI1, SPI_Enable_TX);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_5);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_5);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_5);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_5);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStruct);
SPI_Cmd(SPI1, ENABLE);
return 0;
}
配置SPI1,波特率10Mhz,其中PA7为MOSI
spi写数据:
void SPI_TxData_Polling(uint8_t *Buffer, uint16_t Length)
{
uint16_t i = 0, Data = 0;
for (i = 0; i < Length; i++)
{
SPI_SendData(SPI1, Buffer[i]);
while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT))
{
}
while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_RXAVL))
{
}
Data = SPI_ReceiveData(SPI1);
}
}
四、测试程序
uint8_t ws2812b_basic_init(void)
{
uint32_t i,j;
uint32_t num=21;
uint8_t res;
const uint32_t color[7] = {0xFF0000U, 0xFF7F00U, 0xFFFF00U, 0x00FF00U, 0x00FFFFU, 0x0000FFU, 0x8F00FFU}; //两种测试数据
//const uint32_t color[7] = {0x002000U, 0x003000U, 0x004000U, 0x005000U, 0x006000U, 0x007000U, 0x008000U};
/* link interface function */
DRIVER_WS2812B_LINK_INIT(&gs_handle, ws2812b_handle_t);
DRIVER_WS2812B_LINK_SPI_10MHZ_INIT(&gs_handle, ws2812b_interface_spi_10mhz_init);
DRIVER_WS2812B_LINK_SPI_DEINIT(&gs_handle, ws2812b_interface_spi_deinit);
DRIVER_WS2812B_LINK_SPI_WRITE_COMMAND(&gs_handle, ws2812b_interface_spi_write_cmd);
DRIVER_WS2812B_LINK_DELAY_MS(&gs_handle, ws2812b_interface_delay_ms);
DRIVER_WS2812B_LINK_DEBUG_PRINT(&gs_handle, ws2812b_interface_debug_print);
/* ws2812b initialization */
res = ws2812b_init(&gs_handle);
if (res != 0)
{
//ws2812b_interface_debug_print("ws2812b: init failed.\n");
printf("ws2812b: init failed.\n");
return 1;
}
for (i = 0; i < 1000; i++)
{
for (j = 0; j < 21; j++)
{
gs_rgb[j] = color[i % 7];
}
res = ws2812b_write(&gs_handle, (uint32_t *)gs_rgb, num, gs_buffer, 1500);
printf("\r\nws2812b_write,%d\r\n",res);
delay_ms(1);
}
return 0;
}
color是控制显示花样,测试了两种:渐亮和旋转显示
五、效果
渐亮:
旋转显示:
普通3通道白色LED,不是RGB只能显示成这样了。
全家福: