From c810f9541d23e31ef5ff65e17503efa33dcfa859 Mon Sep 17 00:00:00 2001 From: danielvici123 <94993276+danielvici@users.noreply.github.com> Date: Mon, 2 Dec 2024 11:49:11 +0100 Subject: [PATCH] inf sachen --- INF/Beispiele.zip | Bin 0 -> 18740 bytes INF/libraries/PCA9685/LICENSE | 32 + INF/libraries/PCA9685/README.org | 16 + .../examples/FrequencySweep/Constants.cpp | 18 + .../examples/FrequencySweep/Constants.h | 21 + .../FrequencySweep/FrequencySweep.ino | 41 + .../OffTimeSweepSingleDevice/Constants.cpp | 21 + .../OffTimeSweepSingleDevice/Constants.h | 24 + .../OffTimeSweepSingleDevice.ino | 41 + .../OnTimeSweepMultipleDevices/Constants.cpp | 28 + .../OnTimeSweepMultipleDevices/Constants.h | 27 + .../OnTimeSweepMultipleDevices.ino | 46 + .../examples/ServoController/Constants.cpp | 23 + .../examples/ServoController/Constants.h | 26 + .../ServoController/ServoController.ino | 32 + .../SetChannelDutyCycle/Constants.cpp | 41 + .../examples/SetChannelDutyCycle/Constants.h | 32 + .../SetChannelDutyCycle.ino | 33 + .../SetChannelOnAndOffTime/Constants.cpp | 43 + .../SetChannelOnAndOffTime/Constants.h | 32 + .../SetChannelOnAndOffTime.ino | 33 + .../SetChannelPulseWidth/Constants.cpp | 41 + .../examples/SetChannelPulseWidth/Constants.h | 32 + .../SetChannelPulseWidth.ino | 33 + .../examples/TestSetAndGet/Constants.cpp | 22 + .../examples/TestSetAndGet/Constants.h | 24 + .../examples/TestSetAndGet/TestSetAndGet.ino | 105 ++ INF/libraries/PCA9685/library.properties | 9 + INF/libraries/PCA9685/src/PCA9685.h | 363 ++++++ INF/libraries/PCA9685/src/PCA9685/PCA9685.cpp | 1005 +++++++++++++++++ .../PCA9685/src/PCA9685/PCA9685Definitions.h | 46 + 31 files changed, 2290 insertions(+) create mode 100644 INF/Beispiele.zip create mode 100644 INF/libraries/PCA9685/LICENSE create mode 100644 INF/libraries/PCA9685/README.org create mode 100644 INF/libraries/PCA9685/examples/FrequencySweep/Constants.cpp create mode 100644 INF/libraries/PCA9685/examples/FrequencySweep/Constants.h create mode 100644 INF/libraries/PCA9685/examples/FrequencySweep/FrequencySweep.ino create mode 100644 INF/libraries/PCA9685/examples/OffTimeSweepSingleDevice/Constants.cpp create mode 100644 INF/libraries/PCA9685/examples/OffTimeSweepSingleDevice/Constants.h create mode 100644 INF/libraries/PCA9685/examples/OffTimeSweepSingleDevice/OffTimeSweepSingleDevice.ino create mode 100644 INF/libraries/PCA9685/examples/OnTimeSweepMultipleDevices/Constants.cpp create mode 100644 INF/libraries/PCA9685/examples/OnTimeSweepMultipleDevices/Constants.h create mode 100644 INF/libraries/PCA9685/examples/OnTimeSweepMultipleDevices/OnTimeSweepMultipleDevices.ino create mode 100644 INF/libraries/PCA9685/examples/ServoController/Constants.cpp create mode 100644 INF/libraries/PCA9685/examples/ServoController/Constants.h create mode 100644 INF/libraries/PCA9685/examples/ServoController/ServoController.ino create mode 100644 INF/libraries/PCA9685/examples/SetChannelDutyCycle/Constants.cpp create mode 100644 INF/libraries/PCA9685/examples/SetChannelDutyCycle/Constants.h create mode 100644 INF/libraries/PCA9685/examples/SetChannelDutyCycle/SetChannelDutyCycle.ino create mode 100644 INF/libraries/PCA9685/examples/SetChannelOnAndOffTime/Constants.cpp create mode 100644 INF/libraries/PCA9685/examples/SetChannelOnAndOffTime/Constants.h create mode 100644 INF/libraries/PCA9685/examples/SetChannelOnAndOffTime/SetChannelOnAndOffTime.ino create mode 100644 INF/libraries/PCA9685/examples/SetChannelPulseWidth/Constants.cpp create mode 100644 INF/libraries/PCA9685/examples/SetChannelPulseWidth/Constants.h create mode 100644 INF/libraries/PCA9685/examples/SetChannelPulseWidth/SetChannelPulseWidth.ino create mode 100644 INF/libraries/PCA9685/examples/TestSetAndGet/Constants.cpp create mode 100644 INF/libraries/PCA9685/examples/TestSetAndGet/Constants.h create mode 100644 INF/libraries/PCA9685/examples/TestSetAndGet/TestSetAndGet.ino create mode 100644 INF/libraries/PCA9685/library.properties create mode 100644 INF/libraries/PCA9685/src/PCA9685.h create mode 100644 INF/libraries/PCA9685/src/PCA9685/PCA9685.cpp create mode 100644 INF/libraries/PCA9685/src/PCA9685/PCA9685Definitions.h diff --git a/INF/Beispiele.zip b/INF/Beispiele.zip new file mode 100644 index 0000000000000000000000000000000000000000..c52ebf25c160b2c7d397dbfc5b446c4c852bd1ce GIT binary patch literal 18740 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 Wvw^;k$p8Qd?>`>zdzrjHzx_YDXOv3- literal 0 HcmV?d00001 diff --git a/INF/libraries/PCA9685/LICENSE b/INF/libraries/PCA9685/LICENSE new file mode 100644 index 0000000..ee80abc --- /dev/null +++ b/INF/libraries/PCA9685/LICENSE @@ -0,0 +1,32 @@ +License Agreement +(3-clause BSD License) +Janelia Research Campus Software Copyright 1.1 + +Copyright (c) 2014, Howard Hughes Medical Institute +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the Howard Hughes Medical Institute nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/INF/libraries/PCA9685/README.org b/INF/libraries/PCA9685/README.org new file mode 100644 index 0000000..e1b2904 --- /dev/null +++ b/INF/libraries/PCA9685/README.org @@ -0,0 +1,16 @@ +#+TITLE: PCA9685 +#+AUTHOR: Peter Polidoro +#+EMAIL: peterpolidoro@gmail.com + +* Library Information + - Name :: PCA9685 + - Version :: 2.1.4 + - License :: BSD + - URL :: https://github.com/janelia-arduino/PCA9685 + - Author :: Peter Polidoro + - Email :: peterpolidoro@gmail.com + + The PCA9685 is a 16-channel 12-bit PWM controller. All channels operate at a + programmable frequency between roughly 25 to 1600 Hz with 16 independent + 12-bit duty cycles from 0 to 100%. Supports using a single device (for up to + 16 channels) or up to 55 devices (for up to 880 channels). diff --git a/INF/libraries/PCA9685/examples/FrequencySweep/Constants.cpp b/INF/libraries/PCA9685/examples/FrequencySweep/Constants.cpp new file mode 100644 index 0000000..07c120a --- /dev/null +++ b/INF/libraries/PCA9685/examples/FrequencySweep/Constants.cpp @@ -0,0 +1,18 @@ +// ---------------------------------------------------------------------------- +// Constants.cpp +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#include "Constants.h" + + +namespace constants +{ +const uint8_t device_address = 0x40; +const size_t output_enable_pin = 2; + +const size_t loop_delay = 100; +const uint16_t frequency_increment = 10; +} diff --git a/INF/libraries/PCA9685/examples/FrequencySweep/Constants.h b/INF/libraries/PCA9685/examples/FrequencySweep/Constants.h new file mode 100644 index 0000000..6734e39 --- /dev/null +++ b/INF/libraries/PCA9685/examples/FrequencySweep/Constants.h @@ -0,0 +1,21 @@ +// ---------------------------------------------------------------------------- +// Constants.h +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#ifndef CONSTANTS_H +#define CONSTANTS_H +#include + + +namespace constants +{ +extern const uint8_t device_address; +extern const size_t output_enable_pin; + +extern const size_t loop_delay; +extern const uint16_t frequency_increment; +} +#endif diff --git a/INF/libraries/PCA9685/examples/FrequencySweep/FrequencySweep.ino b/INF/libraries/PCA9685/examples/FrequencySweep/FrequencySweep.ino new file mode 100644 index 0000000..f60b801 --- /dev/null +++ b/INF/libraries/PCA9685/examples/FrequencySweep/FrequencySweep.ino @@ -0,0 +1,41 @@ +#include +#include + +#include "Constants.h" + + +PCA9685 pca9685; + +uint16_t frequency_min; +uint16_t frequency_max; +uint16_t frequency; + +void setup() +{ + pca9685.setupSingleDevice(Wire,constants::device_address); + + pca9685.setupOutputEnablePin(constants::output_enable_pin); + pca9685.enableOutputs(constants::output_enable_pin); + + pca9685.setOutputsNotInverted(); + + uint16_t time_min = pca9685.getTimeMin(); + uint16_t time_max = pca9685.getTimeMax(); + pca9685.setAllChannelsOnAndOffTime(time_min,time_max/4); + + frequency_min = pca9685.getFrequencyMin(); + frequency_max = pca9685.getFrequencyMax(); + + frequency = frequency_min; +} + +void loop() +{ + if (frequency > frequency_max) + { + frequency = frequency_min; + } + pca9685.setToFrequency(frequency); + frequency += constants::frequency_increment; + delay(constants::loop_delay); +} diff --git a/INF/libraries/PCA9685/examples/OffTimeSweepSingleDevice/Constants.cpp b/INF/libraries/PCA9685/examples/OffTimeSweepSingleDevice/Constants.cpp new file mode 100644 index 0000000..d0c27cc --- /dev/null +++ b/INF/libraries/PCA9685/examples/OffTimeSweepSingleDevice/Constants.cpp @@ -0,0 +1,21 @@ +// ---------------------------------------------------------------------------- +// Constants.cpp +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#include "Constants.h" + + +namespace constants +{ +const uint8_t device_address = 0x40; +const size_t output_enable_pin = 2; + +const size_t loop_delay = 100; +const uint16_t frequency = 200; +const uint16_t time_increment = 100; + +const uint8_t channel = 0; +} diff --git a/INF/libraries/PCA9685/examples/OffTimeSweepSingleDevice/Constants.h b/INF/libraries/PCA9685/examples/OffTimeSweepSingleDevice/Constants.h new file mode 100644 index 0000000..c4146ba --- /dev/null +++ b/INF/libraries/PCA9685/examples/OffTimeSweepSingleDevice/Constants.h @@ -0,0 +1,24 @@ +// ---------------------------------------------------------------------------- +// Constants.h +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#ifndef CONSTANTS_H +#define CONSTANTS_H +#include + + +namespace constants +{ +extern const uint8_t device_address; +extern const size_t output_enable_pin; + +extern const size_t loop_delay; +extern const uint16_t frequency; +extern const uint16_t time_increment; + +extern const uint8_t channel; +} +#endif diff --git a/INF/libraries/PCA9685/examples/OffTimeSweepSingleDevice/OffTimeSweepSingleDevice.ino b/INF/libraries/PCA9685/examples/OffTimeSweepSingleDevice/OffTimeSweepSingleDevice.ino new file mode 100644 index 0000000..ffe0f59 --- /dev/null +++ b/INF/libraries/PCA9685/examples/OffTimeSweepSingleDevice/OffTimeSweepSingleDevice.ino @@ -0,0 +1,41 @@ +#include +#include + +#include "Constants.h" + + +PCA9685 pca9685; + +uint16_t time_min; +uint16_t time_max; +uint16_t off_time; + +void setup() +{ + pca9685.setupSingleDevice(Wire,constants::device_address); + + pca9685.setupOutputEnablePin(constants::output_enable_pin); + pca9685.enableOutputs(constants::output_enable_pin); + + pca9685.setOutputsNotInverted(); + + pca9685.setToFrequency(constants::frequency); + + time_min = pca9685.getTimeMin(); + time_max = pca9685.getTimeMax(); + + off_time = time_min; + + pca9685.setChannelOnTime(constants::channel,time_min); +} + +void loop() +{ + if (off_time > time_max) + { + off_time = time_min; + } + pca9685.setChannelOffTime(constants::channel,off_time); + off_time += constants::time_increment; + delay(constants::loop_delay); +} diff --git a/INF/libraries/PCA9685/examples/OnTimeSweepMultipleDevices/Constants.cpp b/INF/libraries/PCA9685/examples/OnTimeSweepMultipleDevices/Constants.cpp new file mode 100644 index 0000000..55aad84 --- /dev/null +++ b/INF/libraries/PCA9685/examples/OnTimeSweepMultipleDevices/Constants.cpp @@ -0,0 +1,28 @@ +// ---------------------------------------------------------------------------- +// Constants.cpp +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#include "Constants.h" + + +namespace constants +{ +const uint8_t device_addresses[DEVICE_COUNT] = +{ + 0x40, + 0x41, + 0x42 +}; +const uint8_t device_index = 0; + +const size_t output_enable_pin = 2; + +const size_t loop_delay = 100; +const uint16_t frequency = 200; +const uint16_t time_increment = 100; + +const uint8_t channel = 0; +} diff --git a/INF/libraries/PCA9685/examples/OnTimeSweepMultipleDevices/Constants.h b/INF/libraries/PCA9685/examples/OnTimeSweepMultipleDevices/Constants.h new file mode 100644 index 0000000..b89390d --- /dev/null +++ b/INF/libraries/PCA9685/examples/OnTimeSweepMultipleDevices/Constants.h @@ -0,0 +1,27 @@ +// ---------------------------------------------------------------------------- +// Constants.h +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#ifndef CONSTANTS_H +#define CONSTANTS_H +#include + + +namespace constants +{ +enum{DEVICE_COUNT=3}; +extern const uint8_t device_addresses[DEVICE_COUNT]; +extern const uint8_t device_index; + +extern const size_t output_enable_pin; + +extern const size_t loop_delay; +extern const uint16_t frequency; +extern const uint16_t time_increment; + +extern const uint8_t channel; +} +#endif diff --git a/INF/libraries/PCA9685/examples/OnTimeSweepMultipleDevices/OnTimeSweepMultipleDevices.ino b/INF/libraries/PCA9685/examples/OnTimeSweepMultipleDevices/OnTimeSweepMultipleDevices.ino new file mode 100644 index 0000000..e00c6ee --- /dev/null +++ b/INF/libraries/PCA9685/examples/OnTimeSweepMultipleDevices/OnTimeSweepMultipleDevices.ino @@ -0,0 +1,46 @@ +#include +#include + +#include "Constants.h" + + +PCA9685 pca9685; + +uint16_t time_min; +uint16_t time_max; +uint16_t on_time; + +void setup() +{ + pca9685.setWire(Wire); + for (uint8_t device_index=0; device_index time_max) + { + on_time = time_min; + } + pca9685.setAllDeviceChannelsOnTime(constants::device_addresses[constants::device_index],on_time); + on_time += constants::time_increment; + delay(constants::loop_delay); +} diff --git a/INF/libraries/PCA9685/examples/ServoController/Constants.cpp b/INF/libraries/PCA9685/examples/ServoController/Constants.cpp new file mode 100644 index 0000000..3c45087 --- /dev/null +++ b/INF/libraries/PCA9685/examples/ServoController/Constants.cpp @@ -0,0 +1,23 @@ +// ---------------------------------------------------------------------------- +// Constants.cpp +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#include "Constants.h" + + +namespace constants +{ +const uint8_t device_address = 0x40; +const size_t output_enable_pin = 2; + +const size_t loop_delay = 100; + +const uint8_t channel = 0; + +const uint16_t servo_pulse_duration_min = 900; +const uint16_t servo_pulse_duration_max = 2100; +const uint16_t servo_pulse_duration_increment = 100; +} diff --git a/INF/libraries/PCA9685/examples/ServoController/Constants.h b/INF/libraries/PCA9685/examples/ServoController/Constants.h new file mode 100644 index 0000000..ffeb5f6 --- /dev/null +++ b/INF/libraries/PCA9685/examples/ServoController/Constants.h @@ -0,0 +1,26 @@ +// ---------------------------------------------------------------------------- +// Constants.h +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#ifndef CONSTANTS_H +#define CONSTANTS_H +#include + + +namespace constants +{ +extern const uint8_t device_address; +extern const size_t output_enable_pin; + +extern const size_t loop_delay; + +extern const uint8_t channel; + +extern const uint16_t servo_pulse_duration_min; +extern const uint16_t servo_pulse_duration_max; +extern const uint16_t servo_pulse_duration_increment; +} +#endif diff --git a/INF/libraries/PCA9685/examples/ServoController/ServoController.ino b/INF/libraries/PCA9685/examples/ServoController/ServoController.ino new file mode 100644 index 0000000..2c907bc --- /dev/null +++ b/INF/libraries/PCA9685/examples/ServoController/ServoController.ino @@ -0,0 +1,32 @@ +#include +#include + +#include "Constants.h" + + +PCA9685 pca9685; + +uint16_t servo_pulse_duration; + +void setup() +{ + pca9685.setupSingleDevice(Wire,constants::device_address); + + pca9685.setupOutputEnablePin(constants::output_enable_pin); + pca9685.enableOutputs(constants::output_enable_pin); + + pca9685.setToServoFrequency(); + + servo_pulse_duration = constants::servo_pulse_duration_min; +} + +void loop() +{ + if (servo_pulse_duration > constants::servo_pulse_duration_max) + { + servo_pulse_duration = constants::servo_pulse_duration_min; + } + pca9685.setChannelServoPulseDuration(constants::channel,servo_pulse_duration); + servo_pulse_duration += constants::servo_pulse_duration_increment; + delay(constants::loop_delay); +} diff --git a/INF/libraries/PCA9685/examples/SetChannelDutyCycle/Constants.cpp b/INF/libraries/PCA9685/examples/SetChannelDutyCycle/Constants.cpp new file mode 100644 index 0000000..4242f9e --- /dev/null +++ b/INF/libraries/PCA9685/examples/SetChannelDutyCycle/Constants.cpp @@ -0,0 +1,41 @@ +// ---------------------------------------------------------------------------- +// Constants.cpp +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#include "Constants.h" + + +namespace constants +{ +const uint8_t device_address = 0x40; +const size_t output_enable_pin = 2; + +const size_t loop_delay = 8000; +const uint16_t frequency = 200; +const uint8_t channel = 0; + +const Example examples[EXAMPLE_COUNT] = +{ + { + 20.0, // DUTY_CYCLE + 10.0, // PERCENT_DELAY + }, + { + 90.0, // DUTY_CYCLE + 90.0, // PERCENT_DELAY + }, + { + // Always ON + 100.0, // DUTY_CYCLE + 0.0, // PERCENT_DELAY + }, + { + // Always OFF + 0.0, // DUTY_CYCLE + 0.0, // PERCENT_DELAY + } +}; +} diff --git a/INF/libraries/PCA9685/examples/SetChannelDutyCycle/Constants.h b/INF/libraries/PCA9685/examples/SetChannelDutyCycle/Constants.h new file mode 100644 index 0000000..31dbc87 --- /dev/null +++ b/INF/libraries/PCA9685/examples/SetChannelDutyCycle/Constants.h @@ -0,0 +1,32 @@ +// ---------------------------------------------------------------------------- +// Constants.h +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#ifndef CONSTANTS_H +#define CONSTANTS_H +#include + + +namespace constants +{ +extern const uint8_t device_address; +extern const size_t output_enable_pin; + +extern const size_t loop_delay; +extern const uint16_t frequency; +extern const uint8_t channel; + +enum{EXAMPLE_COUNT=4}; + +struct Example +{ + double duty_cycle; + double percent_delay; +}; + +extern const Example examples[EXAMPLE_COUNT]; +} +#endif diff --git a/INF/libraries/PCA9685/examples/SetChannelDutyCycle/SetChannelDutyCycle.ino b/INF/libraries/PCA9685/examples/SetChannelDutyCycle/SetChannelDutyCycle.ino new file mode 100644 index 0000000..3fca393 --- /dev/null +++ b/INF/libraries/PCA9685/examples/SetChannelDutyCycle/SetChannelDutyCycle.ino @@ -0,0 +1,33 @@ +#include +#include + +#include "Constants.h" + + +PCA9685 pca9685; + +uint8_t example_index; + +void setup() +{ + pca9685.setupSingleDevice(Wire,constants::device_address); + + pca9685.setupOutputEnablePin(constants::output_enable_pin); + pca9685.enableOutputs(constants::output_enable_pin); + + pca9685.setToFrequency(constants::frequency); + + example_index = 0; +} + +void loop() +{ + delay(constants::loop_delay); + if (example_index >= constants::EXAMPLE_COUNT) + { + example_index = 0; + } + constants::Example example = constants::examples[example_index++]; + + pca9685.setChannelDutyCycle(constants::channel,example.duty_cycle,example.percent_delay); +} diff --git a/INF/libraries/PCA9685/examples/SetChannelOnAndOffTime/Constants.cpp b/INF/libraries/PCA9685/examples/SetChannelOnAndOffTime/Constants.cpp new file mode 100644 index 0000000..eb25a6c --- /dev/null +++ b/INF/libraries/PCA9685/examples/SetChannelOnAndOffTime/Constants.cpp @@ -0,0 +1,43 @@ +// ---------------------------------------------------------------------------- +// Constants.cpp +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#include "Constants.h" + + +namespace constants +{ +const uint8_t device_address = 0x40; +const size_t output_enable_pin = 2; + +const size_t loop_delay = 8000; +const uint16_t frequency = 200; +const uint8_t channel = 0; + +const Example examples[EXAMPLE_COUNT] = +{ + { + // ON_TIME < OFF_TIME + 511, // ON_TIME + 3071, // OFF_TIME + }, + { + // ON_TIME < OFF_TIME + 2047, // ON_TIME + 767, // OFF_TIME + }, + { + // Always ON + 4096, // ON_TIME + 0, // OFF_TIME + }, + { + // Always OFF + 0, // ON_TIME + 4096, // OFF_TIME + } +}; +} diff --git a/INF/libraries/PCA9685/examples/SetChannelOnAndOffTime/Constants.h b/INF/libraries/PCA9685/examples/SetChannelOnAndOffTime/Constants.h new file mode 100644 index 0000000..6dca96e --- /dev/null +++ b/INF/libraries/PCA9685/examples/SetChannelOnAndOffTime/Constants.h @@ -0,0 +1,32 @@ +// ---------------------------------------------------------------------------- +// Constants.h +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#ifndef CONSTANTS_H +#define CONSTANTS_H +#include + + +namespace constants +{ +extern const uint8_t device_address; +extern const size_t output_enable_pin; + +extern const size_t loop_delay; +extern const uint16_t frequency; +extern const uint8_t channel; + +enum{EXAMPLE_COUNT=4}; + +struct Example +{ + uint16_t on_time; + uint16_t off_time; +}; + +extern const Example examples[EXAMPLE_COUNT]; +} +#endif diff --git a/INF/libraries/PCA9685/examples/SetChannelOnAndOffTime/SetChannelOnAndOffTime.ino b/INF/libraries/PCA9685/examples/SetChannelOnAndOffTime/SetChannelOnAndOffTime.ino new file mode 100644 index 0000000..b5d3ac4 --- /dev/null +++ b/INF/libraries/PCA9685/examples/SetChannelOnAndOffTime/SetChannelOnAndOffTime.ino @@ -0,0 +1,33 @@ +#include +#include + +#include "Constants.h" + + +PCA9685 pca9685; + +uint8_t example_index; + +void setup() +{ + pca9685.setupSingleDevice(Wire,constants::device_address); + + pca9685.setupOutputEnablePin(constants::output_enable_pin); + pca9685.enableOutputs(constants::output_enable_pin); + + pca9685.setToFrequency(constants::frequency); + + example_index = 0; +} + +void loop() +{ + delay(constants::loop_delay); + if (example_index >= constants::EXAMPLE_COUNT) + { + example_index = 0; + } + constants::Example example = constants::examples[example_index++]; + + pca9685.setChannelOnAndOffTime(constants::channel,example.on_time,example.off_time); +} diff --git a/INF/libraries/PCA9685/examples/SetChannelPulseWidth/Constants.cpp b/INF/libraries/PCA9685/examples/SetChannelPulseWidth/Constants.cpp new file mode 100644 index 0000000..ccf4c83 --- /dev/null +++ b/INF/libraries/PCA9685/examples/SetChannelPulseWidth/Constants.cpp @@ -0,0 +1,41 @@ +// ---------------------------------------------------------------------------- +// Constants.cpp +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#include "Constants.h" + + +namespace constants +{ +const uint8_t device_address = 0x40; +const size_t output_enable_pin = 2; + +const size_t loop_delay = 8000; +const uint16_t frequency = 200; +const uint8_t channel = 0; + +const Example examples[EXAMPLE_COUNT] = +{ + { + 819, // PULSE_WIDTH + 409, // PHASE_SHIFT + }, + { + 3686, // PULSE_WIDTH + 3685, // PHASE_SHIFT + }, + { + // Always ON + 4096, // PULSE_WIDTH + 0, // PHASE_SHIFT + }, + { + // Always OFF + 0, // PULSE_WIDTH + 0, // PHASE_SHIFT + } +}; +} diff --git a/INF/libraries/PCA9685/examples/SetChannelPulseWidth/Constants.h b/INF/libraries/PCA9685/examples/SetChannelPulseWidth/Constants.h new file mode 100644 index 0000000..c23a555 --- /dev/null +++ b/INF/libraries/PCA9685/examples/SetChannelPulseWidth/Constants.h @@ -0,0 +1,32 @@ +// ---------------------------------------------------------------------------- +// Constants.h +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#ifndef CONSTANTS_H +#define CONSTANTS_H +#include + + +namespace constants +{ +extern const uint8_t device_address; +extern const size_t output_enable_pin; + +extern const size_t loop_delay; +extern const uint16_t frequency; +extern const uint8_t channel; + +enum{EXAMPLE_COUNT=4}; + +struct Example +{ + uint16_t pulse_width; + uint16_t phase_shift; +}; + +extern const Example examples[EXAMPLE_COUNT]; +} +#endif diff --git a/INF/libraries/PCA9685/examples/SetChannelPulseWidth/SetChannelPulseWidth.ino b/INF/libraries/PCA9685/examples/SetChannelPulseWidth/SetChannelPulseWidth.ino new file mode 100644 index 0000000..e34c107 --- /dev/null +++ b/INF/libraries/PCA9685/examples/SetChannelPulseWidth/SetChannelPulseWidth.ino @@ -0,0 +1,33 @@ +#include +#include + +#include "Constants.h" + + +PCA9685 pca9685; + +uint8_t example_index; + +void setup() +{ + pca9685.setupSingleDevice(Wire,constants::device_address); + + pca9685.setupOutputEnablePin(constants::output_enable_pin); + pca9685.enableOutputs(constants::output_enable_pin); + + pca9685.setToFrequency(constants::frequency); + + example_index = 0; +} + +void loop() +{ + delay(constants::loop_delay); + if (example_index >= constants::EXAMPLE_COUNT) + { + example_index = 0; + } + constants::Example example = constants::examples[example_index++]; + + pca9685.setChannelPulseWidth(constants::channel,example.pulse_width,example.phase_shift); +} diff --git a/INF/libraries/PCA9685/examples/TestSetAndGet/Constants.cpp b/INF/libraries/PCA9685/examples/TestSetAndGet/Constants.cpp new file mode 100644 index 0000000..8aeca1e --- /dev/null +++ b/INF/libraries/PCA9685/examples/TestSetAndGet/Constants.cpp @@ -0,0 +1,22 @@ +// ---------------------------------------------------------------------------- +// Constants.cpp +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#include "Constants.h" + + +namespace constants +{ +const uint8_t device_address = 0x40; +const size_t output_enable_pin = 2; + +const long baud = 115200; + +const size_t loop_delay = 100; +const uint16_t frequency = 200; +const uint16_t time_increment = 400; +const double epsilon = 0.001; +} diff --git a/INF/libraries/PCA9685/examples/TestSetAndGet/Constants.h b/INF/libraries/PCA9685/examples/TestSetAndGet/Constants.h new file mode 100644 index 0000000..6f5ae82 --- /dev/null +++ b/INF/libraries/PCA9685/examples/TestSetAndGet/Constants.h @@ -0,0 +1,24 @@ +// ---------------------------------------------------------------------------- +// Constants.h +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#ifndef CONSTANTS_H +#define CONSTANTS_H +#include + + +namespace constants +{ +extern const uint8_t device_address; +extern const size_t output_enable_pin; + +extern const long baud; +extern const size_t loop_delay; +extern const uint16_t frequency; +extern const uint16_t time_increment; +extern const double epsilon; +} +#endif diff --git a/INF/libraries/PCA9685/examples/TestSetAndGet/TestSetAndGet.ino b/INF/libraries/PCA9685/examples/TestSetAndGet/TestSetAndGet.ino new file mode 100644 index 0000000..af6a09e --- /dev/null +++ b/INF/libraries/PCA9685/examples/TestSetAndGet/TestSetAndGet.ino @@ -0,0 +1,105 @@ +#include +#include +#include + +#include "Constants.h" + + +PCA9685 pca9685; + +uint16_t time_min; +uint16_t time_max; + +uint8_t channel; + +uint16_t on_time_set; +uint16_t off_time_set; +uint16_t on_time_get; +uint16_t off_time_get; + +uint16_t pulse_width_set; +uint16_t phase_shift_set; +uint16_t pulse_width_get; +uint16_t phase_shift_get; + +double duty_cycle_set; +double percent_delay_set; +double duty_cycle_get; +double percent_delay_get; + +void setup() +{ + Serial.begin(constants::baud); + + pca9685.setupSingleDevice(Wire,constants::device_address); + + pca9685.setupOutputEnablePin(constants::output_enable_pin); + pca9685.enableOutputs(constants::output_enable_pin); + + pca9685.setOutputsNotInverted(); + + pca9685.setToServoFrequency(); + + time_min = pca9685.getTimeMin(); + time_max = pca9685.getTimeMax(); + + channel = 0; + on_time_set = time_min; + off_time_set = time_max; +} + +void checkMatch(const char * s, bool match) +{ + if (match) + { + Serial << s << " get matches set.\n"; + } + else + { + Serial << s << " get does not match set!\n"; + } +} + +void loop() +{ + if (on_time_set > off_time_set) + { + on_time_set = time_min; + off_time_set = time_max; + } + for (uint8_t channel=0; channel < pca9685.getChannelCount(); ++channel) + { + Serial << "frequency: " << pca9685.getFrequency() << "\n"; + Serial << "channel: " << channel << ", on_time_set: " << on_time_set << ", off_time_set: " << off_time_set << "\n"; + pca9685.setChannelOnAndOffTime(channel,on_time_set,off_time_set); + pca9685.getChannelOnAndOffTime(channel,on_time_get,off_time_get); + checkMatch("ChannelOnAndOffTime",((on_time_set == on_time_get) && (off_time_set == off_time_get))); + + pca9685.setChannelOnTime(channel,on_time_set); + pca9685.getChannelOnTime(channel,on_time_get); + checkMatch("ChannelOnTime",(on_time_set == on_time_get)); + + pca9685.setChannelOffTime(channel,off_time_set); + pca9685.getChannelOffTime(channel,off_time_get); + checkMatch("ChannelOffTime",(off_time_set == off_time_get)); + + pulse_width_set = off_time_set - on_time_set; + phase_shift_set = on_time_set; + Serial << "channel: " << channel << ", pulse_width_set: " << pulse_width_set << ", phase_shift_set: " << phase_shift_set << "\n"; + pca9685.setChannelPulseWidth(channel,pulse_width_set,phase_shift_set); + pca9685.getChannelPulseWidth(channel,pulse_width_get,phase_shift_get); + checkMatch("ChannelPulseWidth",((pulse_width_set == pulse_width_get) && (phase_shift_set == phase_shift_get))); + + duty_cycle_set = (pulse_width_set * pca9685.getDutyCycleMax()) / pca9685.getTimeMax(); + percent_delay_set = (phase_shift_set * pca9685.getPercentDelayMax()) / pca9685.getTimeMax(); + Serial << "channel: " << channel << ", duty_cycle_set: " << duty_cycle_set << ", percent_delay_set: " << percent_delay_set << "\n"; + pca9685.setChannelDutyCycle(channel,duty_cycle_set,percent_delay_set); + pca9685.getChannelDutyCycle(channel,duty_cycle_get,percent_delay_get); + checkMatch("ChannelDutyCycle",((abs(duty_cycle_set - duty_cycle_get) < constants::epsilon) && (abs(percent_delay_set - percent_delay_get) < constants::epsilon))); + + Serial << "\n"; + delay(constants::loop_delay); + } + on_time_set += constants::time_increment; + off_time_set -= constants::time_increment; +} diff --git a/INF/libraries/PCA9685/library.properties b/INF/libraries/PCA9685/library.properties new file mode 100644 index 0000000..3f954db --- /dev/null +++ b/INF/libraries/PCA9685/library.properties @@ -0,0 +1,9 @@ +name=PCA9685 +version=2.1.4 +author=Peter Polidoro +maintainer=Peter Polidoro +sentence=PCA9685 16-channel 12-bit PWM controller. +paragraph=Like this project? Please star it on GitHub! +category=Device Control +url=https://github.com/janelia-arduino/PCA9685.git +architectures=* diff --git a/INF/libraries/PCA9685/src/PCA9685.h b/INF/libraries/PCA9685/src/PCA9685.h new file mode 100644 index 0000000..434b5ac --- /dev/null +++ b/INF/libraries/PCA9685/src/PCA9685.h @@ -0,0 +1,363 @@ +// ---------------------------------------------------------------------------- +// PCA9685.h +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#ifndef PCA9685_H +#define PCA9685_H +#include +#include + + +class PCA9685 +{ +public: + PCA9685(); + + const static uint8_t CHANNELS_PER_DEVICE = 16; + enum {DEVICE_COUNT_MAX=55}; + + // Convenience method when using a single device + void setupSingleDevice(TwoWire & wire=Wire, + uint8_t device_address=0x40, + bool fast_mode_plus=false); + + // Methods for using a single device or multiple devices + void setupOutputEnablePin(size_t output_enable_pin); + void enableOutputs(size_t output_enable_pin); + void disableOutputs(size_t output_enable_pin); + + uint16_t getFrequencyMin(); + uint16_t getFrequencyMax(); + void setToFrequency(uint16_t frequency); + uint16_t getFrequency(); + void setToServoFrequency(); + uint16_t getServoFrequency(); + + uint8_t getChannelCount(); + + double getDutyCycleMin(); + double getDutyCycleMax(); + double getPercentDelayMin(); + double getPercentDelayMax(); + void setChannelDutyCycle(uint8_t channel, + double duty_cycle, + double percent_delay=0); + void getChannelDutyCycle(uint8_t channel, + double & duty_cycle, + double & percent_delay); + void setAllChannelsDutyCycle(double duty_cycle, + double percent_delay=0); + + uint16_t getPulseWidthMin(); + uint16_t getPulseWidthMax(); + uint16_t getPhaseShiftMin(); + uint16_t getPhaseShiftMax(); + void setChannelPulseWidth(uint8_t channel, + uint16_t pulse_width, + uint16_t phase_shift=0); + void getChannelPulseWidth(uint8_t channel, + uint16_t & pulse_width, + uint16_t & phase_shift); + void setAllChannelsPulseWidth(uint16_t pulse_width, + uint16_t phase_shift=0); + + void setChannelServoPulseDuration(uint8_t channel, + uint16_t pulse_duration_microseconds); + void getChannelServoPulseDuration(uint8_t channel, + uint16_t & pulse_duration_microseconds); + void setAllChannelsServoPulseDuration(uint16_t pulse_duration_microseconds); + + uint16_t getTimeMin(); + uint16_t getTimeMax(); + void setChannelOnAndOffTime(uint8_t channel, + uint16_t on_time, + uint16_t off_time); + void getChannelOnAndOffTime(uint8_t channel, + uint16_t & on_time, + uint16_t & off_time); + void setAllChannelsOnAndOffTime(uint16_t on_time, + uint16_t off_time); + void setChannelOnTime(uint8_t channel, + uint16_t on_time); + void getChannelOnTime(uint8_t channel, + uint16_t & on_time); + void setAllChannelsOnTime(uint16_t on_time); + void setChannelOffTime(uint8_t channel, + uint16_t off_time); + void getChannelOffTime(uint8_t channel, + uint16_t & off_time); + void setAllChannelsOffTime(uint16_t off_time); + + void setOutputsInverted(); + void setOutputsNotInverted(); + void setOutputsToTotemPole(); + void setOutputsToOpenDrain(); + void setOutputsLowWhenDisabled(); + void setOutputsHighWhenDisabled(); + void setOutputsHighImpedanceWhenDisabled(); + + // Methods for using multiple devices + // Take care when using fast_mode_plus with non-PCA9685 devices + void setWire(TwoWire & wire=Wire, + bool fast_mode_plus=false); + + // device_address=0x40 when all device address + // hardware select lines are low + // cannot use reserved addresses + void addDevice(uint8_t device_address); + void resetAllDevices(); + + void addDeviceToGroup0(uint8_t device_address); + void removeDeviceFromGroup0(uint8_t device_address); + void addDeviceToGroup1(uint8_t device_address); + void removeDeviceFromGroup1(uint8_t device_address); + void addDeviceToGroup2(uint8_t device_address); + void removeDeviceFromGroup2(uint8_t device_address); + + void setSingleDeviceToFrequency(uint8_t device_address, + uint16_t frequency); + uint16_t getSingleDeviceFrequency(uint8_t device_address); + void setAllDevicesToFrequency(uint16_t frequency); + void setSingleDeviceToServoFrequency(uint8_t device_address); + uint16_t getSingleDeviceServoFrequency(uint8_t device_address); + void setAllDevicesToServoFrequency(); + + uint8_t getDeviceChannelCount(); + + // Use these device address to set more than one device at a time + // with the methods below + const static uint8_t DEVICE_ADDRESS_ALL = 0x70; + const static uint8_t DEVICE_ADDRESS_GROUP0 = 0x71; + const static uint8_t DEVICE_ADDRESS_GROUP1 = 0x72; + const static uint8_t DEVICE_ADDRESS_GROUP2 = 0x73; + + void setDeviceChannelDutyCycle(uint8_t device_address, + uint8_t device_channel, + double duty_cycle, + double percent_delay=0); + void setAllDeviceChannelsDutyCycle(uint8_t device_address, + double duty_cycle, + double percent_delay=0); + + void setDeviceChannelPulseWidth(uint8_t device_address, + uint8_t device_channel, + uint16_t pulse_width, + uint16_t phase_shift=0); + void setAllDeviceChannelsPulseWidth(uint8_t device_address, + uint16_t pulse_width, + uint16_t phase_shift=0); + + void setDeviceChannelServoPulseDuration(uint8_t device_address, + uint8_t device_channel, + uint16_t pulse_duration_microseconds); + void setAllDeviceChannelsServoPulseDuration(uint8_t device_address, + uint16_t pulse_duration_microseconds); + + void setDeviceChannelOnAndOffTime(uint8_t device_address, + uint8_t device_channel, + uint16_t on_time, + uint16_t off_time); + void setAllDeviceChannelsOnAndOffTime(uint8_t device_address, + uint16_t on_time, + uint16_t off_time); + void setDeviceChannelOnTime(uint8_t device_address, + uint8_t device_channel, + uint16_t on_time); + void setAllDeviceChannelsOnTime(uint8_t device_address, + uint16_t on_time); + void setDeviceChannelOffTime(uint8_t device_address, + uint8_t device_channel, + uint16_t off_time); + void setAllDeviceChannelsOffTime(uint8_t device_address, + uint16_t off_time); + + void setSingleDeviceOutputsInverted(uint8_t device_address); + void setAllDevicesOutputsInverted(); + void setSingleDeviceOutputsNotInverted(uint8_t device_address); + void setAllDevicesOutputsNotInverted(); + void setSingleDeviceOutputsToTotemPole(uint8_t device_address); + void setAllDevicesOutputsToTotemPole(); + void setSingleDeviceOutputsToOpenDrain(uint8_t device_address); + void setAllDevicesOutputsToOpenDrain(); + void setSingleDeviceOutputsLowWhenDisabled(uint8_t device_address); + void setAllDevicesOutputsLowWhenDisabled(); + void setSingleDeviceOutputsHighWhenDisabled(uint8_t device_address); + void setAllDevicesOutputsHighWhenDisabled(); + void setSingleDeviceOutputsHighImpedanceWhenDisabled(uint8_t device_address); + void setAllDevicesOutputsHighImpedanceWhenDisabled(); + +private: + const static uint8_t DEVICE_ADDRESS_MIN = 0x40; + const static uint8_t DEVICE_ADDRESS_MAX = 0x7B; + uint8_t device_count_; + uint8_t device_addresses_[DEVICE_COUNT_MAX]; + + TwoWire * wire_ptr_; + const static long FAST_MODE_PLUS_CLOCK_FREQUENCY = 1000000; + + const static int NO_OUTPUT_ENABLE_PIN = -1; + + const static int DEVICE_INDEX_NONE = -1; + const static int DEVICE_INDEX_ALL = -2; + const static int DEVICE_INDEX_GROUP0 = -3; + const static int DEVICE_INDEX_GROUP1 = -4; + const static int DEVICE_INDEX_GROUP2 = -5; + int deviceAddressToDeviceIndex(uint8_t device_address); + + const static uint8_t GENERAL_CALL_DEVICE_ADDRESS = 0x00; + const static uint8_t SWRST = 0b110; + + // Can write to one or more device at a time + // so use address rather than index + template + void write(uint8_t device_address, + uint8_t register_address, + T data); + // Can only read from one device at a time + // so use index rather than address + template + void read(uint8_t device_index, + uint8_t register_address, + T & data); + + const static uint8_t MODE1_REGISTER_ADDRESS = 0x00; + union Mode1Register + { + struct + { + uint8_t allcall : 1; + uint8_t sub3 : 1; + uint8_t sub2 : 1; + uint8_t sub1 : 1; + uint8_t sleep : 1; + uint8_t ai : 1; + uint8_t extclk : 1; + uint8_t restart : 1; + } fields; + uint8_t data; + }; + Mode1Register readMode1Register(uint8_t device_index); + + const static uint8_t MODE2_REGISTER_ADDRESS = 0x01; + union Mode2Register + { + struct + { + uint8_t outne : 2; + uint8_t outdrv : 1; + uint8_t och : 1; + uint8_t invrt : 1; + uint8_t space : 3; + } fields; + uint8_t data; + }; + Mode2Register readMode2Register(uint8_t device_index); + + void sleep(uint8_t device_index); + void wake(uint8_t device_index); + void wakeAll(); + + void setPrescale(uint8_t device_index, + uint8_t prescale); + void getPrescale(uint8_t device_index, + uint8_t & prescale); + uint8_t frequencyToPrescale(uint16_t frequency); + uint16_t prescaleToFrequency(uint8_t prescale); + + uint8_t channelToDeviceIndex(uint8_t channel); + uint8_t channelToDeviceChannel(uint8_t channel); + + void dutyCycleAndPercentDelayToPulseWidthAndPhaseShift(double duty_cycle, + double percent_delay, + uint16_t & pulse_width, + uint16_t & phase_shift); + void pulseWidthAndPhaseShiftToDutyCycleAndPercentDelay(uint16_t pulse_width, + uint16_t phase_shift, + double & duty_cycle, + double & percent_delay); + + void pulseWidthAndPhaseShiftToOnTimeAndOffTime(uint16_t pulse_width, + uint16_t phase_shift, + uint16_t & on_time, + uint16_t & off_time); + void onTimeAndOffTimeToPulseWidthAndPhaseShift(uint16_t on_time, + uint16_t off_time, + uint16_t & pulse_width, + uint16_t & phase_shift); + + void servoPulseDurationToPulseWidthAndPhaseShift(uint16_t pulse_duration_microseconds, + uint16_t & pulse_width, + uint16_t & phase_shift); + void pulseWidthAndPhaseShiftToServoPulseDuration(uint16_t pulse_width, + uint16_t phase_shift, + uint16_t & pulse_duration_microseconds); + + void setOutputsInverted(uint8_t device_index); + void setOutputsNotInverted(uint8_t device_index); + void setOutputsToTotemPole(uint8_t device_index); + void setOutputsToOpenDrain(uint8_t device_index); + void setOutputsLowWhenDisabled(uint8_t device_index); + void setOutputsHighWhenDisabled(uint8_t device_index); + void setOutputsHighImpedanceWhenDisabled(uint8_t device_index); + + const static uint8_t DOES_NOT_RESPOND = 0; + const static uint8_t DOES_RESPOND = 1; + const static uint8_t SUBADR1_REGISTER_ADDRESS = 0x02; + const static uint8_t SUBADR2_REGISTER_ADDRESS = 0x03; + const static uint8_t SUBADR3_REGISTER_ADDRESS = 0x04; + const static uint8_t ALLCALLADR_REGISTER_ADDRESS = 0x05; + + const static uint8_t LED0_ON_L_REGISTER_ADDRESS = 0x06; + const static uint8_t LED0_OFF_L_REGISTER_ADDRESS = 0x08; + const static uint8_t ALL_LED_ON_L_REGISTER_ADDRESS = 0xFA; + const static uint8_t ALL_LED_OFF_L_REGISTER_ADDRESS = 0xFC; + const static uint8_t LED_REGISTERS_SIZE = 4; + const static uint8_t BITS_PER_BYTE = 8; + const static uint8_t BITS_PER_TWO_BYTES = 16; + const static uint8_t BYTE_MAX = 0xFF; + const static uint16_t TWO_BYTE_MAX = 0xFFFF; + + const static uint8_t PRE_SCALE_REGISTER_ADDRESS = 0xFE; + const static uint8_t PRE_SCALE_MIN = 0x03; + const static uint8_t PRE_SCALE_MAX = 0xFF; + // Use period instead of frequency to calculate prescale since it is linear + // Measured 1620 Hz at prescale value 0x03, 1E6/1620=617 + // Datasheet says it should be 1526 Hz, 1E6/1526=655 + const static uint16_t PWM_PERIOD_MIN_US = 617; + // Measured 25.3 Hz at prescale value 0xFF, 1E6/25.3=39525 + // Datasheet says it should be 24 Hz, 1E6/24=41666 + const static uint16_t PWM_PERIOD_MAX_US = 39525; + const static uint32_t MICROSECONDS_PER_SECOND = 1000000; + + const static uint8_t OUTPUTS_INVERTED = 1; + const static uint8_t OUTPUTS_NOT_INVERTED = 0; + const static uint8_t OUTPUTS_TOTEM_POLE = 1; + const static uint8_t OUTPUTS_OPEN_DRAIN = 0; + const static uint8_t OUTPUTS_LOW_WHEN_DISABLED = 0b00; + const static uint8_t OUTPUTS_HIGH_WHEN_DISABLED = 0b01; + const static uint8_t OUTPUTS_HIGH_IMPEDANCE_WHEN_DISABLED = 0b10; + + const static uint8_t SLEEP = 1; + const static uint8_t WAKE = 0; + const static uint8_t AUTO_INCREMENT_ENABLED = 1; + const static uint8_t AUTO_INCREMENT_DISABLED = 0; + const static uint8_t RESTART_ENABLED = 1; + const static uint8_t RESTART_DISABLED = 0; + const static uint8_t RESTART_CLEAR = 1; + + const static uint16_t TIME_MIN = 0; + const static uint16_t TIME_MAX = 4096; + + const static uint8_t PERCENT_MIN = 0; + const static uint8_t PERCENT_MAX = 100; + + const static uint16_t SERVO_FREQUENCY = 50; + const static uint16_t SERVO_PERIOD_MICROSECONDS = 20000; + +}; + +#include "PCA9685/PCA9685Definitions.h" + +#endif diff --git a/INF/libraries/PCA9685/src/PCA9685/PCA9685.cpp b/INF/libraries/PCA9685/src/PCA9685/PCA9685.cpp new file mode 100644 index 0000000..15761d5 --- /dev/null +++ b/INF/libraries/PCA9685/src/PCA9685/PCA9685.cpp @@ -0,0 +1,1005 @@ +// ---------------------------------------------------------------------------- +// PCA9685.cpp +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#include "PCA9685.h" + + +PCA9685::PCA9685() +{ + device_count_ = 0; + for (uint8_t device_index=0; device_index 0) + { + frequency = getSingleDeviceFrequency(device_addresses_[0]); + } + return frequency; +} + +void PCA9685::setToServoFrequency() +{ + setAllDevicesToServoFrequency(); +} + +uint16_t PCA9685::getServoFrequency() +{ + return SERVO_FREQUENCY; +} + +uint8_t PCA9685::getChannelCount() +{ + return CHANNELS_PER_DEVICE * device_count_; +} + +double PCA9685::getDutyCycleMin() +{ + return PERCENT_MIN; +} + +double PCA9685::getDutyCycleMax() +{ + return PERCENT_MAX; +} + +double PCA9685::getPercentDelayMin() +{ + return PERCENT_MIN; +} + +double PCA9685::getPercentDelayMax() +{ + return PERCENT_MAX; +} + +void PCA9685::setChannelDutyCycle(uint8_t channel, + double duty_cycle, + double percent_delay) +{ + uint16_t pulse_width; + uint16_t phase_shift; + dutyCycleAndPercentDelayToPulseWidthAndPhaseShift(duty_cycle,percent_delay,pulse_width,phase_shift); + setChannelPulseWidth(channel,pulse_width,phase_shift); +} + +void PCA9685::getChannelDutyCycle(uint8_t channel, + double & duty_cycle, + double & percent_delay) +{ + uint16_t pulse_width; + uint16_t phase_shift; + getChannelPulseWidth(channel,pulse_width,phase_shift); + pulseWidthAndPhaseShiftToDutyCycleAndPercentDelay(pulse_width,phase_shift,duty_cycle,percent_delay); +} + +void PCA9685::setAllChannelsDutyCycle(double duty_cycle, + double percent_delay) +{ + setAllDeviceChannelsDutyCycle(DEVICE_ADDRESS_ALL,duty_cycle,percent_delay); +} + +uint16_t PCA9685::getPulseWidthMin() +{ + return TIME_MIN; +} + +uint16_t PCA9685::getPulseWidthMax() +{ + return TIME_MAX; +} + +uint16_t PCA9685::getPhaseShiftMin() +{ + return TIME_MIN; +} + +uint16_t PCA9685::getPhaseShiftMax() +{ + return 0xFFFF; +} + +void PCA9685::setChannelPulseWidth(uint8_t channel, + uint16_t pulse_width, + uint16_t phase_shift) +{ + uint16_t on_time; + uint16_t off_time; + pulseWidthAndPhaseShiftToOnTimeAndOffTime(pulse_width,phase_shift,on_time,off_time); + setChannelOnAndOffTime(channel,on_time,off_time); +} + +void PCA9685::getChannelPulseWidth(uint8_t channel, + uint16_t & pulse_width, + uint16_t & phase_shift) +{ + uint16_t on_time = 0; + uint16_t off_time = 0; + getChannelOnAndOffTime(channel,on_time,off_time); + onTimeAndOffTimeToPulseWidthAndPhaseShift(on_time,off_time,pulse_width,phase_shift); +} + +void PCA9685::setAllChannelsPulseWidth(uint16_t pulse_width, + uint16_t phase_shift) +{ + setAllDeviceChannelsPulseWidth(DEVICE_ADDRESS_ALL,pulse_width,phase_shift); +} + +void PCA9685::setChannelServoPulseDuration(uint8_t channel, + uint16_t pulse_duration_microseconds) +{ + uint16_t pulse_width; + uint16_t phase_shift; + servoPulseDurationToPulseWidthAndPhaseShift(pulse_duration_microseconds,pulse_width,phase_shift); + setChannelPulseWidth(channel,pulse_width,phase_shift); +} + +void PCA9685::getChannelServoPulseDuration(uint8_t channel, + uint16_t & pulse_duration_microseconds) +{ + uint16_t pulse_width; + uint16_t phase_shift; + getChannelPulseWidth(channel,pulse_width,phase_shift); + pulseWidthAndPhaseShiftToServoPulseDuration(pulse_width,phase_shift,pulse_duration_microseconds); +} + +void PCA9685::setAllChannelsServoPulseDuration(uint16_t pulse_duration_microseconds) +{ + setAllDeviceChannelsServoPulseDuration(DEVICE_ADDRESS_ALL,pulse_duration_microseconds); +} + +uint16_t PCA9685::getTimeMin() +{ + return TIME_MIN; +} + +uint16_t PCA9685::getTimeMax() +{ + return TIME_MAX; +} + +void PCA9685::setChannelOnAndOffTime(uint8_t channel, + uint16_t on_time, + uint16_t off_time) +{ + if (channel >= getChannelCount()) + { + return; + } + uint8_t device_index = channelToDeviceIndex(channel); + uint8_t device_channel = channelToDeviceChannel(channel); + uint8_t register_address = LED0_ON_L_REGISTER_ADDRESS + LED_REGISTERS_SIZE * device_channel; + uint32_t data = (off_time << BITS_PER_TWO_BYTES) | on_time; + write(device_addresses_[device_index],register_address,data); +} + +void PCA9685::getChannelOnAndOffTime(uint8_t channel, + uint16_t & on_time, + uint16_t & off_time) +{ + if (channel >= getChannelCount()) + { + return; + } + uint8_t device_index = channelToDeviceIndex(channel); + uint8_t device_channel = channelToDeviceChannel(channel); + uint8_t register_address = LED0_ON_L_REGISTER_ADDRESS + LED_REGISTERS_SIZE * device_channel; + uint32_t data; + read(device_index,register_address,data); + on_time = data & TWO_BYTE_MAX; + off_time = (data >> BITS_PER_TWO_BYTES) & TWO_BYTE_MAX; +} + +void PCA9685::setAllChannelsOnAndOffTime(uint16_t on_time, + uint16_t off_time) +{ + setAllDeviceChannelsOnAndOffTime(DEVICE_ADDRESS_ALL,on_time,off_time); +} + +void PCA9685::setChannelOnTime(uint8_t channel, + uint16_t on_time) +{ + if (channel >= getChannelCount()) + { + return; + } + uint8_t device_index = channelToDeviceIndex(channel); + uint8_t device_channel = channelToDeviceChannel(channel); + uint8_t register_address = LED0_ON_L_REGISTER_ADDRESS + LED_REGISTERS_SIZE * device_channel; + write(device_addresses_[device_index],register_address,on_time); +} + +void PCA9685::getChannelOnTime(uint8_t channel, + uint16_t & on_time) +{ + if (channel >= getChannelCount()) + { + return; + } + uint8_t device_index = channelToDeviceIndex(channel); + uint8_t device_channel = channelToDeviceChannel(channel); + uint8_t register_address = LED0_ON_L_REGISTER_ADDRESS + LED_REGISTERS_SIZE * device_channel; + read(device_index,register_address,on_time); +} + +void PCA9685::setAllChannelsOnTime(uint16_t on_time) +{ + setAllDeviceChannelsOnTime(DEVICE_ADDRESS_ALL,on_time); +} + +void PCA9685::setChannelOffTime(uint8_t channel, + uint16_t off_time) +{ + if (channel >= getChannelCount()) + { + return; + } + uint8_t device_index = channelToDeviceIndex(channel); + uint8_t device_channel = channelToDeviceChannel(channel); + uint8_t register_address = LED0_OFF_L_REGISTER_ADDRESS + LED_REGISTERS_SIZE * device_channel; + write(device_addresses_[device_index],register_address,off_time); +} + +void PCA9685::getChannelOffTime(uint8_t channel, + uint16_t & off_time) +{ + if (channel >= getChannelCount()) + { + return; + } + uint8_t device_index = channelToDeviceIndex(channel); + uint8_t device_channel = channelToDeviceChannel(channel); + uint8_t register_address = LED0_OFF_L_REGISTER_ADDRESS + LED_REGISTERS_SIZE * device_channel; + read(device_index,register_address,off_time); +} + +void PCA9685::setAllChannelsOffTime(uint16_t off_time) +{ + setAllDeviceChannelsOffTime(DEVICE_ADDRESS_ALL,off_time); +} + +void PCA9685::setOutputsInverted() +{ + setAllDevicesOutputsInverted(); +} + +void PCA9685::setOutputsNotInverted() +{ + setAllDevicesOutputsNotInverted(); +} + +void PCA9685::setOutputsToTotemPole() +{ + setAllDevicesOutputsToTotemPole(); +} + +void PCA9685::setOutputsToOpenDrain() +{ + setAllDevicesOutputsToOpenDrain(); +} + +void PCA9685::setOutputsLowWhenDisabled() +{ + setAllDevicesOutputsLowWhenDisabled(); +} + +void PCA9685::setOutputsHighWhenDisabled() +{ + setAllDevicesOutputsHighWhenDisabled(); +} + +void PCA9685::setOutputsHighImpedanceWhenDisabled() +{ + setAllDevicesOutputsHighImpedanceWhenDisabled(); +} + +void PCA9685::setWire(TwoWire & wire, + bool fast_mode_plus) +{ + wire_ptr_ = &wire; + wire_ptr_->begin(); + if (fast_mode_plus) + { + wire_ptr_->setClock(FAST_MODE_PLUS_CLOCK_FREQUENCY); + } + +} + +void PCA9685::addDevice(uint8_t device_address) +{ + if ((device_count_ >= DEVICE_COUNT_MAX) || + (device_address < DEVICE_ADDRESS_MIN) || + (device_address > DEVICE_ADDRESS_MAX)) + { + return; + } + int device_index = deviceAddressToDeviceIndex(device_address); + if (device_index != DEVICE_INDEX_NONE) + { + return; + } + device_addresses_[device_count_++] = device_address; +} + +void PCA9685::resetAllDevices() +{ + wire_ptr_->beginTransmission(GENERAL_CALL_DEVICE_ADDRESS); + wire_ptr_->write(SWRST); + wire_ptr_->endTransmission(); + delay(10); + wakeAll(); +} + +void PCA9685::addDeviceToGroup0(uint8_t device_address) +{ + int device_index = deviceAddressToDeviceIndex(device_address); + if (device_index < 0) + { + return; + } + Mode1Register mode1_register = readMode1Register(device_index); + mode1_register.fields.sub1 = DOES_RESPOND; + write(device_address,MODE1_REGISTER_ADDRESS,mode1_register.data); +} + +void PCA9685::removeDeviceFromGroup0(uint8_t device_address) +{ + int device_index = deviceAddressToDeviceIndex(device_address); + if (device_index < 0) + { + return; + } + Mode1Register mode1_register = readMode1Register(device_index); + mode1_register.fields.sub1 = DOES_NOT_RESPOND; + write(device_address,MODE1_REGISTER_ADDRESS,mode1_register.data); +} + +void PCA9685::addDeviceToGroup1(uint8_t device_address) +{ + int device_index = deviceAddressToDeviceIndex(device_address); + if (device_index < 0) + { + return; + } + Mode1Register mode1_register = readMode1Register(device_index); + mode1_register.fields.sub2 = DOES_RESPOND; + write(device_address,MODE1_REGISTER_ADDRESS,mode1_register.data); +} + +void PCA9685::removeDeviceFromGroup1(uint8_t device_address) +{ + int device_index = deviceAddressToDeviceIndex(device_address); + if (device_index < 0) + { + return; + } + Mode1Register mode1_register = readMode1Register(device_index); + mode1_register.fields.sub2 = DOES_NOT_RESPOND; + write(device_address,MODE1_REGISTER_ADDRESS,mode1_register.data); +} + +void PCA9685::addDeviceToGroup2(uint8_t device_address) +{ + int device_index = deviceAddressToDeviceIndex(device_address); + if (device_index < 0) + { + return; + } + Mode1Register mode1_register = readMode1Register(device_index); + mode1_register.fields.sub3 = DOES_RESPOND; + write(device_address,MODE1_REGISTER_ADDRESS,mode1_register.data); +} + +void PCA9685::removeDeviceFromGroup2(uint8_t device_address) +{ + int device_index = deviceAddressToDeviceIndex(device_address); + if (device_index < 0) + { + return; + } + Mode1Register mode1_register = readMode1Register(device_index); + mode1_register.fields.sub3 = DOES_NOT_RESPOND; + write(device_address,MODE1_REGISTER_ADDRESS,mode1_register.data); +} + +void PCA9685::setSingleDeviceToFrequency(uint8_t device_address, + uint16_t frequency) +{ + int device_index = deviceAddressToDeviceIndex(device_address); + if (device_index < 0) + { + return; + } + uint8_t prescale = frequencyToPrescale(frequency); + setPrescale(device_index,prescale); +} + +uint16_t PCA9685::getSingleDeviceFrequency(uint8_t device_address) +{ + uint16_t frequency = 0; + int device_index = deviceAddressToDeviceIndex(device_address); + if (device_index >= 0) + { + uint8_t prescale; + getPrescale(device_index,prescale); + frequency = prescaleToFrequency(prescale); + } + return frequency; +} + +void PCA9685::setAllDevicesToFrequency(uint16_t frequency) +{ + uint8_t prescale = frequencyToPrescale(frequency); + for (uint8_t device_index=0; device_index= getDeviceChannelCount()) + { + return; + } + uint8_t register_address = LED0_ON_L_REGISTER_ADDRESS + LED_REGISTERS_SIZE * device_channel; + uint32_t data = (off_time << BITS_PER_TWO_BYTES) | on_time; + write(device_address,register_address,data); +} + +void PCA9685::setAllDeviceChannelsOnAndOffTime(uint8_t device_address, + uint16_t on_time, + uint16_t off_time) +{ + uint8_t register_address = ALL_LED_ON_L_REGISTER_ADDRESS; + uint32_t data = (off_time << BITS_PER_TWO_BYTES) | on_time; + write(device_address,register_address,data); +} + +void PCA9685::setDeviceChannelOnTime(uint8_t device_address, + uint8_t device_channel, + uint16_t on_time) +{ + if (device_channel >= getDeviceChannelCount()) + { + return; + } + uint8_t register_address = LED0_ON_L_REGISTER_ADDRESS + LED_REGISTERS_SIZE * device_channel; + write(device_address,register_address,on_time); +} + +void PCA9685::setAllDeviceChannelsOnTime(uint8_t device_address, + uint16_t on_time) +{ + uint8_t register_address = ALL_LED_ON_L_REGISTER_ADDRESS; + write(device_address,register_address,on_time); +} + +void PCA9685::setDeviceChannelOffTime(uint8_t device_address, + uint8_t device_channel, + uint16_t off_time) +{ + if (device_channel >= getDeviceChannelCount()) + { + return; + } + uint8_t register_address = LED0_OFF_L_REGISTER_ADDRESS + LED_REGISTERS_SIZE * device_channel; + write(device_address,register_address,off_time); +} + +void PCA9685::setAllDeviceChannelsOffTime(uint8_t device_address, + uint16_t off_time) +{ + uint8_t register_address = ALL_LED_OFF_L_REGISTER_ADDRESS; + write(device_address,register_address,off_time); +} + +void PCA9685::setSingleDeviceOutputsInverted(uint8_t device_address) +{ + int device_index = deviceAddressToDeviceIndex(device_address); + if (device_index < 0) + { + return; + } + setOutputsInverted(device_index); +} + +void PCA9685::setAllDevicesOutputsInverted() +{ + for (uint8_t device_index=0; device_index 0) + { + frequency = round((double)MICROSECONDS_PER_SECOND / (double)period_us); + } + return frequency; +} + +uint8_t PCA9685::channelToDeviceIndex(uint8_t channel) +{ + return channel / CHANNELS_PER_DEVICE; +} + +uint8_t PCA9685::channelToDeviceChannel(uint8_t channel) +{ + return channel % CHANNELS_PER_DEVICE; +} + +void PCA9685::dutyCycleAndPercentDelayToPulseWidthAndPhaseShift(double duty_cycle, + double percent_delay, + uint16_t & pulse_width, + uint16_t & phase_shift) +{ + pulse_width = round(((double)TIME_MAX * duty_cycle) / (double)PERCENT_MAX); + phase_shift = round(((double)TIME_MAX * percent_delay) / (double)PERCENT_MAX); +} + +void PCA9685::pulseWidthAndPhaseShiftToDutyCycleAndPercentDelay(uint16_t pulse_width, + uint16_t phase_shift, + double & duty_cycle, + double & percent_delay) +{ + duty_cycle = (double)(pulse_width * PERCENT_MAX) / (double)TIME_MAX; + percent_delay = (double)(phase_shift * PERCENT_MAX) / (double)TIME_MAX; +} + +void PCA9685::pulseWidthAndPhaseShiftToOnTimeAndOffTime(uint16_t pulse_width, + uint16_t phase_shift, + uint16_t & on_time, + uint16_t & off_time) +{ + if (pulse_width == TIME_MIN) + { + on_time = TIME_MIN; + off_time = TIME_MAX; + return; + } + if (pulse_width >= TIME_MAX) + { + on_time = TIME_MAX; + off_time = TIME_MIN; + return; + } + on_time = phase_shift % TIME_MAX; + off_time = (on_time + pulse_width) % TIME_MAX; +} + +void PCA9685::onTimeAndOffTimeToPulseWidthAndPhaseShift(uint16_t on_time, + uint16_t off_time, + uint16_t & pulse_width, + uint16_t & phase_shift) +{ + if (on_time == TIME_MAX) + { + pulse_width = TIME_MAX; + phase_shift = TIME_MIN; + return; + } + if (off_time == TIME_MAX) + { + pulse_width = TIME_MIN; + phase_shift = TIME_MIN; + return; + } + if (on_time > off_time) + { + pulse_width = TIME_MAX - (on_time - off_time); + phase_shift = on_time; + return; + } + pulse_width = off_time - on_time; + phase_shift = on_time; +} + +void PCA9685::servoPulseDurationToPulseWidthAndPhaseShift(uint16_t pulse_duration_microseconds, + uint16_t & pulse_width, + uint16_t & phase_shift) +{ + phase_shift = 0; + pulse_width = (pulse_duration_microseconds * TIME_MAX) / SERVO_PERIOD_MICROSECONDS; +} + +void PCA9685::pulseWidthAndPhaseShiftToServoPulseDuration(uint16_t pulse_width, + uint16_t phase_shift, + uint16_t & pulse_duration_microseconds) +{ + uint16_t period_us = SERVO_PERIOD_MICROSECONDS; + pulse_duration_microseconds = (pulse_width * period_us) / TIME_MAX; +} + +void PCA9685::setOutputsInverted(uint8_t device_index) +{ + Mode2Register mode2_register = readMode2Register(device_index); + mode2_register.fields.invrt = OUTPUTS_INVERTED; + write(device_addresses_[device_index],MODE2_REGISTER_ADDRESS,mode2_register.data); +} + +void PCA9685::setOutputsNotInverted(uint8_t device_index) +{ + Mode2Register mode2_register = readMode2Register(device_index); + mode2_register.fields.invrt = OUTPUTS_NOT_INVERTED; + write(device_addresses_[device_index],MODE2_REGISTER_ADDRESS,mode2_register.data); +} + +void PCA9685::setOutputsToTotemPole(uint8_t device_index) +{ + Mode2Register mode2_register = readMode2Register(device_index); + mode2_register.fields.outdrv = OUTPUTS_TOTEM_POLE; + write(device_addresses_[device_index],MODE2_REGISTER_ADDRESS,mode2_register.data); +} + +void PCA9685::setOutputsToOpenDrain(uint8_t device_index) +{ + Mode2Register mode2_register = readMode2Register(device_index); + mode2_register.fields.outdrv = OUTPUTS_OPEN_DRAIN; + write(device_addresses_[device_index],MODE2_REGISTER_ADDRESS,mode2_register.data); +} + +void PCA9685::setOutputsLowWhenDisabled(uint8_t device_index) +{ + Mode2Register mode2_register = readMode2Register(device_index); + mode2_register.fields.outne = OUTPUTS_LOW_WHEN_DISABLED; + write(device_addresses_[device_index],MODE2_REGISTER_ADDRESS,mode2_register.data); +} + +void PCA9685::setOutputsHighWhenDisabled(uint8_t device_index) +{ + Mode2Register mode2_register = readMode2Register(device_index); + mode2_register.fields.outne = OUTPUTS_HIGH_WHEN_DISABLED; + write(device_addresses_[device_index],MODE2_REGISTER_ADDRESS,mode2_register.data); +} + +void PCA9685::setOutputsHighImpedanceWhenDisabled(uint8_t device_index) +{ + Mode2Register mode2_register = readMode2Register(device_index); + mode2_register.fields.outne = OUTPUTS_HIGH_IMPEDANCE_WHEN_DISABLED; + write(device_addresses_[device_index],MODE2_REGISTER_ADDRESS,mode2_register.data); +} diff --git a/INF/libraries/PCA9685/src/PCA9685/PCA9685Definitions.h b/INF/libraries/PCA9685/src/PCA9685/PCA9685Definitions.h new file mode 100644 index 0000000..be8cb60 --- /dev/null +++ b/INF/libraries/PCA9685/src/PCA9685/PCA9685Definitions.h @@ -0,0 +1,46 @@ +// ---------------------------------------------------------------------------- +// PCA9685.h +// +// +// Authors: +// Peter Polidoro peterpolidoro@gmail.com +// ---------------------------------------------------------------------------- +#ifndef PCA9685_DEFINITIONS_H +#define PCA9685_DEFINITIONS_H + + +template +void PCA9685::write(uint8_t device_address, + uint8_t register_address, + T data) +{ + int byte_count = sizeof(data); + wire_ptr_->beginTransmission(device_address); + wire_ptr_->write(register_address); + for (int byte_n=0; byte_nwrite((data >> (BITS_PER_BYTE * byte_n)) & BYTE_MAX); + } + wire_ptr_->endTransmission(); +} + +template +void PCA9685::read(uint8_t device_index, + uint8_t register_address, + T & data) +{ + int byte_count = sizeof(data); + int device_address = device_addresses_[device_index]; + wire_ptr_->beginTransmission(device_address); + wire_ptr_->write(register_address); + wire_ptr_->endTransmission(); + + wire_ptr_->requestFrom(device_address,byte_count); + data = 0; + for (int byte_n=0; byte_nread()) << (BITS_PER_BYTE * byte_n); + } +} + +#endif