update libraries M..P

This commit is contained in:
rob tillaart 2020-11-27 11:28:57 +01:00
parent de6544a719
commit 9abe1508b1
93 changed files with 2869 additions and 804 deletions

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,29 @@
# nibbleArray
Arduino library for a compact array of nibbles (4 bit units)
## Description
A nibble is a 4 bit element, which can hold a value 0..15 (0..F in HEX).
The nibbleArray is an array that stores 2 nibbles in a byte therefor it is
twice as small as a normal array.
The current implementation can hold 510 elements. This is due a limitation of
the UNO which can alloc max 255 bytes in one **malloc()** call.
This **NIBBLEARRAY_MAXSIZE** can be defined compiletime "-D NIBBLEARRAY_MAXSIZE"
or one can adjust it in the library if other platforms can allocate more memory.
## Interface
The interface of the nibbleArray is straightforward:
* **get(index)** idem
* **set(index, value)** idem
* **clear()** set all elements to 0;
* **SetAll(value)** set all elements to value
## Operation

View File

@ -0,0 +1,144 @@
//
// FILE: nibbleArray_demo.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo nibble array
// DATE: 2020-06-21
// URL: https://github.com/RobTillaart/nibbleArray
// 0.1.0 2020-06-21 initial version
//
#include "nibbleArray.h"
nibbleArray na(500);
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("NIBBLEARRAY_LIB_VERSION: ");
Serial.println(NIBBLEARRAY_LIB_VERSION);
test_1();
Serial.println("\nDone...");
}
void test_1()
{
int ar[16];
for (int i = 0; i < 16; i++) ar[i] = 0;
na.clear();
// 500 throws with 3 dices (3..18 ==> 0..15)
for (int i = 0; i < 500; i++)
{
uint8_t sum = random(6);
sum += random(6);
sum += random(6);
na.set(i, sum); // diff from na.set(i, random(16));
}
for (int i = 0; i < 500; i++)
{
ar[na.get(i)]++;
Serial.print(" ");
Serial.print(na.get(i), HEX);
if ((i % 32) == 31) Serial.println();
}
Serial.println();
Serial.println("\nFrequency analysis");
for (int i = 0; i < 16; i++)
{
Serial.print(i);
Serial.print("\t");
// for (int p = 0; p < ar[i]; p++) Serial.print(">");
Serial.print(ar[i]);
Serial.println();
}
Serial.println();
Serial.println("\ninterpret data as a route");
for (int i = 0; i < 20; )
{
uint8_t s = na.get(i++);
uint8_t d = na.get(i++);
move(s, d);
}
Serial.println("\nor store music in the array");
for (int i = 0; i < 30; )
{
uint8_t octave = na.get(i++);
uint8_t note = na.get(i++);
uint8_t duration = na.get(i++); // in 1/16th
play(octave, note, duration);
// sendMIDI(note, duration);
}
}
void play(uint8_t chord, uint8_t note, uint8_t duration)
{
Serial.print("Play: ");
// Serial.print(chord);
Serial.print(" ");
switch (note)
{
case 0: Serial.print("C "); break;
case 1: Serial.print("C# "); break;
case 2: Serial.print("D "); break;
case 3: Serial.print("D# "); break;
case 4: Serial.print("E "); break;
case 5: Serial.print("F "); break;
case 6: Serial.print("F# "); break;
case 7: Serial.print("G "); break;
case 8: Serial.print("G# "); break;
case 9: Serial.print("A "); break;
case 10: Serial.print("A# "); break;
case 11: Serial.print("B "); break;
case 12: Serial.print("C "); break;
case 13: Serial.print("C# "); break;
case 14: Serial.print("D "); break;
case 15: Serial.print(" - "); break;
}
for (uint8_t i = 0; i < duration; i++)
{
delay(1000 / 16);
Serial.print(".");
}
Serial.println();
}
void move(uint8_t steps, uint8_t direction)
{
Serial.print(steps);
Serial.print(" steps to the ");
switch (direction)
{
case 0: Serial.print("N"); break;
case 1: Serial.print("NNO"); break;
case 2: Serial.print("NO"); break;
case 3: Serial.print("ONO"); break;
case 4: Serial.print("O"); break;
case 5: Serial.print("OZO"); break;
case 6: Serial.print("ZO"); break;
case 7: Serial.print("ZZO"); break;
case 8: Serial.print("Z"); break;
case 9: Serial.print("ZZW"); break;
case 10: Serial.print("ZW"); break;
case 11: Serial.print("WZW"); break;
case 12: Serial.print("W"); break;
case 13: Serial.print("WNW"); break;
case 14: Serial.print("NW"); break;
case 15: Serial.print("NNW"); break;
}
Serial.println();
delay(100 * steps);
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,170 @@
//
// FILE: nibbleArray_performance.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo performance nibble array
// DATE: 2020-06-21
// URL: https://github.com/RobTillaart/nibbleArray
// 0.1.0 2020-06-21 initial version
//
#include "nibbleArray.h"
nibbleArray na(500);
uint32_t start, stop, d1, d2;
volatile long x = 0;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("NIBBLEARRAY_LIB_VERSION: ");
Serial.println(NIBBLEARRAY_LIB_VERSION);
// performance tests are run first once in a loop
// then twice in a loop, so the difference is without
// the loop overhead.
test_size();
test_get();
test_set();
test_clear();
test_setAll();
Serial.println("Done...");
}
void test_size()
{
Serial.print("Nibble array size:\t");
Serial.println(na.size());
delay(100);
}
void test_get()
{
Serial.println("\nget");
start = micros();
for (int i = 0; i < 500; i++)
{
x += na.get(i);
}
stop = micros();
Serial.print("DURATION:\t");
d1 = stop - start;
Serial.println(d1);
delay(100);
start = micros();
for (int i = 0; i < 500; i++)
{
x += na.get(i);
x += na.get(i);
}
stop = micros();
Serial.print("DURATION:\t");
d2 = stop - start;
Serial.println(d2);
Serial.print("DELTA:\t\t");
Serial.println(d2 - d1);
Serial.print(" X:\t");
Serial.println(x);
delay(100);
}
void test_set()
{
Serial.println("\nset");
start = micros();
for (int i = 0; i < 500; i++)
{
na.set(i, 5);
}
stop = micros();
Serial.print("DURATION:\t");
d1 = stop - start;
Serial.println(d1);
delay(100);
start = micros();
for (int i = 0; i < 500; i++)
{
na.set(i, 5);
na.set(i, 10);
}
stop = micros();
Serial.print("DURATION:\t");
d2 = stop - start;
Serial.println(d2);
Serial.print("DELTA:\t\t");
Serial.println(d2 - d1);
delay(100);
}
void test_clear()
{
Serial.println("\nclear");
start = micros();
na.clear();
stop = micros();
Serial.print("DURATION:\t");
d1 = stop - start;
Serial.println(d1);
delay(100);
start = micros();
na.clear();
na.clear();
stop = micros();
Serial.print("DURATION:\t");
d2 = stop - start;
Serial.println(d2);
Serial.print("DELTA:\t\t");
Serial.println(d2 - d1);
delay(100);
for (int i = 0; i < 500; i++)
{
if (na.get(i) != 0)
{
Serial.println("Error in clear");
}
}
delay(100);
}
void test_setAll()
{
Serial.println("\nsetAll");
start = micros();
na.setAll(1);
stop = micros();
Serial.print("DURATION:\t");
d1 = stop - start;
Serial.println(d1);
delay(100);
for (int i = 0; i < 500; i++)
{
if (na.get(i) != 1)
{
Serial.println("Error in setAll");
}
}
delay(100);
start = micros();
na.setAll(2);
na.setAll(3);
stop = micros();
Serial.print("DURATION:\t");
d2 = stop - start;
Serial.println(d2);
Serial.print("DELTA:\t\t");
Serial.println(d2 - d1);
delay(100);
}
void loop()
{
}
// -- END OF FILE --

View File

@ -13,12 +13,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/nibbleArray.git"
},
"version":"0.1.0",
"version":"0.2.0",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/NibbleArray"
}
"platforms": "*"
}

View File

@ -1,9 +1,11 @@
name=NibbleArray
version=0.1.0
version=0.2.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library to implement a compact array of nibbles (4 bit).
paragraph=
category=Data Processing
url=https://github.com/RobTillaart/Arduino/tree/master/libraries/
architectures=*
architectures=*
includes=nibbleArray.h
depends=

View File

@ -1,47 +1,53 @@
//
// FILE: nibbleArray.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE: compact storage for array of nibbles
// URL:
// VERSION: 0.2.0
// PURPOSE: Arduino library for a compact array of nibbles (4 bits)
// URL: https://github.com/RobTillaart/nibbleArray
//
// HISTORY:
// 0.1.00 by Rob Tillaart (12/APR/2015)
//
// Released to the public domain
// 0.1.0 2015-04-12 initial version
// 0.2.0 2020-06-21 refactor; #pragma once; removed pre 1.0 support
//
#include "nibbleArray.h"
/////////////////////////////////////////////////////
//
// PUBLIC
//
nibbleArray::nibbleArray(uint16_t size)
{
arr = (uint16_t *) malloc((size+1)/2);
_size = min(NIBBLEARRAY_MAXSIZE, size);
arr = (uint8_t *) malloc((_size + 1)/2);
}
nibbleArray::~nibbleArray()
{
if (arr != NULL) free(arr);
if (arr != NULL) free(arr);
}
uint8_t nibbleArray::get(const uint16_t idx)
{
if (idx > _size) return 255; // magic error nr
if (idx & 1) return arr[idx/2] & 0x0F;
return arr[idx/2] >> 4;
if (idx > _size) return NIBBLEARRAY_ERROR_INDEX; // disable this check for more speed
if (idx & 1) return arr[idx/2] & 0x0F;
return arr[idx/2] >> 4;
}
uint8_t nibbleArray::set(const uint16_t idx, uint8_t value)
{
if (idx > _size) return 255; // magic error nr.
uint8_t v = value & 0x0F;
if (idx & 1) arr[idx/2] = (arr[idx/2] & 0xF0) | v;
else arr[idx/2] = (arr[idx/2] & 0x0F) | (v << 4);
if (idx > _size) return NIBBLEARRAY_ERROR_INDEX; // disable this check for more speed
uint8_t v = value & 0x0F;
if (idx & 1) arr[idx/2] = (arr[idx/2] & 0xF0) | v;
else arr[idx/2] = (arr[idx/2] & 0x0F) | (v << 4);
return NIBBLEARRAY_OK;
}
//
// END OF FILE
//
void nibbleArray::clear()
{
memset(arr, 0, (_size+1)/2);
}
void nibbleArray::setAll(uint8_t val)
{
uint8_t v = (val << 4) | val;
memset(arr, v, (_size+1)/2);
}
// -- END OF FILE --

View File

@ -1,39 +1,45 @@
#pragma once
//
// FILE: nibbleArray.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE: compact storage for array of nibbles
// URL:
// VERSION: 0.2.0
// PURPOSE: Arduino library for a compact array of nibbles (4 bits)
// URL: https://github.com/RobTillaart/nibbleArray
//
// HISTORY:
// see nibbleArray.cpp
//
#ifndef nibbleArray_h
#define nibbleArray_h
#if ARDUINO < 100
#include <WProgram.h>
#else
#include <Arduino.h>
#define NIBBLEARRAY_LIB_VERSION "0.2.0"
#ifndef NIBBLEARRAY_MAXSIZE
#define NIBBLEARRAY_MAXSIZE 510
#endif
#define NIBBLEARRAY_LIB_VERSION "0.1.00"
#define NIBBLEARRAY_OK 0x00
#define NIBBLEARRAY_ERROR_INDEX 0xFF
class nibbleArray
{
public:
nibbleArray(uint16_t size);
~nibbleArray();
nibbleArray(uint16_t size);
~nibbleArray();
uint8_t get(const uint16_t idx);
uint8_t set(const uint16_t idx, uint8_t value);
// return 0..F if ok
// retuns 0xFF for index error.
uint8_t get(const uint16_t idx);
// retuns 0xFF for index error.
uint8_t set(const uint16_t idx, uint8_t value);
uint16_t size() { return _size; };
void clear();
void setAll(uint8_t val);
private:
uint16_t *arr;
uint16_t _size;
uint8_t *arr;
uint16_t _size;
};
#endif
//
// END OF FILE
//
// -- END OF FILE --

