ws2812根据芯片手册查看逻辑0与逻辑1的电平设置以及时序按照GRB的顺序高位先发。
在此尝试4种方法点亮:
1.用nop()指令 原理主要是通过GPIO翻转写0或写1实现逻辑0与逻辑1然后利用cpu执行几个空指令产生短延时的效果。也可自己写延时函数让其做加减乘除从而达到延时的效果
主要代码如下:
#include "main.h"
#define LOW 0
#define HIGH 1
#define DI PD0
#define NUM 24 #define NOP \{ \__NOP();__NOP();__NOP();__NOP();__NOP(); \__NOP();__NOP();__NOP();__NOP();__NOP(); \__NOP();__NOP();__NOP();__NOP();__NOP(); \__NOP();__NOP();__NOP();__NOP();__NOP(); \__NOP();__NOP();__NOP();__NOP();__NOP(); \__NOP();__NOP();__NOP();__NOP();__NOP(); \__NOP();__NOP();__NOP();__NOP();__NOP(); \__NOP();__NOP();__NOP();__NOP();__NOP(); \__NOP();__NOP();__NOP();__NOP();__NOP(); \__NOP();__NOP();__NOP();__NOP();__NOP(); \__NOP();__NOP();__NOP();__NOP();__NOP(); \}
void gpio_init(void)
{rcu_periph_clock_enable(RCU_GPIOD);gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_0);gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_0);gpio_bit_reset(GPIOD,GPIO_PIN_0);
}
void ws2812_init()
{unsigned char i;gpio_bit_reset(GPIOD,GPIO_PIN_0);for(i=0;i<=200;i++){NOP;}
}
void ws2812_write_0() {gpio_bit_set(GPIOD, GPIO_PIN_0);//输出高电平 0.25usNOP;gpio_bit_reset(GPIOD, GPIO_PIN_0);//输出低电平 1usNOP;NOP;NOP;NOP;
}
void ws2812_write_1()
{gpio_bit_set(GPIOD, GPIO_PIN_0);//输出高电平 1usNOP;NOP;NOP;NOP;gpio_bit_reset(GPIOD, GPIO_PIN_0);//输出低电平0.25usNOP;
}
//写入数据
void ws2812_write_24bits(unsigned long dat)
{unsigned char t[NUM] = {0};unsigned char i;for (i = 0; i < NUM; i++) {if (dat << i & 0x800000) {t[i] = HIGH;} else {t[i] = LOW;}}for (i = 0; i < NUM; i++) {if (t[i]) {ws2812_write_1();} else {ws2812_write_0();}}
}void ws2812_test()
{unsigned int i = 0;unsigned int j = 0;unsigned int index = 1;unsigned long colors[8] = {0x010101, 0xff0000, 0x00ff00, 0x0000ff,0xffff00, 0xff00ff, 0x00ffff, 0xffffff};ws2812_init();ws2812_write_24bits(0x00ff00);ws2812_write_24bits(0x010101);for (i = 0; i <= 200*50*100; i++) {NOP;}while(1);}int main(void)
{systick_config(); gpio_init();ws2812_test();
}
2.通过pwm产生逻辑0 与逻辑1的波形
3.通过spi的方式 原理:ws2812的速率为800K/s,则周期为1.25us.通过设置spi的预分频以及自动装载值使得产生周期为1.25us左右的波形
这是参考网上的代码
main.c
#include "main.h"
#define LOW 0
#define HIGH 1
#define DI PD0
#define NUM 24 int main(void)
{RGBColor_TypeDef Color;float data[7];systick_config();SPI2_Init();Color.R = 255;Color.G = 1;Color.B = 1;Set_LEDColor(0,Color);RGB_Reflash();Set_LEDColor(1,BLUE);RGB_Reflash();delay_1ms(1000);while(1) {}
}
ws2812.c
#include "ws2812s.h"
#include "systick.h"
#include "stdio.h"// 常见颜色定义
const RGBColor_TypeDef RED = {1, 0, 0};
const RGBColor_TypeDef BLUE = {0, 0, 1};
const RGBColor_TypeDef GREEN = {0, 1, 0};
//用spi字节模拟bit
const uint8_t code[2]={0xC0,0xF8};
// 灯颜色缓存
RGBColor_TypeDef RGB_Data[LED_NUM];uint8_t spi2_Master_transmit_receive(uint8_t data)
{while(RESET == spi_i2s_flag_get(SPI2, SPI_FLAG_TBE));spi_i2s_data_transmit(SPI2, data);//while(RESET == spi_i2s_flag_get(SPI2, SPI_FLAG_RBNE));//return spi_i2s_data_receive(SPI2);
}void SPI_Send_WS2812(uint8_t* data)
{uint8_t i = 24;while(i--){spi2_Master_transmit_receive(*data++);}
}/*** @brief 设置灯带颜色发送缓存* @param[in] ID 颜色*/
void Set_LEDColor(uint16_t i, RGBColor_TypeDef Color)
{RGB_Data[i].G = Color.G;RGB_Data[i].R = Color.R;RGB_Data[i].B = Color.B;
}
void RGB_Reflash()
{static uint8_t RGB_BUFFER[24]={0};uint8_t dat_b,dat_r,dat_g;uint16_t i;for(i=0;i<LED_NUM;i++){// 将数组颜色转化为24个要发送的字节数据dat_g = RGB_Data[i].G;dat_r = RGB_Data[i].R;dat_b = RGB_Data[i].B;for (uint16_t j = 0; j < 8; j++) {RGB_BUFFER[7-j] =code[dat_g & 0x01];RGB_BUFFER[15-j]=code[dat_r & 0x01];RGB_BUFFER[23-j]=code[dat_b & 0x01];dat_g >>=1;//dat_g=dat_g>>1 = dat_g/2dat_r >>=1;dat_b >>=1;} SPI_Send_WS2812(RGB_BUFFER);} delay_1ms(1);
}
ws2812.h
#ifndef __WS2812S_H
#define __WS2812S_H#include "gd32f4xx_libopt.h"#define LED_NUM 2 /* LED灯珠个数*/typedef struct {uint8_t R;uint8_t G;uint8_t B;
}RGBColor_TypeDef; //颜色结构体
// 常见颜色定义
extern const RGBColor_TypeDef RED ;
extern const RGBColor_TypeDef BLUE;
extern const RGBColor_TypeDef GREEN;void RGB_Reflash(void);
void Set_LEDColor(uint16_t LedId, RGBColor_TypeDef Color);#endif
spi 初始化
void SPI2_Init(void)
{spi_parameter_struct spi_init_struct;rcu_periph_clock_enable(RCU_SPI2);//复用功能时钟rcu_periph_clock_enable(RCU_GPIOD); /* configure SPI2 GPIO: MOSI/PD0 */gpio_af_set(GPIOD, GPIO_AF_6, GPIO_PIN_0);gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_0);gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0);/* deinitialize SPI and the parameters */spi_i2s_deinit(SPI2);//重新设置参数spi_struct_para_init(&spi_init_struct); //初始化参数为默认状态
/* configure SPI0 parameter */spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;spi_init_struct.device_mode = SPI_MASTER;spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE;spi_init_struct.nss = SPI_NSS_SOFT;spi_init_struct.prescale = SPI_PSC_8;spi_init_struct.endian = SPI_ENDIAN_MSB;spi_init(SPI2, &spi_init_struct);spi_enable(SPI2);
}