ESP8266 + WS2812 颜色、亮度控制

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zzzw0/article/details/84201202

注意别把灯带接反了,哪边是输入确认一下!!

 

刚开始想到的是用STM32中的DMA传输来实现,但是ESP8266 NONOS_SDK中似乎没有这种功能。

可以基于NODEMCU开发,类似NODE.JS的语法来写,懒得学,又要在Linux环境下编译固件(也可以在NODEMCU官网上自己选择需要的功能,编译好了通过邮件发送给你)就放弃了,以后再尝试。

最终还是用安信可的SDK来做。

项目开发期间使用nodemcu的开发板,接线、下载的时候方便多了。

尝试了下面三种方法。

①试过直接用操作IO电平的函数是不行的,频率太低,不知道是什么原因。

②还可以用串口的方法输出数据,只需将串口配置成6位数据位,无奇偶校验,1位停止位(低电平),起始位必须有1位(低电平),这样就可以使每一帧数据都是8位数据(方便计算所需的波特率),再配置电平翻转(这样两边都是高电平),通过控制6位数据位,控制这一帧数据的高电平时间,从而使WS2812区分出0或1(即串口输出的一帧数据对应WS2812接收到的0或者1)。这个方法比较麻烦,但它不是阻塞式的,将数据存储在串口发送缓冲区即可,后面的电平输出由串口发送中断自动完成。具体参考

③基于NONOS_SDK_2.2.0 ,就是安信可官方的那一套,直接用WRITE_PERI_REG函数来将数据输出,该函数在eagle_soc.c 。

贴代码:

Adafruit_NeoPixel.c

#include "Adafruit_NeoPixel.h"
#include "ets_sys.h"
#include "osapi.h"
/*
 #define GPIO_OUTPUT_SET(gpio_no, bit_value) \
	gpio_output_set(bit_value<<gpio_no, ((~bit_value)&0x01)<<gpio_no, 1<<gpio_no,0)
 */

//I just used a scope to figure out the right time periods.
void SEND_WS_0() {
	uint8_t time;
	time = 3;
	while (time--)
		WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1);
	time = 7;
	while (time--)
		WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0);
}

void SEND_WS_1() {
	uint8_t time;
	time = 7;
	while (time--)
		WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1);
	time = 3;
	while (time--)
		WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0);
}

void // ICACHE_FLASH_ATTR
WS2812Send_8bit(uint8_t dat) {
	uint16_t i;
	GPIO_OUTPUT_SET(GPIO_ID_PIN(WSGPIO), 0);
	ets_intr_lock();
	uint8_t mask = 0x80;
	uint8_t byte = dat;
	while (mask) {
		if (byte & mask)
			SEND_WS_1();
		else
			SEND_WS_0();
		mask >>= 1;
	}

	ets_intr_unlock();
}

//GRB format,MSB firsr.
void //ICACHE_FLASH_ATTR
WS2812BSend_24bit(uint8_t R, uint8_t G, uint8_t B) {
	WS2812Send_8bit(G);
	WS2812Send_8bit(R);
	WS2812Send_8bit(B);
}
//delay for millisecond
void HAL_Delay(int time) {
	os_delay_us(time * 1000);
}

static uint8_t rBuffer[PIXEL_MAX] = { 0 };
static uint8_t gBuffer[PIXEL_MAX] = { 0 };
static uint8_t bBuffer[PIXEL_MAX] = { 0 };

void setOneColor(uint16_t n, uint32_t c) {
	rBuffer[n] = (uint8_t) (c >> 16);
	gBuffer[n] = (uint8_t) (c >> 8);
	bBuffer[n] = (uint8_t) c;
}

void setAllColor(uint32_t c) {
	uint8_t r, g, b;
	r = (uint8_t) (c >> 16);
	g = (uint8_t) (c >> 8);
	b = (uint8_t) c;
	uint8_t i;
	for (i = 0; i < PIXEL_MAX; i++) {
		rBuffer[i] = r;
		gBuffer[i] = g;
		bBuffer[i] = b;
	}
}

