ATTiny85 + Adafruit_NeoPixel not working with array - c++

I want to create a LED animation using Adafruit_NeoPixel library.
Unfortunately I'm struggling with a probably dump thing. For some reason the strip does not anymore work when using a certain array access if (led_states[pixel] > 0) {. Meaning even strip.clean() + strip.show() in setup doesn't work anymore. May you can tell me what I did wrong because I really don't get it. PS: I'm using ATTiny85 with arduino framework if that helps.
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
#include <SoftwareSerial.h>
#define LED_AMOUNT 30
#define LED_DATA_PIN PB1
SoftwareSerial SWSERIAL(0, PB3); // RX, TX
Adafruit_NeoPixel strip(LED_AMOUNT, LED_DATA_PIN, NEO_GRB + NEO_KHZ800);
int step = 2;
int max = 255 - step;
int led_states[LED_AMOUNT] = { 0 };
int led_values[LED_AMOUNT] = { 0 };
unsigned long last_frame = 0;
unsigned long last_change = 0;
void led_test_setup() {
delay(5000);
SWSERIAL.begin(9600);
SWSERIAL.println("Setup");
randomSeed(analogRead(0));
strip.begin();
strip.clear();
strip.show();
}
void led_test_loop() {
unsigned long now = millis();
if (last_change + 200 < now) {
int pixel = random(0, LED_AMOUNT);
led_states[pixel] = 1;
led_values[pixel] = 0;
last_change = now;
}
if (last_frame + 10 < now) {
for (int pixel = 0; pixel < LED_AMOUNT; pixel++) {
if (led_states[pixel] > 0) { // <---- strip works when commenting this block
SWSERIAL.printf("V: %i\n", led_values[pixel]);
}
strip.setPixelColor(pixel, led_values[pixel], led_values[pixel], led_values[pixel]);
}
last_frame = now;
strip.show();
}
}

I may found the issue. Seems like SoftwareSerial and Neopixel library are using both interrupts which then corrupts neo pixel communication.
Found here: https://forum.arduino.cc/t/arduino-nano-softwareserial-adafruit_neopixel-problem/540057/2

Related

Issues with RGB led and Servomotors

I'm on my first Arduino project... On this project, I use an RGB led and 2 Servomotors...
First off all, following OOP, I create a class to control my RGB led...
class StatusLED {
private:
int pinRed;
int pinGreen;
int pinBlue;
public:
StatusLED(int pinRed, int pinGreen, int pinBlue);
void RGB(int redValue, int greenValue, int blueValue);
};
It's working very well, without issues...
After there is all fine with the RGB led, I start to include my Servomotor code...
#include <Servo.h>
#define PIN_RGBLED_R 9
#define PIN_RGBLED_G 10
#define PIN_RGBLED_B 11
#define PIN_SERVO_H 12
#define PIN_SERVO_V 13
Servo servoH;
Servo servoV;
LED led(PIN_RGBLED_R, PIN_RGBLED_G, PIN_RGBLED_B);
void setup() {
servoH.attach(PIN_SERVO_H);
servoV.attach(PIN_SERVO_V);
}
And after I include the servo.attach() lines, my RBG led has a strange behavior, the colors that I used before, like Light Purple RGB(2, 0, 2);, doesn't work anymore, now when i try it, the led turns on with Red color.
If I comment the servo.attach() lines, the led works well.
Already tried:
Change Servo libraries version;
Change servos to another pins;
Someone can please help me?
EDIT:
Just to eliminate the doubt of my LED class are the problem, I create a new file...
#include <Servo.h>
#define PIN_SERVO_H 3
#define PIN_SERVO_V 4
#define PIN_RGBLED_R 9
#define PIN_RGBLED_G 10
#define PIN_RGBLED_B 11
Servo servoH;
Servo servoV;
void setup() {
pinMode(PIN_RGBLED_R, OUTPUT);
pinMode(PIN_RGBLED_G, OUTPUT);
pinMode(PIN_RGBLED_B, OUTPUT);
servoH.attach(PIN_SERVO_H);
servoV.attach(PIN_SERVO_V);
}
void loop() {
RGB(2,0,2);
delay(100);
RGB(4,0,4);
delay(100);
RGB(8,0,8);
delay(100);
RGB(16,0,16);
delay(100);
RGB(0,0,0);
delay(1000);
}
void RGB(int redValue, int greenValue, int blueValue) {
if (redValue > 255) {
redValue = 255;
}
if (greenValue > 255) {
greenValue = 255;
}
if (blueValue > 255) {
blueValue = 255;
}
if (redValue < 0) {
redValue = 0;
}
if (greenValue < 0) {
greenValue = 0;
}
if (blueValue < 0) {
blueValue = 0;
}
// This is a common anode RGB Led.
// So 255 is OFF and 0 is Fully ON
analogWrite(PIN_RGBLED_R, 255 - redValue);
analogWrite(PIN_RGBLED_G, 255 - greenValue);
analogWrite(PIN_RGBLED_B, 255 - blueValue);
}
And the problem continues... if I comment the lines of attach() the led works fine, without comment, it only blinks in Red color...
Depending on the version of your arduino, servo.attach only works on Pin 9 and Pin 10, which conflicts with your RGB pins. See https://www.arduino.cc/en/Reference/ServoAttach

