前回紹介したのは国内外の主要メーカーで採用されているPPM方式に対応しリモコンデータの受信と解析を同時に行うため非常に省メモリな特徴があったがPPM方式ではない他の方式、例えばフィリップス社のマンチェスター符号方式等には対応できなかった。
今回紹介するのは単純に信号のオンオフ時間を記録する方式なので全てのリモコンに対応可能な代わりに多量のメモリが必要となる。ESP32ほどのメモリがあれば問題にはならないがメモリの少ないCPUでは全く使い物にならない。エアコン等のリモコンデータは1Kバイト弱程度にもなる。速攻で作ってみただけなのでノイズ対策もパルス幅補正も行ってなくてHWによっては誤動作することがあるかも...
【サンプル・スケッチ(SHT31用のサンプルに赤外線送受信機能を追加)】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
#include <M5StickC.h> #include "SHT3X.h" #include "DigitalPulse.h" #define M5_BUTTON_A M5_BUTTON_HOME #define M5_BUTTON_B M5_BUTTON_RST #define M5_FONT1 2 #define M5_FONT2 4 static DigitalPulse<uint16_t, 512> dpulse(36, M5_IR, 15); static SHT3X<> sht3x; static uint8_t contrast = 9; static int16_t temp_val = 0; static uint16_t humi_val = 0; static uint8_t ir_data[1024]; void setup() { // // Setup GPIO // pinMode(M5_BUTTON_A, INPUT); pinMode(M5_BUTTON_B, INPUT); pinMode(M5_LED, OUTPUT); digitalWrite(M5_LED, HIGH); // LOW: ON, HIGH: OFF // // Setup Display // M5.begin(); M5.Axp.ScreenBreath(contrast); M5.Lcd.setRotation(1); M5.Lcd.setCursor(0, 0); M5.Lcd.setTextFont(M5_FONT1); M5.Lcd.println(" [SHT3X]"); M5.Lcd.setTextFont(M5_FONT2); // // Setup SHT3X // sht3x.begin(); // // Setup Digital Pulse // dpulse.begin(); } void loop() { // // Handle SHT3X // switch (sht3x.handle()) { case SHT3X_NO_DEVICE: temp_val = 0; humi_val = 0; break; case SHT3X_READY: temp_val = sht3x.temperatureC(); humi_val = sht3x.humidity(); digitalWrite(M5_LED, !digitalRead(M5_LED)); break; } // // Display Temperature and Humidity // M5.Lcd.setCursor(0, 24); M5.Lcd.printf(" %2.2f C ", temp_val / 16.0); M5.Lcd.setCursor(0, 50); M5.Lcd.printf(" %2.2f %% ", humi_val / 16.0); // // IR Play // if(digitalRead(M5_BUTTON_A) == LOW) { Serial.printf("play() = %u\n", dpulse.play(ir_data)); while(digitalRead(M5_BUTTON_A) == LOW) continue; } // // IR Scan // if(digitalRead(M5_BUTTON_B) == LOW) { uint16_t rv = dpulse.scan(); Serial.printf("recoding() = %u\n", rv); if (rv > 0) dpulse.save(ir_data, sizeof(ir_data)); while(digitalRead(M5_BUTTON_B) == LOW) continue; } delay(10); } |
【ライブラリ】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
/* * Digital Pulse Library for M5Stick-C * * Sasapea's Lab * * 2019-06-29: Version 1.0 */ #ifndef _DIGITALPULSE_H #define _DIGITALPULSE_H #include <stdint.h> #include <stdbool.h> #include <string.h> #define DIGITALPULSE_DATA_MARKER "DP" // Data Marker #define DIGITALPULSE_START_TIMEOUT 5000000L // scan start timeout #define DIGITALPULSE_END_TIMEOUT 50000L // scan end timeout #define DIGITALPULSE_IR_FREQUENCY 38000 // 38kHz #define DIGITALPULSE_IR_RESOLUTION 8 // 8bit resolution #define DIGITALPULSE_IR_SUBCARRIER_ON ((1 << DIGITALPULSE_IR_RESOLUTION) * 2 / 3) // 1/3 duty #define DIGITALPULSE_IR_SUBCARRIER_OFF ((1 << DIGITALPULSE_IR_RESOLUTION) * 3 / 3) // 0 duty typedef struct { uint8_t marker[2]; uint16_t unit; uint8_t size; uint8_t value; uint16_t count; } DIGITALPULSE_T; template <typename T, uint16_t SIZE> class DigitalPulse { private: uint8_t _i_pin; uint8_t _o_pin; uint8_t _pwm_ch; struct { DIGITALPULSE_T header; T buffer[SIZE]; } _data; public: DigitalPulse(uint8_t i_pin = 0xFF, uint8_t o_pin = 0xFF, uint8_t pwm_ch = 0xFF, uint16_t unit = 1) : _i_pin(i_pin) , _o_pin(o_pin) , _pwm_ch(pwm_ch) { _data.header.marker[0] = DIGITALPULSE_DATA_MARKER[0]; _data.header.marker[1] = DIGITALPULSE_DATA_MARKER[1]; _data.header.unit = unit; _data.header.size = sizeof(T); _data.header.value = 0; _data.header.count = 0; } void begin(void) { if (_i_pin != 0xFF) pinMode(_i_pin, INPUT); if (_o_pin != 0xFF) { if (_pwm_ch != 0xFF) { ledcSetup(_pwm_ch, DIGITALPULSE_IR_FREQUENCY, DIGITALPULSE_IR_RESOLUTION); ledcWrite(_pwm_ch, DIGITALPULSE_IR_SUBCARRIER_OFF); ledcAttachPin(_o_pin, _pwm_ch); } else pinMode(_o_pin, OUTPUT); } } void end(void) { if (_o_pin != 0xFF) { if (_pwm_ch != 0xFF) ledcDetachPin(_o_pin); else pinMode(_o_pin, INPUT); } } uint16_t scan(uint32_t timeout = DIGITALPULSE_START_TIMEOUT, uint32_t timeout2 = DIGITALPULSE_END_TIMEOUT) { uint8_t value = digitalRead(_i_pin); _data.header.value = !value; _data.header.count = 0; T *p = _data.buffer; bool started = false; uint32_t now, start = micros(); do { now = micros(); if (value != digitalRead(_i_pin)) { if (started) { if (_data.header.count >= SIZE) return 0; // buffer overflow!! ++_data.header.count; uint32_t elapse = now - start; *p++ = (T)(_data.header.unit > 1 ? elapse / _data.header.unit : elapse); } else { started = true; timeout = timeout2; } value = !value; start = now; } } while (now - start < timeout); return _data.header.count; } uint16_t play(void *buf = nullptr, bool invert = false) { DIGITALPULSE_T *h = (DIGITALPULSE_T *)(buf ? buf : &_data.header); if ((h->marker[0] != DIGITALPULSE_DATA_MARKER[0]) || (h->marker[1] != DIGITALPULSE_DATA_MARKER[1]) || (h->size != sizeof(T))) return 0; uint8_t value = _pwm_ch != 0xFF ? HIGH : (invert ? !h->value : h->value); uint16_t unit = h->unit; uint16_t count = h->count; T *p = (T *)&h[1]; uint32_t next = micros(); for (uint16_t i = 0; i < count; ++i) { if (_pwm_ch != 0xFF) ledcWrite(_pwm_ch, value ? DIGITALPULSE_IR_SUBCARRIER_ON : DIGITALPULSE_IR_SUBCARRIER_OFF); else digitalWrite(_o_pin, value); value = !value; next += unit > 1 ? (uint32_t)*p++ * unit : *p++; delayMicroseconds(next - micros()); } if (_pwm_ch != 0xFF) ledcWrite(_pwm_ch, DIGITALPULSE_IR_SUBCARRIER_OFF); else digitalWrite(_o_pin, value); return count; } bool save(void *buf, size_t size, size_t *len = nullptr) { size_t n = sizeof(DIGITALPULSE_T) + sizeof(T) * _data.header.count; if (len) *len = n; if (buf && _data.header.count && (n <= size)) { memcpy(buf, &_data, n); return true; } return false; } }; #endif // _DIGITALPULSE_H |