2018年12月9日日曜日

ESP32/arduino:LM3914 で LED レベルメータ を制御

目的:
 ボリューム/スライダ に LEDレベルメータ を連動させる。
方法:
 LM3914 を使用し、LED調光の値(=ボリューム/スライダの値) を DAC で電圧に変換してレベルメータを制御する。

 DAC は、GPIO 25,26 pin で使用可能。
 dacWrite(ピン番号, 出力値) ; でアナログ値を出力。
 出力値は 0~255 を設定する。( 8bit DAC )
 出力値 255 設定で およそ 3.3V を 出力。

 LM3914 は 3.3V 電源で使用。
 この場合、フルスケールは 1.3V (電源 -2V) での使用となる為、R2 を 0Ω として、フルスケールは 1.25V とする。
 この為、DAC に設定する 出力値は 0~100 ( 0V ~ 1.29V ) とする。
 ( ボリュームをいっぱいに回したときに全LED が点灯すれば OK 程度の 精度 )
    回路構成は、下図の様にした。(ESP32回り詳細は省略)
 

 スケッチ例は以下の通り。(「LED調光_WEBからと外付けのボリュームからを切り替えて調光」 にDAC出力を追加)


/*
 *    WiFi LED ON/OFF TEST
 *     PWM Control
 *     Volume control/Level meter
 */
 
#include <WiFi.h>
#include "FS.h"
#include <SPIFFS.h>
#include <Ticker.h>
#include <math.h>

//#define DEBUG

const char* ssid = "hogehoge";
const char* password = "hogehogepaswd";

IPAddress ip(192, 168, 1, 32);           // for fixed IP Address
IPAddress gateway(192,168, 1, 1);        //
IPAddress subnet(255, 255, 255, 0);      //
IPAddress DNS(192, 168, 1, 90);          //

WiFiServer server(80);

String html_1;
String resp_1;
byte led_brightness = 0 ;
char local_val[10]="checked" ;
char remote_val[10]="" ;
bool local = true ;
bool localen = false ;

Ticker ticker;
bool ticker_val = false ;
int vol_value = 0 ;
int loopcnt = 0;

void setup()
{
    Serial.begin(115200);
    SPIFFS.begin();          //SPIFFSを開始
    pinMode(2, OUTPUT);      // set the LED pin mode
    pinMode(25, OUTPUT);     // set the DAC pin mode

    WiFi.config(ip, gateway, subnet, DNS);   // Set fixed IP address
    delay(10);

    // We start by connecting to a WiFi network -----------------------------
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected.");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    
    server.begin();

    //index.htmlファイルの読み込み
    File index1 = SPIFFS.open("/test_pwm_vol.html", "r");
    if(!index1)
       Serial.println("file open failed");
    else{
      html_1 = index1.readString();    //index.htmlをstringで読み込み
      index1.close();     //ファイルを閉じる
    }

    //resp.htmlファイルの読み込み
    File index2 = SPIFFS.open("/resp_slid.html", "r");
    if(!index2)
       Serial.println("file open failed");
    else{
      resp_1 = index2.readString();    //index.htmlをstringで読み込み
      index2.close();     //ファイルを閉じる
    }      

    // for LED PWM Control ---------------------------------------------------
    ledcSetup(0, 5000, 13);        // setup channel 0 with frequency 5000 Hz, 13 bit precission for LEDC timer
    ledcAttachPin(2,0);            // attach pin 2 to channel 0
    ledcWrite(0, 0);               // initialize channel 0 to off     

    // for Ticker 
    ticker.attach_ms(100, execTicker) ; // 割り込み間隔と割り込み処理を設定。

}