How do I use an arduino as an LED controller?

I'm a total C++ newbie, but I recently got an arduino and I'm doing my first project with it. I may be jumping into the deep end here, but I've got some experience with electronics already. I also have some experience with python.
I want to make a fancy interior lighting setup using two of these led strips and this arduino starter kit.
I need to make a whole bunch of presets that can be quickly activated using the IR remote included with the kit.
I need to be able to split the strips into individual zones , which I can use to easily set the presets. Maybe I want preset1 to be the ceiling lights a dark blue at 50% brightness and the window lights an orange at 25% brightness.
I know that to achieve this I want every button on the remote to call a different function. I've written some Psuedocode and I'd like some advice on the best way to learn how to implement this on an arduino.
I really need help with the software side of this project, the hardware side is all good.
disclaimer: I haven't touched coding since high school, so my psuedocode is probably trash. I just hope it's vaguely understandable
//Psuedocode attempt to make an LED thingy
// Importing needed libraries
Import fastled
Import IRremote
define num_led 300
define data_pin 5
// defining various zones. Zone 1 = Under cabinet, Zone 2 = Around window etc.
Global zone1 = num_led [0:24]
Global zone2 = num_led [24:172]
Global zone3 = num_led [173:277]
Global zone4 = num_led [278:299]
Def preset1()
for led in zone1:
ledRGB = (160, 0, 210)
for led in zone2:
ledRGB = (120, 0, 24)
for led in zone3:
ledRGB = (0, 0, 0)
for led in zone4:
ledRGB = (100,100,100)
// Make a whole bunch more of these normal presets
Def preset6()
for led in zone1:
do cool fastled animation
for led in zone2:
do different fastled animation
for led in zone3:
ledRGB = (0, 0, 0)
for led in zone4:
ledRGB = (0, 0, 0)
// Make a whole bunch more of these fancy presets
Def BrightnessUp()
i = 0
for num_led in zone1 and zone2 and zone3 and zone4:
if i in ledRGB > 0: //This is to minimise colour shift. Any RGB channel set at 0 won’t increase.
i = i+10
else:
return
// Similar for brightness down
void setup() {
FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);
{
//The following is mostly copy pasted C++ code with modifications
//It works to understand the IR remote inputs and call functions based on input
const int RECV_PIN = 7;
IRrecv irrecv(RECV_PIN);
decode_results results;
unsigned long key_value = 0;
void setup(){
irrecv.enableIRIn();
irrecv.blink13(true);
}
void loop(){
if (irrecv.decode(&results)){
if (results.value == 0XFFFFFFFF)
results.value = key_value;
switch(results.value)
case 0xFF30CF:
Serial.println("1");
Call preset1()
break ;
case 0xFF18E7:
Serial.println("2");
Call preset2()
break ;
case 0xFF7A85:
Serial.println("3");
Call preset3()
break ;
//ETC for every number on remote
case 0xFFE01F:
Serial.println("-");
Call BrigtnessDown()
break ;
case 0xFFA857:
Serial.println("+");
Call BrightnessUp()
break ;
}
key_value = results.value;
irrecv.resume();
}
}
Steps to be followed are
Install the FastLED Library from GitHub: FastLED Lib
Install the IRremote Library from GitHub: IRremote Lib
Import it to your Arduino library folder via Arduino IDE: Importing a .zip Library
Here is a basic structure of the program which we will require.
#include "FastLED.h"
#include "IRremote.h"
#define DATA_PIN 5 // digital pin of your arduino
#define NUM_LEDS 300
CRGB leds[NUM_LEDS];
//Zones array
int zone1[2] = {0, 24}; //For zone1: Start,End
int zone2[2] = {25, 172}; //For zone2: Start,End
int zone3[2] = {173, 277}; //For zone3: Start,End
int zone4[2] = {278, 299}; //For zone4: Start,End
// For IR receiver
const int RECV_PIN = 3; // Hardware specs allows 3 or 9 pin to be used for ATmega328p
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup() {
//Setup for FastLED
FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);
//Setup for IRremote
pinMode(LED_BUILTIN, OUTPUT); //LED_BUILTIN is the inbuild led on Arduino UNO at Pin13
irrecv.enableIRIn(); // Start the receiver
irrecv.blink13(true); // Enable blinking the LED when during reception
}
void loop() {
if (irrecv.decode(&results)) {
Serial.println(results.value, HEX);
switch (results.value) {
case 0xFF30CF:
Serial.println("1");
preset1();
break;
case 0xFF18E7:
Serial.println("2");
//preset2(); //TODO: Complete this preset2
break;
case 0xFF7A85:
Serial.println("3");
//preset3(); //TODO: Complete this preset3
break;
//ETC for every number on remote
case 0xFFE01F:
Serial.println("-");
brightnessDown();
break;
case 0xFFA857:
Serial.println("+");
brightnessUp();
break;
default:
Serial.println("Not Understood.");
break;
}
irrecv.resume(); // Receive the next value
}
delay(100);
}
void preset1()
{
//Zone 1
for (int i = zone1[0]; i <= zone1[1]; i++) {
leds[i] = CRGB(160, 0, 210);
}
//Zone 2
for (int i = zone2[0]; i <= zone2[1]; i++) {
leds[i] = CRGB(120, 0, 24);
}
//Zone 3
for (int i = zone3[0]; i <= zone3[1]; i++) {
leds[i] = CRGB(0, 0, 0);
}
//Zone 4
for (int i = zone4[0]; i <= zone4[1]; i++) {
leds[i] = CRGB(100, 100, 100);
}
//To set the LEDs
FastLED.show();
}
void brightnessUp()
{
for (int i = 0; i < NUM_LEDS; i++) {
if (leds[i].r > 0)
leds[i].r = leds[i].r + 10;
if (leds[i].g > 0)
leds[i].g = leds[i].g + 10;
if (leds[i].b > 0)
leds[i].b = leds[i].b + 10;
}
//To set the LEDs
FastLED.show();
}
void brightnessDown()
{
for (int i = 0; i < NUM_LEDS; i++) {
if (leds[i].r > 10)
leds[i].r = leds[i].r - 10;
if (leds[i].g > 10)
leds[i].g = leds[i].g - 10;
if (leds[i].b > 10)
leds[i].b = leds[i].b - 10;
}
//To set the LEDs
FastLED.show();
}
Note: This code this created with the help of Pseudo-code provided and the logic implemented in it, you may have to change certain things in order for it to produce best results.

