搜索
bottom↓
回复: 16

求助:类似WS2812b驱动的SM16703P的全彩灯驱动芯片怎样驱动

[复制链接]

出0入55汤圆

发表于 2018-7-7 21:46:00 | 显示全部楼层 |阅读模式
用的是SM16703P芯片控制的三色灯,图如下

下面是WS2812b的

下面是程序,使用
SPI+DMA驱动方式:
MCU: STM32F103C8T6
IO配置:PA7(SPI1.MOSI) , 3.3V上拉电阻(1K)+ 开漏输出
系统时钟为:48MHz
  1. /******************** 鑫盛电子工作室 ********************
  2. * 文件名  :main.c
  3. * 描述    :板子上的LED1、LED2、LED3轮流闪烁。         
  4. * 实验平台:MINI STM32开发板 基于STM32F103C8T6
  5. * 库版本  :ST3.0.0                                                                                                                                                                                                                    
  6. * 淘宝店:http://shop66177872.taobao.com
  7. *********************************************************/       

  8. #include "stm32f10x.h"
  9. #include "stm32f10x_spi.h"
  10. #include "stm32f10x_dma.h"
  11. #include "led.h"

  12. unsigned char ws2812b_PixBuf[48] = {0};//像素缓存区 16个灯*3
  13. unsigned char spi_SendBuf[576] = {0,0,0};//SPI的发送缓存区

  14. #define SENDLENGTH 576


  15. void Delay(__IO u32 nCount)
  16. {
  17.   for(; nCount != 0; nCount--);
  18. }

  19. /*
  20. *****************************************************
  21. *        功能说明: WS2812b初始化
  22. *        形    参:
  23. *        返 回 值:
  24. *        备    注:
  25. *****************************************************

  26. SPI+DMA驱动方式:
  27. MCU: STM32F103C8T6
  28. IO配置:PB15(SPI2.MOSI) , 5V上拉电阻(1K)+ 开漏输出
  29. SPI时钟:9M,每bit0.11us, 用12bit拼接成一个WS2812的数据位
  30. */
  31. void WS2812b_Init(void)
  32. {
  33.         GPIO_InitTypeDef GPIO_InitStructure;
  34.         SPI_InitTypeDef SPI_InitStructure;
  35.         DMA_InitTypeDef DMA_InitStructure;
  36.         
  37.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  38.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,  ENABLE);
  39.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  40.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_5;
  41.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;  
  42.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  43.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  44.         
  45.         GPIO_ResetBits(GPIOA,GPIO_Pin_7);//拉低数据线,复位WS2812b

  46.         SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;//一线发送
  47.         SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//主模式
  48.         SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//8位
  49.         SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//时钟空闲时为高
  50.         SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//时钟的第二个跳变沿采样数据
  51.         SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//软件控制片选信号
  52.         SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;//波特率4分频  36M/4 = 9M =0.11us
  53.         SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//高位在前
  54.         SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC校验多项式 大于1即可
  55.         SPI_Init(SPI1, &SPI_InitStructure);  
  56.         
  57.         DMA_DeInit(DMA1_Channel3);
  58.         DMA_InitStructure.DMA_BufferSize = SENDLENGTH;
  59.         DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & (SPI1->DR);
  60.         DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)spi_SendBuf;
  61.         DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  62.         DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
  63.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  64.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  65.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  66.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  67.         DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  68.         DMA_Init(DMA1_Channel3, &DMA_InitStructure); /* DMA1 CH5 = MEM -> DR */
  69.         
  70.         SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
  71.         SPI_Cmd(SPI1, ENABLE);
  72.         DMA_Cmd(DMA1_Channel3, DISABLE);
  73. }

  74. /*
  75. *****************************************************
  76. *        功能说明: WS2812b显示
  77. *        形    参:
  78. *        返 回 值:
  79. *        备    注:
  80. *                        放在主循环里面定时刷新,
  81. *           刷新像素缓存区数据即可改变显示
  82. *****************************************************
  83. */
  84. void WS2812b_Display(void)
  85. {
  86.         unsigned short i,j;
  87.         unsigned short index;
  88.         unsigned short tmp;
  89.         
  90.         for(i = 0;i < 48;i++)//轮询像素缓存区
  91.         {
  92.                 for(j = 0;j < 8;j++)//轮询每个像素字节的每个位,转换成SPI的12bit数据
  93.                 {
  94.                         index = 8 * i + j;
  95.                         tmp = ws2812b_PixBuf[i] & (1 << (7 - j));
  96.                         
  97.                         if(index & 1)
  98.                         {
  99.                                 spi_SendBuf[3 * ((index - 1) / 2) + 1] |= 0x0f;
  100.                                 
  101.                                 if(tmp)
  102.                                         spi_SendBuf[3 * ((index - 1) / 2) + 2] = 0xf0;
  103.                                 else               
  104.                                         spi_SendBuf[3 * ((index - 1) / 2) + 2] = 0x00;
  105.                         }
  106.                         else
  107.                         {
  108.                                 spi_SendBuf[3 * (index / 2) + 1] = 0x00;
  109.                                 
  110.                                 if(tmp)
  111.                                         spi_SendBuf[3 * (index / 2)] = 0xff;               
  112.                                 else
  113.                                         spi_SendBuf[3 * (index / 2)] = 0xf0;
  114.                         }
  115.                 }
  116.         }
  117.         
  118.         DMA_Cmd(DMA1_Channel3, DISABLE);
  119.         DMA_ClearFlag(DMA1_FLAG_TC3);
  120.         DMA1_Channel3->CNDTR = SENDLENGTH;
  121.         DMA_Cmd(DMA1_Channel3, ENABLE);
  122. }

  123. int main(void)
  124. {
  125.         int i;
  126.         SystemInit();        // 配置系统时钟为72M        
  127.         LED_GPIO_Config(); //LED 端口初始化
  128.         WS2812b_Init();
  129.        
  130.         for(i=0;i<16;i+=3)
  131.         {
  132.                 ws2812b_PixBuf[i] = 0xff;
  133.                 ws2812b_PixBuf[i+1] = 0xff;
  134.                 ws2812b_PixBuf[i+2] = 0x00;
  135.         }
  136.        
  137.         while (1)
  138.         {
  139.                 LED1( ON );                          // 亮
  140.                 Delay(0x200000);
  141.                 LED1( OFF );                  // 灭
  142.                 Delay(0x200000);
  143.                 WS2812b_Display();
  144.         }
  145. }
