diff --git a/README.md b/README.md index 05aa7d5..6b8c5a8 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Contains the [RobotCarBlueDisplay](https://github.com/ArminJo/Arduino-RobotCar)     [![Button API](https://img.shields.io/badge/API-yellow?logoColor=white&logo=OpenStreetMap)](https://github.com/ArminJo/PWMMotorControl#api)     -[![Button Changelog](https://img.shields.io/badge/Changelog-blue?logoColor=white&logo=AzureArtifacts)](https://github.com/ArminJo/PWMMotorControl#revision-history) +[![Button Changelog](https://img.shields.io/badge/Changelog-blue?logoColor=white&logo=AzureArtifacts)](https://github.com/ArminJo/PWMMotorControl?tab=readme-ov-file#revision-history) diff --git a/examples/Basic/RobotCarPinDefinitionsAndMore.h b/examples/Basic/RobotCarPinDefinitionsAndMore.h index d77f5c9..6738a58 100644 --- a/examples/Basic/RobotCarPinDefinitionsAndMore.h +++ b/examples/Basic/RobotCarPinDefinitionsAndMore.h @@ -235,20 +235,7 @@ # if !defined(LED_BUILTIN) && !defined(CAR_IS_ESP32_CAM_BASED) #define LED_BUILTIN PB1 # endif -#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. -void tone(uint8_t _pin, unsigned int frequency){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); -} -void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); - delay(duration); - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} -void noTone(uint8_t _pin){ - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} + #else // NANO_BASED // Uno based // Pin A0 for VCC monitoring - ADC channel 2 diff --git a/examples/BasicDistance/ADCUtils.h b/examples/BasicDistance/ADCUtils.h index 6e0b51f..c406217 100644 --- a/examples/BasicDistance/ADCUtils.h +++ b/examples/BasicDistance/ADCUtils.h @@ -85,6 +85,7 @@ #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 @@ -92,20 +93,31 @@ #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 @@ -164,7 +176,10 @@ uint16_t waitAndReadADCChannelWithReferenceAndRestoreADMUXAndReference(uint8_t a 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); -uint16_t readADCChannelWithReferenceMultiSamples(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples); +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, @@ -199,7 +214,8 @@ void resetCounterForVCCUndervoltageMultipleTimes(); bool isVCCUndervoltage(); bool isVCCEmergencyUndervoltage(); bool isVCCOvervoltage(); -bool isVCCOvervoltageSimple(); +bool isVCCOvervoltageSimple(); // Version using readVCCVoltageMillivoltSimple() +bool isVCCTooHighSimple(); // Version not using readVCCVoltageMillivoltSimple() #endif // defined(__AVR__) ... diff --git a/examples/BasicDistance/ADCUtils.hpp b/examples/BasicDistance/ADCUtils.hpp index c3abd92..73030b4 100644 --- a/examples/BasicDistance/ADCUtils.hpp +++ b/examples/BasicDistance/ADCUtils.hpp @@ -161,12 +161,15 @@ uint8_t checkAndWaitForReferenceAndChannelToSwitch(uint8_t aADCChannelNumber, ui 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 & 0x0F) != aADCChannelNumber) { + } 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 @@ -249,9 +252,10 @@ uint16_t readADCChannelWithReferenceOversampleFast(uint8_t aADCChannelNumber, ui /* * Returns sum of all sample values - * Conversion time is defined as 0.104 milliseconds for 16 MHz Arduino by ADC_PRESCALE in ADCUtils.h. + * 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 readADCChannelWithReferenceMultiSamples(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples) { +uint16_t readADCChannelMultiSamplesWithReference(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples) { uint16_t tSumValue = 0; ADMUX = aADCChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE); @@ -275,6 +279,65 @@ uint16_t readADCChannelWithReferenceMultiSamples(uint8_t aADCChannelNumber, uint 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. @@ -408,7 +471,7 @@ uint16_t readUntil4ConsecutiveValuesAreEqual(uint8_t aADCChannelNumber, uint8_t */ float getVCCVoltageSimple(void) { // use AVCC with (optional) external capacitor at AREF pin as reference - float tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + float tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); return ((1023 * 1.1 * 4) / tVCC); } @@ -419,7 +482,7 @@ float getVCCVoltageSimple(void) { */ uint16_t getVCCVoltageMillivoltSimple(void) { // use AVCC with external capacitor at AREF pin as reference - uint16_t tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + uint16_t tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); return ((1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCC); } @@ -459,6 +522,9 @@ uint16_t getVCCVoltageMillivolt(void) { return ((1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT) / tVCC); } +/* + * Does not set sVCCVoltageMillivolt + */ uint16_t printVCCVoltageMillivolt(Print *aSerial) { aSerial->print(F("VCC=")); uint16_t tVCCVoltageMillivolt = getVCCVoltageMillivolt(); @@ -480,7 +546,7 @@ void readAndPrintVCCVoltageMillivolt(Print *aSerial) { */ void readVCCVoltageSimple(void) { // use AVCC with (optional) external capacitor at AREF pin as reference - float tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + float tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); sVCCVoltage = (1023 * (((float) ADC_INTERNAL_REFERENCE_MILLIVOLT) / 1000) * 4) / tVCC; } @@ -491,7 +557,7 @@ void readVCCVoltageSimple(void) { */ void readVCCVoltageMillivoltSimple(void) { // use AVCC with external capacitor at AREF pin as reference - uint16_t tVCCVoltageMillivoltRaw = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + uint16_t tVCCVoltageMillivoltRaw = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); sVCCVoltageMillivolt = (1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCCVoltageMillivoltRaw; } @@ -556,7 +622,7 @@ bool isVCCUSBPowered(Print *aSerial) { aSerial->print(F("USB powered is ")); bool tReturnValue; if (VOLTAGE_USB_POWERED_LOWER_THRESHOLD_MILLIVOLT - < sVCCVoltageMillivolt && sVCCVoltageMillivolt < VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT) { + < sVCCVoltageMillivolt&& sVCCVoltageMillivolt < VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT) { tReturnValue = true; aSerial->print(F("true ")); } else { @@ -649,6 +715,7 @@ void resetCounterForVCCUndervoltageMultipleTimes() { * 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() { @@ -660,6 +727,21 @@ bool isVCCOvervoltageSimple() { 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! @@ -671,18 +753,21 @@ float getCPUTemperatureSimple(void) { return 0.0; #else // use internal 1.1 volt as reference. 4 times oversample. Assume the signal has noise, but never verified :-( - uint16_t tTempRaw = readADCChannelWithReferenceOversample(ADC_TEMPERATURE_CHANNEL_MUX, INTERNAL, 2); + uint16_t tTemperatureRaw = readADCChannelWithReferenceOversample(ADC_TEMPERATURE_CHANNEL_MUX, INTERNAL, 2); #if defined(LOCAL_DEBUG) Serial.print(F("TempRaw=")); - Serial.println(tTempRaw); + Serial.println(tTemperatureRaw); #endif #if defined(__AVR_ATmega328PB__) - tTempRaw -= 245; - return (float)tTempRaw; + 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 - tTempRaw -= 317; - return (float) tTempRaw / 1.22; + tTemperatureRaw -= 317; + return (float) tTemperatureRaw / 1.22; #endif #endif } @@ -704,7 +789,7 @@ float getCPUTemperature(void) { } #else // defined(ADC_UTILS_ARE_AVAILABLE) -// Dummy definition of functions defined in ADCUtils to compile examples without errors +// Dummy definition of functions defined in ADCUtils to compile examples for non AVR platforms without errors /* * Persistent storage for VCC value */ diff --git a/examples/BasicDistance/HCSR04.hpp b/examples/BasicDistance/HCSR04.hpp index b700511..5317f08 100644 --- a/examples/BasicDistance/HCSR04.hpp +++ b/examples/BasicDistance/HCSR04.hpp @@ -70,7 +70,15 @@ //#define USE_PIN_CHANGE_INTERRUPT_D0_TO_D7 // using PCINT2_vect - PORT D //#define USE_PIN_CHANGE_INTERRUPT_D8_TO_D13 // using PCINT0_vect - PORT B - Pin 13 is feedback output //#define USE_PIN_CHANGE_INTERRUPT_A0_TO_A5 // using PCINT1_vect - PORT C +#if __has_include("digitalWriteFast.h") #include "digitalWriteFast.h" +#else +#define pinModeFast pinMode +#define digitalReadFast digitalRead +#define digitalWriteFast digitalWrite +#define digitalToggleFast(P) digitalWrite(P, ! digitalRead(P)) +#endif + #include "HCSR04.h" //#define DEBUG @@ -132,6 +140,7 @@ void initUSDistancePin(uint8_t aTriggerOutEchoInPin) { #if !defined (TRIGGER_OUT_PIN) sTriggerOutPin = aTriggerOutEchoInPin; #endif + (void) aTriggerOutEchoInPin; sHCSR04Mode = HCSR04_MODE_USE_1_PIN; } diff --git a/examples/BasicDistance/RobotCarPinDefinitionsAndMore.h b/examples/BasicDistance/RobotCarPinDefinitionsAndMore.h index d77f5c9..6738a58 100644 --- a/examples/BasicDistance/RobotCarPinDefinitionsAndMore.h +++ b/examples/BasicDistance/RobotCarPinDefinitionsAndMore.h @@ -235,20 +235,7 @@ # if !defined(LED_BUILTIN) && !defined(CAR_IS_ESP32_CAM_BASED) #define LED_BUILTIN PB1 # endif -#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. -void tone(uint8_t _pin, unsigned int frequency){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); -} -void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); - delay(duration); - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} -void noTone(uint8_t _pin){ - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} + #else // NANO_BASED // Uno based // Pin A0 for VCC monitoring - ADC channel 2 diff --git a/examples/BasicIRControl/RobotCarPinDefinitionsAndMore.h b/examples/BasicIRControl/RobotCarPinDefinitionsAndMore.h index d77f5c9..6738a58 100644 --- a/examples/BasicIRControl/RobotCarPinDefinitionsAndMore.h +++ b/examples/BasicIRControl/RobotCarPinDefinitionsAndMore.h @@ -235,20 +235,7 @@ # if !defined(LED_BUILTIN) && !defined(CAR_IS_ESP32_CAM_BASED) #define LED_BUILTIN PB1 # endif -#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. -void tone(uint8_t _pin, unsigned int frequency){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); -} -void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); - delay(duration); - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} -void noTone(uint8_t _pin){ - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} + #else // NANO_BASED // Uno based // Pin A0 for VCC monitoring - ADC channel 2 diff --git a/examples/BasicIRControl/TinyIR.h b/examples/BasicIRControl/TinyIR.h index f8fe638..c01a67a 100644 --- a/examples/BasicIRControl/TinyIR.h +++ b/examples/BasicIRControl/TinyIR.h @@ -34,9 +34,9 @@ * @{ */ -#define VERSION_TINYIR "2.0.0" +#define VERSION_TINYIR "2.2.0" #define VERSION_TINYIR_MAJOR 2 -#define VERSION_TINYIR_MINOR 0 +#define VERSION_TINYIR_MINOR 2 #define VERSION_TINYIR_PATCH 0 // The change log is at the bottom of the file @@ -134,6 +134,8 @@ #define TINY_RECEIVER_ADDRESS_BITS NEC_ADDRESS_BITS // the address bits + parity # if defined(USE_ONKYO_PROTOCOL) #define TINY_RECEIVER_ADDRESS_HAS_8_BIT_PARITY false // 16 bit address without parity +# elif defined(USE_EXTENDED_NEC_PROTOCOL) +#define TINY_RECEIVER_ADDRESS_HAS_8_BIT_PARITY false // 16 bit address without parity # else #define TINY_RECEIVER_ADDRESS_HAS_8_BIT_PARITY true // 8 bit and 8 bit parity # endif @@ -241,7 +243,7 @@ struct TinyIRReceiverCallbackDataStruct { uint8_t Command; #endif uint8_t Flags; // Bit coded flags. Can contain one of the bits: IRDATA_FLAGS_IS_REPEAT and IRDATA_FLAGS_PARITY_FAILED - bool justWritten; ///< Is set true if new data is available. Used by the main loop, to avoid multiple evaluations of the same IR frame. + bool justWritten; ///< Is set true if new data is available. Used by the main loop / TinyReceiverDecode(), to avoid multiple evaluations of the same IR frame. }; extern volatile TinyIRReceiverCallbackDataStruct TinyIRReceiverData; @@ -250,16 +252,24 @@ bool initPCIInterruptForTinyReceiver(); bool enablePCIInterruptForTinyReceiver(); void disablePCIInterruptForTinyReceiver(); bool isTinyReceiverIdle(); +bool TinyReceiverDecode(); void printTinyReceiverResultMinimal(Print *aSerial); void sendFAST(uint8_t aSendPin, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0); void sendFast8BitAndParity(uint8_t aSendPin, uint8_t aCommand, uint_fast8_t aNumberOfRepeats = 0); -void sendONKYO(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0); // Send NEC with 16 bit command, even if aCommand < 0x100 +void sendONKYO(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0, bool aSendNEC2Repeats = false); // Send NEC with 16 bit command, even if aCommand < 0x100 void sendNECMinimal(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0) __attribute__ ((deprecated ("Renamed to sendNEC()."))); -void sendNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0); +void sendNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0, bool aSendNEC2Repeats = false); +void sendExtendedNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0, bool aSendNEC2Repeats = false); /* + * Version 2.2.0 - 7/2024 + * - New TinyReceiverDecode() function to be used as drop in for IrReceiver.decode(). + * + * Version 2.1.0 - 2/2024 + * - New sendExtendedNEC() function and new parameter aSendNEC2Repeats. + * * Version 2.0.0 - 10/2023 * - New TinyIRReceiverData which is filled with address, command and flags. * - Removed parameters address, command and flags from callback handleReceivedTinyIRData() and printTinyReceiverResultMinimal(). diff --git a/examples/BasicIRControl/TinyIRReceiver.hpp b/examples/BasicIRControl/TinyIRReceiver.hpp index 4316db8..39b3414 100644 --- a/examples/BasicIRControl/TinyIRReceiver.hpp +++ b/examples/BasicIRControl/TinyIRReceiver.hpp @@ -28,7 +28,7 @@ ************************************************************************************ * MIT License * - * Copyright (c) 2022-2023 Armin Joachimsmeyer + * 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 @@ -58,6 +58,7 @@ * - IR_FEEDBACK_LED_PIN The pin number for TinyIRReceiver feedback LED. * - NO_LED_FEEDBACK_CODE Disables the feedback LED function. Saves 14 bytes program memory. * - DISABLE_PARITY_CHECKS Disable parity checks. Saves 48 bytes of program memory. + * - USE_EXTENDED_NEC_PROTOCOL Like NEC, but take the 16 bit address as one 16 bit value and not as 8 bit normal and 8 bit inverted value. * - USE_ONKYO_PROTOCOL Like NEC, but take the 16 bit address and command each as one 16 bit value and not as 8 bit normal and 8 bit inverted value. * - USE_FAST_PROTOCOL Use FAST protocol (no address and 16 bit data, interpreted as 8 bit command and 8 bit inverted command) instead of NEC. * - ENABLE_NEC2_REPEATS Instead of sending / receiving the NEC special repeat code, send / receive the original frame for repeat. @@ -75,11 +76,14 @@ //#define LOCAL_DEBUG // This enables debug output only for this file #endif +/* + * Protocol selection + */ //#define DISABLE_PARITY_CHECKS // Disable parity checks. Saves 48 bytes of program memory. +//#define USE_EXTENDED_NEC_PROTOCOL // Like NEC, but take the 16 bit address as one 16 bit value and not as 8 bit normal and 8 bit inverted value. //#define USE_ONKYO_PROTOCOL // Like NEC, but take the 16 bit address and command each as one 16 bit value and not as 8 bit normal and 8 bit inverted value. //#define USE_FAST_PROTOCOL // Use FAST protocol instead of NEC / ONKYO. //#define ENABLE_NEC2_REPEATS // Instead of sending / receiving the NEC special repeat code, send / receive the original frame for repeat. - #include "TinyIR.h" // If not defined, it defines IR_RECEIVE_PIN, IR_FEEDBACK_LED_PIN and TINY_RECEIVER_USE_ARDUINO_ATTACH_INTERRUPT #include "digitalWriteFast.h" @@ -379,7 +383,7 @@ void IRPinChangeInterruptHandler(void) { // Here we have 8 bit command TinyIRReceiverData.Command = TinyIRReceiverControl.IRRawData.UBytes[2]; # else - // Here we have 16 bit command + // Here we have 16 bit command TinyIRReceiverData.Command = TinyIRReceiverControl.IRRawData.UWord.HighWord; # endif @@ -421,6 +425,17 @@ bool isTinyReceiverIdle() { return (TinyIRReceiverControl.IRReceiverState == IR_RECEIVER_STATE_WAITING_FOR_START_MARK); } +/* + * Function to be used as drop in for IrReceiver.decode() + */ +bool TinyReceiverDecode() { + bool tJustWritten = TinyIRReceiverData.justWritten; + if (tJustWritten) { + TinyIRReceiverData.justWritten = false; + } + return tJustWritten; +} + /* * Checks if IR_RECEIVE_PIN is connected and high * @return true, if IR Receiver is attached diff --git a/examples/BasicMecanum/RobotCarPinDefinitionsAndMore.h b/examples/BasicMecanum/RobotCarPinDefinitionsAndMore.h index d77f5c9..6738a58 100644 --- a/examples/BasicMecanum/RobotCarPinDefinitionsAndMore.h +++ b/examples/BasicMecanum/RobotCarPinDefinitionsAndMore.h @@ -235,20 +235,7 @@ # if !defined(LED_BUILTIN) && !defined(CAR_IS_ESP32_CAM_BASED) #define LED_BUILTIN PB1 # endif -#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. -void tone(uint8_t _pin, unsigned int frequency){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); -} -void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); - delay(duration); - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} -void noTone(uint8_t _pin){ - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} + #else // NANO_BASED // Uno based // Pin A0 for VCC monitoring - ADC channel 2 diff --git a/examples/IRDispatcherControl/HCSR04.hpp b/examples/IRDispatcherControl/HCSR04.hpp index b700511..5317f08 100644 --- a/examples/IRDispatcherControl/HCSR04.hpp +++ b/examples/IRDispatcherControl/HCSR04.hpp @@ -70,7 +70,15 @@ //#define USE_PIN_CHANGE_INTERRUPT_D0_TO_D7 // using PCINT2_vect - PORT D //#define USE_PIN_CHANGE_INTERRUPT_D8_TO_D13 // using PCINT0_vect - PORT B - Pin 13 is feedback output //#define USE_PIN_CHANGE_INTERRUPT_A0_TO_A5 // using PCINT1_vect - PORT C +#if __has_include("digitalWriteFast.h") #include "digitalWriteFast.h" +#else +#define pinModeFast pinMode +#define digitalReadFast digitalRead +#define digitalWriteFast digitalWrite +#define digitalToggleFast(P) digitalWrite(P, ! digitalRead(P)) +#endif + #include "HCSR04.h" //#define DEBUG @@ -132,6 +140,7 @@ void initUSDistancePin(uint8_t aTriggerOutEchoInPin) { #if !defined (TRIGGER_OUT_PIN) sTriggerOutPin = aTriggerOutEchoInPin; #endif + (void) aTriggerOutEchoInPin; sHCSR04Mode = HCSR04_MODE_USE_1_PIN; } diff --git a/examples/IRDispatcherControl/RobotCarPinDefinitionsAndMore.h b/examples/IRDispatcherControl/RobotCarPinDefinitionsAndMore.h index d77f5c9..6738a58 100644 --- a/examples/IRDispatcherControl/RobotCarPinDefinitionsAndMore.h +++ b/examples/IRDispatcherControl/RobotCarPinDefinitionsAndMore.h @@ -235,20 +235,7 @@ # if !defined(LED_BUILTIN) && !defined(CAR_IS_ESP32_CAM_BASED) #define LED_BUILTIN PB1 # endif -#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. -void tone(uint8_t _pin, unsigned int frequency){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); -} -void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); - delay(duration); - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} -void noTone(uint8_t _pin){ - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} + #else // NANO_BASED // Uno based // Pin A0 for VCC monitoring - ADC channel 2 diff --git a/examples/IRDispatcherControl/RobotCarUtils.hpp b/examples/IRDispatcherControl/RobotCarUtils.hpp index 08c4a79..bc5140d 100644 --- a/examples/IRDispatcherControl/RobotCarUtils.hpp +++ b/examples/IRDispatcherControl/RobotCarUtils.hpp @@ -87,9 +87,9 @@ bool doCalibration = false; # endif #include "ADCUtils.hpp" uint16_t sLastVINRawSum; // Sum of NUMBER_OF_VIN_SAMPLES raw readings of ADC, used to determine if voltage has changed and must be displayed. -float sVINVoltage = FULL_BRIDGE_INPUT_MILLIVOLT / 1000; // set default value for later use uint32_t sMillisOfLastVCCInfo; #endif // defined(VIN_ATTENUATED_INPUT_PIN) +float sVINVoltage = FULL_BRIDGE_INPUT_MILLIVOLT / 1000; // Set default value for later use. Is used a parameter for getVoltageAdjustedSpeedPWM //uint32_t sMillisOfLastAttention = 0; // millis() of last doAttention() or doWave() @@ -227,7 +227,7 @@ bool readVINVoltage() { * Here VIN is the only channel we convert. * Get 10 samples lasting 1030 us, which is almost the PWM period of 1024 us. */ - uint16_t tVINRawSum = readADCChannelWithReferenceMultiSamples(VIN_ATTENUATED_INPUT_CHANNEL, INTERNAL, NUMBER_OF_VIN_SAMPLES); // 10 samples + uint16_t tVINRawSum = readADCChannelMultiSamplesWithReference(VIN_ATTENUATED_INPUT_CHANNEL, INTERNAL, NUMBER_OF_VIN_SAMPLES); // 10 samples #if defined(CAR_HAS_IR_DISTANCE_SENSOR) checkAndWaitForReferenceAndChannelToSwitch(tOldADMUX & MASK_FOR_ADC_CHANNELS, tOldADMUX >> SHIFT_VALUE_FOR_REFERENCE); #endif diff --git a/examples/IRDispatcherControl/TinyIR.h b/examples/IRDispatcherControl/TinyIR.h index f8fe638..c01a67a 100644 --- a/examples/IRDispatcherControl/TinyIR.h +++ b/examples/IRDispatcherControl/TinyIR.h @@ -34,9 +34,9 @@ * @{ */ -#define VERSION_TINYIR "2.0.0" +#define VERSION_TINYIR "2.2.0" #define VERSION_TINYIR_MAJOR 2 -#define VERSION_TINYIR_MINOR 0 +#define VERSION_TINYIR_MINOR 2 #define VERSION_TINYIR_PATCH 0 // The change log is at the bottom of the file @@ -134,6 +134,8 @@ #define TINY_RECEIVER_ADDRESS_BITS NEC_ADDRESS_BITS // the address bits + parity # if defined(USE_ONKYO_PROTOCOL) #define TINY_RECEIVER_ADDRESS_HAS_8_BIT_PARITY false // 16 bit address without parity +# elif defined(USE_EXTENDED_NEC_PROTOCOL) +#define TINY_RECEIVER_ADDRESS_HAS_8_BIT_PARITY false // 16 bit address without parity # else #define TINY_RECEIVER_ADDRESS_HAS_8_BIT_PARITY true // 8 bit and 8 bit parity # endif @@ -241,7 +243,7 @@ struct TinyIRReceiverCallbackDataStruct { uint8_t Command; #endif uint8_t Flags; // Bit coded flags. Can contain one of the bits: IRDATA_FLAGS_IS_REPEAT and IRDATA_FLAGS_PARITY_FAILED - bool justWritten; ///< Is set true if new data is available. Used by the main loop, to avoid multiple evaluations of the same IR frame. + bool justWritten; ///< Is set true if new data is available. Used by the main loop / TinyReceiverDecode(), to avoid multiple evaluations of the same IR frame. }; extern volatile TinyIRReceiverCallbackDataStruct TinyIRReceiverData; @@ -250,16 +252,24 @@ bool initPCIInterruptForTinyReceiver(); bool enablePCIInterruptForTinyReceiver(); void disablePCIInterruptForTinyReceiver(); bool isTinyReceiverIdle(); +bool TinyReceiverDecode(); void printTinyReceiverResultMinimal(Print *aSerial); void sendFAST(uint8_t aSendPin, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0); void sendFast8BitAndParity(uint8_t aSendPin, uint8_t aCommand, uint_fast8_t aNumberOfRepeats = 0); -void sendONKYO(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0); // Send NEC with 16 bit command, even if aCommand < 0x100 +void sendONKYO(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0, bool aSendNEC2Repeats = false); // Send NEC with 16 bit command, even if aCommand < 0x100 void sendNECMinimal(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0) __attribute__ ((deprecated ("Renamed to sendNEC()."))); -void sendNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0); +void sendNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0, bool aSendNEC2Repeats = false); +void sendExtendedNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0, bool aSendNEC2Repeats = false); /* + * Version 2.2.0 - 7/2024 + * - New TinyReceiverDecode() function to be used as drop in for IrReceiver.decode(). + * + * Version 2.1.0 - 2/2024 + * - New sendExtendedNEC() function and new parameter aSendNEC2Repeats. + * * Version 2.0.0 - 10/2023 * - New TinyIRReceiverData which is filled with address, command and flags. * - Removed parameters address, command and flags from callback handleReceivedTinyIRData() and printTinyReceiverResultMinimal(). diff --git a/examples/IRDispatcherControl/TinyIRReceiver.hpp b/examples/IRDispatcherControl/TinyIRReceiver.hpp index 4316db8..39b3414 100644 --- a/examples/IRDispatcherControl/TinyIRReceiver.hpp +++ b/examples/IRDispatcherControl/TinyIRReceiver.hpp @@ -28,7 +28,7 @@ ************************************************************************************ * MIT License * - * Copyright (c) 2022-2023 Armin Joachimsmeyer + * 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 @@ -58,6 +58,7 @@ * - IR_FEEDBACK_LED_PIN The pin number for TinyIRReceiver feedback LED. * - NO_LED_FEEDBACK_CODE Disables the feedback LED function. Saves 14 bytes program memory. * - DISABLE_PARITY_CHECKS Disable parity checks. Saves 48 bytes of program memory. + * - USE_EXTENDED_NEC_PROTOCOL Like NEC, but take the 16 bit address as one 16 bit value and not as 8 bit normal and 8 bit inverted value. * - USE_ONKYO_PROTOCOL Like NEC, but take the 16 bit address and command each as one 16 bit value and not as 8 bit normal and 8 bit inverted value. * - USE_FAST_PROTOCOL Use FAST protocol (no address and 16 bit data, interpreted as 8 bit command and 8 bit inverted command) instead of NEC. * - ENABLE_NEC2_REPEATS Instead of sending / receiving the NEC special repeat code, send / receive the original frame for repeat. @@ -75,11 +76,14 @@ //#define LOCAL_DEBUG // This enables debug output only for this file #endif +/* + * Protocol selection + */ //#define DISABLE_PARITY_CHECKS // Disable parity checks. Saves 48 bytes of program memory. +//#define USE_EXTENDED_NEC_PROTOCOL // Like NEC, but take the 16 bit address as one 16 bit value and not as 8 bit normal and 8 bit inverted value. //#define USE_ONKYO_PROTOCOL // Like NEC, but take the 16 bit address and command each as one 16 bit value and not as 8 bit normal and 8 bit inverted value. //#define USE_FAST_PROTOCOL // Use FAST protocol instead of NEC / ONKYO. //#define ENABLE_NEC2_REPEATS // Instead of sending / receiving the NEC special repeat code, send / receive the original frame for repeat. - #include "TinyIR.h" // If not defined, it defines IR_RECEIVE_PIN, IR_FEEDBACK_LED_PIN and TINY_RECEIVER_USE_ARDUINO_ATTACH_INTERRUPT #include "digitalWriteFast.h" @@ -379,7 +383,7 @@ void IRPinChangeInterruptHandler(void) { // Here we have 8 bit command TinyIRReceiverData.Command = TinyIRReceiverControl.IRRawData.UBytes[2]; # else - // Here we have 16 bit command + // Here we have 16 bit command TinyIRReceiverData.Command = TinyIRReceiverControl.IRRawData.UWord.HighWord; # endif @@ -421,6 +425,17 @@ bool isTinyReceiverIdle() { return (TinyIRReceiverControl.IRReceiverState == IR_RECEIVER_STATE_WAITING_FOR_START_MARK); } +/* + * Function to be used as drop in for IrReceiver.decode() + */ +bool TinyReceiverDecode() { + bool tJustWritten = TinyIRReceiverData.justWritten; + if (tJustWritten) { + TinyIRReceiverData.justWritten = false; + } + return tJustWritten; +} + /* * Checks if IR_RECEIVE_PIN is connected and high * @return true, if IR Receiver is attached diff --git a/examples/IRDispatcherControl/TinyIRSender.hpp b/examples/IRDispatcherControl/TinyIRSender.hpp index 03d0b93..65a1fe1 100644 --- a/examples/IRDispatcherControl/TinyIRSender.hpp +++ b/examples/IRDispatcherControl/TinyIRSender.hpp @@ -19,7 +19,7 @@ ************************************************************************************ * MIT License * - * Copyright (c) 2022-2023 Armin Joachimsmeyer + * 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 @@ -105,12 +105,13 @@ void sendMark(uint8_t aSendPin, unsigned int aMarkMicros) { } /* - * Send NEC with 16 bit command, even if aCommand < 0x100 + * Send NEC with 16 bit address and command, even if aCommand < 0x100 (I.E. ONKYO) * @param aAddress - The 16 bit address to send. * @param aCommand - The 16 bit command to send. * @param aNumberOfRepeats - Number of repeats send at a period of 110 ms. + * @param aSendNEC2Repeats - Instead of sending the NEC special repeat code, send the original frame for repeat. */ -void sendONKYO(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats) { +void sendONKYO(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats, bool aSendNEC2Repeats) { pinModeFast(aSendPin, OUTPUT); uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1; @@ -118,13 +119,10 @@ void sendONKYO(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast unsigned long tStartOfFrameMillis = millis(); sendMark(aSendPin, NEC_HEADER_MARK); -#if !defined(ENABLE_NEC2_REPEATS) - if (tNumberOfCommands < aNumberOfRepeats + 1) { + if ((!aSendNEC2Repeats) && (tNumberOfCommands < aNumberOfRepeats + 1)) { // send the NEC special repeat delayMicroseconds(NEC_REPEAT_HEADER_SPACE); // - 2250 - } else -#endif - { + } else { // send header delayMicroseconds(NEC_HEADER_SPACE); LongUnion tData; @@ -158,15 +156,16 @@ void sendONKYO(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast } /* - * Send NEC with 8 or 16 bit address or data depending on the values of aAddress and aCommand. + * Send NEC with 8 or 16 bit address or command depending on the values of aAddress and aCommand. * @param aAddress - If aAddress < 0x100 send 8 bit address and 8 bit inverted address, else send 16 bit address. * @param aCommand - If aCommand < 0x100 send 8 bit command and 8 bit inverted command, else send 16 bit command. * @param aNumberOfRepeats - Number of repeats send at a period of 110 ms. + * @param aSendNEC2Repeats - Instead of sending the NEC special repeat code, send the original frame for repeat. */ void sendNECMinimal(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats) { sendNEC(aSendPin, aAddress, aCommand, aNumberOfRepeats); // sendNECMinimal() is deprecated } -void sendNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats) { +void sendNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats, bool aSendNEC2Repeats) { pinModeFast(aSendPin, OUTPUT); uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1; @@ -174,13 +173,10 @@ void sendNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_ unsigned long tStartOfFrameMillis = millis(); sendMark(aSendPin, NEC_HEADER_MARK); -#if !defined(ENABLE_NEC2_REPEATS) - if (tNumberOfCommands < aNumberOfRepeats + 1) { + if ((!aSendNEC2Repeats) && (tNumberOfCommands < aNumberOfRepeats + 1)) { // send the NEC special repeat delayMicroseconds(NEC_REPEAT_HEADER_SPACE); // - 2250 - } else -#endif - { + } else { // send header delayMicroseconds(NEC_HEADER_SPACE); LongUnion tData; @@ -228,6 +224,63 @@ void sendNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_ } } +/* + * Send Extended NEC with a forced 16 bit address and 8 or 16 bit command depending on the value of aCommand. + * @param aAddress - Send 16 bit address. + * @param aCommand - If aCommand < 0x100 send 8 bit command and 8 bit inverted command, else send 16 bit command. + * @param aNumberOfRepeats - Number of repeats send at a period of 110 ms. + * @param aSendNEC2Repeats - Instead of sending the NEC special repeat code, send the original frame for repeat. + */ +void sendExtendedNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats, bool aSendNEC2Repeats) { + pinModeFast(aSendPin, OUTPUT); + + uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1; + while (tNumberOfCommands > 0) { + unsigned long tStartOfFrameMillis = millis(); + + sendMark(aSendPin, NEC_HEADER_MARK); + if ((!aSendNEC2Repeats) && (tNumberOfCommands < aNumberOfRepeats + 1)) { + // send the NEC special repeat + delayMicroseconds(NEC_REPEAT_HEADER_SPACE); // - 2250 + } else { + // send header + delayMicroseconds(NEC_HEADER_SPACE); + LongUnion tData; + tData.UWord.LowWord = aAddress; + if (aCommand > 0xFF) { + tData.UWord.HighWord = aCommand; + } else { + tData.UByte.MidHighByte = aCommand; + tData.UByte.HighByte = ~aCommand; // LSB first + } + // Send data + for (uint_fast8_t i = 0; i < NEC_BITS; ++i) { + sendMark(aSendPin, NEC_BIT_MARK); // constant mark length + + if (tData.ULong & 1) { + delayMicroseconds(NEC_ONE_SPACE); + } else { + delayMicroseconds(NEC_ZERO_SPACE); + } + tData.ULong >>= 1; // shift command for next bit + } + } // send stop bit + sendMark(aSendPin, NEC_BIT_MARK); + + tNumberOfCommands--; + // skip last delay! + if (tNumberOfCommands > 0) { + /* + * Check and fallback for wrong RepeatPeriodMillis parameter. I.e the repeat period must be greater than each frame duration. + */ + auto tFrameDurationMillis = millis() - tStartOfFrameMillis; + if (NEC_REPEAT_PERIOD / 1000 > tFrameDurationMillis) { + delay(NEC_REPEAT_PERIOD / 1000 - tFrameDurationMillis); + } + } + } +} + /* * LSB first, send header, command, inverted command and stop bit */ diff --git a/examples/LineFollower/RobotCarPinDefinitionsAndMore.h b/examples/LineFollower/RobotCarPinDefinitionsAndMore.h index d77f5c9..6738a58 100644 --- a/examples/LineFollower/RobotCarPinDefinitionsAndMore.h +++ b/examples/LineFollower/RobotCarPinDefinitionsAndMore.h @@ -235,20 +235,7 @@ # if !defined(LED_BUILTIN) && !defined(CAR_IS_ESP32_CAM_BASED) #define LED_BUILTIN PB1 # endif -#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. -void tone(uint8_t _pin, unsigned int frequency){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); -} -void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); - delay(duration); - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} -void noTone(uint8_t _pin){ - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} + #else // NANO_BASED // Uno based // Pin A0 for VCC monitoring - ADC channel 2 diff --git a/examples/LineFollower/RobotCarUtils.hpp b/examples/LineFollower/RobotCarUtils.hpp index 08c4a79..bc5140d 100644 --- a/examples/LineFollower/RobotCarUtils.hpp +++ b/examples/LineFollower/RobotCarUtils.hpp @@ -87,9 +87,9 @@ bool doCalibration = false; # endif #include "ADCUtils.hpp" uint16_t sLastVINRawSum; // Sum of NUMBER_OF_VIN_SAMPLES raw readings of ADC, used to determine if voltage has changed and must be displayed. -float sVINVoltage = FULL_BRIDGE_INPUT_MILLIVOLT / 1000; // set default value for later use uint32_t sMillisOfLastVCCInfo; #endif // defined(VIN_ATTENUATED_INPUT_PIN) +float sVINVoltage = FULL_BRIDGE_INPUT_MILLIVOLT / 1000; // Set default value for later use. Is used a parameter for getVoltageAdjustedSpeedPWM //uint32_t sMillisOfLastAttention = 0; // millis() of last doAttention() or doWave() @@ -227,7 +227,7 @@ bool readVINVoltage() { * Here VIN is the only channel we convert. * Get 10 samples lasting 1030 us, which is almost the PWM period of 1024 us. */ - uint16_t tVINRawSum = readADCChannelWithReferenceMultiSamples(VIN_ATTENUATED_INPUT_CHANNEL, INTERNAL, NUMBER_OF_VIN_SAMPLES); // 10 samples + uint16_t tVINRawSum = readADCChannelMultiSamplesWithReference(VIN_ATTENUATED_INPUT_CHANNEL, INTERNAL, NUMBER_OF_VIN_SAMPLES); // 10 samples #if defined(CAR_HAS_IR_DISTANCE_SENSOR) checkAndWaitForReferenceAndChannelToSwitch(tOldADMUX & MASK_FOR_ADC_CHANNELS, tOldADMUX >> SHIFT_VALUE_FOR_REFERENCE); #endif diff --git a/examples/MecanumWheelCar/ADCUtils.h b/examples/MecanumWheelCar/ADCUtils.h index 6e0b51f..c406217 100644 --- a/examples/MecanumWheelCar/ADCUtils.h +++ b/examples/MecanumWheelCar/ADCUtils.h @@ -85,6 +85,7 @@ #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 @@ -92,20 +93,31 @@ #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 @@ -164,7 +176,10 @@ uint16_t waitAndReadADCChannelWithReferenceAndRestoreADMUXAndReference(uint8_t a 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); -uint16_t readADCChannelWithReferenceMultiSamples(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples); +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, @@ -199,7 +214,8 @@ void resetCounterForVCCUndervoltageMultipleTimes(); bool isVCCUndervoltage(); bool isVCCEmergencyUndervoltage(); bool isVCCOvervoltage(); -bool isVCCOvervoltageSimple(); +bool isVCCOvervoltageSimple(); // Version using readVCCVoltageMillivoltSimple() +bool isVCCTooHighSimple(); // Version not using readVCCVoltageMillivoltSimple() #endif // defined(__AVR__) ... diff --git a/examples/MecanumWheelCar/ADCUtils.hpp b/examples/MecanumWheelCar/ADCUtils.hpp index c3abd92..73030b4 100644 --- a/examples/MecanumWheelCar/ADCUtils.hpp +++ b/examples/MecanumWheelCar/ADCUtils.hpp @@ -161,12 +161,15 @@ uint8_t checkAndWaitForReferenceAndChannelToSwitch(uint8_t aADCChannelNumber, ui 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 & 0x0F) != aADCChannelNumber) { + } 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 @@ -249,9 +252,10 @@ uint16_t readADCChannelWithReferenceOversampleFast(uint8_t aADCChannelNumber, ui /* * Returns sum of all sample values - * Conversion time is defined as 0.104 milliseconds for 16 MHz Arduino by ADC_PRESCALE in ADCUtils.h. + * 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 readADCChannelWithReferenceMultiSamples(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples) { +uint16_t readADCChannelMultiSamplesWithReference(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples) { uint16_t tSumValue = 0; ADMUX = aADCChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE); @@ -275,6 +279,65 @@ uint16_t readADCChannelWithReferenceMultiSamples(uint8_t aADCChannelNumber, uint 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. @@ -408,7 +471,7 @@ uint16_t readUntil4ConsecutiveValuesAreEqual(uint8_t aADCChannelNumber, uint8_t */ float getVCCVoltageSimple(void) { // use AVCC with (optional) external capacitor at AREF pin as reference - float tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + float tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); return ((1023 * 1.1 * 4) / tVCC); } @@ -419,7 +482,7 @@ float getVCCVoltageSimple(void) { */ uint16_t getVCCVoltageMillivoltSimple(void) { // use AVCC with external capacitor at AREF pin as reference - uint16_t tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + uint16_t tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); return ((1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCC); } @@ -459,6 +522,9 @@ uint16_t getVCCVoltageMillivolt(void) { return ((1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT) / tVCC); } +/* + * Does not set sVCCVoltageMillivolt + */ uint16_t printVCCVoltageMillivolt(Print *aSerial) { aSerial->print(F("VCC=")); uint16_t tVCCVoltageMillivolt = getVCCVoltageMillivolt(); @@ -480,7 +546,7 @@ void readAndPrintVCCVoltageMillivolt(Print *aSerial) { */ void readVCCVoltageSimple(void) { // use AVCC with (optional) external capacitor at AREF pin as reference - float tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + float tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); sVCCVoltage = (1023 * (((float) ADC_INTERNAL_REFERENCE_MILLIVOLT) / 1000) * 4) / tVCC; } @@ -491,7 +557,7 @@ void readVCCVoltageSimple(void) { */ void readVCCVoltageMillivoltSimple(void) { // use AVCC with external capacitor at AREF pin as reference - uint16_t tVCCVoltageMillivoltRaw = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + uint16_t tVCCVoltageMillivoltRaw = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); sVCCVoltageMillivolt = (1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCCVoltageMillivoltRaw; } @@ -556,7 +622,7 @@ bool isVCCUSBPowered(Print *aSerial) { aSerial->print(F("USB powered is ")); bool tReturnValue; if (VOLTAGE_USB_POWERED_LOWER_THRESHOLD_MILLIVOLT - < sVCCVoltageMillivolt && sVCCVoltageMillivolt < VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT) { + < sVCCVoltageMillivolt&& sVCCVoltageMillivolt < VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT) { tReturnValue = true; aSerial->print(F("true ")); } else { @@ -649,6 +715,7 @@ void resetCounterForVCCUndervoltageMultipleTimes() { * 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() { @@ -660,6 +727,21 @@ bool isVCCOvervoltageSimple() { 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! @@ -671,18 +753,21 @@ float getCPUTemperatureSimple(void) { return 0.0; #else // use internal 1.1 volt as reference. 4 times oversample. Assume the signal has noise, but never verified :-( - uint16_t tTempRaw = readADCChannelWithReferenceOversample(ADC_TEMPERATURE_CHANNEL_MUX, INTERNAL, 2); + uint16_t tTemperatureRaw = readADCChannelWithReferenceOversample(ADC_TEMPERATURE_CHANNEL_MUX, INTERNAL, 2); #if defined(LOCAL_DEBUG) Serial.print(F("TempRaw=")); - Serial.println(tTempRaw); + Serial.println(tTemperatureRaw); #endif #if defined(__AVR_ATmega328PB__) - tTempRaw -= 245; - return (float)tTempRaw; + 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 - tTempRaw -= 317; - return (float) tTempRaw / 1.22; + tTemperatureRaw -= 317; + return (float) tTemperatureRaw / 1.22; #endif #endif } @@ -704,7 +789,7 @@ float getCPUTemperature(void) { } #else // defined(ADC_UTILS_ARE_AVAILABLE) -// Dummy definition of functions defined in ADCUtils to compile examples without errors +// Dummy definition of functions defined in ADCUtils to compile examples for non AVR platforms without errors /* * Persistent storage for VCC value */ diff --git a/examples/MecanumWheelCar/MecanumWheelCar.ino b/examples/MecanumWheelCar/MecanumWheelCar.ino index fedfb59..0203272 100644 --- a/examples/MecanumWheelCar/MecanumWheelCar.ino +++ b/examples/MecanumWheelCar/MecanumWheelCar.ino @@ -56,7 +56,8 @@ void setup() { Serial.begin(115200); -#if defined(__AVR_ATmega32U4__) || defined(SERIAL_PORT_USBVIRTUAL) || defined(SERIAL_USB) /*stm32duino*/|| defined(USBCON) /*STM32_stm32*/|| defined(SERIALUSB_PID) || defined(ARDUINO_attiny3217) +#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 diff --git a/examples/MecanumWheelCar/RobotCarPinDefinitionsAndMore.h b/examples/MecanumWheelCar/RobotCarPinDefinitionsAndMore.h index d77f5c9..6738a58 100644 --- a/examples/MecanumWheelCar/RobotCarPinDefinitionsAndMore.h +++ b/examples/MecanumWheelCar/RobotCarPinDefinitionsAndMore.h @@ -235,20 +235,7 @@ # if !defined(LED_BUILTIN) && !defined(CAR_IS_ESP32_CAM_BASED) #define LED_BUILTIN PB1 # endif -#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. -void tone(uint8_t _pin, unsigned int frequency){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); -} -void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); - delay(duration); - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} -void noTone(uint8_t _pin){ - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} + #else // NANO_BASED // Uno based // Pin A0 for VCC monitoring - ADC channel 2 diff --git a/examples/MecanumWheelCar/RobotCarUtils.hpp b/examples/MecanumWheelCar/RobotCarUtils.hpp index 08c4a79..bc5140d 100644 --- a/examples/MecanumWheelCar/RobotCarUtils.hpp +++ b/examples/MecanumWheelCar/RobotCarUtils.hpp @@ -87,9 +87,9 @@ bool doCalibration = false; # endif #include "ADCUtils.hpp" uint16_t sLastVINRawSum; // Sum of NUMBER_OF_VIN_SAMPLES raw readings of ADC, used to determine if voltage has changed and must be displayed. -float sVINVoltage = FULL_BRIDGE_INPUT_MILLIVOLT / 1000; // set default value for later use uint32_t sMillisOfLastVCCInfo; #endif // defined(VIN_ATTENUATED_INPUT_PIN) +float sVINVoltage = FULL_BRIDGE_INPUT_MILLIVOLT / 1000; // Set default value for later use. Is used a parameter for getVoltageAdjustedSpeedPWM //uint32_t sMillisOfLastAttention = 0; // millis() of last doAttention() or doWave() @@ -227,7 +227,7 @@ bool readVINVoltage() { * Here VIN is the only channel we convert. * Get 10 samples lasting 1030 us, which is almost the PWM period of 1024 us. */ - uint16_t tVINRawSum = readADCChannelWithReferenceMultiSamples(VIN_ATTENUATED_INPUT_CHANNEL, INTERNAL, NUMBER_OF_VIN_SAMPLES); // 10 samples + uint16_t tVINRawSum = readADCChannelMultiSamplesWithReference(VIN_ATTENUATED_INPUT_CHANNEL, INTERNAL, NUMBER_OF_VIN_SAMPLES); // 10 samples #if defined(CAR_HAS_IR_DISTANCE_SENSOR) checkAndWaitForReferenceAndChannelToSwitch(tOldADMUX & MASK_FOR_ADC_CHANNELS, tOldADMUX >> SHIFT_VALUE_FOR_REFERENCE); #endif diff --git a/examples/PrintCarValuesWithIMU/ADCUtils.h b/examples/PrintCarValuesWithIMU/ADCUtils.h index 6e0b51f..c406217 100644 --- a/examples/PrintCarValuesWithIMU/ADCUtils.h +++ b/examples/PrintCarValuesWithIMU/ADCUtils.h @@ -85,6 +85,7 @@ #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 @@ -92,20 +93,31 @@ #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 @@ -164,7 +176,10 @@ uint16_t waitAndReadADCChannelWithReferenceAndRestoreADMUXAndReference(uint8_t a 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); -uint16_t readADCChannelWithReferenceMultiSamples(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples); +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, @@ -199,7 +214,8 @@ void resetCounterForVCCUndervoltageMultipleTimes(); bool isVCCUndervoltage(); bool isVCCEmergencyUndervoltage(); bool isVCCOvervoltage(); -bool isVCCOvervoltageSimple(); +bool isVCCOvervoltageSimple(); // Version using readVCCVoltageMillivoltSimple() +bool isVCCTooHighSimple(); // Version not using readVCCVoltageMillivoltSimple() #endif // defined(__AVR__) ... diff --git a/examples/PrintCarValuesWithIMU/ADCUtils.hpp b/examples/PrintCarValuesWithIMU/ADCUtils.hpp index c3abd92..73030b4 100644 --- a/examples/PrintCarValuesWithIMU/ADCUtils.hpp +++ b/examples/PrintCarValuesWithIMU/ADCUtils.hpp @@ -161,12 +161,15 @@ uint8_t checkAndWaitForReferenceAndChannelToSwitch(uint8_t aADCChannelNumber, ui 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 & 0x0F) != aADCChannelNumber) { + } 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 @@ -249,9 +252,10 @@ uint16_t readADCChannelWithReferenceOversampleFast(uint8_t aADCChannelNumber, ui /* * Returns sum of all sample values - * Conversion time is defined as 0.104 milliseconds for 16 MHz Arduino by ADC_PRESCALE in ADCUtils.h. + * 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 readADCChannelWithReferenceMultiSamples(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples) { +uint16_t readADCChannelMultiSamplesWithReference(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples) { uint16_t tSumValue = 0; ADMUX = aADCChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE); @@ -275,6 +279,65 @@ uint16_t readADCChannelWithReferenceMultiSamples(uint8_t aADCChannelNumber, uint 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. @@ -408,7 +471,7 @@ uint16_t readUntil4ConsecutiveValuesAreEqual(uint8_t aADCChannelNumber, uint8_t */ float getVCCVoltageSimple(void) { // use AVCC with (optional) external capacitor at AREF pin as reference - float tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + float tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); return ((1023 * 1.1 * 4) / tVCC); } @@ -419,7 +482,7 @@ float getVCCVoltageSimple(void) { */ uint16_t getVCCVoltageMillivoltSimple(void) { // use AVCC with external capacitor at AREF pin as reference - uint16_t tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + uint16_t tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); return ((1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCC); } @@ -459,6 +522,9 @@ uint16_t getVCCVoltageMillivolt(void) { return ((1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT) / tVCC); } +/* + * Does not set sVCCVoltageMillivolt + */ uint16_t printVCCVoltageMillivolt(Print *aSerial) { aSerial->print(F("VCC=")); uint16_t tVCCVoltageMillivolt = getVCCVoltageMillivolt(); @@ -480,7 +546,7 @@ void readAndPrintVCCVoltageMillivolt(Print *aSerial) { */ void readVCCVoltageSimple(void) { // use AVCC with (optional) external capacitor at AREF pin as reference - float tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + float tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); sVCCVoltage = (1023 * (((float) ADC_INTERNAL_REFERENCE_MILLIVOLT) / 1000) * 4) / tVCC; } @@ -491,7 +557,7 @@ void readVCCVoltageSimple(void) { */ void readVCCVoltageMillivoltSimple(void) { // use AVCC with external capacitor at AREF pin as reference - uint16_t tVCCVoltageMillivoltRaw = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + uint16_t tVCCVoltageMillivoltRaw = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); sVCCVoltageMillivolt = (1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCCVoltageMillivoltRaw; } @@ -556,7 +622,7 @@ bool isVCCUSBPowered(Print *aSerial) { aSerial->print(F("USB powered is ")); bool tReturnValue; if (VOLTAGE_USB_POWERED_LOWER_THRESHOLD_MILLIVOLT - < sVCCVoltageMillivolt && sVCCVoltageMillivolt < VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT) { + < sVCCVoltageMillivolt&& sVCCVoltageMillivolt < VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT) { tReturnValue = true; aSerial->print(F("true ")); } else { @@ -649,6 +715,7 @@ void resetCounterForVCCUndervoltageMultipleTimes() { * 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() { @@ -660,6 +727,21 @@ bool isVCCOvervoltageSimple() { 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! @@ -671,18 +753,21 @@ float getCPUTemperatureSimple(void) { return 0.0; #else // use internal 1.1 volt as reference. 4 times oversample. Assume the signal has noise, but never verified :-( - uint16_t tTempRaw = readADCChannelWithReferenceOversample(ADC_TEMPERATURE_CHANNEL_MUX, INTERNAL, 2); + uint16_t tTemperatureRaw = readADCChannelWithReferenceOversample(ADC_TEMPERATURE_CHANNEL_MUX, INTERNAL, 2); #if defined(LOCAL_DEBUG) Serial.print(F("TempRaw=")); - Serial.println(tTempRaw); + Serial.println(tTemperatureRaw); #endif #if defined(__AVR_ATmega328PB__) - tTempRaw -= 245; - return (float)tTempRaw; + 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 - tTempRaw -= 317; - return (float) tTempRaw / 1.22; + tTemperatureRaw -= 317; + return (float) tTemperatureRaw / 1.22; #endif #endif } @@ -704,7 +789,7 @@ float getCPUTemperature(void) { } #else // defined(ADC_UTILS_ARE_AVAILABLE) -// Dummy definition of functions defined in ADCUtils to compile examples without errors +// Dummy definition of functions defined in ADCUtils to compile examples for non AVR platforms without errors /* * Persistent storage for VCC value */ diff --git a/examples/PrintCarValuesWithIMU/PrintCarValuesWithIMU.ino b/examples/PrintCarValuesWithIMU/PrintCarValuesWithIMU.ino index 2af49b9..1bbee19 100644 --- a/examples/PrintCarValuesWithIMU/PrintCarValuesWithIMU.ino +++ b/examples/PrintCarValuesWithIMU/PrintCarValuesWithIMU.ino @@ -71,7 +71,8 @@ void setup() { Serial.begin(115200); -#if defined(__AVR_ATmega32U4__) || defined(SERIAL_PORT_USBVIRTUAL) || defined(SERIAL_USB) /*stm32duino*/|| defined(USBCON) /*STM32_stm32*/|| defined(SERIALUSB_PID) || defined(ARDUINO_attiny3217) +#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 diff --git a/examples/PrintCarValuesWithIMU/RobotCarPinDefinitionsAndMore.h b/examples/PrintCarValuesWithIMU/RobotCarPinDefinitionsAndMore.h index d77f5c9..6738a58 100644 --- a/examples/PrintCarValuesWithIMU/RobotCarPinDefinitionsAndMore.h +++ b/examples/PrintCarValuesWithIMU/RobotCarPinDefinitionsAndMore.h @@ -235,20 +235,7 @@ # if !defined(LED_BUILTIN) && !defined(CAR_IS_ESP32_CAM_BASED) #define LED_BUILTIN PB1 # endif -#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. -void tone(uint8_t _pin, unsigned int frequency){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); -} -void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); - delay(duration); - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} -void noTone(uint8_t _pin){ - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} + #else // NANO_BASED // Uno based // Pin A0 for VCC monitoring - ADC channel 2 diff --git a/examples/PrintMotorDiagram/PrintMotorDiagram.ino b/examples/PrintMotorDiagram/PrintMotorDiagram.ino index 02cfcb8..2f9aef2 100644 --- a/examples/PrintMotorDiagram/PrintMotorDiagram.ino +++ b/examples/PrintMotorDiagram/PrintMotorDiagram.ino @@ -61,7 +61,8 @@ void setup() { Serial.begin(115200); -#if defined(__AVR_ATmega32U4__) || defined(SERIAL_PORT_USBVIRTUAL) || defined(SERIAL_USB) /*stm32duino*/|| defined(USBCON) /*STM32_stm32*/|| defined(SERIALUSB_PID) || defined(ARDUINO_attiny3217) +#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 #if defined(ENABLE_EXTRA_NON_PLOTTER_OUTPUT) diff --git a/examples/PrintMotorDiagram/RobotCarPinDefinitionsAndMore.h b/examples/PrintMotorDiagram/RobotCarPinDefinitionsAndMore.h index d77f5c9..6738a58 100644 --- a/examples/PrintMotorDiagram/RobotCarPinDefinitionsAndMore.h +++ b/examples/PrintMotorDiagram/RobotCarPinDefinitionsAndMore.h @@ -235,20 +235,7 @@ # if !defined(LED_BUILTIN) && !defined(CAR_IS_ESP32_CAM_BASED) #define LED_BUILTIN PB1 # endif -#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. -void tone(uint8_t _pin, unsigned int frequency){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); -} -void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); - delay(duration); - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} -void noTone(uint8_t _pin){ - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} + #else // NANO_BASED // Uno based // Pin A0 for VCC monitoring - ADC channel 2 diff --git a/examples/RobotCarBasic/HCSR04.hpp b/examples/RobotCarBasic/HCSR04.hpp index b700511..5317f08 100644 --- a/examples/RobotCarBasic/HCSR04.hpp +++ b/examples/RobotCarBasic/HCSR04.hpp @@ -70,7 +70,15 @@ //#define USE_PIN_CHANGE_INTERRUPT_D0_TO_D7 // using PCINT2_vect - PORT D //#define USE_PIN_CHANGE_INTERRUPT_D8_TO_D13 // using PCINT0_vect - PORT B - Pin 13 is feedback output //#define USE_PIN_CHANGE_INTERRUPT_A0_TO_A5 // using PCINT1_vect - PORT C +#if __has_include("digitalWriteFast.h") #include "digitalWriteFast.h" +#else +#define pinModeFast pinMode +#define digitalReadFast digitalRead +#define digitalWriteFast digitalWrite +#define digitalToggleFast(P) digitalWrite(P, ! digitalRead(P)) +#endif + #include "HCSR04.h" //#define DEBUG @@ -132,6 +140,7 @@ void initUSDistancePin(uint8_t aTriggerOutEchoInPin) { #if !defined (TRIGGER_OUT_PIN) sTriggerOutPin = aTriggerOutEchoInPin; #endif + (void) aTriggerOutEchoInPin; sHCSR04Mode = HCSR04_MODE_USE_1_PIN; } diff --git a/examples/RobotCarBasic/RobotCarPinDefinitionsAndMore.h b/examples/RobotCarBasic/RobotCarPinDefinitionsAndMore.h index d77f5c9..6738a58 100644 --- a/examples/RobotCarBasic/RobotCarPinDefinitionsAndMore.h +++ b/examples/RobotCarBasic/RobotCarPinDefinitionsAndMore.h @@ -235,20 +235,7 @@ # if !defined(LED_BUILTIN) && !defined(CAR_IS_ESP32_CAM_BASED) #define LED_BUILTIN PB1 # endif -#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. -void tone(uint8_t _pin, unsigned int frequency){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); -} -void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); - delay(duration); - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} -void noTone(uint8_t _pin){ - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} + #else // NANO_BASED // Uno based // Pin A0 for VCC monitoring - ADC channel 2 diff --git a/examples/RobotCarBasic/RobotCarUtils.hpp b/examples/RobotCarBasic/RobotCarUtils.hpp index 08c4a79..bc5140d 100644 --- a/examples/RobotCarBasic/RobotCarUtils.hpp +++ b/examples/RobotCarBasic/RobotCarUtils.hpp @@ -87,9 +87,9 @@ bool doCalibration = false; # endif #include "ADCUtils.hpp" uint16_t sLastVINRawSum; // Sum of NUMBER_OF_VIN_SAMPLES raw readings of ADC, used to determine if voltage has changed and must be displayed. -float sVINVoltage = FULL_BRIDGE_INPUT_MILLIVOLT / 1000; // set default value for later use uint32_t sMillisOfLastVCCInfo; #endif // defined(VIN_ATTENUATED_INPUT_PIN) +float sVINVoltage = FULL_BRIDGE_INPUT_MILLIVOLT / 1000; // Set default value for later use. Is used a parameter for getVoltageAdjustedSpeedPWM //uint32_t sMillisOfLastAttention = 0; // millis() of last doAttention() or doWave() @@ -227,7 +227,7 @@ bool readVINVoltage() { * Here VIN is the only channel we convert. * Get 10 samples lasting 1030 us, which is almost the PWM period of 1024 us. */ - uint16_t tVINRawSum = readADCChannelWithReferenceMultiSamples(VIN_ATTENUATED_INPUT_CHANNEL, INTERNAL, NUMBER_OF_VIN_SAMPLES); // 10 samples + uint16_t tVINRawSum = readADCChannelMultiSamplesWithReference(VIN_ATTENUATED_INPUT_CHANNEL, INTERNAL, NUMBER_OF_VIN_SAMPLES); // 10 samples #if defined(CAR_HAS_IR_DISTANCE_SENSOR) checkAndWaitForReferenceAndChannelToSwitch(tOldADMUX & MASK_FOR_ADC_CHANNELS, tOldADMUX >> SHIFT_VALUE_FOR_REFERENCE); #endif diff --git a/examples/RobotCarBlueDisplay/HCSR04.hpp b/examples/RobotCarBlueDisplay/HCSR04.hpp index b700511..5317f08 100644 --- a/examples/RobotCarBlueDisplay/HCSR04.hpp +++ b/examples/RobotCarBlueDisplay/HCSR04.hpp @@ -70,7 +70,15 @@ //#define USE_PIN_CHANGE_INTERRUPT_D0_TO_D7 // using PCINT2_vect - PORT D //#define USE_PIN_CHANGE_INTERRUPT_D8_TO_D13 // using PCINT0_vect - PORT B - Pin 13 is feedback output //#define USE_PIN_CHANGE_INTERRUPT_A0_TO_A5 // using PCINT1_vect - PORT C +#if __has_include("digitalWriteFast.h") #include "digitalWriteFast.h" +#else +#define pinModeFast pinMode +#define digitalReadFast digitalRead +#define digitalWriteFast digitalWrite +#define digitalToggleFast(P) digitalWrite(P, ! digitalRead(P)) +#endif + #include "HCSR04.h" //#define DEBUG @@ -132,6 +140,7 @@ void initUSDistancePin(uint8_t aTriggerOutEchoInPin) { #if !defined (TRIGGER_OUT_PIN) sTriggerOutPin = aTriggerOutEchoInPin; #endif + (void) aTriggerOutEchoInPin; sHCSR04Mode = HCSR04_MODE_USE_1_PIN; } diff --git a/examples/RobotCarBlueDisplay/LightweightServo.hpp b/examples/RobotCarBlueDisplay/LightweightServo.hpp index 09d13c1..0da2967 100644 --- a/examples/RobotCarBlueDisplay/LightweightServo.hpp +++ b/examples/RobotCarBlueDisplay/LightweightServo.hpp @@ -118,9 +118,9 @@ void deinitLightweightServoPin9_10(bool aUsePin9, bool aUsePin10) { } /* - * If value is below 180 then assume degree, otherwise assume microseconds - * If aUpdateFast then enable starting a new output pulse if more than 5 ms since last one, some servo might react faster in this mode. - * If aUsePin9 is false, then Pin10 is used + * @param aDegree - If value is below 180 then assume degree, otherwise assume microseconds + * @param aUpdateFast - If true, enable starting a new output pulse if more than 5 ms since last one, some servo might react faster in this mode. + * @param aUsePin9 - If false, then Pin10 is used * 236 / 186(without auto init) bytes code size */ int writeLightweightServo(int aDegree, bool aUsePin9, bool aUpdateFast) { diff --git a/examples/RobotCarBlueDisplay/RobotCarBlueDisplay.ino b/examples/RobotCarBlueDisplay/RobotCarBlueDisplay.ino index 0254403..4352742 100644 --- a/examples/RobotCarBlueDisplay/RobotCarBlueDisplay.ino +++ b/examples/RobotCarBlueDisplay/RobotCarBlueDisplay.ino @@ -264,7 +264,8 @@ void setup() { } else { #if defined(ENABLE_SERIAL_OUTPUT) // requires 1504 bytes program space # if !defined(USE_SIMPLE_SERIAL) && !defined(USE_SERIAL1) // print it now if not printed above -# if defined(__AVR_ATmega32U4__) || defined(SERIAL_PORT_USBVIRTUAL) || defined(SERIAL_USB) /*stm32duino*/|| defined(USBCON) /*STM32_stm32*/|| defined(SERIALUSB_PID) || defined(ARDUINO_attiny3217) +# 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 diff --git a/examples/RobotCarBlueDisplay/RobotCarPinDefinitionsAndMore.h b/examples/RobotCarBlueDisplay/RobotCarPinDefinitionsAndMore.h index d77f5c9..6738a58 100644 --- a/examples/RobotCarBlueDisplay/RobotCarPinDefinitionsAndMore.h +++ b/examples/RobotCarBlueDisplay/RobotCarPinDefinitionsAndMore.h @@ -235,20 +235,7 @@ # if !defined(LED_BUILTIN) && !defined(CAR_IS_ESP32_CAM_BASED) #define LED_BUILTIN PB1 # endif -#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. -void tone(uint8_t _pin, unsigned int frequency){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); -} -void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); - delay(duration); - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} -void noTone(uint8_t _pin){ - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} + #else // NANO_BASED // Uno based // Pin A0 for VCC monitoring - ADC channel 2 diff --git a/examples/RobotCarBlueDisplay/RobotCarUtils.hpp b/examples/RobotCarBlueDisplay/RobotCarUtils.hpp index 08c4a79..bc5140d 100644 --- a/examples/RobotCarBlueDisplay/RobotCarUtils.hpp +++ b/examples/RobotCarBlueDisplay/RobotCarUtils.hpp @@ -87,9 +87,9 @@ bool doCalibration = false; # endif #include "ADCUtils.hpp" uint16_t sLastVINRawSum; // Sum of NUMBER_OF_VIN_SAMPLES raw readings of ADC, used to determine if voltage has changed and must be displayed. -float sVINVoltage = FULL_BRIDGE_INPUT_MILLIVOLT / 1000; // set default value for later use uint32_t sMillisOfLastVCCInfo; #endif // defined(VIN_ATTENUATED_INPUT_PIN) +float sVINVoltage = FULL_BRIDGE_INPUT_MILLIVOLT / 1000; // Set default value for later use. Is used a parameter for getVoltageAdjustedSpeedPWM //uint32_t sMillisOfLastAttention = 0; // millis() of last doAttention() or doWave() @@ -227,7 +227,7 @@ bool readVINVoltage() { * Here VIN is the only channel we convert. * Get 10 samples lasting 1030 us, which is almost the PWM period of 1024 us. */ - uint16_t tVINRawSum = readADCChannelWithReferenceMultiSamples(VIN_ATTENUATED_INPUT_CHANNEL, INTERNAL, NUMBER_OF_VIN_SAMPLES); // 10 samples + uint16_t tVINRawSum = readADCChannelMultiSamplesWithReference(VIN_ATTENUATED_INPUT_CHANNEL, INTERNAL, NUMBER_OF_VIN_SAMPLES); // 10 samples #if defined(CAR_HAS_IR_DISTANCE_SENSOR) checkAndWaitForReferenceAndChannelToSwitch(tOldADMUX & MASK_FOR_ADC_CHANNELS, tOldADMUX >> SHIFT_VALUE_FOR_REFERENCE); #endif diff --git a/examples/SmartCarFollower/ADCUtils.h b/examples/SmartCarFollower/ADCUtils.h index 6e0b51f..c406217 100644 --- a/examples/SmartCarFollower/ADCUtils.h +++ b/examples/SmartCarFollower/ADCUtils.h @@ -85,6 +85,7 @@ #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 @@ -92,20 +93,31 @@ #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 @@ -164,7 +176,10 @@ uint16_t waitAndReadADCChannelWithReferenceAndRestoreADMUXAndReference(uint8_t a 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); -uint16_t readADCChannelWithReferenceMultiSamples(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples); +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, @@ -199,7 +214,8 @@ void resetCounterForVCCUndervoltageMultipleTimes(); bool isVCCUndervoltage(); bool isVCCEmergencyUndervoltage(); bool isVCCOvervoltage(); -bool isVCCOvervoltageSimple(); +bool isVCCOvervoltageSimple(); // Version using readVCCVoltageMillivoltSimple() +bool isVCCTooHighSimple(); // Version not using readVCCVoltageMillivoltSimple() #endif // defined(__AVR__) ... diff --git a/examples/SmartCarFollower/ADCUtils.hpp b/examples/SmartCarFollower/ADCUtils.hpp index c3abd92..73030b4 100644 --- a/examples/SmartCarFollower/ADCUtils.hpp +++ b/examples/SmartCarFollower/ADCUtils.hpp @@ -161,12 +161,15 @@ uint8_t checkAndWaitForReferenceAndChannelToSwitch(uint8_t aADCChannelNumber, ui 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 & 0x0F) != aADCChannelNumber) { + } 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 @@ -249,9 +252,10 @@ uint16_t readADCChannelWithReferenceOversampleFast(uint8_t aADCChannelNumber, ui /* * Returns sum of all sample values - * Conversion time is defined as 0.104 milliseconds for 16 MHz Arduino by ADC_PRESCALE in ADCUtils.h. + * 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 readADCChannelWithReferenceMultiSamples(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples) { +uint16_t readADCChannelMultiSamplesWithReference(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples) { uint16_t tSumValue = 0; ADMUX = aADCChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE); @@ -275,6 +279,65 @@ uint16_t readADCChannelWithReferenceMultiSamples(uint8_t aADCChannelNumber, uint 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. @@ -408,7 +471,7 @@ uint16_t readUntil4ConsecutiveValuesAreEqual(uint8_t aADCChannelNumber, uint8_t */ float getVCCVoltageSimple(void) { // use AVCC with (optional) external capacitor at AREF pin as reference - float tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + float tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); return ((1023 * 1.1 * 4) / tVCC); } @@ -419,7 +482,7 @@ float getVCCVoltageSimple(void) { */ uint16_t getVCCVoltageMillivoltSimple(void) { // use AVCC with external capacitor at AREF pin as reference - uint16_t tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + uint16_t tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); return ((1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCC); } @@ -459,6 +522,9 @@ uint16_t getVCCVoltageMillivolt(void) { return ((1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT) / tVCC); } +/* + * Does not set sVCCVoltageMillivolt + */ uint16_t printVCCVoltageMillivolt(Print *aSerial) { aSerial->print(F("VCC=")); uint16_t tVCCVoltageMillivolt = getVCCVoltageMillivolt(); @@ -480,7 +546,7 @@ void readAndPrintVCCVoltageMillivolt(Print *aSerial) { */ void readVCCVoltageSimple(void) { // use AVCC with (optional) external capacitor at AREF pin as reference - float tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + float tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); sVCCVoltage = (1023 * (((float) ADC_INTERNAL_REFERENCE_MILLIVOLT) / 1000) * 4) / tVCC; } @@ -491,7 +557,7 @@ void readVCCVoltageSimple(void) { */ void readVCCVoltageMillivoltSimple(void) { // use AVCC with external capacitor at AREF pin as reference - uint16_t tVCCVoltageMillivoltRaw = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + uint16_t tVCCVoltageMillivoltRaw = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); sVCCVoltageMillivolt = (1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCCVoltageMillivoltRaw; } @@ -556,7 +622,7 @@ bool isVCCUSBPowered(Print *aSerial) { aSerial->print(F("USB powered is ")); bool tReturnValue; if (VOLTAGE_USB_POWERED_LOWER_THRESHOLD_MILLIVOLT - < sVCCVoltageMillivolt && sVCCVoltageMillivolt < VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT) { + < sVCCVoltageMillivolt&& sVCCVoltageMillivolt < VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT) { tReturnValue = true; aSerial->print(F("true ")); } else { @@ -649,6 +715,7 @@ void resetCounterForVCCUndervoltageMultipleTimes() { * 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() { @@ -660,6 +727,21 @@ bool isVCCOvervoltageSimple() { 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! @@ -671,18 +753,21 @@ float getCPUTemperatureSimple(void) { return 0.0; #else // use internal 1.1 volt as reference. 4 times oversample. Assume the signal has noise, but never verified :-( - uint16_t tTempRaw = readADCChannelWithReferenceOversample(ADC_TEMPERATURE_CHANNEL_MUX, INTERNAL, 2); + uint16_t tTemperatureRaw = readADCChannelWithReferenceOversample(ADC_TEMPERATURE_CHANNEL_MUX, INTERNAL, 2); #if defined(LOCAL_DEBUG) Serial.print(F("TempRaw=")); - Serial.println(tTempRaw); + Serial.println(tTemperatureRaw); #endif #if defined(__AVR_ATmega328PB__) - tTempRaw -= 245; - return (float)tTempRaw; + 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 - tTempRaw -= 317; - return (float) tTempRaw / 1.22; + tTemperatureRaw -= 317; + return (float) tTemperatureRaw / 1.22; #endif #endif } @@ -704,7 +789,7 @@ float getCPUTemperature(void) { } #else // defined(ADC_UTILS_ARE_AVAILABLE) -// Dummy definition of functions defined in ADCUtils to compile examples without errors +// Dummy definition of functions defined in ADCUtils to compile examples for non AVR platforms without errors /* * Persistent storage for VCC value */ diff --git a/examples/SmartCarFollower/HCSR04.hpp b/examples/SmartCarFollower/HCSR04.hpp index b700511..5317f08 100644 --- a/examples/SmartCarFollower/HCSR04.hpp +++ b/examples/SmartCarFollower/HCSR04.hpp @@ -70,7 +70,15 @@ //#define USE_PIN_CHANGE_INTERRUPT_D0_TO_D7 // using PCINT2_vect - PORT D //#define USE_PIN_CHANGE_INTERRUPT_D8_TO_D13 // using PCINT0_vect - PORT B - Pin 13 is feedback output //#define USE_PIN_CHANGE_INTERRUPT_A0_TO_A5 // using PCINT1_vect - PORT C +#if __has_include("digitalWriteFast.h") #include "digitalWriteFast.h" +#else +#define pinModeFast pinMode +#define digitalReadFast digitalRead +#define digitalWriteFast digitalWrite +#define digitalToggleFast(P) digitalWrite(P, ! digitalRead(P)) +#endif + #include "HCSR04.h" //#define DEBUG @@ -132,6 +140,7 @@ void initUSDistancePin(uint8_t aTriggerOutEchoInPin) { #if !defined (TRIGGER_OUT_PIN) sTriggerOutPin = aTriggerOutEchoInPin; #endif + (void) aTriggerOutEchoInPin; sHCSR04Mode = HCSR04_MODE_USE_1_PIN; } diff --git a/examples/SmartCarFollower/LongUnion.h b/examples/SmartCarFollower/LongUnion.h index 3559ac2..8f90f61 100644 --- a/examples/SmartCarFollower/LongUnion.h +++ b/examples/SmartCarFollower/LongUnion.h @@ -87,7 +87,7 @@ union LongUnion { struct { WordUnion LowWord; WordUnion HighWord; - } WordUnion; + } TwoWordUnions; uint8_t UBytes[4]; // seems to have the same code size as using struct UByte int8_t Bytes[4]; // Bytes[0] is LowByte uint16_t UWords[2]; @@ -122,7 +122,7 @@ union LongLongUnion { WordUnion MidLowWord; WordUnion MidHighWord; WordUnion HighWord; - } WordUnion; + } FourWordUnions; struct { uint32_t LowLong; uint32_t HighLong; @@ -134,7 +134,7 @@ union LongLongUnion { struct { LongUnion LowLong; LongUnion HighLong; - } LongUnion; + } TwoLongUnions; uint8_t UBytes[8]; // seems to have the same code size as using struct UByte int8_t Bytes[8]; uint16_t UWords[4]; diff --git a/examples/SmartCarFollower/RobotCarPinDefinitionsAndMore.h b/examples/SmartCarFollower/RobotCarPinDefinitionsAndMore.h index d77f5c9..6738a58 100644 --- a/examples/SmartCarFollower/RobotCarPinDefinitionsAndMore.h +++ b/examples/SmartCarFollower/RobotCarPinDefinitionsAndMore.h @@ -235,20 +235,7 @@ # if !defined(LED_BUILTIN) && !defined(CAR_IS_ESP32_CAM_BASED) #define LED_BUILTIN PB1 # endif -#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. -void tone(uint8_t _pin, unsigned int frequency){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); -} -void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); - delay(duration); - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} -void noTone(uint8_t _pin){ - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} + #else // NANO_BASED // Uno based // Pin A0 for VCC monitoring - ADC channel 2 diff --git a/examples/SmartCarFollower/RobotCarUtils.hpp b/examples/SmartCarFollower/RobotCarUtils.hpp index 08c4a79..bc5140d 100644 --- a/examples/SmartCarFollower/RobotCarUtils.hpp +++ b/examples/SmartCarFollower/RobotCarUtils.hpp @@ -87,9 +87,9 @@ bool doCalibration = false; # endif #include "ADCUtils.hpp" uint16_t sLastVINRawSum; // Sum of NUMBER_OF_VIN_SAMPLES raw readings of ADC, used to determine if voltage has changed and must be displayed. -float sVINVoltage = FULL_BRIDGE_INPUT_MILLIVOLT / 1000; // set default value for later use uint32_t sMillisOfLastVCCInfo; #endif // defined(VIN_ATTENUATED_INPUT_PIN) +float sVINVoltage = FULL_BRIDGE_INPUT_MILLIVOLT / 1000; // Set default value for later use. Is used a parameter for getVoltageAdjustedSpeedPWM //uint32_t sMillisOfLastAttention = 0; // millis() of last doAttention() or doWave() @@ -227,7 +227,7 @@ bool readVINVoltage() { * Here VIN is the only channel we convert. * Get 10 samples lasting 1030 us, which is almost the PWM period of 1024 us. */ - uint16_t tVINRawSum = readADCChannelWithReferenceMultiSamples(VIN_ATTENUATED_INPUT_CHANNEL, INTERNAL, NUMBER_OF_VIN_SAMPLES); // 10 samples + uint16_t tVINRawSum = readADCChannelMultiSamplesWithReference(VIN_ATTENUATED_INPUT_CHANNEL, INTERNAL, NUMBER_OF_VIN_SAMPLES); // 10 samples #if defined(CAR_HAS_IR_DISTANCE_SENSOR) checkAndWaitForReferenceAndChannelToSwitch(tOldADMUX & MASK_FOR_ADC_CHANNELS, tOldADMUX >> SHIFT_VALUE_FOR_REFERENCE); #endif diff --git a/examples/SmartCarFollower/SmartCarFollower.ino b/examples/SmartCarFollower/SmartCarFollower.ino index 25c1cbf..e084374 100644 --- a/examples/SmartCarFollower/SmartCarFollower.ino +++ b/examples/SmartCarFollower/SmartCarFollower.ino @@ -208,15 +208,17 @@ void setup() { /* * Detect USB connection and signal end of boot */ -#if defined(VIN_ATTENUATED_INPUT_PIN) +#if !defined(ESP32) +# if defined(VIN_ATTENUATED_INPUT_PIN) sVINProvided = isVINProvided(); Serial.println(); -#else +# else sVINProvided = !isVCCUSBPowered(&Serial); -#endif +# endif signalUSBPowered(!sVINProvided, false); +#endif -# if defined(US_DISTANCE_SENSOR_ENABLE_PIN) && (defined(CAR_HAS_IR_DISTANCE_SENSOR) || defined(CAR_HAS_TOF_DISTANCE_SENSOR)) +#if defined(US_DISTANCE_SENSOR_ENABLE_PIN) && (defined(CAR_HAS_IR_DISTANCE_SENSOR) || defined(CAR_HAS_TOF_DISTANCE_SENSOR)) // If this pin is connected to ground, use the US distance sensor instead of the IR distance sensor pinMode(US_DISTANCE_SENSOR_ENABLE_PIN, INPUT_PULLUP); #endif @@ -314,9 +316,11 @@ void loop() { } } +#if defined(VIN_ATTENUATED_INPUT_PIN) if (sVINProvided) { checkVinPeriodicallyAndPrintIfChanged(); // checks internally for sVINProvided } +#endif delay(20); // Delay, to avoid receiving the US echo of last distance scan. 20 ms delay corresponds to an US echo from 3.43 m. } diff --git a/examples/SmartCarFollower/TinyIR.h b/examples/SmartCarFollower/TinyIR.h index f8fe638..c01a67a 100644 --- a/examples/SmartCarFollower/TinyIR.h +++ b/examples/SmartCarFollower/TinyIR.h @@ -34,9 +34,9 @@ * @{ */ -#define VERSION_TINYIR "2.0.0" +#define VERSION_TINYIR "2.2.0" #define VERSION_TINYIR_MAJOR 2 -#define VERSION_TINYIR_MINOR 0 +#define VERSION_TINYIR_MINOR 2 #define VERSION_TINYIR_PATCH 0 // The change log is at the bottom of the file @@ -134,6 +134,8 @@ #define TINY_RECEIVER_ADDRESS_BITS NEC_ADDRESS_BITS // the address bits + parity # if defined(USE_ONKYO_PROTOCOL) #define TINY_RECEIVER_ADDRESS_HAS_8_BIT_PARITY false // 16 bit address without parity +# elif defined(USE_EXTENDED_NEC_PROTOCOL) +#define TINY_RECEIVER_ADDRESS_HAS_8_BIT_PARITY false // 16 bit address without parity # else #define TINY_RECEIVER_ADDRESS_HAS_8_BIT_PARITY true // 8 bit and 8 bit parity # endif @@ -241,7 +243,7 @@ struct TinyIRReceiverCallbackDataStruct { uint8_t Command; #endif uint8_t Flags; // Bit coded flags. Can contain one of the bits: IRDATA_FLAGS_IS_REPEAT and IRDATA_FLAGS_PARITY_FAILED - bool justWritten; ///< Is set true if new data is available. Used by the main loop, to avoid multiple evaluations of the same IR frame. + bool justWritten; ///< Is set true if new data is available. Used by the main loop / TinyReceiverDecode(), to avoid multiple evaluations of the same IR frame. }; extern volatile TinyIRReceiverCallbackDataStruct TinyIRReceiverData; @@ -250,16 +252,24 @@ bool initPCIInterruptForTinyReceiver(); bool enablePCIInterruptForTinyReceiver(); void disablePCIInterruptForTinyReceiver(); bool isTinyReceiverIdle(); +bool TinyReceiverDecode(); void printTinyReceiverResultMinimal(Print *aSerial); void sendFAST(uint8_t aSendPin, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0); void sendFast8BitAndParity(uint8_t aSendPin, uint8_t aCommand, uint_fast8_t aNumberOfRepeats = 0); -void sendONKYO(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0); // Send NEC with 16 bit command, even if aCommand < 0x100 +void sendONKYO(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0, bool aSendNEC2Repeats = false); // Send NEC with 16 bit command, even if aCommand < 0x100 void sendNECMinimal(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0) __attribute__ ((deprecated ("Renamed to sendNEC()."))); -void sendNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0); +void sendNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0, bool aSendNEC2Repeats = false); +void sendExtendedNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats = 0, bool aSendNEC2Repeats = false); /* + * Version 2.2.0 - 7/2024 + * - New TinyReceiverDecode() function to be used as drop in for IrReceiver.decode(). + * + * Version 2.1.0 - 2/2024 + * - New sendExtendedNEC() function and new parameter aSendNEC2Repeats. + * * Version 2.0.0 - 10/2023 * - New TinyIRReceiverData which is filled with address, command and flags. * - Removed parameters address, command and flags from callback handleReceivedTinyIRData() and printTinyReceiverResultMinimal(). diff --git a/examples/SmartCarFollower/TinyIRReceiver.hpp b/examples/SmartCarFollower/TinyIRReceiver.hpp index 4316db8..39b3414 100644 --- a/examples/SmartCarFollower/TinyIRReceiver.hpp +++ b/examples/SmartCarFollower/TinyIRReceiver.hpp @@ -28,7 +28,7 @@ ************************************************************************************ * MIT License * - * Copyright (c) 2022-2023 Armin Joachimsmeyer + * 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 @@ -58,6 +58,7 @@ * - IR_FEEDBACK_LED_PIN The pin number for TinyIRReceiver feedback LED. * - NO_LED_FEEDBACK_CODE Disables the feedback LED function. Saves 14 bytes program memory. * - DISABLE_PARITY_CHECKS Disable parity checks. Saves 48 bytes of program memory. + * - USE_EXTENDED_NEC_PROTOCOL Like NEC, but take the 16 bit address as one 16 bit value and not as 8 bit normal and 8 bit inverted value. * - USE_ONKYO_PROTOCOL Like NEC, but take the 16 bit address and command each as one 16 bit value and not as 8 bit normal and 8 bit inverted value. * - USE_FAST_PROTOCOL Use FAST protocol (no address and 16 bit data, interpreted as 8 bit command and 8 bit inverted command) instead of NEC. * - ENABLE_NEC2_REPEATS Instead of sending / receiving the NEC special repeat code, send / receive the original frame for repeat. @@ -75,11 +76,14 @@ //#define LOCAL_DEBUG // This enables debug output only for this file #endif +/* + * Protocol selection + */ //#define DISABLE_PARITY_CHECKS // Disable parity checks. Saves 48 bytes of program memory. +//#define USE_EXTENDED_NEC_PROTOCOL // Like NEC, but take the 16 bit address as one 16 bit value and not as 8 bit normal and 8 bit inverted value. //#define USE_ONKYO_PROTOCOL // Like NEC, but take the 16 bit address and command each as one 16 bit value and not as 8 bit normal and 8 bit inverted value. //#define USE_FAST_PROTOCOL // Use FAST protocol instead of NEC / ONKYO. //#define ENABLE_NEC2_REPEATS // Instead of sending / receiving the NEC special repeat code, send / receive the original frame for repeat. - #include "TinyIR.h" // If not defined, it defines IR_RECEIVE_PIN, IR_FEEDBACK_LED_PIN and TINY_RECEIVER_USE_ARDUINO_ATTACH_INTERRUPT #include "digitalWriteFast.h" @@ -379,7 +383,7 @@ void IRPinChangeInterruptHandler(void) { // Here we have 8 bit command TinyIRReceiverData.Command = TinyIRReceiverControl.IRRawData.UBytes[2]; # else - // Here we have 16 bit command + // Here we have 16 bit command TinyIRReceiverData.Command = TinyIRReceiverControl.IRRawData.UWord.HighWord; # endif @@ -421,6 +425,17 @@ bool isTinyReceiverIdle() { return (TinyIRReceiverControl.IRReceiverState == IR_RECEIVER_STATE_WAITING_FOR_START_MARK); } +/* + * Function to be used as drop in for IrReceiver.decode() + */ +bool TinyReceiverDecode() { + bool tJustWritten = TinyIRReceiverData.justWritten; + if (tJustWritten) { + TinyIRReceiverData.justWritten = false; + } + return tJustWritten; +} + /* * Checks if IR_RECEIVE_PIN is connected and high * @return true, if IR Receiver is attached diff --git a/examples/SmartCarFollower/TinyIRSender.hpp b/examples/SmartCarFollower/TinyIRSender.hpp index 03d0b93..65a1fe1 100644 --- a/examples/SmartCarFollower/TinyIRSender.hpp +++ b/examples/SmartCarFollower/TinyIRSender.hpp @@ -19,7 +19,7 @@ ************************************************************************************ * MIT License * - * Copyright (c) 2022-2023 Armin Joachimsmeyer + * 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 @@ -105,12 +105,13 @@ void sendMark(uint8_t aSendPin, unsigned int aMarkMicros) { } /* - * Send NEC with 16 bit command, even if aCommand < 0x100 + * Send NEC with 16 bit address and command, even if aCommand < 0x100 (I.E. ONKYO) * @param aAddress - The 16 bit address to send. * @param aCommand - The 16 bit command to send. * @param aNumberOfRepeats - Number of repeats send at a period of 110 ms. + * @param aSendNEC2Repeats - Instead of sending the NEC special repeat code, send the original frame for repeat. */ -void sendONKYO(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats) { +void sendONKYO(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats, bool aSendNEC2Repeats) { pinModeFast(aSendPin, OUTPUT); uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1; @@ -118,13 +119,10 @@ void sendONKYO(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast unsigned long tStartOfFrameMillis = millis(); sendMark(aSendPin, NEC_HEADER_MARK); -#if !defined(ENABLE_NEC2_REPEATS) - if (tNumberOfCommands < aNumberOfRepeats + 1) { + if ((!aSendNEC2Repeats) && (tNumberOfCommands < aNumberOfRepeats + 1)) { // send the NEC special repeat delayMicroseconds(NEC_REPEAT_HEADER_SPACE); // - 2250 - } else -#endif - { + } else { // send header delayMicroseconds(NEC_HEADER_SPACE); LongUnion tData; @@ -158,15 +156,16 @@ void sendONKYO(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast } /* - * Send NEC with 8 or 16 bit address or data depending on the values of aAddress and aCommand. + * Send NEC with 8 or 16 bit address or command depending on the values of aAddress and aCommand. * @param aAddress - If aAddress < 0x100 send 8 bit address and 8 bit inverted address, else send 16 bit address. * @param aCommand - If aCommand < 0x100 send 8 bit command and 8 bit inverted command, else send 16 bit command. * @param aNumberOfRepeats - Number of repeats send at a period of 110 ms. + * @param aSendNEC2Repeats - Instead of sending the NEC special repeat code, send the original frame for repeat. */ void sendNECMinimal(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats) { sendNEC(aSendPin, aAddress, aCommand, aNumberOfRepeats); // sendNECMinimal() is deprecated } -void sendNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats) { +void sendNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats, bool aSendNEC2Repeats) { pinModeFast(aSendPin, OUTPUT); uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1; @@ -174,13 +173,10 @@ void sendNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_ unsigned long tStartOfFrameMillis = millis(); sendMark(aSendPin, NEC_HEADER_MARK); -#if !defined(ENABLE_NEC2_REPEATS) - if (tNumberOfCommands < aNumberOfRepeats + 1) { + if ((!aSendNEC2Repeats) && (tNumberOfCommands < aNumberOfRepeats + 1)) { // send the NEC special repeat delayMicroseconds(NEC_REPEAT_HEADER_SPACE); // - 2250 - } else -#endif - { + } else { // send header delayMicroseconds(NEC_HEADER_SPACE); LongUnion tData; @@ -228,6 +224,63 @@ void sendNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_ } } +/* + * Send Extended NEC with a forced 16 bit address and 8 or 16 bit command depending on the value of aCommand. + * @param aAddress - Send 16 bit address. + * @param aCommand - If aCommand < 0x100 send 8 bit command and 8 bit inverted command, else send 16 bit command. + * @param aNumberOfRepeats - Number of repeats send at a period of 110 ms. + * @param aSendNEC2Repeats - Instead of sending the NEC special repeat code, send the original frame for repeat. + */ +void sendExtendedNEC(uint8_t aSendPin, uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats, bool aSendNEC2Repeats) { + pinModeFast(aSendPin, OUTPUT); + + uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1; + while (tNumberOfCommands > 0) { + unsigned long tStartOfFrameMillis = millis(); + + sendMark(aSendPin, NEC_HEADER_MARK); + if ((!aSendNEC2Repeats) && (tNumberOfCommands < aNumberOfRepeats + 1)) { + // send the NEC special repeat + delayMicroseconds(NEC_REPEAT_HEADER_SPACE); // - 2250 + } else { + // send header + delayMicroseconds(NEC_HEADER_SPACE); + LongUnion tData; + tData.UWord.LowWord = aAddress; + if (aCommand > 0xFF) { + tData.UWord.HighWord = aCommand; + } else { + tData.UByte.MidHighByte = aCommand; + tData.UByte.HighByte = ~aCommand; // LSB first + } + // Send data + for (uint_fast8_t i = 0; i < NEC_BITS; ++i) { + sendMark(aSendPin, NEC_BIT_MARK); // constant mark length + + if (tData.ULong & 1) { + delayMicroseconds(NEC_ONE_SPACE); + } else { + delayMicroseconds(NEC_ZERO_SPACE); + } + tData.ULong >>= 1; // shift command for next bit + } + } // send stop bit + sendMark(aSendPin, NEC_BIT_MARK); + + tNumberOfCommands--; + // skip last delay! + if (tNumberOfCommands > 0) { + /* + * Check and fallback for wrong RepeatPeriodMillis parameter. I.e the repeat period must be greater than each frame duration. + */ + auto tFrameDurationMillis = millis() - tStartOfFrameMillis; + if (NEC_REPEAT_PERIOD / 1000 > tFrameDurationMillis) { + delay(NEC_REPEAT_PERIOD / 1000 - tFrameDurationMillis); + } + } + } +} + /* * LSB first, send header, command, inverted command and stop bit */ diff --git a/examples/SmartCarFollowerSimple/ADCUtils.h b/examples/SmartCarFollowerSimple/ADCUtils.h index 6e0b51f..c406217 100644 --- a/examples/SmartCarFollowerSimple/ADCUtils.h +++ b/examples/SmartCarFollowerSimple/ADCUtils.h @@ -85,6 +85,7 @@ #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 @@ -92,20 +93,31 @@ #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 @@ -164,7 +176,10 @@ uint16_t waitAndReadADCChannelWithReferenceAndRestoreADMUXAndReference(uint8_t a 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); -uint16_t readADCChannelWithReferenceMultiSamples(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples); +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, @@ -199,7 +214,8 @@ void resetCounterForVCCUndervoltageMultipleTimes(); bool isVCCUndervoltage(); bool isVCCEmergencyUndervoltage(); bool isVCCOvervoltage(); -bool isVCCOvervoltageSimple(); +bool isVCCOvervoltageSimple(); // Version using readVCCVoltageMillivoltSimple() +bool isVCCTooHighSimple(); // Version not using readVCCVoltageMillivoltSimple() #endif // defined(__AVR__) ... diff --git a/examples/SmartCarFollowerSimple/ADCUtils.hpp b/examples/SmartCarFollowerSimple/ADCUtils.hpp index c3abd92..73030b4 100644 --- a/examples/SmartCarFollowerSimple/ADCUtils.hpp +++ b/examples/SmartCarFollowerSimple/ADCUtils.hpp @@ -161,12 +161,15 @@ uint8_t checkAndWaitForReferenceAndChannelToSwitch(uint8_t aADCChannelNumber, ui 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 & 0x0F) != aADCChannelNumber) { + } 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 @@ -249,9 +252,10 @@ uint16_t readADCChannelWithReferenceOversampleFast(uint8_t aADCChannelNumber, ui /* * Returns sum of all sample values - * Conversion time is defined as 0.104 milliseconds for 16 MHz Arduino by ADC_PRESCALE in ADCUtils.h. + * 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 readADCChannelWithReferenceMultiSamples(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples) { +uint16_t readADCChannelMultiSamplesWithReference(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples) { uint16_t tSumValue = 0; ADMUX = aADCChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE); @@ -275,6 +279,65 @@ uint16_t readADCChannelWithReferenceMultiSamples(uint8_t aADCChannelNumber, uint 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. @@ -408,7 +471,7 @@ uint16_t readUntil4ConsecutiveValuesAreEqual(uint8_t aADCChannelNumber, uint8_t */ float getVCCVoltageSimple(void) { // use AVCC with (optional) external capacitor at AREF pin as reference - float tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + float tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); return ((1023 * 1.1 * 4) / tVCC); } @@ -419,7 +482,7 @@ float getVCCVoltageSimple(void) { */ uint16_t getVCCVoltageMillivoltSimple(void) { // use AVCC with external capacitor at AREF pin as reference - uint16_t tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + uint16_t tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); return ((1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCC); } @@ -459,6 +522,9 @@ uint16_t getVCCVoltageMillivolt(void) { return ((1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT) / tVCC); } +/* + * Does not set sVCCVoltageMillivolt + */ uint16_t printVCCVoltageMillivolt(Print *aSerial) { aSerial->print(F("VCC=")); uint16_t tVCCVoltageMillivolt = getVCCVoltageMillivolt(); @@ -480,7 +546,7 @@ void readAndPrintVCCVoltageMillivolt(Print *aSerial) { */ void readVCCVoltageSimple(void) { // use AVCC with (optional) external capacitor at AREF pin as reference - float tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + float tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); sVCCVoltage = (1023 * (((float) ADC_INTERNAL_REFERENCE_MILLIVOLT) / 1000) * 4) / tVCC; } @@ -491,7 +557,7 @@ void readVCCVoltageSimple(void) { */ void readVCCVoltageMillivoltSimple(void) { // use AVCC with external capacitor at AREF pin as reference - uint16_t tVCCVoltageMillivoltRaw = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); + uint16_t tVCCVoltageMillivoltRaw = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4); sVCCVoltageMillivolt = (1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCCVoltageMillivoltRaw; } @@ -556,7 +622,7 @@ bool isVCCUSBPowered(Print *aSerial) { aSerial->print(F("USB powered is ")); bool tReturnValue; if (VOLTAGE_USB_POWERED_LOWER_THRESHOLD_MILLIVOLT - < sVCCVoltageMillivolt && sVCCVoltageMillivolt < VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT) { + < sVCCVoltageMillivolt&& sVCCVoltageMillivolt < VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT) { tReturnValue = true; aSerial->print(F("true ")); } else { @@ -649,6 +715,7 @@ void resetCounterForVCCUndervoltageMultipleTimes() { * 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() { @@ -660,6 +727,21 @@ bool isVCCOvervoltageSimple() { 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! @@ -671,18 +753,21 @@ float getCPUTemperatureSimple(void) { return 0.0; #else // use internal 1.1 volt as reference. 4 times oversample. Assume the signal has noise, but never verified :-( - uint16_t tTempRaw = readADCChannelWithReferenceOversample(ADC_TEMPERATURE_CHANNEL_MUX, INTERNAL, 2); + uint16_t tTemperatureRaw = readADCChannelWithReferenceOversample(ADC_TEMPERATURE_CHANNEL_MUX, INTERNAL, 2); #if defined(LOCAL_DEBUG) Serial.print(F("TempRaw=")); - Serial.println(tTempRaw); + Serial.println(tTemperatureRaw); #endif #if defined(__AVR_ATmega328PB__) - tTempRaw -= 245; - return (float)tTempRaw; + 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 - tTempRaw -= 317; - return (float) tTempRaw / 1.22; + tTemperatureRaw -= 317; + return (float) tTemperatureRaw / 1.22; #endif #endif } @@ -704,7 +789,7 @@ float getCPUTemperature(void) { } #else // defined(ADC_UTILS_ARE_AVAILABLE) -// Dummy definition of functions defined in ADCUtils to compile examples without errors +// Dummy definition of functions defined in ADCUtils to compile examples for non AVR platforms without errors /* * Persistent storage for VCC value */ diff --git a/examples/SmartCarFollowerSimple/HCSR04.hpp b/examples/SmartCarFollowerSimple/HCSR04.hpp index b700511..5317f08 100644 --- a/examples/SmartCarFollowerSimple/HCSR04.hpp +++ b/examples/SmartCarFollowerSimple/HCSR04.hpp @@ -70,7 +70,15 @@ //#define USE_PIN_CHANGE_INTERRUPT_D0_TO_D7 // using PCINT2_vect - PORT D //#define USE_PIN_CHANGE_INTERRUPT_D8_TO_D13 // using PCINT0_vect - PORT B - Pin 13 is feedback output //#define USE_PIN_CHANGE_INTERRUPT_A0_TO_A5 // using PCINT1_vect - PORT C +#if __has_include("digitalWriteFast.h") #include "digitalWriteFast.h" +#else +#define pinModeFast pinMode +#define digitalReadFast digitalRead +#define digitalWriteFast digitalWrite +#define digitalToggleFast(P) digitalWrite(P, ! digitalRead(P)) +#endif + #include "HCSR04.h" //#define DEBUG @@ -132,6 +140,7 @@ void initUSDistancePin(uint8_t aTriggerOutEchoInPin) { #if !defined (TRIGGER_OUT_PIN) sTriggerOutPin = aTriggerOutEchoInPin; #endif + (void) aTriggerOutEchoInPin; sHCSR04Mode = HCSR04_MODE_USE_1_PIN; } diff --git a/examples/SmartCarFollowerSimple/RobotCarPinDefinitionsAndMore.h b/examples/SmartCarFollowerSimple/RobotCarPinDefinitionsAndMore.h index d77f5c9..6738a58 100644 --- a/examples/SmartCarFollowerSimple/RobotCarPinDefinitionsAndMore.h +++ b/examples/SmartCarFollowerSimple/RobotCarPinDefinitionsAndMore.h @@ -235,20 +235,7 @@ # if !defined(LED_BUILTIN) && !defined(CAR_IS_ESP32_CAM_BASED) #define LED_BUILTIN PB1 # endif -#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. -void tone(uint8_t _pin, unsigned int frequency){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); -} -void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); - delay(duration); - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} -void noTone(uint8_t _pin){ - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} + #else // NANO_BASED // Uno based // Pin A0 for VCC monitoring - ADC channel 2 diff --git a/examples/SmartCarFollowerSimple/RobotCarUtils.hpp b/examples/SmartCarFollowerSimple/RobotCarUtils.hpp index 08c4a79..bc5140d 100644 --- a/examples/SmartCarFollowerSimple/RobotCarUtils.hpp +++ b/examples/SmartCarFollowerSimple/RobotCarUtils.hpp @@ -87,9 +87,9 @@ bool doCalibration = false; # endif #include "ADCUtils.hpp" uint16_t sLastVINRawSum; // Sum of NUMBER_OF_VIN_SAMPLES raw readings of ADC, used to determine if voltage has changed and must be displayed. -float sVINVoltage = FULL_BRIDGE_INPUT_MILLIVOLT / 1000; // set default value for later use uint32_t sMillisOfLastVCCInfo; #endif // defined(VIN_ATTENUATED_INPUT_PIN) +float sVINVoltage = FULL_BRIDGE_INPUT_MILLIVOLT / 1000; // Set default value for later use. Is used a parameter for getVoltageAdjustedSpeedPWM //uint32_t sMillisOfLastAttention = 0; // millis() of last doAttention() or doWave() @@ -227,7 +227,7 @@ bool readVINVoltage() { * Here VIN is the only channel we convert. * Get 10 samples lasting 1030 us, which is almost the PWM period of 1024 us. */ - uint16_t tVINRawSum = readADCChannelWithReferenceMultiSamples(VIN_ATTENUATED_INPUT_CHANNEL, INTERNAL, NUMBER_OF_VIN_SAMPLES); // 10 samples + uint16_t tVINRawSum = readADCChannelMultiSamplesWithReference(VIN_ATTENUATED_INPUT_CHANNEL, INTERNAL, NUMBER_OF_VIN_SAMPLES); // 10 samples #if defined(CAR_HAS_IR_DISTANCE_SENSOR) checkAndWaitForReferenceAndChannelToSwitch(tOldADMUX & MASK_FOR_ADC_CHANNELS, tOldADMUX >> SHIFT_VALUE_FOR_REFERENCE); #endif diff --git a/examples/Square/RobotCarPinDefinitionsAndMore.h b/examples/Square/RobotCarPinDefinitionsAndMore.h index d77f5c9..6738a58 100644 --- a/examples/Square/RobotCarPinDefinitionsAndMore.h +++ b/examples/Square/RobotCarPinDefinitionsAndMore.h @@ -235,20 +235,7 @@ # if !defined(LED_BUILTIN) && !defined(CAR_IS_ESP32_CAM_BASED) #define LED_BUILTIN PB1 # endif -#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. -void tone(uint8_t _pin, unsigned int frequency){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); -} -void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); - delay(duration); - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} -void noTone(uint8_t _pin){ - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} + #else // NANO_BASED // Uno based // Pin A0 for VCC monitoring - ADC channel 2 diff --git a/examples/Square/Square.ino b/examples/Square/Square.ino index 94c76c4..12f1484 100644 --- a/examples/Square/Square.ino +++ b/examples/Square/Square.ino @@ -58,7 +58,8 @@ void setup() { Serial.begin(115200); -#if defined(__AVR_ATmega32U4__) || defined(SERIAL_PORT_USBVIRTUAL) || defined(SERIAL_USB) /*stm32duino*/|| defined(USBCON) /*STM32_stm32*/|| defined(SERIALUSB_PID) || defined(ARDUINO_attiny3217) +#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 diff --git a/examples/Start/RobotCarPinDefinitionsAndMore.h b/examples/Start/RobotCarPinDefinitionsAndMore.h index d77f5c9..6738a58 100644 --- a/examples/Start/RobotCarPinDefinitionsAndMore.h +++ b/examples/Start/RobotCarPinDefinitionsAndMore.h @@ -235,20 +235,7 @@ # if !defined(LED_BUILTIN) && !defined(CAR_IS_ESP32_CAM_BASED) #define LED_BUILTIN PB1 # endif -#define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. -void tone(uint8_t _pin, unsigned int frequency){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); -} -void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ - ledcAttachPin(_pin, TONE_LEDC_CHANNEL); - ledcWriteTone(TONE_LEDC_CHANNEL, frequency); - delay(duration); - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} -void noTone(uint8_t _pin){ - ledcWriteTone(TONE_LEDC_CHANNEL, 0); -} + #else // NANO_BASED // Uno based // Pin A0 for VCC monitoring - ADC channel 2 diff --git a/src/DebugLevel.h b/src/DebugLevel.h index e8223b8..e86a9f4 100644 --- a/src/DebugLevel.h +++ b/src/DebugLevel.h @@ -1,8 +1,15 @@ /* * DebugLevel.h - * Include to propagate debug levels + * Include to propagate debug levels to each other * - * Copyright (C) 2016-2020 Armin Joachimsmeyer + * TRACE // Information you need to understand details of a function or if you hunt a bug. + * DEBUG // Information need to understand the operating of your program. E.g. function calls and values of control variables. + * INFO // Information you want to see in regular operation to see what the program is doing. E.g. "Now playing Muppets melody". + * WARN // Information that the program may encounter problems, like small Heap/Stack area. + * ERROR // Informations to explain why the program will not run. E.g. not enough Ram for all created objects. + * + * + * Copyright (C) 2016-2024 Armin Joachimsmeyer * Email: armin.joachimsmeyer@gmail.com * * This file is part of Arduino-Utils https://github.com/ArminJo/Arduino-Utils. @@ -25,7 +32,7 @@ #ifndef _DEBUGLEVEL_H #define _DEBUGLEVEL_H -// Propagate debug level +// Propagate different debug level #if defined(TRACE) // Information you need to understand details of a function or if you hunt a bug. # if !defined(DEBUG) #define DEBUG // Information need to understand the operating of your program. E.g. function calls and values of control variables. diff --git a/src/LongUnion.h b/src/LongUnion.h index 3559ac2..8f90f61 100644 --- a/src/LongUnion.h +++ b/src/LongUnion.h @@ -87,7 +87,7 @@ union LongUnion { struct { WordUnion LowWord; WordUnion HighWord; - } WordUnion; + } TwoWordUnions; uint8_t UBytes[4]; // seems to have the same code size as using struct UByte int8_t Bytes[4]; // Bytes[0] is LowByte uint16_t UWords[2]; @@ -122,7 +122,7 @@ union LongLongUnion { WordUnion MidLowWord; WordUnion MidHighWord; WordUnion HighWord; - } WordUnion; + } FourWordUnions; struct { uint32_t LowLong; uint32_t HighLong; @@ -134,7 +134,7 @@ union LongLongUnion { struct { LongUnion LowLong; LongUnion HighLong; - } LongUnion; + } TwoLongUnions; uint8_t UBytes[8]; // seems to have the same code size as using struct UByte int8_t Bytes[8]; uint16_t UWords[4]; diff --git a/src/PWMDcMotor.hpp b/src/PWMDcMotor.hpp index bac55fe..1de29e5 100644 --- a/src/PWMDcMotor.hpp +++ b/src/PWMDcMotor.hpp @@ -53,10 +53,6 @@ # endif // defined(USE_SOFT_I2C_MASTER) #endif // defined(USE_ADAFRUIT_MOTOR_SHIELD) -#if defined(ESP32) -#include "analogWrite.h" // from e.g. ESP32Servo library -#endif - //#define TRACE #if defined(DEBUG) #define LOCAL_DEBUG diff --git a/src/SoftI2CMaster.h b/src/SoftI2CMaster.h index 5f638cf..bf30f9a 100644 --- a/src/SoftI2CMaster.h +++ b/src/SoftI2CMaster.h @@ -401,7 +401,11 @@ bool i2c_init(void) TWSR = (1<