21
libraries/PCA9635/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -2,134 +2,182 @@
// FILE: PCA9635.cpp
// AUTHOR: Rob Tillaart
// DATE: 23-apr-2016
// VERSION: 0.1.2
// PURPOSE: I2C PCA9635 library for Arduino
// URL:
// VERSION: 0.2.0
// PURPOSE: Arduino library for PCA9635 I2C LED driver
// URL: https://github.com/RobTillaart/PCA9635
//
// HISTORY:
// 0.1.2 fix for PCA9635_MODE1
// 0.1.01 set autoincr in constructor
// 0.1.00 initial BETA version
// 0.2.0 2020-05-26 major refactor; ESP32 support
// 0.1.2 2020-05-07 fix for PCA9635_MODE1
// 0.1.1 2016-04-24 set autoincr in constructor
// 0.1.0 2016-04-23 initial BETA version
//
#include "PCA9635.h"
#include <Wire.h>
PCA9635::PCA9635(const uint8_t deviceAddress)
{
_address = deviceAddress;
Wire.begin();
// TWBR = 12; // 400KHz
_data = 0;
_error = 0;
writeReg(PCA9635_MODE1, 0x81); // AUTOINCR | NOSLEEP | ALLADRR
_address = deviceAddress;
}
#if defined (ESP8266) || defined(ESP32)
void PCA9635::begin(uint8_t sda, uint8_t scl)
{
Wire.begin(sda, scl);
reset();
}
#endif
void PCA9635::begin()
{
Wire.begin();
reset();
}
void PCA9635::reset()
{
_data = 0;
_error = 0;
writeReg(PCA9635_MODE1, 0x81); // AUTOINCR | NOSLEEP | ALLADRR
}
// write value to single PWM registers
void PCA9635::write1(uint8_t channel, uint8_t value)
uint8_t PCA9635::write1(uint8_t channel, uint8_t value)
{
writeN(channel, &value, 1);
return writeN(channel, &value, 1);
}
// write three values in consecutive PWM registers
// typically for RGB values
void PCA9635::write3(uint8_t channel, uint8_t R, uint8_t G, uint8_t B)
uint8_t PCA9635::write3(uint8_t channel, uint8_t R, uint8_t G, uint8_t B)
{
uint8_t arr[3] = { R, G, B };
writeN(channel, arr, 3);
uint8_t arr[3] = { R, G, B };
return writeN(channel, arr, 3);
}
// write count values in consecutive PWM registers
void PCA9635::writeN(uint8_t channel, uint8_t* arr, uint8_t count)
// does not check if [channel + count > 16]
uint8_t PCA9635::writeN(uint8_t channel, uint8_t* arr, uint8_t count)
{
uint8_t base = PCA9635_PWM(channel);
Wire.beginTransmission(_address);
Wire.write(base);
for(uint8_t i = 0; i < count; i++)
{
Wire.write(arr[i]);
}
_error = Wire.endTransmission();
if (channel + count > 16)
{
_error = PCA9635_ERR_WRITE;
return PCA9635_ERROR;
}
uint8_t base = PCA9635_PWM(channel);
Wire.beginTransmission(_address);
Wire.write(base);
for(uint8_t i = 0; i < count; i++)
{
Wire.write(arr[i]);
}
_error = Wire.endTransmission();
if (_error != 0)
{
_error = PCA9635_ERR_I2C;
return PCA9635_ERROR;
}
return PCA9635_OK;
}
//
void PCA9635::writeMode(uint8_t reg, uint8_t value)
uint8_t PCA9635::writeMode(uint8_t reg, uint8_t value)
{
if (reg == PCA9635_MODE1 || reg == PCA9635_MODE2)
{
writeReg(reg, value);
}
if ((reg == PCA9635_MODE1) || (reg == PCA9635_MODE2))
{
writeReg(reg, value);
return PCA9635_OK;
}
_error = PCA9635_ERR_REG;
return PCA9635_ERROR;
}
//
// Note 0xFF can also mean an error....
uint8_t PCA9635::readMode(uint8_t reg)
{
if ((reg == PCA9635_MODE1) || (reg == PCA9635_MODE2))
{
uint8_t value = readReg(reg);
return value;
}
return PCA9635_ERROR;
if ((reg == PCA9635_MODE1) || (reg == PCA9635_MODE2))
{
uint8_t value = readReg(reg);
return value;
}
_error = PCA9635_ERR_REG;
return PCA9635_ERROR;
}
//
void PCA9635::setLedDriverMode(uint8_t channel, uint8_t mode)
uint8_t PCA9635::setLedDriverMode(uint8_t channel, uint8_t mode)
{
if (channel <= 15 && mode <= 3)
{
uint8_t reg = PCA9635_LEDOUT_BASE + (channel >> 2);
// some bit magic
uint8_t shift = (channel & 0x03) * 2; // 0,2,4,6 places
uint8_t setmask = mode << shift;
uint8_t clrmask = ~(0x03 << shift);
uint8_t value = (readReg(reg) & clrmask) | setmask;
writeReg(reg, value);
}
if (channel > 15)
{
_error = PCA9635_ERR_CHAN;
return PCA9635_ERROR;
}
if (mode > 3)
{
_error = PCA9635_ERR_MODE;
return PCA9635_ERROR;
}
uint8_t reg = PCA9635_LEDOUT_BASE + (channel >> 2);
// some bit magic
uint8_t shift = (channel & 0x03) * 2; // 0,2,4,6 places
uint8_t setmask = mode << shift;
uint8_t clrmask = ~(0x03 << shift);
uint8_t value = (readReg(reg) & clrmask) | setmask;
writeReg(reg, value);
return PCA9635_OK;
}
//
// returns 0..3 if OK, other values indicate an error
uint8_t PCA9635::getLedDriverMode(uint8_t channel)
{
if (channel <= 15)
{
uint8_t reg = PCA9635_LEDOUT_BASE + (channel >> 2);
uint8_t shift = (channel & 0x03) * 2; // 0,2,4,6 places
return (readReg(reg) >> shift ) & 0x03;
}
if (channel > 15)
{
_error = PCA9635_ERR_CHAN;
return PCA9635_ERROR;
}
uint8_t reg = PCA9635_LEDOUT_BASE + (channel >> 2);
uint8_t shift = (channel & 0x03) * 2; // 0,2,4,6 places
uint8_t value = (readReg(reg) >> shift ) & 0x03;
return value;
}
//
// note error flag is reset after read!
int PCA9635::lastError()
{
int e = _error;
_error = 0;
return e;
int e = _error;
_error = 0;
return e;
}
/////////////////////////////////////////////////////
//
// PRIVATE
//
void PCA9635::writeReg(uint8_t reg, uint8_t value)
{
Wire.beginTransmission(_address);
Wire.write(reg);
Wire.write(value);
_error = Wire.endTransmission();
Wire.beginTransmission(_address);
Wire.write(reg);
Wire.write(value);
_error = Wire.endTransmission();
}
uint8_t PCA9635::readReg(uint8_t reg)
{
Wire.beginTransmission(_address);
Wire.write(reg);
_error = Wire.endTransmission();
if (Wire.requestFrom(_address, (uint8_t)1) != 1)
{
_error = PCA9635_ERROR;
return 0;
}
_data = Wire.read();
return _data;
Wire.beginTransmission(_address);
Wire.write(reg);
_error = Wire.endTransmission();
if (Wire.requestFrom(_address, (uint8_t)1) != 1)
{
_error = PCA9635_ERROR;
return 0;
}
_data = Wire.read();
return _data;
}
//
// END OF FILE
//
// -- END OF FILE --

View File

@ -1,21 +1,16 @@
#pragma once
//
// FILE: PCA9635.H
// AUTHOR: Rob Tillaart
// DATE: 23-apr-2016
// VERSION: 0.1.2
// PURPOSE: I2C PCA9635 library for Arduino
// URL: https://github.com/RobTillaart/Arduino/tree/master/libraries
// VERSION: 0.2.0
// PURPOSE: Arduino library for PCA9635 I2C LED driver
// URL: https://github.com/RobTillaart/PCA9635
//
// HISTORY:
// see PCA9635.cpp file
//
#ifndef _PCA9635_H
#define _PCA9635_H
#include "Arduino.h"
#define PCA9635_LIB_VERSION "0.1.00 BETA"
#define PCA9635_LIB_VERSION "0.2.0"
#define PCA9635_MODE1 0x00
#define PCA9635_MODE2 0x01
@ -33,6 +28,11 @@
#define PCA9635_OK 0x00
#define PCA9635_ERROR 0xFF
#define PCA9635_ERR_WRITE 0xFE
#define PCA9635_ERR_CHAN 0xFD
#define PCA9635_ERR_MODE 0xFC
#define PCA9635_ERR_REG 0xFB
#define PCA9635_ERR_I2C 0xFA
// NOT IMPLEMENTED YET
#define PCA9635_SUBADR(x) (0x17+(x)) // x = 1..3
@ -41,44 +41,49 @@
class PCA9635
{
public:
explicit PCA9635(const uint8_t deviceAddress);
explicit PCA9635(const uint8_t deviceAddress);
void setLedDriverMode(uint8_t channel, uint8_t mode);
uint8_t getLedDriverMode(uint8_t channel);
#if defined (ESP8266) || defined(ESP32)
void begin(uint8_t sda, uint8_t scl);
#endif
void begin();
void reset();
uint8_t setLedDriverMode(uint8_t channel, uint8_t mode);
uint8_t getLedDriverMode(uint8_t channel);
// single PWM setting
void write1(uint8_t channel, uint8_t value);
// RGB setting
void write3(uint8_t channel, uint8_t R, uint8_t G, uint8_t B);
// generic workhorse
void writeN(uint8_t channel, uint8_t* arr, uint8_t count);
// single PWM setting
uint8_t write1(uint8_t channel, uint8_t value);
// RGB setting, write three consecutive PWM registers
uint8_t write3(uint8_t channel, uint8_t R, uint8_t G, uint8_t B);
// generic worker, write N consecutive PWM registers
uint8_t writeN(uint8_t channel, uint8_t* arr, uint8_t count);
// reg = 1, 2 check datasheet for values
void writeMode(uint8_t reg, uint8_t value);
uint8_t readMode(uint8_t reg);
// reg = 1, 2 check datasheet for values
uint8_t writeMode(uint8_t reg, uint8_t value);
uint8_t readMode(uint8_t reg);
// TODO PWM also in %% ?
void setGroupPWM(uint8_t value) { writeReg(PCA9635_GRPPWM, value); }
uint8_t getGroupPWM() { return readReg(PCA9635_GRPPWM); }
// TODO PWM also in %% ?
void setGroupPWM(uint8_t value) { writeReg(PCA9635_GRPPWM, value); }
uint8_t getGroupPWM() { return readReg(PCA9635_GRPPWM); }
// TODO set time in millisec and round to nearest value?
void setGroupFREQ(uint8_t value) { writeReg(PCA9635_GRPFREQ, value); }
uint8_t getGroupFREQ() { return readReg(PCA9635_GRPFREQ); }
// TODO set time in millisec and round to nearest value?
void setGroupFREQ(uint8_t value) { writeReg(PCA9635_GRPFREQ, value); }
uint8_t getGroupFREQ() { return readReg(PCA9635_GRPFREQ); }
int lastError();
int lastError();
private:
// DIRECT CONTROL
void writeReg(uint8_t reg, uint8_t value);
uint8_t readReg(uint8_t reg);
// DIRECT CONTROL
void writeReg(uint8_t reg, uint8_t value);
uint8_t readReg(uint8_t reg);
uint8_t _address;
uint8_t _register;
uint8_t _data;
int _error;
uint8_t _address;
uint8_t _register;
uint8_t _data;
int _error;
};
#endif
//
// END OF FILE
//
// -- END OF FILE --

View File

