ESP-12F 手機雲端紅外線控制

學習如何學習!

設備與材料

個人電腦 × 1
手機× 1
ESP12F × 1
麵包板 × 1
紅外線發射器 模組 × 1
電晶體 × 1
電阻 22Ω× 1
電阻 100Ω× 1
連接線 若干

實體接線圖


PWM 相關函式

PWM可用接腳:ESP-12F 可以PWM輸出的接腳 D2(GPIO 4)、D5(GPIO 14)、D6(GPIO 12)、 D8(GPIO 15)

analogWriteFreq(new_frequency):改變 PWM 頻率,频率範圍100Hz-40KHz
例:analogWriteFreq(38000); //設定 PWM 頻率 38kHz 從示波器測量約38.4kHz

analogWrite(pin,val): pin接腳PWM輸出,工作週期 val/255
例:analogWrite(D6,127); //D6接腳 PWM輸出 工作週期 127/255

手機設定

這個專題是手機用 MQTT協定來控制 ESP-12F,必需有手機端的程式, 可以先參考 ESP12F 網路智慧開關(MQTT) 中的手機設定,下載安裝程式並開啟,左上功能選單可以進入MQTT connections 連線設定。按 + 可以新增控制面板,輸入 Name(名稱) 及 Description(描述) 按左上方 就可以新增我們的控制面板。

點進去,按 + 就可以新增控制元件了(如下左圖),選擇 “Button” 形式的控制元件,輸入 Name 並開啟 MQTT enable。

選擇要連線到之前設定的那個伺服器,在 “Topic for publish” 輸入你在 ESP12F 程式內訂閱的主題(a1b2c3d4e5f6/IRControl/set),如果程式有變動,這裡也要變動。按 “Button” 在 “Payload” 欄位輸入 P,表示這個按這個按鈕,程式會發佈 “P” 這個內容到 a1b2c3d4e5f6/IRControl/set 這個主題內。按”Icon“可以更改Icon圖樣,按左上方 就可以新增我們的控制元件。你自己要再新增 “鎖定”、”黑螢幕”等按鈕。記得 “Button” 的 “Payload” 欄位分別是 F 與 M。(按右上雙框ICON 可以調整位置)

設定好,就可以用手機遠端遙控投影機了。

範例程式

/*
 *  手機雲端紅外線控制
 *  開發工具 Arduino IDE 必需自行加入ESP12F 開發板
 *  開發板 ESP12F(ESP8266)   
 *  使用通訊協定 MQTT ,MQTT broker 使用 mqtt.eclipseprojects.io
 *  程式會訂閱 subTopic 設定的主題,只要有對此主題發佈內容P 就發射 電源的紅外線控制碼 
 *  F 就發射 螢幕鎖定的紅外線控制碼,M 就發射黑螢幕的紅外線控制碼 
 *  程式每1秒會發佈 1 到 pubTopic 設定的主題,可以用此判斷設備是不是在線上
 *  https://www.block.tw/blog
 */

// 引用 Wifi AP 程式庫(連上wifi無線AP用)
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
// 引用 Wifi  程式庫(連上網際網路用)
#include <WiFiClient.h>

//引用 MQTT 程式庫 需要自行安裝程式庫 https://github.com/knolleary/pubsubclient
#include <PubSubClient.h>

//宣告 wifi AP網路 連線物件
ESP8266WiFiMulti wifiMulti;

//宣告 wifi 網路連線物件
WiFiClient espClient;

//宣告 MQTT 連線物件
PubSubClient client(espClient);

#define   IR_send_pin   D6 

//紅外線發射 NEC 格式參數
#define   NEC_START_MARK  9000
#define   NEC_START_SPACE 4500
#define   NEC_ONE_MARK    550
#define   NEC_ONE_SPACE   1550
#define   NEC_ZERO_MARK   550
#define   NEC_ZERO_SPACE  600
#define   NEC_END_MARK    600
#define   NEC_END_SPACE   30000



//WIFI SSID 跟密碼
#define   APSSID  "你的wifi SSID"
#define   APPW    "wifi 密碼"

// MQTT mqtt.eclipseprojects.io 伺服器 不需要使用者名稱 密碼
// MQTT test.mosquitto.org 伺服器 不需要使用者名稱 密碼
// 所以每個人都能用,如果有人跟你有相同的主題(topic)就能控制你的設備
const char* brokerUser  = "";  //使用者名稱
const char* brokerPass  = "";  //使用者密碼
//const char* broker      = "test.mosquitto.org";
const char* broker      = "mqtt.eclipseprojects.io";
const char* pubTopic    = "a1b2c3d4e5f6/IRControl/state";
const char* subTopic    = "a1b2c3d4e5f6/IRControl/set";
byte        state       = 0;
char        msg[10]     ;
long        currentTime, lastTime;