复制代码


现在问题是WS2812b时间占空比大概是1:2,而SM16703P的时间占空比是1:3,对STM32不是很了解,程序也是使用坛友大神的代码改的,现在是有输出,0的高电平时间是320nS,低电平时间是670nS,怎样才能配到300:900nS?

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入90汤圆

发表于 2018-7-8 02:40:12 来自手机 | 显示全部楼层
把spi时钟调到12m,数据4:11,用15个bit拼成1个数据位就行了

出0入24汤圆

发表于 2018-7-8 04:06:26 | 显示全部楼层
  1. const unsigned char LUTbl[16][6] = {
  2.                        {0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00},\
  3.                        {0xE0, 0x0E, 0x00, 0xE0, 0x0F, 0xF8},\
  4.                        {0xE0, 0x0E, 0x00, 0xFF, 0x8E, 0x00},\
  5.                        {0xE0, 0x0E, 0x00, 0xFF, 0x8F, 0xF8},\
  6.                        
  7.                        {0xE0, 0x0F, 0xF8, 0xE0, 0x0E, 0x00},\
  8.                        {0xE0, 0x0F, 0xF8, 0xE0, 0x0F, 0xF8},\
  9.                        {0xE0, 0x0F, 0xF8, 0xFF, 0x8E, 0x00},\
  10.                        {0xE0, 0x0F, 0xF8, 0xFF, 0x8F, 0xF8},\
  11.                        
  12.                        {0xFF, 0x8E, 0x00, 0xE0, 0x0E, 0x00},\
  13.                        {0xFF, 0x8E, 0x00, 0xE0, 0x0F, 0xF8},\
  14.                        {0xFF, 0x8E, 0x00, 0xFF, 0x8E, 0x00},\
  15.                        {0xFF, 0x8E, 0x00, 0xFF, 0x8F, 0xF8},\
  16.                        
  17.                        {0xFF, 0x8F, 0xF8, 0xE0, 0x0E, 0x00},\
  18.                        {0xFF, 0x8F, 0xF8, 0xE0, 0x0F, 0xF8},\
  19.                        {0xFF, 0x8F, 0xF8, 0xFF, 0x8E, 0x00},\
  20.                        {0xFF, 0x8F, 0xF8, 0xFF, 0x8F, 0xF8},};


  21. void WS2812b_Display(void)
  22. {
  23.         unsigned long i;
  24.         unsigned long index = 0;
  25.         unsigned char temp = 0;
  26.         
  27.         unsigned char const *p;
  28.         
  29.         for(i = 0;i < 48;i++)//轮询像素缓存区
  30.         {
  31.             temp = ws2812b_PixBuf[i] >> 4;
  32.                         
  33.             p = LUTbl[temp];
  34.             
  35.             spi_SendBuf[index++] = *p++;
  36.             spi_SendBuf[index++] = *p++;
  37.             spi_SendBuf[index++] = *p++;
  38.             spi_SendBuf[index++] = *p++;
  39.             spi_SendBuf[index++] = *p++;
  40.             spi_SendBuf[index++] = *p++;
  41.                     
  42.             temp = ws2812b_PixBuf[i] & 0x0F;
  43.                         
  44.             p = LUTbl[temp];
  45.             
  46.             spi_SendBuf[index++] = *p++;
  47.             spi_SendBuf[index++] = *p++;
  48.             spi_SendBuf[index++] = *p++;
  49.             spi_SendBuf[index++] = *p++;
  50.             spi_SendBuf[index++] = *p++;
  51.             spi_SendBuf[index++] = *p++;
  52.                
  53.         }
  54.       
  55.         DMA_Cmd(DMA1_Channel3, DISABLE);
  56.         DMA_ClearFlag(DMA1_FLAG_TC3);
  57.         DMA1_Channel3->CNDTR = SENDLENGTH;
  58.         DMA_Cmd(DMA1_Channel3, ENABLE);
  59.   
  60. }