@ -0,0 +1,76 @@
# PCA9635
Arduino library for PCA9635 I2C 8 bit PWM LED driver
# Description
This library is to control the I2C PCA9635 PWM extender.
The 16 channels are independently configurable is steps of 1/256.
this allows for better than 1% finetuning of the duty-cycle
of the PWM signal.
### interface
**begin()** initializes the library after startup. Mandatory.
**begin(sda, scl)** idem, ESP32 ESP8266 only. Library does not support
multiple Wire instances (yet).
**reset()** resets the library to start up conditions.
----
**setLedDriverMode(channel, mode)** mode is 0..3 See datasheet for full details.
| LED mode | Value | Description |
|:----|:----:|:----|
| PCA9635_LEDOFF | 0x00 | led is 100% off, default @startup
| PCA9635_LEDON | 0x01 | led is 100% on.
| PCA9635_LEDPWM | 0x02 | set LED in PWM mode, 0..255
| PCA9635_LEDGRPPWM | 0x03 | add LED to the GRPPWM*
\* all leds in the group GRPPWM can be set to the same PWM value in one set.
This is ideal to trigger e.g. multiple LEDS (servo's) at same time.
**getLedDriverMode(channel)** returns the current mode of the channel.
----
**write1(channel, value)** writes a single 8 bit PWM value.
**write3(channel, R, G, B)** writes three consecutive PWM registers.
**writeN(channel, array, count)** write count consecutive PWM registers.
May return **PCA9635_ERR_WRITE** if array has too many elements
(including channel as offset)
**writeMode(reg, mode)** configuration of one of the two configuration registers.
check datasheet for details.
**readMode(reg)** reads back the configured mode, useful to add or remove a
single flag (bit masking)
----
**setGroupPWM(uint8_t value)** sets all channels that are part of the PWM group to value.
**getGroupPWM()** get the current PWM setting of the group.
**setGroupFREQ(value)** see datasheet for details.
**getGroupFREQ()** returns the freq of the PWM group.
**lastError()** returns **PCA9635_OK** if all is OK, and other error codes otherwise.
| Error code | Value | Description |
|:----|:----:|:----|
| PCA9635_OK | 0x00 | Everything went well
| PCA9635_ERROR | 0xFF | Generic error
| PCA9635_ERR_WRITE | 0xFE | Tries to write more elements than PWM channels
| PCA9635_ERR_CHAN | 0xFD | Channel out of range
| PCA9635_ERR_MODE | 0xFC | Invalid mode
| PCA9635_ERR_REG | 0xFB | Invalid register
| PCA9635_ERR_I2C | 0xFA | PCA9635 I2C communication error
# Operation
See examples

View File

@ -2,7 +2,7 @@
// FILE: PCA9635_test01.ino
// AUTHOR: Rob Tillaart
// DATE: 23-APR-2016
// VERSION: 0.1.01
// VERSION: 0.2.0
// PUPROSE: test PCA9635 library
//
@ -13,192 +13,199 @@ PCA9635 ledArray(0x20);
void setup()
{
Serial.begin(115200);
Serial.print("PCA9635 LIB version: ");
Serial.println(PCA9635_LIB_VERSION);
Serial.println();
Serial.begin(115200);
Serial.print("PCA9635 LIB version: ");
Serial.println(PCA9635_LIB_VERSION);
Serial.println();
testSetLedDriverModeLEDON();
testPWMMode();
testWrite1();
testWrite3();
testWriteN();
testSetGroupPWM_FREQ();
testSetAndReadMode();
testSetLedDriverModeLEDOFF();
ledArray.begin();
Serial.print(millis());
Serial.print("\t");
Serial.println("done...");
testSetLedDriverModeLEDON();
testPWMMode();
testWrite1();
testWrite3();
testWriteN();
testSetGroupPWM_FREQ();
testSetAndReadMode();
testSetLedDriverModeLEDOFF();
Serial.print(millis());
Serial.print("\t");
Serial.println("done...");
}
void testSetLedDriverModeLEDON()
{
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - Switch all on");
for (int channel = 0; channel < 16; channel++)
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - Switch all on");
for (int channel = 0; channel < 16; channel++)
{
ledArray.setLedDriverMode(channel, PCA9635_LEDON);
if (ledArray.getLedDriverMode(channel) != PCA9635_LEDON)
{
ledArray.setLedDriverMode(channel, PCA9635_LEDON);
if (ledArray.getLedDriverMode(channel) != PCA9635_LEDON)
{
Serial.print(millis());
Serial.print("\t");
Serial.print("Channel: ");
Serial.println(channel);
}
Serial.print(millis());
Serial.print("\t");
Serial.print("Channel: ");
Serial.println(channel);
}
}
}
void testPWMMode()
{
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - set pwm mode");
for (int channel = 0; channel < 16; channel++)
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - set pwm mode");
for (int channel = 0; channel < 16; channel++)
{
ledArray.setLedDriverMode(channel, PCA9635_LEDON);
delay(200);
ledArray.setLedDriverMode(channel, PCA9635_LEDPWM);
if (ledArray.getLedDriverMode(channel) != PCA9635_LEDPWM)
{
ledArray.setLedDriverMode(channel, PCA9635_LEDON);
delay(200);
ledArray.setLedDriverMode(channel, PCA9635_LEDPWM);
if (ledArray.getLedDriverMode(channel) != PCA9635_LEDPWM)
{
Serial.print(millis());
Serial.print("\t");
Serial.print("Channel: ");
Serial.println(channel);
}
Serial.print(millis());
Serial.print("\t");
Serial.print("Channel: ");
Serial.println(channel);
}
}
}
void testWrite1()
{
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - write1 - I");
for (int channel = 0; channel < 16; channel++)
{
for (int pwm = 0; pwm < 256; pwm++)
{
ledArray.write1(channel, pwm);
}
}
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - write 1 - II");
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - write1 - I");
for (int channel = 0; channel < 16; channel++)
{
for (int pwm = 0; pwm < 256; pwm++)
{
for (int channel = 0; channel < 16; channel++)
{
ledArray.write1(channel, pwm);
}
ledArray.write1(channel, pwm);
}
}
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - write 1 - II");
for (int pwm = 0; pwm < 256; pwm++)
{
for (int channel = 0; channel < 16; channel++)
{
ledArray.write1(channel, pwm);
}
}
}
void testWrite3()
{
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - write3 - random RGB");
for (int channel = 0; channel < 13; channel++) // 13 = 16 -3 !!!
{
uint8_t R = random(256);
uint8_t G = random(256);
uint8_t B = random(256);
ledArray.write3(channel, R, G, B);
}
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - write3 - random RGB");
for (int channel = 0; channel < 13; channel++) // 13 = 16 -3 !!!
{
uint8_t R = random(256);
uint8_t G = random(256);
uint8_t B = random(256);
ledArray.write3(channel, R, G, B);
}
}
void testWriteN()
{
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - writeN ");
uint8_t arr[16] = {16,32,48,64,80,96,112,128,144,160,176,192,208,224,240,255};
ledArray.writeN(0, arr, 16);
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - writeN ");
uint8_t arr[16] = {16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255};
ledArray.writeN(0, arr, 16);
}
void testSetGroupPWM_FREQ()
{
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - GroupPWM");
for (int channel = 0; channel < 16; channel++)
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - GroupPWM");
for (int channel = 0; channel < 16; channel++)
{
ledArray.setLedDriverMode(channel, PCA9635_LEDGRPPWM);
}
for (int pwm = 0; pwm < 256; pwm++)
{
ledArray.setGroupPWM(pwm);
uint8_t p = ledArray.getGroupPWM();
if (p != pwm)
{
ledArray.setLedDriverMode(channel, PCA9635_LEDGRPPWM);
Serial.print(millis());
Serial.print("\t");
Serial.print("pwm: ");
Serial.println(pwm);
}
for (int pwm = 0; pwm < 256; pwm++)
{
ledArray.setGroupPWM(pwm);
uint8_t p = ledArray.getGroupPWM();
if (p != pwm)
{
Serial.print(millis());
Serial.print("\t");
Serial.print("pwm: ");
Serial.println(pwm);
}
}
ledArray.setGroupPWM(127);
}
ledArray.setGroupPWM(127);
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - groupFRQ");
for (int frq = 0; frq < 256; frq++)
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - groupFRQ");
for (int frq = 0; frq < 256; frq++)
{
ledArray.setGroupFREQ(frq);
uint8_t f = ledArray.getGroupFREQ();
if (f != frq)
{
ledArray.setGroupFREQ(frq);
uint8_t f = ledArray.getGroupFREQ();
if (f != frq)
{
Serial.print(millis());
Serial.print("\t");
Serial.print("frq: ");
Serial.println(frq);
}
}
for (int channel = 0; channel < 16; channel++)
{
ledArray.setLedDriverMode(channel, PCA9635_LEDPWM);
Serial.print(millis());
Serial.print("\t");
Serial.print("frq: ");
Serial.println(frq);
}
}
// reset to LEDPWM
for (int channel = 0; channel < 16; channel++)
{
ledArray.setLedDriverMode(channel, PCA9635_LEDPWM);
}
}
void testSetAndReadMode()
{
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - readMode");
uint8_t regval = ledArray.readMode(PCA9635_MODE1);
ledArray.writeMode(PCA9635_MODE1, regval); // non destructive;
Serial.print(millis());
Serial.print("\t");
Serial.print("PCA9635_MODE1: ");
Serial.println(regval);
regval = ledArray.readMode(PCA9635_MODE2);
ledArray.writeMode(PCA9635_MODE2, regval);
Serial.print(millis());
Serial.print("\t");
Serial.print("PCA9635_MODE2: ");
Serial.println(regval);
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - readMode");
uint8_t regval = ledArray.readMode(PCA9635_MODE1);
ledArray.writeMode(PCA9635_MODE1, regval); // non destructive;
Serial.print(millis());
Serial.print("\t");
Serial.print("PCA9635_MODE1: ");
Serial.println(regval);
regval = ledArray.readMode(PCA9635_MODE2);
ledArray.writeMode(PCA9635_MODE2, regval);
Serial.print(millis());
Serial.print("\t");
Serial.print("PCA9635_MODE2: ");
Serial.println(regval);
}
void testSetLedDriverModeLEDOFF()
{
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - Switch all off");
for (int channel = 0; channel < 16; channel++)
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - Switch all off");
for (int channel = 0; channel < 16; channel++)
{
ledArray.setLedDriverMode(channel, PCA9635_LEDOFF);
if (ledArray.getLedDriverMode(channel) != PCA9635_LEDOFF)
{
ledArray.setLedDriverMode(channel, PCA9635_LEDOFF);
if (ledArray.getLedDriverMode(channel) != PCA9635_LEDOFF)
{
Serial.print(millis());
Serial.print("\t");
Serial.print("Channel: ");
Serial.println(channel);
}
Serial.print(millis());
Serial.print("\t");
Serial.print("Channel: ");
Serial.println(channel);
}
}
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,56 @@
//
// FILE: PCA9635_test_multiple.ino
// AUTHOR: Rob Tillaart
// DATE: 2018-02-18
// VERSION: 0.2.0
// PUPROSE: test PCA9635 library
//
#include "PCA9635.h"
#include <Wire.h>
PCA9635 ledArray(0x20);
PCA9635 ledArray2(0x21);
void setup()
{
Serial.begin(115200);
Serial.print("PCA9635 LIB version: ");
Serial.println(PCA9635_LIB_VERSION);
Serial.println();
ledArray.begin();
ledArray2.begin();
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - write1 - I");
for (int channel = 0; channel < 16; channel++)
{
for (int pwm = 0; pwm < 256; pwm++)
{
ledArray.write1(channel, pwm);
ledArray2.write1(channel, pwm);
}
}
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - write 1 - II");
for (int pwm = 0; pwm < 256; pwm++)
{
for (int channel = 0; channel < 16; channel++)
{
ledArray.write1(channel, pwm);
ledArray2.write1(channel, pwm);
}
}
Serial.println("done...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -1,7 +1,7 @@
{
"name": "PCA9635",
"keywords": "I2C,PCA9635,PWM",
"description": "Library for PCA9635 PWM.",
"description": "Arduino library for PCA9635 I2C LED driver",
"authors":
[
{
@ -13,12 +13,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/PCA9635.git"
},
"version":"0.1.2",
"version":"0.2.0",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/PCA9635"
}
"platforms": "*"
}

View File

@ -1,9 +1,11 @@
name=PCA9635
version=0.1.2
version=0.2.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library for PCA9635 PWM.
paragraph=
sentence=Arduino library for PCA9635 I2C LED driver
paragraph=PWM, 8 bit
category=Signal Input/Output
url=https://github.com/RobTillaart/Arduino/tree/master/libraries/
architectures=*
url=https://github.com/RobTillaart/PCA9635
architectures=*
includes=PCA9635.h
depends=

21
libraries/PCA9685/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -2,20 +2,24 @@
// FILE: PCA9685.cpp
// AUTHOR: Rob Tillaart
// DATE: 24-apr-2016
// VERSION: 0.1.1
// PURPOSE: I2C PCA9685 library for Arduino
// URL:
// VERSION: 0.3.0
// PURPOSE: Arduino library for I2C PCA9685 16 channel PWM
// URL: https://github.com/RobTillaart/PCA9685_RT
//
// HISTORY:
// 0.1.0 2016-04-24 initial BETA version
// 0.1.1 2019-01-30 testing && fixing
//
// 0.2.0 2020-05-25 refactor; ESP32 begin(sda,scl)
// 0.2.1 2020-06-19 fix library.json
// 0.2.2 2020-09-21 fix #1 + add getFrequency()
// 0.2.3 2020-11-21 fix digitalWrite (internal version only)
// 0.3.0 2020-11-22 fix setting frequency
#include <Wire.h>
#include "PCA9685.h"
// check datasheet for details
// REGISTERS CONFIGURATION - check datasheet for details
#define PCA9685_MODE1 0x00
#define PCA9685_MODE2 0x01
@ -35,18 +39,30 @@
#define PCA9685_OUTDRV 0x04
#define PCA9685_OUTNE 0x03
// SPECIAL REGISTER - FREQUENCY
#define PCA9685_PRE_SCALE 0xFE
// REGISTERS - CHANNELS
#define PCA9685_CHANNEL_0 0x06 // 0x06 + 4*channel is base per channel
// REGISTERS - FREQUENCY
#define PCA9685_PRE_SCALER 0xFE
// NOT IMPLEMENTED YET
// REGISTERS - Subaddressing I2C - not implemented
#define PCA9685_SUBADR(x) (0x01+(x)) // x = 1..3
#define PCA9685_ALLCALLADR 0x05
#define PCA9685_TESTMODE 0xFF
// REGISTERS - ALL_ON ALL_OFF - partly implemented
#define PCA9685_ALL_ON_L 0xFA
#define PCA9685_ALL_ON_H 0xFB
#define PCA9685_ALL_OFF_L 0xFC
#define PCA9685_ALL_OFF_H 0xFD // used for allOFF()
// NOT IMPLEMENTED YET
#define PCA9685_TESTMODE 0xFF // do not be use. see datasheet.
//////////////////////////////////////////////////////////////
//
// Constructor
//
PCA9685::PCA9685(const uint8_t deviceAddress)
{
_address = deviceAddress;
@ -54,20 +70,31 @@ PCA9685::PCA9685(const uint8_t deviceAddress)
}
#if defined (ESP8266) || defined(ESP32)
void PCA9685::begin(uint8_t sda, uint8_t scl)
{
Wire.begin(sda, scl);
reset();
}
#endif
void PCA9685::begin()
{
Wire.begin();
reset();
}
void PCA9685::reset()
{
_error = 0;
uint8_t mode1 = PCA9685_AUTOINCR | PCA9685_ALLCALL;
writeReg(PCA9685_MODE1, mode1);
uint8_t mode2 = PCA9685_OUTDRV;
writeReg(PCA9685_MODE2, mode2);
writeMode(PCA9685_MODE1, PCA9685_AUTOINCR | PCA9685_ALLCALL);
writeMode(PCA9685_MODE2, PCA9685_OUTDRV);
}
void PCA9685::writeMode(uint8_t reg, uint8_t value)
{
if (reg != PCA9685_MODE1 && reg != PCA9685_MODE2)
if ((reg != PCA9685_MODE1) && (reg != PCA9685_MODE2))
{
_error = PCA9685_ERR_MODE;
return;
@ -78,7 +105,7 @@ void PCA9685::writeMode(uint8_t reg, uint8_t value)
uint8_t PCA9685::readMode(uint8_t reg)
{
if (reg != PCA9685_MODE1 && reg != PCA9685_MODE2)
if ((reg != PCA9685_MODE1) && (reg != PCA9685_MODE2))
{
_error = PCA9685_ERR_MODE;
return 0;
@ -87,6 +114,7 @@ uint8_t PCA9685::readMode(uint8_t reg)
return value;
}
// write value to single PWM channel
void PCA9685::setPWM(uint8_t channel, uint16_t onTime, uint16_t offTime)
{
@ -95,16 +123,19 @@ void PCA9685::setPWM(uint8_t channel, uint16_t onTime, uint16_t offTime)
_error = PCA9685_ERR_CHANNEL;
return;
}
uint8_t reg = 0x06 + (channel << 2);
offTime &= 0x0FFFF; // non-doc feature - to easy set figure 8 P.17
uint8_t reg = PCA9685_CHANNEL_0 + (channel << 2);
writeReg2(reg, onTime, offTime);
}
// write value to single PWM channel
void PCA9685::setPWM(uint8_t channel, uint16_t offTime)
{
setPWM(channel, 0, offTime);
}
// read value from single PWM channel
void PCA9685::getPWM(uint8_t channel, uint16_t* onTime, uint16_t* offTime)
{
@ -113,13 +144,13 @@ void PCA9685::getPWM(uint8_t channel, uint16_t* onTime, uint16_t* offTime)
_error = PCA9685_ERR_CHANNEL;
return;
}
uint8_t reg = 0x06 + (channel << 2);
uint8_t reg = PCA9685_CHANNEL_0 + (channel << 2);
Wire.beginTransmission(_address);
Wire.write(reg);
_error = Wire.endTransmission();
if (Wire.requestFrom(_address, (uint8_t)4) != 4)
{
_error = PCA9685_ERROR;
_error = PCA9685_ERR_I2C;
return;
}
uint16_t _data = Wire.read();
@ -128,25 +159,54 @@ void PCA9685::getPWM(uint8_t channel, uint16_t* onTime, uint16_t* offTime)
*offTime = (Wire.read() * 256) + _data;
}
// set update frequency for all channels
void PCA9685::setFrequency(uint16_t freq)
void PCA9685::setFrequency(uint16_t freq, int offset)
{
if (freq < 24) freq = 24;
if (freq > 1526) freq = 1526;
_freq = freq;
if (_freq < 24) _freq = 24; // page 25 datasheet
if (_freq > 1526) _freq = 1526;
// removed float operation for speed
// uint8_t scaler = round(25e6 / (4096 * freq)) - 1;
uint8_t scaler = 6104 / freq - 1;
writeReg(PCA9685_PRE_SCALE, scaler);
// faster but equal accurate
// uint8_t scaler = round(25e6 / (_freq * 4096)) - 1;
uint8_t scaler = 48828 / (_freq * 8) - 1;
uint8_t mode1 = readMode(PCA9685_MODE1);
writeMode(PCA9685_MODE1, mode1 | PCA9685_SLEEP);
scaler += offset;
writeReg(PCA9685_PRE_SCALER, scaler);
writeMode(PCA9685_MODE1, mode1);
}
void PCA9685::setON(uint8_t channel)
int PCA9685::getFrequency(bool cache)
{
setPWM(channel, 0x1000, 0x0000);
if (cache) return _freq;
uint8_t scaler = readReg(PCA9685_PRE_SCALER);
scaler++;
_freq = 48828 / scaler;
_freq /= 8;
return _freq;
}
void PCA9685::setOFF(uint8_t channel)
// datasheet P.18 - fig. 9:
// Note: bit[11-0] ON should NOT equal timer OFF in ON mode
// in OFF mode it doesn't matter.
void PCA9685::digitalWrite(uint8_t channel, uint8_t mode)
{
setPWM(channel, 0x0000, 0x1000);
if (channel > 15)
{
_error = PCA9685_ERR_CHANNEL;
return;
}
uint8_t reg = PCA9685_CHANNEL_0 + (channel << 2);
if (mode != LOW) writeReg2(reg, 0x1000, 0x0000);
else writeReg2(reg, 0x0000, 0x0000);
}
void PCA9685::allOFF()
{
writeReg(PCA9685_ALL_OFF_H, 0x10);
}
int PCA9685::lastError()
@ -156,6 +216,10 @@ int PCA9685::lastError()
return e;
}
//////////////////////////////////////////////////////////////
//
// PRIVATE
//
void PCA9685::writeReg(uint8_t reg, uint8_t value)
{
Wire.beginTransmission(_address);
@ -164,18 +228,19 @@ void PCA9685::writeReg(uint8_t reg, uint8_t value)
_error = Wire.endTransmission();
}
void PCA9685::writeReg2(uint8_t reg, uint16_t a, uint16_t b)
{
Wire.beginTransmission(_address);
Wire.write(reg);
Wire.write(a & 0xFF);
Wire.write((a >> 8) & 0x0F);
Wire.write((a >> 8) & 0x1F);
Wire.write(b & 0xFF);
Wire.write((b >> 8) & 0x0F);
Wire.write((b >> 8) & 0x1F);
_error = Wire.endTransmission();
}
//
uint8_t PCA9685::readReg(uint8_t reg)
{
Wire.beginTransmission(_address);
@ -183,13 +248,11 @@ uint8_t PCA9685::readReg(uint8_t reg)
_error = Wire.endTransmission();
if (Wire.requestFrom(_address, (uint8_t)1) != 1)
{
_error = PCA9685_ERROR;
_error = PCA9685_ERR_I2C;
return 0;
}
uint8_t _data = Wire.read();
return _data;
}
//
// END OF FILE
//
// -- END OF FILE --

View File

@ -1,27 +1,27 @@
#pragma once
//
// FILE: PCA9685.H
// AUTHOR: Rob Tillaart
// DATE: 24-apr-2016
// VERSION: 0.1.1
// PURPOSE: I2C PCA9685 library for Arduino
// URL: https://github.com/RobTillaart/Arduino/tree/master/libraries
// VERSION: 0.3.0
// PURPOSE: Arduino library for I2C PCA9685 16 channel PWM
// URL: https://github.com/RobTillaart/PCA9685_RT
//
// HISTORY:
// see PCA9685.cpp file
//
#ifndef _PCA9685_H
#define _PCA9685_H
#include "Arduino.h"
#include "Wire.h"
#define PCA9685_LIB_VERSION "0.1.1"
#define PCA9685_LIB_VERSION "0.3.0"
// ERROR CODES
#define PCA9685_OK 0x00
#define PCA9685_ERROR 0xFF
#define PCA9685_ERR_CHANNEL 0xFE
#define PCA9685_ERR_MODE 0xFD
#define PCA9685_ERR_I2C 0xFC
class PCA9685
@ -29,41 +29,54 @@ class PCA9685
public:
explicit PCA9685(const uint8_t deviceAddress);
void begin();
#if defined (ESP8266) || defined(ESP32)
void begin(uint8_t sda, uint8_t scl);
#endif
void begin();
void reset();
// reg = 1, 2 check datasheet for values
void writeMode(uint8_t reg, uint8_t value);
void writeMode(uint8_t reg, uint8_t value);
uint8_t readMode(uint8_t reg);
// single PWM setting, channel = 0..15,
// onTime = 0..4095, offTime = 0..4095
// allows shifted PWM's e.g. 2 servo's that do not start at same time.
void setPWM(uint8_t channel, uint16_t onTime, uint16_t offTime);
void getPWM(uint8_t channel, uint16_t* onTime, uint16_t* offTime);
void setPWM(uint8_t channel, uint16_t onTime, uint16_t offTime);
void getPWM(uint8_t channel, uint16_t* onTime, uint16_t* offTime);
// single PWM setting, channel = 0..15, offTime = 0..4095
void setPWM(uint8_t channel, uint16_t offTime);
// single PWM setting, channel = 0..15, offTime = 0..4095 (onTime = 0)
void setPWM(uint8_t channel, uint16_t offTime);
// set update frequency for all channels
// freq = 24-1526 Hz
void setFrequency(uint16_t freq);
// freq = 24 - 1526 Hz
// note: as the frequency is converted to an 8 bit prescaler
// the frequency set will seldom be exact, but best effort.
void setFrequency(uint16_t freq, int offset = 0);
int getFrequency(bool cache = true);
void setON(uint8_t channel);
void setOFF(uint8_t channel);
// set channel HIGH or LOW (effectively no PWM)
void digitalWrite(uint8_t channel, uint8_t mode);
int lastError();
// for backwards compatibility; will be removed in future
void setON(uint8_t channel) { digitalWrite(channel, HIGH); };
void setOFF(uint8_t channel) { digitalWrite(channel, LOW); };
// experimental for 0.3.0
void allOFF();
int lastError();
private:
// DIRECT CONTROL
void writeReg(uint8_t reg, uint8_t value);
void writeReg2(uint8_t reg, uint16_t a, uint16_t b);
void writeReg(uint8_t reg, uint8_t value);
void writeReg2(uint8_t reg, uint16_t a, uint16_t b);
uint8_t readReg(uint8_t reg);
uint8_t _address;
int _error;
int _freq = 200; // default PWM frequency - P25 datasheet
};
#endif
//
// END OF FILE
//
// -- END OF FILE --

View File

@ -0,0 +1,89 @@
# PCA9685_RT
Arduino library for I2C PCA9685 16 channel PWM extender
# Description
This library is to control the I2C PCA9685 PWM extender.
The 16 channels are independently configurable in steps of 1/4096.
This allows for better than 0.1% finetuning of the duty-cycle
of the PWM signal.
The PWM's of the different channels have individual start and stop moments.
This can be used to distribute the power more evenly over multiple servo's
or give special effects when used in an RGB LED.
The frequency of the PWM can be set from 24 to 1526 according to the datasheet, however in practice not all frequencies are set accurate.
Lower frequencies do better than higher frequencies.
### interface
**begin()** initializes the library after startup. Mandatory.
**begin(sda, scl)** idem, ESP32 ESP8266 only. Library does not support
multiple Wire instances (yet).
**reset()** resets the library to start up conditions.
**writeMode(reg, mode)** configuration of one of the two configuration registers.
check datasheet for details.
**readMode(reg)** reads back the configured mode, useful to add or remove a
single flag (bit masking)
**setPWM(channel, ontime, offtime)** The chip has 16 channels to do PWM.
The signal is divided in 4096 steps, 0..4095.
The pulse can begin =**ontime** on any step and it can stop on any step =**offtime**.
This allows e.g. to distribute the power over the 16 channels, e.g. the
channels do not need to start at the same moment with HIGH.
**setPWM(channel, offtime)** simple PWM that always start on **ontime = 0**
**getPWM(channel, ontime, offtime)** read back the configuration of the channel.
**setFrequency(freq, int offset = 0)** set the update speed of the channels.
This value is set the same for all channels at once.
The frequency is constrained to be between 24 and 1526 Hz.
As the frequency is converted to an 8 bit **prescaler**,
the frequency set will seldom be exact.
After changing the frequency, one must set all channels (again),
so one should set the frequency in **setup()**
The parameter offset can be used to tune the **prescaler** to get a frequency
closer to the requested value. See **PCA9685_setFrequency_offset** example.
Default the offset = 0. As the prescaler is smaller at higher frequencies
higher frequencies are less accurate.
Making offset too large can result in very incorrect frequencies.
When using offset, the **getFrequency(false)** will return the adjusted prescaler.
**getFrequency(cache = true)** get the current update frequency of the channels.
This is same for all channels. If cache is false, the frequency is fetched and
calculated from the **prescaler** register and will probably differ from the
value set with **setFrequency()**.
**digitalWrite(channel, mode)** mode = HIGH or LOW, just use the PCA9685 as
a digitalpin.
This single function replaces the setON() and setOFF() that will become
obsolete in the future.
**allOFF()** switches all PWM channels OFF. **Experimental** in 0.3.0
To "undo" the allOFF one can call the **reset()** function and set all
PWM channels again.
**lastError()** returns **PCA9685_OK = 0** if all is OK, and
| Error code | Value | Description |
|:----|:----:|:----|
| PCA9685_OK | 0x00 | Everything went well
| PCA9685_ERROR | 0xFF | generic error
| PCA9685_ERR_CHANNEL | 0xFE | Channel out of range
| PCA9685_ERR_MODE | 0xFD | Invalid mode register chosen |
| PCA9685_ERR_I2C | 0xFC | PCA9685 I2C communication error
# Operation
See examples

View File

@ -0,0 +1,53 @@
//
// FILE: PCA9685_allOFF_test.ino
// AUTHOR: Rob Tillaart
// DATE: 2020-11-22
// VERSION: 0.1.0
// PUPROSE: test PCA9685 library
//
/*
sets all channels to a PWM
then switches them all off
you can check it by testing all channels.
*/
#include "PCA9685.h"
PCA9685 PCA(0x40);
const uint8_t PIN = 2;
void setup()
{
Wire.begin();
PCA.begin();
Serial.begin(115200);
Serial.print("PCA9685 LIB version: ");
Serial.println(PCA9685_LIB_VERSION);
Serial.println();
pinMode(PIN, INPUT_PULLUP);
for (int channel = 0; channel < 16; channel++)
{
PCA.setPWM(channel, 0, 1000);
}
delay(100); // to be sure they started.
PCA.allOFF();
// delay(100);
// PCA.reset(); // needed to reset the allOFF()
// for (int channel = 0; channel < 16; channel++)
// {
// PCA.digitalWrite(channel, HIGH);
// }
}
void loop()
{
Serial.println(digitalRead(PIN)); // you can measure all pins
}
// -- END OF FILE --

View File

@ -0,0 +1,66 @@
//
// FILE: PCA9685_digitalWrite_test.ino
// AUTHOR: Rob Tillaart
// DATE: 2020-11-21
// VERSION: 0.1.0
// PUPROSE: test PCA9685 library
//
/*
sets one channel to max PWM 0..4095
and connect the output to an interrupt pin 2
to see the frequency of the PWM
*/
#include "PCA9685.h"
PCA9685 PCA(0x40);
const uint8_t IRQ_PIN = 2;
volatile uint16_t count = 0;
uint32_t lastTime = 0;
void setup()
{
Wire.begin();
PCA.begin();
Serial.begin(115200);
Serial.print("PCA9685 LIB version: ");
Serial.println(PCA9685_LIB_VERSION);
Serial.println();
pinMode(IRQ_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(IRQ_PIN), irq, CHANGE);
// PCA.setPWM(15, 0, 1000); // works OK - reference to test irq()
// PCA.digitalWrite(15, LOW); // works OK
PCA.digitalWrite(15, HIGH); // works OK
}
// INTERRUPT ROUTINE TO COUNT THE PULSES
void irq()
{
count++;
}
void loop()
{
uint32_t now = millis();
if (now - lastTime >= 1000)
{
lastTime = now;
// make a copy
noInterrupts();
uint16_t t = count;
count = 0;
interrupts();
Serial.print(t);
Serial.print("\t");
Serial.println(digitalRead(IRQ_PIN));
}
}
// -- END OF FILE --

View File

@ -0,0 +1,70 @@
//
// FILE: PCA9685_maxPWM_test.ino
// AUTHOR: Rob Tillaart
// DATE: 2020-11-22
// VERSION: 0.1.0
// PUPROSE: test PCA9685 library
//
/*
sets one channel to max PWM 0..4095
and connect the output to an interrupt pin 2
to see the frequency of the PWM
*/
#include "PCA9685.h"
PCA9685 PCA(0x40);
const uint8_t IRQ_PIN = 2;
volatile uint16_t count = 0;
uint32_t lastTime = 0;
void setup()
{
Wire.begin();
PCA.begin();
Serial.begin(115200);
Serial.print("PCA9685 LIB version: ");
Serial.println(PCA9685_LIB_VERSION);
Serial.println();
pinMode(IRQ_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(IRQ_PIN), irq, RISING); // CHANGE
Serial.println(PCA.getFrequency());
PCA.setFrequency(200);
Serial.println(PCA.lastError());
Serial.println(PCA.getFrequency(false)); // do not fetch from cache.
PCA.setPWM(15, 0, 4095); // gives 2 changes per interval
}
// INTERRUPT ROUTINE TO COUNT THE PULSES
void irq()
{
count++;
}
void loop()
{
uint32_t now = millis();
if (now - lastTime >= 1000)
{
lastTime += 1000;
// make a working copy of count
noInterrupts();
uint16_t t = count;
count = 0;
interrupts();
Serial.print(t);
Serial.print("\t");
Serial.println(digitalRead(IRQ_PIN));
}
}
// -- END OF FILE --

View File

@ -0,0 +1,101 @@
//
// FILE: PCA9685_setFrequency_offset.ino
// AUTHOR: Rob Tillaart
// DATE: 2020-11-22
// VERSION: 0.1.0
// PUPROSE: test PCA9685 library
//
/*
This sketch is to determine the offset needed to get te best matching
value for offset to match the wanted frequency.
connect PWM line 15 to IRQ line 2 to monitor the real frequency
set the frequency to the value you want.
use the + and - keys to adjust the frequency to get the wanted frequency.
Note: the higher the frequency, the more inaccurate the real frequency,
*/
#include "PCA9685.h"
PCA9685 PCA(0x40);
const uint8_t IRQ_PIN = 2;
volatile uint16_t count = 0;
uint32_t lastTime = 0;
uint16_t freq = 200; // adjust to freq needed (between 24..1526 )
int offset = 0;
int lines = 0;
void setup()
{
Wire.begin();
PCA.begin();
Serial.begin(115200);
Serial.print("PCA9685 LIB version: ");
Serial.println(PCA9685_LIB_VERSION);
Serial.println();
pinMode(IRQ_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(IRQ_PIN), irq, RISING);
PCA.setFrequency(freq, offset);
PCA.setPWM(15, 0, 4095); // gives 2 changes per interval
Serial.println("\nSET\tIRQ\tIRQ%\tOFFSET");
}
// INTERRUPT ROUTINE TO COUNT THE PULSES
void irq()
{
count++;
}
void loop()
{
uint32_t now = millis();
if (now - lastTime >= 1000)
{
lastTime += 1000;
// make a working copy of count
noInterrupts();
uint16_t t = count;
count = 0;
interrupts();
Serial.print(freq);
Serial.print("\t");
Serial.print(t);
Serial.print("\t");
Serial.print(100.0 * t / freq, 1);
Serial.print("\t");
Serial.print(offset);
Serial.print("\n");
lines++;
if (lines == 20)
{
Serial.println("\nSET\tIRQ\tIRQ%\tOFFSET");
lines = 0;
}
}
if (Serial.available())
{
char c = Serial.read();
if (c == '+') offset++;
if (c == '-') offset--;
PCA.setFrequency(freq, offset);
PCA.setPWM(15, 0, 4095);
}
}
// -- END OF FILE --

View File

@ -0,0 +1,92 @@
//
// FILE: PCA9685_setFrequency_test.ino
// AUTHOR: Rob Tillaart
// DATE: 2020-11-22
// VERSION: 0.1.0
// PUPROSE: test PCA9685 library
//
/*
sets one channel to max PWM 0..4095
and connect the output to an interrupt pin 2
to see the frequency of the PWM
*/
#include "PCA9685.h"
PCA9685 PCA(0x40);
const uint8_t IRQ_PIN = 2;
volatile uint16_t count = 0;
uint32_t lastTime = 0;
uint16_t freq = 24;
uint8_t lines = 0;
void setup()
{
Wire.begin();
PCA.begin();
Serial.begin(115200);
Serial.print("PCA9685 LIB version: ");
Serial.println(PCA9685_LIB_VERSION);
Serial.println();
pinMode(IRQ_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(IRQ_PIN), irq, RISING); // CHANGE
PCA.setFrequency(24);
PCA.setPWM(15, 0, 4095); // gives 2 changes per interval
Serial.println("\nSET\tGET\tGET%\tIRQ\tIRQ%");
}
// INTERRUPT ROUTINE TO COUNT THE PULSES
void irq()
{
count++;
}
void loop()
{
uint32_t now = millis();
if (now - lastTime >= 1000)
{
lastTime += 1000;
// make a working copy of count
noInterrupts();
uint16_t t = count;
count = 0;
interrupts();
Serial.print(freq);
Serial.print("\t");
Serial.print(PCA.getFrequency(false));
Serial.print("\t");
Serial.print(100.0 * PCA.getFrequency(false) / freq, 1);
Serial.print("\t");
Serial.print(t);
Serial.print("\t");
Serial.print(100.0 * t / freq, 1);
Serial.print("\n");
freq += 4;
if (freq >= 1526) freq = 24;
PCA.setFrequency(freq);
PCA.setPWM(15, 0, 4095);
lines++;
if (lines == 20)
{
Serial.println("\nSET\tGET\tGET%\tIRQ\tIRQ%");
lines = 0;
}
}
}
// -- END OF FILE --

View File

@ -2,7 +2,7 @@
// FILE: PCA9685_test01.ino
// AUTHOR: Rob Tillaart
// DATE: 24-APR-2016
// VERSION: 0.1.00
// VERSION: 0.1.1
// PUPROSE: test PCA9685 library
//
@ -13,65 +13,67 @@ PCA9685 ledArray(0x20);
void setup()
{
Wire.begin();
ledArray.begin();
Wire.begin();
ledArray.begin();
Serial.begin(115200);
Serial.print("PCA9685 LIB version: ");
Serial.println(PCA9685_LIB_VERSION);
Serial.println();
Serial.begin(115200);
Serial.print("PCA9685 LIB version: ");
Serial.println(PCA9685_LIB_VERSION);
Serial.println();
testSetON();
testPWMMode();
delay(2000);
testSetOFF();
testSetON();
testPWMMode();
delay(2000);
testSetOFF();
Serial.print(millis());
Serial.print("\t");
Serial.println("done...");
Serial.print(millis());
Serial.print("\t");
Serial.println("done...");
}
void testSetON()
{
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - setON");
for (int channel = 0; channel < 16; channel++)
{
ledArray.setON(channel);
}
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - setHIGH");
for (uint8_t channel = 0; channel < 16; channel++)
{
ledArray.digitalWrite(channel, HIGH);
}
}
void testSetOFF()
{
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - setOFF");
for (int channel = 0; channel < 16; channel++)
{
ledArray.setOFF(channel);
}
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - setLOW");
for (uint8_t channel = 0; channel < 16; channel++)
{
ledArray.digitalWrite(channel, LOW);
}
}
void testPWMMode()
{
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - setPwm getPWM");
for (int channel = 0; channel < 16; channel++)
Serial.print(millis());
Serial.print("\t");
Serial.println("Test - setPwm getPWM");
for (uint16_t channel = 0; channel < 16; channel++)
{
// every next line ~twice as much time
ledArray.setPWM(channel, channel * 127, channel * 255);
uint16_t a, b;
ledArray.getPWM(channel, &a, &b);
if ((a != channel * 127) || (b != channel * 255))
{
// every next line ~twice as much time
ledArray.setPWM(channel, channel*127, channel*255);
uint16_t a, b;
ledArray.getPWM(channel, &a, &b);
if (a != channel*127 || b != channel*255)
{
Serial.println(channel);
}
Serial.println(channel);
}
}
}
void loop()
{
}
// -- END OF FILE --

View File

@ -2,12 +2,11 @@
// FILE: PCA9685_test02.ino
// AUTHOR: Rob Tillaart
// DATE: 24-APR-2016
// VERSION: 0.1.0
// VERSION: 0.1.2
// PUPROSE: test PCA9685 library
//
#include "PCA9685.h"
#include <Wire.h>
PCA9685 ledArray(0x40);
@ -22,12 +21,12 @@ void setup()
Serial.println(PCA9685_LIB_VERSION);
Serial.println();
testSetON();
testDigitalWrite(HIGH);
testPWM(0);
testPWMMode();
testFrequency();
delay(2000);
testSetOFF();
testDigitalWrite(LOW);
Serial.print(millis());
Serial.print("\t");
@ -35,26 +34,14 @@ void setup()
}
void testSetON()
void testDigitalWrite(uint8_t mode)
{
Serial.print(millis());
Serial.print("\t");
Serial.println(__FUNCTION__);
for (int channel = 0; channel < 16; channel++)
{
ledArray.setON(channel);
delay(100);
}
}
void testSetOFF()
{
Serial.print(millis());
Serial.print("\t");
Serial.println(__FUNCTION__);
for (int channel = 0; channel < 16; channel++)
{
ledArray.setOFF(channel);
ledArray.digitalWrite(channel, mode);
delay(100);
}
}
@ -105,13 +92,24 @@ void testFrequency()
Serial.println(__FUNCTION__);
ledArray.setPWM(0, 1000, 3000);
for (uint16_t freq = 24; freq < 2000; freq *= 2)
for (uint16_t freq = 12; freq < 2000; freq *= 2)
{
Serial.println(freq);
Serial.print(freq);
ledArray.setFrequency(freq);
// if freq is out of range => report
if (ledArray.getFrequency() != freq)
{
Serial.print("\tconstrained to : ");
Serial.println(ledArray.getFrequency());
}
else
{
Serial.println("\tOK");
}
delay(2000);
}
ledArray.setOFF(0);
Serial.println();
}
@ -119,3 +117,5 @@ void loop()
{
//testPWM(0);
}
// -- END OF FILE --

View File

@ -1,7 +1,7 @@
{
"name": "PCA9685",
"keywords": "I2C,PCA9685,PWM",
"description": "Library for PCA9685.",
"keywords": "I2C,PCA9685,PWM,16channel",
"description": "Arduino library for I2C PCA9685 16 channel PWM",
"authors":
[
{
@ -13,12 +13,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/PCA9685_RT.git"
},
"version":"0.1.1",
"version": "0.3.0",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/PCA9685"
}
"platforms": "*"
}

View File

@ -1,9 +1,11 @@
name=PCA9685
version=0.1.1
name=PCA9685_RT
version=0.3.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library for PCA9685 PWM
sentence=Arduino library for I2C PCA9685 16 channel PWM
paragraph=
category=Signal Input/Output
url=https://github.com/RobTillaart/Arduino/tree/master/libraries/
architectures=*
url=https://github.com/RobTillaart/PCA9685_RT
architectures=*
includes=PCA9685.h
depends=Wire

View File

@ -2,12 +2,13 @@
// FILE: PCF8574.cpp
// AUTHOR: Rob Tillaart
// DATE: 02-febr-2013
// VERSION: 0.2.0
// VERSION: 0.2.1
// PURPOSE: Arduino library for PCF8574 - I2C IO expander
// URL: https://github.com/RobTillaart/PCF8574
// http://forum.arduino.cc/index.php?topic=184800
//
// HISTORY:
// 0.2.1 2020-06-19 fix library.json
// 0.2.0 2020-05-22 #pragma once; refactor;
// removed pre 1.0 support
// added begin(dsa, scl) for ESP32

View File

@ -3,7 +3,7 @@
// FILE: PCF8574.H
// AUTHOR: Rob Tillaart
// DATE: 02-febr-2013
// VERSION: 0.2.0
// VERSION: 0.2.1
// PURPOSE: Arduino library for PCF8574 - I2C IO expander
// URL: https://github.com/RobTillaart/PCF8574
// http://forum.arduino.cc/index.php?topic=184800
@ -14,7 +14,7 @@
#include "Arduino.h"
#define PCF8574_LIB_VERSION "0.2.0"
#define PCF8574_LIB_VERSION "0.2.1"
#define PCF8574_OK 0x00
#define PCF8574_PIN_ERROR 0x81

View File

@ -15,10 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/PCF8574.git"
},
"version":"0.2.0",
"version":"0.2.1",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "*"
}
"platforms": "*"
}

