123下一页
返回列表 发新帖我要提问本帖赏金: 50.00元(功能说明)

[PIC®/AVR®/dsPIC®产品] 使用MCC配置SPI硬件驱动WS2812B灯环

[复制链接]
 楼主| gaoyang9992006 发表于 2024-8-1 10:26 | 显示全部楼层 |阅读模式
<
本帖最后由 gaoyang9992006 于 2024-8-1 16:53 编辑

#申请原创#
关于MCC提速的问题查看下面连接的帖子
https://bbs.21ic.com/icview-3393632-1-1.html
接下来一步一步从新建工程讲起
1、新建工程

2、选择MCC Melody

3、选择本次要使用的设备资源SPI_Host和DELAY


4、接下来对时钟进行配置,将SPI时钟速率设置为8MHz
点击左边Project Resources中的System下的Clock Control,右边会弹出上面界面选项卡,将Clock Source设置为HFINTOSC。
HF Internal Clock 选择为16Mhz,这样可以方便分频出8MHz,
Clock Divider 设置为1,主系统时钟不分频
点击左边Project Resources中的Drivers下的SPI_Host,在右边的设置选项卡做如下图中的设置,将Requested Speed(kHz)设置为8000
即设置到了8Mhz。这样脉宽的最小单位就是0.125us了。

5、接下来需要对IO选择,由哪个IO接口输出SPI数据。引脚的选择是有讲究的,不可随意指定引脚使用,首先你要确定该引脚是否被其他功能占用,这个要根据你的板子上的设计来看,如果是全新的设计,那么选择会更加自有一些。
这里要打开芯片的用户手册,找到引脚分配表一章节,本次要使用的是SPI,另外根据选择的元件封装找到对应的表格。


我们注意到这些备注为1的引脚的默认功能是指定了的,根据备注,可知这是一个可重新映射的PPS输入信号。输入函数可以从显示的默认位置移动到其他几个PORTx引脚之一。
其他横线的引脚为备注2的,在这些行中显示的所有数字输出信号都是PPS可重新映射的。这些信号可以映射到输出到几个PORTx引脚选项之一。我使用的是PIC18F16QQ41-CNANO开发板,因此应按照该开发板原理图,找到合适没有被占用的引脚来使用,我使用的引脚配置如下图所示:


6、驱动原理
要知道驱动原理,需要先知道WS2812B的驱动时序

每一个LED由24BIT数据驱动

数据的时序波形如下图所示

数据参数的定义

LED 灯珠主要根据高电平时间判断“0”码和“1”码。
高电平时间介于 200ns~410ns,IC 判断为“0”码,高电平时间介于 640ns~1000ns,判断为“1”码。
“0”码和“1”码的低电平代表此码结束,准备接收下一数据码。
由于我们配置的SPI时钟为8MHz,那么每一个脉宽为0.125us
对于“0”码的高电平时间,2个脉宽为0.25us即可满足要求,因此我们用具备2个脉宽高电平的数据表示0,这个数据就是:0xC0
对于“1”码的高电平时间,6个脉宽为0.75us即可满足要求,因此我们用具备6个脉宽高电平的数据表示1,这个数据就是:0xFC
明白了这个原理,就可以编写代码了。
7、代码编写
  1. typedef struct COLOR
  2. {
  3.     uint8_t redChannel;
  4.     uint8_t greenChannel;
  5.     uint8_t blueChannel;
  6. } color_t;

  7. void ws2812_send(unsigned char x)
  8. {
  9.     for(int i=0;i<8;i++)
  10.     {
  11.         x<<=i;
  12.         if(x&0x80)
  13.         {
  14.             SPI1_ByteWrite(0xFC);
  15.             while(SPI1_IsTxReady()==false);
  16.         }
  17.         else
  18.         {
  19.             SPI1_ByteWrite(0xC0);
  20.             while(SPI1_IsTxReady()==false);
  21.         }
  22.     }
  23. }

  24. void WriteNeopixel(color_t const color)
  25. {
  26.     ws2812_send(color.greenChannel);   
  27.     ws2812_send(color.redChannel);   
  28.     ws2812_send(color.blueChannel);
  29. }
另外我们只使用SDO的发送数据功能,因此我们要对函数SPI1_ByteWrite进行修改一下。
找到spi1.c文件
将函数修改为
  1. void SPI1_ByteWrite(uint8_t byteData)
  2. {        
  3.         SPI1CON2 = (SPI1CON2 & ~(_SPI1CON2_SPI1RXR_MASK)) | (_SPI1CON2_SPI1TXR_MASK);
  4.         SPI1TCNTL = 1;
  5.         //Write input data to SPI transmit buffer register
  6.         SPI1TXB = byteData;
  7. }