复制代码


没有比查表更快的方式了,4位一查表,均衡一下空间和速度
CPU主频改成40M,SPI时钟4分频是10M,12位是1.2us

出0入0汤圆

发表于 2018-7-8 04:07:17 | 显示全部楼层
在 ESP8266 上,我驱动 WS2812 是 8 bit 的原始数据转换为 32 bit 的 I2S 输入 buffer 数据,数据量变为原始数据的 4 倍
也就是 3 个字节的 R, G, B 值,到 I2S 输出时就变成 12 字节的数据了

出0入10汤圆

发表于 2018-7-8 22:20:26 来自手机 | 显示全部楼层
wudicgi 发表于 2018-7-8 04:07
在 ESP8266 上,我驱动 WS2812 是 8 bit 的原始数据转换为 32 bit 的 I2S 输入 buffer 数据,数据量变为原 ...

你这个是用涂鸦云做的吗?

出0入0汤圆

发表于 2018-7-8 22:28:51 | 显示全部楼层
熬松螺丝 发表于 2018-7-8 22:20
你这个是用涂鸦云做的吗?

涂鸦云是什么?

出0入55汤圆

 楼主| 发表于 2018-7-9 10:20:57 | 显示全部楼层
20061002838 发表于 2018-7-8 04:06
没有比查表更快的方式了,4位一查表,均衡一下空间和速度
CPU主频改成40M,SPI时钟4分频是10M,12位是1.2 ...