Code keeps looping even if serial is available

I'm using an external application to sync my RGB peripherals with my WS2812B Strip. I wanted to make a default color that it could switch to when the application isn't running but after 2 seconds of enabling the strip in the software, it goes back to the default color I set (255,255,255).
#include <Adafruit_NeoPixel.h>
#define PIN 6
#define NUMPIXELS 30
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB +
NEO_KHZ800);
void setup() {
pixels.begin();
Serial.begin(19200, SERIAL_8E1);
}
void loop() {
for (int w = 0; w < NUMPIXELS; w++) {
pixels.setPixelColor(w, 255, 255, 255);
}
pixels.show();
int w = 0;
if (Serial.available()) {
int n = 0;
for (int n = 0; n < 3; n++) {
byte rgb[3];
Serial.readBytes(rgb, 3);
uint32_t r = int(rgb[0]);
uint32_t g = int(rgb[1]);
uint32_t b = int(rgb[2]);
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, r, g, b);
}
pixels.show();
}
}
}
The function Serial.available() does something else than what you expect:
You expect it to return if there is a communication partner available. Instead it checks if there are bytes to read available:
Get the number of bytes (characters) available for reading from the serial port. (Source: https://www.arduino.cc/en/Serial/Available )
This means: Your Arduino has run out of bytes to read, because it empties the pipeline too fast. So, as there are no more bytes to read, it will just make the leds show white.
Sidenote: The if condition should be changed to reflect this (see post on Arduino website):
if (Serial.available() > 0) {

How to read data only when a value is above or under a certain threshold

This may sound a little vague but I will try my best to clarify. Basically I am using an mbed (FRDM k64f) device which sends data to another device via XBee. My question is,
How do I get it to send data only when float mX,mY or mZ(see code below) are above or under a certain threshold, so the rest of the time it is asleep.
Is this possible?
So currently it is sending data every 5 seconds but I would like to change that.
Here is my current code
#include "mbed.h"
#include "C12832.h" //for LCD
#include "FXOS8700Q.h"// for magnetometer
Ticker timer;
DigitalOut gpo(D0);
DigitalOut led(LED_RED);
Serial xbee(D1, D0);
C12832 shld_lcd (D11, D13, D12, D7, D10);
FXOS8700Q_mag mSensor(PTE25, PTE24, FXOS8700CQ_SLAVE_ADDR1);
MotionSensorDataUnits mData;
//int tick = 0;
void setup() {
xbee.baud(9600);
}
/*
void attime() {
tick++;
}
*/
int main()
{
//timer.attach(&attime, 1);
mSensor.enable();
setup();
while (1) {
wait(5);
mSensor.getAxis(mData);
float mX = mData.x;
float mY = mData.y;
float mZ = mData.z;
xbee.printf("%.2f,%.2f,%.2f \r\n",mX,mY,mZ);
}
}
Just have a conditional expression:
while(1) {
wait(5);
msensor.getAxis(mData);
float mX = mData.x;
float mY = mData.y;
float mZ = mData.z;
if (mX >= mX_threshold && mY >= mY_threshold && mZ >= mZ_threshold)
xbee.printf("%.2f,%.2f,%.2f \r\n",mX,mY,mZ);
}
where mX_threshold (and similarly for Y and Z) are the threshold constraints you want.

Neopixel arduino fading from colour to colour using a Sparkcore

This question is a follow from another question I asked here that was answered.
I have the following function:
MotiColor startColor;
MotiColor endColor;
void setup()
{
// Begin strip.
strip.begin();
// Initialize all pixels to 'off'.
strip.show();
Serial1.begin(9600);
startColor = MotiColor(0, 0, 0);
endColor = MotiColor(0, 0, 0);
}
void loop () {
}
int tinkerSetColour(String command)
{
strip.show();
int commaIndex = command.indexOf(',');
int secondCommaIndex = command.indexOf(',', commaIndex+1);
int lastCommaIndex = command.lastIndexOf(',');
String red = command.substring(0, commaIndex);
String grn = command.substring(commaIndex+1, secondCommaIndex);
String blu = command.substring(lastCommaIndex+1);
startColor = MotiColor(red.toInt(), grn.toInt(), blu.toInt());
int16_t redDiff = endColor.getR() - startColor.getR();
int16_t greenDiff = endColor.getG() - startColor.getG();
int16_t blueDiff = endColor.getB() - startColor.getB();
int16_t _delay = 500;
int16_t duration = 3500;
int16_t steps = duration / _delay;
int16_t redValue, greenValue, blueValue;
for (int16_t i = steps; i >= 0; i--) {
redValue = (int16_t)startColor.getR() + (redDiff * i / steps);
greenValue = (int16_t)startColor.getG() + (greenDiff * i / steps);
blueValue = (int16_t)startColor.getB() + (blueDiff * i / steps);
sprintf(rgbString, "%i,%i,%i", redValue, greenValue, blueValue);
Spark.publish("rgb", rgbString);
for (uint16_t i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(redValue, greenValue, blueValue));
}
delay(_delay);
}
delay(_delay);
for (uint16_t i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(endColor.getR(), endColor.getG(), endColor.getB()));
}
delay(_delay);
endColor = MotiColor(startColor.getR(), startColor.getG(), startColor.getB());
return 1;
}
I am seeing the published results correctly:
This is from OFF (0,0,0) -> RED (255,0,0) -> GREEN (0,255,0).
It works fine when I publish the results back to a web console via the Spark.publish() event, however the actual Neopixel LED's don't fade from colour to colour as expected. They just change from colour to colour instead of fading nicely between themselves.
I'm just wondering where I'm going wrong or how I can improve my code so that I actually see the fading in real time.
You have to call strip.show() in your for loop, like so:
for (int16_t i = steps; i >= 0; i--) {
redValue = (int16_t)startColor.getR() + (redDiff * i / steps);
greenValue = (int16_t)startColor.getG() + (greenDiff * i / steps);
blueValue = (int16_t)startColor.getB() + (blueDiff * i / steps);
sprintf(rgbString, "%i,%i,%i", redValue, greenValue, blueValue);
Spark.publish("rgb", rgbString);
for (uint16_t i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(redValue, greenValue, blueValue));
}
// !!! Without this, you'll only see the result the next time you call
// tinkerSetColor() !!!
strip.show();
delay(_delay);
}
To understand what's happening, you can look at the NeoPixel library source. You'll see that strip.setPixelColor() only stores the RGB value in memory (think of it as a drawing buffer, so that you can update the whole strip at once, which makes sense if you look at how the controller chips work). Calling strip.show() causes the routine that will push the values out to each pixel in serial to run.