ARM技术论坛
直播中

HonestQiao

9年用户 577经验值
擅长:嵌入式技术
私信 关注
[经验]

【触觉智能 Purple Pi开发板试用】控制WS2812B炫彩灯珠

WS2812B

在上一篇文章 【新提醒】【触觉智能 Purple Pi开发板试用】macOS上建立Purple Pi开发环境,再使用C点灯 中,分享了使用C语言控制GPIO点亮LED灯,在这个基础上,可以做的更多。

经过了解,开发板上提供了SPI接口,具体可以查看主板背面信息:
1.底板图.jpeg

要控制WS2812B炫彩灯珠,只需要使用一根数据线即可,达到6.4MHz的发送速度,就能够很方便的发送控制数据了。而SPI的MOSI,就能够帮助发送这个数据。
当然,上面这个6.4MHz只是根据WS2812B的数据需要,得到的一个经验值。很多大佬们有更高效的方式,值得好好学习,这里先用最笨的方式来进行。

那么,将WS2812B的DI接到SPI-MOSI接口上,并接上5V、GND即可。
image.png

然后编写控制程序ws2812_test.c:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <time.h>
#include <math.h>

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

#define TRST 0x00
#define TOL 0x80
#define TOH 0xf8

unsigned char default_tx_reset[] = {
    TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, 
    TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, 
    TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, 
    TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, 
    TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, 
    TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, 
    TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, 
    TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST, TRST};

unsigned char default_tx0[] = {
    TOL, TOL, TOL, TOL, TOL, TOL, TOL, TOL,
    TOL, TOL, TOL, TOL, TOL, TOL, TOL, TOL,
    TOL, TOL, TOL, TOL, TOL, TOL, TOL, TOL};

unsigned char default_tx1[7][24] = {
    {
    TOH, TOH, TOH, TOH, TOH, TOH, TOH, TOH,
    TOL, TOL, TOL, TOL, TOL, TOL, TOL, TOL,
    TOL, TOL, TOL, TOL, TOL, TOL, TOL, TOL
    },
    {
    TOL, TOL, TOL, TOL, TOL, TOL, TOL, TOL,
    TOH, TOH, TOH, TOH, TOH, TOH, TOH, TOH,
    TOL, TOL, TOL, TOL, TOL, TOL, TOL, TOL,
    },
    {
    TOL, TOL, TOL, TOL, TOL, TOL, TOL, TOL,
    TOL, TOL, TOL, TOL, TOL, TOL, TOL, TOL,
    TOH, TOH, TOH, TOH, TOH, TOH, TOH, TOH
    },
    {
    TOH, TOH, TOH, TOH, TOH, TOH, TOH, TOH,
    TOH, TOH, TOH, TOH, TOH, TOH, TOH, TOH,
    TOL, TOL, TOL, TOL, TOL, TOL, TOL, TOL,
    },
    {
    TOH, TOH, TOH, TOH, TOH, TOH, TOH, TOH,
    TOL, TOL, TOL, TOL, TOL, TOL, TOL, TOL,
    TOH, TOH, TOH, TOH, TOH, TOH, TOH, TOH
    },
    {
    TOL, TOL, TOL, TOL, TOL, TOL, TOL, TOL,
    TOH, TOH, TOH, TOH, TOH, TOH, TOH, TOH,
    TOH, TOH, TOH, TOH, TOH, TOH, TOH, TOH
    },
    {
    TOH, TOH, TOH, TOH, TOH, TOH, TOH, TOH,
    TOH, TOH, TOH, TOH, TOH, TOH, TOH, TOH,
    TOH, TOH, TOH, TOH, TOH, TOH, TOH, TOH}
};



unsigned char default_rx[ARRAY_SIZE(default_tx0)] = {
    0,
};

int main(int argc, char **argv)
{
    int fd;
    char dev_node[16];
    int mode = 1, bits =8, speed = 6400 * 1000;//6400000;//ceil(8 / 1.25e-6);
    int ret = 0;
    unsigned char tx_buf[1000], rx_buf[1000];
    struct spi_ioc_transfer tr;
    int i, t1, t2;

    sprintf(dev_node, "/dev/spidev%d.0", atoi(argv[1]));
    fd = open(dev_node, O_RDWR);
    if (fd < 0)
    {
        perror("open");
        return -1;
    }

    /* Mode */
    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
    if (ret < 0)
    {
        perror("SPI_IOC_WR_MODE");
        return -1;
    }
    ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
    if (ret < 0)
    {
        perror("SPI_IOC_RD_MODE");
        return -1;
    }

    /* bpw */
    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    if (ret < 0)
    {
        perror("SPI_IOC_WR_BITS_PER_WORD");
        return -1;
    }
    ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
    if (ret < 0)
    {
        perror("SPI_IOC_RD_BITS_PER_WORD");
        return -1;
    }

    /* speed */
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    if (ret < 0)
    {
        perror("SPI_IOC_WR_MAX_SPEED_HZ");
        return -1;
    }
    ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
    if (ret < 0)
    {
        perror("SPI_IOC_RD_MAX_SPEED_HZ");
        return -1;
    }

    printf("spi = %s\n", dev_node);
    printf("Mode = %d\n", mode);
    printf("Bpw = %d\n", bits);
    printf("Baudrate = %d\n", speed);

    tr.tx_buf = (unsigned long)default_tx0;
    tr.rx_buf = (unsigned long)default_rx;
    tr.len = sizeof(default_tx0);
    tr.delay_usecs = 0;
    tr.speed_hz = speed;
    tr.bits_per_word = bits;

    printf("len=%d speed_hz=%d\ndata: 0=[", tr.len, tr.speed_hz);
    for (int i = 0; i < tr.len; i++)
    {
        printf("%02X ", default_tx0[i]);
    }
    printf("]\ndata: 1=[");
    for (int i = 0; i < tr.len; i++)
    {
        printf("%02X ", default_tx1[i]);
    }
    printf("]\n");    

    int index = 0;
    while (1)
    {
        if(index%8==0) {
            ret = write(fd,default_tx0,ARRAY_SIZE(default_tx0));
            if (ret < 1)
                printf("can't send tx0 message ret=%d\n", ret);          
            usleep(1000*1000);            
        } else {
            ret = write(fd,default_tx1[index%8-1],ARRAY_SIZE(default_tx1[0]));
            if (ret < 1)
                printf("can't send tx1 message ret=%d\n", ret);          
            usleep(1000*1000);
        }
        index++;
    };

    return 0;
}

上述代码的逻辑如下:

  1. 打开/dev/spidev0.0
  2. 设置工作模式,及速率为6.4MHz
  3. 然后循环发送数据,发送次数取8的模,=0的时候熄灭,其他时候循环其中颜色

编写完成,编译并上传:

arm-unknown-linux-gnueabihf-gcc ws2812_test.c -o ws2812_test
scp ws2812_test root@192.168.1.30:/root/

然后到开发板上运行:【注意cd切换到/root/再执行】
image.png

WS2812B就会欢快的亮起来,变换颜色了。

WS2812B

更多回帖

发帖
×
20
完善资料,
赚取积分