#include "Keypad2.h"
#include <avr/sleep.h>
const byte ROWS = 4;
const byte COLS = 3;
char keys[ROWS][COLS] = {
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'*', '0', '#'},
}; // end of keys
// Arduino nummering, Portname, Fysiek
// 5, PD5, 11
// 6, PD6, 12
// 7, PD7, 13
// 8, PB0, 14
//
// 9, PB1, 15
// 10, PB2, 16
// 11, PB3, 17
byte rowPins[ROWS] = { 5, 6, 7, 8 };
byte colPins[COLS] = { 9, 10, 11 };
// number of items in an array for pin re-configuration between sleep and keypad routines
#define NUMITEMS(arg) ((unsigned int) (sizeof (arg) / sizeof (arg [0])))
// const byte ledPin = 13;
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// we don't want to do anything except wake
EMPTY_INTERRUPT (PCINT0_vect)
EMPTY_INTERRUPT (PCINT1_vect)
EMPTY_INTERRUPT (PCINT2_vect)
void setup()
{
// pinMode (ledPin, OUTPUT);
// 8 MHz clock divided by 2:
CLKPR = (1<<CLKPCE) | (1<<CLKPS0);
// pin change interrupt masks (see above list)
PCMSK2 |= _BV (PCINT21); // pin 5 - PORTD mask 0x20
PCMSK2 |= _BV (PCINT22); // pin 6 - PORTD mask 0x40
PCMSK2 |= _BV (PCINT23); // pin 7 - PORTD mask 0x80
PCMSK0 |= _BV (PCINT0); // pin 8 - PORTB mask 0x01
Serial.begin(115200);
}
void reconfigurePins ()
{
byte i;
// go back to all pins as per the keypad library
for (i = 0; i < NUMITEMS (colPins); i++)
{
pinMode (colPins [i], OUTPUT);
digitalWrite (colPins [i], HIGH);
} // end of for each column
for (i = 0; i < NUMITEMS (rowPins); i++)
{
pinMode (rowPins [i], INPUT);
digitalWrite (rowPins [i], HIGH);
} // end of for each row
} // end of reconfigurePins
void goToSleep ()
{
byte i;
// set up to detect a keypress
for (i = 0; i < NUMITEMS (colPins); i++)
{
pinMode (colPins [i], OUTPUT);
digitalWrite (colPins [i], LOW); // columns low
} // end of for each column
for (i = 0; i < NUMITEMS (rowPins); i++)
{
pinMode (rowPins [i], INPUT_PULLUP);
} // end of for each row
// now check no pins pressed (otherwise we wake on a key release)
for (i = 0; i < NUMITEMS (rowPins); i++)
{
if (digitalRead (rowPins [i]) == LOW)
{
reconfigurePins ();
return;
} // end of a pin pressed
} // end of for each row
// overcome any debounce delays built into the keypad library
delay (50);
// at this point, pressing a key should connect the high in the row to the
// to the low in the column and trigger a pin change
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
sleep_enable();
byte old_ADCSRA = ADCSRA;
// disable ADC to save power
ADCSRA = 0;
PRR = 0xFF; // turn off various modules
PCIFR |= _BV (PCIF0) | _BV (PCIF1) | _BV (PCIF2); // clear any outstanding interrupts
PCICR |= _BV (PCIE0) | _BV (PCIE1) | _BV (PCIE2); // enable pin change interrupts
// turn off brown-out enable in software
MCUCR = _BV (BODS) | _BV (BODSE);
MCUCR = _BV (BODS);
sleep_cpu ();
// cancel sleep as a precaution
sleep_disable();
PCICR = 0; // cancel pin change interrupts
PRR = 0; // enable modules again
ADCSRA = old_ADCSRA; // re-enable ADC conversion
// put keypad pins back how they are expected to be
reconfigurePins ();
} // end of goToSleep
void irSendNECavr( uint32_t code, volatile uint8_t *port, volatile uint8_t *portDdr, uint8_t portPin, bool inverted = false, bool invertedBitOrder = false ) {
// sends an NEC IR code. No library required. Just copy this function into your sketch.
// where:
// code: the code to send e.g. 0x00FDA857
// port: a refererence to the port for the led pin e.g. &PORTB (note leading &)
// portDdr: a refererence to the port's data direction register e.g. &DDRB (note leading &)
// portPin: the port pin number in range 0 to 7 (NOT the Arduino digital pin number nor physical pin number)
// inverted: (default false). Default case : led wired so pin HIGH = on. otherwise pin LOW = on.
// invertedBitOrder (default false). Default case: MSB as used in ver <= 2 of the Ken Shirriff IR library. Otherwise mirrored for V3+
// sample call: irSendNECblk( 0x00FF1A9B, &PORTB, &DDRB, 5 , false, false ) ; // last 2 parameters optional
// digital pin 13 (portB port pin 5), 38kHz carrier, pin HIGH puts led on, original (non mirrored) hex code format.
// Note: blocks the loop() for approx 70 ms during send operation. Fixed to 38kHz carrier.
// Suspends interrupts during IR_mark phases to minimise glitches from millis() timer. Not really required
// at 4MHz clock and above.
//
// Author: 6v6gt Ver 0_09 04.05.2021 https://forum.arduino.cc/t/extreme-lightweight-ir-sender-for-nec-protocol/858910
uint16_t NecBurstUnit = ( 38 * 562L) / 1000L ; // IR carrier waves for 1 NEC mark or 1 NEC space( bit 0). Fixed at 38KHz
uint8_t * codeSplit ;
codeSplit = ( uint8_t* ) &code ; // treat uint32_t as byte array ;
// tune this table if required to match the Mark and Space for the IR carrier in CPU ticks (33% duty cycle)
// calculated as irPeriodCpuTicks = F_CPU / ( freqKhz * 1000L ) then deduction of overhead.
// Behaviour dependent on compiler optimisation.
#if F_CPU == 16000000L
const uint16_t IR_MARKWAIT = 134; const uint16_t IR_SPACEWAIT = 275 ;
#elif F_CPU == 8000000L
const uint16_t IR_MARKWAIT = 67 ; const uint16_t IR_SPACEWAIT = 130 ;
#elif F_CPU == 4000000L
const uint16_t IR_MARKWAIT = 30 ; const uint16_t IR_SPACEWAIT = 60 ;
#elif F_CPU == 2000000L
const uint16_t IR_MARKWAIT = 14; const uint16_t IR_SPACEWAIT = 24 ;
#elif F_CPU == 1000000L
const uint16_t IR_MARKWAIT = 7; const uint16_t IR_SPACEWAIT = 7 ;
#else
#error "Unsupported clock rate. AVR with 1, 2, 4, 8 or 16MHz supported."
#endif
struct Xmit {
static void xmit( bool isOn, uint16_t waves, bool inverted, volatile uint8_t *port, uint8_t portPin ) {
// send one IR carrier wave
bool markVal = !!isOn != !!inverted ; // XOR
for ( uint16_t i = 0 ; i < waves ; i ++ ) {
markVal ? *port |= _BV(portPin) : *port &= ~_BV(portPin) ;
__builtin_avr_delay_cycles( IR_MARKWAIT ) ;
inverted ? *port |= _BV(portPin) : *port &= ~_BV(portPin) ;
__builtin_avr_delay_cycles( IR_SPACEWAIT ) ;
} ;
};
};
*portDdr |= _BV(portPin) ; // equivalent to pinMode( <digital pin>, OUTPUT ) ;
// noInterrupts() ; // required for lower clock rates only
Xmit::xmit( true , NecBurstUnit * 16 , inverted, port, portPin ) ; // header mark 9000 us
Xmit::xmit( false , NecBurstUnit * 8 , inverted, port, portPin) ; // header space 4500 us // !!!!!!!!!
for ( uint8_t i = 0 ; i < 32 ; i ++ ) { // 32 bits
Xmit::xmit( true , NecBurstUnit , inverted, port, portPin) ; // NEC mark
uint8_t codeByte = !invertedBitOrder ? 3 - i / 8 /*MSB*/ : i/8 /*LSB*/ ;
uint8_t codeBit = !invertedBitOrder ? 7 - i % 8 /*MSB*/ : i % 8 /*LSB*/ ;
Xmit::xmit( false, bitRead( *(codeSplit + codeByte) , codeBit ) == 1 ? NecBurstUnit * 3 : NecBurstUnit , inverted, port, portPin) ; // NEC space(0) 562us or NEC space(1) ~1675us
}
Xmit::xmit( true , NecBurstUnit , inverted, port, portPin ) ; // terminator
// interrupts() ; // required for lower clock rates only
} // end of irSendNECblk()
void loop()
{
byte key = keypad.getKey();
if (!key)
{
goToSleep ();
return;
}
Serial.println(F("Key received"));
uint32_t hexCode ;
// hexCode = 0x00FDA857 ; // OK
// hexCode = 0xEA15BF00 ; // NEC OK mirrored
// You may choose any pin. You identify it by Port and Pin within port.
// You must also include the data direction register for that port.
// The example below is for digital pin 3
// digital pin 3 = port: PORTD, port pin 3 with matching data direction register.
// both inverted and mirrored bit order are false.
// Note that 3 here is pin number within the port, not necessarily the Arduino
// digital pin number
// irSendNECavr( hexCode , &PORTD, &DDRD, 3 , false, false ) ;
if (key == '1') {
// Protocol=NEC Address=0x45 Command=0x1A Raw-Data=0xE51ABA45 32 bits LSB first
// Send with: IrSender.sendNEC(0x45, 0x1A, <numberOfRepeats>);
hexCode = 0xE51ABA45;
Serial.println(F("1"));
}
if (key == '2') {
// Protocol=NEC Address=0x45 Command=0x1F Raw-Data=0xE01FBA45 32 bits LSB first
// Send with: IrSender.sendNEC(0x45, 0x1F, <numberOfRepeats>);
hexCode = 0xE01FBA45;
Serial.println(F("2"));
}
if (key == '3') {
// Protocol=NEC Address=0x45 Command=0x58 Raw-Data=0xA758BA45 32 bits LSB first
// Send with: IrSender.sendNEC(0x45, 0x58, <numberOfRepeats>);
hexCode = 0xA758BA45;
}
if (key == '4') {
// Protocol=NEC Address=0x45 Command=0x16 Raw-Data=0xE916BA45 32 bits LSB first
// Send with: IrSender.sendNEC(0x45, 0x16, <numberOfRepeats>);
hexCode = 0xE916BA45;
}
if (key == '5') {
// Protocol=NEC Address=0x45 Command=0x1B Raw-Data=0xE41BBA45 32 bits LSB first
// Send with: IrSender.sendNEC(0x45, 0x1B, <numberOfRepeats>);
hexCode = 0xE41BBA45;
}
if (key == '6') {
// Protocol=NEC Address=0x45 Command=0x54 Raw-Data=0xAB54BA45 32 bits LSB first
// Send with: IrSender.sendNEC(0x45, 0x54, <numberOfRepeats>);
hexCode = 0xAB54BA45;
}
if (key == '7') {
// Protocol=NEC Address=0x45 Command=0x12 Raw-Data=0xED12BA45 32 bits LSB first
// Send with: IrSender.sendNEC(0x45, 0x12, <numberOfRepeats>);
hexCode = 0xED12BA45;
}
if (key == '8') {
// Protocol=NEC Address=0x45 Command=0x17 Raw-Data=0xE817BA45 32 bits LSB first
// Send with: IrSender.sendNEC(0x45, 0x17, <numberOfRepeats>);
hexCode = 0xE817BA45;
}
if (key == '9') {
// Protocol=NEC Address=0x45 Command=0x50 Raw-Data=0xAF50BA45 32 bits LSB first
// Send with: IrSender.sendNEC(0x45, 0x50, <numberOfRepeats>);
hexCode = 0xAF50BA45;
}
if (key == '0') {
// Protocol=NEC Address=0x45 Command=0x13 Raw-Data=0xEC13BA45 32 bits LSB first
// Send with: IrSender.sendNEC(0x45, 0x13, <numberOfRepeats>);
hexCode = 0xEC13BA45;
}
if (key == '*') {
// Standby:
// Protocol=NEC Address=0x45 Command=0x1E Raw-Data=0xE11EBA45 32 bits LSB first
// Send with: IrSender.sendNEC(0x45, 0x1E, <numberOfRepeats>);
hexCode = 0xE11EBA45;
Serial.println(F("*"));
}
if (key == '#') {
// CHG+:
// Protocol=NEC Address=0x45 Command=0x48 Raw-Data=0xB748BA45 32 bits LSB first
// Send with: IrSender.sendNEC(0x45, 0x48, <numberOfRepeats>);
hexCode = 0xB748BA45;
Serial.println(F("#"));
}
noInterrupts();
// irSendNECavr( hexCode , &PORTD, &DDRD, 3 , false, false ) ;
// Fysiek pinnummer = 23, PC0 (ADC0/PCINT8)
irSendNECavr( hexCode , &PORTC, &DDRC, 0 , false, false ) ;
interrupts();
}