View File

@ -1,5 +1,5 @@
name=PCF8574
version=0.1.9
version=0.2.1
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for PCF8574 - I2C IO expander

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2010-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,44 +1,70 @@
/*
Par27979.h - library for Arduino & Parallax 27979 serial display
Copyright (c) 2010. All right reserved.
#pragma once
//
// FILE: PAR27979.h
// AUTHOR: Rob Tillaart
// VERSION: 0.2.0
// PURPOSE: Arduino library for Parallax 27979 _serial LCD display
// URL: https://github.com/RobTillaart/PAR27979
//
// HISTORY:
// 0.1.0 2010-03-06 - initial version Macro's only
// 0.2.0 2020-06-23 complete redo as class
// also support for 27976, 27977 (not tested)
This library is free software; you can redistribute it and/or
modify it as long as you leave this copyright notice intact
#define PAR27929_VERSION 0.2.0
This library 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.
*/
#include "Arduino.h"
#ifndef Par27979_h
#define Par27979_h
#define PAR27929_VERSION 0.1.00
#define DISPLAYOFF Serial.print((char)21)
#define DISPLAYON Serial.print((char)22)
#define DISPLAYCLR Serial.print((char)12); delay(10)
#define BACKLIGHTOFF Serial.print((char)18)
#define BACKLIGHTON Serial.print((char)17)
#define GOTOXY(x,y) Serial.print((char)(128 + y*20 + x))
#define LEFT Serial.print((char)8)
#define RIGHT Serial.print((char)9)
#define LINEFEED Serial.print((char)10)
#define FORMFEED Serial.print((char)12)
#define RETURN Serial.print((char)13)
#endif
/*
void setup()
class PAR27979 : public Print
{
Serial.begin(9600);
DISPLAYON;
GOTOXY(2,3);
Serial.print("hello");
}
public:
PAR27979(Stream * str) { _ser = str; };
void loop()
{
}
*/
void on() { _ser->write(22); };
void off() { _ser->write(21); };
void clearHome() { _ser->write(12); delay(5); };
void backlightOn() { _ser->write(17); };
void backlightOff() { _ser->write(18); };
// MOVEMENT
void left() { _ser->write(8); };
void right() { _ser->write(9); };
void down() { _ser->write(10); };
void gotoXY(uint8_t x, uint8_t y) { _ser->write(128 + y*20 + x); };
// CUSTOM CHARS
// array will need to be 8 bytes. - see datasheet.
void defineCustomChar(uint8_t idx, uint8_t * arr)
{
_ser->write(248 + idx);
for (int i = 0; i < 8; i++) _ser->write(arr[i]);
}
void customChar(uint8_t idx) { _ser->write(idx); };
// PLAY MUSIC
// octave = 3, 4, 5, 6, 7
void octave(uint8_t octave) { _ser->write(212 + octave); };
// duration is in 1/64 = 1, 2, 4, 8, 16, 32, 64
void duration(uint8_t duration)
{
uint8_t ch = 207;
while(duration) { duration /= 2; ch++; };
_ser->write(ch);
}
// A = 0, A# = 1 etc, see datasheet
void play(uint8_t note) { _ser->write(220 + note); };
void noSound() { _ser->write(232); };
// PRINT interface
size_t write(const uint8_t data) { return _ser->write(data); };
private:
Stream *_ser;
};
// -- END OF FILE --