即对SPI1CON2只设置为发送模式。
然后在main函数就可以使用上述函数对灯珠进行控制了。

  1. #include "mcc_generated_files/system/system.h"
  2. #include"mcc_generated_files/timer/delay.h"

  3. #include"ws2812b.h"


  4. //显示缓存,所有的变化操作都在这个数组进行
  5. long led_buff_temp[20]={0};

  6. /*
  7.     Main application
  8. */
  9. color_t neopixelsBuffer[20] = {

  10.     { 64, 100, 64 }, { 64, 64,  0 }, {  0, 64, 64 }, {  0, 64,  0 },

  11.     { 64,  0, 64 }, { 64,  0,  0 }, {  0,  0, 64 }, {  30,  10,  2 },

  12.     { 96, 96, 96 }, { 48, 48, 48 }, { 24, 24, 24 }, { 12, 24, 12 },

  13.     {  36,  36,  6 }, {  3,  33,  33 }, {  16,  16,  1 }, {  50,  0,  0 },

  14.     {  6,  60,  6 }, {  3,  3,  30 }, {  10,  1,  10 }, {  0,  10,  0 }

  15. };
  16. color_t temp_led;

  17. int main(void)
  18. {
  19.     SYSTEM_Initialize();
  20.     // If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts
  21.     // If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global Interrupts
  22.     // Use the following macros to:

  23.     // Enable the Global Interrupts
  24.     //INTERRUPT_GlobalInterruptEnable();

  25.     // Disable the Global Interrupts
  26.     //INTERRUPT_GlobalInterruptDisable();
  27.     SPI1_Open(HOST_CONFIG);
  28. //点亮
  29.     for(int i=0;i<20;i++) WriteNeopixel(neopixelsBuffer[i]);
  30. //色彩滚动   


  31.     while(1)
  32.     {
  33.         temp_led.blueChannel =neopixelsBuffer[0].blueChannel;
  34.         temp_led.greenChannel=neopixelsBuffer[0].greenChannel;
  35.         temp_led.redChannel  =neopixelsBuffer[0].redChannel;
  36.         for(int i=0;i<19;i++)
  37.         {
  38.             neopixelsBuffer[i].blueChannel=neopixelsBuffer[i+1].blueChannel;
  39.             neopixelsBuffer[i].greenChannel=neopixelsBuffer[i+1].greenChannel;
  40.             neopixelsBuffer[i].redChannel=neopixelsBuffer[i+1].redChannel;
  41.         }
  42.         neopixelsBuffer[19].blueChannel =temp_led.blueChannel;
  43.         neopixelsBuffer[19].greenChannel=temp_led.greenChannel;
  44.         neopixelsBuffer[19].redChannel  =temp_led.redChannel;   
  45.         DELAY_milliseconds(500);
  46.         for(int i=0;i<20;i++) WriteNeopixel(neopixelsBuffer[i]);
  47.     }   
  48. }
烧录程序,可以看到灯环上的20个彩色LED颜色滚动起来了。

效果

工程文件下载
游客,如果您要查看本帖隐藏内容请回复








本帖子中包含更多资源

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

×

打赏榜单

21小跑堂 打赏了 50.00 元 2024-08-08
理由:恭喜通过原创审核!期待你更多的原创作品~

评论

使用MCC配置硬件SPI驱动WS2812,实现动态灯效。配置过程完整详细,注意事项描述得当,代码清晰。实现效果较好。  发表于 2024-8-8 17:16
gejigeji521 发表于 2024-8-1 10:50 | 显示全部楼层
看起来很不错,学习一下,看看附件。
pzsh 发表于 2024-8-1 11:05 | 显示全部楼层
很好的实现方式。 驱动WS2812, 是不是也可以使用CLC, 或者CLB (PIC6F31xx 系列上的)来实现? 这样的话,代码量会少一些。
KCCHEN 发表于 2024-8-1 11:16 | 显示全部楼层
看起来很不错,学习一下
 楼主| gaoyang9992006 发表于 2024-8-1 11:42 | 显示全部楼层
pzsh 发表于 2024-8-1 11:05
很好的实现方式。 驱动WS2812, 是不是也可以使用CLC, 或者CLB (PIC6F31xx 系列上的)来实现? 这样的话 ...

嗯,好主意,我看看怎么用CLC实现。
jcy8508 发表于 2024-8-11 00:21 | 显示全部楼层
驱动WS2812学习一下
wuyushan 发表于 2024-8-11 11:48 | 显示全部楼层
xinxianshi 发表于 2024-8-13 22:40 | 显示全部楼层
手把手教学,懂了,一步一步操作,就觉得挺容易的。看来不能省略一些细节步骤。
AloneKaven 发表于 2024-8-15 23:07 来自手机 | 显示全部楼层
这个整挺好
wanduzi 发表于 2024-9-3 16:00 | 显示全部楼层
SPI实现的原理看懂了,如果使用PWM该如何实现呢,如何控制PWM就生成1个周期的脉宽?这一点不懂,没操作过
clolcj 发表于 2024-10-15 23:29 | 显示全部楼层
参考
yellow555 发表于 2024-10-31 13:35 来自手机 | 显示全部楼层
脉宽的最小单位是0.125us是为了做什么啊?
 楼主| gaoyang9992006 发表于 2024-10-31 20:36 | 显示全部楼层
yellow555 发表于 2024-10-31 13:35
脉宽的最小单位是0.125us是为了做什么啊?

方便匹配这个通信协议的高低电平长度。
643757107 发表于 2024-11-27 20:43 | 显示全部楼层
下载学习参靠一下。
小明的同学 发表于 2024-11-28 10:35 | 显示全部楼层
这个灯珠挺好用的。
小明的同学 发表于 2024-11-28 10:35 | 显示全部楼层
停止输出后是不是可以保持?
zhuotuzi 发表于 2024-11-28 20:38 | 显示全部楼层
火过一段时间的元件,现在好多彩色灯光用的这个。
xixi2017 发表于 2024-11-29 16:25 | 显示全部楼层
有没有I2C的操作演示啊,参靠一下。
xixi2017 发表于 2024-11-29 16:25 | 显示全部楼层
我想用I2C驱动OLED单色屏。
yiyigirl2014 发表于 2024-11-29 19:51 | 显示全部楼层
多少个LED都可以驱动吗
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:如果你觉得我的分享或者答复还可以,请给我点赞,谢谢。

2046

主题

16356

帖子

221

粉丝
快速回复 在线客服 返回列表 返回顶部
个人签名:如果你觉得我的分享或者答复还可以,请给我点赞,谢谢。

2046

主题

16356

帖子

221

粉丝
快速回复 在线客服 返回列表 返回顶部