void loop(){
  WiFiClient client = server.available();     // listen for incoming clients
  int pos ;
  int val = 0 ;
  int xhr ;
  String cmd = "" ;
  String htmlwk = "" ;
  String respwk = "" ;

  if (ticker_val) {  // フラグが true だったら、処理を実行。
     do_JOB() ;
  }

  if (client) {                                               // if you get a client,
    # ifdef DEBUG
        Serial.println("***** Client access start *****");       // print a message out the serial port
    #endif
    xhr = 0 ;
    while (client.connected()) {                              // loop while the client's connected
      if (client.available()) {                               // if there's bytes to read from the client,
        String line = client.readStringUntil('\n');           // Get Line data until '\n'
        # ifdef DEBUG
            Serial.println(line);
        #endif
        if ((pos= line.indexOf("GET /?remote")) != -1) {
          pos += 13 ;
          while(line.charAt(pos) !=' ') { 
            cmd += line.charAt(pos++) ;
          }
          if (cmd=="local") {
            local = true ;
            ticker.attach_ms(100, execTicker) ; // 割り込み間隔と割り込み処理を設定。
            strcpy(local_val,"checked") ;
            strcpy(remote_val,"") ;
          } else {
            local = false ;
            localen = false ;
            ticker.detach() ;    
            strcpy(local_val,"") ;
            strcpy(remote_val,"checked") ;
          }
        }
        if ((pos= line.indexOf("GET /?pol")) != -1) {
          xhr=1;
        }
        if ((pos= line.indexOf("GET /?slid")) != -1) {
          pos += 11 ;
          while((line.charAt(pos) >='0') & (line.charAt(pos) <='9')) { 
            cmd += line.charAt(pos++) ;
          }
          val = cmd.toInt() ;
          if (val>256) val = 255 ;
          led_brightness = (byte)val ;
          xhr=1;
        }
        if ((pos= line.indexOf("GET /?led_v")) != -1) {
          pos += 12 ;
          while((line.charAt(pos) >='0') & (line.charAt(pos) <='9')) { 
            cmd += line.charAt(pos++) ;
          }
          val = cmd.toInt() ;
          if (val>256) val = 255 ;
          led_brightness = (byte)val ;
        }
        if ((pos=line.indexOf("GET /?on")) != -1) {                 // Client request was "GET /?on" 
          led_brightness += 1 ;
        }
        if ((pos=line.indexOf("GET /?off")) != -1) {                // Client request was "GET /?off"
          led_brightness = 0 ;
        }
        ledcWrite(0, 8191*led_brightness/255) ;                  // set PWM value to channel#0
        dacWrite(25, led_brightness*100/255) ;

        if (line.length() == 1 && line[0] == '\r'){           // end of HTTP request
          if (xhr == 0) {
            htmlwk = html_1 ;
            htmlwk.replace("$led_brightness",String(led_brightness)) ;
            Serial.print("radio_local = ");
            Serial.println(local);
            Serial.print("brightness  = ");
            Serial.println(led_brightness);
            htmlwk.replace("$checked_lo",local_val) ;
            htmlwk.replace("$checked_rm",remote_val) ;
            send_html(client,htmlwk) ;                             // send response to client
          } else {
            respwk = resp_1 ;
            respwk.replace("$led_brightness",String(led_brightness)) ;
            send_html(client,respwk) ;                             // send response to client
            # ifdef DEBUG
                Serial.print("xhr value :"); Serial.println(led_brightness);
            #endif
          }
          break;                                              // break while loop
        }
      }
    }
    delay(1);                                        // give the web browser time to receive the data
    // close the connection:
    client.stop();
    //
    # ifdef DEBUG
        Serial.println("Client Disconnected.");
        Serial.println("--------------------------------------------------");
    #endif
  }
}

// ------------------------------------------------------------------

void send_html(WiFiClient client, String html ) {
    client.println("HTTP/1.1 200 OK");
    client.println("Content-type:text/html");
    client.println();

    client.print(html) ;

    # ifdef DEBUG
        Serial.println( " --- send html --- ");
    #endif
}

void execTicker() {
  ticker_val = true ;  // フラグを True にする。
}

void do_JOB() {
  // ... 実行したい処理 ...
  vol_value  = analogRead(A4);

  if (localen == true) {
    led_brightness = (byte) ((vol_value*255)/4095) ;
    ledcWrite(0, 8191*led_brightness/255) ;                  // set PWM value to channel#0
    dacWrite(25, led_brightness*100/255) ;
  } else  if (vol_value == 0)
    localen = true ;
        
  loopcnt++ ;
  if (loopcnt ==10) {
    Serial.println("") ;
    Serial.print( "A4 :") ; Serial.println(vol_value) ;
    loopcnt = 0;
  }
  ticker_val = false ;    // 処理を実行したら、フラグを false にする。
}

  変更部のポイントは、以下の通り。
  ( 行# 43 )
25ピンを出力用に定義。
  ( 行# 166 )
Remote 時 (Web から スライダーで制御時) に LED調光の設定と同時に レベルメータ用の出力を設定。
MAX時 (led_brightness = 255時)、100 となる様、値を調整。
  ( 行# 227 )
Local 時 (ボリュームで制御時) に LED調光の設定と同時に レベルメータ用の出力を設定。(Remote 時と同様)

その他は、「LED調光_WEBからと外付けのボリュームからを切り替えて調光」 と同じ。

0 件のコメント:

コメントを投稿