在上一篇文章 【新提醒】【触觉智能 Purple Pi开发板试用】macOS上建立Purple Pi开发环境,再使用C点灯 中,分享了使用C语言控制GPIO点亮LED灯,在这个基础上,可以做的更多。
经过了解,开发板上提供了SPI接口,具体可以查看主板背面信息:
要控制WS2812B炫彩灯珠,只需要使用一根数据线即可,达到6.4MHz的发送速度,就能够很方便的发送控制数据了。而SPI的MOSI,就能够帮助发送这个数据。
当然,上面这个6.4MHz只是根据WS2812B的数据需要,得到的一个经验值。很多大佬们有更高效的方式,值得好好学习,这里先用最笨的方式来进行。
那么,将WS2812B的DI接到SPI-MOSI接口上,并接上5V、GND即可。
然后编写控制程序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;
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;
}
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;
}
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;
}
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;
}
上述代码的逻辑如下:
- 打开/dev/spidev0.0
- 设置工作模式,及速率为6.4MHz
- 然后循环发送数据,发送次数取8的模,=0的时候熄灭,其他时候循环其中颜色
编写完成,编译并上传:
arm-unknown-linux-gnueabihf-gcc ws2812_test.c -o ws2812_test
scp ws2812_test root@192.168.1.30:/root/
然后到开发板上运行:【注意cd切换到/root/再执行】
WS2812B就会欢快的亮起来,变换颜色了。