プログラム内容
過去記事にて作成した以下の各プログラム要素を全て使用でき、起動画面にて各メニューを選択できるプログラムを作成する。
・WIFiにてインターネットから取得した現在時刻をLCDに表示
・温湿度気圧センサ(BME280)から取得した温湿度気圧値をLCDに表示
・赤外線送受信リモコン
回路図
過去の記事で回路図について作成しているので詳細はそちらを確認ください。
ピン接続は以下を参考にしてください。
名称 | 使用部品 | データのやり取り | ESP32への接続ピン |
---|---|---|---|
I2C接続LCDモジュール | AE-AQM1602A(KIT) | I2C通信 | SDA:21,SCL:22 |
温湿度気圧センサモジュール | AE-BME280 | SPI通信 | SCK:14,SDO:12,SDI:13,CSB:26 |
赤外線受信モジュール | IRM-3638 | 入力 | OUT:17 |
トグルスイッチ | 小型3Pトグルスイッチ(1回路2接点) | 入力 | 39 |
タクトスイッチ | タクトスイッチ | 入力 | 34,35,36 |
赤外線LED | L-53F3BT | 出力 | トランジスタ(ベース):16 |
プログラム内容
基本は過去のプログラム内容をそのまま活用しているが、シリアルモニターへの出力機能等の無駄なプログラムは削除している。
以下がプログラム動作時の状態である。
・電源ON時
・メニュー選択画面
・01_TIME MODE
WiFI接続NG時
WiFI接続OK時
・02_BME280 MODE
・03_IR MODE
以下は今回使用したプログラムなのでコピーして使用してみて下さい。
※WiFi接続ルータとPASSは打ち替える必要有り
※過去プログラムの複合なので詳細解説は無し
04_COMPOUND_PROGRAM
/* 作成日;2020/5/17
ファイル名;04_COMPOUND PROGRAM
プログラム内容;3モードの機能を操作
①現在時刻表示
②温湿度気圧測定
③赤外線送受信
使用部品;ESP32、LCD、WiFiルータ、トグルスイッチ、IRM-3638、タクトスイッチ×2、L-53F3BT、BME280
ESP32へのピン接続;回路図参照
*/
/****************************各ライブラリ設定****************************/
# include <Wire.h> //I2C通信ライブラリ(LCO用)
# include <WiFi.h> //WiFiモジュールライブラリ(ESP32用)
# include "ESP32_BME280_SPI.h" //BME280ライブラリ
//赤外線送受信関係ライブラリ
# include <Arduino.h>
# include <IRrecv.h>
# include <IRsend.h>
# include <IRremoteESP8266.h>
# include <IRac.h>
# include <IRtext.h>
# include <IRutils.h>
/****************************各ライブラリ設定****************************/
/****************************各ピンの接続箇所設定***************************/
const uint16_t kIrLed = 16; //赤外線送信ピン
const uint16_t kRecvPin = 17; //赤外線受信ピン
const uint16_t Tac_SW1 = 34; //前ボタン,モード終了ボタン
const uint16_t Tac_SW2 = 35; //次ボタン,赤外線受信許可変更ボタン
const uint16_t Tac_SW3 = 36; //決定ボタン,BME280計測開始&終了ボタン,赤外線受信データ送信ボタン
const uint16_t Tog_SW = 39; //WiFi接続トグルスイッチ
/****************************各ピンの接続箇所設定***************************/
/****************************各フラグ宣言***************************/
bool Tog_Flag = false; //WiFi接続トグルスイッチ割り込みフラグ
bool Wifi_Flag = false; //WiFi接続フラグ
bool Mesure_Flag = false; //BME280計測開始ボタン割り込みフラグ
bool Mode_Flag = false; //BME280計測モード変更フラグ
bool Mode_finish = false; //BME280計測モード終了フラグ
/****************************各フラグ宣言***************************/
/****************************LCD関係****************************/
# define LCD_ADRS 0x3E //LCDのI2C用アドレス
uint8_t lcd_menu_select; //メニューセレクト判別(1:現在時刻表示,2:温湿度気圧測定,3:赤外線送受信)
bool lcd_menu_decision = false; //メニュー決定フラグ
String lcd_bdata1; //最新のLCD表示文字格納変数(1列目)
String lcd_bdata2; //最新のLCD表示文字格納変数(2列目)
String lcd_cdata1; //表示用LCD表示文字格納変数(1列目)
String lcd_cdata2; //表示用LCD表示文字格納変数(2列目)
byte lcd_bcommand; //最新のLCDコマンド格納変数
/****************************LCD関係****************************/
/****************************WiFi関係****************************/
WiFiServer server(80); //PCからの応答を読み取るためのサーバ定義
const char* ssid = "自宅ルータのSSID"; //SSID
const char* password = "自宅ルータのPASS"; //PASS
IPAddress ip; //IPアドレス格納変数
String ip_string = ""; //IPアドレスをString型に変換した値を格納する
/****************************WiFi関係****************************/
/****************************赤外線送受信関係****************************/
//各変数を設定
const uint16_t kCaptureBufferSize = 1024; //受信データ格納バッファ数(赤外線ON/OFFの時間を格納)
String recv_code = ""; //受信コード挿入変数
uint16_t recv_bits; //受信コード総ビット数挿入変数
uint16_t recv_onoff_bits; //ONOFF回数挿入変数
uint16_t recv_state_bits; //A/C受信コード挿入変数
uint64_t recv_data; //受信データ挿入変数
uint16_t rawData[1000]; //送信データ格納バッファ(AC以外)
unsigned char samsungState[500]; //送信データ格納バッファ(AC)
bool recv_pms_flag = true; //赤外線受信許可フラグ
const uint16_t kMinUnknownSize = 12; //不明な赤外線受信をカットするための変数
//kTimeout = 赤外線データの終了を判断するmsの値を設定(kTimeoutミリ秒間受信がなければ終了と判断する)
# if DECODE_AC //エアコンの赤外線リモコンの場合
const uint8_t kTimeout = 50; //50ms
# else //その他の赤外線リモコン機器の場合
const uint8_t kTimeout = 15; //15ms
# endif
//各インスタンスを生成
IRrecv irrecv(kRecvPin, kCaptureBufferSize, kTimeout, true); //IRrecv(赤外線受信ピン、受信データ格納バッファサイズ、データ終了判断時間、値保存機能(true推奨))
decode_results results; //受信結果を保存するクラスのインスタンスを生成
IRsend irsend(kIrLed); //赤外線送信クラスのインスタンスを生成
decode_type_t maker_code; //メーカーコードのインスタンスを生成
/****************************赤外線送受信関係****************************/
/****************************BME280関係****************************/
//各種SPI通信用変数設定
const uint8_t SCLK_bme280 = 14; //クロック入力
const uint8_t MOSI_bme280 =13; //マスター(ESP32):出力、スレーブ(BME280):入力
const uint8_t MISO_bme280 =12; //マスター(ESP32):入力、スレーブ(BME280):出力
const uint8_t CS_bme280 = 26; //チップ選択
//各種BME280測定モード設定用変数設定
uint8_t t_sb = 0; //測定間でのスタンバイ時間=0.5[ms] (0:0.5ms、1:62.5ms、2:125ms、3:250ms、4:500ms、5:1000ms、6:10、7:20ms)
uint8_t filter = 4; //測定値精度=16 (0:フィルターオフ、1:2、2:4、3:8、4以上:16) ※数字が大きいほどサンプリング回数が増える
uint8_t osrs_t = 2; //温度のオーバーサンプリング値=2 (0:無(ノイズ影響受ける)、1:1、2:2、3:4、4:8、5以上:16) ※オーバサンプリングをすると測定時間が伸びるがノイズ影響が減る
uint8_t osrs_p = 5; //気圧のオーバーサンプリング値=5 (0:無(ノイズ影響受ける)、1:1、2:2、3:4、4:8、5以上:16) ※オーバサンプリングをすると測定時間が伸びるがノイズ影響が減る
uint8_t osrs_h = 1; //湿度のオーバーサンプリング値=1 (0:無(ノイズ影響受ける)、1:1、2:2、3:4、4:8、5以上:16) ※オーバサンプリングをすると測定時間が伸びるがノイズ影響が減る
uint8_t Mode = 0; //計測=スリープモード(0:スリープモード(計測しない,電源ON直後)、1or2:フォースドモード(1度だけ測定)、3:ノーマルモード(繰り返し測定))
ESP32_BME280_SPI bme280spi(SCLK_bme280, MOSI_bme280, MISO_bme280, CS_bme280, 10000000); //10MHzにてSPIクラスのインスタンスを生成
/****************************BME280関係****************************/
/****************************外部割り込み設定****************************/
volatile unsigned long time_prev = 0; //割り込み時刻コピー変数
volatile unsigned long time_now; //現在の割り込み時刻取得変数
unsigned long time_chat = 500; //割り込み時刻
/****************************外部割り込み設定****************************/
/****************************現在時刻取得設定****************************/
struct tm timeInfo; //時刻を格納するオブジェクト
String date_string = ""; //日付をString型に変換した値を格納する
String time_string = ""; //時刻をString型に変換した値を格納する
/****************************現在時刻取得設定****************************/
/****************************タイマー割り込み設定****************************/
volatile int interruptCounter; //タイマーカウンター
hw_timer_t * timer = NULL; //タイマー変数
volatile SemaphoreHandle_t timerSemaphore; //タイマー割り込みが発生したかどうかを表すセマフォ
/****************************タイマー割り込み設定****************************/
/****************************タタイマー割り込み処理****************************/
void IRAM_ATTR onTimer() {
interruptCounter ++; //割り込みカウント
xSemaphoreGiveFromISR(timerSemaphore, NULL); //割り込みフラグをリセット
}
/****************************タイマー割り込み処理****************************/
/****************************初期設定 ****************************/
void setup() {
//ピン入出力設定
pinMode(Tac_SW1, INPUT); //SW1を入力
pinMode(Tac_SW2, INPUT); //SW2を入力
pinMode(Tac_SW3, INPUT); //SW3を入力
pinMode(Tog_SW, INPUT); //トグルスイッチを入力
//通信関係処理
Serial.begin(115200); //シリアル通信レート開始(通信レート:115200bits/s)
Wire.begin(); //I2C通信開始(ESP32をマスター)
irrecv.enableIRIn(); //赤外線受信開始
irsend.begin(); //赤外線送信開始
bme280spi.ESP32_BME280_SPI_Init(t_sb, filter, osrs_t, osrs_p, osrs_h, Mode); //各レジスタに初期設定をSPI通信にて書き込み
#if DECODE_HASH
irrecv.setUnknownThreshold(kMinUnknownSize); //不明な赤外線受信データは除外する
#endif
//タイマー割り込み設定
timerSemaphore = xSemaphoreCreateBinary(); //割り込みハンドラが呼ばれた際の通信のために利用するセマフォ(バイナリセマフォ)の作成
timer = timerBegin(0, 80, true); //タイマー番号0(0〜3)、分周比80(ESP32のクロック周波数は80MHz)、タイマー増減(true:増加,false:減少)
timerAttachInterrupt(timer, &onTimer, true); //タイマー変数指定:timer、タイマー割り込みする処理関:onTimer、割り込みタイプ(true:エッジ,false:レベル)
timerAlarmWrite(timer, 1000000, true); //タイマー1秒割り込み(80000000(クロック周波数) / 80(分周比) = 1000000Hz(=1カウントで1μs))
init_LCD(); //LCD初期化
lcdwriteData("Booting now...");
delay(2000);
wifiConnect(); //WiFi接続処理
delay(2000);
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData("MENU SELECT");
lcdwriteCommand(0x40+0x80); //2行目へカーソル移動
lcdwriteData("01_TIME MODE");
lcd_menu_select = 1; //現在時刻表示モード
//attachInterrupt(Tac_SW1, mesure_change, RISING); //タクトスイッチを押すとBME280計測開始or終了外部割り込み有効
attachInterrupt(Tog_SW, wifiFlag, CHANGE); //トグルスイッチの切り替えごとにWiFi接続外部割り込み有効
}
/****************************初期設定 ****************************/
/****************************メイン本文*****************************/
void loop() {
//前ボタン(Tac_SW1)が押されたら
if(digitalRead(Tac_SW1) == HIGH){
//ボタンが離されるまでループ
while(1){
delay(100);
if(digitalRead(Tac_SW1) == LOW){
break;
}
}
delay(100); //チャタリング防止
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData("MENU SELECT");
lcdwriteCommand(0x40+0x80); //2行目へカーソル移動
switch(lcd_menu_select){ //lcd_menuの値に応じて表示文字分け
case 1: //現在表示メニューが「01_TIME MODE」の場合
lcdwriteData("03_IR MODE");
lcd_menu_select = 3; //メニューセレクト更新(赤外線受信モード)
break;
case 2: //現在表示メニューが「02_BME280 MODE」の場合
lcdwriteData("01_TIME MODE");
lcd_menu_select = 1; //メニューセレクト更新(現在時刻表示モード)
break;
case 3: //現在表示メニューが「03_IR MODE」の場合
lcdwriteData("02_BME280 MODE");
lcd_menu_select = 2; //メニューセレクト更新(温湿度気圧測定モード)
break;
}
}
//次ボタン(Tac_SW2)が押されたら
if(digitalRead(Tac_SW2) == HIGH){
//ボタンが離されるまでループ
while(1){
delay(100);
if(digitalRead(Tac_SW2) == LOW){
break;
}
}
delay(100); //チャタリング防止
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData("MENU SELECT");
lcdwriteCommand(0x40+0x80); //2行目へカーソル移動
switch(lcd_menu_select){ //lcd_menuの値に応じて表示文字分け
case 1: //現在表示メニューが「01_TIME MODE」の場合
lcdwriteData("02_BME280 MODE");
lcd_menu_select = 2; //メニューセレクト更新(温湿度気圧測定モード)
break;
case 2: //現在表示メニューが「02_BME280 MODE」の場合
lcdwriteData("03_IR MODE");
lcd_menu_select = 3; //メニューセレクト更新(赤外線受信モード)
break;
case 3: //現在表示メニューが「03_IR MODE」の場合
lcdwriteData("01_TIME MODE");
lcd_menu_select = 1; //メニューセレクト更新(現在時刻表示モード)
break;
}
}
//決定ボタン(Tac_SW3)が押されたら
if(digitalRead(Tac_SW3) == HIGH){
//ボタンが離されるまでループ
while(1){
delay(100);
if(digitalRead(Tac_SW3) == LOW){
break;
}
}
delay(100); //チャタリング防止
lcd_menu_decision = true; //メニュー決定フラグON
}
//トグルスイッチが操作されたら
if(Tog_Flag){
lcd_cdata1 = lcd_bdata1; //LCD表示用文字を一時保存(1行目)
lcd_cdata2 = lcd_bdata2; //LCD表示用文字を一時保存(2行目)
delay(100); //チャタリング防止
detachInterrupt(Tog_SW); //外部割り込み禁止
wifiConnect(); //WiFi接続処理
Tog_Flag = !Tog_Flag; //トグルスイッチ割り込みフラグ反転
attachInterrupt(Tog_SW, wifiFlag, CHANGE); //外部割り込み再開
//直前に表示していた文字を再表示
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData(lcd_cdata1);
lcdwriteCommand(0x40+0x80); //2行目へカーソル移動
lcdwriteData(lcd_cdata2);
}
//決定ボタン(Tac_SW3)が押されてメニューが選択されたら
if(lcd_menu_decision){
switch(lcd_menu_select){ //lcd_menuの値に応じて表示文字分け
case 1: //選択メニューが「01_TIME MODE」の場合
time_mode(); //現在時刻表示
break;
case 2: //選択メニューが「02_BME280 MODE」の場合
bme280_mode(); //温湿度気圧
break;
case 3: //選択メニューが「03_IR MODE」の場合
ir_mode(); //赤外線送受信
break;
}
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData("Finishjing...");
lcd_menu_decision = false; //メニュー決定リセット
delay(2000);
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData("MENU SELECT");
lcdwriteCommand(0x40+0x80); //2行目へカーソル移動
switch(lcd_menu_select){ //lcd_menuの値に応じて表示文字分け
case 1: //現在表示メニューが「01_TIME MODE」の場合
lcdwriteData("01_TIME MODE");
lcd_menu_select = 1; //メニューセレクト更新(現在時刻表示モード)
break;
case 2: //現在表示メニューが「02_BME280 MODE」の場合
lcdwriteData("02_BME280 MODE");
lcd_menu_select = 2; //メニューセレクト更新(温湿度気圧測定モード)
break;
case 3: //現在表示メニューが「03_IR MODE」の場合
lcdwriteData("03_IR MODE");
lcd_menu_select = 3; //メニューセレクト更新(赤外線受信モード)
break;
}
}
}
/****************************メイン本文*****************************/
/*************************現在時刻表示処理*************************/
void dateDisplay() {
getLocalTime(&timeInfo);//tmオブジェクトのtimeInfoに現在時刻を入れ込む
date_string = "DATE " + String(timeInfo.tm_year + 1900) + "/" + String(timeInfo.tm_mon + 1) + "/" + String(timeInfo.tm_mday); //日付をString型に変換
time_string = "TIME " + String(timeInfo.tm_hour) + ":" + String(timeInfo.tm_min) + ":" + String(timeInfo.tm_sec); //時刻をString型に変換
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData(date_string); //日付を表示
lcdwriteCommand(0x40+0x80); //2行目へカーソル移動
lcdwriteData(time_string); //時刻を表示
}
/*************************現在時刻表示処理*************************/
/****************WiFi接続トグルスイッチ外部割り込み処理****************/
void wifiFlag() {
Tog_Flag = !Tog_Flag; //トグルスイッチ割り込みフラグ反転
}
/****************WiFi接続トグルスイッチ外部割り込み処理****************/
/****************BME280計測モード終了外部割り込み処理****************/
void bme280mode_finish() {
Mode_finish = !Mode_finish; //BME280計測モード終了フラグ反転
}
/****************WiFi接続トグルスイッチ外部割り込み処理****************/
/*************************WiFi接続処理*************************/
void wifiConnect() {
delay(500); //チャタリング防止
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
if(digitalRead(Tog_SW) == HIGH){ //WiFi接続SWがONなら
WiFi.begin(ssid, password); //Wi-Fiへの接続処理
while (WiFi.status() != WL_CONNECTED) { //WiFiに接続されるまで待機
delay(500);
}
ip = WiFi.localIP(); //ESP32のIPアドレスを取得
ip_string = "IP:" + String(ip[0]) + "." + String(ip[1]) + "." + String(ip[2]) + "." + String(ip[3]); //ESP32のIPアドレスをString型へ変換
lcdwriteData("WiFi Connect OK"); //起動OKの表示
lcdwriteCommand(0x40+0x80); //2行目へカーソル移動(0x40 = 2行目先頭文字アドレス、0x80 = DDRAMアドレスへの移動)
lcdwriteData(ip_string); //IPアドレスの表示
delay(1000);
//configTime(オフセット時間[s] = 標準時 + 9h * 3600、サマータイム 0:無,1:有、ntpサーバー設定)
configTime(9 * 3600L, 0, "ntp.nict.jp", "time.google.com", "ntp.jst.mfeed.ad.jp"); //時刻取得用のNTPの設定
server.begin(); //サーバー起動
Wifi_Flag = true; //WiFiフラグ切り替え
}else{ //WiFi接続SWがOFFなら
lcdwriteData("WiFi Connect NG"); //WiFi接続NGの表示
if(Wifi_Flag) { //WiFi接続SWがONからOFFになった時
server.stop(); //サーバー停止
WiFi.disconnect(); //WiFi接続停止
/* タイマー割り込み停止操作 */
interruptCounter --; //割り込みカウントリセット
timerAlarmDisable(timer); //タイマー停止
/* タイマー割り込み停止操作 */
delay(1000);
Wifi_Flag = !Wifi_Flag; //WiFiフラグ切り替え
}
}
}
/*************************WiFi接続処理*************************/
/**************************BME280測定**************************/
void bme_get(){
double temperature = bme280spi.Read_Temperature(); //温度を取得
double humidity = bme280spi.Read_Humidity(); //湿度を取得
double pressure = bme280spi.Read_Pressure(); //気圧を取得
//LCDへ各値を表示
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData("T=" + String(temperature, 1) + "C ");
lcdwriteData("H=" + String(humidity, 1) + "%");
lcdwriteCommand(0x40+0x80); //2行目へカーソル移動
lcdwriteData("P=" + String(pressure, 1) + "hPa");
}
/**************************BME280測定**************************/
/*************************測定モード変更*************************/
void mesure_change(){ //タクトスイッチが押されたら
time_now = millis(); //現在の割り込み時刻を取得
if( time_now-time_prev > time_chat){ //前回の割り込みから500[ms]以上経過ならば
Mesure_Flag = !Mesure_Flag; //測定フラグ反転
Mode_Flag = !Mode_Flag; //モードフラグ反転
}
time_prev = time_now; //現在の割り込み時刻を前回の割り込み時刻へコピー
}
/*************************測定モード変更*************************/
/*************************01_TIME MODE*************************/
void time_mode(){
if(digitalRead(Tog_SW) == LOW){
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData("WiFi Connect NG");
delay(2000);
return;
}
timerAlarmEnable(timer); //タイマー起動
while(digitalRead(Tog_SW) == HIGH){ //Tog_SWがOFFになるまで繰り返し
if(interruptCounter > 0) { //タイマー割り込みされれば
interruptCounter --; //割り込みカウントリセット
dateDisplay(); //ネットから取得した現在時刻を表示
}
if(digitalRead(Tac_SW1) == HIGH){ //モード終了ボタンが押されたら終了
break;
}
}
//タイマー割り込み停止操作
interruptCounter --; //割り込みカウントリセット
timerAlarmDisable(timer); //タイマー停止
delay(100); //チャタリング防止
}
/*************************01_TIME MODE*************************/
/************************02_BME280 MODE************************/
void bme280_mode(){
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData("BME280");
lcdwriteCommand(0x40+0x80); //2行目へカーソル移動
lcdwriteData("Mesure Wating"); //測定待ちの表示
attachInterrupt(Tac_SW3, mesure_change, RISING); //タクトスイッチ3を押すと計測開始or終了の割り込み有効
attachInterrupt(Tac_SW1, bme280mode_finish, RISING); //タクトスイッチ1を押すとモード終了
while(!Mode_finish){ //モード終了ボタンが押されたら終了
if(Mode_Flag){ //測定モード変更スイッチが押されたら
if(Mesure_Flag){ //計測開始の場合
//LCDへ表示
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData("Mesure START"); //測定待ちの表示
Mode = 3; //計測モードを繰り返し測定に変数指定
}else{ //計測終了の場合
//LCDへ表示
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData("Mesure STOP"); //測定待ちの表示
Mode = 0; //計測モードをスリープ状態に変数指定
}
uint8_t ctrl_meas = (osrs_t << 5) | (osrs_p << 2) | Mode; //測定条件レジスタに書き込む内容を入力
bme280spi.WriteRegister(0xF4, ctrl_meas); //測定モード変更レジスタ(ctrl_meas 0xF4)へモード変更を書き込み
Mode_Flag = false; //モード変更フラグリセット
}
while(Mesure_Flag & !Mode_Flag & !Mode_finish){ //計測開始になれば
delay(5000); //5秒毎に表示
bme_get(); //各値を取得しシリアルモニター&LCDへ出力
}
}
//各フラグ初期値設定
Mesure_Flag = false; //BME280計測開始ボタン割り込みフラグ初期設定
Mode_Flag = false; //BME280計測モード変更フラグ初期設定
Mode_finish = false; //BME280計測モード終了フラグ初期設定
Mode = 0; //計測モードをスリープ状態初期設定
//外部割り込み禁止
detachInterrupt(Tac_SW1);
detachInterrupt(Tac_SW3);
}
/************************02_BME280 MODE************************/
/**************************03_IR MODE**************************/
void ir_mode(){
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData("IR Wating");
while(digitalRead(Tac_SW1) == LOW){ //タクトスイッチ1を押すとモード終了
if (irrecv.decode(&results) & recv_pms_flag) { //赤外線受信および受信許可モードになれば
maker_code = results.decode_type; //メーカーコード取得
recv_code = resultToHexidecimal(&results); //赤外線受信データを16進数で取得
recv_bits = results.bits; //受信データの総Bit数を取得
recv_onoff_bits = getCorrectedRawLength(&results); //受信データのON/OFF切り替え回数を取得
for(int i=1; i < recv_onoff_bits + 1; i++){ //受信ONOFFデータを格納
rawData[i-1] = results.rawbuf[i] * kRawTick;
}
if (hasACState(maker_code)) { //メーカーコードがACだった場合
recv_state_bits = recv_bits / 8; //赤外線受信データの分割ビット数を格納
for(int i = 0; i < recv_state_bits; i++) { //AC受信データ格納
samsungState[i] = char(results.state[i]);
}
}else{ //メーカーコードがAC以外だった場合
recv_data = results.value; //データを取得
}
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData("RECIEVED");
lcdwriteCommand(0x40+0x80); //2行目へカーソル移動
lcdwriteData(typeToString(maker_code,false)); //メーカーコードを表示
delay(2000);
recv_pms_flag = false; //赤外線受信許可フラグOFF
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData("Reception");
lcdwriteCommand(0x40+0x80); //2行目へカーソル移動
lcdwriteData("Prohibited");
}
if(digitalRead(Tac_SW3) == HIGH){ //赤外線データ送信ボタン(Tac_SW3)が押されたら
delay(500); //チャタリング防止
if (recv_pms_flag){
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData("Data Nothing");
}else if (hasACState(maker_code)) { //メーカーコードがACだった場合
irsend.send(maker_code, samsungState, recv_state_bits); //AC送信データコード(メーカーコード、Stateデータ、Stateビット数)
}else{ //メーカーコードがAC以外だった場合
//SHARPのテレビ電源OFF後、1分ちょい開くと1度のデータコード送信だと電源が入らないので、常時リーダーコードを頭につけて送信する
irsend.sendRaw(rawData,2,38); //赤外線のデータコードを38kHz帯で送信
delay(10); //1つの送信データは「リーダー部+8ms以上off」が必要なので10ms待つ
irsend.send(maker_code, recv_data, recv_bits, 0); //AC以外送信データコード(メーカーコード、送信データ、送信ビット数、リピート回数)
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData("Data Send");
}
}
if(digitalRead(Tac_SW2) == HIGH){ //赤外線受信許可ボタン(Tac_SW2)が押されたら
delay(500); //チャタリング防止
recv_pms_flag = true; //赤外線受信許可フラグON
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
lcdwriteData("Reception");
lcdwriteCommand(0x40+0x80); //2行目へカーソル移動
lcdwriteData("Permited");
}
}
//赤外線送受信モード終了
recv_pms_flag = true; //赤外線受信許可フラグ初期化
delay(500); //チャタリング防止
}
/**************************03_IR MODE**************************/
/*******************データ書き込み(複数byte)*******************/
void lcdwriteData(String t_data){
int m_count = t_data.length(); //送信データの文字数をカウント
//全文字を表示
for(int i=0;i<m_count;i++){
Wire.beginTransmission(LCD_ADRS); //LCDをI2Cスレーブとして通信開始([slave address])
Wire.write(0x40); //最終データ、LCDへの表示データ([control byte] = 8bit目 0:最終,1:連続、7bit目 0:命令,1:表示データ)
Wire.write(t_data[i]); //1文字をキューに格納
Wire.endTransmission(); //キューに格納されたデータを送信してI2C通信停止
}
if(lcd_bcommand == 0x40+0x80){ //2行目のデータなら
lcd_bdata2 = t_data; //2行目のLCD文字を保存
}
else{
lcd_bdata1 = t_data; //1行目のLCD文字を保存
}
}
/*******************データ書き込み(複数byte)*******************/
/*******************コマンド書き込み(1byte)*******************/
void lcdwriteCommand(byte t_command){ //(書き込み順 = [slave address] + [control byte] + [data byte] )
Wire.beginTransmission(LCD_ADRS); //LCDをI2Cスレーブとして通信開始([slave address])
Wire.write(0x00); //最終データ、LCDへの命令([control byte] = 8bit目 0:最終,1:連続、7bit目 0:命令,1:表示データ)
Wire.write(t_command); //命令文を送信([data byte])
Wire.endTransmission(); //I2C通信停止
delay(10); //10ms待つ
lcd_bcommand = t_command; //最新コマンドを保存
if(lcd_bcommand == 0x01){ //液晶文字クリアコマンドなら最新LCD表示文字データを初期化
lcd_bdata1 = "";
lcd_bdata2 = "";
}
}
/*******************コマンド書き込み(1byte)*******************/
/*************************LCD初期化*************************/
void init_LCD(){
delay(100); //電源ON後40ms以上待つ
//[Function set] = 5bit目 0:4ビット,1:8ビット、4bit目 0:1行,1:2行、3bit目 フォントサイズ(0でOK)、1bit目 0:通常状態,1:以降拡張コマンド入力
lcdwriteCommand(0x38); //8ビット、2行表示、5×8ドット、通常状態([Function set])
delay(20); //26.3μs以上待つ(「lcdwriteCommand」で10ms待つためなくてもOK)
lcdwriteCommand(0x39); //8ビット、2行表示、5×8ドット、以降拡張コマンド入力([Function set])
delay(20); //26.3μs以上待つ(「lcdwriteCommand」で10ms待つためなくてもOK)
//[Internal OSC frequency] = 4bit目 0:1/5バイアス電圧,1:1/4バイアス電圧、3〜1bit クロック周波数[kbits/s]
lcdwriteCommand(0x14); //1/5バイアス電圧、クロック周波数100kbit/s(標準)([Internal OSC frequency])
delay(20); //26.3μs以上待つ(「lcdwriteCommand」で10ms待つためなくてもOK)
//[Contrast set] = 4〜1bit コントラスト64段階調整([Power/ICONcontrol/Contrast set]と併せて設定)
lcdwriteCommand(0x73); //コントラスト設定([Contrast set])
delay(20); //26.3μs以上待つ(「lcdwriteCommand」で10ms待つためなくてもOK)
//[Power/ICONcontrol/Contrast set] = 4bit目 0:アイコン無,1:アイコン有(このLCDにはアイコンがないため0で設定)、3bit目 0:ブースターON(3.3V時),1:ブースターOFF(5V時)、
// 2〜1bit コントラスト64段階調整([Contrast set]と併せて設定))
lcdwriteCommand(0x56); //アイコン無、ブースターON(3.3Vのため)、コントラスト設定(35)([Power/ICONcontrol/Contrast set])
delay(20); //26.3μs以上待つ(「lcdwriteCommand」で10ms待つためなくてもOK)
//[Follower control] = 4bit目 0:フォロア回路OFF,1:フォロア回路ON、3〜1bit 増幅率の設定(0〜7)
lcdwriteCommand(0x6C); //フォロア回路ON、増幅度6([Follower control])
delay(500); //200ms以上待つ
lcdwriteCommand(0x38); //8ビット、2行表示、5×8ドット、通常状態(拡張コマンド入力終了)([Function set])
delay(20); //26.3μs以上待つ(「lcdwriteCommand」で10ms待つためなくてもOK)
lcdwriteCommand(0x01); //LCD液晶文字クリア([Clear Display])
delay(20); //26.3μs以上待つ(「lcdwriteCommand」で10ms待つためなくてもOK)
//[Display ON/OFF] = 3bit目 0:文字表示OFF(RAM内のデータはそのまま),1:文字表示ON、2bit目 0:カーソル表示OFF,1:カーソル表示ON、
// 1bit目 0:ブランク表示OFF,1:ブランク表示ON
lcdwriteCommand(0x0F); //文字表示ON、カーソル表示ON、ブランク表示ON([Display ON/OFF])
delay(20); //26.3μs以上待つ(「lcdwriteCommand」で10ms待つためなくてもOK)
}
/*************************LCD初期化*************************/
次回記事予定
Xcodeを用いたiPhoneアプリ環境開発の構築