View File

@ -0,0 +1,78 @@
//
// FILE: par27979_demo.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
// DATE: 2020-06-23
// (c) : MIT
//
#include <SoftwareSerial.h>
SoftwareSerial sws(3, 3);
#include "PAR27979.h"
PAR27979 display(&sws);
void setup()
{
sws.begin(19200); // max speed parallax display
display.clearHome();
// ON OFF TEST
display.on();
delay(1000);
display.off();
delay(1000);
display.on();
// BACKLIGHT TEST
display.backlightOn();
delay(1000);
display.backlightOff();
delay(1000);
display.backlightOn();
// PRINT
display.gotoXY(0, 0);
display.print(10);
delay(100);
display.println();
display.print(-10);
delay(100);
display.println();
display.print(20L);
delay(100);
display.println();
display.print(-20L);
delay(100);
display.println();
display.print(PI, 7);
delay(100);
display.print(F("that is"));
display.print("all folks");
delay(1000);
// CUSTOM CHAR
uint8_t ch_array[8] = { 0, 2, 4, 8, 31, 8, 4, 2 };
display.defineCustomChar(0, ch_array);
display.customChar(0);
// PLAY
display.duration(64); // 1 second.
display.octave(4);
for (int n = 0; n < 12; n++) display.play(n);
display.noSound();
// FINISH
display.clearHome();
// display.print("Done...");
}
void loop()
{
}

View File