你好,使用你这代码,CPU改成20M(因为只有20,36,48,56,72),SPI时钟2分频
其他没变,把之前这个函数去掉,得出结果是低电平是300ns,高电平320uS左右(这个uS,不是nS),为什么高电平那么长时间?

出0入55汤圆

 楼主| 发表于 2018-7-9 10:23:40 | 显示全部楼层
aammoo 发表于 2018-7-8 02:40
把spi时钟调到12m,数据4:11,用15个bit拼成1个数据位就行了

你好,CPU时钟换成48,SPI4分频可以得到12,数据4:11是怎么设置的?15个bit拼成一个数据又是怎样设置的?
不好意思,对STM32真不熟。。。

出0入90汤圆

发表于 2018-7-9 11:28:29 | 显示全部楼层
jssd 发表于 2018-7-9 10:23
你好,CPU时钟换成48,SPI4分频可以得到12,数据4:11是怎么设置的?15个bit拼成一个数据又是怎样设置的 ...

12M的SPI一个周期是 1/12=0.08333333333333333333333333333333us
4个bit数据是 0.08333333333333333333333333333333 * 4 = 0.33333333333333333333333333333333us
11个bit数据是 0.08333333333333333333333333333333 * 11  = 0.91666666666666666666666666666667us
符合0.05us的容许误差
发4bit的1,11bit的0就是发了个0
发11bit的1,4bit的0就是发了个1
改一下你贴的那段程序就行了

出0入24汤圆

发表于 2018-7-9 13:02:13 | 显示全部楼层
jssd 发表于 2018-7-9 10:20
你好,使用你这代码,CPU改成20M(因为只有20,36,48,56,72),SPI时钟2分频
其他没变,把之前这个函数 ...

怎么可能,代码我之前软件仿真过,没问题的
刚才又实际在单片机上面跑了一次,完美

逻辑分析仪截图,发送的数据是,0, 1, 2

工程,CubeMX配置,IAR编译,8M外部时钟,PLL倍频到40M

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入55汤圆

 楼主| 发表于 2018-7-9 13:24:58 | 显示全部楼层
本帖最后由 jssd 于 2018-7-9 13:27 编辑
20061002838 发表于 2018-7-9 13:02
怎么可能,代码我之前软件仿真过,没问题的
刚才又实际在单片机上面跑了一次,完美


