Aruduino UNOもどき(uno8)
しばらく休憩しているうちに多くを忘れてしまって、自分のページを見ても思い出せない状態です。復習を兼ねて遊び心でarduino IDEを使ってみようと思います。
ハードウエアはATmega328pを使って、8MHzのUNOでコンパイルしてavrのライターで書き込みます。このハードをuno8と名付けました。あまり見ていただく価値はないと思いますが…。
1 ハードウエアについて 2023.03.02
2 EEPROMのテスト 2023.03.02
3 mega328p内蔵EEPROM 2023.03.05
4 ステッピングモーター(バイポーラ)ドライバー 2023.03.09
5 I2Cスレーブの試行 2023.03.21
6 直流モーター PWM風 2023.04.07
1 ハードウエアについて 2023.03.02
MCU:ATmega328p clock:8MHz fuse:FF DF FD(boot256 bod2.7V)
LCD出力端子:1GND 2Vcc 3RS-D11 4E-D12 5d4-D7 6d5-D8 7d6-D9 8d7-D10
LiquidCrystal lcd(11, 12, 7, 8, 9, 10);
I2C出力端子:左から SCL SDA Vcc GND(2つとも)
スイッチ:左から reset D2(on=low)
LED:左赤=D13 右3色R=A1,G=A2,B=A3
周辺回路との関係で3.3Vで使います。UNOは16MHzですから3.3Vでは苦しくなります。boards.txtは8MHzのものを書きたしました。
ハードウエア その2
MCU:ATmega328p clock:8MHz fuse:FF DF FD(boot256 bod2.7V)
LCD出力端子:LiquidCrystal lcd(7,8,9,10,11,12);
2 EEPROMのテスト 2023.03.02
手持ちのeepromがあります。M24C64で64kbit(8kB)でI2Cで使うものです。このページに詳細なプログラムが書かれていましたのでほとんどそれを頂戴してテストしました。
左のものは以前にはんだ付けしたもので、今回は新たにピンを取り付けました。ピッチ0.65mmなので苦労しましたが。
アドレスの下位3ビットはすべてGNDに接続しています。
プログラムです。プログラムzipです。
8kBのデータを書き込むのに時間がかかります。1分程でしょうか。1バイト書き込みに6msのderayを入れています。書き込みに時間がかかるのと、eepromは書き込み回数に制限がある(10万回とか)ので、D2に接続したスイッチを押した状態でリセットすると書き込まずに読み出しだけができるようにしました。
8000個あまりのデータです。00からFFまで8個ずつ表示してそれを4回繰り返します。teratermで受けています。
3 mega328p内蔵EEPROM
mega328pは1024バイトのeepromを持っています。今までほとんど使ったことはなく、以前にmega48を使った温度計を作っったときに補正値を記録するために使用したことがあったくらいです。どのように書いたが忘れましたが今回arduinoで書き込んでみました。
ライブラリーEEPROM.hを使って、
EEPROM.write(addr, data); addr=eepromアドレス(int) data(byte)で書き込み、
data = EEPROM.read(addr); でデータを読み出します。
なお、回数に制限があるeepromの無駄な書き込みを防ぐための update(int address, uint8_t value); があるようです。書き込み時に読み出して値が同じであれば書き込まないそうです。
プログラムは上の外部eepromと同じようなものです。
4 ステッピングモーター(バイポーラ)ドライバー 2023.03.09
部品箱にTA8428KというHブリッジのモータードライバーICが2つありました。2つあればバイポーラステッピングモーターが回るはずだと思いarduinoで試してみることにしました。
最初はこのタイトルのUNOもどきで試したのですが、あまりにもプログラムサイズが小さいので手持ちのmega48で置き換えてみますと問題なく回りましたので最終的にはmega48で作ることにしました。mega48のarduino環境については後ほど書きます。
このモーターは廃品のプリンターから取り出したもので昔(2005年)に他のドライバーで試したものです。その時はスイッチで回転速度を変えていましたので最高回転を含めて広く速度を選択できるように可変抵抗で速度調整を行いたいと考えました。
コイルの切り替え周期をプログラムのdelay()で決めていますが、VRの電圧をアナログで読み取ってそれを50で割った値(ミリ秒)で決めています。最大で1024/50≒20ミリ秒のdelayとなっています。およその回転数は最大で毎秒2回転(これ以上は失調して回らない)、最小は毎秒1/4回転程です。電源の電流計(MAX 0.6A)では遅い回転ではメーターが振り切れ、ドライバーICがかなり熱くなります。最大回転の近傍ではスムーズに回り、電流は200mAほどに収まり、ICが熱くなることもありません。
裏面の写真はありませんが、配線の大部分は裏面で行っています。今まで0.2mmUEWを使っていたのですが、今回は0.26mmUEWを使いました。線画太くなった分だけ剛性が強くなり収まり良くなりました。
回路図は次のとおりです。
プログラムです。
今回は収まるまでにいくつかのトラブルが有りました。
まずはブレッドボードです。使い込んだブレッドボードしかなかったのですが、一部に接触不良が発生していたようです。
動作が不安定でどこが悪いのか決定できません。それで、あまり使いたくない簡易型のブレッドボードに変更しました。
2つ目はモーター端子の配列です。4つの端子のうち1番と2番がAコイル、3と4がBコイルだと信じていました。1相励磁でも不思議な動きをしていたのですがもしやと思って測りますと1と3、2と4が2つのコイルとなっていました。
3つ目は、上記のトラブルが解決してから、ドライバICを繋がないときはMCUが正常にIO出力を出すのですが(LEDで調べました)、ドライバICをつなぐと信号が消えます。しばらく悩んだ末、もしやと思って電源に33μFのコンデンサを挿入すると正常な信号が出るようになりました。今まで大部分の工作で電解コンデンサを入れなくても動いていたので気が付かなかったのです。
mega48のarduino環境について
部品箱にいくつかのmega48があります。arduinoでこれが使えると便利だろうと思っていたのですが、mega48のboardを作ってくれた方がいます。GitHubのMCUdude/MiniCoreです。
このページで"json"で検索すると、https://mcudude.github.io/MiniCore/package_MCUdude_MiniCore_index.json が見つかりますのでこれをコピーして、arduinoの「ファイル」→「環境設定」→「追加のボードマネージャーのURAL」に書き込みます。続けて、ボードマネージャーを開き、スクロールしてMiniCoreのボードをインストールすると使えます。mega48ではbootloderが使えませんが、AVRに直接書き込む方法の私には問題はありません。
なお、このboardsはmega328、168、88、48の様々なボードに対応しているようです。
2023.03.11 一相励磁も試しました。電流値が半分になりドライバICgが熱くなることもなくなりました。トルク的にも使えそうです。 プログラム
2023.03.13 ボードにショートピンによる切り替えを付加して、一相励磁と二相励磁をプログラムで切り替えることにしました。
プログラムです。
5 I2Cスレーブの試行 2023.03.21
uno8をI2Cのスレーブにする実験をしました。
回路は2つのuno8の I2C-SCL同士、I2C-SDA同士、グランド同士をつなぎ共通の3.3V電源で行いました。
考え方は単純で、マスター側とスレーブ側にuint8_t型の配列 d[20] を設定して、マスター側から読み書き(互いのd[20]をコピーする)とうものです。マスターのライトルーチンでスレーブの配列に20個のデータを書き込み、リードルーチンでスレーブの配列をマスターにコピーします。
マスターとスレーブのプログラムは次のとおりとなりました。
マスター
/* name:i2c_master01
mcu:uno8 xtal:8MHz
compile;miniCore_328p
2023.03.21
*/
#include <Wire.h>
uint8_t d[20], val;
char s, ss;
void setup() {
Serial.begin(9600);
delay(500);
Serial.println("serial on");
Wire.begin();
}
void loop() {
Serial.println("");
Serial.println("--- M E N U -----");
Serial.println(" 1 write 2 read 1 or 2 ? ");
while (!Serial.available()) { ; } //シリアル入力待ち
while (Serial.available()) {
ss = (char)Serial.read();
}
if (ss == '1') {
writeE();
}
if (ss == '2') {
readE();
}
}
void readE() {
int i = 0;
Wire.beginTransmission(8); // スレーブアドレス=8(7bit)
//Wire.write(0); // inner address なし
Wire.endTransmission(false);
Wire.requestFrom(8, 20);
Serial.println("slave_register: ");
while (Wire.available() > 0) {
val = Wire.read();
d[i] = val;
Serial.print(val);
Serial.print(" ");
i++;
}
Serial.println(" ");
}
void writeE() {
int i = 0;
for (int j = 0; j < 20; j++) {
d[j] = 255;
}
Serial.println("input data 0--255,20data");
for (i = 0; i < 20; i++) {
Serial.print(i); Serial.print(":");
while (!Serial.available()) {;}
while (Serial.available()) {
d[i] = (uint8_t)Serial.parseInt(); //数値で取り込む
} Serial.println(d[i]);
}
Wire.beginTransmission(8);
//Wire.write(0);
for (int i = 0; i < 20; i++) {
Wire.write(d[i]);
}
Wire.endTransmission();
}
スレーブ
/* name:i2c_slave01
mcu:uno8 xtal:8MHz
compile;miniCore_328p
2023.03.21
*/
#include <Wire.h>
uint8_t slaveADR = 8;
uint8_t d[20];
void setup() {
Wire.begin(slaveADR);
Wire.onReceive(ReceiveE);
Wire.onRequest(SendE);
for (int i = 0; i < 20; i++) {
d[i] = 20 + i;
}
}
void loop() {
delay(300);
}
void ReceiveE(int j) {
int i = 0;
while (Wire.available()) {
if (i < 20) {
d[i] = Wire.read();
}
else {
Wire.read();
}
i = i + 1;
}
}
void SendE() {
for (int i = 0; i < 20; i++) {
Wire.write(d[i]);
//delay(100);
}
}
Wire.onReceive(ReceiveE);のレシーブルーチンはint型の引数を取らねばならないし、
Wire.onRequest(SendE);の送り出しルーチンは引数なしでないといけないようでした。
これを利用すると、マスターから指令を与えたり(スレーブでLCD表示など)、スレーブのデータを利用したり(センサーとして使うときなど)ができると思います。
6 直流モーター PWM風 2023.04.07
直流モーターを低速で使いたいと考え、PMWでコントロールしてはどうかと試してみました。
例によってUNOもどきで試行しましたがプログラムが小さいので最終はmega48となりました。
正規のPWMだと回転数は遅くなるのですが、同時にトルクも小さくなって使いにくいようです。試しに10msの周期でPWM制御するとなめらかには動くのですがトルクが小さくなりすぎます。
そこで、PWM制御と言うよりは回したり止めたりして回転数を落としONのときはやや時間を長くしてしっかり回転させる、という方法を考えました。
結果的には、周期100msでデューティを変えてコントロールします。ブルブルと振動しながらぎこちなく回りますがそこそこのトルクが得られるようです。
AD変換で可変抵抗の電圧を読み取り(0〜1024)、÷20で0〜50の値を得て、その値が20のとき、モーターONが20ms、OFFが80msとなるようにしています。
部品は手持ちのものを使いました。
細いエナメル線をミシンボビンに巻き取るときに使えそうです。
/*
name: moter_pwm01
mcu: mega48
MOTER drive
*/
int t ;
void setup() {
pinMode(8, OUTPUT);
pinMode(A0, INPUT);
}
void loop() {
while (1) {
t = analogRead(A0) / 20;
digitalWrite(8, HIGH);
delay(t);
digitalWrite(8, LOW);
delay(100 - t);
}
}
1 ハードウエアについて 2023.03.02