@ -0,0 +1,75 @@
//
// FILE: par27979_demo.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
// DATE: 2020-06-23
// (c) : MIT
//
#include "PAR27979.h"
PAR27979 display(&Serial);
void setup()
{
Serial.begin(19200); // max speed parallax display
display.clearHome();
// ON OFF TEST
display.on();
delay(1000);
display.off();
delay(1000);
display.on();
// BACKLIGHT TEST
display.backlightOn();
delay(1000);
display.backlightOff();
delay(1000);
display.backlightOn();
// PRINT
display.gotoXY(0, 0);
display.print(10);
delay(100);
display.println();
display.print(-10);
delay(100);
display.println();
display.print(20L);
delay(100);
display.println();
display.print(-20L);
delay(100);
display.println();
display.print(PI, 7);
delay(100);
display.print(F("that is"));
display.print("all folks");
delay(1000);
// CUSTOM CHAR
uint8_t ch_array[8] = { 0, 2, 4, 8, 31, 8, 4, 2 };
display.defineCustomChar(0, ch_array);
display.customChar(0);
// PLAY
display.duration(64); // 1 second.
display.octave(4);
for (int n = 0; n < 12; n++) display.play(n);
display.noSound();
// FINISH
display.clearHome();
display.print("Done...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,28 @@
# Syntax Coloring Map For PAR27979
# Datatypes (KEYWORD1)
PAR27979 KEYWORD1
# Methods and Functions (KEYWORD2)
on KEYWORD2
off KEYWORD2
clearHome KEYWORD2
backlightOn KEYWORD2
backlightOff KEYWORD2
left KEYWORD2
right KEYWORD2
down KEYWORD2
gotoXY KEYWORD2
defineCustomChar KEYWORD2
customChar KEYWORD2
octave KEYWORD2
duration KEYWORD2
play KEYWORD2
noSound KEYWORD2
# Instances (KEYWORD2)
# Constants (LITERAL1)

View File

@ -1,7 +1,7 @@
{
"name": "Par27979",
"keywords": "Parallax,27979,serial,display",
"description": "Defines for Parallax 27979 serial display.",
"name": "PAR27979",
"keywords": "Parallax,27979,serial,display,27976,27977",
"description": "Arduino library for Parallax 27979 serial LCD display.",
"authors":
[
{
@ -13,12 +13,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/PAR27979.git"
},
"version":"0.1.0",
"version":"0.2.0",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/Par27979"
}
"platforms": "*"
}

View File

@ -1,9 +1,11 @@
name=Par27979
version=0.1.0
name=PAR27979
version=0.2.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Defines for Parallax 27979 serial display.
paragraph=Supports
category=Sensors
url=https://github.com/RobTillaart/Arduino/tree/master/libraries/
architectures=*
sentence=Arduino library for Parallax 27979 serial LCD display.
paragraph=Supports 27976 and 27977 (not tested)
category=Display
url=https://github.com/RobTillaart/PAR27979
architectures=*
includes=PAR27979.h
depends=

View File

@ -1,4 +1,44 @@
# PAR27979
This is just a collection of simple macros,
not a real class with a stream as param
(todo someday somewhere)
Arduino library for the Parallax 27979 serial display
## Description
The library is essentially a wrapper around a Stream, typically Serial,
Serial2 (3,4..) or newSoftSerial or equivalent.
This stream is given as parameter in the constructor.
The library implements the **Print** interface to print integers
floats and strings and all printable types.
The library does not keep any state information, it only implements a few
methods to make working with it easier.
These methods are quite trivial.
* **on()** switch display on
* **off()** switch display off
* **clearHome()** clear the display
* **backlightOn()** enable the backlight
* **backLightOff()** disable the backlight
**Movement**
* **cursorLeft()** move cursor
* **cursorRight()** move cursor
* **lineFeed()** idem
* **formFeed()** idem
* **gotoXY(x, y)**
**Sound support**
* **octave(octave)** octave = 3 4 5 6 7
* **duration(duration)** duration = 1 2 4 8 16 32 64
* **play(note)** note = 0 1 2 3 4 5 6 7 8 9 10 11 0=A 1=A# etc
* **noSound()**
## Support Parallax 27976 & 27977
Although not tested, the functions should work with the
Parallax 27976 and 27977 displays too.
## Operation
See example

View File

@ -0,0 +1 @@
https://github.com/RobTillaart/ParallelPrinter

View File

@ -1,7 +1,7 @@
//
// FILE: PinInGroup.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// VERSION: 0.1.2
// DATE: 2017-04-26
// PURPOSE: PinInGroup library for Arduino
// goal is to easily read a group of pins that logically
@ -10,8 +10,10 @@
// URL: https://github.com/RobTillaart/PinInGroup
// http://forum.arduino.cc/index.php?topic=469599.0
//
// 0.1.0 2017-08-20 initial version (based upon pinGroup)
// 0.1.1 2020-05-19 refactor; added clear(); added param for INPUT or INPUT_PULLUP
// 0.1.0 2017-08-20 initial version (based upon pinGroup)
// 0.1.1 2020-05-19 refactor; added clear();
// added param for INPUT or INPUT_PULLUP
// 0.1.2 2020-06-19 fix library.json
#include "PinInGroup.h"

View File

@ -1,7 +1,7 @@
#pragma once
// FILE: PinInGroup.h
// AUTHOR: Rob dot Tillaart at gmail dot com
// VERSION: 0.1.1
// VERSION: 0.1.2
// DATE: 2017-04-26
// PURPOSE: PinInGroup library for Arduino
// HISTORY: See PinInGroup.cpp
@ -12,7 +12,7 @@
#include "Arduino.h"
#define PININGROUP_LIB_VERSION "0.1.1"
#define PININGROUP_LIB_VERSION "0.1.2"
// smaller MAXSIZE will reduce memory footprint with ditto bytes.
#ifndef PININGROUP_MAXSIZE

View File

@ -15,10 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/PinInGroup.git"
},
"version":"0.1.1",
"version":"0.1.2",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "PinInGroup
}
"platforms": "*"
}

View File

@ -1,5 +1,5 @@
name=PinInGroup
version=0.1.1
version=0.1.2
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=A class that groups input pins so they can be read in one logical step.

View File

@ -1,22 +1,22 @@
//
// FILE: PinOutGroup.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// VERSION: 0.1.2
// DATE: 2017-04-26
// PURPOSE: PinOutGroup library for Arduino
// goal is to easily change a group of pins that logically
// goal is to easily change a group of pins that logically
// belong to each other e.g. 8 data pins of a parallel printer.
// these pins can be in any order.
// URL:
// URL:
// http://forum.arduino.cc/index.php?topic=469599.0
//
// 0.1.0 - 20-08-2017 initial version (based upon experimental pinGroup)
// 0.1.1 - 2020-05-19 main refactor;
// 0.1.1 - 2020-05-19 main refactor;
// added tests; added clear(); added write(idx, value)
// renamed set to write() to be in line with digitalWrite()
//
//
// 0.1.2 2020-06-19 fix library.json
//
#include "PinOutGroup.h"
@ -35,7 +35,7 @@ void PinOutGroup::clear()
bool PinOutGroup::add(uint8_t sz, uint8_t* ar, uint8_t value)
{
bool b = true;
for (uint8_t i = 0; i < sz && b; i++)
for (uint8_t i = 0; i < sz && b; i++)
{
b = b && add(ar[i], value);
}
@ -62,7 +62,7 @@ uint8_t PinOutGroup::write(uint16_t value)
uint8_t changeCount = 0;
for (uint8_t i = 0; i < _size; i++)
{
if ((changed & bitMask) > 0)
if ((changed & bitMask) > 0)
{
digitalWrite(_pins[i], (value & bitMask) > 0);
changeCount++;

View File

@ -1,7 +1,7 @@
#pragma once
// FILE: PinOutGroup.h
// AUTHOR: Rob dot Tillaart at gmail dot com
// VERSION: 0.1.1
// VERSION: 0.1.2
// DATE: 2017-04-26
// PURPOSE: PinOutGroup library for Arduino
// HISTORY: See PinOutGroup.cpp
@ -9,7 +9,7 @@
#include "Arduino.h"
#define PINOUTGROUP_LIB_VERSION "0.1.1"
#define PINOUTGROUP_LIB_VERSION "0.1.2"
// smaller MAXSIZE will reduce memory footprint with ditto bytes.
#ifndef PINOUTGROUP_MAXSIZE

View File

@ -15,10 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/PinOutGroup.git"
},
"version":"0.1.1",
"version":"0.1.2",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "PinOutGroup
}
"platforms": "*"
}

View File

@ -1,5 +1,5 @@
name=PinOutGroup
version=0.1.1
version=0.1.2
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=A class that groups output pins so they can be updated easier and slightly faster on average.

View File

@ -1,13 +1,15 @@
//
// FILE: Prandom.cpp
// AUTHOR: Rob dot Tillaart at gmail dot com
// VERSION: 0.1.1
// VERSION: 0.1.2
// PURPOSE: Arduino library for random number generation with Python random interface
// URL: https://github.com/RobTillaart/Prandom
//
// HISTORY:
// 0.1.0 2020-05-13 complete redo based upon python random interface
// https://docs.python.org/3/library/random.html
// 0.1.1 renamed all to Prandom
// 0.1.2 2020-06-19 fix library.json
// code nased upon Python implementation although some small optimizations
// and tweaks were needed to get it working.

View File

@ -2,58 +2,58 @@
//
// FILE: Prandom.h
// AUTHOR: Rob dot Tillaart at gmail dot com
// VERSION: 0.1.1
// VERSION: 0.1.2
// PURPOSE: Arduino library for random numbers with Python Random interface
// The underlying pseudo-random number generator is a
// The underlying pseudo-random number generator is a
// Multiply-with-carry method invented by George Marsaglia.
// URL: https://github.com/RobTillaart/random
// URL: https://github.com/RobTillaart/Prandom
// https://docs.python.org/3/library/random.html
// https://www.pcg-random.org/
//
#include "Arduino.h"
#define PRANDOM_LIB_VERSION "0.1.1"
#define PRANDOM_LIB_VERSION "0.1.2"
class Prandom
{
public:
Prandom();
Prandom(uint32_t s);
Prandom();
Prandom(uint32_t s);
void seed();
void seed(uint32_t s, uint32_t t = 2); // marsaglia need 2 seeds, but 1 will work too
void seed();
void seed(uint32_t s, uint32_t t = 2); // marsaglia need 2 seeds, but 1 will work too
//
// integer methods
//
uint32_t getrandbits(uint8_t n);
uint32_t randrange(uint32_t stop);
uint32_t randrange(uint32_t start, uint32_t stop, uint32_t step = 1);
// randint is inclusive end value
uint32_t randint(uint32_t start, uint32_t stop) { return randrange(start, stop + 1); };
//
// integer methods
//
uint32_t getrandbits(uint8_t n);
uint32_t randrange(uint32_t stop);
uint32_t randrange(uint32_t start, uint32_t stop, uint32_t step = 1);
// randint is inclusive end value
uint32_t randint(uint32_t start, uint32_t stop) { return randrange(start, stop + 1); };
//
// real distributions
//
float random(const float top = 1.0);
float uniform(float lo, float hi);
float triangular(float lo = 0, float hi = 1.0, float mid = 0.5);
float normalvariate(float mu = 0, float sigma = 1.0);
float lognormvariate(float mu = 0, float sigma = 1.0);
float gauss(float mu = 0, float sigma = 1.0);
float expovariate(float lambda);
float gammavariate(float alpha, float beta);
float betavariate(float alpha, float beta);
float paretovariate(float alpha);
float weibullvariate(float alpha, float beta);
//
// Circular distributions
//
// mu is mean angle in radians
// kappa is concentration param, 0 -> uniform.
float vonmisesvariate(float mu, float kappa = 0);
//
// real distributions
//
float random(const float top = 1.0);
float uniform(float lo, float hi);
float triangular(float lo = 0, float hi = 1.0, float mid = 0.5);
float normalvariate(float mu = 0, float sigma = 1.0);
float lognormvariate(float mu = 0, float sigma = 1.0);
float gauss(float mu = 0, float sigma = 1.0);
float expovariate(float lambda);
float gammavariate(float alpha, float beta);
float betavariate(float alpha, float beta);
float paretovariate(float alpha);
float weibullvariate(float alpha, float beta);
//
// Circular distributions
//
// mu is mean angle in radians
// kappa is concentration param, 0 -> uniform.
float vonmisesvariate(float mu, float kappa = 0);
private:
@ -62,7 +62,7 @@ private:
// Marsaglia 'constants'
uint32_t _m_w = 1;
uint32_t _m_z = 2;
uint32_t _m_z = 2;
uint32_t __random();
};

View File

@ -15,10 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/Prandom.git"
},
"version":"0.1.1",
"version":"0.1.2",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "Prandom"
}
"platforms": "*"
}

View File

@ -1,5 +1,5 @@
name=Prandom
version=0.1.1
version=0.1.2
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for random number generation with Python random interface.

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,35 +1,35 @@
#pragma once
//
// FILE: PrintCharArray.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// VERSION: 0.2.1
// PURPOSE: Class that captures prints into a char array
// DATE: 2017-12-07
// URL:
// HISTORY: 0.1.0 2017-12-07 initial version
// URL: https://github.com/RobTillaart/PrintCharArray
//
// Released to the public domain
//
#ifndef PrintCharArray_h
#define PrintCharArray_h
// 0.1.0 2017-12-07 initial version
// 0.1.1 2020-04-28 minor optimization
// 0.2.0 2020-04-30 dynamic memory
// 0.2.1 2020-06-19 fix library.json
#include "Print.h"
#define PRINTCHARARRAY_VERSION "0.1.0"
#define BUFFERSIZE 256
#define PRINTCHARARRAY_VERSION "0.2.1"
class PrintCharArray: public Print
{
public:
PrintCharArray() {};
PrintCharArray(uint8_t size = 100)
{
_bufSize = constrain(size, 20, 250);
_buffer = (char *) malloc(_bufSize);
};
size_t write(uint8_t c)
{
if (index < BUFFERSIZE-1)
if (_index < _bufSize - 1)
{
buffer[index] = c;
index++;
buffer[index] = '\0';
_buffer[_index++] = c;
return 1;
}
return 0;
@ -37,19 +37,23 @@ class PrintCharArray: public Print
void clear()
{
index = 0;
buffer[index] = '\0';
_index = 0;
}
int free() { return (BUFFERSIZE - index); }
int free() { return (_bufSize - _index); }
int size() { return index; }
int size() { return _index; }
char * getBuffer() { return buffer; }
char * getBuffer()
{
_buffer[_index] = '\0';
return _buffer;
}
private:
char buffer[BUFFERSIZE];
int index = 0;
char* _buffer;
uint8_t _bufSize = 0;
uint8_t _index = 0;
};
#endif
// -- END OF FILE --

View File

@ -3,6 +3,7 @@
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
// URL: https://github.com/RobTillaart/PrintCharArray
//
// HISTORY:
// 0.1.0 2017-12-07 initial version
@ -35,3 +36,4 @@ void loop()
}
// -- END OF FILE --

View File

@ -2,7 +2,8 @@
// FILE: printCharArray2.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
// PURPOSE: demo right alignment
// URL: https://github.com/RobTillaart/PrintCharArray
//
// HISTORY:
// 0.1.0 2017-12-09 initial version
@ -53,3 +54,4 @@ void printSpaces(int n)
}
}
// -- END OF FILE --

View File

@ -1,18 +1,20 @@
//
// FILE: printCharArray3.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
// VERSION: 0.1.1
// PURPOSE: demo with XML writer
// URL: https://github.com/RobTillaart/PrintCharArray
//
// HISTORY:
// 0.1.0 2017-12-09 initial version
// 0.1.0 2017-12-09 initial version
// 0.1.1 2020-04-30 minor refactor
//
#include "PrintCharArray.h"
#include "XMLWriter.h"
#include "XMLWriter.h" // https://github.com/RobTillaart/XMLWriter
PrintCharArray ps;
PrintCharArray ps(250);
XMLWriter XML(&ps);
void setup()
@ -32,6 +34,7 @@ void setup()
XML.writeNode("Rain", "10mm");
XML.writeNode("Sun", "40");
XML.tagClose();
XML.flush();
// write the XML generated in one call
Serial.println(ps.getBuffer());
@ -44,3 +47,4 @@ void loop()
}
// -- END OF FILE --

View File