非常感谢!我用keil,编译烧录后确实是只有一个300nS的拉低,其他都是高,如循环。
然后我直接对spi_SendBuf赋值,只控制一个灯亮红色,结果没问题,然后控制两个也没问题,如下
  1.                 //R
  2.                 spi_SendBuf[index++] = 0xFF;
  3.                 spi_SendBuf[index++] = 0x8F;
  4.                 spi_SendBuf[index++] = 0xF8;
  5.                
  6.                 spi_SendBuf[index++] = 0xFF;
  7.                 spi_SendBuf[index++] = 0x8F;
  8.                 spi_SendBuf[index++] = 0xF8;
  9.                
  10.                 spi_SendBuf[index++] = 0xFF;
  11.                 spi_SendBuf[index++] = 0x8F;
  12.                 spi_SendBuf[index++] = 0xF8;
  13.                
  14.                 spi_SendBuf[index++] = 0xFF;
  15.                 spi_SendBuf[index++] = 0x8F;
  16.                 spi_SendBuf[index++] = 0xF8;
  17.                
  18.                
  19.                 //G
  20.                 spi_SendBuf[index++] = 0xE0;
  21.                 spi_SendBuf[index++] = 0x0E;
  22.                 spi_SendBuf[index++] = 0x00;
  23.                
  24.                 spi_SendBuf[index++] = 0xE0;
  25.                 spi_SendBuf[index++] = 0x0E;
  26.                 spi_SendBuf[index++] = 0x00;
  27.                
  28.                 spi_SendBuf[index++] = 0xE0;
  29.                 spi_SendBuf[index++] = 0x0E;
  30.                 spi_SendBuf[index++] = 0x00;
  31.                
  32.                 spi_SendBuf[index++] = 0xE0;
  33.                 spi_SendBuf[index++] = 0x0E;
  34.                 spi_SendBuf[index++] = 0x00;
  35.                
  36.                
  37.                 //B
  38.                 spi_SendBuf[index++] = 0xE0;
  39.                 spi_SendBuf[index++] = 0x0E;
  40.                 spi_SendBuf[index++] = 0x00;
  41.                
  42.                 spi_SendBuf[index++] = 0xE0;
  43.                 spi_SendBuf[index++] = 0x0E;
  44.                 spi_SendBuf[index++] = 0x00;
  45.                
  46.                 spi_SendBuf[index++] = 0xE0;
  47.                 spi_SendBuf[index++] = 0x0E;
  48.                 spi_SendBuf[index++] = 0x00;
  49.                
  50.                 spi_SendBuf[index++] = 0xE0;
  51.                 spi_SendBuf[index++] = 0x0E;
  52.                 spi_SendBuf[index++] = 0x00;
  53.                
  54.                 //R
  55.                 spi_SendBuf[index++] = 0xFF;
  56.                 spi_SendBuf[index++] = 0x8F;
  57.                 spi_SendBuf[index++] = 0xF8;
  58.                
  59.                 spi_SendBuf[index++] = 0xFF;
  60.                 spi_SendBuf[index++] = 0x8F;
  61.                 spi_SendBuf[index++] = 0xF8;
  62.                
  63.                 spi_SendBuf[index++] = 0xFF;
  64.                 spi_SendBuf[index++] = 0x8F;
  65.                 spi_SendBuf[index++] = 0xF8;
  66.                
  67.                 spi_SendBuf[index++] = 0xFF;
  68.                 spi_SendBuf[index++] = 0x8F;
  69.                 spi_SendBuf[index++] = 0xF8;
复制代码


接着我更改void WS2812b_Display(void)里面如下,,初始化时对像素缓存区ws2812b_PixBuf赋值如下,结果是前6个灯为红色,后10个灯都不亮,看示波器波形,也确实只有前6个灯的波形出来,后面全是低,很诡异。。。
  1. for(i=0;i<48;i+=3)
  2.         {
  3.                 ws2812b_PixBuf[i] = 0xff;
  4.                 ws2812b_PixBuf[i+1] = 0x00;
  5.                 ws2812b_PixBuf[i+2] = 0x00;
  6.         }
复制代码
  1. void WS2812b_Display(void)
  2. {
  3.         unsigned long i;
  4.         unsigned long index = 0;
  5.         unsigned char temp = 0;
  6.         unsigned char j = 0;
  7. //        unsigned char const *p;
  8.        
  9.                 index = 0;
  10.         
  11.         for(i = 0;i < 48;i++)//轮询像素缓存区
  12.         {
  13.             temp = (ws2812b_PixBuf[i] >> 4);
  14.                         j = 0;
  15.                         spi_SendBuf[index++] = LUTbl[temp][j++];
  16.                         spi_SendBuf[index++] = LUTbl[temp][j++];
  17.                         spi_SendBuf[index++] = LUTbl[temp][j++];
  18.                         spi_SendBuf[index++] = LUTbl[temp][j++];
  19.                         spi_SendBuf[index++] = LUTbl[temp][j++];
  20.                         spi_SendBuf[index++] = LUTbl[temp][j++];
  21.                         
  22. //            p = LUTbl[temp];
  23. //            
  24. //            spi_SendBuf[index++] = *p++;
  25. //            spi_SendBuf[index++] = *p++;
  26. //            spi_SendBuf[index++] = *p++;
  27. //            spi_SendBuf[index++] = *p++;
  28. //            spi_SendBuf[index++] = *p++;
  29. //            spi_SendBuf[index++] = *p++;
  30.                     
  31.             temp = (ws2812b_PixBuf[i] & 0x0F);
  32.             j = 0;
  33.                         spi_SendBuf[index++] = LUTbl[temp][j++];
  34.                         spi_SendBuf[index++] = LUTbl[temp][j++];
  35.                         spi_SendBuf[index++] = LUTbl[temp][j++];
  36.                         spi_SendBuf[index++] = LUTbl[temp][j++];
  37.                         spi_SendBuf[index++] = LUTbl[temp][j++];
  38.                         spi_SendBuf[index++] = LUTbl[temp][j++];
  39. //            p = LUTbl[temp];
  40. //            
  41. //            spi_SendBuf[index++] = *p++;
  42. //            spi_SendBuf[index++] = *p++;
  43. //            spi_SendBuf[index++] = *p++;
  44. //            spi_SendBuf[index++] = *p++;
  45. //            spi_SendBuf[index++] = *p++;
  46. //            spi_SendBuf[index++] = *p++;
  47.                
  48.         }
  49.       
  50.         DMA_Cmd(DMA1_Channel3, DISABLE);
  51.         DMA_ClearFlag(DMA1_FLAG_TC3);
  52.         DMA1_Channel3->CNDTR = SENDLENGTH;
  53.         DMA_Cmd(DMA1_Channel3, ENABLE);
  54.   
  55. }
