удалила непонятные примеры

This commit is contained in:
KLASSENTS 2025-01-17 14:34:02 +07:00
parent d9cc0d0988
commit 959016ad61
10 changed files with 0 additions and 3560 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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