James Martel
Published © GPL3+

What Do I Build Next? An Arduino Nano Minicar

Back in January of 2019, Elegoo sent me an email asking if i'd like to test, comment, and review a new product design. I said "YES."

BeginnerFull instructions provided2 hours978
What Do I Build Next? An Arduino Nano Minicar

Things used in this project

Hardware components

generic handtools- phillips screwdriver, adjustable wrench, needle nose pliers
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Digilent Screwdriver
Digilent Screwdriver
Plier, Needle Nose
Plier, Needle Nose

Story

Read more

Schematics

wiring

Code

Elegoo Project files and documents

Arduino
Elegoo Project files
#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(&parameter[2][0], &ptr, 16);
    // rgb.led_rgb_new[1] = strtol(&parameter[2][0], &ptr, 16);
    // rgb.led_rgb_old[0] = strtol(&parameter[2][0], &ptr, 16);
    // rgb.led_rgb_old[1] = strtol(&parameter[2][0], &ptr, 16);

    // rgb.brightBlueColor();
    // Serial.println(strtol(&parameter[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(&parameter[0][0], &ptr, 16);
    if (parameter[1] == "0")
    {
      rgb.led_rgb_old[1] = strtol(&parameter[0][0], &ptr, 16);
...

This file has been truncated, please download it to see its full contents.

MiniCar Sketch Upload Tutorial for Windows.pdf

Arduino
No preview (download only).

Elegoo Project files and documents

Arduino
No preview (download only).

MiniCar Driver Win7.exe

Properties
No preview (download only).

MiniCar Sketch Upload Tutorial for MacOS.pdf

Arduino
No preview (download only).

Android App

Properties
No preview (download only).

Adafruit_NeoPixel.cpp

Arduino
Neopixels
/*-------------------------------------------------------------------------
 *  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.

Adafruit_NeoPixel.h

Arduino
Neopixel
/*--------------------------------------------------------------------
 *  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

Music.h

Arduino
music files
//
#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);
    }
}

PinChangeInt.h

Arduino
expansion info
#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

Pins.h

Arduino
info
#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

Rgb.h

Arduino
#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;

Ticker.cpp

Arduino
#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;
}

Ticker.h

Arduino
#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

Credits

James Martel

James Martel

47 projects • 59 followers
Self taught Robotics platform developer with electronics background

Comments