复制代码


工程如下:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入55汤圆

 楼主| 发表于 2018-7-9 13:38:54 | 显示全部楼层
20061002838 发表于 2018-7-9 13:02
怎么可能,代码我之前软件仿真过,没问题的
刚才又实际在单片机上面跑了一次,完美

用示波器看,1的高电平的时间是1.1uS了,低电平是300nS

出0入0汤圆

发表于 2018-7-9 13:46:07 | 显示全部楼层
数据手册上为什么只有红色二极管要加RL电阻?

出0入55汤圆

 楼主| 发表于 2018-7-9 13:56:31 | 显示全部楼层
LVmcu 发表于 2018-7-9 13:46
数据手册上为什么只有红色二极管要加RL电阻?

红色LED压降低

出0入24汤圆

发表于 2018-7-9 14:04:11 | 显示全部楼层
jssd 发表于 2018-7-9 13:38
用示波器看,1的高电平的时间是1.1uS了,低电平是300nS

你该买个逻辑分析仪了,或者你没看你的SCK波形

你的波形是这个鬼样子,SPI没有连续发送
试了一下,SPI时钟2分频导致的,主频设置成40M,SPI 4分频就好了

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入55汤圆

 楼主| 发表于 2018-7-9 15:19:03 | 显示全部楼层
20061002838 发表于 2018-7-9 14:04
你该买个逻辑分析仪了,或者你没看你的SCK波形

你的波形是这个鬼样子,SPI没有连续发送

