2023年11月28日火曜日

安いモータードライバー(TC1508)の使い方

 ■今日は一つ安いモータードライバーモジュールを紹介いたします。

  下記図の2台モーターコントロールできるものです。


■製品仕様:
 電源電圧:2V~10V
 信号電圧:1.8V~7V
 動作電流:~1.5A
 待機電流:<0.1uA
 製品サイズ:24.7*21*5mm
 重量:5g

■接続端子:

モーター接続端子MOTOR-A1つ目のモーターを接続する端子
MOTOR-B2つ目のモーターを接続する端子
電源端子+駆動用電源端子(2V~10V)
-GND端子
制御端子IN1
IN2
モーター①の制御用の端子。(回転方向を決める)
IN3
IN4
モーター②の制御用の端子。(回転方向を決める)
■制御:
ON/OFFのみの制御のほかPWM制御により回転スピードを変えることも出来ます。

■配線図:
下図はESP32の接続方法

■プログラム:
下記は1つモーターコントロール用サンプルプログラムです。
#define INT1 22
#define INT2 23

void setup() {
  Serial.begin(9600);
  pinMode(INT1, OUTPUT);
  pinMode(INT2, OUTPUT);
}

void loop() {
  // Forword INT1 H,INT2 L
  digitalWrite(INT1, HIGH);
  digitalWrite(INT2, LOW);
  delay(5000);

  // Back INT1 L,INT2 H
  digitalWrite(INT1, LOW);
  digitalWrite(INT2, HIGH);
  delay(5000);
}








ESP8266 ロボットカードライバサイト

■目的:

 携帯などでロボットカーの運転をコントロールために、

 ESP8266のAPモードで、コントロール用サイトを構築する。

 ソースは下記通り:

■プログラム:

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#define STATUS_FORWORD 1
#define STATUS_BACK 2
#define STATUS_LEFT 3
#define STATUS_RIGHT 4
#define STATUS_STOP 5
const char *ssid = "phoenix";  // WIFI名
const char *password = "12345678"; // パスワード
IPAddress local_ip(192,168,1,1);
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);
ESP8266WebServer server(8090);
int status = 0;
void setup() {
  Serial.begin(115200);
  WiFi.softAP(ssid, password);  // APモード
  WiFi.softAPConfig(local_ip, gateway, subnet);
  Serial.print("Access Point: ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.softAPIP());
  delay(100);
  server.on("/", handle_OnConnect);
  server.on("/forword", handle_forword);
  server.on("/back", handle_back);
  server.on("/left", handle_left);
  server.on("/right", handle_right);
  server.on("/stop", handle_stop);
  
  server.begin();
  Serial.println("HTTP server started");
}
void loop() {
  server.handleClient();
  op();
  delay(100);
}
void op() {
  switch (status) {
    case STATUS_FORWORD:
      Serial.println("forword");
      break;
    case STATUS_BACK:
      Serial.println("back");
      break;
    case STATUS_LEFT:
      Serial.println("left");
      break;
    case STATUS_RIGHT:
      Serial.println("right");
      break;
    case STATUS_STOP:
      Serial.println("stop");
      break;
    deault:
      break;
  }
}
void handle_OnConnect() {
  server.send(200, "text/html", SendHTML());
}
void handle_forword() {
  status = STATUS_FORWORD;
  handle_OnConnect();
}
void handle_back() {
  status = STATUS_BACK;
  handle_OnConnect();
}
void handle_left() {
  status = STATUS_LEFT;
  handle_OnConnect();
}
void handle_right() {
  status = STATUS_RIGHT;
  handle_OnConnect();
}
void handle_stop() {
  status = STATUS_STOP;
  handle_OnConnect();
}
String SendHTML() {
  String ptr = "<!DOCTYPE html> <html>\n";
  ptr += "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
  ptr +="<title>Robot Car Controller</title>\n";
  ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
  ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n";
  ptr +=".button {display: block;width: 120px;background-color: #1abc9c;border: none;color: white;padding: 13px 30px;text-decoration: none;font-size: 25px;margin: 0px auto 35px;cursor: pointer;border-radius: 4px;}\n";
  ptr +=".button-on {background-color: #1abc9c;}\n";
  ptr +=".button-on:active {background-color: #16a085;}\n";
  ptr +=".button-off {background-color: #34495e;}\n";
  ptr +=".button-off:active {background-color: #2c3e50;}\n";
  ptr +="p {font-size: 14px;color: #888;margin-bottom: 10px;}\n";
  ptr +="</style>\n";
  ptr +="</head>\n";
  ptr +="<body>\n";
  ptr +="<a class=\"button button-on\" href=\"/forword\">FORWORD</a>\n";
  ptr +="<a class=\"button button-on\" href=\"/back\">BACK</a>\n";
  ptr +="<a class=\"button button-on\" href=\"/left\">LEFT</a>\n";
  ptr +="<a class=\"button button-on\" href=\"/right\">RIGHT</a>\n";
  ptr +="<a class=\"button button-on\" href=\"/stop\">STOP</a>\n";
  
  ptr +="</body>\n";
  ptr +="</html>\n";
  return ptr;
}

2022年11月17日木曜日

熊ちゃんランプーー半田トレーニングその1

半田トレーニングとして、今回は熊ちゃんのランプを作りましょう。

完成品はこのようなものです。

■回路図

 

■基板

メイン基板

LED基板

■パーツリスト

抵抗

680KΩ*1、220KΩ*1、2.2Ω*1

R1,R2,R3

汎用整流用ダイオード

1N4007*4

D1,D2,D3,D4

LED

3mm赤*1

LED

LED

5mm白*12

LED1~LED12

フィルムコンデンサ

334/400V*1

C1

スイッチ

*1

K1

蓄電池

*1

 

基板

*2

 

ランプシェル

セット*1


■作り方
・LED用基板の半田付け
  上図ように半田付けします。
  要注意:LEDの足が長い方がプラスです。
・LEDのシェルの組み合わせ
  上図のように、LEDのシェルをねじでしっかり固定しましょう。
・メイン基板の半田付け
  パーツ一覧での記号と合わせて、各パーツを半田付けしましょう。
  要注意:
   ダイオードで、白いバーがある端はマイナス
   半田付け時、抵抗などの小さいパーツを先につけます
   B+、B-は蓄電池とつながります
   L+、L-はLED基板とつながります
   AC1、AC2はプラグとつながります
・メイン基板をねじで固定します
・最後の模様
  出来上がりました!!!
  直接110Vで充電ができます。。。
  あどは、点灯。。。

2022年8月16日火曜日

SCCBバスプロトコル詳解と実装方法

 ■SCCB紹介

 SCCB (Serial Camera Control Bus) は、OmniVision社のシリアル カメラ バス プロトコルです。OV7670 などの OV で始まるカメラ モジュールは、SCCB プロトコルを使用します。I2C プロトコルと類似しているため、SIO_CSIO_DSCLSDAと呼びます。

 本文は2線式SCCBプロトコルの内容とプログラム実装を中心に解説します。

■回路図

 2線式SCCBに対して、SIO_CSIO_Dだけを接続すればよいです。

■プロトコルの内容とプログラム実装

2 線式 SCCB バス プロトコル解析

<1>送信開始フラグ: 送信 (データの読み取りまたは書き込み) ごとに、下図に従って SIO_C SIO_D に指定されたHIGH-LOWレベルを出力する必要があります。対応するレベルを受け取ると、Slaveは転送開始が判ります。次のように操作します。SIO_CHIGHのままでSIO_DHIGHからLOWに変換して、SIO_CLOWに戻ります。

void SCCB_Start(void) {

  SCCB_SDA = 1;

  SCCB_SCL = 1;

  delay_us(50);

  SCCB_SDA = 0;

  delay_us(50);

  SCCB_SCL = 0;

}

<2>送信完了フラグ:Slaveに送信完了を通知します。次のように操作します。SIO_CHIGHのままでSIO_DLOWからHIGHに変換します。 

void SCCB_Stop(void) {

  SCCB_SDA = 0;

  delay_us(50);

  SCCB_SCL = 1;

  delay_us(50);

  SCCB_SDA = 1;

  delay_us(50);

}

<3>伝送フェーズ

転送フェーズ(Transmission Phases)は、データ転送の基本単位です。9bitで構成しています、それぞれは、bit7bit09bit目のDon't careまたはNAです。Don't care ビットと NA ビットの意味は後で説明します。

<4>書き込み

Slave1バイトのデータを書き込みすることは1回書き込み操作と呼びます。1バイトのデータを書き込み時、SlaveID、対象レジスタ番号も伝える必要があるため、書き込み操作のプロセスは三つのフェーズ(Phase)が必要です。

フェーズ1SCCBプロトコルは複数のSlaveに転送ができるため、Slaveの番号が伝える必要があります。実際のIDアドレスは8bitで、bit7bit1Slaveの番号ですが、0127のトータル128Slaveに転送が可能です。bit0Slaveにデータを書き込み(0)か読み取り(1)かを示しています。9bit目はDon't careビット(上図Xのビット)です。例えば、OV7670の場合、Masterから 8bitのデータを受信した後、SIO_C=1の期間にSlaveSIO_DピンにLOWをセットします。この間、MasterSIO_Dのレベル情報を読み取って判断する、LOWレベルを読み取った場合は、Slaveはフェーズ1の最初8bitを正常受信したことを示して、送信は成功します。それ以外の場合、送信は失敗します。

フェーズ2:データが書き込まれるレジスタの番号をスレーブに送信します。レジスタの番号は、OVセンサーのデータシートに記載されています。レジスタの番号も 8bitのデータです。 同様に、フェーズ29bit目もDon't careビットであり、このbitの説明はフェーズ1と同じです。

フェーズ3:指定されたレジスタにデータを書き込みます。bit7bit0は、レジスタに書き込みたいデータです。9ビット目もDon't careビットです。

u8 SCCB_WR_Byte(u8 dat) { // 一つフェーズを書き込み

  u8 j, res;

  for (j = 0; j < 8; j++) {

    if (dat&0x80) SCCB_SDA = 1;

    else SCCB_SDA = 0;

    data<<=1;

    delay_us(50);

    SCCB_SCL = 1;

    delay_us(50);

    SCCB_SCL = 0;

}

SCCB_SDA_IN();  // 或いはpinMode(SDA, INPUT); Slaveは値をセット可能

delay_us(50);

SCCB_SCL = 1; // SCLHIGHにする、Slaveはデータを受信した後、SDALOW

delay_us(50);

if (SCCB_READ_SDA) res = 1;  // SDAHIGHの場合、送信失敗

  else res = 0;  // 送信成功

  SCCB_SCL = 0;

  SCCB_SDA_OUT(); // あるいは pinMode(SDA, OUTPUT);

  Return res;

}

三つフェーズを書き込みの関数:

u8 SCCB_WR_Reg(u8 reg, u8 data) {

  u8 res = 0;

  SCCB_Start();

  If (SCCB_WR_Byte(SCCB_ID)) res = 1; // OV7670の場合は0x42

  delay_us(100);

  if (SCCB_WR_Byte(reg)) res = 1;

  delay_us(100);

  if (SCCB_WR_Byte(data)) res = 1;

  SCCB_Stop();

  return res;

} 

<5>読み取り操作

Slaveのレジスタから 1 バイトのデータを読み取る時、次の 2 つのデータ送信プロセスが必要です。

2 フェーズ書き込み送信プロセス:MasterからSlave2フェーズを送信します。最初のフェーズは、スレーブの ID 番号を示します。 2 番目のフェーズは、スレーブのどのレジスタから読み取るかを示します。 

2フェーズ読み取り送信プロセス:Slaveからデータを読み取っています。フェーズ1は①のフェーズ1とほぼ同じですが、Slaveから読み取りから、bit01のほうをご注意ください。フェーズ2は転送データです。

したがって、SIO_Dにつながっているピンは入力モードに設定する必要があります。8bitのデータを読み取った後、データが正常に受信されたことをSlaveに伝えるために、Master1bitの応答信号(NA)Slaveに送信する必要があります。

NAを送信するために、MasterSIO_DHIGHにセットしたままで、SIO_CLOWからHIGHに変更してからLOWに戻る必要があります。

void SCCB_No_Ack(void) {

  delay_us(50);

  SCCB_SDA = 1;

  SCCB_SCL = 1;

  delay_us(50);

  SCCB_SCL = 0;

  delay_us(50);

  SCCB_SDA = 0;

  delay_us(50);

}

2フェーズを読み取り関数

u8 SCCB_RD_Byte(void) {

  u8 temp = 0, j;

  SCCB_SDA_IN();

  for (j = 8; j > 0; j--) {

    delay_us(50);

    SCCB_SCL = 1;

    temp = temp << 1;

    if (SCCB_READ_SDA) temp++;

    delay_us(50);

    SCCB_SCL = 0;

  }

  SCCB_SDA_OUT();

  return temp;

}

レジスタから読み取り関数:

u8 SCCB_RD_Reg(u8 reg) {

  u8 val = 0;

  SCCB_Start();

  SCCB_WR_Byte(SCCB_ID);

  delay_us(100);

  SCCB_WR_Byte(reg);

  delay_us(100);

  SCCB_Stop();

  

  SCCB_Start();

  SCCB_WR_Byte(SCCB_ID|0x01);

  delay_us(100);

  val = SCCB_RD_Byte();

  SCCB_No_Ack();

  SCCB_Stop();

  return val;

}

ここまで、SCCBのレジスタ読み取り操作とレジスタ書き込み操作の関数SCCB_RD_RegSCCB_WR_Regを実装しました。この二つ関数を利用して、OVセンサーの指定されたレジスタへのデータを読み取りしたり、書き込みしたり、センサーの初期化ができました。



2022年8月11日木曜日

PWMの理解ーーその2:ブザーで音楽

■周波数

PWMとは、Pulse Width Modulationの略で、波長のような制御を行います。

細かい部分で見ると、ONとOFFを一定間隔で繰り返しているだけです。

ここで周波数といった名前が登場しますが、ONの長さの事を指します。

ブザーにとっての周波数とは、ドレミの音階を指定することができることになります。

ESP32では、PWM制御の関数が用意されております。(ledcSetup、ledcAttachPin、ledcWriteTone)

■音階

音階は、「音を高低の順番に並べたもの」あり、音の高低は周波数で表します。

音は、周波数が半分になると1オクターブ低くなり、周波数が倍になると1オクターブ高くなります。

1オクターブには12の音があり(①ド、②ド#(レ♭)、③レ、④レ#(ミ♭)、⑤ミ、⑥ファ、⑦ファ#(ソ♭)、⑧ソ、⑨ソ#(ラ♭)、⑩ラ、⑪ラ#(シ♭)、⑫シ)、

その12の音は、隣り合う半音間での周波数の比率が同じです。(音階に対して等比数列的に増える)

音階と周波数の関係は下記サイトをご参照ください。

音階の周波数

■配線図

■プログラム

#define BUZZER_PIN 2              // ブザーのピン番号
#define BUZZER_CHANEL 0       // ブザーのチャネル番号
#define BEAT 250                   // 音の長さ(0.25秒間隔)
#define G3 196 // ソ3
#define C4 261.6 // ド4       1
#define D4 293.665 // レ4     2
#define E4 329.63 // ミ4      3
#define F4 349.228 // ファ4   4
#define G4 391.995 // ソ4     5
#define A4 440 // ラ4         6
#define B4 493.883 // シ4     7
#define C5 523.251 // ド5     i
void playTone(double tone, int num) {
  ledcWriteTone(BUZZER_CHANEL, tone);
  delay(BEAT * num);
}
void playTone(long tone) {
  playTone(tone, 2);
}
void playMusic() {
  // 1 2 3 1 | 1 2 3 1 | 3 4 5 - | 3 4 5 - |
  // 56543 1 | 56543 1 | 3 5 1 - | 3 5 1 -
  playTone(C4);
  playTone(D4);
  playTone(E4);
  playTone(C4);
  playTone(C4);
  playTone(D4);
  playTone(E4);
  playTone(C4);
  playTone(E4);
  playTone(F4);
  playTone(G4, 4);
  playTone(E4);
  playTone(F4);
  playTone(G4, 4);
  playTone(G4, 1);
  playTone(A4, 1);
  playTone(G4, 1);
  playTone(F4, 1);
  playTone(E4);
  playTone(C4);
  playTone(G4, 1);
  playTone(A4, 1);
  playTone(G4, 1);
  playTone(F4, 1);
  playTone(E4);
  playTone(C4);
  playTone(E4);
  playTone(G3);
  playTone(C4, 4);
  playTone(E4);
  playTone(G3);
  playTone(C4, 4);
}
void setup() {
  ledcSetup(BUZZER_CHANEL, 12000, 8);
  ledcAttachPin(BUZZER_PIN, BUZZER_CHANEL);
}
void loop() {
  playMusic();
  delay(1000);
}

シンプルロボットカーセットの使い方

■ マイコン :ESP3266-CH340  シンプルの案として、マイコンは安いESP8266-CH340開発ボードを選びました。該当マイコンもWIFI機能があります。  ドライバーダウンロード場所:    https://sparks.gogo.co.nz/ch340.html...