void cleanOneColor(uint16_t n, uint32_t c) {
	rBuffer[n] = 0;
	gBuffer[n] = 0;
	bBuffer[n] = 0;
}

void cleanAllColor() {
	uint8_t i;
	for (i = 0; i < PIXEL_MAX; i++) {
		rBuffer[i] = 0;
		gBuffer[i] = 0;
		bBuffer[i] = 0;
	}
}

void setAllPixel(void) {
	uint8_t i;
	for (i = 0; i < PIXEL_MAX; i++) {
		WS2812BSend_24bit(rBuffer[i], gBuffer[i], bBuffer[i]);
	}
}

uint32_t Color(uint8_t r, uint8_t g, uint8_t b) {
	return ((uint32_t) r << 16) | ((uint32_t) g << 8) | b;
}
uint32_t Wheel(uint8_t WheelPos) {
	WheelPos = 255 - WheelPos;
	if (WheelPos < 85) {
		return Color(255 - WheelPos * 3, 0, WheelPos * 3);
	}
	if (WheelPos < 170) {
		WheelPos -= 85;
		return Color(0, WheelPos * 3, 255 - WheelPos * 3);
	}
	WheelPos -= 170;
	return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

void rainbow(uint8_t wait) {
	uint16_t i, j;
	for (j = 0; j < 256; j++) {
		for (i = 0; i < PIXEL_MAX; i++) {
			setOneColor(i, Wheel((i + j) & 255));
		}
		HAL_Delay(wait);
	}
	setAllPixel();
}
// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
	uint16_t i, j;

	for (j = 0; j < 256 * 5; j++) { // 5 cycles of all colors on wheel
		for (i = 0; i < PIXEL_MAX; i++) {
			setOneColor(i, Wheel(((i * 256 / PIXEL_MAX) + j) & 255));
		}
		HAL_Delay(wait);
	}
	setAllPixel();
}
//Theatre-style crawling lights.o??¨¹¦Ì?
void theaterChase(uint32_t c, uint8_t wait) {
	int i, j, q;
	for (j = 0; j < 10; j++) {  //do 10 cycles of chasing
		for (q = 0; q < 3; q++) {
			for (i = 0; i < PIXEL_MAX; i = i + 1)  //turn every one pixel on
					{
				setOneColor(i + q, c);
			}
			HAL_Delay(wait);

			for (i = 0; i < PIXEL_MAX; i = i + 1) //turn every one pixel off
					{
				setOneColor(i + q, 0);
			}
		}
	}
	setAllPixel();
}

//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow(uint8_t wait) {
	int i, j, q;
	for (j = 0; j < 256; j++) {     // cycle all 256 colors in the wheel
		for (q = 0; q < 3; q++) {
			for (i = 0; i < PIXEL_MAX; i = i + 1) //turn every one pixel on
					{
				setOneColor(i + q, Wheel((i + j) % 255));
			}

			HAL_Delay(wait);

			for (i = 0; i < PIXEL_MAX; i = i + 1) //turn every one pixel off
					{
				setOneColor(i + q, 0);
			}
		}
	}
	setAllPixel();
}
// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
	uint16_t i = 0;
	for (i = 0; i < PIXEL_MAX; i++) {
		setOneColor(i, c);
		HAL_Delay(wait);
	}
}

void //ICACHE_FLASH_ATTR
WS2812B_Init(void) {
	setAllColor(0);
	setAllPixel();
}

void WS2812B_Test(void) {
	//HAL_Delay(500);
	// rainbowCycle(20);
	// theaterChaseRainbow(50);
}

 

Adafruit_NeoPixel.h

#ifndef _Adafruit_NeoPixel_H
#define _Adafruit_NeoPixel_H