@ -1,16 +1,18 @@
//
// FILE: printCharArray4.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// VERSION: 0.1.1
// PURPOSE: demo it takes less time to send data out.
// URL: https://github.com/RobTillaart/PrintCharArray
//
// HISTORY:
// 0.1.0 2017-12-09 initial version
// 0.1.0 2017-12-09 initial version
// 0.1.1 2020-04-30 minor refactor
//
#include "PrintCharArray.h"
PrintCharArray ps;
PrintCharArray ps(200);
uint32_t start, stop;
@ -20,30 +22,36 @@ void setup()
Serial.println(__FILE__);
Serial.println("Using direct print");
start = millis();
for (int i=0; i<10; i++)
start = micros();
for (int i = 0; i < 10; i++)
{
Serial.println(1000+i);
Serial.println(1000 + i);
}
stop = millis();
stop = micros();
Serial.println(stop - start);
Serial.println();
Serial.println("Using printCharArray");
start = micros();
ps.clear();
for (int i=0; i<10; i++)
for (int i = 0; i < 10; i++)
{
ps.println(1000+i)
ps.println(1000 + i);
}
start = millis();
Serial.println(ps.getBuffer());
stop = millis();
stop = micros();
Serial.println(stop - start);
Serial.println();
Serial.println("print PrintCharArray again");
start = micros();
Serial.println(ps.getBuffer());
Serial.println(ps.free());
stop = micros();
Serial.println(stop - start);
Serial.println();
Serial.print("FREE: ");
Serial.println(ps.free());
}
void loop()
@ -51,3 +59,4 @@ void loop()
}
// -- END OF FILE --

View File

@ -0,0 +1,39 @@
//
// FILE: printCharArrayDynamicSize.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
// URL: https://github.com/RobTillaart/PrintCharArray
//
// HISTORY:
// 0.1.0 2020-04-30 initial version
//
#include "PrintCharArray.h"
PrintCharArray ps(100);
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println(ps.free());
ps.println("Hello World");
Serial.println(ps.free());
ps.println(3.14159265, 4);
Serial.println(ps.free());
Serial.println(ps.getBuffer());
ps.clear();
ps.println(3.14159265, 4);
ps.println("Hello World");
Serial.println(ps.getBuffer());
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,14 @@
# Syntax Coloring Map For PrintCharArray
# Datatypes (KEYWORD1)
PrintCharArray KEYWORD1
# Methods and Functions (KEYWORD2)
write KEYWORD2
clear KEYWORD2
free KEYWORD2
size KEYWORD2
getBuffer KEYWORD2
# Constants (LITERAL1)

View File

@ -13,12 +13,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/PrintCharArray.git"
},
"version":"0.1.0",
"version":"0.2.1",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/PrintCharArray"
}
"platforms": "*"
}

View File

@ -1,10 +1,12 @@
name=PrintCharArray
version=0.1.0
version=0.2.1
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library to capture prints into a char array.
paragraph=
category=Data Processing
url=https://github.com/RobTillaart/Arduino/tree/master/libraries
url=https://github.com/RobTillaart/PrintCharArray.git
architectures=*
includes=PrintCharArray.h
depends=

View File

@ -1,12 +1,17 @@
# PrintCharArray
Arduino library to print to a char array
# Description
PrintCharArray is a class that buffers a number of print statements in a char array.
This char array can be processed later.
Typical usecase:
- buffer slow generated of a packet of data
and send it with minimum time between bytes
- print to buffer an see how long output is;
- buffer slowly generated data, and send it with minimum time between bytes
- print to buffer to see how many chars the output is;
use to prevent "display line overflow"
(e.g. floats)
## Operation
See examples

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,28 +1,43 @@
#pragma once
//
// FILE: PrintSize.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// VERSION: 0.2.1
// PURPOSE: Class that determines printSize
// DATE: 2017-12-09
// URL:
// HISTORY: 0.1.0 2017-12-09 initial version
// URL: https://github.com/RobTillaart/PrintSize
//
// Released to the public domain
//
#ifndef PrintSize_h
#define PrintSize_h
// HISTORY:
// 0.1.0 2017-12-09 initial version
// 0.2.0 2020-04-30 add total counter to sum multiple print statements
// 0.2.1 2020-05-26 fix #1 - URLS + centering example
// 0.2.2 2020-06-19 fix library.json
#include "Print.h"
#define PRINTSIZE_VERSION "0.1.0"
#define PRINTSIZE_VERSION "0.2.2"
class PrintSize: public Print
{
public:
PrintSize() {};
PrintSize()
{
reset();
};
size_t write(uint8_t c) { return 1; }
// note: warning unused parameter - remove c to remove warning)
size_t write(uint8_t c)
{
_total++;
return 1;
}
void reset() { _total = 0; }
uint32_t total() { return _total; };
private:
uint32_t _total = 0;
};
#endif
// -- END OF FILE --

View File

@ -1,8 +1,9 @@
//
// FILE: PrintSize1.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// VERSION: 0.1.1
// PURPOSE: demo printSize
// URL: https://github.com/RobTillaart/PrintSize
//
// HISTORY:
// 0.1.0 2017-12-09 initial version
@ -48,3 +49,4 @@ void printSpaces(uint8_t n)
while (n--) Serial.print(' ');
}
// -- END OF FILE --

View File

@ -0,0 +1,83 @@
//
// FILE: PrintSize_centering.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo printSize centering
// URL: https://github.com/RobTillaart/PrintSize
//
// HISTORY:
// 0.1.0 2020-04-30 initial version
//
#include "PrintSize.h"
char woord[24];
int idx = 0;
PrintSize ps;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println();
Serial.println(__FILE__);
Serial.println("Determine length of 10 random numbers and right ");
Serial.println("align the numbers in a table with their sum.");
Serial.println();
ps.reset();
}
void loop()
{
uint32_t sum = 0;
Serial.println();
Serial.println(" Centering");
for (int i = 0; i < 10; i++)
{
// create different order of magnitude random numbers
uint32_t maxsize = pow(10, 1 + random(9));
uint32_t rn = random(maxsize);
int length = ps.println(rn);
printSpaces((15 - length) / 2);
sum += rn;
Serial.println(rn);
}
Serial.print("================ +\n");
int length = ps.println(sum);
printSpaces((15 - length) / 2);
Serial.println(sum);
Serial.println();
Serial.println();
Serial.println(" Right Align");
for (int i = 0; i < 10; i++)
{
// create different order of magnitude random numbers
uint32_t maxsize = pow(10, 1 + random(9));
uint32_t rn = random(maxsize);
int length = ps.println(rn);
printSpaces(15 - length);
sum += rn;
Serial.println(rn);
}
Serial.print("================ +\n");
length = ps.println(sum);
printSpaces(15 - length);
Serial.println(sum);
Serial.println();
delay(1000);
}
void printSpaces(uint8_t n)
{
while (n--) Serial.print(' ');
}
// -- END OF FILE --

View File

@ -52,3 +52,5 @@ void printSpaces(uint8_t n)
{
while (n--) Serial.print(' ');
}
// -- END OF FILE --

View File

@ -0,0 +1,89 @@
//
// FILE: PrintSize_total.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo printSize total counter
// URL: https://github.com/RobTillaart/PrintSize
//
// HISTORY:
// 0.1.0 2020-04-30 initial version
//
/*
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed mattis eget odio ut
tempor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin consectetur,
massa nec eleifend aliquet, tellus nulla dapibus magna, eu pharetra dolor turpis
sit amet mauris. Quisque tempor luctus nisl. Donec nisi quam, gravida id urna quis,
vestibulum placerat ex. Etiam auctor odio nisl, at molestie arcu gravida et.
Integer rutrum enim ligula, eget commodo lorem dapibus nec. Ut bibendum sapien at
tellus posuere, lobortis vestibulum magna blandit. Curabitur aliquam, massa sit
amet aliquet ullamcorper, dui metus sollicitudin purus, luctus tempor nisi enim
commodo justo. Nullam tempus, nunc finibus hendrerit mollis, purus odio mattis
nisl, porttitor malesuada erat urna eu neque. Phasellus ultricies ante tortor,
ac facilisis diam dignissim sit amet. Donec accumsan ac orci a malesuada.
*/
#include "PrintSize.h"
char woord[24];
int idx = 0;
PrintSize ps;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println();
Serial.println(__FILE__);
Serial.println("\nType words < 20 chars in the Serial monitor\n");
ps.reset();
}
void loop()
{
if (Serial.available() > 0)
{
char c = Serial.read();
if (c == ' ' || c == '\n')
{
process(woord, 60);
woord[0] = '\0';
idx = 0;
}
else
{
woord[idx++] = c;
woord[idx] = '\0';
}
}
}
// split the stream of words in lines of maxlen
void process(char * w, uint8_t maxlen)
{
// skip empty words.
if (strlen(w) == 0) return;
// remember position
uint8_t prev = ps.total();
// does the word fit on the line
ps.print(w);
ps.print(' ');
if (ps.total() >= maxlen)
{
// if not, fill line with -
for (; prev < maxlen; prev++) Serial.print('-');
Serial.println();
// start counter for new line.
ps.reset();
ps.print(w);
ps.print(' ');
}
Serial.print(w);
Serial.print(' ');
}
// -- END OF FILE --

View File

@ -0,0 +1,12 @@
# Syntax Coloring Map For PrintSize
# Datatypes (KEYWORD1)
PrintSize KEYWORD1
# Methods and Functions (KEYWORD2)
write KEYWORD2
reset KEYWORD2
total KEYWORD2
# Constants (LITERAL1)

View File

@ -13,12 +13,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/PrintSize.git"
},
"version":"0.1.0",
"version":"0.2.2",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/PrintSize"
}
"platforms": "*"
}

View File

@ -1,10 +1,11 @@
name=PrintSize
version=0.1.0
version=0.2.2
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library to determine size of a printed variable.
paragraph=
category=Data Processing
url=https://github.com/RobTillaart/Arduino/tree/master/libraries
url=https://github.com/RobTillaart/PrintSize
architectures=*
includes=PrintSize.h
depends=

View File

@ -1,18 +1,25 @@
# PrintSize
Arduino library to determine the length of print statements
# Description
PrintSize is a minimal library to determine the length of a variable when printed.
This includes printing of floats
This includes printing of floats, integers in decimal or hex notation.
## Examples
Example show the alignment of 10 random numbers,
both print(), println() and if supported printf().
Works for **print()**, **println()** and if supported **printf()** e.g. ESP32.
Finally since **0.2.0** it has a total counter to add up the characters "printed" since
the last **reset()** call. (see example)
# Operational
Example shows the right alignment of 10 random numbers
Example shows (elementary) line fitting
### notes
Can be used to calculate the needed space.
- to properly do a right alignment e.g. for numbers.
- do left alignement and overwrite previous output with spaces.
- to properly do a right alignment e.g. for numbers or variable text
- do left alignement and overwrite previous output with just enough spaces.
- centering of numbers
- see if output will fit into a line.
- see if output will fit into a line / display

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 20017-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,22 +1,21 @@
#pragma once
//
// FILE: PrintString.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// VERSION: 0.1.2
// PURPOSE: Class that captures prints into a String
// DATE: 2017-12-09
// URL:
// HISTORY: 0.1.0 2017-12-09 initial version
// URL: https://github.com/RobTillaart/PrintString
//
// Released to the public domain
// 0.1.0 2017-12-09 initial version
// 0.1.1 2020-04-26 added size
// 0.1.2 2020-06-19 fix library.json
//
#ifndef PrintString_h
#define PrintString_h
#include "Arduino.h"
#include "Print.h"
#include "String.h"
#define PRINTSTRING_VERSION "0.1.0"
#define PRINTSTRING_VERSION "0.1.2"
class PrintString: public Print
{
@ -25,10 +24,15 @@ public:
size_t write(uint8_t c)
{
buffer += (char)c;
buffer.concat(char(c));
return 1;
}
size_t size()
{
return buffer.length();
}
void clear()
{
buffer = "";
@ -39,5 +43,5 @@ public:
private:
String buffer;
};
#endif
// -- END OF FILE --

View File

@ -0,0 +1,19 @@
# PrintString
Arduino library to print to a String
# Description
PrintString is a class that buffers a number of print statements in a String.
This String can be requested to process later.
- buffer slowly generated data, and send it with minimum time between bytes
e.g. to maximize packets for ethernet
- print to buffer to see how many chars the output is;
use to prevent "display line overflow"
(e.g. floats)
# Operational
See examples

View File

@ -1,16 +1,17 @@
//
// FILE: printString.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// VERSION: 0.1.1
// PURPOSE: demo experimental
// URL: https://github.com/RobTillaart/PrintString
//
// HISTORY:
// 0.1.0 2017-12-09 initial version
// 0.1.0 2017-12-09 initial version
// 0.1.1 2020-04-30 align demo with latest XMLWriter lib
//
#include "PrintString.h"
#include "XMLWriter.h"
#include "XMLWriter.h" // https://github.com/RobTillaart/XMLWriter
PrintString ps;
XMLWriter XML(&ps);
@ -41,6 +42,7 @@ void setup()
XML.writeNode("Rain", "10mm");
XML.writeNode("Sun", "40");
XML.tagClose();
XML.flush();
Serial.println(ps.getString());
@ -50,4 +52,5 @@ void setup()
void loop()
{
}
// END OF FILE
// -- END OF FILE --

View File

@ -0,0 +1,13 @@
# Syntax Coloring Map For PrintString
# Datatypes (KEYWORD1)
PrintString KEYWORD1
# Methods and Functions (KEYWORD2)
write KEYWORD2
size KEYWORD2
clear KEYWORD2
getString KEYWORD2
# Constants (LITERAL1)

View File

@ -13,12 +13,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/PrintString.git"
},
"version":"0.1.0",
"version":"0.1.2",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/PrintString"
}
"platforms": "*"
}

View File

