查看: 1372|回复: 2

【庆典三:项目速成设计】MCXN947驱动WS2812

[复制链接]
  • TA的每日心情
    开心
    昨天 14:16
  • 签到天数: 1171 天

    连续签到: 2 天

    [LV.10]以坛为家III

    28

    主题

    4410

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    6071
    最后登录
    2025-10-7
    发表于 2024-12-5 11:51:46 | 显示全部楼层 |阅读模式
    本帖最后由 suncat0504 于 2024-12-5 12:03 编辑

    WS2812是一种基于数字信号传输的RGB LED灯珠,包含了三种颜色的LED和一个控制电路。
    图片1.png

    WS2812的工作电压范围比较宽,3.5V ~ 5.3V。其构成的三色LED参数:
    图片2.png

    驱动时,每个LED占用3个字节,数据形式为:
    图片3.png

    每个 bit 都是通过(一个高电平 + 一个低电平)表示。
    图片4.png
    图片5.png

    按照这个要求,发送0码/1码,需要1/3.5≈3MHz的时钟。
    WS2812的数据传输速率较慢,在使用单片机驱动WS2812时要注意传输速率。

    在实际应用中经常使用级联方式,将多个WS2812串接起来,制作成灯条、灯带等方式。
    图片6.png 图片7.png

    在级联方式下的数据传输方法:
    图片8.png

    如果以SPI方式驱动WS2812,前面已经计算,SPI的时钟频率要达到3MHz。下例是使一个WS2812发绿色光,亮度为16的数据,
    图片9.png

    下面我就用MCXN947开发板编程驱动一款WS2812B模块(6个WS2812B)。MCXN947开发板有几组可用的SPI输出接口,这里只使用J2中的SPI的MOSI(J2 - 8)输出控制WS2812B,为了避免供电不足,不用开发板上的电源,而是使用独立的供电给WS2812B供电。开发环境使用MCUXpresso,在已有的SPI例程(frdmmcxn947_lpspi_edma_b2b_transfer_master)上进行修改。
    追加的处理代码:
    1. // 传输72字节,等同于24组码位
    2. // 每个WS2812使用3个字节、24位控制,换成码位数据为96位,
    3. // 这96位换算成码位字节数数据=96/8=12字节,6个WS2812就是6*12=72字节
    4. #define TRANSFER_SIZE     72U     /* Transfer dataSize */
    5. // SPI主频设置为3MHz,保证WS2812的驱动时序
    6. #define TRANSFER_BAUDRATE 3000000U /* Transfer baudrate - 3MHz */

    7. #define        LED_LD        10                                    //亮度,最大255
    8. #define        WS2812_NUM        6                                //LED灯个数
    9. #define        SPI_NUM        (WS2812_NUM*12)            //LED灯对应SPI字节数(码位数据,供72字节)
    10. uint8_t        led_RGB[WS2812_NUM][3];            //LED对应的RGB,led_buff[i][0]-->绿,led_buff[i][1]-->红,led_buff[i][0]-->蓝.

    11. // 将颜色装载到SPI发送数据单元
    12. void convWS2812Data(void) {
    13.         uint8_t          *px;
    14.         uint16_t  i,j;
    15.         uint16_t  k;
    16.         uint8_t          dat;

    17.     // 测试用数据:红、绿、蓝、蓝、绿、红
    18.     // 第1个LED:红色
    19.     led_RGB[0][0] = 0;
    20.     led_RGB[0][1] = LED_LD;        //红色的显示亮度
    21.     led_RGB[0][2] = 0;

    22.     // 第2个LED:绿色
    23.     led_RGB[1][0] = LED_LD;        //绿色的显示亮度
    24.     led_RGB[1][1] = 0;
    25.     led_RGB[1][2] = 0;

    26.     // 第3个LED:蓝色
    27.     led_RGB[2][0] = 0;
    28.     led_RGB[2][1] = 0;
    29.     led_RGB[2][2] = LED_LD;        //蓝色的显示亮度

    30.     // 第4个LED:蓝色
    31.     led_RGB[3][0] = 0;
    32.     led_RGB[3][1] = 0;
    33.     led_RGB[3][2] = LED_LD;        //蓝色的显示亮度

    34.     // 第5个LED:绿色
    35.     led_RGB[4][0] = LED_LD;        //绿色的显示亮度
    36.     led_RGB[4][1] = 0;
    37.     led_RGB[4][2] = 0;

    38.     // 第6个LED:红色
    39.     led_RGB[5][0] = 0;
    40.     led_RGB[5][1] = LED_LD;        //红色的显示亮度
    41.     led_RGB[5][2] = 0;

    42.     // 初始化要发送的数据
    43.         for(i=0; i<SPI_NUM; i++)        masterTxData[i] = 0;

    44.     // 设置中间变量使用的起始地址
    45.         px = &led_RGB[0][0];        //首地址

    46.     // 循环WS2812数量对应的红绿蓝三个字节数据
    47.         for(i=0, j=0; i<(WS2812_NUM*3); i++) {
    48.                 dat = *px;
    49.                 px++;
    50.         // 处理对应WS2812的字节数据,每个WS2812的绿红蓝3个字节,对应为24位。
    51.         // 每次处理2位
    52.         // 转换每个数据位对应的0码/1码为4位基本码位数据
    53.                 for(k=0; k<4; k++) {
    54.                         if(dat & 0x80)
    55.                                 masterTxData[j]  = 0xE0;        // 字码1 : 1110xxxx,
    56.                         else
    57.                                 masterTxData[j]  = 0x80;        // 字码0 : 1000xxxx

    58.                         if(dat & 0x40)
    59.                                 masterTxData[j] |= 0x0E;        // 字码1 : 1110
    60.                         else
    61.                                 masterTxData[j] |= 0x08;        // 字码0 : 1000

    62.             // 每次处理2位,2位对应WS2912的一个字节
    63.                         dat <<= 2;

    64.             // 指向下一个字节(红、绿、蓝顺序)
    65.                         j++;
    66.                 }
    67.         }
    68. }
    复制代码
    在主程序处理中,完成了SPI外设的初始化后,启动WS2812的驱动处理:
    1.     // 配置WS2812数据
    2.         convWS2812Data();

    3.     /* Print out transmit buffer */
    4.     PRINTF("\r\n Master transmit:\r\n");
    5.     for (i = 0; i < TRANSFER_SIZE; i++) {
    6.         /* Print 16 numbers in a line */
    7.         if ((i % 12) == 0U) {
    8.             PRINTF("\r\n");
    9.         }
    10.         PRINTF(" %02X", masterTxData[i]);
    11.     }
    12.     PRINTF("\r\n");

    13.     // 启动传输
    14.     masterXfer.txData   = masterTxData;
    15.     masterXfer.rxData   = NULL;
    16.     masterXfer.dataSize = TRANSFER_SIZE;
    17.     isTransferCompleted = false;

    18.     LPSPI_MasterTransferEDMALite(EXAMPLE_LPSPI_MASTER_BASEADDR, &g_m_edma_handle,&masterXfer);

    19.     // 等待传输完成
    20.     while (!isTransferCompleted);
    21.     PRINTF("The Transfer is Completed!\r\n");
    复制代码

    测试效果如下:
    图片10.png

    图片13.png

    实测SPI的接口波形信号:
    图片11.png
    图片12.png


    哎...今天够累的,签到来了~
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2024-5-23 06:13
  • 签到天数: 1082 天

    连续签到: 1 天

    [LV.10]以坛为家III

    18

    主题

    1975

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    6266
    最后登录
    2025-10-5
    发表于 2024-12-5 17:57:45 | 显示全部楼层
    工具齐全,技艺精湛,行文流畅!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    昨天 14:16
  • 签到天数: 1171 天

    连续签到: 2 天

    [LV.10]以坛为家III

    28

    主题

    4410

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    6071
    最后登录
    2025-10-7
     楼主| 发表于 2024-12-5 21:07:59 | 显示全部楼层
    过奖过奖,玩的时间长了,一点点积累起这些家当。谢谢!
    哎...今天够累的,签到来了~
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-10-8 15:00 , Processed in 0.122131 second(s), 22 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

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