Hardware components | ||||||
| × | 1 | ||||
Software apps and online services | ||||||
![]() |
| |||||
Hand tools and fabrication machines | ||||||
![]() |
| |||||
![]() |
|
What Do I Build Next? An Arduino Nano based Robot Minicar by Elegoo.
This kit is not available for purchase as of 6/3/19.
Back in early January of 2019, I received an email asking me "if" i'd like to receive, assemble, test, comment, suggest and review a new product that was still under development "Why Yes, I naturally said". Within two weeks my surprise package arrived.
Although the inner packaging clearly stated "FRAGILE", the outer plastic bag did not. The plastic box with my "surprise" kit had been crushed. Under further inspection, there was damage to the electronics module, interface board.
I naturally kept the inspection and assembly process going, but first performed a "dry test" of the electronics to ensure operability before assembly. I didn't feel the "broken buzzer" was a show stopper. Besides, I knew I could "MacGuyver" another one in its place.
Four sheets of laser-cut body panels, battery, extension servo interface module and cable, assorted screws, small roll of PVC tape?, two right-angled DC Motors, and Arduino Nano Mainboard.
Be advised, if you live in a HIGH Humidity environment allow all wood pieces to acclimate.. wood expands with moisture. These pieces are press fit together and slid and lock in place with tension. Do not exert excessive force during assembly or locking tabs may split. Possibly, the use of "very fine grit sandpaper ie 400-600 grit" (not included) to reduce dimension of "T-shaped" pieces might be required. Though, this was only a suggestion I made.
But NO printed instructions or software CD or weblinks. More on that later. I also gathered some additional assembly hardware.
Do I power on? YES. Am I seen by my Windows 7 Pro Laptop? YES. Does the Arduino IDE recognize the Elegoo Nano? YES.
A very special "Download link" was sent to me with an initial assembly video "pre-release" as well as web link to Windows 7 USB driver and Arduino code. Yes, code so I can see what's going on later.
First steps were successful. My Mainboard powered ON and did not have any apparent damage except buzzer... or so I thought.
Carefully separate laser-cut body panels and group accordingly.
Step two:
Gather bottom wood panel, Mainboard, front ball-bearing (Universal Wheel) assembly and two screws and nuts (2 x M3*12 Phillips Screws and Nuts), two copper standoffs ( 2 x M2*25 ) and two small screws ( 2 x M2*6 Phillips Screws ), all hardware are in clearly labelled bags and naturally the included Phillips Screwdriver.
Align the Mainboard on "top-side" of bottom plate with two holes and insert one M3*12 Phillips screw to hold in place. Flip plate over to attached universal wheel to threaded M3*12 screw and secure with M3 nut. Do not over-tighten. Insert second M3*12 screw through second hole on mainboard and again feed through universal wheel and attach M3 nut.
Feed M2*6 Phillips screw through next two holes and attach M2*25 copper standoffs, finger tighten as well. These are the Battery supports.
Step Three:
Gather Left and Right wooden body plates, two DC Motor fixing plates, two Right-angled DC Motors, four "T-shaped" pieces, four (M2*22 Phillips Screws and M2 nuts), and naturally the included Phillips Screwdriver.
Step Four:
Attach Left and Right body panels to bottom plate using "T-shaped" pieces and front and rear wooden body panels.
Step Five:
Attach wheels to DC Motor shafts and secure using two (M2*16 Phillips screws). Do not over-tightened screws in Tires as the tire hubs may rub against body panel. "a suggestion to Elegoo, make side panel hub opennings slightly larger to prevent rubbing".
Step Six:
Attach DC Motor power connections to labelled connection ports on mainboard.
Step Seven:
Attach battery to copper standoffs, using two ( M2*6 Phillips Screws).
Step Eight:
Attach one end of auxiliary electronics interconnect cable (9P cable) to mainboard.
Step Nine:
Attach extension/expansion electronics module to roof panel using two screws and nuts (2 x M3*10 Phillips screws and nuts)
Step Ten:
Attach front and rear body bumpers, hood, windshield, and rear window.
Step Eleven:
Attach other end of auxiliary electronics interconnect cable (9P cable) to extension/expansion electronics module. Secure roof to body
Step Twelve:
Attach "spare" wooden tires to rear body
Step Thirteen:
Important!!! Charge battery overnight. RED indicator LED means "charging" GREEN indicator LED means "charge complete".
Note:
There is a MODE button. This is a momentary "manual" selection switch. It can be used to select : Obstacle avoidance, line following, mobile control, auto-follow, and explorer modes. This manual selection is of optional use, in case Android or IOS phone, tablet or PC are unavailable. With each push, a different colored LED schema will be illuminated.
A little factoid here: in January I received my 1st Minicar that had suffered damage during the shipping process. My Minicar was functional but I needed to "MacGyver" repairs (ie: I added a different buzzer, I needed to rebuild the "mode" button that had become non-functional and actually fell apart.
I never did receive replacement parts from Elegoo, but I did manage to outsource comparable parts via Amazon.
Elegoo decided to send me a more "Production" worthy unit, it was packaged in a cardboard box and had stickers/decals and a "pictogram" assembly drawing that I really feel did not depict the assembly of this kit. Since I was familiar with it and had viewed and paused the assembly video, I was able to assemble the kit 1st without the decals and then with minor dissassembly with the decals.
You need to decided before hand whether you like the decals or not.
The kit still functions the same. My "story" here was taken originally "less stickers".
Below are pictures of Production build kit and differences.
Step Fourteen:
Install Android App. Enable Bluetooth on Phone. Turn power ON via switch on Minicar. Open Bluetooth on phone to verify that Minicar's Bluetooth signal is seen (pairing to phone is not capable). Open APP, select "MINICAR" from available icons. (This APP can control multiple other Elegoo project vehicles). Select pairing (upper left corner of screen to see BT16), when "paired in APP" upper right BLUETOOTH icon will illuminate.
Now have fun.
Be advised, there is "No Android Bluetooth device pairing", connection is accomplished via the Android/IOS application proprietary interface. Although my Windows 10 Pro laptop and Samsung S9 phone both could "see" the Elegoo Bluetooth module "BT16" there were not able to "pair" with it.
The Bluetooth App does have an option to create a custom control interface where you can select different functions and assigned them to another button and/or layout. Although, for this review, I did not utilize that feature but I did prove the concept by testing it.
I mentioned during the build, that there was an optional expansion port. The ports are labeled from left to right: AREF, 13, 9, 8, A4, A5, 3V3, GND and are in 3 rows which are labelled from top to bottom: GND, VCC, ~. This appears to be standard servo port configuration. Elegoo did revise this optional sensor board, initially the 9 pin interconnect cable was routed "UP" through roof and connected via the Top port, but in the "Production" release this 9 pin cable connected via a bottom port. Although, for this review I did not add additional hardware like a servo or Ultrasonic Sensor. Maybe later...
#include <avr/pgmspace.h>
#include <Arduino.h>
#include "Pins.h"
#include "Ticker.h"
#include "PinChangeInt.h"
#include "Rgb.h"
#include <stdio.h>
#include "Music.h"
typedef unsigned long millis_t;
Ticker line_tracking;
Ticker key_mode;
Ticker ir_recevie;
Ticker voltage_measure;
int key_value = 0;
bool is_left_line_tracking = false;
bool is_right_line_tracking = false;
bool is_ir_recevie = false;
#define MAX_CMD_SIZE 96
#define BUFSIZE 4
uint8_t commands_in_queue = 0;
uint8_t cmd_queue_index_r = 0;
uint8_t cmd_queue_index_w = 0;
char command_queue[BUFSIZE][MAX_CMD_SIZE];
static int serial_count;
#define parameter_num_max 6 //
String parameter[parameter_num_max]; //
float get_time = 0;
static millis_t get_time_delay;
class L293
{
public:
int left_1_pin;
int left_2_pin;
int right_1_pin;
int right_2_pin;
int enable_left_pin;
int enable_right_pin;
int car_speed = 160;
uint16_t left_speed = 150;
uint16_t right_speed = 150;
void init(int left1pin, int left2pin, int right1pin, int right2pin, int enableleftpin, int enablerightpin)
{
left_1_pin = left1pin;
left_2_pin = left2pin;
right_1_pin = right1pin;
right_2_pin = right2pin;
enable_left_pin = enableleftpin;
enable_right_pin = enablerightpin;
pinMode(left_1_pin, OUTPUT);
pinMode(left_2_pin, OUTPUT);
pinMode(right_1_pin, OUTPUT);
pinMode(right_2_pin, OUTPUT);
pinMode(enable_left_pin, OUTPUT);
pinMode(enable_right_pin, OUTPUT);
stop();
}
void leftFront(int leftspeed)
{
analogWrite(enable_left_pin, leftspeed);
digitalWrite(left_1_pin, HIGH);
digitalWrite(left_2_pin, LOW);
}
void leftBack(int leftspeed)
{
analogWrite(enable_left_pin, leftspeed);
digitalWrite(left_1_pin, LOW);
digitalWrite(left_2_pin, HIGH);
}
void leftStop()
{
analogWrite(enable_left_pin, 0);
digitalWrite(left_1_pin, LOW);
digitalWrite(left_2_pin, LOW);
}
void rightFront(int rightspeed)
{
analogWrite(enable_right_pin, rightspeed);
digitalWrite(right_1_pin, LOW);
digitalWrite(right_2_pin, HIGH);
}
void rightBack(int rightspeed)
{
analogWrite(enable_right_pin, rightspeed);
digitalWrite(right_1_pin, HIGH);
digitalWrite(right_2_pin, LOW);
}
void rightStop()
{
analogWrite(enable_right_pin, 0);
digitalWrite(right_1_pin, LOW);
digitalWrite(right_2_pin, LOW);
}
void forward(int speed)
{
left_speed = speed;
right_speed = speed;
leftFront(speed);
rightFront(speed);
}
void back(int speed)
{
left_speed = speed;
right_speed = speed;
leftBack(speed);
rightBack(speed);
}
void left(int speed)
{
left_speed = speed;
right_speed = speed;
leftBack(speed);
rightFront(speed);
}
void right(int speed)
{
left_speed = speed;
right_speed = speed;
leftFront(speed);
rightBack(speed);
}
void stop()
{
left_speed = 0;
right_speed = 0;
car_speed = 0;
leftStop();
rightStop();
}
private:
} l293;
enum FUNCTION_MODE
{
IDLE,
LINE_TRACKING,
OBSTACLE_AVOIDANCE,
FOLLOW,
BLUETOOTH,
EXPLORE,
} function_mode = IDLE;
//
enum SERIAL_COMMAND
{
CMD_NULL, //
CMD_OA, //
CMD_LT, //
CMD_TURN, //
CMD_MOVE, //
CMD_MOVES, //
CMD_RGB, //RGB
CMD_RGBS, //RGB
CMD_RGBB, //RGB
CMD_BEEP, //
CMD_BEEPS, //
CMD_KEY, //
} serial_command = CMD_NULL;
void voltageInit()
{
pinMode(VOL_MEASURE_PIN, INPUT);
voltage_measure.start(voltageMeasure, 1000);
}
void voltageMeasure()
{
double voltage = analogRead(VOL_MEASURE_PIN) * 4.96 / 1024;
if (voltage < 3.6)
{
rgb.flashRedColorFlag();
}
else
{
rgb.flashGreedYellowColorFlag();
}
}
void followMode()
{
l293.car_speed = 170;
if (is_ir_recevie)
{
l293.forward(l293.car_speed);
}
else
{
l293.stop();
}
}
void obstacleAvoidanceMode()
{
l293.car_speed = 180;
static millis_t delay_time = millis();
static bool flag = false;
if (flag)
{
if (millis() - delay_time > 150)
{
flag = false;
}
}
else
{
if (is_ir_recevie)
{
random() % 2 ? l293.right(l293.car_speed) : l293.left(l293.car_speed);
flag = true;
delay_time = millis();
}
else
{
l293.forward(l293.car_speed);
}
}
}
void exploreMode()
{
l293.car_speed = 160;
static millis_t delay_time = millis();
static bool flag = false;
static bool stopFlag = false;
if (is_left_line_tracking || is_right_line_tracking)
{
if (stopFlag)
{
stopFlag = false;
l293.back(255);
delay(50);
}
l293.stop();
}
else
{
stopFlag = true;
if (flag)
{
if (millis() - delay_time > 150)
{
flag = false;
}
}
else
{
if (is_ir_recevie)
{
random() % 2 ? l293.right(l293.car_speed) : l293.left(l293.car_speed);
flag = true;
delay_time = millis();
}
else
{
l293.forward(l293.car_speed);
}
}
}
}
void getKeyValue()
{
static bool key_flag = false;
if (!digitalRead(KEY_MODE))
{
key_flag = true;
}
if (key_flag && digitalRead(KEY_MODE))
{
key_flag = false;
key_value++;
if (key_value >= 5)
{
key_value = 0;
}
switch (key_value)
{
case 0:
function_mode = IDLE;
l293.stop();
rgb.lightOff();
break;
case 1:
function_mode = LINE_TRACKING;
rgb.brightGreenColor();
break;
case 2:
function_mode = OBSTACLE_AVOIDANCE;
rgb.brightYellowColor();
break;
case 3:
function_mode = FOLLOW;
rgb.brightBlueColor();
break;
case 4:
function_mode = EXPLORE;
rgb.brightWhiteColor();
break;
default:
break;
}
}
}
void keyInit()
{
pinMode(KEY_MODE, INPUT_PULLUP);
key_mode.start(getKeyValue, 40);
}
void irInit()
{
pinMode(IR_RECEIVE_PIN, INPUT);
ir_recevie.start(getIrData, 20);
}
void getIrData()
{
static int ir_recevie_data;
int ir_recevie_threshold = 1000;
ir_recevie_data = analogRead(IR_RECEIVE_PIN);
// Serial.print(ir_recevie_data);
// Serial.print("\n");
is_ir_recevie = ir_recevie_data < ir_recevie_threshold ? true : false;
}
void getLineTrackingData()
{
static int line_tracking_left_data;
static int line_tracking_right_data;
int line_tracking_threshold = 800;
line_tracking_left_data = analogRead(LINE_TRACKING_LEFT_PIN);
line_tracking_right_data = analogRead(LINE_TRACKING_RIGHT_PIN);
// Serial.print(line_tracking_left_data);
// Serial.print("\t");
// Serial.print(line_tracking_right_data);
// Serial.print("\n");
is_left_line_tracking = line_tracking_left_data >= line_tracking_threshold ? true : false;
is_right_line_tracking = line_tracking_right_data >= line_tracking_threshold ? true : false;
}
void lineTrackingInit()
{
pinMode(LINE_TRACKING_LEFT_PIN, INPUT);
pinMode(LINE_TRACKING_RIGHT_PIN, INPUT);
line_tracking.start(getLineTrackingData, 20);
}
void lineTrackingMode()
{
l293.car_speed = 190;
if (is_left_line_tracking && is_right_line_tracking)
{
l293.stop();
}
else if (is_left_line_tracking)
{
l293.left(l293.car_speed);
}
else if (is_right_line_tracking)
{
l293.right(l293.car_speed);
}
else
{
l293.forward(l293.car_speed);
}
}
inline bool enqueuecommand(const char *cmd)
{
if (commands_in_queue >= BUFSIZE)
return false;
strcpy(command_queue[cmd_queue_index_w], cmd);
if (++cmd_queue_index_w >= BUFSIZE)
{
cmd_queue_index_w = 0;
}
commands_in_queue++;
return true;
}
inline void get_command()
{
static millis_t printTime;
printTime = millis();
static char serial_line_buffer[MAX_CMD_SIZE];
static bool command_start = false;
int c;
while (commands_in_queue < BUFSIZE && (c = Serial.read()) >= 0)
{
char serial_char = c;
if (serial_char == '{')
{
if (command_start)
{
serial_line_buffer[serial_count] = 0;
serial_count = 0;
}
else
{
command_start = true;
}
}
else if (command_start)
{
if (serial_char == '}')
{
if (!serial_count)
{
continue;
}
serial_line_buffer[serial_count] = 0;
serial_count = 0;
if (command_start)
{
command_start = false;
enqueuecommand(serial_line_buffer);
// Serial.print(millis() - printTime);
}
}
else if (serial_count >= MAX_CMD_SIZE - 1)
{
}
else if (serial_char == '\\')
{
if ((c = Serial.read()) >= 0)
serial_line_buffer[serial_count++] = (char)c;
}
else
{
serial_line_buffer[serial_count++] = serial_char;
}
}
}
}
void process_parsed_command()
{
int index_start[parameter_num_max]; //
int index_end[parameter_num_max]; //
int parameter_num = 0; //
int car_speed;
String current_command(command_queue[cmd_queue_index_r]); //String
int i = 0;
// Serial.println(current_command);
// return;
//
index_start[i] = current_command.indexOf('[');
if (index_start[i] <= 0)
{
return;
}
index_end[i] = current_command.indexOf(']');
if (index_end[i] <= 0 || index_start[i] >= index_end[i])
{
return;
}
parameter_num++;
String command_head = current_command.substring(0, index_start[i]); //
parameter[i] = current_command.substring(index_start[i] + 1, index_end[i]);
//
for (++i; i < parameter_num_max; i++)
{
index_start[i] = current_command.indexOf('[', index_end[i - 1] + 1);
if (index_start[i] <= 0)
{
break;
}
index_end[i] = current_command.indexOf(']', index_end[i - 1] + 1);
if (index_end[i] <= 0 || index_start[i] >= index_end[i])
{
index_start[i] = 0;
index_end[i] = 0;
break;
}
parameter_num++;
parameter[i] = current_command.substring(index_start[i] + 1, index_end[i]);
}
if (command_head == "OA" && parameter_num == 1)
{
if (parameter[0] == "?")
{
is_ir_recevie ? Serial.print("{true}") : Serial.print("{false}");
}
else
{
return;
}
}
else if (command_head == "LT" && parameter_num == 2)
{
if (parameter[1] == "?")
{
if (parameter[0] == "0")
{
is_left_line_tracking ? Serial.print("{true}") : Serial.print("{false}");
}
else if (parameter[0] == "1")
{
is_right_line_tracking ? Serial.print("{true}") : Serial.print("{false}");
}
else
{
return;
}
}
else
{
return;
}
}
else if (command_head == "TURN" && parameter_num == 2)
{
if (parameter[1] == "0")
{
car_speed = 0;
}
if (parameter[1] == "300")
{
car_speed = 300;
}
else
{
if (parameter[1].toInt() != 0)
{
car_speed = parameter[1].toInt();
}
else
{
return;
}
}
if (car_speed != 300)
{
l293.car_speed = car_speed;
}
else
{
if (parameter[0] != "0" && l293.car_speed == 0)
{
l293.car_speed = 255;
}
}
if (parameter[0] == "0")
{
l293.stop();
}
else if (parameter[0] == "1")
{
l293.forward(l293.car_speed);
}
else if (parameter[0] == "2")
{
l293.back(l293.car_speed);
}
else if (parameter[0] == "3")
{
l293.left(l293.car_speed);
}
else if (parameter[0] == "4")
{
l293.right(l293.car_speed);
}
else
{
return;
}
Serial.print("{ok}");
}
else if (command_head == "TURNS" && parameter_num == 3)
{
if (parameter[1] == "0")
{
car_speed = 0;
}
if (parameter[1] == "300")
{
car_speed = 300;
}
else
{
if (parameter[1].toInt() != 0)
{
car_speed = parameter[1].toInt();
}
else
{
return;
}
}
if (car_speed != 300)
{
l293.car_speed = car_speed;
}
else
{
if (parameter[0] != "0" && l293.car_speed == 0)
{
l293.car_speed = 255;
}
}
if (parameter[0] == "0")
{
l293.stop();
}
else if (parameter[0] == "1")
{
l293.forward(l293.car_speed);
}
else if (parameter[0] == "2")
{
l293.back(l293.car_speed);
}
else if (parameter[0] == "3")
{
l293.left(l293.car_speed);
}
else if (parameter[0] == "4")
{
l293.right(l293.car_speed);
}
else
{
return;
}
char *ptr;
if (parameter[2] == "0")
{
rgb.lightOff();
}
else if (parameter[2] == "1")
{
rgb.led_rgb_new[0] = 0xA020F0; //
rgb.led_rgb_old[0] = 0xA020F0;
rgb.led_rgb_new[1] = 0xA020F0;
rgb.led_rgb_old[1] = 0xA020F0;
}
else if (parameter[2] == "2")
{
rgb.led_rgb_new[0] = 0xA020F0; //
rgb.led_rgb_old[0] = 0xA020F0;
rgb.led_rgb_new[1] = 0xA020F0;
rgb.led_rgb_old[1] = 0xA020F0;
}
// rgb.led_rgb_new[0] = strtol(¶meter[2][0], &ptr, 16);
// rgb.led_rgb_new[1] = strtol(¶meter[2][0], &ptr, 16);
// rgb.led_rgb_old[0] = strtol(¶meter[2][0], &ptr, 16);
// rgb.led_rgb_old[1] = strtol(¶meter[2][0], &ptr, 16);
// rgb.brightBlueColor();
// Serial.println(strtol(¶meter[2][0], &ptr, 16), HEX);
// Serial.println(commands_in_queue);
}
else if (command_head == "MOVE" && parameter_num == 3)
{
if (parameter[2] == "0")
{
car_speed = 0;
}
if (parameter[2] == "300")
{
car_speed = 300;
}
else
{
if (parameter[2].toInt() != 0)
{
car_speed = parameter[2].toInt();
}
else
{
return;
}
}
if (parameter[0] == "0")
{
if (car_speed != 300)
{
l293.car_speed = car_speed;
}
else
{
if ((parameter[1] == "1" || parameter[2] == "2") && l293.car_speed == 0)
{
l293.car_speed = 255;
}
}
if (parameter[1] == "0")
{
l293.stop();
}
else if (parameter[1] == "1")
{
l293.forward(l293.car_speed);
}
else if (parameter[1] == "2")
{
l293.back(l293.car_speed);
}
else if (parameter[1] == "3")
{
}
else
{
return;
}
}
else if (parameter[0] == "1")
{
if (car_speed != 300)
{
l293.left_speed = car_speed;
}
else
{
if ((parameter[1] == "1" || parameter[2] == "2") && l293.left_speed == 0)
{
l293.left_speed = 255;
}
}
if (parameter[1] == "0")
{
l293.stop();
}
else if (parameter[1] == "1")
{
l293.leftFront(l293.left_speed);
}
else if (parameter[1] == "2")
{
l293.leftBack(l293.left_speed);
}
else if (parameter[1] == "3")
{
}
else
{
return;
}
}
else if (parameter[0] == "2")
{
if (car_speed != 300)
{
l293.right_speed = car_speed;
}
else
{
if ((parameter[1] == "1" || parameter[1] == "2") && l293.right_speed == 0)
{
l293.right_speed = 255;
}
}
if (parameter[1] == "0")
{
l293.stop();
}
else if (parameter[1] == "1")
{
l293.rightFront(l293.right_speed);
}
else if (parameter[1] == "2")
{
l293.rightBack(l293.right_speed);
}
else if (parameter[1] == "3")
{
}
else
{
return;
}
}
else
{
return;
}
Serial.print("{ok}");
}
else if (command_head == "MOVES" && parameter_num == 4)
{
if (parameter[1] == "0")
{
car_speed = 0;
}
if (parameter[1] == "300")
{
car_speed = 300;
}
else
{
if (parameter[1].toInt() != 0)
{
car_speed = parameter[1].toInt();
}
else
{
return;
}
}
if (car_speed != 300)
{
l293.left_speed = car_speed;
}
else
{
if ((parameter[0] == "1" || parameter[0] == "2") && l293.left_speed == 0)
{
l293.left_speed = 255;
}
}
if (parameter[0] == "0")
{
l293.left_speed = 0;
l293.leftStop();
}
else if (parameter[0] == "1")
{
l293.leftFront(l293.left_speed);
}
else if (parameter[0] == "2")
{
l293.leftBack(l293.left_speed);
}
else if (parameter[0] == "3")
{
}
else
{
return;
}
if (parameter[3] == "0")
{
car_speed = 0;
}
if (parameter[3] == "300")
{
car_speed = 300;
}
else
{
if (parameter[3].toInt() != 0)
{
car_speed = parameter[3].toInt();
}
else
{
return;
}
}
if (car_speed != 300)
{
l293.right_speed = car_speed;
}
else
{
if ((parameter[2] == "1" || parameter[2] == "2") && l293.right_speed == 0)
{
l293.right_speed = 255;
}
}
if (parameter[2] == "0")
{
l293.right_speed = 0;
l293.rightStop();
}
else if (parameter[2] == "1")
{
l293.rightFront(l293.right_speed);
}
else if (parameter[2] == "2")
{
l293.rightBack(l293.right_speed);
}
else if (parameter[2] == "3")
{
}
else
{
return;
}
Serial.print("{ok}");
}
else if (command_head == "RGB" && parameter_num == 6)
{
if (parameter[3] == "0")
{
rgb.led_rgb_new[0] = rgb.Color(parameter[0].toInt(), parameter[1].toInt(), parameter[2].toInt());
rgb.led_rgb_new[1] = rgb.Color(parameter[0].toInt(), parameter[1].toInt(), parameter[2].toInt());
if (parameter[5] == "0")
{
rgb.led_rgb_old[0] = rgb.Color(parameter[0].toInt(), parameter[1].toInt(), parameter[2].toInt());
rgb.led_rgb_old[1] = rgb.Color(parameter[0].toInt(), parameter[1].toInt(), parameter[2].toInt());
}
else
{
rgb.led_rgb_old[0] = rgb.Color(0, 0, 0);
rgb.led_rgb_old[1] = rgb.Color(0, 0, 0);
}
}
else if (parameter[3] == "1")
{
rgb.led_rgb_new[1] = rgb.Color(parameter[0].toInt(), parameter[1].toInt(), parameter[2].toInt());
if (parameter[5] == "0")
{
rgb.led_rgb_old[1] = rgb.Color(parameter[0].toInt(), parameter[1].toInt(), parameter[2].toInt());
}
else
{
rgb.led_rgb_old[1] = rgb.Color(0, 0, 0);
}
}
else if (parameter[3] == "2")
{
rgb.led_rgb_new[0] = rgb.Color(parameter[0].toInt(), parameter[1].toInt(), parameter[2].toInt());
if (parameter[5] == "0")
{
rgb.led_rgb_old[0] = rgb.Color(parameter[0].toInt(), parameter[1].toInt(), parameter[2].toInt());
}
else
{
rgb.led_rgb_old[0] = rgb.Color(0, 0, 0);
}
}
else
{
return;
}
if (parameter[4] == "0")
{
get_time = 0;
}
else if (parameter[4].toInt() != 0)
{
get_time = parameter[4].toInt();
}
else if (parameter[4].toFloat() != 0)
{
get_time = parameter[4].toFloat();
}
else
{
return;
}
if (get_time == 0)
{
Serial.print("{ok}");
}
else
{
serial_command = CMD_RGB;
get_time_delay = millis();
}
}
else if (command_head == "RGBS" && parameter_num == 4)
{
char *ptr;
rgb.led_rgb_new[1] = strtol(¶meter[0][0], &ptr, 16);
if (parameter[1] == "0")
{
rgb.led_rgb_old[1] = strtol(¶meter[0][0], &ptr, 16);
...
This file has been truncated, please download it to see its full contents.
Elegoo Project files and documents
ArduinoNo preview (download only).
/*-------------------------------------------------------------------------
* Arduino library to control a wide variety of WS2811- and WS2812-based RGB
* LED devices such as Adafruit FLORA RGB Smart Pixels and NeoPixel strips.
* Currently handles 400 and 800 KHz bitstreams on 8, 12 and 16 MHz ATmega
* MCUs, with LEDs wired for various color orders. 8 MHz MCUs provide
* output on PORTB and PORTD, while 16 MHz chips can handle most output pins
* (possible exception with upper PORT registers on the Arduino Mega).
*
* Written by Phil Burgess / Paint Your Dragon for Adafruit Industries,
* contributions by PJRC, Michael Miller and other members of the open
* source community.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing products
* from Adafruit!
*
* -------------------------------------------------------------------------
* This file is part of the Adafruit NeoPixel library.
*
* NeoPixel is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* NeoPixel is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with NeoPixel. If not, see
* <http://www.gnu.org/licenses/>.
* -------------------------------------------------------------------------*/
#include "Adafruit_NeoPixel.h"
// Constructor when length, pin and type are known at compile-time:
Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, uint8_t p, neoPixelType t) :
begun(false), brightness(0), pixels(NULL), endTime(0)
{
updateType(t);
updateLength(n);
setPin(p);
}
// via Michael Vogt/neophob: empty constructor is used when strand length
// isn't known at compile-time; situations where program config might be
// read from internal flash memory or an SD card, or arrive via serial
// command. If using this constructor, MUST follow up with updateType(),
// updateLength(), etc. to establish the strand type, length and pin number!
Adafruit_NeoPixel::Adafruit_NeoPixel() :
#ifdef NEO_KHZ400
is800KHz(true),
#endif
begun(false), numLEDs(0), numBytes(0), pin(-1), brightness(0), pixels(NULL),
rOffset(1), gOffset(0), bOffset(2), wOffset(1), endTime(0)
{
}
Adafruit_NeoPixel::~Adafruit_NeoPixel()
{
if (pixels) {
free(pixels);
}
if (pin >= 0) {
pinMode(pin, INPUT);
}
}
void Adafruit_NeoPixel::begin(void)
{
if (pin >= 0) {
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
}
begun = true;
}
void Adafruit_NeoPixel::updateLength(uint16_t n)
{
if (pixels) {
free(pixels); // Free existing data (if any)
}
// Allocate new data -- note: ALL PIXELS ARE CLEARED
numBytes = n * ((wOffset == rOffset) ? 3 : 4);
if ((pixels = (uint8_t *)malloc(numBytes))) {
memset(pixels, 0, numBytes);
numLEDs = n;
} else {
numLEDs = numBytes = 0;
}
}
void Adafruit_NeoPixel::updateType(neoPixelType t)
{
boolean oldThreeBytesPerPixel = (wOffset == rOffset); // false if RGBW
wOffset = (t >> 6) & 0b11; // See notes in header file
rOffset = (t >> 4) & 0b11; // regarding R/G/B/W offsets
gOffset = (t >> 2) & 0b11;
bOffset = t & 0b11;
#ifdef NEO_KHZ400
is800KHz = (t < 256); // 400 KHz flag is 1<<8
#endif
// If bytes-per-pixel has changed (and pixel data was previously
// allocated), re-allocate to new size. Will clear any data.
if (pixels) {
boolean newThreeBytesPerPixel = (wOffset == rOffset);
if (newThreeBytesPerPixel != oldThreeBytesPerPixel) {
updateLength(numLEDs);
}
}
}
#ifdef ESP8266
// ESP8266 show() is external to enforce ICACHE_RAM_ATTR execution
extern "C" void ICACHE_RAM_ATTR espShow(
uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t type);
#endif // ESP8266
void Adafruit_NeoPixel::show(void)
{
if (!pixels) {
return;
}
// Data latch = 50+ microsecond pause in the output stream. Rather than
// put a delay at the end of the function, the ending time is noted and
// the function will simply hold off (if needed) on issuing the
// subsequent round of data until the latch time has elapsed. This
// allows the mainline code to start generating the next frame of data
// rather than stalling for the latch.
while (!canShow())
{
}
// endTime is a private member (rather than global var) so that mutliple
// instances on different pins can be quickly issued in succession (each
// instance doesn't delay the next).
// In order to make this code runtime-configurable to work with any pin,
// SBI/CBI instructions are eschewed in favor of full PORT writes via the
// OUT or ST instructions. It relies on two facts: that peripheral
// functions (such as PWM) take precedence on output pins, so our PORT-
// wide writes won't interfere, and that interrupts are globally disabled
// while data is being issued to the LEDs, so no other code will be
// accessing the PORT. The code takes an initial 'snapshot' of the PORT
// state, computes 'pin high' and 'pin low' values, and writes these back
// to the PORT register as needed.
noInterrupts(); // Need 100% focus on instruction timing
#ifdef __AVR__
// AVR MCUs -- ATmega & ATtiny (no XMEGA) ---------------------------------
volatile uint16_t
i = numBytes; // Loop counter
volatile uint8_t
*ptr = pixels, // Pointer to next byte
b = *ptr++, // Current byte value
hi, // PORT w/output bit set high
lo; // PORT w/output bit set low
// Hand-tuned assembly code issues data to the LED drivers at a specific
// rate. There's separate code for different CPU speeds (8, 12, 16 MHz)
// for both the WS2811 (400 KHz) and WS2812 (800 KHz) drivers. The
// datastream timing for the LED drivers allows a little wiggle room each
// way (listed in the datasheets), so the conditions for compiling each
// case are set up for a range of frequencies rather than just the exact
// 8, 12 or 16 MHz values, permitting use with some close-but-not-spot-on
// devices (e.g. 16.5 MHz DigiSpark). The ranges were arrived at based
// on the datasheet figures and have not been extensively tested outside
// the canonical 8/12/16 MHz speeds; there's no guarantee these will work
// close to the extremes (or possibly they could be pushed further).
// Keep in mind only one CPU speed case actually gets compiled; the
// resulting program isn't as massive as it might look from source here.
// 8 MHz(ish) AVR ---------------------------------------------------------
#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL)
#ifdef NEO_KHZ400 // 800 KHz check needed only if 400 KHz support enabled
if (is800KHz) {
#endif
volatile uint8_t n1, n2 = 0; // First, next bits out
// Squeezing an 800 KHz stream out of an 8 MHz chip requires code
// specific to each PORT register. At present this is only written
// to work with pins on PORTD or PORTB, the most likely use case --
// this covers all the pins on the Adafruit Flora and the bulk of
// digital pins on the Arduino Pro 8 MHz (keep in mind, this code
// doesn't even get compiled for 16 MHz boards like the Uno, Mega,
// Leonardo, etc., so don't bother extending this out of hand).
// Additional PORTs could be added if you really need them, just
// duplicate the else and loop and change the PORT. Each add'l
// PORT will require about 150(ish) bytes of program space.
// 10 instruction clocks per bit: HHxxxxxLLL
// OUT instructions: ^ ^ ^ (T=0,2,7)
#ifdef PORTD // PORTD isn't present on ATtiny85, etc.
if (port == &PORTD) {
hi = PORTD | pinMask;
lo = PORTD & ~pinMask;
n1 = lo;
if (b & 0x80) {
n1 = hi;
}
// Dirty trick: RJMPs proceeding to the next instruction are used
// to delay two clock cycles in one instruction word (rather than
// using two NOPs). This was necessary in order to squeeze the
// loop down to exactly 64 words -- the maximum possible for a
// relative branch.
asm volatile (
"headD:" "\n\t" // Clk Pseudocode
// Bit 7:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
"out %[port] , %[n1]" "\n\t" // 1 PORT = n1
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 6" "\n\t" // 1-2 if(b & 0x40)
"mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 6:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
"out %[port] , %[n2]" "\n\t" // 1 PORT = n2
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 5" "\n\t" // 1-2 if(b & 0x20)
"mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 5:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
"out %[port] , %[n1]" "\n\t" // 1 PORT = n1
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 4" "\n\t" // 1-2 if(b & 0x10)
"mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 4:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
"out %[port] , %[n2]" "\n\t" // 1 PORT = n2
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 3" "\n\t" // 1-2 if(b & 0x08)
"mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 3:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
"out %[port] , %[n1]" "\n\t" // 1 PORT = n1
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 2" "\n\t" // 1-2 if(b & 0x04)
"mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 2:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
"out %[port] , %[n2]" "\n\t" // 1 PORT = n2
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 1" "\n\t" // 1-2 if(b & 0x02)
"mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 1:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
"out %[port] , %[n1]" "\n\t" // 1 PORT = n1
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 0" "\n\t" // 1-2 if(b & 0x01)
"mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"sbiw %[count], 1" "\n\t" // 2 i-- (don't act on Z flag yet)
// Bit 0:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
"out %[port] , %[n2]" "\n\t" // 1 PORT = n2
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80)
"mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"brne headD" "\n" // 2 while(i) (Z flag set above)
: [byte] "+r" (b),
[n1] "+r" (n1),
[n2] "+r" (n2),
[count] "+w" (i)
: [port] "I" (_SFR_IO_ADDR(PORTD)),
[ptr] "e" (ptr),
[hi] "r" (hi),
[lo] "r" (lo));
} else if (port == &PORTB) {
#endif // PORTD
// Same as above, just switched to PORTB and stripped of comments.
hi = PORTB | pinMask;
lo = PORTB & ~pinMask;
n1 = lo;
if (b & 0x80) {
n1 = hi;
}
asm volatile (
"headB:" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n2] , %[lo]" "\n\t"
"out %[port] , %[n1]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 6" "\n\t"
"mov %[n2] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n1] , %[lo]" "\n\t"
"out %[port] , %[n2]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 5" "\n\t"
"mov %[n1] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n2] , %[lo]" "\n\t"
"out %[port] , %[n1]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 4" "\n\t"
"mov %[n2] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n1] , %[lo]" "\n\t"
"out %[port] , %[n2]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 3" "\n\t"
"mov %[n1] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n2] , %[lo]" "\n\t"
"out %[port] , %[n1]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 2" "\n\t"
"mov %[n2] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n1] , %[lo]" "\n\t"
"out %[port] , %[n2]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 1" "\n\t"
"mov %[n1] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n2] , %[lo]" "\n\t"
"out %[port] , %[n1]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 0" "\n\t"
"mov %[n2] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"sbiw %[count], 1" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n1] , %[lo]" "\n\t"
"out %[port] , %[n2]" "\n\t"
"ld %[byte] , %a[ptr]+" "\n\t"
"sbrc %[byte] , 7" "\n\t"
"mov %[n1] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"brne headB" "\n"
: [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i)
: [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi),
[lo] "r" (lo));
#ifdef PORTD
} // endif PORTB
#endif
#ifdef NEO_KHZ400
} else { // end 800 KHz, do 400 KHz
// Timing is more relaxed; unrolling the inner loop for each bit is
// not necessary. Still using the peculiar RJMPs as 2X NOPs, not out
// of need but just to trim the code size down a little.
// This 400-KHz-datastream-on-8-MHz-CPU code is not quite identical
// to the 800-on-16 code later -- the hi/lo timing between WS2811 and
// WS2812 is not simply a 2:1 scale!
// 20 inst. clocks per bit: HHHHxxxxxxLLLLLLLLLL
// ST instructions: ^ ^ ^ (T=0,4,10)
volatile uint8_t next, bit;
hi = *port | pinMask;
lo = *port & ~pinMask;
next = lo;
bit = 8;
asm volatile (
"head20:" "\n\t" // Clk Pseudocode (T = 0)
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128)
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4)
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 6)
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7)
"dec %[bit]" "\n\t" // 1 bit-- (T = 8)
"breq nextbyte20" "\n\t" // 1-2 if(bit == 0)
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12)
"rjmp .+0" "\n\t" // 2 nop nop (T = 14)
"rjmp .+0" "\n\t" // 2 nop nop (T = 16)
"rjmp .+0" "\n\t" // 2 nop nop (T = 18)
"rjmp head20" "\n\t" // 2 -> head20 (next bit out)
"nextbyte20:" "\n\t" // (T = 10)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12)
"nop" "\n\t" // 1 nop (T = 13)
"ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 14)
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 16)
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 18)
"brne head20" "\n" // 2 if(i != 0) -> (next byte)
: [port] "+e" (port),
[byte] "+r" (b),
[bit] "+r" (bit),
[next] "+r" (next),
[count] "+w" (i)
: [hi] "r" (hi),
[lo] "r" (lo),
[ptr] "e" (ptr));
}
#endif // NEO_KHZ400
// 12 MHz(ish) AVR --------------------------------------------------------
#elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL)
#ifdef NEO_KHZ400 // 800 KHz check needed only if 400 KHz support enabled
if (is800KHz) {
#endif
// In the 12 MHz case, an optimized 800 KHz datastream (no dead time
// between bytes) requires a PORT-specific loop similar to the 8 MHz
// code (but a little more relaxed in this case).
// 15 instruction clocks per bit: HHHHxxxxxxLLLLL
// OUT instructions: ^ ^ ^ (T=0,4,10)
volatile uint8_t next;
#ifdef PORTD
if (port == &PORTD) {
hi = PORTD | pinMask;
lo = PORTD & ~pinMask;
next = lo;
if (b & 0x80) {
next = hi;
}
// Don't "optimize" the OUT calls into the bitTime subroutine;
// we're exploiting the RCALL and RET as 3- and 4-cycle NOPs!
asm volatile (
"headD:" "\n\t" // (T = 0)
"out %[port], %[hi]" "\n\t" // (T = 1)
"rcall bitTimeD" "\n\t" // Bit 7 (T = 15)
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 6
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 5
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 4
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 3
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 2
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 1
// Bit 0:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi (T = 1)
"rjmp .+0" "\n\t" // 2 nop nop (T = 3)
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 5)
"out %[port] , %[next]" "\n\t" // 1 PORT = next (T = 6)
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7)
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) (T = 8)
"mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 9)
"nop" "\n\t" // 1 (T = 10)
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo (T = 11)
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 13)
"brne headD" "\n\t" // 2 if(i != 0) -> (next byte)
"rjmp doneD" "\n\t"
"bitTimeD:" "\n\t" // nop nop nop (T = 4)
"out %[port], %[next]" "\n\t" // 1 PORT = next (T = 5)
"mov %[next], %[lo]" "\n\t" // 1 next = lo (T = 6)
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 7)
"sbrc %[byte], 7" "\n\t" // 1-2 if(b & 0x80) (T = 8)
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 9)
"nop" "\n\t" // 1 (T = 10)
"out %[port], %[lo]" "\n\t" // 1 PORT = lo (T = 11)
"ret" "\n\t" // 4 nop nop nop nop (T = 15)
"doneD:" "\n"
: [byte] "+r" (b),
[next] "+r" (next),
[count] "+w" (i)
: [port] "I" (_SFR_IO_ADDR(PORTD)),
[ptr] "e" (ptr),
[hi] "r" (hi),
[lo] "r" (lo));
} else if (port == &PORTB) {
#endif // PORTD
hi = PORTB | pinMask;
lo = PORTB & ~pinMask;
next = lo;
if (b & 0x80) {
next = hi;
}
// Same as above, just set for PORTB & stripped of comments
asm volatile (
"headB:" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port] , %[hi]" "\n\t"
"rjmp .+0" "\n\t"
"ld %[byte] , %a[ptr]+" "\n\t"
"out %[port] , %[next]" "\n\t"
"mov %[next] , %[lo]" "\n\t"
"sbrc %[byte] , 7" "\n\t"
"mov %[next] , %[hi]" "\n\t"
"nop" "\n\t"
"out %[port] , %[lo]" "\n\t"
"sbiw %[count], 1" "\n\t"
"brne headB" "\n\t"
"rjmp doneB" "\n\t"
"bitTimeB:" "\n\t"
"out %[port], %[next]" "\n\t"
"mov %[next], %[lo]" "\n\t"
"rol %[byte]" "\n\t"
"sbrc %[byte], 7" "\n\t"
"mov %[next], %[hi]" "\n\t"
"nop" "\n\t"
"out %[port], %[lo]" "\n\t"
"ret" "\n\t"
"doneB:" "\n"
: [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i)
: [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi),
[lo] "r" (lo));
#ifdef PORTD
}
#endif
#ifdef NEO_KHZ400
} else { // 400 KHz
// 30 instruction clocks per bit: HHHHHHxxxxxxxxxLLLLLLLLLLLLLLL
// ST instructions: ^ ^ ^ (T=0,6,15)
volatile uint8_t next, bit;
hi = *port | pinMask;
lo = *port & ~pinMask;
next = lo;
bit = 8;
asm volatile (
"head30:" "\n\t" // Clk Pseudocode (T = 0)
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128)
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4)
"rjmp .+0" "\n\t" // 2 nop nop (T = 6)
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 8)
"rjmp .+0" "\n\t" // 2 nop nop (T = 10)
"rjmp .+0" "\n\t" // 2 nop nop (T = 12)
"rjmp .+0" "\n\t" // 2 nop nop (T = 14)
"nop" "\n\t" // 1 nop (T = 15)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 17)
"rjmp .+0" "\n\t" // 2 nop nop (T = 19)
"dec %[bit]" "\n\t" // 1 bit-- (T = 20)
"breq nextbyte30" "\n\t" // 1-2 if(bit == 0)
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 22)
"rjmp .+0" "\n\t" // 2 nop nop (T = 24)
"rjmp .+0" "\n\t" // 2 nop nop (T = 26)
"rjmp .+0" "\n\t" // 2 nop nop (T = 28)
"rjmp head30" "\n\t" // 2 -> head30 (next bit out)
"nextbyte30:" "\n\t" // (T = 22)
"nop" "\n\t" // 1 nop (T = 23)
"ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 24)
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 26)
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 28)
"brne head30" "\n" // 1-2 if(i != 0) -> (next byte)
: [port] "+e" (port),
[byte] "+r" (b),
[bit] "+r" (bit),
[next] "+r" (next),
[count] "+w" (i)
: [hi] "r" (hi),
[lo] "r" (lo),
[ptr] "e" (ptr));
}
#endif // NEO_KHZ400
// 16 MHz(ish) AVR --------------------------------------------------------
#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L)
#ifdef NEO_KHZ400 // 800 KHz check needed only if 400 KHz support enabled
if (is800KHz) {
#endif
// WS2811 and WS2812 have different hi/lo duty cycles; this is
// similar but NOT an exact copy of the prior 400-on-8 code.
// 20 inst. clocks per bit: HHHHHxxxxxxxxLLLLLLL
// ST instructions: ^ ^ ^ (T=0,5,13)
volatile uint8_t next, bit;
hi = *port | pinMask;
lo = *port & ~pinMask;
next = lo;
bit = 8;
asm volatile (
"head20:" "\n\t" // Clk Pseudocode (T = 0)
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
"sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128)
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4)
"dec %[bit]" "\n\t" // 1 bit-- (T = 5)
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7)
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8)
"breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above)
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10)
"rjmp .+0" "\n\t" // 2 nop nop (T = 12)
"nop" "\n\t" // 1 nop (T = 13)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15)
"nop" "\n\t" // 1 nop (T = 16)
"rjmp .+0" "\n\t" // 2 nop nop (T = 18)
"rjmp head20" "\n\t" // 2 -> head20 (next bit out)
"nextbyte20:" "\n\t" // (T = 10)
"ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11)
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15)
"nop" "\n\t" // 1 nop (T = 16)
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 18)
"brne head20" "\n" // 2 if(i != 0) -> (next byte)
: [port] "+e" (port),
[byte] "+r" (b),
[bit] "+r" (bit),
[next] "+r" (next),
[count] "+w" (i)
: [ptr] "e" (ptr),
[hi] "r" (hi),
[lo] "r" (lo));
#ifdef NEO_KHZ400
} else { // 400 KHz
// The 400 KHz clock on 16 MHz MCU is the most 'relaxed' version.
// 40 inst. clocks per bit: HHHHHHHHxxxxxxxxxxxxLLLLLLLLLLLLLLLLLLLL
// ST instructions: ^ ^ ^ (T=0,8,20)
volatile uint8_t next, bit;
hi = *port | pinMask;
lo = *port & ~pinMask;
next = lo;
bit = 8;
asm volatile (
"head40:" "\n\t" // Clk Pseudocode (T = 0)
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128)
"mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 4)
"rjmp .+0" "\n\t" // 2 nop nop (T = 6)
"rjmp .+0" "\n\t" // 2 nop nop (T = 8)
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 10)
"rjmp .+0" "\n\t" // 2 nop nop (T = 12)
"rjmp .+0" "\n\t" // 2 nop nop (T = 14)
"rjmp .+0" "\n\t" // 2 nop nop (T = 16)
"rjmp .+0" "\n\t" // 2 nop nop (T = 18)
"rjmp .+0" "\n\t" // 2 nop nop (T = 20)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 22)
"nop" "\n\t" // 1 nop (T = 23)
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 24)
"dec %[bit]" "\n\t" // 1 bit-- (T = 25)
"breq nextbyte40" "\n\t" // 1-2 if(bit == 0)
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 27)
"nop" "\n\t" // 1 nop (T = 28)
"rjmp .+0" "\n\t" // 2 nop nop (T = 30)
"rjmp .+0" "\n\t" // 2 nop nop (T = 32)
"rjmp .+0" "\n\t" // 2 nop nop (T = 34)
"rjmp .+0" "\n\t" // 2 nop nop (T = 36)
"rjmp .+0" "\n\t" // 2 nop nop (T = 38)
"rjmp head40" "\n\t" // 2 -> head40 (next bit out)
"nextbyte40:" "\n\t" // (T = 27)
"ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 28)
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 30)
"rjmp .+0" "\n\t" // 2 nop nop (T = 32)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 34)
"rjmp .+0" "\n\t" // 2 nop nop (T = 36)
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 38)
"brne head40" "\n" // 1-2 if(i != 0) -> (next byte)
: [port] "+e" (port),
[byte] "+r" (b),
[bit] "+r" (bit),
[next] "+r" (next),
[count] "+w" (i)
: [ptr] "e" (ptr),
[hi] "r" (hi),
[lo] "r" (lo));
}
#endif // NEO_KHZ400
#else
#error "CPU SPEED NOT SUPPORTED"
#endif // end F_CPU ifdefs on __AVR__
// END AVR ----------------------------------------------------------------
#elif defined(__arm__)
// ARM MCUs -- Teensy 3.0, 3.1, LC, Arduino Due ---------------------------
#if defined(__MK20DX128__) || defined(__MK20DX256__) // Teensy 3.0 & 3.1
#define CYCLES_800_T0H (F_CPU / 4000000)
#define CYCLES_800_T1H (F_CPU / 1250000)
#define CYCLES_800 (F_CPU / 800000)
#define CYCLES_400_T0H (F_CPU / 2000000)
#define CYCLES_400_T1H (F_CPU / 833333)
#define CYCLES_400 (F_CPU / 400000)
uint8_t *p = pixels,
*end = p + numBytes, pix, mask;
volatile uint8_t *set = portSetRegister(pin),
*clr = portClearRegister(pin);
uint32_t cyc;
ARM_DEMCR |= ARM_DEMCR_TRCENA;
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
#ifdef NEO_KHZ400 // 800 KHz check needed only if 400 KHz support enabled
if (is800KHz) {
#endif
cyc = ARM_DWT_CYCCNT + CYCLES_800;
while (p < end)
{
pix = *p++;
for (mask = 0x80; mask; mask >>= 1)
{
while (ARM_DWT_CYCCNT - cyc < CYCLES_800)
{
}
cyc = ARM_DWT_CYCCNT;
*set = 1;
if (pix & mask) {
while (ARM_DWT_CYCCNT - cyc < CYCLES_800_T1H)
{
}
} else {
while (ARM_DWT_CYCCNT - cyc < CYCLES_800_T0H)
{
}
}
*clr = 1;
}
}
while (ARM_DWT_CYCCNT - cyc < CYCLES_800)
{
}
#ifdef NEO_KHZ400
} else { // 400 kHz bitstream
cyc = ARM_DWT_CYCCNT + CYCLES_400;
while (p < end)
{
pix = *p++;
for (mask = 0x80; mask; mask >>= 1)
{
while (ARM_DWT_CYCCNT - cyc < CYCLES_400)
{
}
cyc = ARM_DWT_CYCCNT;
*set = 1;
if (pix & mask) {
while (ARM_DWT_CYCCNT - cyc < CYCLES_400_T1H)
{
}
} else {
while (ARM_DWT_CYCCNT - cyc < CYCLES_400_T0H)
{
}
}
*clr = 1;
}
}
while (ARM_DWT_CYCCNT - cyc < CYCLES_400)
{
}
}
#endif // NEO_KHZ400
#elif defined(__MKL26Z64__) // Teensy-LC
#if F_CPU == 48000000
uint8_t *p = pixels,
pix, count, dly,
bitmask = digitalPinToBitMask(pin);
volatile uint8_t *reg = portSetRegister(pin);
uint32_t num = numBytes;
asm volatile (
"L%=_begin:" "\n\t"
"ldrb %[pix], [%[p], #0]" "\n\t"
"lsl %[pix], #24" "\n\t"
"movs %[count], #7" "\n\t"
"L%=_loop:" "\n\t"
"lsl %[pix], #1" "\n\t"
"bcs L%=_loop_one" "\n\t"
"L%=_loop_zero:"
"strb %[bitmask], [%[reg], #0]" "\n\t"
"movs %[dly], #4" "\n\t"
"L%=_loop_delay_T0H:" "\n\t"
"sub %[dly], #1" "\n\t"
"bne L%=_loop_delay_T0H" "\n\t"
"strb %[bitmask], [%[reg], #4]" "\n\t"
"movs %[dly], #13" "\n\t"
"L%=_loop_delay_T0L:" "\n\t"
"sub %[dly], #1" "\n\t"
"bne L%=_loop_delay_T0L" "\n\t"
"b L%=_next" "\n\t"
"L%=_loop_one:"
"strb %[bitmask], [%[reg], #0]" "\n\t"
"movs %[dly], #13" "\n\t"
"L%=_loop_delay_T1H:" "\n\t"
"sub %[dly], #1" "\n\t"
"bne L%=_loop_delay_T1H" "\n\t"
"strb %[bitmask], [%[reg], #4]" "\n\t"
"movs %[dly], #4" "\n\t"
"L%=_loop_delay_T1L:" "\n\t"
"sub %[dly], #1" "\n\t"
"bne L%=_loop_delay_T1L" "\n\t"
"nop" "\n\t"
"L%=_next:" "\n\t"
"sub %[count], #1" "\n\t"
"bne L%=_loop" "\n\t"
"lsl %[pix], #1" "\n\t"
"bcs L%=_last_one" "\n\t"
"L%=_last_zero:"
"strb %[bitmask], [%[reg], #0]" "\n\t"
"movs %[dly], #4" "\n\t"
"L%=_last_delay_T0H:" "\n\t"
"sub %[dly], #1" "\n\t"
"bne L%=_last_delay_T0H" "\n\t"
"strb %[bitmask], [%[reg], #4]" "\n\t"
"movs %[dly], #10" "\n\t"
"L%=_last_delay_T0L:" "\n\t"
"sub %[dly], #1" "\n\t"
"bne L%=_last_delay_T0L" "\n\t"
"b L%=_repeat" "\n\t"
"L%=_last_one:"
"strb %[bitmask], [%[reg], #0]" "\n\t"
"movs %[dly], #13" "\n\t"
"L%=_last_delay_T1H:" "\n\t"
"sub %[dly], #1" "\n\t"
"bne L%=_last_delay_T1H" "\n\t"
"strb %[bitmask], [%[reg], #4]" "\n\t"
"movs %[dly], #1" "\n\t"
"L%=_last_delay_T1L:" "\n\t"
"sub %[dly], #1" "\n\t"
"bne L%=_last_delay_T1L" "\n\t"
"nop" "\n\t"
"L%=_repeat:" "\n\t"
"add %[p], #1" "\n\t"
"sub %[num], #1" "\n\t"
"bne L%=_begin" "\n\t"
"L%=_done:" "\n\t"
: [p] "+r" (p),
[pix] "=&r" (pix),
[count] "=&r" (count),
[dly] "=&r" (dly),
[num] "+r" (num)
: [bitmask] "r" (bitmask),
[reg] "r" (reg)
);
#else
#error "Sorry, only 48 MHz is supported, please set Tools > CPU Speed to 48 MHz"
#endif // F_CPU == 48000000
#elif defined(__SAMD21G18A__) // Arduino Zero
// Tried this with a timer/counter, couldn't quite get adequate
// resolution. So yay, you get a load of goofball NOPs...
uint8_t *ptr, *end, p, bitMask, portNum;
uint32_t pinMask;
portNum = g_APinDescription[pin].ulPort;
pinMask = 1ul << g_APinDescription[pin].ulPin;
ptr = pixels;
end = ptr + numBytes;
p = *ptr++;
bitMask = 0x80;
volatile uint32_t *set = &(PORT->Group[portNum].OUTSET.reg),
*clr = &(PORT->Group[portNum].OUTCLR.reg);
#ifdef NEO_KHZ400 // 800 KHz check needed only if 400 KHz support enabled
if (is800KHz) {
#endif
for ( ; ;)
{
*set = pinMask;
asm ("nop; nop; nop; nop; nop; nop; nop; nop;");
if (p & bitMask) {
asm ("nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop;");
*clr = pinMask;
} else {
*clr = pinMask;
asm ("nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop;");
}
if (bitMask >>= 1) {
asm ("nop; nop; nop; nop; nop; nop; nop; nop; nop;");
} else {
if (ptr >= end) {
break;
}
p = *ptr++;
bitMask = 0x80;
}
}
#ifdef NEO_KHZ400
} else { // 400 KHz bitstream
for ( ; ;)
{
*set = pinMask;
asm ("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;");
if (p & bitMask) {
asm ("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;");
*clr = pinMask;
} else {
*clr = pinMask;
asm ("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;");
}
asm ("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;");
if (bitMask >>= 1) {
asm ("nop; nop; nop; nop; nop; nop; nop;");
} else {
if (ptr >= end) {
break;
}
p = *ptr++;
bitMask = 0x80;
}
}
}
#endif
#elif defined (ARDUINO_STM32_FEATHER) // FEATHER WICED (120MHz)
// Tried this with a timer/counter, couldn't quite get adequate
// resolution. So yay, you get a load of goofball NOPs...
uint8_t *ptr, *end, p, bitMask;
uint32_t pinMask;
pinMask = BIT(PIN_MAP[pin].gpio_bit);
ptr = pixels;
end = ptr + numBytes;
p = *ptr++;
bitMask = 0x80;
volatile uint16_t *set = &(PIN_MAP[pin].gpio_device->regs->BSRRL);
volatile uint16_t *clr = &(PIN_MAP[pin].gpio_device->regs->BSRRH);
#ifdef NEO_KHZ400 // 800 KHz check needed only if 400 KHz support enabled
if (is800KHz) {
#endif
for ( ; ;)
{
if (p & bitMask) { // ONE
// High 800ns
*set = pinMask;
asm ("nop; nop; nop; nop; nop; nop; nop; nop;"
...
This file has been truncated, please download it to see its full contents.
/*--------------------------------------------------------------------
* This file is part of the Adafruit NeoPixel library.
*
* NeoPixel is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* NeoPixel is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with NeoPixel. If not, see
* <http://www.gnu.org/licenses/>.
* --------------------------------------------------------------------*/
#ifndef ADAFRUIT_NEOPIXEL_H
#define ADAFRUIT_NEOPIXEL_H
#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#include <pins_arduino.h>
#endif
// The order of primary colors in the NeoPixel data stream can vary
// among device types, manufacturers and even different revisions of
// the same item. The third parameter to the Adafruit_NeoPixel
// constructor encodes the per-pixel byte offsets of the red, green
// and blue primaries (plus white, if present) in the data stream --
// the following #defines provide an easier-to-use named version for
// each permutation. e.g. NEO_GRB indicates a NeoPixel-compatible
// device expecting three bytes per pixel, with the first byte
// containing the green value, second containing red and third
// containing blue. The in-memory representation of a chain of
// NeoPixels is the same as the data-stream order; no re-ordering of
// bytes is required when issuing data to the chain.
// Bits 5,4 of this value are the offset (0-3) from the first byte of
// a pixel to the location of the red color byte. Bits 3,2 are the
// green offset and 1,0 are the blue offset. If it is an RGBW-type
// device (supporting a white primary in addition to R,G,B), bits 7,6
// are the offset to the white byte...otherwise, bits 7,6 are set to
// the same value as 5,4 (red) to indicate an RGB (not RGBW) device.
// i.e. binary representation:
// 0bWWRRGGBB for RGBW devices
// 0bRRRRGGBB for RGB
// RGB NeoPixel permutations; white and red offsets are always same
// Offset: W R G B
#define NEO_RGB ((0 << 6) | (0 << 4) | (1 << 2) | (2))
#define NEO_RBG ((0 << 6) | (0 << 4) | (2 << 2) | (1))
#define NEO_GRB ((1 << 6) | (1 << 4) | (0 << 2) | (2))
#define NEO_GBR ((2 << 6) | (2 << 4) | (0 << 2) | (1))
#define NEO_BRG ((1 << 6) | (1 << 4) | (2 << 2) | (0))
#define NEO_BGR ((2 << 6) | (2 << 4) | (1 << 2) | (0))
// RGBW NeoPixel permutations; all 4 offsets are distinct
// Offset: W R G B
#define NEO_WRGB ((0 << 6) | (1 << 4) | (2 << 2) | (3))
#define NEO_WRBG ((0 << 6) | (1 << 4) | (3 << 2) | (2))
#define NEO_WGRB ((0 << 6) | (2 << 4) | (1 << 2) | (3))
#define NEO_WGBR ((0 << 6) | (3 << 4) | (1 << 2) | (2))
#define NEO_WBRG ((0 << 6) | (2 << 4) | (3 << 2) | (1))
#define NEO_WBGR ((0 << 6) | (3 << 4) | (2 << 2) | (1))
#define NEO_RWGB ((1 << 6) | (0 << 4) | (2 << 2) | (3))
#define NEO_RWBG ((1 << 6) | (0 << 4) | (3 << 2) | (2))
#define NEO_RGWB ((2 << 6) | (0 << 4) | (1 << 2) | (3))
#define NEO_RGBW ((3 << 6) | (0 << 4) | (1 << 2) | (2))
#define NEO_RBWG ((2 << 6) | (0 << 4) | (3 << 2) | (1))
#define NEO_RBGW ((3 << 6) | (0 << 4) | (2 << 2) | (1))
#define NEO_GWRB ((1 << 6) | (2 << 4) | (0 << 2) | (3))
#define NEO_GWBR ((1 << 6) | (3 << 4) | (0 << 2) | (2))
#define NEO_GRWB ((2 << 6) | (1 << 4) | (0 << 2) | (3))
#define NEO_GRBW ((3 << 6) | (1 << 4) | (0 << 2) | (2))
#define NEO_GBWR ((2 << 6) | (3 << 4) | (0 << 2) | (1))
#define NEO_GBRW ((3 << 6) | (2 << 4) | (0 << 2) | (1))
#define NEO_BWRG ((1 << 6) | (2 << 4) | (3 << 2) | (0))
#define NEO_BWGR ((1 << 6) | (3 << 4) | (2 << 2) | (0))
#define NEO_BRWG ((2 << 6) | (1 << 4) | (3 << 2) | (0))
#define NEO_BRGW ((3 << 6) | (1 << 4) | (2 << 2) | (0))
#define NEO_BGWR ((2 << 6) | (3 << 4) | (1 << 2) | (0))
#define NEO_BGRW ((3 << 6) | (2 << 4) | (1 << 2) | (0))
// Add NEO_KHZ400 to the color order value to indicate a 400 KHz
// device. All but the earliest v1 NeoPixels expect an 800 KHz data
// stream, this is the default if unspecified. Because flash space
// is very limited on ATtiny devices (e.g. Trinket, Gemma), v1
// NeoPixels aren't handled by default on those chips, though it can
// be enabled by removing the ifndef/endif below -- but code will be
// bigger. Conversely, can disable the NEO_KHZ400 line on other MCUs
// to remove v1 support and save a little space.
#define NEO_KHZ800 0x0000 // 800 KHz datastream
#ifndef __AVR_ATtiny85__
#define NEO_KHZ400 0x0100 // 400 KHz datastream
#endif
// If 400 KHz support is enabled, the third parameter to the constructor
// requires a 16-bit value (in order to select 400 vs 800 KHz speed).
// If only 800 KHz is enabled (as is default on ATtiny), an 8-bit value
// is sufficient to encode pixel color order, saving some space.
#ifdef NEO_KHZ400
typedef uint16_t neoPixelType;
#else
typedef uint8_t neoPixelType;
#endif
class Adafruit_NeoPixel {
public:
// Constructor: number of LEDs, pin number, LED type
Adafruit_NeoPixel(uint16_t n, uint8_t p = 6, neoPixelType t = NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel(void);
~Adafruit_NeoPixel();
void
begin(void),
show(void),
setPin(uint8_t p),
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b),
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w),
setPixelColor(uint16_t n, uint32_t c),
setBrightness(uint8_t),
clear(),
updateLength(uint16_t n),
updateType(neoPixelType t);
uint8_t
*getPixels(void) const,
getBrightness(void) const;
uint16_t
numPixels(void) const;
static uint32_t
Color(uint8_t r, uint8_t g, uint8_t b),
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w);
uint32_t
getPixelColor(uint16_t n) const;
inline bool
canShow(void)
{
return ((micros() - endTime) >= 50L);
}
private:
boolean
#ifdef NEO_KHZ400 // If 400 KHz NeoPixel support enabled...
is800KHz, // ...true if 800 KHz pixels
#endif
begun; // true if begin() previously called
uint16_t
numLEDs, // Number of RGB LEDs in strip
numBytes; // Size of 'pixels' buffer below (3 or 4 bytes/pixel)
int8_t
pin; // Output pin number (-1 if not yet set)
uint8_t
brightness,
*pixels, // Holds LED color values (3 or 4 bytes each)
rOffset, // Index of red byte within each 3- or 4-byte pixel
gOffset, // Index of green byte
bOffset, // Index of blue byte
wOffset; // Index of white byte (same as rOffset if no white)
uint32_t
endTime; // Latch timing reference
#ifdef __AVR__
volatile uint8_t
*port; // Output PORT register
uint8_t
pinMask; // Output PORT bitmask
#endif
};
#endif // ADAFRUIT_NEOPIXEL_H
//
#define Note1_0 -1
#define Note1_1 262
#define Note1_2 294
#define Note1_3 330
#define Note1_4 350
#define Note1_5 393
#define Note1_6 441
#define Note1_7 495
#define NOTE1_LEN 32 //
//
int note1[] = {
Note1_1, Note1_2, Note1_3, Note1_1, Note1_1,
Note1_2, Note1_3, Note1_1, Note1_3, Note1_4,
Note1_5, Note1_3, Note1_4, Note1_5, Note1_5,
Note1_6, Note1_5, Note1_4, Note1_3, Note1_1,
Note1_5, Note1_6, Note1_5, Note1_4, Note1_3,
Note1_1, Note1_1, Note1_5, Note1_1, Note1_1,
Note1_5, Note1_1};
//
float beat1[] = {
1, 1, 1, 1, 1,
1, 1, 1, 1, 1,
2, 1, 1, 2, 0.75,
0.25, 0.75, 0.25, 1, 1,
0.75, 0.25, 0.75, 0.25, 1,
1, 1, 1, 2, 1,
1, 2};
void play1()
{
for (int i = 0; i < NOTE1_LEN; i++)
{
tone(BEEP_PIN, note1[i]);
delay(400 * beat1[i]);
noTone(BEEP_PIN);
}
}
#define PCINT_VERSION 2402
#define detachPinChangeInterrupt(pin) PCintPort::detachInterrupt(pin)
#define attachPinChangeInterrupt(pin,userFunc,mode) PCintPort::attachInterrupt(pin, &userFunc,mode)
#define getInterruptedPin() PCintPort::getArduinoPin()
#ifndef PinChangeInt_h
#define PinChangeInt_h
#include "stddef.h"
#include <Arduino.h>
#include <new.h>
#include <wiring_private.h>
#undef DEBUG
#undef INLINE_PCINT
#define INLINE_PCINT
#if defined __AVR_ATmega2560__ || defined __AVR_ATmega1280__ || defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ || defined __AVR_ATmega640__
#define __USE_PORT_JK
#define NO_PORTA_PINCHANGES
#define NO_PORTC_PINCHANGES
#define NO_PORTD_PINCHANGES
#if ((defined(NO_PORTB_PINCHANGES) && defined(NO_PORTJ_PINCHANGES)) || \
(defined(NO_PORTJ_PINCHANGES) && defined(NO_PORTK_PINCHANGES)) || \
(defined(NO_PORTK_PINCHANGES) && defined(NO_PORTB_PINCHANGES)))
#define INLINE_PCINT inline
#endif
#else
#define NO_PORTJ_PINCHANGES
#define NO_PORTK_PINCHANGES
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
#ifndef NO_PORTA_PINCHANGES
#define __USE_PORT_A
#endif
#else
#define NO_PORTA_PINCHANGES
#endif
#if ( (defined(NO_PORTA_PINCHANGES) && defined(NO_PORTB_PINCHANGES) && defined(NO_PORTC_PINCHANGES)) || \
(defined(NO_PORTA_PINCHANGES) && defined(NO_PORTB_PINCHANGES) && defined(NO_PORTD_PINCHANGES)) || \
(defined(NO_PORTA_PINCHANGES) && defined(NO_PORTC_PINCHANGES) && defined(NO_PORTD_PINCHANGES)) || \
(defined(NO_PORTB_PINCHANGES) && defined(NO_PORTC_PINCHANGES) && defined(NO_PORTD_PINCHANGES)) )
#define INLINE_PCINT inline
#endif
#endif
#define PCdetachInterrupt(pin) PCintPort::detachInterrupt(pin)
#define PCattachInterrupt(pin,userFunc,mode) PCintPort::attachInterrupt(pin, userFunc,mode)
#define PCgetArduinoPin() PCintPort::getArduinoPin()
typedef void (*PCIntvoidFuncPtr)(void);
class PCintPort {
public:
PCintPort(int index,int pcindex, volatile uint8_t& maskReg) :
portInputReg(*portInputRegister(index)),
portPCMask(maskReg),
PCICRbit(1 << pcindex),
portRisingPins(0),
portFallingPins(0),
firstPin(NULL)
#ifdef PINMODE
,intrCount(0)
#endif
{
#ifdef FLASH
ledsetup();
#endif
}
volatile uint8_t& portInputReg;
static int8_t attachInterrupt(uint8_t pin, PCIntvoidFuncPtr userFunc, int mode);
static void detachInterrupt(uint8_t pin);
INLINE_PCINT void PCint();
static volatile uint8_t curr;
#ifndef NO_PIN_NUMBER
static volatile uint8_t arduinoPin;
#endif
#ifndef NO_PIN_STATE
static volatile uint8_t pinState;
#endif
#ifdef PINMODE
static volatile uint8_t pinmode;
static volatile uint8_t s_portRisingPins;
static volatile uint8_t s_portFallingPins;
static volatile uint8_t s_lastPinView;
static volatile uint8_t s_pmask;
static volatile char s_PORT;
static volatile uint8_t s_changedPins;
static volatile uint8_t s_portRisingPins_nCurr;
static volatile uint8_t s_portFallingPins_nNCurr;
static volatile uint8_t s_currXORlastPinView;
volatile uint8_t intrCount;
static volatile uint8_t s_count;
static volatile uint8_t pcint_multi;
static volatile uint8_t PCIFRbug;
#endif
#ifdef FLASH
static void ledsetup(void);
#endif
protected:
class PCintPin {
public:
PCintPin() :
PCintFunc((PCIntvoidFuncPtr)NULL),
mode(0) {}
PCIntvoidFuncPtr PCintFunc;
uint8_t mode;
uint8_t mask;
uint8_t arduinoPin;
PCintPin* next;
};
void enable(PCintPin* pin, PCIntvoidFuncPtr userFunc, uint8_t mode);
int8_t addPin(uint8_t arduinoPin,PCIntvoidFuncPtr userFunc, uint8_t mode);
volatile uint8_t& portPCMask;
const uint8_t PCICRbit;
volatile uint8_t portRisingPins;
volatile uint8_t portFallingPins;
volatile uint8_t lastPinView;
PCintPin* firstPin;
};
#ifndef LIBCALL_PINCHANGEINT
volatile uint8_t PCintPort::curr=0;
#ifndef NO_PIN_NUMBER
volatile uint8_t PCintPort::arduinoPin=0;
#endif
#ifndef NO_PIN_STATE
volatile uint8_t PCintPort::pinState=0;
#endif
#ifdef PINMODE
volatile uint8_t PCintPort::pinmode=0;
volatile uint8_t PCintPort::s_portRisingPins=0;
volatile uint8_t PCintPort::s_portFallingPins=0;
volatile uint8_t PCintPort::s_lastPinView=0;
volatile uint8_t PCintPort::s_pmask=0;
volatile char PCintPort::s_PORT='x';
volatile uint8_t PCintPort::s_changedPins=0;
volatile uint8_t PCintPort::s_portRisingPins_nCurr=0;
volatile uint8_t PCintPort::s_portFallingPins_nNCurr=0;
volatile uint8_t PCintPort::s_currXORlastPinView=0;
volatile uint8_t PCintPort::s_count=0;
volatile uint8_t PCintPort::pcint_multi=0;
volatile uint8_t PCintPort::PCIFRbug=0;
#endif
#ifdef FLASH
#define PINLED 13
volatile uint8_t *led_port;
uint8_t led_mask;
uint8_t not_led_mask;
boolean ledsetup_run=false;
void PCintPort::ledsetup(void) {
if (! ledsetup_run) {
led_port=portOutputRegister(digitalPinToPort(PINLED));
led_mask=digitalPinToBitMask(PINLED);
not_led_mask=led_mask^0xFF;
pinMode(PINLED, OUTPUT); digitalWrite(PINLED, LOW);
ledsetup_run=true;
}
};
#endif
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
#ifndef NO_PORTA_PINCHANGES
PCintPort portA=PCintPort(1, 0,PCMSK0);
#endif
#ifndef NO_PORTB_PINCHANGES
PCintPort portB=PCintPort(2, 1,PCMSK1);
#endif
#ifndef NO_PORTC_PINCHANGES
PCintPort portC=PCintPort(3, 2,PCMSK2);
#endif
#ifndef NO_PORTD_PINCHANGES
PCintPort portD=PCintPort(4, 3,PCMSK3);
#endif
#else
#ifndef NO_PORTB_PINCHANGES
PCintPort portB=PCintPort(2, 0,PCMSK0);
#endif
#ifndef NO_PORTC_PINCHANGES
PCintPort portC=PCintPort(3, 1,PCMSK1);
#endif
#ifndef NO_PORTD_PINCHANGES
PCintPort portD=PCintPort(4, 2,PCMSK2);
#endif
#endif
#ifdef __USE_PORT_JK
#ifndef NO_PORTJ_PINCHANGES
PCintPort portJ=PCintPort(10,1,PCMSK1);
#endif
#ifndef NO_PORTK_PINCHANGES
PCintPort portK=PCintPort(11,2,PCMSK2);
#endif
#endif
static PCintPort *lookupPortNumToPort( int portNum ) {
PCintPort *port = NULL;
switch (portNum) {
#ifndef NO_PORTA_PINCHANGES
case 1:
port=&portA;
break;
#endif
#ifndef NO_PORTB_PINCHANGES
case 2:
port=&portB;
break;
#endif
#ifndef NO_PORTC_PINCHANGES
case 3:
port=&portC;
break;
#endif
#ifndef NO_PORTD_PINCHANGES
case 4:
port=&portD;
break;
#endif
#ifdef __USE_PORT_JK
#ifndef NO_PORTJ_PINCHANGES
case 10:
port=&portJ;
break;
#endif
#ifndef NO_PORTK_PINCHANGES
case 11:
port=&portK;
break;
#endif
#endif
}
return port;
}
void PCintPort::enable(PCintPin* p, PCIntvoidFuncPtr userFunc, uint8_t mode) {
p->mode=mode;
p->PCintFunc=userFunc;
#ifndef NO_PORTJ_PINCHANGES
if ((p->arduinoPin == 14) || (p->arduinoPin == 15)) {
portPCMask |= (p->mask << 1);
}
else {
portPCMask |= p->mask;
}
#else
portPCMask |= p->mask;
#endif
if ((p->mode == RISING) || (p->mode == CHANGE)) portRisingPins |= p->mask;
if ((p->mode == FALLING) || (p->mode == CHANGE)) portFallingPins |= p->mask;
PCICR |= PCICRbit;
}
int8_t PCintPort::addPin(uint8_t arduinoPin, PCIntvoidFuncPtr userFunc, uint8_t mode)
{
PCintPin* tmp;
tmp=firstPin;
if (firstPin != NULL) {
do {
if (tmp->arduinoPin == arduinoPin) { enable(tmp, userFunc, mode); return(0); }
if (tmp->next == NULL) break;
tmp=tmp->next;
} while (true);
}
PCintPin* p=new PCintPin;
if (p == NULL) return(-1);
p->arduinoPin=arduinoPin;
p->mode = mode;
p->next=NULL;
p->mask = digitalPinToBitMask(arduinoPin);
if (firstPin == NULL) firstPin=p;
else tmp->next=p;
#ifdef DEBUG
Serial.print("addPin. pin given: "); Serial.print(arduinoPin, DEC);
int addr = (int) p;
Serial.print(" instance addr: "); Serial.println(addr, HEX);
Serial.print("userFunc addr: "); Serial.println((int)p->PCintFunc, HEX);
#endif
enable(p, userFunc, mode);
#ifdef DEBUG
Serial.print("addPin. pin given: "); Serial.print(arduinoPin, DEC), Serial.print (" pin stored: ");
int addr = (int) p;
Serial.print(" instance addr: "); Serial.println(addr, HEX);
#endif
return(1);
}
int8_t PCintPort::attachInterrupt(uint8_t arduinoPin, PCIntvoidFuncPtr userFunc, int mode)
{
PCintPort *port;
uint8_t portNum = digitalPinToPort(arduinoPin);
if ((portNum == NOT_A_PORT) || (userFunc == NULL)) return(-1);
port=lookupPortNumToPort(portNum);
port->lastPinView=port->portInputReg;
#ifdef DEBUG
Serial.print("attachInterrupt- pin: "); Serial.println(arduinoPin, DEC);
#endif
return(port->addPin(arduinoPin,userFunc,mode));
}
void PCintPort::detachInterrupt(uint8_t arduinoPin)
{
PCintPort *port;
PCintPin* current;
uint8_t mask;
uint8_t portNum = digitalPinToPort(arduinoPin);
if (portNum == NOT_A_PORT) return;
port=lookupPortNumToPort(portNum);
mask=digitalPinToBitMask(arduinoPin);
current=port->firstPin;
while (current) {
if (current->mask == mask) {
uint8_t oldSREG = SREG;
cli();
#ifndef NO_PORTJ_PINCHANGES
if ((arduinoPin == 14) || (arduinoPin == 15)) {
port->portPCMask &= ~(mask << 1);
}
else {
port->portPCMask &= ~mask;
}
#else
port->portPCMask &= ~mask;
#endif
if (port->portPCMask == 0) PCICR &= ~(port->PCICRbit);
port->portRisingPins &= ~current->mask; port->portFallingPins &= ~current->mask;
SREG = oldSREG;
return;
}
current=current->next;
}
}
void PCintPort::PCint() {
#ifdef FLASH
if (*led_port & led_mask) *led_port&=not_led_mask;
else *led_port|=led_mask;
#endif
#ifndef DISABLE_PCINT_MULTI_SERVICE
uint8_t pcifr;
while (true) {
#endif
#ifdef PINMODE
PCintPort::s_lastPinView=lastPinView;
intrCount++;
PCintPort::s_count=intrCount;
#endif
uint8_t changedPins = (PCintPort::curr ^ lastPinView) &
((portRisingPins & PCintPort::curr ) | ( portFallingPins & ~PCintPort::curr ));
#ifdef PINMODE
PCintPort::s_currXORlastPinView=PCintPort::curr ^ lastPinView;
PCintPort::s_portRisingPins_nCurr=portRisingPins & PCintPort::curr;
PCintPort::s_portFallingPins_nNCurr=portFallingPins & ~PCintPort::curr;
#endif
lastPinView = PCintPort::curr;
PCintPin* p = firstPin;
while (p) {
if (p->mask & changedPins) {
#ifndef NO_PIN_STATE
PCintPort::pinState=PCintPort::curr & p->mask ? HIGH : LOW;
#endif
#ifndef NO_PIN_NUMBER
PCintPort::arduinoPin=p->arduinoPin;
#endif
#ifdef PINMODE
PCintPort::pinmode=p->mode;
PCintPort::s_portRisingPins=portRisingPins;
PCintPort::s_portFallingPins=portFallingPins;
PCintPort::s_pmask=p->mask;
PCintPort::s_changedPins=changedPins;
#endif
p->PCintFunc();
}
p=p->next;
}
#ifndef DISABLE_PCINT_MULTI_SERVICE
pcifr = PCIFR & PCICRbit;
if (pcifr == 0) break;
PCIFR |= PCICRbit;
#ifdef PINMODE
PCintPort::pcint_multi++;
if (PCIFR & PCICRbit) PCintPort::PCIFRbug=1;
#endif
PCintPort::curr=portInputReg;
}
#endif
}
#ifndef NO_PORTA_PINCHANGES
ISR(PCINT0_vect) {
#ifdef PINMODE
PCintPort::s_PORT='A';
#endif
PCintPort::curr = portA.portInputReg;
portA.PCint();
}
#define PORTBVECT PCINT1_vect
#define PORTCVECT PCINT2_vect
#define PORTDVECT PCINT3_vect
#else
#define PORTBVECT PCINT0_vect
#define PORTCVECT PCINT1_vect
#define PORTDVECT PCINT2_vect
#endif
#ifndef NO_PORTB_PINCHANGES
ISR(PORTBVECT) {
#ifdef PINMODE
PCintPort::s_PORT='B';
#endif
PCintPort::curr = portB.portInputReg;
portB.PCint();
}
#endif
#ifndef NO_PORTC_PINCHANGES
ISR(PORTCVECT) {
#ifdef PINMODE
PCintPort::s_PORT='C';
#endif
PCintPort::curr = portC.portInputReg;
portC.PCint();
}
#endif
#ifndef NO_PORTD_PINCHANGES
ISR(PORTDVECT){
#ifdef PINMODE
PCintPort::s_PORT='D';
#endif
PCintPort::curr = portD.portInputReg;
portD.PCint();
}
#endif
#ifdef __USE_PORT_JK
#ifndef NO_PORTJ_PINCHANGES
ISR(PCINT1_vect) {
#ifdef PINMODE
PCintPort::s_PORT='J';
#endif
PCintPort::curr = portJ.portInputReg;
portJ.PCint();
}
#endif
#ifndef NO_PORTK_PINCHANGES
ISR(PCINT2_vect){
#ifdef PINMODE
PCintPort::s_PORT='K';
#endif
PCintPort::curr = portK.portInputReg;
portK.PCint();
}
#endif
#endif
#ifdef GET_PCINT_VERSION
uint16_t getPCIntVersion () {
return ((uint16_t) PCINT_VERSION);
}
#endif
#endif
#endif
#ifndef Pins_h
#define Pins_h
#define ECHO_PIN 6
#define TRIG_PIN 10
#define NUMPIXELS 3
#define RGB_PIN 3
#define L293_ENABLE_LEFT_PIN 11
#define L293_ENABLE_RIGHT_PIN 10
#define L293_LEFT_1_PIN 7
#define L293_LEFT_2_PIN 8
#define L293_RIGHT_1_PIN 12
#define L293_RIGHT_2_PIN 4
#define IR_SEND_PIN 9
#define IR_RECEIVE_PIN A2
#define KEY_MODE 2
#define BEEP_PIN 5
#define LINE_TRACKING_LEFT_PIN A1
#define LINE_TRACKING_RIGHT_PIN A0
#define VOL_MEASURE_PIN A3
#endif
#include "Adafruit_NeoPixel.h"
class RGB : public Adafruit_NeoPixel
{
public:
RGB() : Adafruit_NeoPixel(NUMPIXELS, RGB_PIN, NEO_GRB + NEO_KHZ800) {}
// const PROGMEM uint8_t gamma[256] = {
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
// 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
// 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
// 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
// 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
// 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
// 25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
// 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
// 51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
// 69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
// 90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 109, 110, 112, 114,
// 115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133, 135, 137, 138, 140, 142,
// 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 167, 169, 171, 173, 175,
// 177, 180, 182, 184, 186, 189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213,
// 215, 218, 220, 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252, 255};
uint32_t led_rgb_new[NUMPIXELS]; //right left mid
uint32_t led_rgb_old[NUMPIXELS];
int brightness = 50;
unsigned long rgb_delay_time = 0;
unsigned long dispaly_timeout = 0;
char flag = 0;
bool rgbDelay(unsigned long wait)
{
rgb_delay_time = millis();
while (millis() - rgb_delay_time < wait)
{
if (false)
{
return true;
}
}
return false;
}
uint32_t Wheel(byte 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);
}
uint8_t red(uint32_t c)
{
return (c >> 8);
}
uint8_t green(uint32_t c)
{
return (c >> 16);
}
uint8_t blue(uint32_t c)
{
return (c);
}
// bool pulseWhite(uint8_t wait)
// {
// for (int j = 0; j < 256; j++)
// {
// for (uint16_t i = 0; i < numPixels(); i++)
// {
// setPixelColor(i, Color(0, 0, 0, gamma[j]));
// }
// if (rgbDelay(wait))
// {
// return true;
// }
// show();
// }
// for (int j = 255; j >= 0; j--)
// {
// for (uint16_t i = 0; i < numPixels(); i++)
// {
// setPixelColor(i, Color(0, 0, 0, gamma[j]));
// }
// if (rgbDelay(wait))
// {
// return true;
// }
// show();
// }
// return false;
// }
bool theaterChase(uint8_t r, uint8_t g, uint8_t b, uint8_t wait)
{
for (int j = 0; j < 200; j++)
{
for (int q = 0; q < 3; q++)
{
for (uint16_t i = 0; i < numPixels(); i = i + 3)
{
setPixelColor(i + q, Color(r, g, b));
}
show();
if (rgbDelay(wait))
{
return true;
}
for (uint16_t i = 0; i < numPixels(); i = i + 3)
{
setPixelColor(i + q, 0);
}
}
}
return false;
}
bool rainbow(uint8_t wait)
{
for (uint16_t k = 0; k <= 100; k++)
{
for (uint16_t j = 0; j < 256; j++)
{
for (uint16_t i = 0; i < numPixels(); i++)
{
setPixelColor(i, Wheel((i + j) & 255));
}
show();
if (rgbDelay(wait))
{
return true;
}
}
}
return false;
}
bool rainbowCycle(uint8_t wait)
{
for (uint16_t j = 0; j < 256 * 100; j++)
{
for (uint16_t i = 0; i < numPixels(); i++)
{
setPixelColor(i, Wheel(((i * 256 / numPixels()) + j) & 255));
}
show();
if (rgbDelay(wait))
{
return true;
}
}
return false;
}
bool theaterChaseRainbow(uint8_t wait)
{
for (int k = 0; k < 30; k++)
{
for (int j = 0; j < 256; j++)
{
for (int q = 0; q < 3; q++)
{
for (uint16_t i = 0; i < numPixels(); i = i + 3)
{
setPixelColor(i + q, Wheel((i + j) % 255));
}
show();
if (rgbDelay(wait))
{
return true;
}
for (uint16_t i = 0; i < numPixels(); i = i + 3)
{
setPixelColor(i + q, 0);
}
}
}
}
return false;
}
// bool rainbowFade2White(uint8_t wait, int rainbowLoops, int whiteLoops)
// {
// float fadeMax = 100.0;
// int fadeVal = 0;
// uint32_t wheelVal;
// int redVal, greenVal, blueVal;
// for (int k = 0; k < rainbowLoops; k++)
// {
// for (uint16_t j = 0; j < 256; j++)
// {
// for (uint16_t i = 0; i < numPixels(); i++)
// {
// wheelVal = Wheel(((i * 256 / numPixels()) + j) & 255);
// redVal = red(wheelVal) * float(fadeVal / fadeMax);
// greenVal = green(wheelVal) * float(fadeVal / fadeMax);
// blueVal = blue(wheelVal) * float(fadeVal / fadeMax);
// setPixelColor(i, Color(redVal, greenVal, blueVal));
// }
// if (k == 0 && fadeVal < fadeMax - 1)
// {
// fadeVal++;
// }
// else if ((k == rainbowLoops - 1) && (j > 255 - fadeMax))
// {
// fadeVal--;
// }
// show();
// if (rgbDelay(wait))
// {
// return true;
// }
// }
// }
// if (rgbDelay(500))
// {
// return true;
// }
// for (int k = 0; k < whiteLoops; k++)
// {
// for (int j = 0; j < 256; j++)
// {
// for (uint16_t i = 0; i < numPixels(); i++)
// {
// setPixelColor(i, Color(0, 0, 0, gamma[j]));
// }
// show();
// }
// if (rgbDelay(2000))
// {
// return true;
// }
// for (int j = 255; j >= 0; j--)
// {
// for (uint16_t i = 0; i < numPixels(); i++)
// {
// setPixelColor(i, Color(0, 0, 0, gamma[j]));
// }
// show();
// }
// }
// if (rgbDelay(500))
// {
// return true;
// }
// return false;
// }
bool whiteOverRainbow(uint8_t wait, uint8_t whiteSpeed, uint8_t whiteLength)
{
if (whiteLength >= numPixels())
whiteLength = numPixels() - 1;
unsigned int head = whiteLength - 1;
unsigned int tail = 0;
int loops = 100;
int loopNum = 0;
static unsigned long lastTime = 0;
while (true)
{
for (int j = 0; j < 256; j++)
{
for (uint16_t i = 0; i < numPixels(); i++)
{
if ((i >= tail && i <= head) || (tail > head && i >= tail) || (tail > head && i <= head))
{
setPixelColor(i, Color(0, 0, 0, 255));
}
else
{
setPixelColor(i, Wheel(((i * 256 / numPixels()) + j) & 255));
}
}
if (millis() - lastTime > whiteSpeed)
{
head++;
tail++;
if (head == numPixels())
{
loopNum++;
}
lastTime = millis();
}
if (loopNum == loops)
return false;
head %= numPixels();
tail %= numPixels();
show();
if (rgbDelay(wait))
{
return true;
}
}
}
return false;
}
void initialize()
{
begin();
setBrightness(brightness);
show();
}
void setKeyColorNew(unsigned char r, unsigned char g, unsigned char b)
{
led_rgb_new[2] = Color(r, g, b);
}
void setKeyColorOld(unsigned char r, unsigned char g, unsigned char b)
{
led_rgb_old[2] = Color(r, g, b);
}
//
void setColorNew(unsigned char r2, unsigned char g2, unsigned char b2)
{
led_rgb_new[2] = Color(r2, g2, b2);
}
//
void setColorOld(unsigned char r2, unsigned char g2, unsigned char b2)
{
led_rgb_old[2] = Color(r2, g2, b2);
}
//
void setColorNew(unsigned char r0, unsigned char g0, unsigned char b0, unsigned char r1, unsigned char g1, unsigned char b1)
{
led_rgb_new[0] = Color(r0, g0, b0);
led_rgb_new[1] = Color(r1, g1, b1);
}
//
void setColorOld(unsigned char r0, unsigned char g0, unsigned char b0, unsigned char r1, unsigned char g1, unsigned char b1)
{
led_rgb_old[0] = Color(r0, g0, b0);
led_rgb_old[1] = Color(r1, g1, b1);
}
//
void setColorNew(unsigned char r0, unsigned char g0, unsigned char b0, unsigned char r1, unsigned char g1, unsigned char b1, unsigned char r2, unsigned char g2, unsigned char b2)
{
led_rgb_new[0] = Color(r0, g0, b0);
led_rgb_new[1] = Color(r1, g1, b1);
led_rgb_new[2] = Color(r2, g2, b2);
}
//
void setColorOld(unsigned char r0, unsigned char g0, unsigned char b0, unsigned char r1, unsigned char g1, unsigned char b1, unsigned char r2, unsigned char g2, unsigned char b2)
{
led_rgb_old[0] = Color(r0, g0, b0);
led_rgb_old[1] = Color(r1, g1, b1);
led_rgb_old[2] = Color(r2, g2, b2);
}
void blink(unsigned long delay_time) //
{
if ((millis() - previous_millis < delay_time) && (delay_flag == 0))
{
delay_flag = 1;
for (size_t i = 0; i < numPixels(); i++)
{
setPixelColor(i, led_rgb_new[i]);
}
show();
}
else if ((millis() - previous_millis < delay_time * 2) && (millis() - previous_millis > delay_time) && (delay_flag == 1))
{
delay_flag = 2;
for (size_t i = 0; i < numPixels(); i++)
{
setPixelColor(i, led_rgb_old[i]);
}
show();
}
else if (millis() - previous_millis >= delay_time * 2)
{
delay_flag = 0;
previous_millis = millis();
}
}
void lightOff() //
{
setColorNew(0, 0, 0, 0, 0, 0);
setColorOld(0, 0, 0, 0, 0, 0);
}
void lightKeyOff() //
{
setKeyColorNew(0, 0, 0);
setKeyColorOld(0, 0, 0);
}
void brightWhiteColor()
{
led_rgb_new[0] = 0xFFFFFF;
led_rgb_new[1] = 0xFFFFFF;
led_rgb_old[0] = 0xFFFFFF;
led_rgb_old[1] = 0xFFFFFF;
}
void lightOffAll()
{
setColorNew(0, 0, 0, 0, 0, 0, 0, 0, 0);
setColorOld(0, 0, 0, 0, 0, 0, 0, 0, 0);
}
void flashRGBColorAll()
{
setColorNew(255, 0, 0, 0, 255, 0, 0, 0, 255);
setColorOld(0, 0, 0, 0, 0, 0, 0, 0, 0);
}
void brightRedColor() //
{
setColorNew(255, 0, 0, 255, 0, 0);
setColorOld(255, 0, 0, 255, 0, 0);
}
void brightRedColorAll() //
{
setColorNew(255, 0, 0, 255, 0, 0, 255, 0, 0);
setColorOld(255, 0, 0, 255, 0, 0, 255, 0, 0);
}
void brightKeyRedColor()
{
setKeyColorNew(255, 0, 0);
setKeyColorOld(255, 0, 0);
}
void flashRedColor() //
{
setColorNew(255, 0, 0, 255, 0, 0);
setColorOld(0, 0, 0, 0, 0, 0);
}
void flashRedColorAll() //
{
setColorNew(255, 0, 0, 255, 0, 0, 255, 0, 0);
setColorOld(0, 0, 0, 0, 0, 0, 0, 0, 0);
}
void flashRedColorFlag()
{
setColorNew(255, 0, 0);
setColorOld(0, 0, 0);
}
void flashGreedYellowColorFlag()
{
setColorNew(173, 255, 47);
setColorOld(173, 255, 47);
}
void flashKeyRedColor()
{
setKeyColorNew(255, 0, 0);
setKeyColorOld(0, 0, 0);
}
void brightBlueColor() //
{
setColorNew(0, 0, 255, 0, 0, 255);
setColorOld(0, 0, 255, 0, 0, 255);
}
void brightBlueColorAll() //
{
setColorNew(0, 0, 255, 0, 0, 255, 0, 0, 255);
setColorOld(0, 0, 255, 0, 0, 255, 0, 0, 255);
}
void flashBlueColorLeft() //
{
setColorNew(0, 0, 0, 0, 0, 255);
setColorOld(0, 0, 0, 0, 0, 0);
}
void flashBlueColorRight() //
{
setColorNew(0, 0, 255, 0, 0, 0);
setColorOld(0, 0, 0, 0, 0, 0);
}
void brightYellowColor() //
{
setColorNew(255, 255, 0, 255, 255, 0);
setColorOld(255, 255, 0, 255, 255, 0);
}
void brightYellowColorAll() //
{
setColorNew(255, 255, 0, 255, 255, 0, 255, 255, 0);
setColorOld(255, 255, 0, 255, 255, 0, 255, 255, 0);
}
void flashYellowColorLeft() //
{
setColorNew(0, 0, 0, 255, 255, 0);
setColorOld(0, 0, 0, 0, 0, 0);
}
void flashYellowColorRight() //
{
setColorNew(255, 255, 0, 0, 0, 0);
setColorOld(0, 0, 0, 0, 0, 0);
}
void brightGreenColor() //
{
setColorNew(0, 255, 0, 0, 255, 0);
setColorOld(0, 255, 0, 0, 255, 0);
}
void brightGreenColorAll() //
{
setColorNew(0, 255, 0, 0, 255, 0, 0, 255, 0);
setColorOld(0, 255, 0, 0, 255, 0, 0, 255, 0);
}
void flashGreenColorLeft() //
{
setColorNew(0, 0, 0, 0, 255, 0);
setColorOld(0, 0, 0, 0, 0, 0);
}
void flashGreenColorRight() //
{
setColorNew(0, 255, 0, 0, 0, 0);
setColorOld(0, 0, 0, 0, 0, 0);
}
private:
unsigned char delay_flag = 0;
unsigned long previous_millis = 0;
} rgb;
#include "Ticker.h"
Ticker::Ticker() {}
Ticker::~Ticker() {}
void Ticker::start(fptr callback, uint32_t timer, uint16_t repeat, resolution_t resolution)
{
this->resolution = resolution;
if (this->resolution == MICROS)
timer *= 1000;
this->timer = timer;
this->repeat = repeat;
this->callback = callback;
if (this->callback == NULL)
return;
if (this->resolution == MILLIS)
lastTime = millis();
else
lastTime = micros();
enabled = true;
counts = 0;
status = RUNNING;
}
void Ticker::resume()
{
if (callback == NULL)
return;
if (resolution == MILLIS)
lastTime = millis() - diffTime;
else
lastTime = micros() - diffTime;
if (status == STOPPED)
counts = 0;
enabled = true;
status = RUNNING;
}
void Ticker::stop()
{
enabled = false;
counts = 0;
status = STOPPED;
}
void Ticker::pause()
{
if (resolution == MILLIS)
diffTime = millis() - lastTime;
else
diffTime = micros() - lastTime;
enabled = false;
status = PAUSED;
}
void Ticker::update()
{
if (tick())
callback();
}
bool Ticker::tick()
{
if (!enabled)
return false;
if (resolution == MILLIS)
{
if ((millis() - lastTime) >= timer)
{
lastTime = millis();
if (repeat - counts == 1)
enabled = false;
counts++;
return true;
}
}
else
{
if ((micros() - lastTime) >= timer)
{
lastTime = micros();
if (repeat - counts == 1)
enabled = false;
counts++;
return true;
}
}
return false;
}
void Ticker::interval(uint32_t timer)
{
if (resolution == MICROS)
timer *= 1000;
this->timer = timer;
}
uint32_t Ticker::elapsed()
{
if (resolution == MILLIS)
return millis() - lastTime;
else
return micros() - lastTime;
}
status_t Ticker::state()
{
return status;
}
uint32_t Ticker::counter()
{
return counts;
}
#ifndef TICKER_H
#define TICKER_H
#include "Arduino.h"
enum resolution_t
{
MICROS,
MILLIS,
MICROS_MICROS
};
enum status_t
{
STOPPED,
RUNNING,
PAUSED
};
typedef void (*fptr)();
class Ticker
{
public:
Ticker();
~Ticker();
void start(fptr callback, uint32_t timer, uint16_t repeat = 0, resolution_t resolution = MICROS);
void resume();
void pause();
void stop();
void update();
void interval(uint32_t timer);
uint32_t elapsed();
status_t state();
uint32_t counter();
private:
bool tick();
bool enabled;
uint32_t timer;
uint16_t repeat;
resolution_t resolution = MICROS;
uint32_t counts;
status_t status;
fptr callback;
uint32_t lastTime;
uint32_t diffTime;
};
#endif
Comments
Please log in or sign up to comment.