Skip to content

Instantly share code, notes, and snippets.

@ArminJo
Created September 12, 2020 09:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ArminJo/3664e7638ce5e6c3936915dc097530dd to your computer and use it in GitHub Desktop.
Save ArminJo/3664e7638ce5e6c3936915dc097530dd to your computer and use it in GitHub Desktop.
Arduino 433 MHz sender for PT2262/PT2272 sender/receiver chip combinations.
/*
* 433MHzSenderPT2262.cpp
*
* 433 MHz sender for PT2262/PT2272 sender/receiver chip combinations.
* https://cdn-shop.adafruit.com/datasheets/PT2262.pdf
*
* Copyright (C) 2020 Armin Joachimsmeyer
* armin.joachimsmeyer@gmail.com
*
* 433MHzSenderPT2262 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
*
*/
#include <Arduino.h>
//#define USE_DIGITAL_WRITE_FAST_LIBRARY
#ifdef USE_DIGITAL_WRITE_FAST_LIBRARY
// https://github.com/watterott/Arduino-Libs/tree/master/digitalWriteFast
#include "digitalWriteFast.h"
#else
// otherwise replace all calls to digitalWriteFast() with digitalWrite()
#define digitalWriteFast(a,b) digitalWrite(a,b)
#endif
#define VERSION_EXAMPLE "1.0"
const int OUT_433_SIGNAL_PIN = 5;
/*
* Debounced button library
*/
#define USE_BUTTON_0 // Enable code for button at INT0 / pin 2
#include "EasyButtonAtInt01.cpp.h"
void handleButtonPress(bool aButtonToggleState);
EasyButton Button1AtPin2(&handleButtonPress); // Button is connected to INT0 / pin 2
// Forward declarations
void sendFrameForPT2262(uint16_t a10BitAddress, uint8_t a2BitData);
void sendFrameForPT2262(uint16_t a5BitSenderAddress, uint16_t a5BitReceiverAddressExtension, uint8_t a2BitData);
/*
* The value of the clock period of the sender. We have 32 clocks per bit.
* If you have only a receiver at hand -> Data sheet says: transmitter clock has to be 2.5 to 8 times slower than sender clock
* A complete sender word consists of 32 x 12 + 4 (4 for last sync bit) = 388 clock cycles.
* A frame consists of 4 repeats of (address/data + sync) aka word
*/
//#define PT2262_CLOCK_PERIOD_MICROS 110 // 3.7 times slower than measured 33.91 kHz / 29.5 us receiver clock
#define PT2262_CLOCK_PERIOD_MICROS 81 // derived from sender word length of 31.5 ms
/*
* Settings for my ELRO / Flamingo set
*/
#define ADDRESS_SENDER_5_BIT 0b01110 // LSB's ON = 0, OFF = 1
#define ADDRESS_RECEIVER_5_BIT_A 0b10110
#define ADDRESS_RECEIVER_5_BIT_B 0b11101
#define ADDRESS_RECEIVER_5_BIT_C 0b11011
#define ADDRESS_RECEIVER_5_BIT_D 0b10111
#define ADDRESS_RECEIVER_10_BIT_D 0x2EE // or 0b1011101110
#define DATA_SWITCH_ON 0b10
#define DATA_SWITCH_OFF 0b01
/*
* Send code for receiver D
*/
void handleButtonPress(bool aButton0ToggleState) {
Serial.print(F("Send a "));
Serial.println(aButton0ToggleState);
if (aButton0ToggleState) {
sendFrameForPT2262(ADDRESS_SENDER_5_BIT, ADDRESS_RECEIVER_5_BIT_D, DATA_SWITCH_ON);
// sendFrameForPT2262(ADDRESS_RECEIVER_10_BIT_D, 2);
} else {
sendFrameForPT2262(ADDRESS_SENDER_5_BIT, ADDRESS_RECEIVER_5_BIT_D, DATA_SWITCH_OFF);
// sendFrameForPT2262(ADDRESS_RECEIVER_10_BIT_D, 1);
}
}
void setup() {
// initialize the digital pin as an output.
pinMode(LED_BUILTIN, OUTPUT);
pinMode(OUT_433_SIGNAL_PIN, OUTPUT);
Serial.begin(115200);
// Just to know which program is running on my Arduino
Serial.println(F("START " __FILE__ "\r\nVersion " VERSION_EXAMPLE " from " __DATE__));
}
void loop() {
// we have a callback function :-)
}
/*
* PT2262/2272 Stuff
*/
#define PT2262_DURATION4 (PT2262_CLOCK_PERIOD_MICROS * 4)
#define PT2262_DURATION12 (PT2262_CLOCK_PERIOD_MICROS * 12)
#define PT2262_DURATION128 (PT2262_CLOCK_PERIOD_MICROS * 128)
/*
* Sender IC HX2262
* Receiver IC PT2262
*/
#define PT2262_0 0 // DIP switch in position ON (connect HX2262 pin to ground)
#define PT2262_1 1
#define PT2262_FLOAT 3 // Code input pin floating - DIP switch in position off
#define PT2262_SYNC 4
#define PT2262_FLOAT_MASK 0x02
void sendBitForPT2262(uint8_t aCode) {
switch (aCode) {
case PT2262_0: // Bit"0" 4 high + 12 low + 4 high + 12 low
case 2:
digitalWriteFast(OUT_433_SIGNAL_PIN, 1);
delayMicroseconds(PT2262_DURATION4);
digitalWriteFast(OUT_433_SIGNAL_PIN, 0);
delayMicroseconds(PT2262_DURATION12);
digitalWriteFast(OUT_433_SIGNAL_PIN, 1);
delayMicroseconds(PT2262_DURATION4);
digitalWriteFast(OUT_433_SIGNAL_PIN, 0);
delayMicroseconds(PT2262_DURATION12);
break;
case PT2262_1: // Bit"1" 12 high + 4 low + 12 high + 4 low
digitalWriteFast(OUT_433_SIGNAL_PIN, 1);
delayMicroseconds(PT2262_DURATION12);
digitalWriteFast(OUT_433_SIGNAL_PIN, 0);
delayMicroseconds(PT2262_DURATION4);
digitalWriteFast(OUT_433_SIGNAL_PIN, 1);
delayMicroseconds(PT2262_DURATION12);
digitalWriteFast(OUT_433_SIGNAL_PIN, 0);
delayMicroseconds(PT2262_DURATION4);
break;
case PT2262_FLOAT: // Bit"f" Floating 4 high + 12 low + 12 high + 4 low
digitalWriteFast(OUT_433_SIGNAL_PIN, 1);
delayMicroseconds(PT2262_DURATION4);
digitalWriteFast(OUT_433_SIGNAL_PIN, 0);
delayMicroseconds(PT2262_DURATION12);
digitalWriteFast(OUT_433_SIGNAL_PIN, 1);
delayMicroseconds(PT2262_DURATION12);
digitalWriteFast(OUT_433_SIGNAL_PIN, 0);
delayMicroseconds(PT2262_DURATION4);
break;
case PT2262_SYNC: // Sync 4 high + 128 low
digitalWriteFast(OUT_433_SIGNAL_PIN, 1);
delayMicroseconds(PT2262_DURATION4);
digitalWriteFast(OUT_433_SIGNAL_PIN, 0);
delayMicroseconds(PT2262_DURATION128);
break;
default:
break;
}
}
/*
* A frame consists of 4 repeats of (address/data + sync) aka word
* @param a1MeansFloating true send floating code instead of code for a 1. This is default for most of the switches
* Floating is required for DIP switches which let the pin float at position 1
* @param aAddressData 10 bit address/data LSB is sent first
*/
void sendFrameForPT2262(uint16_t aAddressData, bool a1MeansFloating) {
Serial.print(F("Address/Data=0x"));
Serial.print(aAddressData,HEX);
Serial.print(F(", 0b"));
Serial.println(aAddressData,BIN);
// 4 words
for (uint8_t i = 0; i < 4; ++i) {
// 12 bit address/data
uint16_t tAddressData = aAddressData;
for (uint8_t j = 0; j < 12; ++j) {
uint8_t tValue = tAddressData & 0x01;
tAddressData = tAddressData >> 1;
if (a1MeansFloating) {
sendBitForPT2262(tValue | PT2262_FLOAT_MASK);
} else {
sendBitForPT2262(tValue);
}
}
// sync
sendBitForPT2262(PT2262_SYNC);
}
}
void sendFrameForPT2262(uint16_t a10BitAddress, uint8_t a2BitData) {
sendFrameForPT2262(a10BitAddress | (a2BitData << 10), true);
}
void sendFrameForPT2262(uint16_t a5BitSenderAddress, uint16_t a5BitReceiverAddressExtension, uint8_t a2BitData) {
sendFrameForPT2262((a5BitSenderAddress | (a5BitReceiverAddressExtension << 5)) | (a2BitData << 10), true);
}
#define BIT_READ(value, bit) ((value) & (1UL << (bit)))
#define BIT_SET(value, bit) ((value) |= (1UL << (bit)))
#define BIT_CLEAR(value, bit) ((value) &= ~(1UL << (bit)))
#define BIT_WRITE(value, bit, bitvalue) (bitvalue ? BIT_SET(value, bit) : BIT_CLEAR(value, bit))
#if !defined(digitalPinToPortReg)
#if (defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || \
defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__))
// Arduino Mega Pins
#define __digitalPinToPortReg(P) \
(((P) >= 22 && (P) <= 29) ? &PORTA : \
((((P) >= 10 && (P) <= 13) || ((P) >= 50 && (P) <= 53)) ? &PORTB : \
(((P) >= 30 && (P) <= 37) ? &PORTC : \
((((P) >= 18 && (P) <= 21) || (P) == 38) ? &PORTD : \
((((P) >= 0 && (P) <= 3) || (P) == 5) ? &PORTE : \
(((P) >= 54 && (P) <= 61) ? &PORTF : \
((((P) >= 39 && (P) <= 41) || (P) == 4) ? &PORTG : \
((((P) >= 6 && (P) <= 9) || (P) == 16 || (P) == 17) ? &PORTH : \
(((P) == 14 || (P) == 15) ? &PORTJ : \
(((P) >= 62 && (P) <= 69) ? &PORTK : &PORTL))))))))))
#define __digitalPinToDDRReg(P) \
(((P) >= 22 && (P) <= 29) ? &DDRA : \
((((P) >= 10 && (P) <= 13) || ((P) >= 50 && (P) <= 53)) ? &DDRB : \
(((P) >= 30 && (P) <= 37) ? &DDRC : \
((((P) >= 18 && (P) <= 21) || (P) == 38) ? &DDRD : \
((((P) >= 0 && (P) <= 3) || (P) == 5) ? &DDRE : \
(((P) >= 54 && (P) <= 61) ? &DDRF : \
((((P) >= 39 && (P) <= 41) || (P) == 4) ? &DDRG : \
((((P) >= 6 && (P) <= 9) || (P) == 16 || (P) == 17) ? &DDRH : \
(((P) == 14 || (P) == 15) ? &DDRJ : \
(((P) >= 62 && (P) <= 69) ? &DDRK : &DDRL))))))))))
#define __digitalPinToPINReg(P) \
(((P) >= 22 && (P) <= 29) ? &PINA : \
((((P) >= 10 && (P) <= 13) || ((P) >= 50 && (P) <= 53)) ? &PINB : \
(((P) >= 30 && (P) <= 37) ? &PINC : \
((((P) >= 18 && (P) <= 21) || (P) == 38) ? &PIND : \
((((P) >= 0 && (P) <= 3) || (P) == 5) ? &PINE : \
(((P) >= 54 && (P) <= 61) ? &PINF : \
((((P) >= 39 && (P) <= 41) || (P) == 4) ? &PING : \
((((P) >= 6 && (P) <= 9) || (P) == 16 || (P) == 17) ? &PINH : \
(((P) == 14 || (P) == 15) ? &PINJ : \
(((P) >= 62 && (P) <= 69) ? &PINK : &PINL))))))))))
#define __digitalPinToBit(P) \
(((P) >= 7 && (P) <= 9) ? (P) - 3 : \
(((P) >= 10 && (P) <= 13) ? (P) - 6 : \
(((P) >= 22 && (P) <= 29) ? (P) - 22 : \
(((P) >= 30 && (P) <= 37) ? 37 - (P) : \
(((P) >= 39 && (P) <= 41) ? 41 - (P) : \
(((P) >= 42 && (P) <= 49) ? 49 - (P) : \
(((P) >= 50 && (P) <= 53) ? 53 - (P) : \
(((P) >= 54 && (P) <= 61) ? (P) - 54 : \
(((P) >= 62 && (P) <= 69) ? (P) - 62 : \
(((P) == 0 || (P) == 15 || (P) == 17 || (P) == 21) ? 0 : \
(((P) == 1 || (P) == 14 || (P) == 16 || (P) == 20) ? 1 : \
(((P) == 19) ? 2 : \
(((P) == 5 || (P) == 6 || (P) == 18) ? 3 : \
(((P) == 2) ? 4 : \
(((P) == 3 || (P) == 4) ? 5 : 7)))))))))))))))
// 15 PWM
#define __digitalPinToTimer(P) \
(((P) == 13 || (P) == 4) ? &TCCR0A : \
(((P) == 11 || (P) == 12) ? &TCCR1A : \
(((P) == 10 || (P) == 9) ? &TCCR2A : \
(((P) == 5 || (P) == 2 || (P) == 3) ? &TCCR3A : \
(((P) == 6 || (P) == 7 || (P) == 8) ? &TCCR4A : \
(((P) == 46 || (P) == 45 || (P) == 44) ? &TCCR5A : 0))))))
#define __digitalPinToTimerBit(P) \
(((P) == 13) ? COM0A1 : (((P) == 4) ? COM0B1 : \
(((P) == 11) ? COM1A1 : (((P) == 12) ? COM1B1 : \
(((P) == 10) ? COM2A1 : (((P) == 9) ? COM2B1 : \
(((P) == 5) ? COM3A1 : (((P) == 2) ? COM3B1 : (((P) == 3) ? COM3C1 : \
(((P) == 6) ? COM4A1 : (((P) == 7) ? COM4B1 : (((P) == 8) ? COM4C1 : \
(((P) == 46) ? COM5A1 : (((P) == 45) ? COM5B1 : COM5C1))))))))))))))
#elif (defined(__AVR_ATmega644__) || \
defined(__AVR_ATmega644P__))
// Arduino 644 Pins
#define __digitalPinToPortReg(P) \
(((P) >= 0 && (P) <= 7) ? &PORTB : (((P) >= 8 && (P) <= 15) ? &PORTD : (((P) >= 16 && (P) <= 23) ? &PORTC : &PORTA)))
#define __digitalPinToDDRReg(P) \
(((P) >= 0 && (P) <= 7) ? &DDRB : (((P) >= 8 && (P) <= 15) ? &DDRD : (((P) >= 8 && (P) <= 15) ? &DDRC : &DDRA)))
#define __digitalPinToPINReg(P) \
(((P) >= 0 && (P) <= 7) ? &PINB : (((P) >= 8 && (P) <= 15) ? &PIND : (((P) >= 8 && (P) <= 15) ? &PINC : &PINA)))
#define __digitalPinToBit(P) \
(((P) >= 0 && (P) <= 7) ? (P) : (((P) >= 8 && (P) <= 15) ? (P) - 8 : (((P) >= 16 && (P) <= 23) ? (P) - 16 : (P) - 24)))
// 6 PWM
#define __digitalPinToTimer(P) \
(((P) == 3 || (P) == 4) ? &TCCR0A : \
(((P) == 12 || (P) == 13) ? &TCCR1A : \
(((P) == 14 || (P) == 15) ? &TCCR2A : 0)))
#define __digitalPinToTimerBit(P) \
(((P) == 3) ? COM0A1 : (((P) == 4) ? COM0B1 : \
(((P) == 13) ? COM1A1 : (((P) == 12) ? COM1B1 : \
(((P) == 15) ? COM2A1 : COM2B1)))))
#else
// Standard Arduino Pins
#define __digitalPinToPortReg(P) \
(((P) >= 0 && (P) <= 7) ? &PORTD : (((P) >= 8 && (P) <= 13) ? &PORTB : &PORTC))
#define __digitalPinToDDRReg(P) \
(((P) >= 0 && (P) <= 7) ? &DDRD : (((P) >= 8 && (P) <= 13) ? &DDRB : &DDRC))
#define __digitalPinToPINReg(P) \
(((P) >= 0 && (P) <= 7) ? &PIND : (((P) >= 8 && (P) <= 13) ? &PINB : &PINC))
#define __digitalPinToBit(P) \
(((P) >= 0 && (P) <= 7) ? (P) : (((P) >= 8 && (P) <= 13) ? (P) - 8 : (P) - 14))
#if defined(__AVR_ATmega8__)
// 3 PWM
#define __digitalPinToTimer(P) \
(((P) == 9 || (P) == 10) ? &TCCR1A : (((P) == 11) ? &TCCR2 : 0))
#define __digitalPinToTimerBit(P) \
(((P) == 9) ? COM1A1 : (((P) == 10) ? COM1B1 : COM21))
#else //168,328
// 6 PWM
#define __digitalPinToTimer(P) \
(((P) == 6 || (P) == 5) ? &TCCR0A : \
(((P) == 9 || (P) == 10) ? &TCCR1A : \
(((P) == 11 || (P) == 3) ? &TCCR2A : 0)))
#define __digitalPinToTimerBit(P) \
(((P) == 6) ? COM0A1 : (((P) == 5) ? COM0B1 : \
(((P) == 9) ? COM1A1 : (((P) == 10) ? COM1B1 : \
(((P) == 11) ? COM2A1 : COM2B1)))))
#endif //defined(__AVR_ATmega8__)
#endif
#endif //#if !defined(digitalPinToPortReg)
#if !defined(digitalWriteFast)
#define digitalWriteFast(P, V) \
if (__builtin_constant_p(P) && __builtin_constant_p(V)) { \
BIT_WRITE(*__digitalPinToPortReg(P), __digitalPinToBit(P), (V)); \
} else { \
digitalWrite((P), (V)); \
}
#endif
#if !defined(pinModeFast)
#define pinModeFast(P, V) \
if (__builtin_constant_p(P) && __builtin_constant_p(V)) { \
if (digitalPinToTimer(P)) \
BIT_CLEAR(*__digitalPinToTimer(P), __digitalPinToTimerBit(P)); \
BIT_WRITE(*__digitalPinToDDRReg(P), __digitalPinToBit(P), (V)); \
} else { \
pinMode((P), (V)); \
}
#endif
#if !defined(digitalReadFast)
#define digitalReadFast(P) ( (int) __digitalReadFast((P)) )
#define __digitalReadFast(P) \
(__builtin_constant_p(P)) \
? BIT_READ(*__digitalPinToPINReg(P), __digitalPinToBit(P)) \
: digitalRead((P))
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment