2020年6月5日金曜日

ATtiny85でOLED(SH1106 128x64 I2C)が使えてる(・o・)

OLEDシリーズも第3弾になりました!
すっかりハマっております^^;

目に止まったのが、このサイト
この8pinのIC、ひょっとしたらと思ったら
何と!
ATtiny85でOLED(SH1106 128x64 I2C)を使えてるのです。
OLEDは、RAMを大量消費するので無理かと思ってました。
「Tiny Graphics Library」ってのがあるようですね~
特別にライブラリをインストールするわけではなさそうです。
詳しい英文の解説が続いて、
最後の方に
「Tiny Graphic Library Program」部にスケッチへのリンクがあります。
このリンクはちと分かり難かった~
そのリンクのスケッチを開いて、全てコピーして
Arduino IDE Ver.1.8.3に貼り付けます。
取り敢えず、そのまま[検証・コンパイル]してみます。
設定は、これです。
お~っ!何事もなく無事コンパイルできました!
懸念してたグローバル変数の使用量は、10%です!
さて、作者David Johnson-Daviesさん使用の温度センサーは、
TMP37 20mV/℃、0mV at 0°C

マーティー手持ちの温度センサーも同じ様な TO-92 3pin
NSのLM35DZ、10mV/℃、0mV @0℃
温度センサーの計算式だけ変更すればいいハズです。
LM35DZは、0℃で0mV、100℃で1000mV

analogReference(INTERNAL1V1);
なので、基準電圧:1.1V
入力:1.1V の時にADC:1023になるので
100℃、1000mVの時、
・温度[℃]=(ADC値 ÷ 1023 x 1100mV)÷ 10mV/℃
                = ADC値 x 110 ÷ 1023
更に1目盛 0.5℃刻みなので
・温度[0.5℃刻み]= ADC値 x 110 ÷ 1023 x 2
                       = ADC値 x 220 ÷ 1023

ということで、スケッチを
*********
int Temperature = (analogRead(A2)*25)/233;

int Temperature = (analogRead(A2)*220)/1023;
*********
に変更します。

ATtiny85は、すっかりお気に入りになり
新品の生チップを10個、ここで調達しております。
US$ 12.31/10個(送料無料)

この設定にして、Arduino UNOの書込機でやるので
[書込装置:”Arduino as ISP”]です
新品の生チップは、
Clock:8MHz、Prescale Resister:1/8になってるので
最初に[ブートローダを書き込む]して
Fuse bitをセットする必要があります。
Fuse bitの書換が終ったら
スケッチを書き込みます。
書き込みも無事終わりました。
この時作ったArduino UNOの書込装置です。
ちなみに、14pinのソケットを新調しております^^;
US$ 1.01/2個(30% OFF)

配線して~
電源ON!
表示には数秒かかるという遅さで、
半世紀前のPC8001のBASICインタプリタを思いだしました^^;
ちゃんと表示されたと思いきや
ん?温度が表示されません(T_T)
あれっ? 15分経つと画面が真っ暗になってしまいました(-_-;)
電源入れ直すと、目盛りは、また表示されます。
スケッチを見直すと~
「int Temperature = (analogRead(A2)*220)/1023;」
の「analogRead(A2)*220」の最大時
intの最大 32767 < 1023 x 220 でオーバーフローしてました~(-_-;)
Y軸のTemperature値がオーバーフローすると止まるようです。
ということで、
オリジナルのセンサー 20mV/℃ から 10mV/℃への変更だけなので
元の式を単純に2倍することにして
int ⇒ unsigned int にして
65535 > 1023 x 25 x 2
なので、今度はオーバーフローしないハズです^^;
*********
int Temperature = (analogRead(A2)*25)/233;

unsigned int Temperature = (analogRead(A2)*25*2)/233;
*********

それと、15分間隔で24時間は、確認が大変なので
ひとまず、1.5秒間隔にします。
*********
while ((unsigned long) ((StartMins + millis()/60000)/15)%96 == SampleNo);
 ⇒
while ((unsigned long) ((StartMins + millis()/100)/15)%96 == SampleNo); 
*********

横軸 2.4分になりました。
途中、センサーを手で温めて山を作ってみました^^;
無事動作したので
横軸を24時間に戻して~
*********
while ((unsigned long) ((StartMins + millis()/100)/15)%96 == SampleNo);
 ⇒
while ((unsigned long) ((StartMins + millis()/60000)/15)%96 == SampleNo); 
*********

夜中の0時に始めるので
*********
const int Now = 1547;     // To set the time; eg 15:47

const int Now = 0000;
*********
にして、書き込んで開始です。
一晩様子を見たいと思います。
・・・朝8時、夜中の室温は、もう初夏なのであまり下がってないですね~
小型のリチウムイオン電池のモバイルバッテリーで放置してます。
12時間後
20時辺りの跳ね上がりは、夕食のために位置を移動してます。
こういうスタンドアローンのデータロガーもなかなか面白いですね~
結局、変更したのは、温度センサーだけですが、
一応、Google Driveのここに全スケッチを入れてます。
ここにLICENSE FREEのある免責事項が書いてあります。

