удалила непонятные примеры
This commit is contained in:
parent
d9cc0d0988
commit
959016ad61
@ -1,234 +0,0 @@
|
||||
/*
|
||||
* ADCUtils.h
|
||||
*
|
||||
* Copyright (C) 2016-2022 Armin Joachimsmeyer
|
||||
* Email: armin.joachimsmeyer@gmail.com
|
||||
*
|
||||
* This file is part of Arduino-Utils https://github.com/ArminJo/Arduino-Utils.
|
||||
*
|
||||
* ArduinoUtils is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ADC_UTILS_H
|
||||
#define _ADC_UTILS_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#if defined(__AVR__) && defined(ADCSRA) && defined(ADATE) && (!defined(__AVR_ATmega4809__))
|
||||
#define ADC_UTILS_ARE_AVAILABLE
|
||||
|
||||
// PRESCALE4 => 13 * 4 = 52 microseconds per ADC conversion at 1 MHz Clock => 19,2 kHz
|
||||
#define ADC_PRESCALE2 1 // 26 microseconds per ADC conversion at 1 MHz
|
||||
#define ADC_PRESCALE4 2 // 52 microseconds per ADC conversion at 1 MHz
|
||||
// PRESCALE8 => 13 * 8 = 104 microseconds per ADC sample at 1 MHz Clock => 9,6 kHz
|
||||
#define ADC_PRESCALE8 3 // 104 microseconds per ADC conversion at 1 MHz
|
||||
#define ADC_PRESCALE16 4 // 13/208 microseconds per ADC conversion at 16/1 MHz - degradations in linearity at 16 MHz
|
||||
#define ADC_PRESCALE32 5 // 26/416 microseconds per ADC conversion at 16/1 MHz - very good linearity at 16 MHz
|
||||
#define ADC_PRESCALE64 6 // 52 microseconds per ADC conversion at 16 MHz
|
||||
#define ADC_PRESCALE128 7 // 104 microseconds per ADC conversion at 16 MHz --- Arduino default
|
||||
|
||||
// definitions for 0.1 ms conversion time
|
||||
#if (F_CPU == 1000000)
|
||||
#define ADC_PRESCALE ADC_PRESCALE8
|
||||
#elif (F_CPU == 8000000)
|
||||
#define ADC_PRESCALE ADC_PRESCALE64
|
||||
#elif (F_CPU == 16000000)
|
||||
#define ADC_PRESCALE ADC_PRESCALE128
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Reference shift values are complicated for ATtinyX5 since we have the extra register bit REFS2
|
||||
* in ATTinyCore, this bit is handled programmatical and therefore the defines are different.
|
||||
* To keep my library small, I use the changed defines.
|
||||
* After including this file you can not call the ATTinyCore readAnalog functions reliable, if you specify references other than default!
|
||||
*/
|
||||
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
|
||||
// defines are for ADCUtils.cpp, they can be used WITHOUT bit reordering
|
||||
#undef DEFAULT
|
||||
#undef EXTERNAL
|
||||
#undef INTERNAL1V1
|
||||
#undef INTERNAL
|
||||
#undef INTERNAL2V56
|
||||
#undef INTERNAL2V56_EXTCAP
|
||||
|
||||
#define DEFAULT 0
|
||||
#define EXTERNAL 4
|
||||
#define INTERNAL1V1 8
|
||||
#define INTERNAL INTERNAL1V1
|
||||
#define INTERNAL2V56 9
|
||||
#define INTERNAL2V56_EXTCAP 13
|
||||
|
||||
#define SHIFT_VALUE_FOR_REFERENCE REFS2
|
||||
#define MASK_FOR_ADC_REFERENCE (_BV(REFS0) | _BV(REFS1) | _BV(REFS2))
|
||||
#define MASK_FOR_ADC_CHANNELS (_BV(MUX0) | _BV(MUX1) | _BV(MUX2) | _BV(MUX3))
|
||||
#else // AVR_ATtiny85
|
||||
|
||||
#define SHIFT_VALUE_FOR_REFERENCE REFS0
|
||||
#define MASK_FOR_ADC_REFERENCE (_BV(REFS0) | _BV(REFS1))
|
||||
#define MASK_FOR_ADC_CHANNELS (_BV(MUX0) | _BV(MUX1) | _BV(MUX2) | _BV(MUX3))
|
||||
#endif
|
||||
|
||||
// Temperature channel definitions - 1 LSB / 1 degree Celsius
|
||||
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
|
||||
#define ADC_TEMPERATURE_CHANNEL_MUX 15
|
||||
#define ADC_1_1_VOLT_CHANNEL_MUX 12
|
||||
#define ADC_GND_CHANNEL_MUX 13
|
||||
#define ADC_CHANNEL_MUX_MASK 0x0F
|
||||
|
||||
#elif defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
|
||||
#define ADC_ISCR_CHANNEL_MUX 3
|
||||
#define ADC_TEMPERATURE_CHANNEL_MUX 11
|
||||
#define ADC_1_1_VOLT_CHANNEL_MUX 12
|
||||
#define ADC_GND_CHANNEL_MUX 14
|
||||
#define ADC_VCC_4TH_CHANNEL_MUX 13
|
||||
#define ADC_CHANNEL_MUX_MASK 0x1F
|
||||
|
||||
#elif defined(__AVR_ATmega328P__)
|
||||
#define ADC_TEMPERATURE_CHANNEL_MUX 8
|
||||
#define ADC_1_1_VOLT_CHANNEL_MUX 14
|
||||
#define ADC_GND_CHANNEL_MUX 15
|
||||
#define ADC_CHANNEL_MUX_MASK 0x0F
|
||||
|
||||
#elif defined(__AVR_ATmega644P__)
|
||||
#define ADC_TEMPERATURE_CHANNEL_MUX // not existent
|
||||
#define ADC_1_1_VOLT_CHANNEL_MUX 0x1E
|
||||
#define ADC_GND_CHANNEL_MUX 0x1F
|
||||
#define ADC_CHANNEL_MUX_MASK 0x0F
|
||||
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
#define ADC_TEMPERATURE_CHANNEL_MUX 0x27
|
||||
#define ADC_1_1_VOLT_CHANNEL_MUX 0x1E
|
||||
#define ADC_GND_CHANNEL_MUX 0x1F
|
||||
#define ADC_CHANNEL_MUX_MASK 0x3F
|
||||
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
|
||||
#define ADC_1_1_VOLT_CHANNEL_MUX 0x1E
|
||||
#define ADC_GND_CHANNEL_MUX 0x1F
|
||||
#define ADC_CHANNEL_MUX_MASK 0x1F
|
||||
|
||||
#define INTERNAL INTERNAL1V1
|
||||
|
||||
#else
|
||||
#error "No temperature channel definitions specified for this AVR CPU"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Thresholds for OVER and UNDER voltage and detection of kind of power supply (USB or Li-ion)
|
||||
*
|
||||
* Default values are suitable for Li-ion batteries.
|
||||
* We normally have voltage drop at the connectors, so the battery voltage is assumed slightly higher, than the Arduino VCC.
|
||||
* But keep in mind that the ultrasonic distance module HC-SR04 may not work reliable below 3.7 volt.
|
||||
*/
|
||||
#if !defined(LI_ION_VCC_UNDERVOLTAGE_THRESHOLD_MILLIVOLT)
|
||||
#define LI_ION_VCC_UNDERVOLTAGE_THRESHOLD_MILLIVOLT 3400 // Do not stress your battery and we require some power for standby
|
||||
#endif
|
||||
#if !defined(LI_ION_VCC_EMERGENCY_UNDERVOLTAGE_THRESHOLD_MILLIVOLT)
|
||||
#define LI_ION_VCC_EMERGENCY_UNDERVOLTAGE_THRESHOLD_MILLIVOLT 3000 // Many Li-ions are specified down to 3.0 volt
|
||||
#endif
|
||||
|
||||
#if !defined(VCC_UNDERVOLTAGE_THRESHOLD_MILLIVOLT)
|
||||
#define VCC_UNDERVOLTAGE_THRESHOLD_MILLIVOLT LI_ION_VCC_UNDERVOLTAGE_THRESHOLD_MILLIVOLT
|
||||
#endif
|
||||
#if !defined(VCC_EMERGENCY_UNDERVOLTAGE_THRESHOLD_MILLIVOLT)
|
||||
#define VCC_EMERGENCY_UNDERVOLTAGE_THRESHOLD_MILLIVOLT LI_ION_VCC_EMERGENCY_UNDERVOLTAGE_THRESHOLD_MILLIVOLT
|
||||
#endif
|
||||
#if !defined(VCC_OVERVOLTAGE_THRESHOLD_MILLIVOLT)
|
||||
#define VCC_OVERVOLTAGE_THRESHOLD_MILLIVOLT 5250 // + 5 % operation voltage
|
||||
#endif
|
||||
#if !defined(VCC_EMERGENCY_OVERVOLTAGE_THRESHOLD_MILLIVOLT)
|
||||
#define VCC_EMERGENCY_OVERVOLTAGE_THRESHOLD_MILLIVOLT 5500 // +10 %. Max recommended operation voltage
|
||||
#endif
|
||||
#if !defined(VCC_CHECK_PERIOD_MILLIS)
|
||||
#define VCC_CHECK_PERIOD_MILLIS 10000L // 10 seconds period of VCC checks
|
||||
#endif
|
||||
#if !defined(VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP)
|
||||
#define VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP 6 // Shutdown after 6 times (60 seconds) VCC below VCC_UNDERVOLTAGE_THRESHOLD_MILLIVOLT or 1 time below VCC_EMERGENCY_UNDERVOLTAGE_THRESHOLD_MILLIVOLT
|
||||
#endif
|
||||
|
||||
#if !defined(VOLTAGE_USB_POWERED_LOWER_THRESHOLD_MILLIVOLT)
|
||||
#define VOLTAGE_USB_POWERED_LOWER_THRESHOLD_MILLIVOLT 4300 // Assume USB powered above this voltage
|
||||
#endif
|
||||
|
||||
#if !defined(VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT)
|
||||
#define VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT 4950 // Assume USB powered below this voltage, because of the loss in USB cable. If we have > 4950, we assume to be powered by VIN.
|
||||
// In contrast to e.g. powered by VIN, which results in almost perfect 5 volt supply
|
||||
#endif
|
||||
|
||||
extern long sLastVCCCheckMillis;
|
||||
extern uint8_t sVCCTooLowCounter;
|
||||
|
||||
uint16_t readADCChannel(uint8_t aADCChannelNumber);
|
||||
uint16_t readADCChannelWithReference(uint8_t aADCChannelNumber, uint8_t aReference);
|
||||
uint16_t waitAndReadADCChannelWithReference(uint8_t aADCChannelNumber, uint8_t aReference);
|
||||
uint16_t waitAndReadADCChannelWithReferenceAndRestoreADMUXAndReference(uint8_t aADCChannelNumber, uint8_t aReference);
|
||||
uint16_t readADCChannelWithOversample(uint8_t aADCChannelNumber, uint8_t aOversampleExponent);
|
||||
void setADCChannelAndReferenceForNextConversion(uint8_t aADCChannelNumber, uint8_t aReference);
|
||||
uint16_t readADCChannelWithReferenceOversampleFast(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aOversampleExponent);
|
||||
uint32_t readADCChannelMultiSamples(uint8_t aPrescale, uint16_t aNumberOfSamples);
|
||||
uint16_t readADCChannelMultiSamplesWithReference(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples);
|
||||
uint32_t readADCChannelMultiSamplesWithReferenceAndPrescaler(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aPrescale,
|
||||
uint16_t aNumberOfSamples);
|
||||
uint16_t readADCChannelWithReferenceMax(uint8_t aADCChannelNumber, uint8_t aReference, uint16_t aNumberOfSamples);
|
||||
uint16_t readADCChannelWithReferenceMaxMicros(uint8_t aADCChannelNumber, uint8_t aReference, uint16_t aMicrosecondsToAquire);
|
||||
uint16_t readUntil4ConsecutiveValuesAreEqual(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aDelay,
|
||||
uint8_t aAllowedDifference, uint8_t aMaxRetries);
|
||||
|
||||
uint8_t checkAndWaitForReferenceAndChannelToSwitch(uint8_t aADCChannelNumber, uint8_t aReference);
|
||||
|
||||
/*
|
||||
* readVCC*() functions store the result in sVCCVoltageMillivolt or sVCCVoltage
|
||||
*/
|
||||
float getVCCVoltageSimple(void);
|
||||
void readVCCVoltageSimple(void);
|
||||
void readVCCVoltageMillivoltSimple(void);
|
||||
void readVCCVoltage(void);
|
||||
uint16_t getVCCVoltageMillivolt(void);
|
||||
void readVCCVoltageMillivolt(void);
|
||||
uint16_t getVCCVoltageReadingFor1_1VoltReference(void);
|
||||
uint16_t printVCCVoltageMillivolt(Print *aSerial);
|
||||
void readAndPrintVCCVoltageMillivolt(Print *aSerial);
|
||||
|
||||
uint16_t getVoltageMillivolt(uint16_t aVCCVoltageMillivolt, uint8_t aADCChannelForVoltageMeasurement);
|
||||
uint16_t getVoltageMillivolt(uint8_t aADCChannelForVoltageMeasurement);
|
||||
uint16_t getVoltageMillivoltWith_1_1VoltReference(uint8_t aADCChannelForVoltageMeasurement);
|
||||
float getCPUTemperatureSimple(void);
|
||||
float getCPUTemperature(void);
|
||||
float getTemperature(void) __attribute__ ((deprecated ("Renamed to getCPUTemperature()"))); // deprecated
|
||||
|
||||
bool isVCCUSBPowered();
|
||||
bool isVCCUSBPowered(Print *aSerial);
|
||||
bool isVCCUndervoltageMultipleTimes();
|
||||
void resetCounterForVCCUndervoltageMultipleTimes();
|
||||
bool isVCCUndervoltage();
|
||||
bool isVCCEmergencyUndervoltage();
|
||||
bool isVCCOvervoltage();
|
||||
bool isVCCOvervoltageSimple(); // Version using readVCCVoltageMillivoltSimple()
|
||||
bool isVCCTooHighSimple(); // Version not using readVCCVoltageMillivoltSimple()
|
||||
|
||||
#endif // defined(__AVR__) ...
|
||||
|
||||
/*
|
||||
* Variables and functions defined as dummies to allow for seamless compiling on non AVR platforms
|
||||
*/
|
||||
extern float sVCCVoltage;
|
||||
extern uint16_t sVCCVoltageMillivolt;
|
||||
|
||||
uint16_t readADCChannelWithReferenceOversample(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aOversampleExponent);
|
||||
|
||||
uint16_t getVCCVoltageMillivoltSimple(void);
|
||||
float getVCCVoltage(void);
|
||||
float getCPUTemperature(void);
|
||||
|
||||
#endif // _ADC_UTILS_H
|
||||
@ -1,818 +0,0 @@
|
||||
/*
|
||||
* ADCUtils.hpp
|
||||
*
|
||||
* ADC utility functions. Conversion time is defined as 0.104 milliseconds for 16 MHz Arduinos in ADCUtils.h.
|
||||
*
|
||||
* Copyright (C) 2016-2023 Armin Joachimsmeyer
|
||||
* Email: armin.joachimsmeyer@gmail.com
|
||||
*
|
||||
* This file is part of Arduino-Utils https://github.com/ArminJo/Arduino-Utils.
|
||||
*
|
||||
* ArduinoUtils is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
|
||||
*/
|
||||
|
||||
#ifndef _ADC_UTILS_HPP
|
||||
#define _ADC_UTILS_HPP
|
||||
|
||||
#include "ADCUtils.h"
|
||||
#if defined(ADC_UTILS_ARE_AVAILABLE) // set in ADCUtils.h, if supported architecture was detected
|
||||
|
||||
#if !defined(STR_HELPER)
|
||||
#define STR_HELPER(x) #x
|
||||
#define STR(x) STR_HELPER(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* By replacing this value with the voltage you measured a the AREF pin after a conversion
|
||||
* with INTERNAL you can calibrate your ADC readout. For my Nanos I measured e.g. 1060 mV and 1093 mV.
|
||||
*/
|
||||
#if !defined(ADC_INTERNAL_REFERENCE_MILLIVOLT)
|
||||
#define ADC_INTERNAL_REFERENCE_MILLIVOLT 1100L // Change to value measured at the AREF pin. If value > real AREF voltage, measured values are > real values
|
||||
#endif
|
||||
|
||||
// Union to speed up the combination of low and high bytes to a word
|
||||
// it is not optimal since the compiler still generates 2 unnecessary moves
|
||||
// but using -- value = (high << 8) | low -- gives 5 unnecessary instructions
|
||||
union WordUnionForADCUtils {
|
||||
struct {
|
||||
uint8_t LowByte;
|
||||
uint8_t HighByte;
|
||||
} UByte;
|
||||
uint16_t UWord;
|
||||
int16_t Word;
|
||||
uint8_t *BytePointer;
|
||||
};
|
||||
|
||||
/*
|
||||
* Enable this to see information on each call.
|
||||
* Since there should be no library which uses Serial, it should only be enabled for development purposes.
|
||||
*/
|
||||
#if defined(DEBUG) && !defined(LOCAL_DEBUG)
|
||||
#define LOCAL_DEBUG
|
||||
#else
|
||||
//#define LOCAL_DEBUG // This enables debug output only for this file
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Persistent storage for VCC value
|
||||
*/
|
||||
float sVCCVoltage;
|
||||
uint16_t sVCCVoltageMillivolt;
|
||||
|
||||
// for isVCCTooLowMultipleTimes()
|
||||
long sLastVCCCheckMillis;
|
||||
uint8_t sVCCTooLowCounter = 0;
|
||||
|
||||
/*
|
||||
* Conversion time is defined as 0.104 milliseconds by ADC_PRESCALE in ADCUtils.h.
|
||||
*/
|
||||
uint16_t readADCChannel(uint8_t aADCChannelNumber) {
|
||||
WordUnionForADCUtils tUValue;
|
||||
ADMUX = aADCChannelNumber | (DEFAULT << SHIFT_VALUE_FOR_REFERENCE);
|
||||
|
||||
// ADCSRB = 0; // Only active if ADATE is set to 1.
|
||||
// ADSC-StartConversion ADIF-Reset Interrupt Flag - NOT free running mode
|
||||
ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADIF) | ADC_PRESCALE);
|
||||
|
||||
// wait for single conversion to finish
|
||||
loop_until_bit_is_clear(ADCSRA, ADSC);
|
||||
|
||||
// Get value
|
||||
tUValue.UByte.LowByte = ADCL;
|
||||
tUValue.UByte.HighByte = ADCH;
|
||||
return tUValue.UWord;
|
||||
// return ADCL | (ADCH <<8); // needs 4 bytes more
|
||||
}
|
||||
|
||||
/*
|
||||
* Conversion time is defined as 0.104 milliseconds by ADC_PRESCALE in ADCUtils.h.
|
||||
*/
|
||||
uint16_t readADCChannelWithReference(uint8_t aADCChannelNumber, uint8_t aReference) {
|
||||
WordUnionForADCUtils tUValue;
|
||||
ADMUX = aADCChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE);
|
||||
|
||||
// ADCSRB = 0; // Only active if ADATE is set to 1.
|
||||
// ADSC-StartConversion ADIF-Reset Interrupt Flag - NOT free running mode
|
||||
ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADIF) | ADC_PRESCALE);
|
||||
|
||||
// wait for single conversion to finish
|
||||
loop_until_bit_is_clear(ADCSRA, ADSC);
|
||||
|
||||
// Get value
|
||||
tUValue.UByte.LowByte = ADCL;
|
||||
tUValue.UByte.HighByte = ADCH;
|
||||
return tUValue.UWord;
|
||||
}
|
||||
|
||||
/*
|
||||
* Conversion time is defined as 0.104 milliseconds by ADC_PRESCALE in ADCUtils.h.
|
||||
* Does NOT restore ADMUX after reading
|
||||
*/
|
||||
uint16_t waitAndReadADCChannelWithReference(uint8_t aADCChannelNumber, uint8_t aReference) {
|
||||
checkAndWaitForReferenceAndChannelToSwitch(aADCChannelNumber, aReference);
|
||||
return readADCChannelWithReference(aADCChannelNumber, aReference);
|
||||
}
|
||||
|
||||
/*
|
||||
* Conversion time is defined as 0.104 milliseconds by ADC_PRESCALE in ADCUtils.h.
|
||||
* Restores ADMUX after reading
|
||||
*/
|
||||
uint16_t waitAndReadADCChannelWithReferenceAndRestoreADMUXAndReference(uint8_t aADCChannelNumber, uint8_t aReference) {
|
||||
uint8_t tOldADMUX = checkAndWaitForReferenceAndChannelToSwitch(aADCChannelNumber, aReference);
|
||||
uint16_t tResult = readADCChannelWithReference(aADCChannelNumber, aReference);
|
||||
checkAndWaitForReferenceAndChannelToSwitch(tOldADMUX & MASK_FOR_ADC_CHANNELS, tOldADMUX >> SHIFT_VALUE_FOR_REFERENCE);
|
||||
return tResult;
|
||||
}
|
||||
|
||||
/*
|
||||
* To prepare reference and ADMUX for next measurement
|
||||
*/
|
||||
void setADCChannelAndReferenceForNextConversion(uint8_t aADCChannelNumber, uint8_t aReference) {
|
||||
ADMUX = aADCChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE);
|
||||
}
|
||||
|
||||
/*
|
||||
* @return original ADMUX register content for optional later restoring values
|
||||
* All experimental values are acquired by using the ADCSwitchingTest example from this library
|
||||
*/
|
||||
uint8_t checkAndWaitForReferenceAndChannelToSwitch(uint8_t aADCChannelNumber, uint8_t aReference) {
|
||||
uint8_t tOldADMUX = ADMUX;
|
||||
/*
|
||||
* Must wait >= 7 us if reference has to be switched from 1.1 volt/INTERNAL to VCC/DEFAULT (seen on oscilloscope)
|
||||
* This is done after the 2 ADC clock cycles required for Sample & Hold :-)
|
||||
*
|
||||
* Must wait >= 7600 us for Nano board >= 6200 for Uno board if reference has to be switched from VCC/DEFAULT to 1.1 volt/INTERNAL
|
||||
* Must wait >= 200 us if channel has to be switched to 1.1 volt internal channel if S&H was at 5 Volt
|
||||
*/
|
||||
uint8_t tNewReference = (aReference << SHIFT_VALUE_FOR_REFERENCE);
|
||||
ADMUX = aADCChannelNumber | tNewReference;
|
||||
#if defined(INTERNAL2V56)
|
||||
if ((tOldADMUX & MASK_FOR_ADC_REFERENCE) != tNewReference && (aReference == INTERNAL || aReference == INTERNAL2V56)) {
|
||||
#else
|
||||
if ((tOldADMUX & MASK_FOR_ADC_REFERENCE) != tNewReference && aReference == INTERNAL) {
|
||||
#endif
|
||||
#if defined(LOCAL_DEBUG)
|
||||
Serial.println(F("Switch from DEFAULT to INTERNAL"));
|
||||
#endif
|
||||
/*
|
||||
* Switch reference from DEFAULT to INTERNAL
|
||||
*/
|
||||
delayMicroseconds(8000); // experimental value is >= 7600 us for Nano board and 6200 for Uno board
|
||||
} else if ((tOldADMUX & ADC_CHANNEL_MUX_MASK) != aADCChannelNumber) {
|
||||
if (aADCChannelNumber == ADC_1_1_VOLT_CHANNEL_MUX) {
|
||||
/*
|
||||
* Internal 1.1 Volt channel requires <= 200 us for Nano board
|
||||
*/
|
||||
delayMicroseconds(350); // 350 was ok and 300 was too less for UltimateBatteryTester - result was 226 instead of 225
|
||||
} else {
|
||||
/*
|
||||
* 100 kOhm requires < 100 us, 1 MOhm requires 120 us S&H switching time
|
||||
*/
|
||||
delayMicroseconds(120); // experimental value is <= 1100 us for Nano board
|
||||
}
|
||||
}
|
||||
return tOldADMUX;
|
||||
}
|
||||
|
||||
/*
|
||||
* Oversample and multiple samples only makes sense if you expect a noisy input signal
|
||||
* It does NOT increase the precision of the measurement, since the ADC has insignificant noise
|
||||
*/
|
||||
uint16_t readADCChannelWithOversample(uint8_t aADCChannelNumber, uint8_t aOversampleExponent) {
|
||||
return readADCChannelWithReferenceOversample(aADCChannelNumber, DEFAULT, aOversampleExponent);
|
||||
}
|
||||
|
||||
/*
|
||||
* Conversion time is defined as 0.104 milliseconds by ADC_PRESCALE in ADCUtils.h.
|
||||
*/
|
||||
uint16_t readADCChannelWithReferenceOversample(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aOversampleExponent) {
|
||||
uint16_t tSumValue = 0;
|
||||
ADMUX = aADCChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE);
|
||||
|
||||
ADCSRB = 0; // Free running mode. Only active if ADATE is set to 1.
|
||||
// ADSC-StartConversion ADATE-AutoTriggerEnable ADIF-Reset Interrupt Flag
|
||||
ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADATE) | _BV(ADIF) | ADC_PRESCALE);
|
||||
|
||||
uint8_t tCount = _BV(aOversampleExponent);
|
||||
for (uint8_t i = 0; i < tCount; i++) {
|
||||
/*
|
||||
* wait for free running conversion to finish.
|
||||
* Do not wait for ADSC here, since ADSC is only low for 1 ADC Clock cycle on free running conversion.
|
||||
*/
|
||||
loop_until_bit_is_set(ADCSRA, ADIF);
|
||||
|
||||
ADCSRA |= _BV(ADIF); // clear bit to enable recognizing next conversion has finished
|
||||
// Add value
|
||||
tSumValue += ADCL | (ADCH << 8); // using WordUnionForADCUtils does not save space here
|
||||
// tSumValue += (ADCH << 8) | ADCL; // this does NOT work!
|
||||
}
|
||||
ADCSRA &= ~_BV(ADATE); // Disable auto-triggering (free running mode)
|
||||
// return rounded value
|
||||
return ((tSumValue + (tCount >> 1)) >> aOversampleExponent);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use ADC_PRESCALE32 which gives 26 us conversion time and good linearity for 16 MHz Arduino
|
||||
*/
|
||||
uint16_t readADCChannelWithReferenceOversampleFast(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aOversampleExponent) {
|
||||
uint16_t tSumValue = 0;
|
||||
ADMUX = aADCChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE);
|
||||
|
||||
ADCSRB = 0; // Free running mode. Only active if ADATE is set to 1.
|
||||
// ADSC-StartConversion ADATE-AutoTriggerEnable ADIF-Reset Interrupt Flag
|
||||
ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADATE) | _BV(ADIF) | ADC_PRESCALE32);
|
||||
|
||||
uint8_t tCount = _BV(aOversampleExponent);
|
||||
for (uint8_t i = 0; i < tCount; i++) {
|
||||
/*
|
||||
* wait for free running conversion to finish.
|
||||
* Do not wait for ADSC here, since ADSC is only low for 1 ADC Clock cycle on free running conversion.
|
||||
*/
|
||||
loop_until_bit_is_set(ADCSRA, ADIF);
|
||||
|
||||
ADCSRA |= _BV(ADIF); // clear bit to enable recognizing next conversion has finished
|
||||
// Add value
|
||||
tSumValue += ADCL | (ADCH << 8); // using WordUnionForADCUtils does not save space here
|
||||
// tSumValue += (ADCH << 8) | ADCL; // this does NOT work!
|
||||
}
|
||||
ADCSRA &= ~_BV(ADATE); // Disable auto-triggering (free running mode)
|
||||
return ((tSumValue + (tCount >> 1)) >> aOversampleExponent);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns sum of all sample values
|
||||
* Conversion time is defined as 0.104 milliseconds for 16 MHz Arduino by ADC_PRESCALE (=ADC_PRESCALE128) in ADCUtils.h.
|
||||
* @ param aNumberOfSamples If > 64 an overflow may occur.
|
||||
*/
|
||||
uint16_t readADCChannelMultiSamplesWithReference(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples) {
|
||||
uint16_t tSumValue = 0;
|
||||
ADMUX = aADCChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE);
|
||||
|
||||
ADCSRB = 0; // Free running mode. Only active if ADATE is set to 1.
|
||||
// ADSC-StartConversion ADATE-AutoTriggerEnable ADIF-Reset Interrupt Flag
|
||||
ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADATE) | _BV(ADIF) | ADC_PRESCALE);
|
||||
|
||||
for (uint8_t i = 0; i < aNumberOfSamples; i++) {
|
||||
/*
|
||||
* wait for free running conversion to finish.
|
||||
* Do not wait for ADSC here, since ADSC is only low for 1 ADC Clock cycle on free running conversion.
|
||||
*/
|
||||
loop_until_bit_is_set(ADCSRA, ADIF);
|
||||
|
||||
ADCSRA |= _BV(ADIF); // clear bit to enable recognizing next conversion has finished
|
||||
// Add value
|
||||
tSumValue += ADCL | (ADCH << 8); // using WordUnionForADCUtils does not save space here
|
||||
// tSumValue += (ADCH << 8) | ADCL; // this does NOT work!
|
||||
}
|
||||
ADCSRA &= ~_BV(ADATE); // Disable auto-triggering (free running mode)
|
||||
return tSumValue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns sum of all sample values
|
||||
* Conversion time is defined as 0.104 milliseconds for 16 MHz Arduino for ADC_PRESCALE128 in ADCUtils.h.
|
||||
* @ param aPrescale can be one of ADC_PRESCALE2, ADC_PRESCALE4, 8, 16, 32, 64, 128.
|
||||
* ADC_PRESCALE32 is recommended for excellent linearity and fast readout of 26 microseconds
|
||||
* @ param aNumberOfSamples If > 16k an overflow may occur.
|
||||
*/
|
||||
uint32_t readADCChannelMultiSamplesWithReferenceAndPrescaler(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aPrescale,
|
||||
uint16_t aNumberOfSamples) {
|
||||
uint32_t tSumValue = 0;
|
||||
ADMUX = aADCChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE);
|
||||
|
||||
ADCSRB = 0; // Free running mode. Only active if ADATE is set to 1.
|
||||
// ADSC-StartConversion ADATE-AutoTriggerEnable ADIF-Reset Interrupt Flag
|
||||
ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADATE) | _BV(ADIF) | aPrescale);
|
||||
|
||||
for (uint16_t i = 0; i < aNumberOfSamples; i++) {
|
||||
/*
|
||||
* wait for free running conversion to finish.
|
||||
* Do not wait for ADSC here, since ADSC is only low for 1 ADC Clock cycle on free running conversion.
|
||||
*/
|
||||
loop_until_bit_is_set(ADCSRA, ADIF);
|
||||
|
||||
ADCSRA |= _BV(ADIF); // clear bit to enable recognizing next conversion has finished
|
||||
// Add value
|
||||
tSumValue += ADCL | (ADCH << 8); // using WordUnionForADCUtils does not save space here
|
||||
// tSumValue += (ADCH << 8) | ADCL; // this does NOT work!
|
||||
}
|
||||
ADCSRA &= ~_BV(ADATE); // Disable auto-triggering (free running mode)
|
||||
return tSumValue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns sum of all sample values
|
||||
* Assumes, that channel and reference are still set to the right values
|
||||
* @ param aNumberOfSamples If > 16k an overflow may occur.
|
||||
*/
|
||||
uint32_t readADCChannelMultiSamples(uint8_t aPrescale, uint16_t aNumberOfSamples) {
|
||||
uint32_t tSumValue = 0;
|
||||
|
||||
ADCSRB = 0; // Free running mode. Only active if ADATE is set to 1.
|
||||
// ADSC-StartConversion ADATE-AutoTriggerEnable ADIF-Reset Interrupt Flag
|
||||
ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADATE) | _BV(ADIF) | aPrescale);
|
||||
|
||||
for (uint16_t i = 0; i < aNumberOfSamples; i++) {
|
||||
/*
|
||||
* wait for free running conversion to finish.
|
||||
* Do not wait for ADSC here, since ADSC is only low for 1 ADC Clock cycle on free running conversion.
|
||||
*/
|
||||
loop_until_bit_is_set(ADCSRA, ADIF);
|
||||
|
||||
ADCSRA |= _BV(ADIF); // clear bit to enable recognizing next conversion has finished
|
||||
// Add value
|
||||
tSumValue += ADCL | (ADCH << 8); // using WordUnionForADCUtils does not save space here
|
||||
// tSumValue += (ADCH << 8) | ADCL; // this does NOT work!
|
||||
}
|
||||
ADCSRA &= ~_BV(ADATE); // Disable auto-triggering (free running mode)
|
||||
return tSumValue;
|
||||
}
|
||||
/*
|
||||
* use ADC_PRESCALE32 which gives 26 us conversion time and good linearity
|
||||
* @return the maximum value of aNumberOfSamples samples.
|
||||
*/
|
||||
uint16_t readADCChannelWithReferenceMax(uint8_t aADCChannelNumber, uint8_t aReference, uint16_t aNumberOfSamples) {
|
||||
uint16_t tADCValue = 0;
|
||||
uint16_t tMaximum = 0;
|
||||
ADMUX = aADCChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE);
|
||||
|
||||
ADCSRB = 0; // Free running mode. Only active if ADATE is set to 1.
|
||||
// ADSC-StartConversion ADATE-AutoTriggerEnable ADIF-Reset Interrupt Flag
|
||||
ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADATE) | _BV(ADIF) | ADC_PRESCALE32);
|
||||
|
||||
for (uint16_t i = 0; i < aNumberOfSamples; i++) {
|
||||
/*
|
||||
* wait for free running conversion to finish.
|
||||
* Do not wait for ADSC here, since ADSC is only low for 1 ADC Clock cycle on free running conversion.
|
||||
*/
|
||||
loop_until_bit_is_set(ADCSRA, ADIF);
|
||||
|
||||
ADCSRA |= _BV(ADIF); // clear bit to enable recognizing next conversion has finished
|
||||
// check value
|
||||
tADCValue = ADCL | (ADCH << 8);
|
||||
if (tADCValue > tMaximum) {
|
||||
tMaximum = tADCValue;
|
||||
}
|
||||
}
|
||||
ADCSRA &= ~_BV(ADATE); // Disable auto-triggering (free running mode)
|
||||
return tMaximum;
|
||||
}
|
||||
|
||||
/*
|
||||
* use ADC_PRESCALE32 which gives 26 us conversion time and good linearity
|
||||
* @return the maximum value during aMicrosecondsToAquire measurement.
|
||||
*/
|
||||
uint16_t readADCChannelWithReferenceMaxMicros(uint8_t aADCChannelNumber, uint8_t aReference, uint16_t aMicrosecondsToAquire) {
|
||||
uint16_t tNumberOfSamples = aMicrosecondsToAquire / 26;
|
||||
return readADCChannelWithReferenceMax(aADCChannelNumber, aReference, tNumberOfSamples);
|
||||
}
|
||||
|
||||
/*
|
||||
* aMaxRetries = 255 -> try forever
|
||||
* @return (tMax + tMin) / 2
|
||||
*/
|
||||
uint16_t readUntil4ConsecutiveValuesAreEqual(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aDelay,
|
||||
uint8_t aAllowedDifference, uint8_t aMaxRetries) {
|
||||
int tValues[4]; // last value is in tValues[3]
|
||||
int tMin;
|
||||
int tMax;
|
||||
|
||||
/*
|
||||
* Initialize first 4 values before checking
|
||||
*/
|
||||
tValues[0] = readADCChannelWithReference(aADCChannelNumber, aReference);
|
||||
for (int i = 1; i < 4; ++i) {
|
||||
if (aDelay != 0) {
|
||||
delay(aDelay); // Minimum is only 3 delays!
|
||||
}
|
||||
tValues[i] = readADCChannelWithReference(aADCChannelNumber, aReference);
|
||||
}
|
||||
|
||||
do {
|
||||
/*
|
||||
* Get min and max of the last 4 values
|
||||
*/
|
||||
tMin = 1024;
|
||||
tMax = 0;
|
||||
for (uint_fast8_t i = 0; i < 4; ++i) {
|
||||
if (tValues[i] < tMin) {
|
||||
tMin = tValues[i];
|
||||
}
|
||||
if (tValues[i] > tMax) {
|
||||
tMax = tValues[i];
|
||||
}
|
||||
}
|
||||
/*
|
||||
* check for terminating condition
|
||||
*/
|
||||
if ((tMax - tMin) <= aAllowedDifference) {
|
||||
break;
|
||||
} else {
|
||||
/*
|
||||
* Get next value
|
||||
*/
|
||||
// Serial.print("Difference=");
|
||||
// Serial.println(tMax - tMin);
|
||||
// Move values to front
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
tValues[i] = tValues[i + 1];
|
||||
}
|
||||
// and wait before getting next value
|
||||
if (aDelay != 0) {
|
||||
delay(aDelay);
|
||||
}
|
||||
tValues[3] = readADCChannelWithReference(aADCChannelNumber, aReference);
|
||||
}
|
||||
if (aMaxRetries != 255) {
|
||||
aMaxRetries--;
|
||||
}
|
||||
} while (aMaxRetries > 0);
|
||||
|
||||
#if defined(LOCAL_DEBUG)
|
||||
if(aMaxRetries == 0) {
|
||||
Serial.print(F("No 4 equal values for difference "));
|
||||
Serial.print(aAllowedDifference);
|
||||
Serial.print(F(" found "));
|
||||
Serial.print(tValues[0]);
|
||||
Serial.print(' ');
|
||||
Serial.print(tValues[1]);
|
||||
Serial.print(' ');
|
||||
Serial.print(tValues[2]);
|
||||
Serial.print(' ');
|
||||
Serial.println(tValues[3]);
|
||||
} else {
|
||||
Serial.print(aMaxRetries);
|
||||
Serial.println(F(" retries left"));
|
||||
}
|
||||
#endif
|
||||
|
||||
return (tMax + tMin) / 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* !!! Function without handling of switched reference and channel.!!!
|
||||
* Use it ONLY if you only call getVCCVoltageSimple() or getVCCVoltageMillivoltSimple() in your program.
|
||||
* !!! Resolution is only 20 millivolt !!!
|
||||
* Raw reading of 1.1 V is 225 at 5 V.
|
||||
* Raw reading of 1.1 V is 221 at 5.1 V.
|
||||
* Raw reading of 1.1 V is 214 at 5.25 V (+5 %).
|
||||
* Raw reading of 1.1 V is 204 at 5.5 V (+10 %).
|
||||
*/
|
||||
float getVCCVoltageSimple(void) {
|
||||
// use AVCC with (optional) external capacitor at AREF pin as reference
|
||||
float tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4);
|
||||
return ((1023 * 1.1 * 4) / tVCC);
|
||||
}
|
||||
|
||||
/*
|
||||
* !!! Function without handling of switched reference and channel.!!!
|
||||
* Use it ONLY if you only call getVCCVoltageSimple() or getVCCVoltageMillivoltSimple() in your program.
|
||||
* !!! Resolution is only 20 millivolt !!!
|
||||
*/
|
||||
uint16_t getVCCVoltageMillivoltSimple(void) {
|
||||
// use AVCC with external capacitor at AREF pin as reference
|
||||
uint16_t tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4);
|
||||
return ((1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets the hypothetical 14 bit reading of VCC using 1.1 volt reference
|
||||
* Similar to getVCCVoltageMillivolt() * 1023 / 1100
|
||||
*/
|
||||
uint16_t getVCCVoltageReadingFor1_1VoltReference(void) {
|
||||
uint16_t tVCC = waitAndReadADCChannelWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT);
|
||||
/*
|
||||
* Do not switch back ADMUX to enable checkAndWaitForReferenceAndChannelToSwitch() to work correctly for the next measurement
|
||||
*/
|
||||
return ((1023L * 1023L) / tVCC);
|
||||
}
|
||||
|
||||
/*
|
||||
* !!! Resolution is only 20 millivolt !!!
|
||||
*/
|
||||
float getVCCVoltage(void) {
|
||||
return (getVCCVoltageMillivolt() / 1000.0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read value of 1.1 volt internal channel using VCC (DEFAULT) as reference.
|
||||
* Handles reference and channel switching by introducing the appropriate delays.
|
||||
* !!! Resolution is only 20 millivolt !!!
|
||||
* Raw reading of 1.1 V is 225 at 5 V.
|
||||
* Raw reading of 1.1 V is 221 at 5.1 V.
|
||||
* Raw reading of 1.1 V is 214 at 5.25 V (+5 %).
|
||||
* Raw reading of 1.1 V is 204 at 5.5 V (+10 %).
|
||||
*/
|
||||
uint16_t getVCCVoltageMillivolt(void) {
|
||||
uint16_t tVCC = waitAndReadADCChannelWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT);
|
||||
/*
|
||||
* Do not switch back ADMUX to enable checkAndWaitForReferenceAndChannelToSwitch() to work correctly for the next measurement
|
||||
*/
|
||||
return ((1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT) / tVCC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Does not set sVCCVoltageMillivolt
|
||||
*/
|
||||
uint16_t printVCCVoltageMillivolt(Print *aSerial) {
|
||||
aSerial->print(F("VCC="));
|
||||
uint16_t tVCCVoltageMillivolt = getVCCVoltageMillivolt();
|
||||
aSerial->print(tVCCVoltageMillivolt);
|
||||
aSerial->println(" mV");
|
||||
return tVCCVoltageMillivolt;
|
||||
}
|
||||
|
||||
void readAndPrintVCCVoltageMillivolt(Print *aSerial) {
|
||||
aSerial->print(F("VCC="));
|
||||
sVCCVoltageMillivolt = getVCCVoltageMillivolt();
|
||||
aSerial->print(sVCCVoltageMillivolt);
|
||||
aSerial->println(" mV");
|
||||
}
|
||||
/*
|
||||
* !!! Function without handling of switched reference and channel.!!!
|
||||
* Use it ONLY if you only call getVCCVoltageSimple() or getVCCVoltageMillivoltSimple() in your program.
|
||||
* !!! Resolution is only 20 millivolt !!!
|
||||
*/
|
||||
void readVCCVoltageSimple(void) {
|
||||
// use AVCC with (optional) external capacitor at AREF pin as reference
|
||||
float tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4);
|
||||
sVCCVoltage = (1023 * (((float) ADC_INTERNAL_REFERENCE_MILLIVOLT) / 1000) * 4) / tVCC;
|
||||
}
|
||||
|
||||
/*
|
||||
* !!! Function without handling of switched reference and channel.!!!
|
||||
* Use it ONLY if you only call getVCCVoltageSimple() or getVCCVoltageMillivoltSimple() in your program.
|
||||
* !!! Resolution is only 20 millivolt !!!
|
||||
*/
|
||||
void readVCCVoltageMillivoltSimple(void) {
|
||||
// use AVCC with external capacitor at AREF pin as reference
|
||||
uint16_t tVCCVoltageMillivoltRaw = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4);
|
||||
sVCCVoltageMillivolt = (1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCCVoltageMillivoltRaw;
|
||||
}
|
||||
|
||||
/*
|
||||
* !!! Resolution is only 20 millivolt !!!
|
||||
*/
|
||||
void readVCCVoltage(void) {
|
||||
sVCCVoltage = getVCCVoltageMillivolt() / 1000.0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read value of 1.1 volt internal channel using VCC (DEFAULT) as reference.
|
||||
* Handles reference and channel switching by introducing the appropriate delays.
|
||||
* !!! Resolution is only 20 millivolt !!!
|
||||
* Sets also the sVCCVoltageMillivolt variable.
|
||||
*/
|
||||
void readVCCVoltageMillivolt(void) {
|
||||
uint16_t tVCCVoltageMillivoltRaw = waitAndReadADCChannelWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT);
|
||||
/*
|
||||
* Do not switch back ADMUX to enable checkAndWaitForReferenceAndChannelToSwitch() to work correctly for the next measurement
|
||||
*/
|
||||
sVCCVoltageMillivolt = (1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT) / tVCCVoltageMillivoltRaw;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get voltage at ADC channel aADCChannelForVoltageMeasurement
|
||||
* aVCCVoltageMillivolt is assumed as reference voltage
|
||||
*/
|
||||
uint16_t getVoltageMillivolt(uint16_t aVCCVoltageMillivolt, uint8_t aADCChannelForVoltageMeasurement) {
|
||||
uint16_t tInputVoltageRaw = waitAndReadADCChannelWithReference(aADCChannelForVoltageMeasurement, DEFAULT);
|
||||
return (aVCCVoltageMillivolt * (uint32_t) tInputVoltageRaw) / 1023;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get voltage at ADC channel aADCChannelForVoltageMeasurement
|
||||
* Reference voltage VCC is determined just before
|
||||
*/
|
||||
uint16_t getVoltageMillivolt(uint8_t aADCChannelForVoltageMeasurement) {
|
||||
uint16_t tInputVoltageRaw = waitAndReadADCChannelWithReference(aADCChannelForVoltageMeasurement, DEFAULT);
|
||||
return (getVCCVoltageMillivolt() * (uint32_t) tInputVoltageRaw) / 1023;
|
||||
}
|
||||
|
||||
uint16_t getVoltageMillivoltWith_1_1VoltReference(uint8_t aADCChannelForVoltageMeasurement) {
|
||||
uint16_t tInputVoltageRaw = waitAndReadADCChannelWithReference(aADCChannelForVoltageMeasurement, INTERNAL);
|
||||
return (ADC_INTERNAL_REFERENCE_MILLIVOLT * (uint32_t) tInputVoltageRaw) / 1023;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if sVCCVoltageMillivolt is > 4.3 V and < 4.95 V
|
||||
*/
|
||||
bool isVCCUSBPowered() {
|
||||
readVCCVoltageMillivolt();
|
||||
return (VOLTAGE_USB_POWERED_LOWER_THRESHOLD_MILLIVOLT < sVCCVoltageMillivolt
|
||||
&& sVCCVoltageMillivolt < VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if sVCCVoltageMillivolt is > 4.3 V and < 4.95 V
|
||||
*/
|
||||
bool isVCCUSBPowered(Print *aSerial) {
|
||||
readVCCVoltageMillivolt();
|
||||
aSerial->print(F("USB powered is "));
|
||||
bool tReturnValue;
|
||||
if (VOLTAGE_USB_POWERED_LOWER_THRESHOLD_MILLIVOLT
|
||||
< sVCCVoltageMillivolt&& sVCCVoltageMillivolt < VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT) {
|
||||
tReturnValue = true;
|
||||
aSerial->print(F("true "));
|
||||
} else {
|
||||
tReturnValue = false;
|
||||
aSerial->print(F("false "));
|
||||
}
|
||||
printVCCVoltageMillivolt(aSerial);
|
||||
return tReturnValue;
|
||||
}
|
||||
|
||||
/*
|
||||
* @ return true only once, when VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP (6) times voltage too low -> shutdown
|
||||
*/
|
||||
bool isVCCUndervoltageMultipleTimes() {
|
||||
/*
|
||||
* Check VCC every VCC_CHECK_PERIOD_MILLIS (10) seconds
|
||||
*/
|
||||
|
||||
if (millis() - sLastVCCCheckMillis >= VCC_CHECK_PERIOD_MILLIS) {
|
||||
sLastVCCCheckMillis = millis();
|
||||
|
||||
# if defined(INFO)
|
||||
readAndPrintVCCVoltageMillivolt(&Serial);
|
||||
# else
|
||||
readVCCVoltageMillivolt();
|
||||
# endif
|
||||
|
||||
if (sVCCTooLowCounter < VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP) {
|
||||
/*
|
||||
* Do not check again if shutdown has happened
|
||||
*/
|
||||
if (sVCCVoltageMillivolt > VCC_UNDERVOLTAGE_THRESHOLD_MILLIVOLT) {
|
||||
sVCCTooLowCounter = 0; // reset counter
|
||||
} else {
|
||||
/*
|
||||
* Voltage too low, wait VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP (6) times and then shut down.
|
||||
*/
|
||||
if (sVCCVoltageMillivolt < VCC_EMERGENCY_UNDERVOLTAGE_THRESHOLD_MILLIVOLT) {
|
||||
// emergency shutdown
|
||||
sVCCTooLowCounter = VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP;
|
||||
# if defined(INFO)
|
||||
Serial.println(
|
||||
F(
|
||||
"Voltage < " STR(VCC_EMERGENCY_UNDERVOLTAGE_THRESHOLD_MILLIVOLT) " mV detected -> emergency shutdown"));
|
||||
# endif
|
||||
} else {
|
||||
sVCCTooLowCounter++;
|
||||
# if defined(INFO)
|
||||
Serial.print(F("Voltage < " STR(VCC_UNDERVOLTAGE_THRESHOLD_MILLIVOLT) " mV detected: "));
|
||||
Serial.print(VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP - sVCCTooLowCounter);
|
||||
Serial.println(F(" tries left"));
|
||||
# endif
|
||||
}
|
||||
if (sVCCTooLowCounter == VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP) {
|
||||
/*
|
||||
* 6 times voltage too low -> return signal for shutdown etc.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if VCC_EMERGENCY_UNDERVOLTAGE_THRESHOLD_MILLIVOLT (3 V) reached
|
||||
*/
|
||||
bool isVCCUndervoltage() {
|
||||
readVCCVoltageMillivolt();
|
||||
return (sVCCVoltageMillivolt < VCC_UNDERVOLTAGE_THRESHOLD_MILLIVOLT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if VCC_EMERGENCY_UNDERVOLTAGE_THRESHOLD_MILLIVOLT (3 V) reached
|
||||
*/
|
||||
bool isVCCEmergencyUndervoltage() {
|
||||
readVCCVoltageMillivolt();
|
||||
return (sVCCVoltageMillivolt < VCC_EMERGENCY_UNDERVOLTAGE_THRESHOLD_MILLIVOLT);
|
||||
}
|
||||
|
||||
void resetCounterForVCCUndervoltageMultipleTimes() {
|
||||
sVCCTooLowCounter = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Recommended VCC is 1.8 V to 5.5 V, absolute maximum VCC is 6.0 V.
|
||||
* Check for 5.25 V, because such overvoltage is quite unlikely to happen during regular operation.
|
||||
* Raw reading of 1.1 V is 225 at 5 V.
|
||||
* Raw reading of 1.1 V is 221 at 5.1 V.
|
||||
* Raw reading of 1.1 V is 214 at 5.25 V (+5 %).
|
||||
* Raw reading of 1.1 V is 204 at 5.5 V (+10 %).
|
||||
* Raw reading of 1.1 V is 1126000 / VCC_MILLIVOLT
|
||||
* @return true if 5 % overvoltage reached
|
||||
*/
|
||||
bool isVCCOvervoltage() {
|
||||
readVCCVoltageMillivolt();
|
||||
return (sVCCVoltageMillivolt > VCC_OVERVOLTAGE_THRESHOLD_MILLIVOLT);
|
||||
}
|
||||
bool isVCCOvervoltageSimple() {
|
||||
readVCCVoltageMillivoltSimple();
|
||||
return (sVCCVoltageMillivolt > VCC_OVERVOLTAGE_THRESHOLD_MILLIVOLT);
|
||||
}
|
||||
|
||||
// Version not using readVCCVoltageMillivoltSimple()
|
||||
bool isVCCTooHighSimple() {
|
||||
ADMUX = ADC_1_1_VOLT_CHANNEL_MUX | (DEFAULT << SHIFT_VALUE_FOR_REFERENCE);
|
||||
// ADCSRB = 0; // Only active if ADATE is set to 1.
|
||||
// ADSC-StartConversion ADIF-Reset Interrupt Flag - NOT free running mode
|
||||
ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADIF) | ADC_PRESCALE128); // 128 -> 104 microseconds per ADC conversion at 16 MHz --- Arduino default
|
||||
// wait for single conversion to finish
|
||||
loop_until_bit_is_clear(ADCSRA, ADSC);
|
||||
|
||||
// Get value
|
||||
uint16_t tRawValue = ADCL | (ADCH << 8);
|
||||
|
||||
return tRawValue < 1126000 / VCC_OVERVOLTAGE_THRESHOLD_MILLIVOLT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Temperature sensor is enabled by selecting the appropriate channel.
|
||||
* Different formula for 328P and 328PB!
|
||||
* !!! Function without handling of switched reference and channel.!!!
|
||||
* Use it ONLY if you only use INTERNAL reference (e.g. only call getTemperatureSimple()) in your program.
|
||||
*/
|
||||
float getCPUTemperatureSimple(void) {
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
return 0.0;
|
||||
#else
|
||||
// use internal 1.1 volt as reference. 4 times oversample. Assume the signal has noise, but never verified :-(
|
||||
uint16_t tTemperatureRaw = readADCChannelWithReferenceOversample(ADC_TEMPERATURE_CHANNEL_MUX, INTERNAL, 2);
|
||||
#if defined(LOCAL_DEBUG)
|
||||
Serial.print(F("TempRaw="));
|
||||
Serial.println(tTemperatureRaw);
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATmega328PB__)
|
||||
tTemperatureRaw -= 245;
|
||||
return (float)tTemperatureRaw;
|
||||
#elif defined(__AVR_ATtiny85__)
|
||||
tTemperatureRaw -= 273; // 273 and 1.1666 are values from the datasheet
|
||||
return (float)tTemperatureRaw / 1.1666;
|
||||
#else
|
||||
tTemperatureRaw -= 317;
|
||||
return (float) tTemperatureRaw / 1.22;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Handles usage of 1.1 V reference and channel switching by introducing the appropriate delays.
|
||||
*/
|
||||
float getTemperature(void) {
|
||||
return getCPUTemperature();
|
||||
}
|
||||
float getCPUTemperature(void) {
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
return 0.0;
|
||||
#else
|
||||
// use internal 1.1 volt as reference
|
||||
checkAndWaitForReferenceAndChannelToSwitch(ADC_TEMPERATURE_CHANNEL_MUX, INTERNAL);
|
||||
return getCPUTemperatureSimple();
|
||||
#endif
|
||||
}
|
||||
|
||||
#else // defined(ADC_UTILS_ARE_AVAILABLE)
|
||||
// Dummy definition of functions defined in ADCUtils to compile examples for non AVR platforms without errors
|
||||
/*
|
||||
* Persistent storage for VCC value
|
||||
*/
|
||||
float sVCCVoltage;
|
||||
uint16_t sVCCVoltageMillivolt;
|
||||
|
||||
uint16_t getVCCVoltageMillivoltSimple(void){
|
||||
return 3300;
|
||||
}
|
||||
|
||||
uint16_t readADCChannelWithReferenceOversample(uint8_t aChannelNumber __attribute__((unused)),
|
||||
uint8_t aReference __attribute__((unused)), uint8_t aOversampleExponent __attribute__((unused))) {
|
||||
return 0;
|
||||
}
|
||||
float getCPUTemperature() {
|
||||
return 20.0;
|
||||
}
|
||||
float getVCCVoltage() {
|
||||
return 3.3;
|
||||
}
|
||||
#endif // defined(ADC_UTILS_ARE_AVAILABLE)
|
||||
|
||||
#if defined(LOCAL_DEBUG)
|
||||
#undef LOCAL_DEBUG
|
||||
#endif
|
||||
#endif // _ADC_UTILS_HPP
|
||||
@ -1,482 +0,0 @@
|
||||
/*
|
||||
* AllProtocolsOnLCD.cpp
|
||||
*
|
||||
* Modified ReceiveDemo.cpp with additional 1602 LCD output.
|
||||
* If debug button is pressed (pin connected to ground) a long output is generated.
|
||||
*
|
||||
* This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.
|
||||
*
|
||||
************************************************************************************
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Armin Joachimsmeyer
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
************************************************************************************
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "PinDefinitionsAndMore.h" // Define macros for input and output pin etc.
|
||||
|
||||
#if !defined(RAW_BUFFER_LENGTH)
|
||||
// For air condition remotes it requires 750. Default is 200.
|
||||
# if (defined(RAMEND) && RAMEND <= 0x4FF) || (defined(RAMSIZE) && RAMSIZE < 0x4FF)
|
||||
#define RAW_BUFFER_LENGTH 360
|
||||
# else
|
||||
#define RAW_BUFFER_LENGTH 750
|
||||
# endif
|
||||
|
||||
# if (defined(RAMEND) && RAMEND <= 0x8FF) || (defined(RAMSIZE) && RAMSIZE < 0x8FF)
|
||||
#define DISTANCE_WIDTH_DECODER_DURATION_ARRAY_SIZE 200 // The decoder accepts mark or space durations up to 200 * 50 (MICROS_PER_TICK) = 10 milliseconds
|
||||
# else
|
||||
#define DISTANCE_WIDTH_DECODER_DURATION_ARRAY_SIZE 400 // The decoder accepts mark or space durations up to 400 * 50 (MICROS_PER_TICK) = 20 milliseconds
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//#define NO_LED_FEEDBACK_CODE // saves 92 bytes program memory
|
||||
#if FLASHEND <= 0x1FFF // For 8k flash or less, like ATtiny85. Exclude exotic protocols.
|
||||
#define EXCLUDE_EXOTIC_PROTOCOLS
|
||||
# if !defined(DIGISTUMPCORE) // ATTinyCore is bigger than Digispark core
|
||||
#define EXCLUDE_UNIVERSAL_PROTOCOLS // Saves up to 1000 bytes program memory.
|
||||
# endif
|
||||
#endif
|
||||
//#define EXCLUDE_UNIVERSAL_PROTOCOLS // Saves up to 1000 bytes program memory.
|
||||
//#define EXCLUDE_EXOTIC_PROTOCOLS // saves around 650 bytes program memory if all other protocols are active
|
||||
|
||||
// MARK_EXCESS_MICROS is subtracted from all marks and added to all spaces before decoding,
|
||||
// to compensate for the signal forming of different IR receiver modules. See also IRremote.hpp line 142.
|
||||
#define MARK_EXCESS_MICROS 20 // Adapt it to your IR receiver module. 20 is recommended for the cheap VS1838 modules.
|
||||
|
||||
//#define RECORD_GAP_MICROS 12000 // Default is 8000. Activate it for some LG air conditioner protocols.
|
||||
|
||||
//#define DEBUG // Activate this for lots of lovely debug output from the decoders.
|
||||
//#define DECODE_NEC // Includes Apple and Onkyo
|
||||
|
||||
#include <IRremote.hpp>
|
||||
|
||||
/*
|
||||
* Activate the type of LCD you use
|
||||
* Default is parallel LCD with 2 rows of 16 characters (1602).
|
||||
* Serial LCD has the disadvantage, that the first repeat is not detected,
|
||||
* because of the long lasting serial communication.
|
||||
*/
|
||||
//#define USE_NO_LCD
|
||||
//#define USE_SERIAL_LCD
|
||||
// Definitions for the 1602 LCD
|
||||
#define LCD_COLUMNS 16
|
||||
#define LCD_ROWS 2
|
||||
|
||||
#if defined(USE_SERIAL_LCD)
|
||||
#include "LiquidCrystal_I2C.h" // Use an up to date library version, which has the init method
|
||||
LiquidCrystal_I2C myLCD(0x27, LCD_COLUMNS, LCD_ROWS); // set the LCD address to 0x27 for a 16 chars and 2 line display
|
||||
#elif !defined(USE_NO_LCD)
|
||||
#define USE_PARALLEL_LCD
|
||||
#include "LiquidCrystal.h"
|
||||
//LiquidCrystal myLCD(4, 5, 6, 7, 8, 9);
|
||||
LiquidCrystal myLCD(7, 8, 3, 4, 5, 6);
|
||||
#endif
|
||||
|
||||
#if defined(USE_PARALLEL_LCD)
|
||||
#define DEBUG_BUTTON_PIN 11 // If low, print timing for each received data set
|
||||
#undef TONE_PIN
|
||||
#define TONE_PIN 9 // Pin 4 is used by LCD
|
||||
#else
|
||||
#define DEBUG_BUTTON_PIN 6
|
||||
#endif
|
||||
#if defined(__AVR_ATmega328P__)
|
||||
#define AUXILIARY_DEBUG_BUTTON_PIN 12 // Is set to low to enable using of a simple connector for enabling debug with pin 11
|
||||
#endif
|
||||
|
||||
#define MILLIS_BETWEEN_ATTENTION_BEEP 60000 // 60 sec
|
||||
uint32_t sMillisOfLastReceivedIRFrame = 0;
|
||||
|
||||
#if defined(USE_SERIAL_LCD) || defined(USE_PARALLEL_LCD)
|
||||
#define USE_LCD
|
||||
# if defined(__AVR__) && defined(ADCSRA) && defined(ADATE)
|
||||
// For cyclically display of VCC and isVCCUSBPowered()
|
||||
#define VOLTAGE_USB_POWERED_LOWER_THRESHOLD_MILLIVOLT 4250
|
||||
#include "ADCUtils.hpp"
|
||||
#define MILLIS_BETWEEN_VOLTAGE_PRINT 5000
|
||||
#define LCD_VOLTAGE_START_INDEX 11
|
||||
uint32_t volatile sMillisOfLastVoltagePrint = 0;
|
||||
bool ProtocolStringOverwritesVoltage = false;
|
||||
# endif
|
||||
#define LCD_IR_COMMAND_START_INDEX 9
|
||||
|
||||
void printsVCCVoltageMillivoltOnLCD();
|
||||
void printIRResultOnLCD();
|
||||
size_t printByteHexOnLCD(uint16_t aHexByteValue);
|
||||
void printSpacesOnLCD(uint_fast8_t aNumberOfSpacesToPrint);
|
||||
|
||||
#endif // defined(USE_SERIAL_LCD) || defined(USE_PARALLEL_LCD)
|
||||
|
||||
void setup() {
|
||||
#if FLASHEND >= 0x3FFF // For 16k flash or more, like ATtiny1604. Code does not fit in program memory of ATtiny85 etc.
|
||||
pinMode(DEBUG_BUTTON_PIN, INPUT_PULLUP);
|
||||
# if defined(AUXILIARY_DEBUG_BUTTON_PIN)
|
||||
pinMode(AUXILIARY_DEBUG_BUTTON_PIN, OUTPUT);
|
||||
digitalWrite(AUXILIARY_DEBUG_BUTTON_PIN, LOW); // To use a simple connector to enable debug
|
||||
# endif
|
||||
#endif
|
||||
|
||||
Serial.begin(115200);
|
||||
while (!Serial)
|
||||
; // Wait for Serial to become available. Is optimized away for some cores.
|
||||
|
||||
#if defined(__AVR_ATmega32U4__) || defined(SERIAL_PORT_USBVIRTUAL) || defined(SERIAL_USB) /*stm32duino*/|| defined(USBCON) /*STM32_stm32*/ \
|
||||
|| defined(SERIALUSB_PID) || defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_attiny3217)
|
||||
delay(4000); // To be able to connect Serial monitor after reset or power up and before first print out. Do not wait for an attached Serial Monitor!
|
||||
#endif
|
||||
// Just to know which program is running on my Arduino
|
||||
Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE));
|
||||
|
||||
tone(TONE_PIN, 2200);
|
||||
delay(200);
|
||||
noTone(TONE_PIN);
|
||||
|
||||
// In case the interrupt driver crashes on setup, give a clue
|
||||
// to the user what's going on.
|
||||
Serial.println(F("Enabling IRin..."));
|
||||
|
||||
// Start the receiver and if not 3. parameter specified, take LED_BUILTIN pin from the internal boards definition as default feedback LED
|
||||
IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);
|
||||
|
||||
Serial.print(F("Ready to receive IR signals of protocols: "));
|
||||
printActiveIRProtocols(&Serial);
|
||||
Serial.println(F("at pin " STR(IR_RECEIVE_PIN)));
|
||||
|
||||
#if defined(USE_SERIAL_LCD)
|
||||
Serial.println(
|
||||
F("With serial LCD connection, the first repeat is not detected, because of the long lasting serial communication!"));
|
||||
#endif
|
||||
|
||||
#if FLASHEND >= 0x3FFF // For 16k flash or more, like ATtiny1604. Code does not fit in program memory of ATtiny85 etc.
|
||||
Serial.println();
|
||||
Serial.print(F("If you connect debug pin "));
|
||||
# if defined(APPLICATION_PIN_STRING)
|
||||
Serial.print(APPLICATION_PIN_STRING);
|
||||
# else
|
||||
Serial.print(DEBUG_BUTTON_PIN);
|
||||
# endif
|
||||
Serial.print(F(" to ground"));
|
||||
# if defined(AUXILIARY_DEBUG_BUTTON_PIN)
|
||||
Serial.print(F(" or to pin "));
|
||||
Serial.print(AUXILIARY_DEBUG_BUTTON_PIN);
|
||||
#endif
|
||||
Serial.println(F(", raw data is always printed"));
|
||||
|
||||
// Info for receive
|
||||
Serial.print(RECORD_GAP_MICROS);
|
||||
Serial.println(F(" us is the (minimum) gap, after which the start of a new IR packet is assumed"));
|
||||
Serial.print(MARK_EXCESS_MICROS);
|
||||
Serial.println(F(" us are subtracted from all marks and added to all spaces for decoding"));
|
||||
#endif
|
||||
|
||||
#if defined(USE_LCD) && defined(ADC_UTILS_ARE_AVAILABLE)
|
||||
readVCCVoltageMillivolt();
|
||||
#endif
|
||||
|
||||
#if defined(USE_SERIAL_LCD)
|
||||
myLCD.init();
|
||||
myLCD.clear();
|
||||
myLCD.backlight(); // Switch backlight LED on
|
||||
#endif
|
||||
#if defined(USE_PARALLEL_LCD)
|
||||
myLCD.begin(LCD_COLUMNS, LCD_ROWS); // This also clears display
|
||||
#endif
|
||||
|
||||
#if defined(USE_LCD)
|
||||
myLCD.setCursor(0, 0);
|
||||
myLCD.print(F("IRRemote v" VERSION_IRREMOTE));
|
||||
myLCD.setCursor(0, 1);
|
||||
myLCD.print(F(__DATE__));
|
||||
#endif
|
||||
|
||||
#if defined(USE_LCD) && defined(ADC_UTILS_ARE_AVAILABLE)
|
||||
readVCCVoltageMillivolt();
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
/*
|
||||
* Check if received data is available and if yes, try to decode it.
|
||||
* Decoded result is in the IrReceiver.decodedIRData structure.
|
||||
*
|
||||
* E.g. command is in IrReceiver.decodedIRData.command
|
||||
* address is in command is in IrReceiver.decodedIRData.address
|
||||
* and up to 32 bit raw data in IrReceiver.decodedIRData.decodedRawData
|
||||
*/
|
||||
if (IrReceiver.decode()) {
|
||||
Serial.println();
|
||||
// Print a short summary of received data
|
||||
IrReceiver.printIRResultShort(&Serial);
|
||||
|
||||
if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_WAS_OVERFLOW) {
|
||||
Serial.println(F("Try to increase the \"RAW_BUFFER_LENGTH\" value of " STR(RAW_BUFFER_LENGTH) " in " __FILE__));
|
||||
#if defined(USE_LCD)
|
||||
myLCD.setCursor(0, 0);
|
||||
myLCD.print(F("Overflow "));
|
||||
#endif
|
||||
|
||||
// see also https://github.com/Arduino-IRremote/Arduino-IRremote#compile-options--macros-for-this-library
|
||||
|
||||
} else {
|
||||
// play tone
|
||||
auto tStartMillis = millis();
|
||||
// IrReceiver.stopTimer(); // Not really required for Uno, but we then should use restartTimer(aMicrosecondsToAddToGapCounter)
|
||||
tone(TONE_PIN, 2200);
|
||||
|
||||
if ((IrReceiver.decodedIRData.protocol == UNKNOWN || digitalRead(DEBUG_BUTTON_PIN) == LOW)
|
||||
#if defined(USE_LCD) && defined(ADC_UTILS_ARE_AVAILABLE)
|
||||
|| isVCCUSBPowered()
|
||||
#endif
|
||||
) {
|
||||
// Print more info, but only if we are connected to USB, i.e. VCC is > 4300 mV, because this may take to long to detect some fast repeats
|
||||
IrReceiver.printIRSendUsage(&Serial);
|
||||
// IrReceiver.printIRResultRawFormatted(&Serial, false); // print ticks, this is faster :-)
|
||||
IrReceiver.printIRResultRawFormatted(&Serial); // print us, this is better to compare :-)
|
||||
}
|
||||
|
||||
// Guarantee at least 5 millis for tone. decode starts 5 millis (RECORD_GAP_MICROS) after end of frame
|
||||
// so here we are 10 millis after end of frame. Sony20 has only a 12 ms repeat gap.
|
||||
while ((millis() - tStartMillis) < 5)
|
||||
;
|
||||
noTone(TONE_PIN);
|
||||
IrReceiver.restartTimer(5000); // Restart IR timer.
|
||||
|
||||
#if defined(USE_LCD)
|
||||
printIRResultOnLCD();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* !!!Important!!! Enable receiving of the next value,
|
||||
* since receiving has stopped after the end of the current received data packet.
|
||||
*/
|
||||
IrReceiver.resume();
|
||||
} // if (IrReceiver.decode())
|
||||
|
||||
/*
|
||||
* Check if generating attention beep every minute, after the current measurement was finished
|
||||
*/
|
||||
if ((millis() - sMillisOfLastReceivedIRFrame) >= MILLIS_BETWEEN_ATTENTION_BEEP
|
||||
#if defined(USE_LCD) && defined(ADC_UTILS_ARE_AVAILABLE)
|
||||
&& !isVCCUSBPowered()
|
||||
#endif
|
||||
) {
|
||||
sMillisOfLastReceivedIRFrame = millis();
|
||||
#if defined(USE_LCD) && defined(ADC_UTILS_ARE_AVAILABLE)
|
||||
printsVCCVoltageMillivoltOnLCD();
|
||||
#endif
|
||||
// IrReceiver.stopTimer(); // Not really required for Uno, but we then should use restartTimer(aMicrosecondsToAddToGapCounter)
|
||||
tone(TONE_PIN, 2200);
|
||||
delay(50);
|
||||
noTone(TONE_PIN);
|
||||
IrReceiver.restartTimer(50000);
|
||||
}
|
||||
|
||||
#if defined(USE_LCD) && defined(ADC_UTILS_ARE_AVAILABLE)
|
||||
//Periodically print VCC
|
||||
if (!ProtocolStringOverwritesVoltage && millis() - sMillisOfLastVoltagePrint > MILLIS_BETWEEN_VOLTAGE_PRINT) {
|
||||
/*
|
||||
* Periodically print VCC
|
||||
*/
|
||||
sMillisOfLastVoltagePrint = millis();
|
||||
readVCCVoltageMillivolt();
|
||||
printsVCCVoltageMillivoltOnLCD();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if defined(USE_LCD)
|
||||
void printsVCCVoltageMillivoltOnLCD() {
|
||||
# if defined(ADC_UTILS_ARE_AVAILABLE)
|
||||
char tVoltageString[5];
|
||||
dtostrf(sVCCVoltageMillivolt / 1000.0, 4, 2, tVoltageString);
|
||||
myLCD.setCursor(LCD_VOLTAGE_START_INDEX - 1, 0);
|
||||
myLCD.print(' ');
|
||||
myLCD.print(tVoltageString);
|
||||
myLCD.print('V');
|
||||
# endif
|
||||
}
|
||||
|
||||
/*
|
||||
* LCD output for 1602 LCDs
|
||||
* 40 - 55 Milliseconds per initial output
|
||||
* The expander runs at 100 kHz :-(
|
||||
* 8 milliseconds for 8 bit; 10 ms for 16 bit code output
|
||||
* 3 milliseconds for repeat output
|
||||
*
|
||||
*/
|
||||
void printIRResultOnLCD() {
|
||||
static uint16_t sLastProtocolIndex = 4711;
|
||||
static uint16_t sLastProtocolAddress = 4711;
|
||||
static uint16_t sLastCommand = 0;
|
||||
static uint8_t sLastCommandPrintPosition;
|
||||
|
||||
/*
|
||||
* Print only if protocol has changed
|
||||
*/
|
||||
if (sLastProtocolIndex != IrReceiver.decodedIRData.protocol) {
|
||||
sLastProtocolIndex = IrReceiver.decodedIRData.protocol;
|
||||
/*
|
||||
* Show protocol name and handle overwrite over voltage display
|
||||
*/
|
||||
myLCD.setCursor(0, 0);
|
||||
uint_fast8_t tProtocolStringLength = myLCD.print(getProtocolString(IrReceiver.decodedIRData.protocol));
|
||||
# if defined(__AVR__) && defined(ADCSRA) && defined(ADATE)
|
||||
if (tProtocolStringLength > LCD_VOLTAGE_START_INDEX) {
|
||||
// we overwrite the voltage -> clear rest of line and inhibit new printing of voltage
|
||||
ProtocolStringOverwritesVoltage = true;
|
||||
if (tProtocolStringLength < LCD_COLUMNS) {
|
||||
printSpacesOnLCD(LCD_COLUMNS - tProtocolStringLength);
|
||||
}
|
||||
} else {
|
||||
// Trigger printing of VCC in main loop
|
||||
sMillisOfLastVoltagePrint = 0;
|
||||
ProtocolStringOverwritesVoltage = false;
|
||||
printSpacesOnLCD(LCD_VOLTAGE_START_INDEX - tProtocolStringLength);
|
||||
}
|
||||
# else
|
||||
printSpacesOnLCD(LCD_COLUMNS - tProtocolStringLength);
|
||||
# endif
|
||||
}
|
||||
|
||||
if (IrReceiver.decodedIRData.protocol == UNKNOWN) {
|
||||
/*
|
||||
* Print number of bits received and hash code or microseconds of signal
|
||||
*/
|
||||
myLCD.setCursor(0, 1);
|
||||
uint8_t tNumberOfBits = (IrReceiver.decodedIRData.rawDataPtr->rawlen + 1) / 2;
|
||||
uint_fast8_t tPrintedStringLength = myLCD.print(tNumberOfBits);
|
||||
myLCD.print(F(" bit "));
|
||||
|
||||
if (IrReceiver.decodedIRData.decodedRawData != 0) {
|
||||
if (tNumberOfBits < 10) {
|
||||
myLCD.print('0');
|
||||
tPrintedStringLength++;
|
||||
}
|
||||
myLCD.print('x');
|
||||
tPrintedStringLength += myLCD.print(IrReceiver.decodedIRData.decodedRawData, HEX) + 1;
|
||||
} else {
|
||||
tPrintedStringLength += myLCD.print(IrReceiver.getTotalDurationOfRawData());
|
||||
myLCD.print(F(" \xE4s")); // \xE4 is micro symbol
|
||||
}
|
||||
printSpacesOnLCD(11 - tPrintedStringLength);
|
||||
sLastProtocolAddress = 4711;
|
||||
sLastCommand = 44711;
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Protocol is know here
|
||||
* Print address only if it has changed
|
||||
*/
|
||||
if (sLastProtocolAddress != IrReceiver.decodedIRData.address || IrReceiver.decodedIRData.protocol == PULSE_DISTANCE
|
||||
|| IrReceiver.decodedIRData.protocol == PULSE_WIDTH) {
|
||||
|
||||
myLCD.setCursor(0, 1);
|
||||
/*
|
||||
* Show address
|
||||
*/
|
||||
# if defined(DECODE_DISTANCE_WIDTH)
|
||||
if (IrReceiver.decodedIRData.protocol == PULSE_DISTANCE || IrReceiver.decodedIRData.protocol == PULSE_WIDTH) {
|
||||
sLastProtocolAddress = 4711; // To enforce next print of address
|
||||
myLCD.print(F("[0]=0x"));
|
||||
uint_fast8_t tAddressStringLength = myLCD.print(IrReceiver.decodedIRData.decodedRawDataArray[0], HEX);
|
||||
printSpacesOnLCD(LCD_COLUMNS - tAddressStringLength);
|
||||
sLastCommand = 0; // to trigger restoration of "C=" string, if another protocol is received
|
||||
/*
|
||||
* No command here!
|
||||
*/
|
||||
return;
|
||||
|
||||
} else {
|
||||
# endif
|
||||
sLastProtocolAddress = IrReceiver.decodedIRData.address;
|
||||
// Serial.print(F("Print address 0x"));
|
||||
// Serial.println(IrReceiver.decodedIRData.address, HEX);
|
||||
myLCD.print(F("A="));
|
||||
uint_fast8_t tAddressStringLength = printByteHexOnLCD(IrReceiver.decodedIRData.address);
|
||||
printSpacesOnLCD((LCD_IR_COMMAND_START_INDEX - 2) - tAddressStringLength);
|
||||
# if defined(DECODE_DISTANCE_WIDTH)
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Print command always
|
||||
*/
|
||||
uint16_t tCommand = IrReceiver.decodedIRData.command;
|
||||
|
||||
// Check if prefix position must change
|
||||
if (sLastCommand == 0 || (sLastCommand >= 0x100 && tCommand < 0x100) || (sLastCommand < 0x100 && tCommand >= 0x100)) {
|
||||
sLastCommand = tCommand;
|
||||
/*
|
||||
* Print prefix for 8/16 bit commands
|
||||
*/
|
||||
if (tCommand >= 0x100) {
|
||||
// Do not print "C=" here to have 2 additional characters for command
|
||||
sLastCommandPrintPosition = 9;
|
||||
} else {
|
||||
myLCD.setCursor(LCD_IR_COMMAND_START_INDEX, 1);
|
||||
myLCD.print(F("C="));
|
||||
sLastCommandPrintPosition = 11;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Command data
|
||||
*/
|
||||
// Serial.print(F("Print command 0x"));
|
||||
// Serial.print(tCommand, HEX);
|
||||
// Serial.print(F(" at "));
|
||||
// Serial.println(sLastCommandPrintPosition);
|
||||
myLCD.setCursor(sLastCommandPrintPosition, 1);
|
||||
printByteHexOnLCD(tCommand);
|
||||
|
||||
/*
|
||||
* Show or clear repetition flag
|
||||
*/
|
||||
if (IrReceiver.decodedIRData.flags & (IRDATA_FLAGS_IS_REPEAT)) {
|
||||
myLCD.print('R');
|
||||
return; // Since it is a repetition, printed data has not changed
|
||||
} else {
|
||||
myLCD.print(' ');
|
||||
}
|
||||
} // IrReceiver.decodedIRData.protocol == UNKNOWN
|
||||
}
|
||||
|
||||
size_t printByteHexOnLCD(uint16_t aHexByteValue) {
|
||||
myLCD.print(F("0x"));
|
||||
size_t tPrintSize = 2;
|
||||
if (aHexByteValue < 0x10 || (aHexByteValue > 0x100 && aHexByteValue < 0x1000)) {
|
||||
myLCD.print('0'); // leading 0
|
||||
tPrintSize++;
|
||||
}
|
||||
return myLCD.print(aHexByteValue, HEX) + tPrintSize;
|
||||
}
|
||||
|
||||
void printSpacesOnLCD(uint_fast8_t aNumberOfSpacesToPrint) {
|
||||
for (uint_fast8_t i = 0; i < aNumberOfSpacesToPrint; ++i) {
|
||||
myLCD.print(' ');
|
||||
}
|
||||
}
|
||||
#endif // defined(USE_LCD)
|
||||
@ -1,326 +0,0 @@
|
||||
#include "LiquidCrystal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "Arduino.h"
|
||||
|
||||
// When the display powers up, it is configured as follows:
|
||||
//
|
||||
// 1. Display clear
|
||||
// 2. Function set:
|
||||
// DL = 1; 8-bit interface data
|
||||
// N = 0; 1-line display
|
||||
// F = 0; 5x8 dot character font
|
||||
// 3. Display on/off control:
|
||||
// D = 0; Display off
|
||||
// C = 0; Cursor off
|
||||
// B = 0; Blinking off
|
||||
// 4. Entry mode set:
|
||||
// I/D = 1; Increment by 1
|
||||
// S = 0; No shift
|
||||
//
|
||||
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
|
||||
// can't assume that its in that state when a sketch starts (and the
|
||||
// LiquidCrystal constructor is called).
|
||||
|
||||
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
||||
{
|
||||
init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
|
||||
}
|
||||
|
||||
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
||||
{
|
||||
init(0, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
|
||||
}
|
||||
|
||||
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
|
||||
{
|
||||
init(1, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
|
||||
{
|
||||
init(1, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void LiquidCrystal::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
||||
{
|
||||
_rs_pin = rs;
|
||||
_rw_pin = rw;
|
||||
_enable_pin = enable;
|
||||
|
||||
_data_pins[0] = d0;
|
||||
_data_pins[1] = d1;
|
||||
_data_pins[2] = d2;
|
||||
_data_pins[3] = d3;
|
||||
_data_pins[4] = d4;
|
||||
_data_pins[5] = d5;
|
||||
_data_pins[6] = d6;
|
||||
_data_pins[7] = d7;
|
||||
|
||||
if (fourbitmode)
|
||||
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
||||
else
|
||||
_displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
||||
|
||||
begin(16, 1);
|
||||
}
|
||||
|
||||
void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
|
||||
if (lines > 1) {
|
||||
_displayfunction |= LCD_2LINE;
|
||||
}
|
||||
_numlines = lines;
|
||||
|
||||
setRowOffsets(0x00, 0x40, 0x00 + cols, 0x40 + cols);
|
||||
|
||||
// for some 1 line displays you can select a 10 pixel high font
|
||||
if ((dotsize != LCD_5x8DOTS) && (lines == 1)) {
|
||||
_displayfunction |= LCD_5x10DOTS;
|
||||
}
|
||||
|
||||
pinMode(_rs_pin, OUTPUT);
|
||||
// we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
|
||||
if (_rw_pin != 255) {
|
||||
pinMode(_rw_pin, OUTPUT);
|
||||
}
|
||||
pinMode(_enable_pin, OUTPUT);
|
||||
|
||||
// Do these once, instead of every time a character is drawn for speed reasons.
|
||||
for (int i=0; i<((_displayfunction & LCD_8BITMODE) ? 8 : 4); ++i)
|
||||
{
|
||||
pinMode(_data_pins[i], OUTPUT);
|
||||
}
|
||||
|
||||
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
|
||||
// according to datasheet, we need at least 40ms after power rises above 2.7V
|
||||
// before sending commands. Arduino can turn on way before 4.5V so we'll wait 50
|
||||
delayMicroseconds(50000);
|
||||
// Now we pull both RS and R/W low to begin commands
|
||||
digitalWrite(_rs_pin, LOW);
|
||||
digitalWrite(_enable_pin, LOW);
|
||||
if (_rw_pin != 255) {
|
||||
digitalWrite(_rw_pin, LOW);
|
||||
}
|
||||
|
||||
//put the LCD into 4 bit or 8 bit mode
|
||||
if (! (_displayfunction & LCD_8BITMODE)) {
|
||||
// this is according to the hitachi HD44780 datasheet
|
||||
// figure 24, pg 46
|
||||
|
||||
// we start in 8bit mode, try to set 4 bit mode
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// second try
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// third go!
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// finally, set to 4-bit interface
|
||||
write4bits(0x02);
|
||||
} else {
|
||||
// this is according to the hitachi HD44780 datasheet
|
||||
// page 45 figure 23
|
||||
|
||||
// Send function set command sequence
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
delayMicroseconds(4500); // wait more than 4.1ms
|
||||
|
||||
// second try
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// third go
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
}
|
||||
|
||||
// finally, set # lines, font size, etc.
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
|
||||
// turn the display on with no cursor or blinking default
|
||||
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
|
||||
display();
|
||||
|
||||
// clear it off
|
||||
clear();
|
||||
|
||||
// Initialize to default text direction (for romance languages)
|
||||
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
|
||||
// set the entry mode
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
|
||||
}
|
||||
|
||||
void LiquidCrystal::setRowOffsets(int row0, int row1, int row2, int row3)
|
||||
{
|
||||
_row_offsets[0] = row0;
|
||||
_row_offsets[1] = row1;
|
||||
_row_offsets[2] = row2;
|
||||
_row_offsets[3] = row3;
|
||||
}
|
||||
|
||||
/********** high level commands, for the user! */
|
||||
void LiquidCrystal::clear()
|
||||
{
|
||||
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
}
|
||||
|
||||
void LiquidCrystal::home()
|
||||
{
|
||||
command(LCD_RETURNHOME); // set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
}
|
||||
|
||||
void LiquidCrystal::setCursor(uint8_t col, uint8_t row)
|
||||
{
|
||||
const size_t max_lines = sizeof(_row_offsets) / sizeof(*_row_offsets);
|
||||
if ( row >= max_lines ) {
|
||||
row = max_lines - 1; // we count rows starting w/0
|
||||
}
|
||||
if ( row >= _numlines ) {
|
||||
row = _numlines - 1; // we count rows starting w/0
|
||||
}
|
||||
|
||||
command(LCD_SETDDRAMADDR | (col + _row_offsets[row]));
|
||||
}
|
||||
|
||||
// Turn the display on/off (quickly)
|
||||
void LiquidCrystal::noDisplay() {
|
||||
_displaycontrol &= ~LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal::display() {
|
||||
_displaycontrol |= LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// Turns the underline cursor on/off
|
||||
void LiquidCrystal::noCursor() {
|
||||
_displaycontrol &= ~LCD_CURSORON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal::cursor() {
|
||||
_displaycontrol |= LCD_CURSORON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// Turn on and off the blinking cursor
|
||||
void LiquidCrystal::noBlink() {
|
||||
_displaycontrol &= ~LCD_BLINKON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal::blink() {
|
||||
_displaycontrol |= LCD_BLINKON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// These commands scroll the display without changing the RAM
|
||||
void LiquidCrystal::scrollDisplayLeft(void) {
|
||||
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
|
||||
}
|
||||
void LiquidCrystal::scrollDisplayRight(void) {
|
||||
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
|
||||
}
|
||||
|
||||
// This is for text that flows Left to Right
|
||||
void LiquidCrystal::leftToRight(void) {
|
||||
_displaymode |= LCD_ENTRYLEFT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This is for text that flows Right to Left
|
||||
void LiquidCrystal::rightToLeft(void) {
|
||||
_displaymode &= ~LCD_ENTRYLEFT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This will 'right justify' text from the cursor
|
||||
void LiquidCrystal::autoscroll(void) {
|
||||
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This will 'left justify' text from the cursor
|
||||
void LiquidCrystal::noAutoscroll(void) {
|
||||
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// Allows us to fill the first 8 CGRAM locations
|
||||
// with custom characters
|
||||
void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) {
|
||||
location &= 0x7; // we only have 8 locations 0-7
|
||||
command(LCD_SETCGRAMADDR | (location << 3));
|
||||
for (int i=0; i<8; i++) {
|
||||
write(charmap[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*********** mid level commands, for sending data/cmds */
|
||||
|
||||
inline void LiquidCrystal::command(uint8_t value) {
|
||||
send(value, LOW);
|
||||
}
|
||||
|
||||
inline size_t LiquidCrystal::write(uint8_t value) {
|
||||
send(value, HIGH);
|
||||
return 1; // assume sucess
|
||||
}
|
||||
|
||||
/************ low level data pushing commands **********/
|
||||
|
||||
// write either command or data, with automatic 4/8-bit selection
|
||||
void LiquidCrystal::send(uint8_t value, uint8_t mode) {
|
||||
digitalWrite(_rs_pin, mode);
|
||||
|
||||
// if there is a RW pin indicated, set it low to Write
|
||||
if (_rw_pin != 255) {
|
||||
digitalWrite(_rw_pin, LOW);
|
||||
}
|
||||
|
||||
if (_displayfunction & LCD_8BITMODE) {
|
||||
write8bits(value);
|
||||
} else {
|
||||
write4bits(value>>4);
|
||||
write4bits(value);
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidCrystal::pulseEnable(void) {
|
||||
digitalWrite(_enable_pin, LOW);
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(_enable_pin, HIGH);
|
||||
delayMicroseconds(1); // enable pulse must be >450ns
|
||||
digitalWrite(_enable_pin, LOW);
|
||||
delayMicroseconds(100); // commands need > 37us to settle
|
||||
}
|
||||
|
||||
void LiquidCrystal::write4bits(uint8_t value) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
digitalWrite(_data_pins[i], (value >> i) & 0x01);
|
||||
}
|
||||
|
||||
pulseEnable();
|
||||
}
|
||||
|
||||
void LiquidCrystal::write8bits(uint8_t value) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
digitalWrite(_data_pins[i], (value >> i) & 0x01);
|
||||
}
|
||||
|
||||
pulseEnable();
|
||||
}
|
||||
@ -1,108 +0,0 @@
|
||||
#ifndef LiquidCrystal_h
|
||||
#define LiquidCrystal_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "Print.h"
|
||||
|
||||
// commands
|
||||
#define LCD_CLEARDISPLAY 0x01
|
||||
#define LCD_RETURNHOME 0x02
|
||||
#define LCD_ENTRYMODESET 0x04
|
||||
#define LCD_DISPLAYCONTROL 0x08
|
||||
#define LCD_CURSORSHIFT 0x10
|
||||
#define LCD_FUNCTIONSET 0x20
|
||||
#define LCD_SETCGRAMADDR 0x40
|
||||
#define LCD_SETDDRAMADDR 0x80
|
||||
|
||||
// flags for display entry mode
|
||||
#define LCD_ENTRYRIGHT 0x00
|
||||
#define LCD_ENTRYLEFT 0x02
|
||||
#define LCD_ENTRYSHIFTINCREMENT 0x01
|
||||
#define LCD_ENTRYSHIFTDECREMENT 0x00
|
||||
|
||||
// flags for display on/off control
|
||||
#define LCD_DISPLAYON 0x04
|
||||
#define LCD_DISPLAYOFF 0x00
|
||||
#define LCD_CURSORON 0x02
|
||||
#define LCD_CURSOROFF 0x00
|
||||
#define LCD_BLINKON 0x01
|
||||
#define LCD_BLINKOFF 0x00
|
||||
|
||||
// flags for display/cursor shift
|
||||
#define LCD_DISPLAYMOVE 0x08
|
||||
#define LCD_CURSORMOVE 0x00
|
||||
#define LCD_MOVERIGHT 0x04
|
||||
#define LCD_MOVELEFT 0x00
|
||||
|
||||
// flags for function set
|
||||
#define LCD_8BITMODE 0x10
|
||||
#define LCD_4BITMODE 0x00
|
||||
#define LCD_2LINE 0x08
|
||||
#define LCD_1LINE 0x00
|
||||
#define LCD_5x10DOTS 0x04
|
||||
#define LCD_5x8DOTS 0x00
|
||||
|
||||
class LiquidCrystal : public Print {
|
||||
public:
|
||||
LiquidCrystal(uint8_t rs, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
|
||||
LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
|
||||
LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3);
|
||||
LiquidCrystal(uint8_t rs, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3);
|
||||
|
||||
void init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
|
||||
|
||||
void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
|
||||
|
||||
void clear();
|
||||
void home();
|
||||
|
||||
void noDisplay();
|
||||
void display();
|
||||
void noBlink();
|
||||
void blink();
|
||||
void noCursor();
|
||||
void cursor();
|
||||
void scrollDisplayLeft();
|
||||
void scrollDisplayRight();
|
||||
void leftToRight();
|
||||
void rightToLeft();
|
||||
void autoscroll();
|
||||
void noAutoscroll();
|
||||
|
||||
void setRowOffsets(int row1, int row2, int row3, int row4);
|
||||
void createChar(uint8_t, uint8_t[]);
|
||||
void setCursor(uint8_t, uint8_t);
|
||||
virtual size_t write(uint8_t);
|
||||
void command(uint8_t);
|
||||
|
||||
using Print::write;
|
||||
private:
|
||||
void send(uint8_t, uint8_t);
|
||||
void write4bits(uint8_t);
|
||||
void write8bits(uint8_t);
|
||||
void pulseEnable();
|
||||
|
||||
uint8_t _rs_pin; // LOW: command. HIGH: character.
|
||||
uint8_t _rw_pin; // LOW: write to LCD. HIGH: read from LCD.
|
||||
uint8_t _enable_pin; // activated by a HIGH pulse.
|
||||
uint8_t _data_pins[8];
|
||||
|
||||
uint8_t _displayfunction;
|
||||
uint8_t _displaycontrol;
|
||||
uint8_t _displaymode;
|
||||
|
||||
uint8_t _initialized;
|
||||
|
||||
uint8_t _numlines;
|
||||
uint8_t _row_offsets[4];
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,375 +0,0 @@
|
||||
// LiquidCrystal_I2C.hpp
|
||||
// Based on the work by DFRobot
|
||||
/*
|
||||
* Extensions made by AJ 2023
|
||||
* Removed Arduino 0.x support
|
||||
* Added SoftI2CMaste support, which drastically reduces program size.
|
||||
* Added OLED stuff
|
||||
* Added createChar() with PROGMEM input
|
||||
* Added fast timing
|
||||
*/
|
||||
#ifndef _LIQUID_CRYSTAL_I2C_HPP
|
||||
#define _LIQUID_CRYSTAL_I2C_HPP
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#if defined(__AVR__) && !defined(USE_SOFT_I2C_MASTER) && __has_include("SoftI2CMasterConfig.h")
|
||||
#define USE_SOFT_I2C_MASTER // must be before #include "LiquidCrystal_I2C.h"
|
||||
#endif
|
||||
|
||||
#include "LiquidCrystal_I2C.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
inline size_t LiquidCrystal_I2C::write(uint8_t value) {
|
||||
send(value, Rs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(USE_SOFT_I2C_MASTER)
|
||||
//#define USE_SOFT_I2C_MASTER_H_AS_PLAIN_INCLUDE
|
||||
#include "SoftI2CMasterConfig.h" // Include configuration for sources
|
||||
#include "SoftI2CMaster.h" // include sources
|
||||
#elif defined(USE_SOFT_WIRE)
|
||||
#define USE_SOFTWIRE_H_AS_PLAIN_INCLUDE
|
||||
#include "SoftWire.h"
|
||||
#endif
|
||||
|
||||
#if defined(__AVR__)
|
||||
/*
|
||||
* The datasheet says: a command need > 37us to settle. Enable pulse must be > 450ns.
|
||||
* Use no delay for enable pulse after each command,
|
||||
* because the overhead of this library seems to be using the 37 us and 450 ns.
|
||||
* At least it works perfectly for all my LCD's connected to Uno, Nano etc.
|
||||
* and it saves a lot of time in realtime applications using LCD as display,
|
||||
* like https://github.com/ArminJo/Arduino-DTSU666H_PowerMeter
|
||||
*/
|
||||
#define USE_FAST_TIMING
|
||||
#endif
|
||||
|
||||
// When the display powers up, it is configured as follows:
|
||||
//
|
||||
// 1. Display clear
|
||||
// 2. Function set:
|
||||
// DL = 1; 8-bit interface data
|
||||
// N = 0; 1-line display
|
||||
// F = 0; 5x8 dot character font
|
||||
// 3. Display on/off control:
|
||||
// D = 0; Display off
|
||||
// C = 0; Cursor off
|
||||
// B = 0; Blinking off
|
||||
// 4. Entry mode set:
|
||||
// I/D = 1; Increment by 1
|
||||
// S = 0; No shift
|
||||
//
|
||||
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
|
||||
// can't assume that its in that state when a sketch starts (and the
|
||||
// LiquidCrystal constructor is called).
|
||||
|
||||
LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t lcd_cols, uint8_t lcd_rows) {
|
||||
_Addr = lcd_Addr;
|
||||
_cols = lcd_cols;
|
||||
_rows = lcd_rows;
|
||||
_backlightval = LCD_NOBACKLIGHT;
|
||||
_oled = false;
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::oled_init() {
|
||||
_oled = true;
|
||||
init_priv();
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::init() {
|
||||
init_priv();
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::init_priv() {
|
||||
#if defined(USE_SOFT_I2C_MASTER)
|
||||
i2c_init();
|
||||
#else
|
||||
Wire.begin();
|
||||
#endif
|
||||
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
||||
begin(_cols, _rows);
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::begin(uint8_t cols __attribute__((unused)), uint8_t lines, uint8_t dotsize) {
|
||||
if (lines > 1) {
|
||||
_displayfunction |= LCD_2LINE;
|
||||
}
|
||||
_numlines = lines;
|
||||
|
||||
// for some 1 line displays you can select a 10 pixel high font
|
||||
if ((dotsize != 0) && (lines == 1)) {
|
||||
_displayfunction |= LCD_5x10DOTS;
|
||||
}
|
||||
|
||||
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
|
||||
// according to datasheet, we need at least 40ms after power rises above 2.7V
|
||||
// before sending commands. Arduino can turn on way before 4.5V so we'll wait 50
|
||||
delay(50);
|
||||
|
||||
// Now we pull both RS and R/W low to begin commands
|
||||
expanderWrite(_backlightval); // reset expander and turn backlight off (Bit 8 =1)
|
||||
delay(1000);
|
||||
|
||||
//put the LCD into 4 bit mode
|
||||
// this is according to the hitachi HD44780 datasheet
|
||||
// figure 24, pg 46
|
||||
|
||||
// we start in 8bit mode, try to set 4 bit mode
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// second try
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// third go!
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// finally, set to 4-bit interface
|
||||
write4bits(0x02 << 4);
|
||||
|
||||
// set # lines, font size, etc.
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
|
||||
// turn the display on with no cursor or blinking default
|
||||
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
|
||||
display();
|
||||
|
||||
// clear it off
|
||||
clear();
|
||||
|
||||
// Initialize to default text direction (for roman languages)
|
||||
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
|
||||
|
||||
// set the entry mode
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
|
||||
home();
|
||||
|
||||
}
|
||||
|
||||
/********** high level commands, for the user! */
|
||||
void LiquidCrystal_I2C::clear() {
|
||||
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
||||
#if defined(USE_FAST_TIMING)
|
||||
delayMicroseconds(1500); // this command takes a long time! // AJ 20.9.23 1200 is too short for my 2004 LCD's, 1400 is OK
|
||||
#else
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
#endif
|
||||
if (_oled)
|
||||
setCursor(0, 0);
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::home() {
|
||||
command(LCD_RETURNHOME); // set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::setCursor(uint8_t col, uint8_t row) {
|
||||
int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
|
||||
if (row > _numlines) {
|
||||
row = _numlines - 1; // we count rows starting w/0
|
||||
}
|
||||
command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
|
||||
}
|
||||
|
||||
// Turn the display on/off (quickly)
|
||||
void LiquidCrystal_I2C::noDisplay() {
|
||||
_displaycontrol &= ~LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal_I2C::display() {
|
||||
_displaycontrol |= LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// Turns the underline cursor on/off
|
||||
void LiquidCrystal_I2C::noCursor() {
|
||||
_displaycontrol &= ~LCD_CURSORON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal_I2C::cursor() {
|
||||
_displaycontrol |= LCD_CURSORON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// Turn on and off the blinking cursor
|
||||
void LiquidCrystal_I2C::noBlink() {
|
||||
_displaycontrol &= ~LCD_BLINKON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal_I2C::blink() {
|
||||
_displaycontrol |= LCD_BLINKON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// These commands scroll the display without changing the RAM
|
||||
void LiquidCrystal_I2C::scrollDisplayLeft(void) {
|
||||
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
|
||||
}
|
||||
void LiquidCrystal_I2C::scrollDisplayRight(void) {
|
||||
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
|
||||
}
|
||||
|
||||
// This is for text that flows Left to Right
|
||||
void LiquidCrystal_I2C::leftToRight(void) {
|
||||
_displaymode |= LCD_ENTRYLEFT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This is for text that flows Right to Left
|
||||
void LiquidCrystal_I2C::rightToLeft(void) {
|
||||
_displaymode &= ~LCD_ENTRYLEFT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This will 'right justify' text from the cursor
|
||||
void LiquidCrystal_I2C::autoscroll(void) {
|
||||
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This will 'left justify' text from the cursor
|
||||
void LiquidCrystal_I2C::noAutoscroll(void) {
|
||||
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// Allows us to fill the first 8 CGRAM locations
|
||||
// with custom characters
|
||||
void LiquidCrystal_I2C::createChar(uint8_t location, uint8_t charmap[]) {
|
||||
location &= 0x7; // we only have 8 locations 0-7
|
||||
command(LCD_SETCGRAMADDR | (location << 3));
|
||||
for (int i = 0; i < 8; i++) {
|
||||
write(charmap[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//createChar with PROGMEM input
|
||||
void LiquidCrystal_I2C::createChar(uint8_t location, const char *charmap) {
|
||||
location &= 0x7; // we only have 8 locations 0-7
|
||||
command(LCD_SETCGRAMADDR | (location << 3));
|
||||
for (int i = 0; i < 8; i++) {
|
||||
write(pgm_read_byte_near(charmap++));
|
||||
}
|
||||
}
|
||||
|
||||
// Turn the (optional) backlight off/on
|
||||
void LiquidCrystal_I2C::noBacklight(void) {
|
||||
_backlightval = LCD_NOBACKLIGHT;
|
||||
expanderWrite(0);
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::backlight(void) {
|
||||
_backlightval = LCD_BACKLIGHT;
|
||||
expanderWrite(0);
|
||||
}
|
||||
|
||||
/*********** mid level commands, for sending data/cmds */
|
||||
|
||||
inline void LiquidCrystal_I2C::command(uint8_t value) {
|
||||
send(value, 0);
|
||||
}
|
||||
|
||||
/************ low level data pushing commands **********/
|
||||
|
||||
// write either command or data
|
||||
void LiquidCrystal_I2C::send(uint8_t value, uint8_t mode) {
|
||||
uint8_t highnib = value & 0xf0;
|
||||
uint8_t lownib = (value << 4) & 0xf0;
|
||||
write4bits((highnib) | mode);
|
||||
write4bits((lownib) | mode);
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::write4bits(uint8_t value) {
|
||||
expanderWrite(value);
|
||||
pulseEnable(value);
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::expanderWrite(uint8_t _data) {
|
||||
#if defined(USE_SOFT_I2C_MASTER)
|
||||
i2c_write_byte(_Addr << 1, _data | _backlightval);
|
||||
#else
|
||||
Wire.beginTransmission(_Addr);
|
||||
Wire.write((int )(_data) | _backlightval);
|
||||
Wire.endTransmission();
|
||||
#endif
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::pulseEnable(uint8_t _data) {
|
||||
expanderWrite(_data | En); // En high
|
||||
#if !defined(USE_FAST_TIMING)
|
||||
delayMicroseconds(1); // enable pulse must be > 450ns // AJ 20.9.23 not required for my LCD's
|
||||
#endif
|
||||
expanderWrite(_data & ~En); // En low
|
||||
#if !defined(USE_FAST_TIMING)
|
||||
delayMicroseconds(50); // commands need > 37us to settle // AJ 20.9.23 not required for my LCD's
|
||||
#endif
|
||||
}
|
||||
|
||||
// Alias functions
|
||||
|
||||
void LiquidCrystal_I2C::cursor_on() {
|
||||
cursor();
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::cursor_off() {
|
||||
noCursor();
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::blink_on() {
|
||||
blink();
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::blink_off() {
|
||||
noBlink();
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::load_custom_character(uint8_t char_num, uint8_t *rows) {
|
||||
createChar(char_num, rows);
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::setBacklight(uint8_t new_val) {
|
||||
if (new_val) {
|
||||
backlight(); // turn backlight on
|
||||
} else {
|
||||
noBacklight(); // turn backlight off
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::printstr(const char c[]) {
|
||||
//This function is not identical to the function used for "real" I2C displays
|
||||
//it's here so the user sketch doesn't have to be changed
|
||||
print(c);
|
||||
}
|
||||
|
||||
// unsupported API functions
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
void LiquidCrystal_I2C::off() {
|
||||
}
|
||||
void LiquidCrystal_I2C::on() {
|
||||
}
|
||||
void LiquidCrystal_I2C::setDelay(int cmdDelay, int charDelay) {
|
||||
}
|
||||
uint8_t LiquidCrystal_I2C::status() {
|
||||
return 0;
|
||||
}
|
||||
uint8_t LiquidCrystal_I2C::keypad() {
|
||||
return 0;
|
||||
}
|
||||
uint8_t LiquidCrystal_I2C::init_bargraph(uint8_t graphtype) {
|
||||
return 0;
|
||||
}
|
||||
void LiquidCrystal_I2C::draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end) {
|
||||
}
|
||||
void LiquidCrystal_I2C::draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_row_end) {
|
||||
}
|
||||
void LiquidCrystal_I2C::setContrast(uint8_t new_val) {
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#endif // _LIQUID_CRYSTAL_I2C_HPP
|
||||
@ -1,129 +0,0 @@
|
||||
//YWROBOT
|
||||
#ifndef LiquidCrystal_I2C_h
|
||||
#define LiquidCrystal_I2C_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "Print.h"
|
||||
#if !defined(USE_SOFT_I2C_MASTER) && !defined(USE_SOFT_WIRE)
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
|
||||
// commands
|
||||
#define LCD_CLEARDISPLAY 0x01
|
||||
#define LCD_RETURNHOME 0x02
|
||||
#define LCD_ENTRYMODESET 0x04
|
||||
#define LCD_DISPLAYCONTROL 0x08
|
||||
#define LCD_CURSORSHIFT 0x10
|
||||
#define LCD_FUNCTIONSET 0x20
|
||||
#define LCD_SETCGRAMADDR 0x40
|
||||
#define LCD_SETDDRAMADDR 0x80
|
||||
|
||||
// flags for display entry mode
|
||||
#define LCD_ENTRYRIGHT 0x00
|
||||
#define LCD_ENTRYLEFT 0x02
|
||||
#define LCD_ENTRYSHIFTINCREMENT 0x01
|
||||
#define LCD_ENTRYSHIFTDECREMENT 0x00
|
||||
|
||||
// flags for display on/off control
|
||||
#define LCD_DISPLAYON 0x04
|
||||
#define LCD_DISPLAYOFF 0x00
|
||||
#define LCD_CURSORON 0x02
|
||||
#define LCD_CURSOROFF 0x00
|
||||
#define LCD_BLINKON 0x01
|
||||
#define LCD_BLINKOFF 0x00
|
||||
|
||||
// flags for display/cursor shift
|
||||
#define LCD_DISPLAYMOVE 0x08
|
||||
#define LCD_CURSORMOVE 0x00
|
||||
#define LCD_MOVERIGHT 0x04
|
||||
#define LCD_MOVELEFT 0x00
|
||||
|
||||
// flags for function set
|
||||
#define LCD_8BITMODE 0x10
|
||||
#define LCD_4BITMODE 0x00
|
||||
#define LCD_2LINE 0x08
|
||||
#define LCD_1LINE 0x00
|
||||
#define LCD_5x10DOTS 0x04
|
||||
#define LCD_5x8DOTS 0x00
|
||||
|
||||
// flags for backlight control
|
||||
#define LCD_BACKLIGHT 0x08
|
||||
#define LCD_NOBACKLIGHT 0x00
|
||||
|
||||
#define En 0b00000100 // Enable bit
|
||||
#define Rw 0b00000010 // Read/Write bit
|
||||
#define Rs 0b00000001 // Register select bit
|
||||
|
||||
class LiquidCrystal_I2C : public Print {
|
||||
public:
|
||||
LiquidCrystal_I2C(uint8_t lcd_Addr,uint8_t lcd_cols,uint8_t lcd_rows);
|
||||
void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS );
|
||||
void clear();
|
||||
void home();
|
||||
void noDisplay();
|
||||
void display();
|
||||
void noBlink();
|
||||
void blink();
|
||||
void noCursor();
|
||||
void cursor();
|
||||
void scrollDisplayLeft();
|
||||
void scrollDisplayRight();
|
||||
void printLeft();
|
||||
void printRight();
|
||||
void leftToRight();
|
||||
void rightToLeft();
|
||||
void shiftIncrement();
|
||||
void shiftDecrement();
|
||||
void noBacklight();
|
||||
void backlight();
|
||||
void autoscroll();
|
||||
void noAutoscroll();
|
||||
void createChar(uint8_t, uint8_t[]);
|
||||
void createChar(uint8_t location, const char *charmap);
|
||||
// Example: const char bell[8] PROGMEM = {B00100,B01110,B01110,B01110,B11111,B00000,B00100,B00000};
|
||||
|
||||
void setCursor(uint8_t, uint8_t);
|
||||
size_t write(uint8_t);
|
||||
void command(uint8_t);
|
||||
void init();
|
||||
void oled_init();
|
||||
|
||||
////compatibility API function aliases
|
||||
void blink_on(); // alias for blink()
|
||||
void blink_off(); // alias for noBlink()
|
||||
void cursor_on(); // alias for cursor()
|
||||
void cursor_off(); // alias for noCursor()
|
||||
void setBacklight(uint8_t new_val); // alias for backlight() and nobacklight()
|
||||
void load_custom_character(uint8_t char_num, uint8_t *rows); // alias for createChar()
|
||||
void printstr(const char[]);
|
||||
|
||||
////Unsupported API functions (not implemented in this library)
|
||||
uint8_t status();
|
||||
void setContrast(uint8_t new_val);
|
||||
uint8_t keypad();
|
||||
void setDelay(int,int);
|
||||
void on();
|
||||
void off();
|
||||
uint8_t init_bargraph(uint8_t graphtype);
|
||||
void draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end);
|
||||
void draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end);
|
||||
|
||||
|
||||
private:
|
||||
void init_priv();
|
||||
void send(uint8_t, uint8_t);
|
||||
void write4bits(uint8_t);
|
||||
void expanderWrite(uint8_t);
|
||||
void pulseEnable(uint8_t);
|
||||
uint8_t _Addr;
|
||||
uint8_t _displayfunction;
|
||||
uint8_t _displaycontrol;
|
||||
uint8_t _displaymode;
|
||||
uint8_t _numlines;
|
||||
bool _oled;
|
||||
uint8_t _cols;
|
||||
uint8_t _rows;
|
||||
uint8_t _backlightval;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,349 +0,0 @@
|
||||
/*
|
||||
* PinDefinitionsAndMore.h
|
||||
*
|
||||
* Contains pin definitions for IRremote examples for various platforms
|
||||
* as well as definitions for feedback LED and tone() and includes
|
||||
*
|
||||
* Copyright (C) 2021-2023 Armin Joachimsmeyer
|
||||
* armin.joachimsmeyer@gmail.com
|
||||
*
|
||||
* This file is part of IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.
|
||||
*
|
||||
* Arduino-IRremote is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Pin mapping table for different platforms
|
||||
*
|
||||
* Platform IR input IR output Tone Core/Pin schema
|
||||
* --------------------------------------------------------------
|
||||
* DEFAULT/AVR 2 3 4 Arduino
|
||||
* ATtinyX5 0|PB0 4|PB4 3|PB3 ATTinyCore
|
||||
* ATtiny167 3|PA3 2|PA2 7|PA7 ATTinyCore
|
||||
* ATtiny167 9|PA3 8|PA2 5|PA7 Digispark original core
|
||||
* ATtiny84 |PB2 |PA4 |PA3 ATTinyCore
|
||||
* ATtiny88 3|PD3 4|PD4 9|PB1 ATTinyCore
|
||||
* ATtiny3217 18|PA1 19|PA2 20|PA3 MegaTinyCore
|
||||
* ATtiny1604 2 3|PA5 %
|
||||
* ATtiny816 14|PA1 16|PA3 1|PA5 MegaTinyCore
|
||||
* ATtiny1614 8|PA1 10|PA3 1|PA5 MegaTinyCore
|
||||
* SAMD21 3 4 5
|
||||
* ESP8266 14|D5 12|D6 %
|
||||
* ESP32 15 4 27
|
||||
* ESP32-C3 2 3 4
|
||||
* BluePill PA6 PA7 PA3
|
||||
* APOLLO3 11 12 5
|
||||
* RP2040 3|GPIO15 4|GPIO16 5|GPIO17
|
||||
*/
|
||||
//#define _IR_MEASURE_TIMING // For debugging purposes.
|
||||
|
||||
#if defined(__AVR__)
|
||||
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) // Digispark board. For use with ATTinyCore.
|
||||
#include "ATtinySerialOut.hpp" // TX is at pin 2 - Available as Arduino library "ATtinySerialOut". Saves 700 bytes program memory and 70 bytes RAM for ATtinyCore.
|
||||
#define IR_RECEIVE_PIN PIN_PB0
|
||||
#define IR_SEND_PIN PIN_PB4 // Pin 2 is serial output with ATtinySerialOut. Pin 1 is internal LED and Pin3 is USB+ with pullup on Digispark board.
|
||||
#define TONE_PIN PIN_PB3
|
||||
#define _IR_TIMING_TEST_PIN PIN_PB3
|
||||
|
||||
# elif defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__) // Digispark pro board
|
||||
#include "ATtinySerialOut.hpp" // Available as Arduino library "ATtinySerialOut"
|
||||
// For ATtiny167 Pins PB6 and PA3 are usable as interrupt source.
|
||||
# if defined(ARDUINO_AVR_DIGISPARKPRO)
|
||||
// For use with Digispark original core
|
||||
#define IR_RECEIVE_PIN 9 // PA3 - on Digispark board labeled as pin 9
|
||||
//#define IR_RECEIVE_PIN 14 // PB6 / INT0 is connected to USB+ on DigisparkPro boards
|
||||
#define IR_SEND_PIN 8 // PA2 - on Digispark board labeled as pin 8
|
||||
#define TONE_PIN 5 // PA7 - on Digispark board labeled as pin 5
|
||||
#define _IR_TIMING_TEST_PIN 10 // PA4
|
||||
# else
|
||||
// For use with ATTinyCore
|
||||
#define IR_RECEIVE_PIN PIN_PA3 // On Digispark board labeled as pin 9 - INT0 is connected to USB+ on DigisparkPro boards
|
||||
#define IR_SEND_PIN PIN_PA2 // On Digispark board labeled as pin 8
|
||||
#define TONE_PIN PIN_PA7 // On Digispark board labeled as pin 5
|
||||
# endif
|
||||
|
||||
# elif defined(__AVR_ATtiny84__) // For use with ATTinyCore
|
||||
#include "ATtinySerialOut.hpp" // Available as Arduino library "ATtinySerialOut". Saves 128 bytes program memory.
|
||||
#define IR_RECEIVE_PIN PIN_PB2 // INT0
|
||||
#define IR_SEND_PIN PIN_PA4
|
||||
#define TONE_PIN PIN_PA3
|
||||
#define _IR_TIMING_TEST_PIN PIN_PA5
|
||||
|
||||
# elif defined(__AVR_ATtiny88__) // MH-ET Tiny88 board. For use with ATTinyCore.
|
||||
#include "ATtinySerialOut.hpp" // Available as Arduino library "ATtinySerialOut". Saves 128 bytes program memory.
|
||||
// Pin 6 is TX, pin 7 is RX
|
||||
#define IR_RECEIVE_PIN PIN_PD3 // 3 - INT1
|
||||
#define IR_SEND_PIN PIN_PD4 // 4
|
||||
#define TONE_PIN PIN_PB1 // 9
|
||||
#define _IR_TIMING_TEST_PIN PIN_PB0 // 8
|
||||
|
||||
# elif defined(__AVR_ATtiny1616__) || defined(__AVR_ATtiny3216__) || defined(__AVR_ATtiny3217__) // For use with megaTinyCore
|
||||
// Tiny Core Dev board
|
||||
// https://www.tindie.com/products/xkimi/tiny-core-16-dev-board-attiny1616/ - Out of Stock
|
||||
// https://www.tindie.com/products/xkimi/tiny-core-32-dev-board-attiny3217/ - Out of Stock
|
||||
#define IR_RECEIVE_PIN PIN_PA1 // use 18 instead of PIN_PA1 for TinyCore32
|
||||
#define IR_SEND_PIN PIN_PA2 // 19
|
||||
#define TONE_PIN PIN_PA3 // 20
|
||||
#define APPLICATION_PIN PIN_PA0 // 0
|
||||
#undef LED_BUILTIN // No LED available on the TinyCore 32 board, take the one on the programming board which is connected to the DAC output
|
||||
#define LED_BUILTIN PIN_PA6 // use 2 instead of PIN_PA6 for TinyCore32
|
||||
|
||||
# elif defined(__AVR_ATtiny816__) // For use with megaTinyCore
|
||||
#define IR_RECEIVE_PIN PIN_PA1 // 14
|
||||
#define IR_SEND_PIN PIN_PA1 // 16
|
||||
#define TONE_PIN PIN_PA5 // 1
|
||||
#define APPLICATION_PIN PIN_PA4 // 0
|
||||
#undef LED_BUILTIN // No LED available, take the one which is connected to the DAC output
|
||||
#define LED_BUILTIN PIN_PB5 // 4
|
||||
|
||||
# elif defined(__AVR_ATtiny1614__) // For use with megaTinyCore
|
||||
#define IR_RECEIVE_PIN PIN_PA1 // 8
|
||||
#define IR_SEND_PIN PIN_PA3 // 10
|
||||
#define TONE_PIN PIN_PA5 // 1
|
||||
#define APPLICATION_PIN PIN_PA4 // 0
|
||||
|
||||
# elif defined(__AVR_ATtiny1604__) // For use with megaTinyCore
|
||||
#define IR_RECEIVE_PIN PIN_PA6 // 2 - To be compatible with interrupt example, pin 2 is chosen here.
|
||||
#define IR_SEND_PIN PIN_PA7 // 3
|
||||
#define APPLICATION_PIN PIN_PB2 // 5
|
||||
|
||||
#define tone(...) void() // Define as void, since TCB0_INT_vect is also used by tone()
|
||||
#define noTone(a) void()
|
||||
#define TONE_PIN 42 // Dummy for examples using it
|
||||
|
||||
# elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) \
|
||||
|| defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) \
|
||||
|| defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) \
|
||||
|| defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega164A__) \
|
||||
|| defined(__AVR_ATmega164P__) || defined(__AVR_ATmega32__) \
|
||||
|| defined(__AVR_ATmega16__) || defined(__AVR_ATmega8535__) \
|
||||
|| defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) \
|
||||
|| defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) \
|
||||
|| defined(__AVR_ATmega8515__) || defined(__AVR_ATmega162__)
|
||||
#define IR_RECEIVE_PIN 2
|
||||
#define IR_SEND_PIN 13
|
||||
#define TONE_PIN 4
|
||||
#define APPLICATION_PIN 5
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 7
|
||||
|
||||
# else // Default as for ATmega328 like on Uno, Nano, Leonardo, Teensy 2.0 etc.
|
||||
#define IR_RECEIVE_PIN 2 // To be compatible with interrupt example, pin 2 is chosen here.
|
||||
#define IR_SEND_PIN 3
|
||||
#define TONE_PIN 4
|
||||
#define APPLICATION_PIN 5
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 7
|
||||
|
||||
# if defined(ARDUINO_AVR_PROMICRO) // Sparkfun Pro Micro is __AVR_ATmega32U4__ but has different external circuit
|
||||
// We have no built in LED at pin 13 -> reuse RX LED
|
||||
#undef LED_BUILTIN
|
||||
#define LED_BUILTIN LED_BUILTIN_RX
|
||||
# endif
|
||||
# endif // defined(__AVR_ATtiny25__)...
|
||||
|
||||
#elif defined(ARDUINO_ARCH_RENESAS_UNO) // Uno R4
|
||||
// To be compatible with Uno R3.
|
||||
#define IR_RECEIVE_PIN 2
|
||||
#define IR_SEND_PIN 3
|
||||
#define TONE_PIN 4
|
||||
#define APPLICATION_PIN 5
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 7
|
||||
|
||||
#elif defined(ESP8266)
|
||||
#define FEEDBACK_LED_IS_ACTIVE_LOW // The LED on my board (D4) is active LOW
|
||||
#define IR_RECEIVE_PIN 14 // D5
|
||||
#define IR_SEND_PIN 12 // D6 - D4/pin 2 is internal LED
|
||||
#define _IR_TIMING_TEST_PIN 2 // D4
|
||||
#define APPLICATION_PIN 13 // D7
|
||||
|
||||
#define tone(...) void() // tone() inhibits receive timer
|
||||
#define noTone(a) void()
|
||||
#define TONE_PIN 42 // Dummy for examples using it#
|
||||
|
||||
#elif defined(ARDUINO_NOLOGO_ESP32C3_SUPER_MINI)
|
||||
#define FEEDBACK_LED_IS_ACTIVE_LOW // The LED on my board (D8) is active LOW
|
||||
#define IR_RECEIVE_PIN 2
|
||||
#define IR_SEND_PIN 3
|
||||
#define TONE_PIN 4
|
||||
#define APPLICATION_PIN 10
|
||||
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(ARDUINO_ESP32C3_DEV)
|
||||
#define NO_LED_FEEDBACK_CODE // The WS2812 on pin 8 of AI-C3 board crashes if used as receive feedback LED, other I/O pins are working...
|
||||
#define IR_RECEIVE_PIN 6
|
||||
#define IR_SEND_PIN 7
|
||||
#define TONE_PIN 10
|
||||
#define APPLICATION_PIN 18
|
||||
|
||||
#elif defined(ESP32)
|
||||
#include <Arduino.h>
|
||||
|
||||
// tone() is included in ESP32 core since 2.0.2
|
||||
#if !defined(ESP_ARDUINO_VERSION_VAL)
|
||||
#define ESP_ARDUINO_VERSION_VAL(major, minor, patch) 12345678
|
||||
#endif
|
||||
#if ESP_ARDUINO_VERSION <= ESP_ARDUINO_VERSION_VAL(2, 0, 2)
|
||||
#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer.
|
||||
void tone(uint8_t aPinNumber, unsigned int aFrequency){
|
||||
ledcAttachPin(aPinNumber, TONE_LEDC_CHANNEL);
|
||||
ledcWriteTone(TONE_LEDC_CHANNEL, aFrequency);
|
||||
}
|
||||
void tone(uint8_t aPinNumber, unsigned int aFrequency, unsigned long aDuration){
|
||||
ledcAttachPin(aPinNumber, TONE_LEDC_CHANNEL);
|
||||
ledcWriteTone(TONE_LEDC_CHANNEL, aFrequency);
|
||||
delay(aDuration);
|
||||
ledcWriteTone(TONE_LEDC_CHANNEL, 0);
|
||||
}
|
||||
void noTone(uint8_t aPinNumber){
|
||||
ledcWriteTone(TONE_LEDC_CHANNEL, 0);
|
||||
}
|
||||
#endif // ESP_ARDUINO_VERSION <= ESP_ARDUINO_VERSION_VAL(2, 0, 2)
|
||||
|
||||
#define IR_RECEIVE_PIN 15 // D15
|
||||
#define IR_SEND_PIN 4 // D4
|
||||
#define TONE_PIN 27 // D27 25 & 26 are DAC0 and 1
|
||||
#define APPLICATION_PIN 16 // RX2 pin
|
||||
|
||||
#elif defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_STM32F1) // BluePill
|
||||
// Timer 3 blocks PA6, PA7, PB0, PB1 for use by Servo or tone()
|
||||
#define IR_RECEIVE_PIN PA6
|
||||
#define IR_RECEIVE_PIN_STRING "PA6"
|
||||
#define IR_SEND_PIN PA7
|
||||
#define IR_SEND_PIN_STRING "PA7"
|
||||
#define TONE_PIN PA3
|
||||
#define _IR_TIMING_TEST_PIN PA5
|
||||
#define APPLICATION_PIN PA2
|
||||
#define APPLICATION_PIN_STRING "PA2"
|
||||
# if defined(ARDUINO_GENERIC_STM32F103C) || defined(ARDUINO_BLUEPILL_F103C8)
|
||||
// BluePill LED is active low
|
||||
#define FEEDBACK_LED_IS_ACTIVE_LOW
|
||||
# endif
|
||||
|
||||
#elif defined(ARDUINO_ARCH_APOLLO3) // Sparkfun Apollo boards
|
||||
#define IR_RECEIVE_PIN 11
|
||||
#define IR_SEND_PIN 12
|
||||
#define TONE_PIN 5
|
||||
|
||||
#elif defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_MBED_NANO) // Arduino Nano 33 BLE and Arduino Nano Connect layout for MBED
|
||||
// Must be before ARDUINO_ARCH_RP2040, since it is the layout for the MBED core of Arduino Nano Connect
|
||||
#define IR_RECEIVE_PIN 3 // GPIO15 Start with pin 3 since pin 2|GPIO25 is connected to LED on Pi pico
|
||||
#define IR_SEND_PIN 4 // GPIO16
|
||||
#define TONE_PIN 5
|
||||
#define APPLICATION_PIN 6
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 7 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 8
|
||||
|
||||
#elif defined(ARDUINO_ARCH_RP2040) // Arduino Nano Connect, Pi Pico with arduino-pico core https://github.com/earlephilhower/arduino-pico
|
||||
#define IR_RECEIVE_PIN 15 // GPIO15 to be compatible with the Arduino Nano RP2040 Connect (pin3)
|
||||
#define IR_SEND_PIN 16 // GPIO16
|
||||
#define TONE_PIN 17
|
||||
#define APPLICATION_PIN 18
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 19 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 20
|
||||
|
||||
// If you program the Nano RP2040 Connect with this core, then you must redefine LED_BUILTIN
|
||||
// and use the external reset with 1 kOhm to ground to enter UF2 mode
|
||||
#undef LED_BUILTIN
|
||||
#define LED_BUILTIN 6
|
||||
|
||||
#elif defined(PARTICLE) // !!!UNTESTED!!!
|
||||
#define IR_RECEIVE_PIN A4
|
||||
#define IR_SEND_PIN A5 // Particle supports multiple pins
|
||||
|
||||
#define LED_BUILTIN D7
|
||||
|
||||
/*
|
||||
* 4 times the same (default) layout for easy adaption in the future
|
||||
*/
|
||||
#elif defined(TEENSYDUINO) // Teensy 2.0 is handled at default for ATmega328 like on Uno, Nano, Leonardo etc.
|
||||
#define IR_RECEIVE_PIN 2
|
||||
#define IR_SEND_PIN 3
|
||||
#define TONE_PIN 4
|
||||
#define APPLICATION_PIN 5
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 7
|
||||
|
||||
#elif defined(ARDUINO_ARCH_MBED) // Arduino Nano 33 BLE
|
||||
#define IR_RECEIVE_PIN 2
|
||||
#define IR_SEND_PIN 3
|
||||
#define TONE_PIN 4
|
||||
#define APPLICATION_PIN 5
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 7
|
||||
|
||||
#elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_SAM)
|
||||
#define IR_RECEIVE_PIN 2
|
||||
#define IR_SEND_PIN 3
|
||||
#define TONE_PIN 4
|
||||
#define APPLICATION_PIN 5
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 7
|
||||
|
||||
#if !defined(ARDUINO_SAMD_ADAFRUIT) && !defined(ARDUINO_SEEED_XIAO_M0)
|
||||
// On the Zero and others we switch explicitly to SerialUSB
|
||||
#define Serial SerialUSB
|
||||
#endif
|
||||
|
||||
// Definitions for the Chinese SAMD21 M0-Mini clone, which has no led connected to D13/PA17.
|
||||
// Attention!!! D2 and D4 are swapped on these boards!!!
|
||||
// If you connect the LED, it is on pin 24/PB11. In this case activate the next two lines.
|
||||
//#undef LED_BUILTIN
|
||||
//#define LED_BUILTIN 24 // PB11
|
||||
// As an alternative you can choose pin 25, it is the RX-LED pin (PB03), but active low.In this case activate the next 3 lines.
|
||||
//#undef LED_BUILTIN
|
||||
//#define LED_BUILTIN 25 // PB03
|
||||
//#define FEEDBACK_LED_IS_ACTIVE_LOW // The RX LED on the M0-Mini is active LOW
|
||||
|
||||
#elif defined (NRF51) // BBC micro:bit
|
||||
#define IR_RECEIVE_PIN 2
|
||||
#define IR_SEND_PIN 3
|
||||
#define APPLICATION_PIN 1
|
||||
#define _IR_TIMING_TEST_PIN 4
|
||||
|
||||
#define tone(...) void() // no tone() available
|
||||
#define noTone(a) void()
|
||||
#define TONE_PIN 42 // Dummy for examples using it
|
||||
|
||||
#else
|
||||
#warning Board / CPU is not detected using pre-processor symbols -> using default values, which may not fit. Please extend PinDefinitionsAndMore.h.
|
||||
// Default valued for unidentified boards
|
||||
#define IR_RECEIVE_PIN 2
|
||||
#define IR_SEND_PIN 3
|
||||
#define TONE_PIN 4
|
||||
#define APPLICATION_PIN 5
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 7
|
||||
#endif // defined(ESP8266)
|
||||
|
||||
#if defined(ESP32) || defined(ARDUINO_ARCH_RP2040) || defined(PARTICLE) || defined(ARDUINO_ARCH_MBED)
|
||||
#define SEND_PWM_BY_TIMER // We do not have pin restrictions for this CPU's, so lets use the hardware PWM for send carrier signal generation
|
||||
#else
|
||||
# if defined(SEND_PWM_BY_TIMER)
|
||||
#undef IR_SEND_PIN // SendPin is determined by timer! This avoids warnings in IRremote.hpp and IRTimer.hpp
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined (FLASHEND)
|
||||
#define FLASHEND 0xFFFF // Dummy value for platforms where FLASHEND is not defined
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Helper macro for getting a macro definition as string
|
||||
*/
|
||||
#if !defined(STR_HELPER)
|
||||
#define STR_HELPER(x) #x
|
||||
#define STR(x) STR_HELPER(x)
|
||||
#endif
|
||||
@ -1,390 +0,0 @@
|
||||
/**
|
||||
* @file MicroGirs.ino
|
||||
*
|
||||
* @brief This is a minimalistic <a href="http://harctoolbox.org/Girs.html">Girs server</a>.
|
||||
* It only depends on (a subset of) IRremote. It can be used with
|
||||
* <a href="http://www.harctoolbox.org/IrScrutinizer.html">IrScrutinizer</a>
|
||||
* (select Sending/Capturing hw = Girs Client) as well as
|
||||
* <a href="http://lirc.org">Lirc</a>
|
||||
* version 0.9.4 and later, using the driver <a href="http://lirc.org/html/girs.html">Girs</a>).
|
||||
* (Authors of similar software are encourage to implement support.)
|
||||
*
|
||||
* It runs on all hardware on which IRemote runs.
|
||||
*
|
||||
* It consists of an interactive IR server, taking one-line commands from
|
||||
* the "user" (which is typically not a person but another program), and
|
||||
* responds with a one-line response. In the language of the Girs
|
||||
* specifications, the modules "base", receive, and transmit are
|
||||
* implemented. (The two latter can be disabled by not defining two
|
||||
* corresponding CPP symbols.)
|
||||
*
|
||||
* It understands the following commands:
|
||||
*
|
||||
* The "version" command returns the program name and version,
|
||||
* The "modules" command returns the modules implemented, normally base, receive and transmit.
|
||||
* The "receive" command reads an IR signal using the used, demodulating IR sensor.
|
||||
* The "send" commands transmits a supplied raw signal the requested number of times.
|
||||
*
|
||||
* Only the first character of the command is evaluated in this implementation.
|
||||
*
|
||||
* The "receive" command returns the received IR sequence as a sequence
|
||||
* of durations, including a (dummy) trailing silence. On-periods
|
||||
* ("marks", "flashes") are prefixed by "+", while off-periods ("spaces",
|
||||
* "gaps") are prefixed by "-". The present version never times out.
|
||||
*
|
||||
* The \c send command takes the following parameters:
|
||||
*
|
||||
* send noSends frequencyHz introLength repeatLength endingLength durations...
|
||||
|
||||
* where
|
||||
*
|
||||
* * frequencyHz denotes the modulation frequency in Hz
|
||||
* (\e not khz, as is normally used in IRremote)
|
||||
* * introLength denotes the length of the intro sequence, must be even,
|
||||
* * repeatLength denotes the length of the repeat sequence, must be even,
|
||||
* * endingLength denotes the length of the ending sequence (normally 0), must be even.
|
||||
* * duration... denotes the microsecond durations to send,
|
||||
* starting with the first on-period, ending with a (possibly dummy) trailing silence
|
||||
*
|
||||
* Semantics: first the intro sequence will be sent once (i.e., the first
|
||||
* repeatLength durations) (if non-empty). Then the repeat sequence will
|
||||
* be sent (noSends-1) times, unless the intro sequence was empty, in
|
||||
* which case it will be send noSends times. Finally, the ending
|
||||
* sequence will be send once (if non-empty).
|
||||
*
|
||||
* Weaknesses of the IRremote implementation:
|
||||
* * Reception never times out if no IR is seen.
|
||||
* * The IRrecv class does its own decoding which is irrelevant for us.
|
||||
* * The timeout at the end on a signal reception is not configurable.
|
||||
* For example, a NEC1 type signal will cut after the intro sequence,
|
||||
* and the repeats will be considered independent signals.
|
||||
* In IrSqrutinizer, recognition of repeating signals will therefore not work.
|
||||
* The size of the data is platform dependent ("unsigned int", which is 16 bit on AVR boards, 32 bits on 32 bit boards).
|
||||
*
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "PinDefinitionsAndMore.h" // Define macros for input and output pin etc.
|
||||
|
||||
#if !defined(RAW_BUFFER_LENGTH)
|
||||
// For air condition remotes it requires 750. Default is 200.
|
||||
# if (defined(RAMEND) && RAMEND <= 0x4FF) || (defined(RAMSIZE) && RAMSIZE < 0x4FF)
|
||||
#define RAW_BUFFER_LENGTH 360
|
||||
# else
|
||||
#define RAW_BUFFER_LENGTH 750
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Baud rate for the serial/USB connection.
|
||||
* (115200 is the default for IrScrutinizer and Lirc.)
|
||||
*/
|
||||
#define BAUDRATE 115200
|
||||
#define NO_DECODER
|
||||
|
||||
#include "IRremote.hpp"
|
||||
#include <limits.h>
|
||||
|
||||
/**
|
||||
* Define to support reception of IR.
|
||||
*/
|
||||
#define RECEIVE
|
||||
|
||||
/**
|
||||
* Define to support transmission of IR signals.
|
||||
*/
|
||||
#define TRANSMIT
|
||||
|
||||
// (The sending pin is in general not configurable, see the documentation of IRremote.)
|
||||
|
||||
/**
|
||||
* Character that ends the command lines. Do not change unless you known what
|
||||
* you are doing. IrScrutinizer and Lirc expects \r.
|
||||
*/
|
||||
#define EOLCHAR '\r'
|
||||
|
||||
////// End of user configurable variables ////////////////////
|
||||
|
||||
/**
|
||||
* The modules supported, as given by the "modules" command.
|
||||
*/
|
||||
#if defined(TRANSMIT)
|
||||
#if defined(RECEIVE)
|
||||
#define modulesSupported "base transmit receive"
|
||||
#else // ! RECEIVE
|
||||
#define modulesSupported "base transmit"
|
||||
#endif
|
||||
#else // !TRANSMIT
|
||||
#if defined(RECEIVE)
|
||||
#define modulesSupported "base receive"
|
||||
#else // ! RECETVE
|
||||
#error At lease one of TRANSMIT and RECEIVE must be defined
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Name of program, as reported by the "version" command.
|
||||
*/
|
||||
#define PROGNAME "MicroGirs"
|
||||
|
||||
/**
|
||||
* Version of program, as reported by the "version" command.
|
||||
*/
|
||||
#define VERSION "2020-07-05"
|
||||
|
||||
#define okString "OK"
|
||||
#define errorString "ERROR"
|
||||
#define timeoutString "."
|
||||
|
||||
// For compatibility with IRremote, we deliberately use
|
||||
// the platform dependent types.
|
||||
// (Although it is a questionable idea ;-) )
|
||||
/**
|
||||
* Type used for modulation frequency in Hz (\e not kHz).
|
||||
*/
|
||||
typedef unsigned frequency_t; // max 65535, unless 32-bit
|
||||
|
||||
/**
|
||||
* Type used for durations in micro seconds.
|
||||
*/
|
||||
typedef uint16_t microseconds_t; // max 65535
|
||||
|
||||
static const microseconds_t DUMMYENDING = 40000U;
|
||||
static const frequency_t FREQUENCY_T_MAX = UINT16_MAX;
|
||||
static const frequency_t MICROSECONDS_T_MAX = UINT16_MAX;
|
||||
|
||||
/**
|
||||
* Our own tokenizer class. Breaks the command line into tokens.
|
||||
* Usage outside of this package is discouraged.
|
||||
*/
|
||||
class Tokenizer {
|
||||
private:
|
||||
static const int invalidIndex = -1;
|
||||
|
||||
int index; // signed since invalidIndex is possible
|
||||
const String &payload;
|
||||
void trim();
|
||||
|
||||
public:
|
||||
Tokenizer(const String &str);
|
||||
|
||||
String getToken();
|
||||
String getRest();
|
||||
String getLine();
|
||||
long getInt();
|
||||
microseconds_t getMicroseconds();
|
||||
frequency_t getFrequency();
|
||||
|
||||
static const int invalid = INT_MAX;
|
||||
};
|
||||
|
||||
Tokenizer::Tokenizer(const String &str) :
|
||||
index(0), payload(str) {
|
||||
}
|
||||
|
||||
String Tokenizer::getRest() {
|
||||
String result = index == invalidIndex ? String("") : payload.substring(index);
|
||||
index = invalidIndex;
|
||||
return result;
|
||||
}
|
||||
|
||||
String Tokenizer::getLine() {
|
||||
if (index == invalidIndex) return String("");
|
||||
|
||||
int i = payload.indexOf('\n', index);
|
||||
String s = (i > 0) ? payload.substring(index, i) : payload.substring(index);
|
||||
index = (i > 0) ? i + 1 : invalidIndex;
|
||||
return s;
|
||||
}
|
||||
|
||||
String Tokenizer::getToken() {
|
||||
if (index < 0) return String("");
|
||||
|
||||
int i = payload.indexOf(' ', index);
|
||||
String s = (i > 0) ? payload.substring(index, i) : payload.substring(index);
|
||||
index = (i > 0) ? i : invalidIndex;
|
||||
if (index != invalidIndex) if (index != invalidIndex) while (payload.charAt(index) == ' ')
|
||||
index++;
|
||||
return s;
|
||||
}
|
||||
|
||||
long Tokenizer::getInt() {
|
||||
String token = getToken();
|
||||
return token == "" ? (long) invalid : token.toInt();
|
||||
}
|
||||
|
||||
microseconds_t Tokenizer::getMicroseconds() {
|
||||
long t = getToken().toInt();
|
||||
return (microseconds_t) ((t < MICROSECONDS_T_MAX) ? t : MICROSECONDS_T_MAX);
|
||||
}
|
||||
|
||||
frequency_t Tokenizer::getFrequency() {
|
||||
long t = getToken().toInt();
|
||||
return (frequency_t) ((t < FREQUENCY_T_MAX) ? t : FREQUENCY_T_MAX);
|
||||
}
|
||||
///////////////// end Tokenizer /////////////////////////////////
|
||||
|
||||
#if defined(TRANSMIT)
|
||||
static inline unsigned hz2khz(frequency_t hz) {
|
||||
return (hz + 500) / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmits the IR signal given as argument.
|
||||
*
|
||||
* The intro sequence (possibly empty) is first sent. Then the repeat signal
|
||||
* (also possibly empty) is sent, "times" times, except for the case of
|
||||
* the intro signal being empty, in which case it is sent "times" times.
|
||||
* Finally the ending sequence (possibly empty) is sent.
|
||||
*
|
||||
* @param intro Sequence to be sent exactly once at the start.
|
||||
* @param lengthIntro Number of durations in intro sequence, must be even.
|
||||
* @param repeat Sequence top possibly be sent multiple times
|
||||
* @param lengthRepeat Number of durations in repeat sequence.
|
||||
* @param ending Sequence to be sent at the end, possibly empty
|
||||
* @param lengthEnding Number of durations in ending sequence
|
||||
* @param frequency Modulation frequency, in Hz (not kHz as normally in IRremote)
|
||||
* @param times Number of times to send the signal, in the sense above.
|
||||
*/
|
||||
static void sendRaw(const microseconds_t intro[], unsigned lengthIntro, const microseconds_t repeat[], unsigned lengthRepeat,
|
||||
const microseconds_t ending[], unsigned lengthEnding, frequency_t frequency, unsigned times) {
|
||||
if (lengthIntro > 0U) IrSender.sendRaw(intro, lengthIntro, hz2khz(frequency));
|
||||
if (lengthRepeat > 0U) for (unsigned i = 0U; i < times - (lengthIntro > 0U); i++)
|
||||
IrSender.sendRaw(repeat, lengthRepeat, hz2khz(frequency));
|
||||
if (lengthEnding > 0U) IrSender.sendRaw(ending, lengthEnding, hz2khz(frequency));
|
||||
}
|
||||
#endif // TRANSMIT
|
||||
|
||||
#if defined(RECEIVE)
|
||||
|
||||
static void dump(Stream &stream) {
|
||||
unsigned int count = IrReceiver.decodedIRData.rawDataPtr->rawlen;
|
||||
// If buffer gets full, count = RAW_BUFFER_LENGTH, which is odd,
|
||||
// and IrScrutinizer does not like that.
|
||||
count &= ~1;
|
||||
for (unsigned int i = 1; i < count; i++) {
|
||||
stream.write(i & 1 ? '+' : '-');
|
||||
stream.print(IrReceiver.decodedIRData.rawDataPtr->rawbuf[i] * MICROS_PER_TICK, DEC);
|
||||
stream.print(" ");
|
||||
}
|
||||
stream.print('-');
|
||||
stream.println(DUMMYENDING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a command from the stream given as argument.
|
||||
* @param stream Stream to read from, typically Serial.
|
||||
*/
|
||||
static void receive(Stream &stream) {
|
||||
IrReceiver.start();
|
||||
|
||||
while (!IrReceiver.decode()) {
|
||||
}
|
||||
IrReceiver.stop();
|
||||
|
||||
dump(stream);
|
||||
}
|
||||
|
||||
#endif // RECEIVE
|
||||
|
||||
/**
|
||||
* Initialization.
|
||||
*/
|
||||
void setup() {
|
||||
Serial.begin(BAUDRATE);
|
||||
while (!Serial)
|
||||
; // Wait for Serial to become available. Is optimized away for some cores.
|
||||
|
||||
Serial.println(F(PROGNAME " " VERSION));
|
||||
// Just to know which program is running on my Arduino
|
||||
Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE));
|
||||
|
||||
#if defined(RECEIVE)
|
||||
// Start the receiver and if not 3. parameter specified, take LED_BUILTIN pin from the internal boards definition as default feedback LED
|
||||
IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);
|
||||
|
||||
Serial.print(F("Ready to receive IR signals of protocols: "));
|
||||
printActiveIRProtocols(&Serial);
|
||||
Serial.print(F("at pin "));
|
||||
#endif
|
||||
|
||||
#if defined(IR_SEND_PIN)
|
||||
IrSender.begin(); // Start with IR_SEND_PIN -which is defined in PinDefinitionsAndMore.h- as send pin and enable feedback LED at default feedback LED pin
|
||||
#else
|
||||
IrSender.begin(3, ENABLE_LED_FEEDBACK, USE_DEFAULT_FEEDBACK_LED_PIN); // Specify send pin and enable feedback LED at default feedback LED pin
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static String readCommand(Stream &stream) {
|
||||
while (stream.available() == 0) {
|
||||
}
|
||||
|
||||
String line = stream.readStringUntil(EOLCHAR);
|
||||
line.trim();
|
||||
return line;
|
||||
}
|
||||
|
||||
static void processCommand(const String &line, Stream &stream) {
|
||||
Tokenizer tokenizer(line);
|
||||
String cmd = tokenizer.getToken();
|
||||
|
||||
// Decode the command in cmd
|
||||
if (cmd.length() == 0) {
|
||||
// empty command, do nothing
|
||||
stream.println(F(okString));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (cmd[0]) {
|
||||
case 'm':
|
||||
stream.println(F(modulesSupported));
|
||||
break;
|
||||
|
||||
#if defined(RECEIVE)
|
||||
case 'r': // receive
|
||||
//case 'a':
|
||||
//case 'c':
|
||||
receive(stream);
|
||||
break;
|
||||
#endif // RECEIVE
|
||||
|
||||
#if defined(TRANSMIT)
|
||||
case 's': // send
|
||||
{
|
||||
// TODO: handle unparsable data gracefully
|
||||
unsigned noSends = (unsigned) tokenizer.getInt();
|
||||
frequency_t frequency = tokenizer.getFrequency();
|
||||
unsigned introLength = (unsigned) tokenizer.getInt();
|
||||
unsigned repeatLength = (unsigned) tokenizer.getInt();
|
||||
unsigned endingLength = (unsigned) tokenizer.getInt();
|
||||
microseconds_t intro[introLength];
|
||||
microseconds_t repeat[repeatLength];
|
||||
microseconds_t ending[endingLength];
|
||||
for (unsigned i = 0; i < introLength; i++)
|
||||
intro[i] = tokenizer.getMicroseconds();
|
||||
for (unsigned i = 0; i < repeatLength; i++)
|
||||
repeat[i] = tokenizer.getMicroseconds();
|
||||
for (unsigned i = 0; i < endingLength; i++)
|
||||
ending[i] = tokenizer.getMicroseconds();
|
||||
sendRaw(intro, introLength, repeat, repeatLength, ending, endingLength, frequency, noSends);
|
||||
stream.println(F(okString));
|
||||
}
|
||||
break;
|
||||
#endif // TRANSMIT
|
||||
|
||||
case 'v': // version
|
||||
stream.println(F(PROGNAME " " VERSION));
|
||||
break;
|
||||
default:
|
||||
stream.println(F(errorString));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a command from the serial line and executes it-
|
||||
*/
|
||||
void loop() {
|
||||
String line = readCommand(Serial);
|
||||
processCommand(line, Serial);
|
||||
}
|
||||
@ -1,349 +0,0 @@
|
||||
/*
|
||||
* PinDefinitionsAndMore.h
|
||||
*
|
||||
* Contains pin definitions for IRremote examples for various platforms
|
||||
* as well as definitions for feedback LED and tone() and includes
|
||||
*
|
||||
* Copyright (C) 2021-2023 Armin Joachimsmeyer
|
||||
* armin.joachimsmeyer@gmail.com
|
||||
*
|
||||
* This file is part of IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.
|
||||
*
|
||||
* Arduino-IRremote is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Pin mapping table for different platforms
|
||||
*
|
||||
* Platform IR input IR output Tone Core/Pin schema
|
||||
* --------------------------------------------------------------
|
||||
* DEFAULT/AVR 2 3 4 Arduino
|
||||
* ATtinyX5 0|PB0 4|PB4 3|PB3 ATTinyCore
|
||||
* ATtiny167 3|PA3 2|PA2 7|PA7 ATTinyCore
|
||||
* ATtiny167 9|PA3 8|PA2 5|PA7 Digispark original core
|
||||
* ATtiny84 |PB2 |PA4 |PA3 ATTinyCore
|
||||
* ATtiny88 3|PD3 4|PD4 9|PB1 ATTinyCore
|
||||
* ATtiny3217 18|PA1 19|PA2 20|PA3 MegaTinyCore
|
||||
* ATtiny1604 2 3|PA5 %
|
||||
* ATtiny816 14|PA1 16|PA3 1|PA5 MegaTinyCore
|
||||
* ATtiny1614 8|PA1 10|PA3 1|PA5 MegaTinyCore
|
||||
* SAMD21 3 4 5
|
||||
* ESP8266 14|D5 12|D6 %
|
||||
* ESP32 15 4 27
|
||||
* ESP32-C3 2 3 4
|
||||
* BluePill PA6 PA7 PA3
|
||||
* APOLLO3 11 12 5
|
||||
* RP2040 3|GPIO15 4|GPIO16 5|GPIO17
|
||||
*/
|
||||
//#define _IR_MEASURE_TIMING // For debugging purposes.
|
||||
|
||||
#if defined(__AVR__)
|
||||
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) // Digispark board. For use with ATTinyCore.
|
||||
#include "ATtinySerialOut.hpp" // TX is at pin 2 - Available as Arduino library "ATtinySerialOut". Saves 700 bytes program memory and 70 bytes RAM for ATtinyCore.
|
||||
#define IR_RECEIVE_PIN PIN_PB0
|
||||
#define IR_SEND_PIN PIN_PB4 // Pin 2 is serial output with ATtinySerialOut. Pin 1 is internal LED and Pin3 is USB+ with pullup on Digispark board.
|
||||
#define TONE_PIN PIN_PB3
|
||||
#define _IR_TIMING_TEST_PIN PIN_PB3
|
||||
|
||||
# elif defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__) // Digispark pro board
|
||||
#include "ATtinySerialOut.hpp" // Available as Arduino library "ATtinySerialOut"
|
||||
// For ATtiny167 Pins PB6 and PA3 are usable as interrupt source.
|
||||
# if defined(ARDUINO_AVR_DIGISPARKPRO)
|
||||
// For use with Digispark original core
|
||||
#define IR_RECEIVE_PIN 9 // PA3 - on Digispark board labeled as pin 9
|
||||
//#define IR_RECEIVE_PIN 14 // PB6 / INT0 is connected to USB+ on DigisparkPro boards
|
||||
#define IR_SEND_PIN 8 // PA2 - on Digispark board labeled as pin 8
|
||||
#define TONE_PIN 5 // PA7 - on Digispark board labeled as pin 5
|
||||
#define _IR_TIMING_TEST_PIN 10 // PA4
|
||||
# else
|
||||
// For use with ATTinyCore
|
||||
#define IR_RECEIVE_PIN PIN_PA3 // On Digispark board labeled as pin 9 - INT0 is connected to USB+ on DigisparkPro boards
|
||||
#define IR_SEND_PIN PIN_PA2 // On Digispark board labeled as pin 8
|
||||
#define TONE_PIN PIN_PA7 // On Digispark board labeled as pin 5
|
||||
# endif
|
||||
|
||||
# elif defined(__AVR_ATtiny84__) // For use with ATTinyCore
|
||||
#include "ATtinySerialOut.hpp" // Available as Arduino library "ATtinySerialOut". Saves 128 bytes program memory.
|
||||
#define IR_RECEIVE_PIN PIN_PB2 // INT0
|
||||
#define IR_SEND_PIN PIN_PA4
|
||||
#define TONE_PIN PIN_PA3
|
||||
#define _IR_TIMING_TEST_PIN PIN_PA5
|
||||
|
||||
# elif defined(__AVR_ATtiny88__) // MH-ET Tiny88 board. For use with ATTinyCore.
|
||||
#include "ATtinySerialOut.hpp" // Available as Arduino library "ATtinySerialOut". Saves 128 bytes program memory.
|
||||
// Pin 6 is TX, pin 7 is RX
|
||||
#define IR_RECEIVE_PIN PIN_PD3 // 3 - INT1
|
||||
#define IR_SEND_PIN PIN_PD4 // 4
|
||||
#define TONE_PIN PIN_PB1 // 9
|
||||
#define _IR_TIMING_TEST_PIN PIN_PB0 // 8
|
||||
|
||||
# elif defined(__AVR_ATtiny1616__) || defined(__AVR_ATtiny3216__) || defined(__AVR_ATtiny3217__) // For use with megaTinyCore
|
||||
// Tiny Core Dev board
|
||||
// https://www.tindie.com/products/xkimi/tiny-core-16-dev-board-attiny1616/ - Out of Stock
|
||||
// https://www.tindie.com/products/xkimi/tiny-core-32-dev-board-attiny3217/ - Out of Stock
|
||||
#define IR_RECEIVE_PIN PIN_PA1 // use 18 instead of PIN_PA1 for TinyCore32
|
||||
#define IR_SEND_PIN PIN_PA2 // 19
|
||||
#define TONE_PIN PIN_PA3 // 20
|
||||
#define APPLICATION_PIN PIN_PA0 // 0
|
||||
#undef LED_BUILTIN // No LED available on the TinyCore 32 board, take the one on the programming board which is connected to the DAC output
|
||||
#define LED_BUILTIN PIN_PA6 // use 2 instead of PIN_PA6 for TinyCore32
|
||||
|
||||
# elif defined(__AVR_ATtiny816__) // For use with megaTinyCore
|
||||
#define IR_RECEIVE_PIN PIN_PA1 // 14
|
||||
#define IR_SEND_PIN PIN_PA1 // 16
|
||||
#define TONE_PIN PIN_PA5 // 1
|
||||
#define APPLICATION_PIN PIN_PA4 // 0
|
||||
#undef LED_BUILTIN // No LED available, take the one which is connected to the DAC output
|
||||
#define LED_BUILTIN PIN_PB5 // 4
|
||||
|
||||
# elif defined(__AVR_ATtiny1614__) // For use with megaTinyCore
|
||||
#define IR_RECEIVE_PIN PIN_PA1 // 8
|
||||
#define IR_SEND_PIN PIN_PA3 // 10
|
||||
#define TONE_PIN PIN_PA5 // 1
|
||||
#define APPLICATION_PIN PIN_PA4 // 0
|
||||
|
||||
# elif defined(__AVR_ATtiny1604__) // For use with megaTinyCore
|
||||
#define IR_RECEIVE_PIN PIN_PA6 // 2 - To be compatible with interrupt example, pin 2 is chosen here.
|
||||
#define IR_SEND_PIN PIN_PA7 // 3
|
||||
#define APPLICATION_PIN PIN_PB2 // 5
|
||||
|
||||
#define tone(...) void() // Define as void, since TCB0_INT_vect is also used by tone()
|
||||
#define noTone(a) void()
|
||||
#define TONE_PIN 42 // Dummy for examples using it
|
||||
|
||||
# elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) \
|
||||
|| defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) \
|
||||
|| defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) \
|
||||
|| defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega164A__) \
|
||||
|| defined(__AVR_ATmega164P__) || defined(__AVR_ATmega32__) \
|
||||
|| defined(__AVR_ATmega16__) || defined(__AVR_ATmega8535__) \
|
||||
|| defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) \
|
||||
|| defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) \
|
||||
|| defined(__AVR_ATmega8515__) || defined(__AVR_ATmega162__)
|
||||
#define IR_RECEIVE_PIN 2
|
||||
#define IR_SEND_PIN 13
|
||||
#define TONE_PIN 4
|
||||
#define APPLICATION_PIN 5
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 7
|
||||
|
||||
# else // Default as for ATmega328 like on Uno, Nano, Leonardo, Teensy 2.0 etc.
|
||||
#define IR_RECEIVE_PIN 2 // To be compatible with interrupt example, pin 2 is chosen here.
|
||||
#define IR_SEND_PIN 3
|
||||
#define TONE_PIN 4
|
||||
#define APPLICATION_PIN 5
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 7
|
||||
|
||||
# if defined(ARDUINO_AVR_PROMICRO) // Sparkfun Pro Micro is __AVR_ATmega32U4__ but has different external circuit
|
||||
// We have no built in LED at pin 13 -> reuse RX LED
|
||||
#undef LED_BUILTIN
|
||||
#define LED_BUILTIN LED_BUILTIN_RX
|
||||
# endif
|
||||
# endif // defined(__AVR_ATtiny25__)...
|
||||
|
||||
#elif defined(ARDUINO_ARCH_RENESAS_UNO) // Uno R4
|
||||
// To be compatible with Uno R3.
|
||||
#define IR_RECEIVE_PIN 2
|
||||
#define IR_SEND_PIN 3
|
||||
#define TONE_PIN 4
|
||||
#define APPLICATION_PIN 5
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 7
|
||||
|
||||
#elif defined(ESP8266)
|
||||
#define FEEDBACK_LED_IS_ACTIVE_LOW // The LED on my board (D4) is active LOW
|
||||
#define IR_RECEIVE_PIN 14 // D5
|
||||
#define IR_SEND_PIN 12 // D6 - D4/pin 2 is internal LED
|
||||
#define _IR_TIMING_TEST_PIN 2 // D4
|
||||
#define APPLICATION_PIN 13 // D7
|
||||
|
||||
#define tone(...) void() // tone() inhibits receive timer
|
||||
#define noTone(a) void()
|
||||
#define TONE_PIN 42 // Dummy for examples using it#
|
||||
|
||||
#elif defined(ARDUINO_NOLOGO_ESP32C3_SUPER_MINI)
|
||||
#define FEEDBACK_LED_IS_ACTIVE_LOW // The LED on my board (D8) is active LOW
|
||||
#define IR_RECEIVE_PIN 2
|
||||
#define IR_SEND_PIN 3
|
||||
#define TONE_PIN 4
|
||||
#define APPLICATION_PIN 10
|
||||
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(ARDUINO_ESP32C3_DEV)
|
||||
#define NO_LED_FEEDBACK_CODE // The WS2812 on pin 8 of AI-C3 board crashes if used as receive feedback LED, other I/O pins are working...
|
||||
#define IR_RECEIVE_PIN 6
|
||||
#define IR_SEND_PIN 7
|
||||
#define TONE_PIN 10
|
||||
#define APPLICATION_PIN 18
|
||||
|
||||
#elif defined(ESP32)
|
||||
#include <Arduino.h>
|
||||
|
||||
// tone() is included in ESP32 core since 2.0.2
|
||||
#if !defined(ESP_ARDUINO_VERSION_VAL)
|
||||
#define ESP_ARDUINO_VERSION_VAL(major, minor, patch) 12345678
|
||||
#endif
|
||||
#if ESP_ARDUINO_VERSION <= ESP_ARDUINO_VERSION_VAL(2, 0, 2)
|
||||
#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer.
|
||||
void tone(uint8_t aPinNumber, unsigned int aFrequency){
|
||||
ledcAttachPin(aPinNumber, TONE_LEDC_CHANNEL);
|
||||
ledcWriteTone(TONE_LEDC_CHANNEL, aFrequency);
|
||||
}
|
||||
void tone(uint8_t aPinNumber, unsigned int aFrequency, unsigned long aDuration){
|
||||
ledcAttachPin(aPinNumber, TONE_LEDC_CHANNEL);
|
||||
ledcWriteTone(TONE_LEDC_CHANNEL, aFrequency);
|
||||
delay(aDuration);
|
||||
ledcWriteTone(TONE_LEDC_CHANNEL, 0);
|
||||
}
|
||||
void noTone(uint8_t aPinNumber){
|
||||
ledcWriteTone(TONE_LEDC_CHANNEL, 0);
|
||||
}
|
||||
#endif // ESP_ARDUINO_VERSION <= ESP_ARDUINO_VERSION_VAL(2, 0, 2)
|
||||
|
||||
#define IR_RECEIVE_PIN 15 // D15
|
||||
#define IR_SEND_PIN 4 // D4
|
||||
#define TONE_PIN 27 // D27 25 & 26 are DAC0 and 1
|
||||
#define APPLICATION_PIN 16 // RX2 pin
|
||||
|
||||
#elif defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_STM32F1) // BluePill
|
||||
// Timer 3 blocks PA6, PA7, PB0, PB1 for use by Servo or tone()
|
||||
#define IR_RECEIVE_PIN PA6
|
||||
#define IR_RECEIVE_PIN_STRING "PA6"
|
||||
#define IR_SEND_PIN PA7
|
||||
#define IR_SEND_PIN_STRING "PA7"
|
||||
#define TONE_PIN PA3
|
||||
#define _IR_TIMING_TEST_PIN PA5
|
||||
#define APPLICATION_PIN PA2
|
||||
#define APPLICATION_PIN_STRING "PA2"
|
||||
# if defined(ARDUINO_GENERIC_STM32F103C) || defined(ARDUINO_BLUEPILL_F103C8)
|
||||
// BluePill LED is active low
|
||||
#define FEEDBACK_LED_IS_ACTIVE_LOW
|
||||
# endif
|
||||
|
||||
#elif defined(ARDUINO_ARCH_APOLLO3) // Sparkfun Apollo boards
|
||||
#define IR_RECEIVE_PIN 11
|
||||
#define IR_SEND_PIN 12
|
||||
#define TONE_PIN 5
|
||||
|
||||
#elif defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_MBED_NANO) // Arduino Nano 33 BLE and Arduino Nano Connect layout for MBED
|
||||
// Must be before ARDUINO_ARCH_RP2040, since it is the layout for the MBED core of Arduino Nano Connect
|
||||
#define IR_RECEIVE_PIN 3 // GPIO15 Start with pin 3 since pin 2|GPIO25 is connected to LED on Pi pico
|
||||
#define IR_SEND_PIN 4 // GPIO16
|
||||
#define TONE_PIN 5
|
||||
#define APPLICATION_PIN 6
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 7 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 8
|
||||
|
||||
#elif defined(ARDUINO_ARCH_RP2040) // Arduino Nano Connect, Pi Pico with arduino-pico core https://github.com/earlephilhower/arduino-pico
|
||||
#define IR_RECEIVE_PIN 15 // GPIO15 to be compatible with the Arduino Nano RP2040 Connect (pin3)
|
||||
#define IR_SEND_PIN 16 // GPIO16
|
||||
#define TONE_PIN 17
|
||||
#define APPLICATION_PIN 18
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 19 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 20
|
||||
|
||||
// If you program the Nano RP2040 Connect with this core, then you must redefine LED_BUILTIN
|
||||
// and use the external reset with 1 kOhm to ground to enter UF2 mode
|
||||
#undef LED_BUILTIN
|
||||
#define LED_BUILTIN 6
|
||||
|
||||
#elif defined(PARTICLE) // !!!UNTESTED!!!
|
||||
#define IR_RECEIVE_PIN A4
|
||||
#define IR_SEND_PIN A5 // Particle supports multiple pins
|
||||
|
||||
#define LED_BUILTIN D7
|
||||
|
||||
/*
|
||||
* 4 times the same (default) layout for easy adaption in the future
|
||||
*/
|
||||
#elif defined(TEENSYDUINO) // Teensy 2.0 is handled at default for ATmega328 like on Uno, Nano, Leonardo etc.
|
||||
#define IR_RECEIVE_PIN 2
|
||||
#define IR_SEND_PIN 3
|
||||
#define TONE_PIN 4
|
||||
#define APPLICATION_PIN 5
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 7
|
||||
|
||||
#elif defined(ARDUINO_ARCH_MBED) // Arduino Nano 33 BLE
|
||||
#define IR_RECEIVE_PIN 2
|
||||
#define IR_SEND_PIN 3
|
||||
#define TONE_PIN 4
|
||||
#define APPLICATION_PIN 5
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 7
|
||||
|
||||
#elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_SAM)
|
||||
#define IR_RECEIVE_PIN 2
|
||||
#define IR_SEND_PIN 3
|
||||
#define TONE_PIN 4
|
||||
#define APPLICATION_PIN 5
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 7
|
||||
|
||||
#if !defined(ARDUINO_SAMD_ADAFRUIT) && !defined(ARDUINO_SEEED_XIAO_M0)
|
||||
// On the Zero and others we switch explicitly to SerialUSB
|
||||
#define Serial SerialUSB
|
||||
#endif
|
||||
|
||||
// Definitions for the Chinese SAMD21 M0-Mini clone, which has no led connected to D13/PA17.
|
||||
// Attention!!! D2 and D4 are swapped on these boards!!!
|
||||
// If you connect the LED, it is on pin 24/PB11. In this case activate the next two lines.
|
||||
//#undef LED_BUILTIN
|
||||
//#define LED_BUILTIN 24 // PB11
|
||||
// As an alternative you can choose pin 25, it is the RX-LED pin (PB03), but active low.In this case activate the next 3 lines.
|
||||
//#undef LED_BUILTIN
|
||||
//#define LED_BUILTIN 25 // PB03
|
||||
//#define FEEDBACK_LED_IS_ACTIVE_LOW // The RX LED on the M0-Mini is active LOW
|
||||
|
||||
#elif defined (NRF51) // BBC micro:bit
|
||||
#define IR_RECEIVE_PIN 2
|
||||
#define IR_SEND_PIN 3
|
||||
#define APPLICATION_PIN 1
|
||||
#define _IR_TIMING_TEST_PIN 4
|
||||
|
||||
#define tone(...) void() // no tone() available
|
||||
#define noTone(a) void()
|
||||
#define TONE_PIN 42 // Dummy for examples using it
|
||||
|
||||
#else
|
||||
#warning Board / CPU is not detected using pre-processor symbols -> using default values, which may not fit. Please extend PinDefinitionsAndMore.h.
|
||||
// Default valued for unidentified boards
|
||||
#define IR_RECEIVE_PIN 2
|
||||
#define IR_SEND_PIN 3
|
||||
#define TONE_PIN 4
|
||||
#define APPLICATION_PIN 5
|
||||
#define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output.
|
||||
#define _IR_TIMING_TEST_PIN 7
|
||||
#endif // defined(ESP8266)
|
||||
|
||||
#if defined(ESP32) || defined(ARDUINO_ARCH_RP2040) || defined(PARTICLE) || defined(ARDUINO_ARCH_MBED)
|
||||
#define SEND_PWM_BY_TIMER // We do not have pin restrictions for this CPU's, so lets use the hardware PWM for send carrier signal generation
|
||||
#else
|
||||
# if defined(SEND_PWM_BY_TIMER)
|
||||
#undef IR_SEND_PIN // SendPin is determined by timer! This avoids warnings in IRremote.hpp and IRTimer.hpp
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined (FLASHEND)
|
||||
#define FLASHEND 0xFFFF // Dummy value for platforms where FLASHEND is not defined
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Helper macro for getting a macro definition as string
|
||||
*/
|
||||
#if !defined(STR_HELPER)
|
||||
#define STR_HELPER(x) #x
|
||||
#define STR(x) STR_HELPER(x)
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user