unsigned char POWER[] = {0x83, 0x55, 0x90, 0x6F };
unsigned char FREEZE[] = {0x83, 0x55, 0x92, 0x6D };
unsigned char MUTE[] = {0x83, 0x55, 0x93, 0x6C };


void setup()
{
  pinMode(IR_send_pin,OUTPUT);      //設定 PWM接腳為輸出
  analogWriteFreq(38000);       //設定PWM頻率 38kHz
  pinMode(LED_BUILTIN, OUTPUT);
  //內建板上 LED 滅
  digitalWrite(LED_BUILTIN, HIGH);
  Serial.begin(115200);
  setupWiFi();
  client.setServer(broker, 1883);
  client.setCallback(callback);
}

void loop()
{
  if (!client.connected())
  {
    //連接 MQTT 伺服器
    MQTTconnect();
  }
  client.loop();
  currentTime = millis();
  
  //1秒發一次訊息
  if(currentTime - lastTime > 1000)
  {
    Serial.print("Sending messages:\t");        
    dtostrf(state, 1, 0, msg);             //byte 轉 char *
    Serial.println(msg);
    client.publish(pubTopic,msg);          //發佈
    lastTime = millis();
    
  }
   
}

//訂閱的主題有人發佈訊息時的處理函式
void callback(char* topic, byte* payload, unsigned int len)
{
  Serial.print("Received messages: ");
  Serial.println(subTopic);
  for (unsigned int i = 0; i < len; i++)
  {
    Serial.print((char) payload[i]);

    if (len == 1 && payload[0] == 'P'){
      //發射電源控制碼
      state=1;      
      NECsend(POWER, 4);      
      dtostrf(state, 1, 0, msg);    
      client.publish(pubTopic,msg);
    }else if (len == 1 && payload[0] == 'F'){
      //發射螢幕鎖定控制碼        
      state=1;
      NECsend(FREEZE, 4);            
      dtostrf(state, 1, 0, msg);    
      client.publish(pubTopic,msg);
    }else if (len == 1 && payload[0] == 'M'){
      //發射黑螢幕控制碼        
      state=1;
      NECsend(MUTE, 4);
      dtostrf(state, 1, 0, msg);    
      client.publish(pubTopic,msg);
      
    }
    
  }
  Serial.println();
}

//連接無線 wifi 的處理函式
void setupWiFi()
{
  delay(100);

  //連接無線 wifi 可以設定很多組
  wifiMulti.addAP(APSSID, APPW);
  wifiMulti.addAP("第2組wifi SSID","密碼");

  Serial.println("Wifi Connecting ...");

  //內建板上 LED 亮
  digitalWrite(LED_BUILTIN, LOW);

  while (wifiMulti.run() != WL_CONNECTED)
  {
    delay(250);
    Serial.print('.');
  }

  //內建板上 LED 滅
  digitalWrite(LED_BUILTIN, HIGH);

  Serial.println('\n');
  Serial.print("Connected to:\t");
  Serial.println(WiFi.SSID());

  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());
}


void MQTTconnect()
{
  while (!client.connected())
  {
    //連接 MQTT 伺服器,因為是免費無使用帳號跟密碼,所以底下隨便輸入的
    if (client.connect("MQTT_CLIENT_ID", "brokerUser", "brokerPass")) {
      Serial.print("\nConnected to ");
      Serial.println(broker);
      //訂閱主題
      client.subscribe(subTopic);
    } else {
      Serial.println("Connecting");
      delay(2500);
    }
  }
}

//NEC 格式的發射函式
void NECsend(unsigned char buf[], int len) {
  byte data;
  //啟始位元
  mark(NEC_START_MARK);
  space(NEC_START_SPACE);
  //資料位元
  for (byte i = 0; i < len; i++) {
    data = buf[i];
    //並列轉串列
    for (byte j = 0; j < 8; j++) {
      if ((1 << j & data)) {
        mark(NEC_ONE_MARK);        
        space(NEC_ONE_SPACE);
      } else {        
        mark(NEC_ZERO_MARK);
        space(NEC_ZERO_SPACE);
      }
    }
  }
  //結束位元
  mark(NEC_END_MARK);
  space(NEC_END_SPACE);
}

//紅外線接腳輸出38kHz方波 time us
void mark(int time) {
  unsigned long beginTime = micros();
  unsigned long endTime = (unsigned long)time;
  unsigned long nowTime = micros();
  analogWrite(IR_send_pin,127);
  while (nowTime - beginTime < endTime) {
    nowTime = micros();             
  }
  analogWrite(IR_send_pin,0);
}

//紅外線接腳低電位 time us
void space(int time) {  
  unsigned long beginTime = micros();           
  unsigned long endTime = (unsigned long)time;
  unsigned long nowTime = micros();             
  while (nowTime - beginTime < endTime) {
    nowTime = micros();                         
  }
}    

入門
知識
語法
流程
函式
實習

發佈留言