ちょっとPlotの描画速度を測りたいと思います。
PB1(6pin)が空いてるので
setupに1行追加して
*********
void setup() {
  // initialize
 
pinMode(1, OUTPUT);  // PB1(pin6) for PlotDot時間確認用

*********

最高速にするため、while行をコメントアウトします。
*********
// Now start plotting the temperature every 15 mins
// while ((unsigned long) ((StartMins + millis()/60000)/15)%96 == SampleNo);

*********

PlotPointコードの後に「PINB |= 0b10;」を追加して
は、ADC完了毎にPB1をトグルしてます。
つまり、1dotプロットする毎にPB1を反転させます。
PB1のパルスの1/2が、ADCしてPlotPointする処理時間になります。
*********
PlotPoint(SampleNo+x1, Temperature-10+y1);
PINB |= 0b10;  // PB1反転

*********

CPU Clock 8MHz(internal)
PB1の波形を見ます。
1周期の1/2(HIGH or LOW期間)が1dotプロットする時間なので
2.1msec/dotってとこですね~
かなり遅いな~
1msecを軽く切ると思ってました。
では、CPU Clock 16MHz(PLL)
ちなみに、ATtiny85のCPU Clockを変更するには、
[16MHz(PLL)]にして
で、忘れるのはマーティーだけだと思うのですが
この[ブートローダを書き込む]を忘れないように実行してから
スケッチを書き込みます。
CPU Clock 16MHz(PLL)
1.9msec
ちょっとしか速くなりませんね~
ADC Clock 50KHzでも高々0.26msecのはずなので、
analogReadの時間が支配的だとも考え難いし~?
ATtiny85のDatasheetには、
ADC Clockは、CPU Clockに応じて決まると書いてあるだけですが
たぶん、
Clock   8MHzではPrescale   1/64でADC Clock 125KHz
Clock 16MHzではPrescale 1/128でADC Clock 125KHz
で13cycleだと0.104msecだと思われます。

では、CPU Clock 16MHzのまま
更に、ADCもコメントアウトして殺します。
forルーチン内はこれだけです。
*********
for (;;) {
    SampleNo = (SampleNo+1)%96;
// unsigned int Temperature = (analogRead(A2)*25*2)/223;
    unsigned int Temperature = 20;
    PlotPoint(SampleNo+x1, Temperature-10+y1);
    PINB |= 0b10;   // PB1反転
  }
*********

1.75msec(Clock 16MHz)
ADC有り1.9msecから0.15msec減ってるので
上のADC時間はほぼ正しいことになります。
ん~ん、IICの通信レートで決まるのかな~?
これをCPU Clock 8MHzでは、2msec
ADC有りでは、2.1msecだったので
やはりADC処理部は、0.1~0.15msecということになります。
整理すると
この差、つまりADCの有無の処理時間を波形で見ます。
*********
unsigned int Temperature = (analogRead(A2)*25*2)/223;

unsigned int Temperature = 20;
*********

PB1のパルスの1/2が、ADCとPlotPointする処理時間になります。
CPU Clock 8MHzのADC処理部の有り
CPU Clock 8MHzのADC処理部の無し

CPU Clock 16MHzのADC処理部の有り
CPU Clock 16MHzのADC処理部の無し
8MHz、16MHzともADC Clockは、自動的に125KHzだと考えられます。

I2C Clock Default 100KHzらしいので、400KHzにしてみます。
  Wire.begin();
の後に追加
  Wire.setClock(400000);
を追加して変更できるのですが、このATtiny85では変化なし(T_T)
  Wire.setClock(100000L); 
でも変化なし
  #define I2C_FASTMODE  1
も変化なし

これは、CPU Clock 16MHzのADC処理部の無し
I2C 400KHzにしたつもりですが、一つ上のショットと全く変わりありません。
どうやらATtiny85では、固定されてるようです。
ATmega328Pでは、TWI ModuleのBit Rate Generatorをいじってますね~
ATtiny85には、TWI Moduleがないので変化しないんですね。
で、どこだったか、こんな文章が!
「the default Arduino Wire() library does not support changes in bus speed or feature proper clock stretching support.」
・・・I2C speedは、変更できないのか~(T_T)

このSoftI2CMasterライブラリを使えばできるようですが、
またの機会にします^^;

ということで、
1dot 2msecとして、横100dotだと、200msecになるので
5Hzの1周期がReal Timeでサンプリングして表示できる速度です。
何に応用しようかな~?

最後に、Y軸の温度範囲を変更しようと思いましたが
画面ドットの座標は、この図の仕様で
これを8x8pixelに分割してProgram Memoryに格納して
Graphic Fontとして表示しています。
だからバッファ領域が不要なのですが、
データ作るのは、とても大変ですね~
汎用のツールがないので、自力でソフト組まないといけないのです。
Pythonで作れそうですが、マーティーにはちと重たいな~(-_-;)

もう一つ、同じ作者David Johnson-Davies氏の
これ、面白そうなんですが
ATtiny85のRAMでは、OLED 64x48が限界だそうで、
I/Fは、IICではなく、描画データ転送速度が速いSPIが必要らしいので
今回はできませんね~
さて、OLEDシリーズ第4弾に取り掛かるとします^^;

2 件のコメント:

昔青年 さんのコメント...

IOTばやりの時代です。第4弾はぜひそちら方向に発展させてください。
当方注文中のOLEDいまだ到着せず。��

マーティーの工房日誌 さんのコメント...

昔青年さん、全弾でコメントいただきありがとうございますm(_ _)m
IOTですか~
通信系はあまり得意じゃなくて...(-_-;)
ESP32なんちゃら辺りでServer化して面白そうなことできそうな気もするんですけどね~
ちなみに第4段は、大昔に宿題いただいてたタコメーターの予定で~す^^;