#include "c_types.h"
#include "user_interface.h"
#include "ets_sys.h"
#include "gpio.h"

//thanks for https://github.com/cnlohr/ws2812esp8266 
//thanks for https://github.com/adafruit/Adafruit_NeoPixel

#define WSGPIO 0 //must use the ESP8266 GPIO0 as the pin to drive WS2812B RGB LED!!!
//user can change
#define PIXEL_MAX 12//the total numbers of LEDs you are used in your project

//You will have to 	os_intr_lock();  	os_intr_unlock();

//void setAllColor(uint8_t r, uint8_t g, uint8_t b);
void setOneColor(uint16_t n, uint32_t c);
void setAllColor(uint32_t c);
void cleanOneColor(uint16_t n, uint32_t c);
void cleanAllColor(void);

void setAllPixel(void);

uint32_t Color(uint8_t r, uint8_t g, uint8_t b);
uint32_t Wheel(uint8_t WheelPos);
void rainbowCycle(uint8_t wait) ;
void theaterChase(uint32_t c, uint8_t wait);
void theaterChaseRainbow(uint8_t wait);
void colorWipe(uint32_t c, uint8_t wait);
void WS2812B_Test(void);
void ICACHE_FLASH_ATTR WS2812B_Init(void);

uint32_t changeL(uint32_t rgb, float k);

#endif

改变亮度的话看网上别人说的:RGB转HSV后,将V值乘以系数[0,1] ,再HSV转RGB。

发现好像直接将RGB值都乘以系数,结果是一样的。。。

uint32_t changeL(uint32_t rgb, float k) {
	uint8_t r, g, b;
	float h, s, v;
	uint8_t cmax, cmin, cdes;

	r = (uint8_t) (rgb >> 16);
	g = (uint8_t) (rgb >> 8);
	b = (uint8_t) (rgb);

	os_printf("1:  0x%x \r\n", rgb);
	os_printf("1:  %d %d %d \r\n", r, g, b);

	cmax = r > g ? r : g;
	if (b > cmax)
		cmax = b;
	cmin = r < g ? r : g;
	if (b < cmin)
		cmin = b;
	cdes = cmax - cmin;

	v = cmax / 255.0f;
	s = cmax == 0 ? 0 : cdes / (float) cmax;
	h = 0;

	if (cmax == r && g >= b)
		h = ((g - b) * 60.0f / cdes) + 0;
	else if (cmax == r && g < b)
		h = ((g - b) * 60.0f / cdes) + 360;
	else if (cmax == g)
		h = ((b - r) * 60.0f / cdes) + 120;
	else
		h = ((r - g) * 60.0f / cdes) + 240;

	//////

	v *= k;

	float f, p, q, t;
	float rf, gf, bf;
	int i = ((int) (h / 60) % 6);
	f = (h / 60) - i;
	p = v * (1 - s);
	q = v * (1 - f * s);
	t = v * (1 - (1 - f) * s);
	switch (i) {
	case 0:
		rf = v;
		gf = t;
		bf = p;
		break;
	case 1:
		rf = q;
		gf = v;
		bf = p;
		break;
	case 2:
		rf = p;
		gf = v;
		bf = t;
		break;
	case 3:
		rf = p;
		gf = q;
		bf = v;
		break;
	case 4:
		rf = t;
		gf = p;
		bf = v;
		break;
	case 5:
		rf = v;
		gf = p;
		bf = q;
		break;
	default:
		break;
	}

	r = (uint8_t) (rf * 255.0);
	g = (uint8_t) (gf * 255.0);
	b = (uint8_t) (bf * 255.0);

	uint32_t returnColor = ((uint32_t) r << 16) | ((uint32_t) g << 8) | b;
	os_printf("2:  %d %d %d \r\n", (int) r, (int) g, (int) b);
	os_printf("2:  0x%x \r\n\r\n", returnColor);
	return returnColor;
}

 

展开阅读全文

没有更多推荐了,返回首页