@ -1,5 +1,5 @@
name=PrintString
version=0.1.0
version=0.1.2
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library to capture prints into a String.
@ -7,4 +7,5 @@ paragraph=
category=Data Processing
url=https://github.com/RobTillaart/Arduino/tree/master/libraries
architectures=*
includes=PrintString.h
depends=

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2012-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,8 +1,9 @@
//
// FILE: PulsePattern.cpp
// AUTHOR: Rob dot Tillaart at gmail dot com
// VERSION: see PULSEPATTERN_LIB_VERSION in .h
// PURPOSE: PulsePattern library for Arduino
// VERSION: 0.1.2
// DATE: 2012-11-23
// PURPOSE: Arduino Library to generate repeating pulse patterns
//
// HISTORY:
// 0.0.1 - 2012-11-23 initial version
@ -12,29 +13,14 @@
// 0.0.5 - 2012-12-27 code cleanup+comment
// 0.0.6 - 2015-04-18 completed the state machine
// 0.0.7 - 2017-07-16 refactor & review
//
// Released to the public domain
//
// TODO
// - fast function iso array to return the next period?
// more adaptive to e.g. sensor values. (investigate)
// - test PRE 1.0 backwards compatibility
// - move code to .h file so compiler can inline?
// - optimize timer code
// - adjust timing to more accurate values -> setTimer()
// - worker should be private - how???
// - test invalid array periods
// - start en stop index ipv size?
// - pulsepattern recorder
//
// 0.0.8 - 2018-12-13 refactor -> remove some warnings
// 0.1.0 2020-06-19 #pragma once; remove pre 1.0 support; refactor
// 0.1.1 2020-07-04 add continue function, fix spaces.
// 0.1.2 2020-08-07 speed up toggle pin + get/setFactor()
#include "PulsePattern.h"
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
// Predefined generator (singleton)
PulsePattern PPGenerator;
@ -55,29 +41,39 @@ PulsePattern::PulsePattern()
_pin = 0;
}
void PulsePattern::init(uint8_t pin, uint16_t * ar, uint8_t size,
uint8_t level, uint8_t prescaler)
void PulsePattern::init(const uint8_t pin, const uint16_t * ar, const uint8_t size,
const uint8_t level, const uint8_t prescaler)
{
_pin = pin;
pinMode(_pin, OUTPUT);
stop();
_ar = ar;
_ar = (uint16_t *) ar;
_size = size;
// TODO: run over the array to test invalid values?
// constrain them 10-4095?
_level = constrain(level, LOW, HIGH);
_level = level ? LOW : HIGH;
_prescaler = constrain(prescaler, PRESCALE_1, PRESCALE_1024);
_cnt = 0;
digitalWrite(_pin, _level);
_state = STOPPED;
// fast low level AVR ports
uint8_t _pinport = digitalPinToPort(_pin);
_pinout = portOutputRegister(_pinport);
_pinbit = digitalPinToBitMask(_pin);
}
void PulsePattern::start()
{
if (_size == 0) return; // no pattern
if (_state == RUNNING) return; // no restart
_cnt = 0; // start from begin
cont();
}
void PulsePattern::cont()
{
if (_state == RUNNING) return; // no continue
if (_size == 0) return; // no pattern
setTimer(1); // start asap
_state = RUNNING;
}
@ -95,14 +91,21 @@ void PulsePattern::worker()
if (_state != RUNNING) return;
// set next period & flip signal
_level = !_level;
// direct port faster
digitalWrite(_pin, _level);
// TODO: adjustment needed for code overhead when micros?;
// + 5.2 usec for digitalWrite
// + 3 usec for settimer call
OCR1A = (_ar[_cnt]) * (F_CPU/1000000L);
// digitalWrite(_pin, _level);
// direct port much faster
if (_level == 0) *_pinout &= ~_pinbit;
else *_pinout |= _pinbit;
if (_factor != 4096)
{
OCR1A = _ar[_cnt] * _factor * (F_CPU/1000000UL) / 4096;
}
else
{
OCR1A = _ar[_cnt] * (F_CPU/1000000UL);
}
_cnt++;
if (_cnt >= _size) _cnt = 0; // repeat
if (_cnt >= _size) _cnt = 0; // repeat pattern
}
// TIMER code based upon - http://www.gammon.com.au/forum/?id=11504
@ -112,21 +115,20 @@ void PulsePattern::stopTimer()
TCCR1B = 0;
}
// TODO: can be optimized?
void PulsePattern::setTimer(const uint16_t cc) const
{
TCCR1A = 0;
TCCR1A = 0; // stop timer first
TCCR1B = 0;
TCNT1 = 0; // reset counter
OCR1A = cc * 16; // compare A register value;
TCNT1 = 0; // reset counter
OCR1A = cc * 16; // compare A register value;
// * 16 makes max period 4095
// min period 12?
// 4: CTC mode, top = OCR1A
TCCR1A = _BV (COM1A1); // clear on compare
TCCR1A = _BV (COM1A1); // clear on compare
TCCR1B = _BV (WGM12) | _prescaler;
TIFR1 |= _BV (OCF1A); // clear interrupt flag
TIMSK1 = _BV (OCIE1A); // interrupt on Compare A Match
}
// END OF FILE
// -- END OF FILE --

View File

@ -1,59 +1,71 @@
#ifndef PulsePattern_h
#define PulsePattern_h
#pragma once
//
// FILE: PulsePattern.h
// AUTHOR: Rob dot Tillaart at gmail dot com
// PURPOSE: PulsePattern library for Arduino
// VERSION: 0.1.2
// DATE: 2012-11-23
// PURPOSE: Arduino Library to generate repeating pulse patterns
// sends a pulse pattern to a digital pin (continuously)
// HISTORY: See PulsePattern.cpp
//
// Released to the public domain
//
#include <inttypes.h>
#if !defined(__AVR__)
#error "Only support for AVR boards"
#endif
#include "Arduino.h"
#define PULSEPATTERN_LIB_VERSION "0.1.2"
#define PULSEPATTERN_LIB_VERSION "0.0.7"
#define NOTINIT -1
#define STOPPED 0
#define RUNNING 1
#define NO_CLOCK 0
#define PRESCALE_1 1
#define PRESCALE_8 2
#define PRESCALE_64 3
#define PRESCALE_256 4
#define PRESCALE_1024 5
#define NO_CLOCK 0 // timer off
#define PRESCALE_1 1
#define PRESCALE_8 2
#define PRESCALE_64 3
#define PRESCALE_256 4
#define PRESCALE_1024 5
#define EXT_T1_FALLING 6 // external clock
#define EXT_T2_RISING 7 // external clock
class PulsePattern
{
public:
PulsePattern();
void init(const uint8_t pin,
const uint16_t * ar, const uint8_t size,
const uint8_t level, const uint8_t prescaler);
void start();
void stop();
bool isRunning() const { return _state == RUNNING; };
void init(const uint8_t pin,
const uint16_t * ar, const uint8_t size,
const uint8_t level, const uint8_t prescaler);
void worker();
void setFactor(float perc) { _factor = round(4096 * (1 + perc)); };
float getFactor() { return _factor / 4096.0 - 1; };
void start();
void cont();
void stop();
bool isRunning() const { return _state == RUNNING; };
void worker();
private:
void stopTimer();
void setTimer(const uint16_t cc) const;
void stopTimer();
void setTimer(const uint16_t cc) const;
uint32_t _factor = 4096;
uint16_t * _ar;
uint8_t _size;
uint8_t _pin;
uint8_t _prescaler;
volatile uint8_t _level;
volatile int8_t _state;
volatile uint8_t _cnt;
uint8_t _size;
uint8_t _pin;
uint8_t _pinbit;
volatile uint8_t * _pinout;
uint8_t _prescaler;
volatile uint8_t _level;
volatile int8_t _state;
volatile uint8_t _cnt;
};
extern PulsePattern PPGenerator;
#endif
// END OF FILE
// -- END OF FILE --

View File

@ -0,0 +1,58 @@
# PulsePattern
Arduino Library to generate repeating pulse patterns **AVR ONLY**
## Description
This is an **experimental** library to generate pulse patterns by means of an Arduino UNO.
As the library uses **AVR hardware timers** it is definitely **NOT** working for ESP
or other non-AVR processors.
The library uses timer1 for the timing of the pulses.
Therefor the class is implemented with a static instance called PPO.
Still by calling init() one can change all parameters of the process.
One should note that calling init() forces the timer to stop.
The timer code is based upon the website of Nick Gammon which
holds quite a lot of good solid material (Thanks Nick!).
https://gammon.com.au/forum/bbshowpost.php?bbtopic_id=123
Use with care.
## Interface
- **PulsePattern()** constructor
- **init(pin, \*ar, size, level, prescaler)** initializer of the Timer1
* pin that outputs the pattern
* array of durations
* size (or part) of the array to be used
* starting level HIGH/LOW
* prescaler, one of the 5 defines from .h file (table below)
- **setFactor(perc)** percentage = factor to correct timing (relative).
- **getFactor()** get the internal used factor. Due to rounding it can be slightly different.
- **stop()** stop the pattern generator
- **start()** start the pattern generator
- **cont()** continue the pattern generator from the last stopped place (approx).
- **isRunning()** status indicator
- **worker()** must be public otherwise the ISR cannot call it.
There is some bad understood __vector_11() error when worker() is private.
### Prescaler constants
| Value | Prescaler | Timer1 | notes |
|:----:|:----|:----|:----:|
| 0 | NO_CLOCK | timer off | |
| 1 | PRESCALE_1 | clk / 1 | |
| 2 | PRESCALE_8 | clk / 8 | |
| 3 | PRESCALE_64 | clk / 64 | |
| 4 | PRESCALE_256 | clk / 250 | |
| 5 | PRESCALE_1024 | clk / 1024 | about 1 ms / pulse |
| 6 | EXT_T1_FALLING | T1 = pin 5 | not tested |
| 7 | EXT_T2_RISING | | not tested |
###
# Operation
See example

View File

@ -1,39 +1,36 @@
//
// FILE: SOS_demo2.pde
// FILE: SOS_demo2.ino
// AUTHOR: Rob Tillaart
// DATE: 2012-11-23
//
// PUPROSE: demo of the PulsePattern Library
// uses timer1
//
#include "PulsePattern.h"
// a pattern consists of durations of LOW and HIGH periods
// so the first line of the SOSpattern is
// so the first line of the SOSpattern is
// 500 units LOW, 500 units HIGH etc
// for a dutycycle of 50% LOW and HIGH should have equal periods
// NOTE max period = 4095.
// min period = about 12
uint16_t SOSpattern[] = {
500,500,500,500,500,1500, // SOS in morse
1500,500,1500,500,1500,1500,
500,500,500,500,500,1500 };
uint16_t XYZpattern[] = {
100,100,100,100,100,100, // SOS in morse
500,500,500,500,500,500,
1000,1000,1000,1000,1000,1000 };
// min period = about 12
uint16_t SOSpattern[] =
{
500,500,500,500,500,1500, // SOS in morse
1500,500,1500,500,1500,1500,
500,500,500,500,500,1500
};
uint8_t patternSize = 18;
uint8_t startLevel = LOW;
void setup()
{
Serial.begin(9600);
Serial.println("Start PulsePattern");
Serial.begin(115200);
Serial.println(__FILE__);
// as the prescaler = 1024 the periods of the pattern are a
// as the prescaler = 1024 the periods of the pattern are a
// few percent less than a millisecond
PPGenerator.init(13, SOSpattern, patternSize, startLevel, PRESCALE_1024);
PPGenerator.start();

View File

@ -0,0 +1,60 @@
//
// FILE: pattern_recorder.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: records and writes a pattern to serial
// DATE: 2020-07-25
#include "Arduino.h"
uint8_t pin = 4;
uint16_t minDuration = 50;
uint16_t units = 10;
uint32_t counter = 0;
uint32_t sum = 0;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
}
void loop()
{
uint32_t duration = recordPulse(pin, units, minDuration);
sum += duration;
counter++;
Serial.print(duration);
Serial.print("\t");
Serial.println(sum/counter);
}
uint32_t recordPulse(uint8_t pin, uint16_t unit, uint16_t minperiod)
{
static uint8_t state;
static uint32_t start;
static bool first = true;
if (first)
{
first = false;
pinMode(pin, INPUT_PULLUP);
state = digitalRead(pin);
start = millis();
}
uint8_t newState = state;
while ((millis() - start) < minperiod - unit);
uint32_t now = millis();
while (newState == state)
{
while (millis() - now < unit);
now = millis();
newState = digitalRead(pin);
}
state = newState;
uint32_t duration = (now - start + unit - 1) / unit;
start = now;
return duration;
}
// -- END OF FILE --

View File

@ -0,0 +1,49 @@
//
// FILE: random_pattern.ino
// AUTHOR: Rob Tillaart
// DATE: 2020-07-04
//
// PUPROSE: demo of the PulsePattern Library
// uses timer1
//
#include "PulsePattern.h"
// a pattern constants of durations of LOW and HIGH periods
// so the first line of the SOSpattern
// 500 units LOW, 500 units HIGH etc
// for a dutycycle of 50% LOW and HIGH should have equal periods
// NOTE max period = 4095.
// min period = about 12
uint16_t random_pattern[] = { 500, 500 };
uint8_t patternSize = 2;
uint8_t startLevel = LOW;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
// as the prescaler = 1024 the periods of the pattern are a
// few percent less than a millisecond
PPGenerator.init(13, random_pattern, patternSize, startLevel, PRESCALE_1024);
PPGenerator.start();
}
void loop()
{
random_pattern[0] = 100 + millis() % 1000;
random_pattern[1] = 100 + micros() % 1000;
Serial.print(millis());
Serial.print('\t');
Serial.print(micros());
Serial.print('\t');
Serial.print(random_pattern[0]);
Serial.print('\t');
Serial.print(random_pattern[1]);
Serial.println();
delay(5000);
}
// -- END OF FILE --

View File

@ -0,0 +1,38 @@
//
// FILE: siren_pattern.ino
// AUTHOR: Rob Tillaart
// DATE: 2012-11-23
//
// PUPROSE: demo of the PulsePattern Library
// uses timer1
//
#include "PulsePattern.h"
// a pattern consists of durations of LOW and HIGH periods
// NOTE max period = 4095.
// min period = about 12
uint16_t pattern[] =
{
1500, 1500, 1400, 1400, 1300, 1300, 1200, 1200, 1100, 1100,
1000, 1000, 900, 900, 800, 800, 700, 700, 600, 600,
500, 500, 400, 400, 300, 300, 200, 200, 100, 100
};
uint8_t patternSize = 30;
uint8_t startLevel = LOW;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
PPGenerator.init(13, pattern, patternSize, startLevel, PRESCALE_1024);
PPGenerator.start();
}
void loop()
{
Serial.println(millis());
delay(1000);
}

View File

@ -0,0 +1,26 @@
# Syntax Coloring Map for PulsePattern
# Datatypes (KEYWORD1)
PulsePattern KEYWORD1
# Methods and Functions (KEYWORD2)
init KEYWORD2
setFactor KEYWORD2
getFactor KEYWORD2
start KEYWORD2
cont KEYWORD2
stop KEYWORD2
isRunning KEYWORD2
# Constants (LITERAL1)
PULSEPATTERN_LIB_VERSION LITERAL1
NO_CLOCK LITERAL1
PRESCALE_1 LITERAL1
PRESCALE_8 LITERAL1
PRESCALE_64 LITERAL1
PRESCALE_256 LITERAL1
PRESCALE_1024 LITERAL1
EXT_T1_FALLING LITERAL1
EXT_T2_RISING LITERAL1

View File

@ -1,7 +1,7 @@
{
"name": "PulsePattern",
"keywords": "Pulse,pattern,repeating",
"description": "Library to generate repeating pulse patterns. (uses timer1)",
"keywords": "Pulse, pattern, repeat",
"description": "Library to generate repeating pulse patterns. (uses timer1) AVR only",
"authors":
[
{
@ -13,12 +13,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/PulsePattern.git"
},
"version":"0.0.7",
"version":"0.1.2",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/PulsePattern"
}
"platforms": "avr"
}

View File

@ -1,9 +1,11 @@
name=PulsePattern
version=0.0.7
version=0.1.2
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library to generate repeating pulse patterns.
paragraph=uses timer1
sentence=Library to generate repeating pulse patterns. (AVR only)
paragraph=uses timer1
category=Signal Input/Output
url=https://github.com/RobTillaart/Arduino/tree/master/libraries/
architectures=*
url=https://github.com/RobTillaart/PulsePattern
architectures=avr
includes=PulsePattern.h
depends=