真的非常感谢你的解答!谢谢!
现在正常了,问题出在时钟,我使用了内部40MHz,出来的时间有点不准,现在换成外部8MHz时钟,用你的显示程序,完全正常!如下
  1. /*********************************************************  
  2. * 实验平台:基于STM32F103C8T6
  3. * 库版本  :ST3.0.0                                                                                                                                                                                                                    
  4. *********************************************************/       

  5. #include "stm32f10x.h"
  6. #include "stm32f10x_spi.h"
  7. #include "stm32f10x_dma.h"
  8. #include "led.h"

  9. #define LEDNUM 40                                        //显示的灯的数量 , 需要人工指定
  10. #define PIXNUM        LEDNUM*3                                        //像素数量
  11. #define SENDLENGTH PIXNUM*12                                //发送位数,SPI时钟:10M,每bit0.1us, 用12bit拼接成一个WS2812的数据位

  12. unsigned char ws2812b_PixBuf[PIXNUM] = {0};//像素缓存区 16个灯*3
  13. unsigned char spi_SendBuf[SENDLENGTH] = {0,0,0};//SPI的发送缓存区



  14. void Delay(__IO u32 nCount)
  15. {
  16.   for(; nCount != 0; nCount--);
  17. }

  18. /*
  19. *****************************************************
  20. *        功能说明: WS2812b初始化
  21. *        形    参:
  22. *        返 回 值:
  23. *        备    注:
  24. *****************************************************

  25. SPI+DMA驱动方式:
  26. MCU: STM32F103C8T6
  27. IO配置:PA7(SPI1.MOSI) , 5V上拉电阻(1K)+ 开漏输出
  28. 外部时钟:8MHz,倍频致40MHz
  29. SPI时钟:10M,每bit0.1us, 用12bit拼接成一个WS2812的数据位
  30. */
  31. void WS2812b_Init(void)
  32. {
  33.         GPIO_InitTypeDef GPIO_InitStructure;
  34.         SPI_InitTypeDef SPI_InitStructure;
  35.         DMA_InitTypeDef DMA_InitStructure;
  36.         
  37.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  38.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,  ENABLE);
  39.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  40.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_5;
  41.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;  
  42.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  43.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  44.         
  45.         GPIO_ResetBits(GPIOA,GPIO_Pin_7);//拉低数据线,复位WS2812b

  46.         SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;//一线发送
  47.         SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//主模式
  48.         SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//8位
  49.         SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//时钟空闲时为高
  50.         SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//时钟的第二个跳变沿采样数据
  51.         SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//软件控制片选信号
  52.         SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;//波特率4分频  40M/4 = 10M =0.1us
  53.         SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//高位在前
  54.         SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC校验多项式 大于1即可
  55.         SPI_Init(SPI1, &SPI_InitStructure);  
  56.         
  57.         DMA_DeInit(DMA1_Channel3);
  58.         DMA_InitStructure.DMA_BufferSize = SENDLENGTH;
  59.         DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & (SPI1->DR);
  60.         DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)spi_SendBuf;
  61.         DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  62.         DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
  63.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  64.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  65.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  66.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  67.         DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  68.         DMA_Init(DMA1_Channel3, &DMA_InitStructure); /* DMA1 CH3 = MEM -> DR */
  69.         
  70.         SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
  71.         SPI_Cmd(SPI1, ENABLE);
  72.         DMA_Cmd(DMA1_Channel3, DISABLE);
  73. }


  74. /*4位一查表,均衡一下空间和速度
  75. CPU主频改成40M,SPI时钟4分频是10M,12位是1.2us*/
  76. const unsigned char LUTbl[16][6] = {
  77.    {0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00},\
  78.    {0xE0, 0x0E, 0x00, 0xE0, 0x0F, 0xF8},\
  79.    {0xE0, 0x0E, 0x00, 0xFF, 0x8E, 0x00},\
  80.    {0xE0, 0x0E, 0x00, 0xFF, 0x8F, 0xF8},\
  81.    
  82.    {0xE0, 0x0F, 0xF8, 0xE0, 0x0E, 0x00},\
  83.    {0xE0, 0x0F, 0xF8, 0xE0, 0x0F, 0xF8},\
  84.    {0xE0, 0x0F, 0xF8, 0xFF, 0x8E, 0x00},\
  85.    {0xE0, 0x0F, 0xF8, 0xFF, 0x8F, 0xF8},\
  86.    
  87.    {0xFF, 0x8E, 0x00, 0xE0, 0x0E, 0x00},\
  88.    {0xFF, 0x8E, 0x00, 0xE0, 0x0F, 0xF8},\
  89.    {0xFF, 0x8E, 0x00, 0xFF, 0x8E, 0x00},\
  90.    {0xFF, 0x8E, 0x00, 0xFF, 0x8F, 0xF8},\
  91.    
  92.    {0xFF, 0x8F, 0xF8, 0xE0, 0x0E, 0x00},\
  93.    {0xFF, 0x8F, 0xF8, 0xE0, 0x0F, 0xF8},\
  94.    {0xFF, 0x8F, 0xF8, 0xFF, 0x8E, 0x00},\
  95.    {0xFF, 0x8F, 0xF8, 0xFF, 0x8F, 0xF8},};

  96.   
  97. /*当更改完ws2812b_PixBuf后,调用这个函数刷新灯显示*/
  98. void WS2812b_Display(void)
  99. {
  100.         unsigned long i;
  101.         unsigned long index = 0;
  102.         unsigned char temp = 0;
  103.         unsigned char const *p;

  104.         for(i = 0;i < PIXNUM;i++)//轮询像素缓存区
  105.         {
  106.             temp = (ws2812b_PixBuf[i] >> 4);
  107.                         
  108.             p = LUTbl[temp];
  109.             spi_SendBuf[index++] = *p++;
  110.             spi_SendBuf[index++] = *p++;
  111.             spi_SendBuf[index++] = *p++;
  112.             spi_SendBuf[index++] = *p++;
  113.             spi_SendBuf[index++] = *p++;
  114.             spi_SendBuf[index++] = *p++;
  115.                     
  116.             temp = (ws2812b_PixBuf[i] & 0x0F);
  117.             p = LUTbl[temp];
  118.             
  119.             spi_SendBuf[index++] = *p++;
  120.             spi_SendBuf[index++] = *p++;
  121.             spi_SendBuf[index++] = *p++;
  122.             spi_SendBuf[index++] = *p++;
  123.             spi_SendBuf[index++] = *p++;
  124.             spi_SendBuf[index++] = *p++;
  125.                
  126.         }
  127.       
  128.         DMA_Cmd(DMA1_Channel3, DISABLE);
  129.         DMA_ClearFlag(DMA1_FLAG_TC3);
  130.         DMA1_Channel3->CNDTR = SENDLENGTH;
  131.         DMA_Cmd(DMA1_Channel3, ENABLE);
  132.   
  133. }

  134. void SystemClock_Config(void)  
  135. {  
  136.     RCC_DeInit();                        //初始化
  137.     RCC_HSEConfig(RCC_HSE_ON);   //打开外部时钟HSE    8MHz
  138.    
  139.     if(RCC_WaitForHSEStartUp() == SUCCESS)    //等待HSE启动成功
  140.     {  
  141.    
  142.         RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_5);  //选择PLL的时钟源并5倍 40Mhz
  143.         RCC_PLLCmd(ENABLE);   //使能PLL时钟                                 
  144.         while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)     //等待PLL时钟就绪
  145.         {  
  146.         }  
  147.         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //系统时钟选择PLL作为时钟源  
  148.         // *           - 0x00: HSI used as system clock  
  149.         // *           - 0x04: HSE used as system clock   
  150.         // *           - 0x08: PLL used as system clock  
  151.         // *           - 0x0C: HSI48 used as system clock, applicable only for STM32F072 devices   
  152.         while(RCC_GetSYSCLKSource()!=0x08)   //判断返回的时钟源是否为PLL时钟源
  153.         {  
  154.         }  
  155.         RCC_HCLKConfig(RCC_SYSCLK_Div1); //PLL不分频给系统时钟   40MHz
  156.     }  
  157. }

  158. int main(void)
  159. {
  160.         int i;
  161.         SystemClock_Config();
  162.         LED_GPIO_Config(); //LED 端口初始化
  163.         WS2812b_Init();
  164.        
  165.         for(i=0;i<PIXNUM;i+=3)
  166.         {
  167.                 ws2812b_PixBuf[i] = 0x00;
  168.                 ws2812b_PixBuf[i+1] = 0x00;
  169.                 ws2812b_PixBuf[i+2] = 0xff;
  170.         }
  171.         WS2812b_Display();
  172.         while (1)
  173.         {
  174.                 LED1( ON );                          // 亮
  175.                 Delay(0x200000);
  176.                 LED1( OFF );                  // 灭
  177.                 Delay(0x200000);
  178.                
  179.         }
  180. }





复制代码



再次感谢你热心的解答!!!

出0入0汤圆

发表于 2018-7-11 10:17:27 来自手机 | 显示全部楼层
学习标记下,单线控制带协议LED灯(灯内有IC)
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-30 01:35

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表