勝手な電子工作・・

勝手なオリジナル電子工作に関する記事を書きます

快速マイコンの Teensy4.xを使ってみる

f:id:a-tomi:20210319203954j:plain

米国のPJRC最新マイコン開発ボードである、Teensy4.0と4.1を試しています。高速・大容量でとてもいいと思います。

パフォーマンスはCoreMarkのベンチマークで圧倒的に高速。

f:id:a-tomi:20210319204558j:plain

中国生まれのESPを圧倒ですね。折柄、米中対立で?・・^^;

この小さなPCBによくもCortex-M7を搭載したものだと思います。しかも安いし。ただし、PJRCで直接買えば正価で安いのですが、EU向け以外は送料がかなりかさみます。日本ではRobotShop.comで買えば、日本法人があるのでそこそこの価格で入手できます(その他ではとんでもなく高価なのにびっくり)。とはいえ、いまだに品切れになりやすい状態。主な仕様は次のとおりですが、とにかく凄い。

f:id:a-tomi:20210319204908j:plain

通常は600MHzで動かしますが、オーバークロックで動かせばなんと1GHzを超える速度が可能です(その場合は冷却が必須ですが)。

使っていたTeensy3.5と比べても長足の進歩。ここ数年間はこの世界はESPに席巻されていたようでもあるし、これは大歓迎ですね。高速信号をとらえたりする用途もこれのみで楽にできそうです。

f:id:a-tomi:20210319205341j:plain

ハードウェアの作りの品質の良さは袋にまで及び "Assembled in USA"と誇らしげ(?)に書かれているのもいい感じですね。

次のPJRCのHP

https://www.pjrc.com/

から製品の情報をたどれば、使い方のチュートリアル等もしっかりあり、英語ではありますがとてもわかりやすく書かれています。

そして、ある時期のモデルからはArduino-IDEでの開発となりましたので楽ちんです。対応ライブラリーがまだ少ないのが少し残念ではありますが、勝手な電子工作としてはひるまずに使いたいマイコンです。

この記事ではTeensy4.0について簡単に紹介したいと思います。

f:id:a-tomi:20210319210820j:plain

これにIDEでプログラミングする際に、実行速度が指定できます。

f:id:a-tomi:20210319210913j:plain

0.9GHzからはクーリングが必須と書いてありますね。

600MHzだってハンパない速さです。これでどういう発熱をするのかを測ってみました。実行開始から10分後の発熱状況は次です。

f:id:a-tomi:20210319211146j:plain

室温25℃の机上で紙の上に置いて測りましたが、最高温度は46.7℃にちゃんと収まっています。ヘダーピンをつけてない状態ですが、つけてそれなりのソケットに刺せばさらに下がると思われ、安心しました。

このPCBは裏にもオプションがつけられるようになっています。

f:id:a-tomi:20210319211828j:plain

そのためヘダーピンをさっさととり付けるのがはばかられ、最初のうちはヘダーピンをつけずに接続してテストしていました(簡単・確実にブレッドボードにつける方法を考えついて^^。そのうちに別記事でご紹介しようと思います)。

まずは20x4のキャラクターLCD表示をしようとしましたが、Liquide Crystal_I2Cでコンパイルエラーがでます。その解決に回り道するのは時間が勿体ない^^;

I2Cデバイスの多くは、データシートをみながらライブラリーなしでコーディングしても簡単です。この場合は、前に次の記事に書いた通りで、確実に動くプロトコルがわかっています。

https://a-tomi.hatenablog.com/entry/2020/12/21/211852

そこに書いたとおり、20x4のI2C-4bit-LCDは、最小限で次のプロトコルを使えば簡単に動きます。

f:id:a-tomi:20210319213117j:plain

ついでにRTC(リアルタイムクロック)もつけますが、そもそもTeensyのこのモデルにはRTCが最初からついています。しかしそのクロックの維持のためにPCB自体にバッテリーをつけておく必要があるので、当面はそれを使わず単体のRTCをつなぎます。今回はRTCを読み込むだけですが、時間を更新する際の簡単な方法は、前に次の記事に書きました。

回路不要のかんたんなRTCライター:Arduinoで - 勝手な電子工作・・

今回のスケッチは次です(2021.3.20追記:LCDへのEdit方法を少し改善したV02に差し替えておきます)。

/************************************************************
       Teensy 4.0 RTC and LCD Test via I2C - V02
         using Wire library (i2c_t3 is no more compatible)
         (c) 2021 Akira Tominaga, All rights reserved.
        Revisions:
          Initial version V00; 3/6, 2021
          V01; LCD interfaces to Roll-your-own      3/7,2021
          V02: writeString instead of writeLine    3/20,2021
 ************************************************************/
#include "Wire.h"       // Teensy Wire library
#define sclP 19         // SCL pin 19
#define sdaP 18         // SDA pin 18
#define aLCD 0x27       // LCD I2C addr
#define aRTC 0x68       // RTC I2C addr
// for LCD I2C 20x4
#define wT 12           // microsec between bytes to LCD
#define fL 20           // full-length for one line
// for Real Time Clock DS3231
byte  vR[8];            // values in RTC format
int vI[8] = { 0, 0, 0, 0, 0, 0, 0, 0};  // RTC data area
#define mdI 0           // Initial mode
#define mds 1           // ss mode
#define mdm 2           // mm mode
#define mdh 3           // hh mode
#define mdW 4           // WW=Day-of-Week mode
#define mdD 5           // DD mode
#define mdM 6           // MM mode
#define mdY 7           // YY mode
char  strYMDhms[20];    // editting area for RTC values

void setup() { // *** Teensy 4.x setup() ***
  Wire.setSCL(sclP);
  Wire.setSDA(sdaP);
  Wire.begin();
  Serial.begin(9600);
  while (!Serial) {}
  Serial.println(F("\nStarting"));
  iL();                 // initialize LCD
  Serial.println(F("LCD initialized"));
  // write strings to LCD               // *V02
  wS(0, 0, F("* Teensy 4.x Test *"));   // *V02
  wS(0, 1, F("with Real Time Clock"));  // *V02
  wS(3, 3, F("by Akira Tominaga"));     // *V02
}

void loop() { // *** Teensy 4.x loop() ***
  getTime();            // get time
  sC(1, 2);             // set cursor (1,2)
  for (uint8_t m = 0; m < 19; m++) {
    wC(strYMDhms[m]) ; // write characters
  }
  delay(100);
}

/********************************************************
     User defined fumctions
 ********************************************************/
// LCD - application program interfaces
// *** iL() *** initialize LCD ***
void iL(void) {
  wA(0x00);
  delay(100);
  wA(0x34);
  wA(0x30);
  delay(5);
  wA(0x34);
  wA(0x30);
  delayMicroseconds(200);
  wA(0x34);
  wA(0x30);
  delayMicroseconds(200);
  wA(0x24);
  wA(0x20);
  delayMicroseconds(200);
  wA(0x24);
  wA(0x20);
  wA(0x84);
  wA(0x80);
  delayMicroseconds(200);
  wA(0x04);
  wA(0x00);
  wA(0xC4);
  wA(0xC0);
  delayMicroseconds(150);
  wA(0x04);
  wA(0x00);
  wA(0x14);
  wA(0x10);
  delay(2);
  wA(0x04);
  wA(0x00);
  wA(0x64);
  wA(0x60);
  delayMicroseconds(150);
  wA(0x08);
  delay(1);
}
// *** wS(column,row,string) *** write String (x,y,string) ***
void wS(uint8_t col, uint8_t row, String strC) { // *V02
  sC(col, row);         // set cursor to (x,y)
  uint8_t sLen = strC.length();
  Serial.print("("); Serial.print(col); Serial.print(",");
  Serial.print(row); Serial.print(") "); Serial.println(strC);
  if (col + sLen > fL) {
    Serial.println(F("*** Too long & truncated."));
    sLen = fL - col;    // shorten sLen to avoid line-over 
  }
  for  (uint8_t nChr = 0; nChr < sLen; nChr++) {
    wC(strC.charAt(nChr));
  }
}
// *** sC(column,line) *** set cursor to (x,y) ***
void sC(uint8_t Col, uint8_t Line) {
  uint8_t Pos;
  switch (Line) {
    case 0: Pos = 128 + Col; break;
    case 1: Pos = 192 + Col; break;
    case 2: Pos = 148 + Col; break;
    case 3: Pos = 212 + Col; break;
    default: Serial.println("Err for LCD line");
      while (true) {}
  }
  wA((Pos & 0xF0) | 0x0C);
  wA((Pos & 0xF0) | 0x08);
  wA(((Pos << 4) & 0xF0) | 0x0C);
  wA(((Pos << 4) & 0xF0) | 0x08);
  delayMicroseconds(wT);
}
// *** wC(char) *** write a character to LCD ***
void wC(byte Chr) {
  wA((Chr & 0xF0) | 0x0D);
  wA((Chr & 0xF0) | 0x09);
  wA(((Chr << 4) & 0xF0) | 0x0D);
  wA(((Chr << 4) & 0xF0) | 0x09);
  delayMicroseconds(wT);
}
// *** cS() *** clear LCD screen ***
void cS() {
  wA(0x0C);
  wA(0x08);
  wA(0x1C);
  wA(0x18);
  delay(1);
}
// for LCD control
// *** wA(byte) *** write an absolute byte to LCD ***
void wA(byte Abs) {
  Wire.beginTransmission(aLCD);
  Wire.write(Abs);
  Wire.endTransmission();
}

// Real Time Clock -  application program interfaces
// *** getTime() *** get RTC MMDD & hhmm into strMDhm
void getTime(void) {
  rRTC();             // read RTC device
  cR2I();             // convert RTC-format to Integers
  sprintf(strYMDhms, "20%02d-%02d-%02d %02d:%02d:%02d", vI[mdY], vI[mdM], vI[mdD], vI[mdh], vI[mdm], vI[mds]);
}
// for RTC control
// *** rRTC() *** read Real-Time-Clock
void rRTC(void) {
  Wire.beginTransmission(aRTC);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(aRTC, 7);
  while (Wire.available() < 7) {}  // wait for data
  for (int i = 1; i < 8; i++) {
    vR[i] = Wire.read();
  }
  Wire.endTransmission();
}
// *** cR2I() *** convert RTC-format to Integers
void cR2I(void) {
  vI[mds] = ((vR[mds] & B01110000) / 16) * 10 + (vR[mds] & B00001111);
  vI[mdm] = ((vR[mdm] & B01110000) / 16) * 10 + (vR[mdm] & B00001111);
  vI[mdh] = ((vR[mdh] & B00100000) / 32) * 20 + ((vR[mdh] & B00010000) / 16) * 10 + (vR[mdh] & B00001111);
  vI[mdW] = vR[mdW];
  vI[mdD] = ((vR[mdD] & B01110000) / 16) * 10 + (vR[mdD] & B00001111);
  vI[mdM] = ((vR[mdM] & B00010000) / 16) * 10 + (vR[mdM] & B00001111);
  vI[mdY] = ((vR[mdY] & B11110000) / 16) * 10 + (vR[mdY] & B00001111);
}
// *** End of program ***

 ブレッドボードの配線は主にI2Cだけですが、3.3V専用のTeensy4.0は5Vトレランシーがありません。よってI2C 信号レベルコンバーターをつけます。また、SCL, SDAを外部の4.7kオームでそれぞれプルアップします。次の写真のとおりです。

f:id:a-tomi:20210319222336j:plain

 I2Cプロトコルは相手デバイス(I2Cスレーブ)の都合上、Defaultのボーレート100kHzで動かしていますが、その他の実行部分の速さ(Loop内実行所用時間の短さ)は、当然とはいえびっくりするほど速いです。念のためにI2Cの様子を覗くと、次のように時間的な乱れ全くなしでキッチリと動いています。

f:id:a-tomi:20210319223213j:plain

 

今後、速度や容量が要る用途には、これをどんどん使っていこうと思います。

 

追記:最近の世界のGoogle検索量を調べると、マイコン開発ボードではESP32の人気がなんとArduino Unoよりも高い状態となっています。

f:id:a-tomi:20210606210851j:plain

ESP32はWiFiBluetoothを内蔵しているだけでなく、専用IDEなど開発環境が急速に充実しましたし、Arduino IDEへの対応も安定してきたのがその大きな理由かと推測。Teensy4.xも今後ぜひ躍進してほしいと思います。普及は、WiFi等の組込みというよりも、むしろ開発環境の進展次第かと勝手に思います。

 

以上、ごく簡単な紹介でしたが、なんらかのお役に立てば幸いです。

 

©2021 Akira Tominaga, All rights reserved.

続・入眠用MP3プレーヤーの製作(#4)

f:id:a-tomi:20210306154203j:plain

外出自粛でとかく運動不足。夜寝つきにくいことがあります。自作のスリープタイマー付きのMP3プレーヤーを使い始めてからは、30分のタイマーでつけておけば早く快適に眠れます。.夜中に目覚めても、また演奏を始めればOKです^^

つまり、思いのほか役にたっています!そして、家族のリクエストで追加を作りました。こちらは場所をとらないように、小サイズにカッコよく(?)まとめました(自画自賛)。自分用のは大きくて不格好のままでいいのですが^^;。3月はなにかと時間がとりにくい月ですが、週末が来たのでやっと記事に書きます。

「眠るための音楽」とか「快適に眠りにつく曲」とか「睡眠を誘う音楽」とか、適当な言葉でYouTubeを検索してみれば、そのための曲は今やてんこ盛りです^^; 今、世界中で需要が高いのでしょうかね。その中から自分に合いそうで、ダウンロード可能なものを選んでMP3にします。

ところで、市販のMP3プレーヤーにはスリープタイマー付きが未だに見当たらないよう(また、スピーカー付きのMP3プレーヤーはどれも充電タイプで、不精者には面倒)ですがどうなんでしょう?よって自作したわけで、これまでの記事に書いたDFPlayer miniという廉価なマイクロSDのMP3デコーダモジュールを、Arduino(ATmega328p)で動かしています。ところが、この小さなモジュールはシリアル通信でコントロールする場合ノイズが載りやすいため、それを避けて勝手な方法で動かしています。経緯は前の記事に書いたとおりです(右のカテゴリー欄のDFPlayer miniで前の3記事がご覧になれます)。

今回は最近の超小型スピーカーで、今年製の30㎜径3Wフルレンジを使いました。といってもAliExpressで2個で百円ほどでした^^; これに合わせてケースは次の小さくてカッコよい透明ケース。

f:id:a-tomi:20210306162604j:plain

f:id:a-tomi:20210306162705j:plain

かつて百均で入手したものですがなかなか丈夫で精密に、しっかりできています。さすがに本物の日本製。今でも同じものがあるかどうかわかりませんが(ネットで同等品を探したところ、形は少し違いますが、よさそうなのはちなみに1個200円ほどで見当たります)。

今回はどうせ作ならと、使っていなかったピンを曲のNext(Forward)とPrevious(Bakward)ボタンとして使える(使わなくてもよい)ようにしました。この記事の最後に掲げるプログラムもそのように改善しておきました。この製作ではそのプログラムを使っていますが、それらのボタンはつけていません。そのうちに別のに生かせるかと。そもそも長押し・短押しを使い分けるのは面倒ですから、必要とする場合は専用ボタンにするほうがいいですからね。

f:id:a-tomi:20210306163200j:plain

これに合わせて基板も、少しだけ模様替えしました。左下のところ。

f:id:a-tomi:20210306163645j:plain

今後の追加作成のために、まとめて3枚をCNCルーターで削りました。

f:id:a-tomi:20210306163819j:plain

30分ほどで3枚が削れました。銅箔面は次。

f:id:a-tomi:20210306163942j:plain

今回の生基板は、ベークライト(=紙フェノール樹脂)の材料がいかにも「私の原料は紙でした」という感じなのですが、こういう用途には特に問題ないですね^^;

f:id:a-tomi:20210306164119j:plain

ケースを次のように加工しました。小さなスピーカーを透明ケースに直接接着すると糊(ホットボンド)が見えて恰好わるそうですから、別に厚めの樹脂でバッフル板を作ってそれにとりつけることにしました。そうすると穴あけの手間はケースに加えてほぼ二重にかかりますがね^^;

f:id:a-tomi:20210306164431j:plain

そして組みあがりの基板をケースの底にとりつけたのが次。

f:id:a-tomi:20210306164623j:plain

そして組んでみたところが次です。まだゴミだらけですが。

f:id:a-tomi:20210306164714j:plain

ゴミやバリなどをとって下の写真が出来上がり。

f:id:a-tomi:20210306164914j:plain

今回も操作ボタンは電源と音声ボリュームの-と+だけで単純です。タイマーの設定やSDカードの交換は必要がごく少ないので蓋を開けて行いますが、それで十分ですね。我ながら小さく思い通りにできてよかったと思うわけです^^;

プログラムは次のように拡張と改善をしました。とはいってもライブラリーを特に使いませんので、ArduinoーUNOでの使用量はデータもプログラムも容量の1割以下です。

/********************************************************
   DFPlayer with Sleep-timer and Volume-control,
     without using any libraries for DFPlayer-mini.
       Initial version-01 (c)Jan.30,2021 Akira Tominaga
   How to operate:
     Insert micro SD with mp3 or wav files, in playing
     sequences. Maximum 255 files x 99 folders.
     Power off & on to re-play after the timer expired.
     15,30,45,60,75,90,& 105 minutes timer available.
     Buttons are volume-up, volume-down, and optional
     skip-forward & backward.
   Revisions:
     V02: Changed all pin assignments.     Feb.1,2021
     V02b: Added 15min timer switch        Feb.7,2021
     V03: Added skip-forward & backward    Mar.1,2021
 *****************************************************:**/
#define pBusy 15        // DFP BUSY pin, H when busy
#define Tmr15 12        // +15 min for sleep-timer (V02a)
#define Tmr30 11        // +30 min for sleep-timer 
#define Tmr60 10        // +60 min for sleep-timer
uint8_t vTsv = 0;       // save-a to detect timer changes
#define vol_D 5         // volume-down button
#define vol_U 8         // volume-up button
#define Fwd 3           // Forward button   *V03 added
#define Bkw 2           // Backward button  *V03 added
#define ledG  9         // led green for sleep-timer
#define IO1 17          // DFPIO1 short-on=<<,long-on=Vol-
#define IO2 16          // DFPIO2 short-on=>>,long-on=Vol+
#define sOn 100         // time (mS) for short-on
#define lOn 850         // time (mS) for long-on
#define chatrT 100      // chattering time to avoid
#define init_vol_D 15   // init. or ending # of vol.-downs 
unsigned long slpT = 0; // elapsed timer mS (large value)
#define stopOff 0       // stop signal is off
#define stopOn 1        // stop signal is on
uint8_t stopSig = stopOff; // initialize stop signal

void setup() {          // *** Arduino setup() ***
  pinMode (IO1, OUTPUT);
  digitalWrite(IO1, LOW);
  pinMode (IO2, OUTPUT);
  digitalWrite(IO2, LOW);
  pinMode (pBusy, INPUT);
  pinMode (Tmr15, INPUT_PULLUP);
  pinMode (Tmr30, INPUT_PULLUP);
  pinMode (Tmr60, INPUT_PULLUP);
  pinMode (vol_D, INPUT_PULLUP);
  pinMode (vol_U, INPUT_PULLUP);
  pinMode (Fwd, INPUT_PULLUP);    //  *V03 added
  pinMode (Bkw, INPUT_PULLUP);    //  *V03 added
  pinMode(ledG, OUTPUT);
  digitalWrite(ledG, HIGH); // show "I am awake"
  Serial.begin(9600);
  for (uint8_t i = 0; i < init_vol_D; i++) { // vol.down
    volDown();          // lower in the beginning
  }
  digitalWrite(ledG, LOW); // LED off
  Serial.println(F("DFP start"));
  playNext();           // start 1st music
  delay(300);           // delay before loop
}

void loop() {           // *** Arduino loop ***
  if (digitalRead(pBusy) == HIGH) { // if idle
    playNext();
  }
  if (digitalRead(vol_D) == LOW) { // vol.d button?
    while (digitalRead(vol_D) == LOW) {} // -released?
    volDown();          //  then decrease volume
  }
  if (digitalRead(vol_U) == LOW) { // vol.up button?
    while (digitalRead(vol_U) == LOW) {} // released?
    volUp();             // then increase volume
  }
  if (digitalRead(Fwd) == LOW) {  // Forward button?
    while (digitalRead(Fwd) == LOW) {} // released?
    skpFwd();            // then skip to forward file
  }
  if (digitalRead(Bkw) == LOW) {  // Backward button?
    while (digitalRead(Bkw) == LOW) {} // released?
    skpFwd();            // then skip to backward file
  } 
  setTmr();   // check and set sleep-timer
  delay(10);
}

/******************************
     User defined functions
 ******************************/
// *** Volume down as fnction volDown() ***
void volDown(void) {
  digitalWrite(IO1, HIGH);
  delay(lOn);           // long IO-on
  digitalWrite(IO1, LOW);
  Serial.println(F("Vol -" ));
  delay(chatrT);        // avoid double detect.
}
// *** Volume up as function volUp() ***
void volUp(void) {
  digitalWrite(IO2, HIGH);
  delay(lOn);           // long IO2-on
  digitalWrite(IO2, LOW);
  Serial.println(F("Vol +"));
  delay(chatrT);        // avoid double detect.
}
// *** Skip forward as function skpFwd() ***
void skpFwd(void) {     // *V03 added as optional
  digitalWrite(IO2, HIGH); // to skip to forward file
  delay(sOn);           // short IO2-on
  digitalWrite(IO2, LOW); // and off
  Serial.println(F("Fwd"));
  delay(chatrT);        // avoid double detect.
}
// *** Skip backward as function skpBkw() ***
void skpBkw(void) {     // *V03 added as optional
  digitalWrite(IO1, HIGH); // to skip to backward file
  delay(sOn);           // short IO2-on
  digitalWrite(IO1, LOW); // and off
  Serial.println(F("Bkw"));
  delay(chatrT);        // avoid double detect.
}
// *** Play the next as function playNext() ***
void playNext(void) {
  if (stopSig != stopOn) { // if not stop timing,
    digitalWrite(IO2, HIGH); // then play next, by
    delay(sOn);         // setting IO2-on
    digitalWrite(IO2, LOW); // for a short time
    Serial.println(F("Next file"));
    // wait for DFP action done
    while(digitalRead(pBusy) == HIGH){} 
  } else {
    Serial.println(F("Stopped"));
    while (true) {}   // and stop here
  }
}
// *** Set sleep-timer as function setTmr() ***
void setTmr(void) {
#define noSleep 2000000000 // 2 Billion mS (23days)
  static uint8_t vTmr;  // sleep-timer value (min)
  vTmr = 0;             // initialize static vTmr
  if (digitalRead(Tmr15) == LOW) { // if Tmr15 is set
    vTmr = vTmr + 15;   // then add 15 minutes
  }
  if (digitalRead(Tmr30) == LOW) { // if Tmr30 is set
    vTmr = vTmr + 30;   // then add 30 minutes
  }
  if (digitalRead(Tmr60) == LOW) { // if Tmr60 is set
    vTmr = vTmr + 60;   // then add 60 minutes
  }
  if (vTmr != vTsv) {   // if sleep-timer changed
    vTsv = vTmr;        // save it
    Serial.print(F("Timer(min)=")); // and show it
    Serial.println(vTmr);
  }
  static unsigned long lTmr = vTmr; // convert type
  slpT = lTmr * 60 * 1000 + 10000;  // mS val.+10sec
  if (vTmr == 0) {      // if no timer set,
    slpT = noSleep;     // then set a huge value
    digitalWrite(ledG, LOW); // and timer-LED off
  }
  if (vTmr > 0) {       // if sleep-timer set
    digitalWrite(ledG, HIGH); // timer-LED on
  }
  static unsigned long pTime;
  pTime = millis();     // get passed time
  if (slpT < pTime) {   // if timer expired,
    Serial.println(F("Timer expired"));
    digitalWrite(ledG, LOW); // timer-LED off
    for (uint8_t i = 0; i < init_vol_D; i++) {
      volDown();        // minimize volume
    }                   // power-off req'd afterward
    stopSig = stopOn;   // and set stop-sign on
  }
}
// *** End of program

 

以上、とりあえずご紹介まで。眠りにくい夜の入眠のお役に立てば幸いです。

 

©2021 Akira Tominaga, All rights reserved.

 

 

入眠タイマー付きMP3プレーヤーの製作(その3)

f:id:a-tomi:20210220180127j:plain

まさかこの単純な記事を3回にわたって書くとは思いませんでした。

前々回、前回からの続きですが、写真のような本番機をチョコッと作り試していましたら、なかなかいい感じなので書くことにしました。SN比も音質もとても良く、目的通りで眠りつくのも早い^^; ので、これが役立つ人がおられるかも。

操作部分は電源スイッチと、音量ダウンボタン、音量アップボタンのたった3つです。枕元近くに置くので、電源スイッチはトグルスイッチよりはスライドスイッチのほうが安全でよいでしょうね。

最初のうちは試しにマイクロSDに英語のセンテンスを沢山収容し、きっとこれならすぐに眠くなるだろうとやってみました。ところが30分たってもしっかり聞いてしまって眠くなりませんでした^^;。そこでタイマースイッチの15分を追加、設定が15分、30分、45分、60分、75分、90分、105分の7通りできるようにしました。

手直しした最終的なプログラムはこの記事の最後につけておきます。

この回路は「その2」と殆ど同じですが次です。

f:id:a-tomi:20210221092339j:plain



スリープタイマーがセットされていることを知らせるLED(緑)は、なるべく暗く点灯するようにRを大きめに設定してあります。

数日後から内容を入れ替えて、英語ではなく眠くなる音楽を選んで適当に入れてみました。ファイル名の順番に自動演奏されます。タイマーが来たら曲の途中でも音量がぐっと下がり、その曲が終わったら停止します。停止すると所用電流は小さいので、とくにパワーオフはしません。朝起きたらオフればよいわけで。

タイマーを45分にセットしていましたが、眠くなる音楽の場合はそんなに長い必要はありませんでした。30分で十分になりました^^;

単純な工作なのでどう作っても大丈夫でしょうが、以下、この場合の製作についてダラダラと書かせていただきます(といっても短いですが)。

基板は、50mmx50mmで次のようにデザイン(Top view=部品面から)。例によってはんだ用のランドなどは面倒なので省略し、早く作るのが優先でして^^

f:id:a-tomi:20210220181333j:plain

ソフトで変換した銅箔面の切削図(ツールパス)は次です。

f:id:a-tomi:20210220181453j:plain

毎度ですが、長年大事に使っているCNCルータでさっさと削ります。

f:id:a-tomi:20210220181608j:plain

次ができあがりの銅箔面。今回は比較的大きいので、アースはループを作らないようにしました。

f:id:a-tomi:20210220181741j:plain

表(部品面)は次です。

f:id:a-tomi:20210221164457j:plain


単純ですから、はんだ付けはすぐに終わりました。

f:id:a-tomi:20210220181916j:plain

きたないはんだ付けではありますが、一応電源を試験してとくに何も問題はない感じ。

f:id:a-tomi:20210220182016j:plain

ということで、使うスピーカーに見合うケースに組みこみました。秋月の次のケースです。

f:id:a-tomi:20210220182153j:plain

このケースは重く頑丈で箱鳴りの心配がない感じ。蓋もきっちりしまるのを選びました。容積は287mlあるので、ここで使っている小型フルレンジスピーカーなら、このほぼ密閉ボックスで問題が全くない感じです。

思いのほか大音量となるので、プログラムの最初で音量を実に15段階も下げてからスタートするようにしました。その分だけスタートが遅いですが、まあ入眠用ですからね^^

f:id:a-tomi:20210220182434j:plain

上の写真では、タイマーは30分にセットしてあります。

ついでですが、こういう基板をネジ穴なく取り付けるのに、次の「貼り付けボス」を使うとたいへん簡単で便利です。

f:id:a-tomi:20210220201910j:plain

この部品はケースにしっかり固定されますし、大きすぎる場合はニッパーで好きなように切れますので自由自在。

今回のマイコンの分担機能は単純なので、8ピンPICを使ってごく小さい基板でもできそうですね。回路のバリエーションも色々考えられますし。そして、近頃の超小型フルレンジスピーカーを使えばごく小さな箱でもできるわけです。そのうちにやってみます。

最後に、今回の製作に合わせた更新済プログラムをつけておきます。

 

/********************************************************
   DFPlayer with Sleep-timer and Volume-control,
     without using any libraries for DFPlayer-mini.
       Initial version-01 (c)Jan.30,2021 Akira Tominaga
   How to operate:
     Insert micro SD with mp3 or wav files, in playing
     sequences. Maximum 255 files x 99 folders.
     Power off & on to re-play after the timer expired.
     15,30,45,60,75,90,& 105 minutes timer available.
   Revisions:
     V02: Changed all pin assignments.     Feb.1,2021
     V02b: Added 15min timer switch        Feb.7,2021
 *******************************************************/
#define pBusy 15        // DFP BUSY pin, H when busy
#define Tmr15 12        // +15 min for sleep-timer (V02a)
#define Tmr30 11        // +30 min for sleep-timer 
#define Tmr60 10        // +60 min for sleep-timer
uint8_t vTsv = 0;       // save-a to detect timer changes
#define vol_D 5         // volume-down button
#define vol_U 8         // volume-up button
#define ledG  9         // led green for sleep-timer
#define IO1 17          // DFPIO1 short-on=<<,long-on=Vol-
#define IO2 16          // DFPIO2 short-on=>>,long-on=Vol+
#define sOn 100         // time (mS) for short-on
#define lOn 850         // time (mS) for long-on
#define chatrT 100      // chattering time to avoid
#define init_vol_D 15   // init. or ending # of vol.-downs 
unsigned long slpT = 0; // elapsed timer mS (large value)
#define stopOff 0       // stop signal is off
#define stopOn 1        // stop signal is on
uint8_t stopSig = stopOff; // initialize stop signal

void setup() {          // *** Arduino setup() ***
  pinMode (IO1, OUTPUT);
  digitalWrite(IO1, LOW);
  pinMode (IO2, OUTPUT);
  digitalWrite(IO2, LOW);
  pinMode (pBusy, INPUT);
  pinMode (Tmr15, INPUT_PULLUP);
  pinMode (Tmr30, INPUT_PULLUP);
  pinMode (Tmr60, INPUT_PULLUP);
  pinMode (vol_D, INPUT_PULLUP);
  pinMode (vol_U, INPUT_PULLUP);
  pinMode(ledG, OUTPUT);
  digitalWrite(ledG, HIGH); // show that I waked-up
  Serial.begin(9600);
  for (uint8_t i = 0; i < init_vol_D; i++) { // vol.down
    volDown();          // lower in the beginning
  }
  digitalWrite(ledG, LOW); // LED off
  Serial.println(F("DFP start"));
  playNext();           // start 1st music
  delay(300);           // delay before loop
}

void loop() {           // *** Arduino loop ***
  if (digitalRead(pBusy) == HIGH) { // if idle
    playNext();
  }
  if (digitalRead(vol_D) == LOW) { // vol.d button?
    while (digitalRead(vol_D) == LOW) {} // released?
    volDown();          //  then decrease volume
  }
  if (digitalRead(vol_U) == LOW) { // vol.up button?
    while (digitalRead(vol_U) == LOW) {} // released?
    volUp();             // then increase volue
  }
  setTmr();   // check and set sleep-timer
  delay(50);
}

/******************************
     User defined functions
 ******************************/
// *** Volume down as fnction volDown() ***
void volDown(void) {
  digitalWrite(IO1, HIGH);
  delay(lOn);           // long IO-on
  digitalWrite(IO1, LOW);
  Serial.println(F("Vol -" ));
  delay(chatrT);        // avoid double detect.
}
// *** Volume up as function volUp() ***
void volUp(void) {
  digitalWrite(IO2, HIGH);
  delay(lOn);           // long IO2-on
  digitalWrite(IO2, LOW);
  Serial.println(F("Vol +"));
  delay(chatrT);        // avoid double detect.
}

// *** Play the next as function playNext() ***
void playNext(void) {
  if (stopSig != stopOn) { // if not stop timing,
    digitalWrite(IO2, HIGH); // then play next, by
    delay(sOn);         // setting IO2-on
    digitalWrite(IO2, LOW); // for a short time
    Serial.println(F("Next file"));
    // wait for DFP action done
    while(digitalRead(pBusy) == HIGH){}
  } else {
    Serial.println(F("Stopped"));
    while (true) {}   // and stop here
  }
}

// *** Set sleep-timer as function setTmr() ***
void setTmr(void) {
#define noSleep 2000000000 // 2 Billion mS (23days)
  static uint8_t vTmr;  // sleep-timer value (min)
  vTmr = 0;             // initialize static vTmr
  if (digitalRead(Tmr15) == LOW) { // if Tmr15 is set
    vTmr = vTmr + 15;   // then add 15 minutes
  }
  if (digitalRead(Tmr30) == LOW) { // if Tmr30 is set
    vTmr = vTmr + 30;   // then add 30 minutes
  }
  if (digitalRead(Tmr60) == LOW) { // if Tmr60 is set
    vTmr = vTmr + 60;   // then add 60 minutes
  }
  if (vTmr != vTsv) {   // if sleep-timer changed
    vTsv = vTmr;        // save it
    Serial.print(F("Timer(min)=")); // and show it
    Serial.println(vTmr);
  }
  static unsigned long lTmr = vTmr; // convert type
  slpT = lTmr * 60 * 1000 + 10000;  // mS val.+10sec
  if (vTmr == 0) {      // if no timer set,
    slpT = noSleep;     // then set a huge value
    digitalWrite(ledG, LOW); // and timer-LED off
  }
  if (vTmr > 0) {       // if sleep-timer set
    digitalWrite(ledG, HIGH); // timer-LED on
  }
  static unsigned long pTime;
  pTime = millis();     // get passed time
  if (slpT < pTime) {   // if timer expired,
    Serial.println(F("Timer expired"));
    digitalWrite(ledG, LOW); // timer-LED off
    for (uint8_t i = 0; i < init_vol_D; i++) {
      volDown();        // minimize volume
    }                   // power-off req'd afterward
    stopSig = stopOn;   // and set stop-sign on
  }
}
// *** End of program

 

 簡単な紹介でしたが、どなたかのお役に立てば幸いです。

 

©2021 Akira Tominaga, All rights reserved.

 

 

これでOK!睡眠タイマー付きMP3プレイヤーをArduinoで(その2)

f:id:a-tomi:20210202121028j:plain

前回の記事の続きです。

工夫をした結果、ついにノイズの心配なくコントロールできるようになりました!

DFPlayerのノイズにつながり易いシリアル通信でのコントロールをやめて、IOボタン機能をArduinoでコントロールするようにしたらバッチリです。上の写真のとおり、大きなキャパシターは不要ですし、電源5VをATmega328Pと問題なく共用できます。そして良い音が出ます。

新たな回路は次のとおりです。毎度ながら汚い手書きですみませんが m(_ _)m

f:id:a-tomi:20210202133753j:plain
今回はDFPlayerのIO_1、IO_2ボタンにオープンコレクター出力をつないでコントロールします。このために2SC1815トランジスタを経由しますが、小信号用のNPNトランジスタなら何でもよいです。小さなトランジスタアレイ部品でもよいですね。2つだけなのでここではディスクリート(単体)部品を使っています。このやり方ならDFPlayerの発振の恐れをかんたんに回避できます。

f:id:a-tomi:20210202131610j:plain

上の写真で右下にあるIO_1、IO_2ボタンが、短押し(short push)だとそれぞれ前の曲、次の曲で、長押し(long push)だとそれぞれボリュームを下げる、上げるとなっています。また、右上にあるBUSY端子は曲の演奏中はLOWに、曲が終わり停止中はHIGHの信号を出します。

この3つの端子を使えばそのままプレイヤーとして機能します。「勝手な電子工作」としてはこれをマイコンでコントロールしたい。そして自動演奏(最後の次は最初にLoop)と、スリープ時間での停止がしたいわけです。スリープは曲の終了を待たず先にボリュームをゼロにしておけばさらによいかと。

DFPlayerのデータシートには、短押し、長押しの時間の記述箇所がなぜか見当たりません^^;  ここでは短押しは100mS、長押しは850mSにしますがこれで問題なし。(短くしたいですが、実験の結果、長押しを700mSにすると前後の曲選択ととられることがある)。

また、こういうスイッチ入力端子の場合、デバイス側では押下の検知後にチャタリングの影響回避として30~50mSのホールド時間がとられていると推定します。よって短押しも確実さのため上記の長さとしました。

Arduinoのプログラムは次のように作りました。ライブラリーなどを何も使わずに簡単にできますので、UNOの容量は10%以下に収まります。

/********************************************************
 * DFPlayer with Sleep-timer and Volume-control,        *
 *   without using any libraries for DFPlayer-mini.     *
 *     Initial version-01 (c)Jan.30,2021 Akira Tominaga *
 * How to operate:                                      *
 *   Insert micro SD with mp3 or wav files, in playing  *
 *   sequences. Maximum 255 files x 99 folders.         *
 *   Power off & on to re-play after the timer expired. *
 * Revisions:                                           *
 *   V02: Changed all pin assignments.     Feb.1,2021   *
 *****************************************************:**/
 #define pBusy 15       // DFPlayer BUSY pin, H when busy
#define Tmr30 11        // 30 min switch for sleep-timer 
#define Tmr60 10        // 60 min switch for sleep-timer
uint8_t vTsv = 0;       // save-a to detect timer changes
#define vol_D 5         // volume-down button
#define vol_U 8         // volume-up button
#define ledG  9         // led green for sleep-timer
#define IO1 17          // DFPIO1 short-on=<<,long-on=Vol-
#define IO2 16          // DFPIO2 short-on=>>,long-on=Vol+
#define sOn 100         // time (mS) for short-on
#define lOn 850         // time (mS) for long-on
unsigned long slpT = 0; // elapsed timer mS (large value)
#define stopOff 0       // stop signal is off
#define stopOn 1        // stop signal is on
uint8_t stopSig = stopOff; // initialize stop signal

void setup() {          // *** Arduino setup() ***
  pinMode (IO1, OUTPUT);
  digitalWrite(IO1, LOW);
  pinMode (IO2, OUTPUT);
  digitalWrite(IO2, LOW);
  pinMode (pBusy, INPUT);
  pinMode (Tmr30,INPUT_PULLUP);
  pinMode (Tmr60,INPUT_PULLUP);
  pinMode (vol_D, INPUT_PULLUP);
  pinMode (vol_U, INPUT_PULLUP);
  pinMode(ledG, OUTPUT);
  digitalWrite(ledG, HIGH); // show that I waked-up
  Serial.begin(9600);
   for (uint8_t i = 0; i < 3; i++) { // decrease volume
    volDown();          // lower in the beginning 
  }
  digitalWrite(ledG, LOW); // LED off 
  Serial.println(F("DFP start"));
  playNext();           // start 1st music
  delay(300);           // delay before loop
}

void loop() {           // *** Arduino loop ***
  if (digitalRead(pBusy) == HIGH) { // if idle
    playNext();
  }
  if (digitalRead(vol_D) == LOW) { // vol.d button?
    while (digitalRead(vol_D) == LOW) {} // released?
    volDown();          //  then decrease volume
  }
  if (digitalRead(vol_U) == LOW) { // vol.up button?
    while (digitalRead(vol_U) == LOW) {} // released?
    volUp();             // then increase volue
  }
  setTmr();   // check and set sleep-timer
  delay(300);
}

/******************************
 *   User defined functions   *
 ******************************/
// *** Volume down as fnction volDown() ***
void volDown(void) {
  digitalWrite(IO1, HIGH);
  delay(lOn);           // long IO-on
  digitalWrite(IO1, LOW);
  Serial.println(F("Vol -" ));
  delay(10);
}
// *** Volume up as function volUp() ***
void volUp(void) {
  digitalWrite(IO2, HIGH);
  delay(lOn);           // long IO2-on
  digitalWrite(IO2, LOW);
  Serial.println(F("Vol +"));
  delay(10);
}

// *** Play the next as function playNext() ***
void playNext(void) {
  if (stopSig != stopOn) { // if not stop timing,
    digitalWrite(IO2, HIGH); // then play next, by
    delay(sOn);         // setting IO2-on
    digitalWrite(IO2, LOW); // for a short time
    Serial.println(F("Next file"));
  } else {
    Serial.println(F("Stopped"));
    while (true) {}   // and stop here
  }
}

// *** Set sleep-timer as function setTmr() ***
void setTmr(void) {
#define noSleep 2000000000 // 2 Billion mS (23days)
  static uint8_t vTmr;  // sleep-timer value (min)
  vTmr = 0;             // initialize static vTmr
  if (digitalRead(Tmr30) == LOW) { // if Tmr30 is set
    vTmr = vTmr + 30;   // then add 30 minutes
  }
  if (digitalRead(Tmr60) == LOW) { // if Tmr60 is set
    vTmr = vTmr + 60;   // then add 630minutes
  }
  if (vTmr != vTsv) {   // if sleep-timer changed
    vTsv = vTmr;        // save it
    Serial.print(F("Timer(min)=")); // and show it
    Serial.println(vTmr); 
  }
  static unsigned long lTmr = vTmr; // convert type
  slpT = lTmr * 60 * 1000 + 10000;  // mS val.+10sec
  if (vTmr == 0) {      // if no timer set,
    slpT = noSleep;     // then set a huge value
    digitalWrite(ledG, LOW); // and timer-LED off
  }
  if (vTmr > 0) {       // if sleep-timer set
    digitalWrite(ledG, HIGH); // timer-LED on
  }
  static unsigned long pTime;
  pTime = millis();     // get passed time
  if (slpT < pTime) {   // if timer expired,
    Serial.println(F("Timer expired"));
    digitalWrite(ledG, LOW); // timer-LED off
    for (uint8_t i=0;i<10;i++){
      volDown();        // minimize volume
    }                   // power-off req'd afterward 
    stopSig = stopOn;   // and set stop-sign on
  }
}
// *** End of program

前回の記事でも書きましたが、Arduino-IDEを使ってArduinoーUNOへ普通にスケッチを書き込み、そしてATmega328p単体を抜き取って使うわけです。そうすれば本番機を小さく作るのが簡単なわけです。もちろん、ArduinoーUNOで結線しても、今回の回路は問題なくきれいに動きノイズは全くのりません。

f:id:a-tomi:20210202132718j:plain

これを実行するとシリアルモニターへ次のアウトプットが出ます。

f:id:a-tomi:20210202151142j:plain

出だしの音が少し大きすぎるので、プログラムでは最初にまずボリュームを3回下げています。

タイマー指定はパワーオンからの経過時間(+10秒としました)にしています。設定値は最初にでますが、演奏の途中で設定を変更すれば再設定され、追加で出力されるようにしてあります。曲を次々と演奏しますが、途中でボリュームボタンをいじるとそのように表示されます。

ATmega328p単体で実行する場合でも、Tx端子にシリアルモニター(作り方は次の記事の最後のほうに載せてあります。)をつなげば同じようにトレースができますね。

ソフトウェアシリアルをコンパクトに作るーArduino編-そしてトレースに使う - 勝手な電子工作・・

 

さて、本番機を作る前にこの記事を書こうとして試しました。そこで一苦労し、次のことに気づきました。

以下は余談ですから、読み飛ばされてもかまいませんが、DFPlayerを使ってもしノイズに悩まされる場合はご覧いただくと役立つかと思います。

==========================

UNOとの接続でいかにノイズが載らないとしても、下手なブレッドボードを使って下手な配置をすると発振がのる場合があります。次のような適当な配置だと音は出ますが、シュルシュルというかすかなノイズが混じり、びっくりしました。この場合、DFPlayerの電源に大きなCを入れても完全には解決しません。DFPlayerの発振だからです。

f:id:a-tomi:20210202152129j:plain

 

 接続線が長いのはまずいですが、ブレッドボードそのものにも問題の原因があることがわかりました。このブレッドボードは内部の接続部品が大きいため、浮遊容量(ストレ、Stray、寄生容量)が他のボードより大きいのです。裏をはがしてみれば一目瞭然ですが、次の写真で下のものです。

f:id:a-tomi:20210202152456j:plain

DFPlayerは小さなボードにデコーダー、DAC、それにアンプを積んでいるため、ストレが大きいと、出力が入力に回り込みやすいわけ。こういうブレッドボードでは配置をよく考えないと少し厳しいわけです。

 

テストであってもマイコン側の使用ピンを吟味して、DFlayerの入力ピンからは短く接続したいものです。そういうわけでブレッドボード自体をとりかえて、かつArduinoのピン割り当ても見直して試作したのが最初の写真です。

これであればたいへん安定しており、DFPlayerの電源に大きなCなどは不要です。ようやく完全に問題が出なくなったわけです^^; ここは普通のパスコン0.1μFでも大丈夫ですが、デジタルアンプを使うので一応1μFを入れてあります(D級アンプなので音量次第で電流はごく少ないし無音時はほぼ流れないわけです)。

ブレッドボードではなくいきなり基板を作っての本番機なら、そういう発振は簡単に防げそうでしょうが、なにせ事前にテストしたいものですから^^;

===========================

 

どっちにしても、余計な心配をしなくて済む今回の安定した回路で、近々本番機を基板から作ろうと思っています。そうすれば今後はきっとよく眠れますね・・・^^

シリアル接続でコントロールするのと比べた場合の機能上の違いは、イコライザの指定ができないことです。とはいえ、目的は睡眠用に小さな音で演奏するものなのでDefaultのLoudnessイコライザで十分。もし本格的なステレオを作る場合は、DFPlayerにStereo DAC出力ピンがついてます(大したものです)から、そこから他のアンプモジュールに入れる形にするのがよいですね。

 

ところで、あいにく決算期限と確定申告が迫ってます。ひょっとすると本番機の製作は少し後になるかもしれませんが、とにかく急いで追加記事を先に書かせていただきました。この記事がお役に立てばたいへん幸いです。

 

2021.2.22追記:チョコっと本番機を作ってしばらく試していました。音も良く入眠用に具合が良いので、ソフトも更新し次のリンクへ追加しておきました^^;

入眠タイマー付きMP3プレーヤーの製作(その3) - 勝手な電子工作・・

 

©2021 Akira Tominaga, All rights reserved.

 

 

 

 

 

 

 

睡眠タイマー付きMP3プレーヤをArduinoで作ってみる(・・?

f:id:a-tomi:20210126164901j:plain

巣籠りが長引き、運動不足が続くと眠りにくくなりがちです。

人の話を聴いていると、私は眠くなる癖(かつて会議で眠る癖がついたからかも^^;)があるため、最近は23:05から始まる「NHKラジオ深夜便」の話し声を耳元で聞きながら眠ったりします。小型のラジオについているスリープタイマーを30から40分にセットして、いつ消えたのかに気づかずに寝ています。

とはいっても、人の話し声よりは静かな音楽が良いという人は多いでしょうね。妻もそうですが。最近はYouTubeで「眠るための音楽」がやけにたくさん出ていますが、世界的に今はそういう傾向があるのかもしれません。しかし、PCなどをつけっぱなしで眠るわけにもいきませんので、MP3等に記録してかけるのが良いかも。AlexaやGoogleHomeでそういう音楽を頼むのも一法ですが、時々目が覚める音楽に変わっていたりもしますからね^^

ところが探しても睡眠タイマーがついているMP3プレーヤーは、ありそうで見当たりません。よし、それなら作るか・・。

うってつけのデバイスがDFPlayerミニのようです、たぶん。

MP3かWAVのファイルをマイクロSDに入れておけば再生しDecodeしDA変換、さらにそれを内蔵Digital-Amp.(3W)で鳴らしてくれるという、優れものに見えます。これならすぐできそうですが、海外ネットではなぜか驚くべき廉価です。送料込みで10個で1500円ほど、つまり1個150 円ほど!

f:id:a-tomi:20210126171902j:plain

ずいぶん小さいですね。この筐体にデコーダーもDACもアンプも内蔵しているとは凄い・・・

f:id:a-tomi:20210126172058j:plain

裏はこうなっています。ヘダーピンは最初からついてきます。

f:id:a-tomi:20210126172226j:plain

ほとんどがソフトウェアでできているとはいえ、よくぞこんな小さくまとめたこと!

音量調整やスリープタイマーをつけたいわけなので、マイコンからシリアル通信でコントロールします。

次のように回路を考えて、ArduinoIDEでプログラミングをします(UNOで作ってATmega328pだけを使うわけですが)。ハードウェアシリアルのデバッグメッセージを使いたいので、DFPlayerとの通信にはソフトウェアシリアルを使います。

f:id:a-tomi:20210126172459j:plain

上の回路でMOSI(master out, slave in)のラインだけに1KΩを入れるのは、DFPlayerは5V電源OKなのですが扱う信号レベルが3.3Vなので、Arduino(ATmega328p)から5V信号を送ることによる、まさかのLatch-up等を防ぐためです。逆にMISO(master in, slave out)のラインは抵抗は不要、むしろ入れてはいけませんね(5V駆動のArduino側でHighの受信信号が判定しにくくなるからです)。

UNOでプログラミングしてATmega328マイコンだけを取り出す一番簡単で勝手な方法は、次の記事の前のほうに詳しく載せてありますので、必要な方はご参照ください。

Zoom用かんたん操作ボタンをArduino-UNOで作る(その1) - 勝手な電子工作・・

なお、新たなATmega328pを使うときは事前にArduinoブートローダーを入れる必要がありますが、その方法はネットに沢山出ていますからここでは省略させていただきます

。DFPlayerのピン配置は次です。

f:id:a-tomi:20210126173302j:plain

そしてArduino-UNOで次のようにコーディングしました。DFplayerが再生している間はArduino-loopが動いていますが、この中にはDelay()を入れるわけにはいきません。なぜなら、そのDelayの間にDFPlayer側からArduinoのソフトウェアRxにくるMessageを見逃しそのタイムアウト多数反復によるDFPlayer異常終了を起こさせないためです。(2021.1.30 Bugを直しましたm(_ _)mスマン)

/***************************************************
  MP3 player with Sleep-timer & Sound-volume-control,
    using DFplayer's GNU-GPL as described below.
  How to use:
    Insert micro SD card containing mp3 or wav files
    in playing sequence. Sound-volume and sleep-timer
    (30,60 or 90 minutes) controls are available.
  Revisions:
    Initial Version-00 Jan.23,2021 (c)Akira Tominaga
    V01: Timer from VR to swithes.    Jan.24, 2021
    V02; setSlpt() function debugged. Jan.30, 2021
  ==================== GNU GPL ====================
  DFPlayer - A Mini MP3 Player for Arduino
  <https://www.dfrobot.com/product-1121.html>
  Examples by Angelo.qiao@dfrobot.com 2016-12-07 used,
  with GNU Lesser General Public License.
  See <http://www.gnu.org/licenses/> for details.
  The above must be included in any redistribution.
  ****************************************************/
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
#define sRx 10            // MISO ( device's Tx )
#define sTx 11            // MOSI ( device's Rx )
SoftwareSerial sSer(sRx, sTx);
DFRobotDFPlayerMini dfP;

#define Tmr30 2           // sleep timer 30min
#define Tmr60 3           // sleep timer 60min
#define ledG 6            // green LED for Sleep-timer
unsigned long slpT;       // sleep timer in milli second
uint16_t vVol;            // sound volume of DFPlayer

void setup() { // *** Arduino setup ***
  sSer.begin(9600);
  Serial.begin(9600);
  pinMode(ledG, OUTPUT);  // LED to show Timer-on
  digitalWrite(ledG, HIGH);
  delay(300);             // indicate that I am awake
  digitalWrite(ledG, LOW);
  pinMode (Tmr30, INPUT_PULLUP); // timer for 30 min.
  pinMode (Tmr60, INPUT_PULLUP); // timer for 60min
  Serial.println(F("Starting DFP"));
  while (!dfP.begin(sSer)) {
    Serial.print(".");
    delay(100);
  }
  Serial.println(F("DFP connected"));
  setSlpT();              // chk & set sleep-timer
  Serial.print(F("Sleep-timer mS = "));
  Serial.println(slpT);
  setVol();               // chk & set sound volume
  Serial.print(F("Sound Vol. = "));
  Serial.println(vVol);
  // Set Equalizer by deleting required line's "//"
  //  dfP.EQ(DFPLAYER_EQ_NORMAL);
  //  dfP.EQ(DFPLAYER_EQ_POP);
  //  dfP.EQ(DFPLAYER_EQ_ROCK);
  //  dfP.EQ(DFPLAYER_EQ_JAZZ);
  //  dfP.EQ(DFPLAYER_EQ_CLASSIC);
  dfP.EQ(DFPLAYER_EQ_BASS);
  //
  dfP.enableLoop();       // enable loop of files
  Serial.println(F("Loop enabled"));
  dfP.play(1);            // start the first file
  Serial.println(F("file #1 started"));
}

void loop() { // *** Arduino loop ***
  // No delays allowed to avoid Rx time-out
  static unsigned long chkT = millis(); // get ms passed
  if (millis() - chkT > 50) { // if 50mS have been passed,
    chkT = millis();      // then set new time to chkT
    setVol();             // check and set sound volume
    setSlpT();            // set and check sleep-timer
  }
  if (dfP.available()) {  // if message from DFPlayer,
    prtMsg(dfP.readType(), dfP.read()); // then print it
  }
}

// *** Set and check Sleep-Timer setSlpT() ***
void setSlpT(void) {
#define noSleep 2000000000 // 2 Billion mS(about 23days)
  static uint8_t vTmr; // sleep-timer (minute)  updt*V02
  vTmr = 0;					isrt*V02
  if (digitalRead(Tmr30) == LOW) { // if Tmr30 Sw on
    vTmr = vTmr + 30;     // then add 30 minutes
  }
  if (digitalRead(Tmr60) == LOW) { // if Tmr60 Sw on
    vTmr = vTmr + 60;     // then add 60 minutes
  }
  static unsigned long lTmr = vTmr; // change attribute
  slpT = lTmr * 60 * 1000 + 10000; // calculate mS+10sec
  digitalWrite(ledG, HIGH); // show Sleep-timer is on
  if (vTmr == 0) {        // if no timer Sw set
    slpT = noSleep;       // then set a very long timer
    digitalWrite(ledG, LOW); // show Sleep-timer is off
  }
  if (slpT < millis()) {  // if sleep time arrived,
    Serial.println(F("Sleep-timer expired"));
    digitalWrite(ledG, LOW); // off the Timer LED
    dfP.pause();           // then stop playing
    while (true) {}        // and do nothing
  }
}

// *** Check and set sound Volume setVol() ***
void setVol(void) {
#define aVol 0          // analog-input for sound volume
#define vMax 30         // maximum DFP sound volume
  static uint8_t vVsv;    // save area for vVol
  vVol = (uint16_t)(analogRead(aVol) * vMax / 1023);
  if (vVol != vVsv) {
    dfP.volume(vVol);     //volume
    vVsv = vVol;          // save the volume value
  }
}

// *** Print messsages from DFP prtMsg(type,val) ***
void prtMsg(uint8_t type, int value) {
  switch (type) {
    case TimeOut:
      Serial.println(F("Time-out!")); break;
    case WrongStack:
      Serial.println(F("Stack wrong!")); break;
    case DFPlayerCardInserted:
      Serial.println(F("Card inserted!")); break;
    case DFPlayerCardRemoved:
      Serial.println(F("Card removed!")); break;
    case DFPlayerCardOnline:
      Serial.println(F("Card Online!")); break;
    case DFPlayerUSBInserted:
      Serial.println("USB Inserted!"); break;
    case DFPlayerUSBRemoved:
      Serial.println("USB Removed!"); break;
    case DFPlayerPlayFinished:
      Serial.print(F(" Finished #"));
      Serial.println(value);
      // do some if to avoid Stack at any cost ^^
      dfP.next();  // play next music
      break;
    case DFPlayerError:
      Serial.print(F("DFPlayerError:"));
      switch (value) {
        case Busy:
          Serial.println(F("No card")); break;
        case Sleeping:
          Serial.println(F("Sleeping"));  break;
        case SerialWrongStack:
          Serial.println(F("Wrong stack")); break;
        case CheckSumNotMatch:
          Serial.println(F("Check-sum error")); break;
        case FileIndexOut:
          Serial.println(F("File-index error")); break;
        case FileMismatch:
          Serial.println(F("Cannot find file")); break;
        case Advertise:
          Serial.println(F("In advertise")); break;
        default:
          break;
      }
      break;
    default: break;
  }
}

スリープタイマーは、2つのスイッチを使って30分か60分か90分が選べます。 上のスケッチでは、消費メモリーはデータ、スケッチともに2割しか使いません。UNOで余裕たっぷりですね。マイクロSDカードには次のようにテスト音楽を8つ入れています(フォルダーmp3を作りその中にmp3ファイルを8つ入れてある)。そして早速テストしているのが冒頭に掲げた写真です。

f:id:a-tomi:20210126202041j:plain

ちなみに、マイクロSDカードは大32GBまででFAT16形式とFAT32形式をサポート。フォルダーは99個まで、各フォルダー内の曲数は255までです。推奨フォルダー名は数字の00から99、曲名は数字の001から255(拡張子は当然ながら.mp3または.wav)ですが、順序さえわかれば他の短い英数字名をつけても問題ありません。

 

上のプログラムを実行した結果、Serial.モニターへの出力は次のようになりました。

Starting DFP
DFP connected
Sleep-timer mS = 1810000
Sound Vol. = 7
Loop enabled
file #1 started
 Finished #1
Stack wrong!
 Finished #2
Stack wrong!
 Finished #3
Stack wrong!
 Finished #4
Stack wrong!
 Finished #5
Stack wrong!
 Finished #6
Stack wrong!
 Finished #7
Stack wrong!
 Finished #8
Stack wrong!
 Finished #1
Stack wrong!
 Finished #2
Stack wrong!
 Finished #3
Stack wrong!
 Finished #4
Stack wrong!

  設定通りに曲1~8の演奏を繰り返し、設定したタイマーで演奏をやめます。上のリストのとおり、曲と曲の間にエラー(Wrong Stack)が1度ずつでています。コードを確認してDFPlayerミニのデータシートをみると、なかなかわかりにくいですがどうやらシリアル通信上の問題のようで、リトライされるので結果的には問題なさそう。

そこまでは万事よいのですが、ここからがあれ?

良い音が再生されるので感心していました。

そして音量を下げてみるとありゃ、カツッ、カツッ、・・と大きなノイズがでています。完全に周期的で、スピーカーラインをオシロでトリガーをかけて観察してみました。ノイズ多数回を記録したのが次です。

みると主に130mS毎に大ノイズが生じています。DFPlayerを別の個体に代えてみても、どれも完全に同じです!おお、個体のもんだいではない!

f:id:a-tomi:20210126175523j:plain

これはいったい何でしょう。

Arduinoとの接続?でしょうか。しかし接続はグランド以外にはソフトウェアシリアル通信線2本、それに当初はArduinoからの5Vラインだけです。

まずはシリアル線を点検。

f:id:a-tomi:20210126175807j:plain

ここにはノイズの元は全く見当たりません。

然れば残りは電源のみ?まさかね・・・

デジタルアンプ3Wなので電流をたくさん食うわけではない(実際80mA程度)ですが、それなら電源をArduinoからとらずに5VDCアダプター(これは容量2Aもある)から別に供給してみます。なんと、それでもノイズがやみません。DFPlayer側の電源端子間を試しにCを外してオシロ(AC接続)で見ると次。

f:id:a-tomi:20210126175850j:plain

 おお、まさしく正確に130mS毎に鋭いノイズが載っているではありませんか!

なんということでしょうか??DFPlayerが出しているに相違ないでしょう。

それでは・・と10μFのセラミックコンデンサーをいれても全く効果なし。ではと次に100μFのケミコンを入れると弱まりました。そこでこの際、470μFを入れてみましたら次のように大幅に低減しました。

f:id:a-tomi:20210126180654j:plain

考えてみればここはインピーダンスの低い電源なので、この場合は小さな容量ではこのノイズを消すには効き目が少ないわけですね。よほどひどいノイズを出しているのでしょう。

さて、これでスピーカーからはノイズが全く出なくなりすっきりです。DFPlayerの仕様にはサンプリング最大48KHz、24bitーDAC、ダイナミックレンジ90dB、SN比85dBとあり、そこらへんのPlayerと比べカタログ上は遜色ありませんね^^

早速こんどはUNOを外してATmega328Pで全体を試作。

f:id:a-tomi:20210126180933j:plain

おっ、ノイズもなくきれいな音でうまく動くじゃないですか!

ただし、DFPlayer側の電源には大容量のキャパシターを入れたので、DFplayer側の電源オンをしたあとでマイコン側の電源を入れています。まあ、これはArduinoスケッチのSetup()内にDelayを入れることで、その分だけ開始時刻を遅らせれば済むことですね。また、電源としては、おそらく三端子レギュレータ2つを使えば、1つの元電源から供給できるでしょう。

この新たなブレッドボード配線の詳細は次です。

f:id:a-tomi:20210126181338j:plain

いよいよ第1号機をちゃんと作るか・・・と思いながら、稼働状況を更によく観察したら、スリープタイマーが入っていることを表示する緑色のLEDが、不思議なことに6.6秒毎に1回だけ50mSだけ消灯するのです。たいへん規則的ですが、音には全く何も関係がないのです。これはいったい何なのでしょうか?

論理上は、点灯したらタイマー時間が終わり、演奏終了するまではこのLED消灯なしで常時点灯していなければならないつもりですが。。。いったい何が影響しているのでしょうか。

そして、UNOでの試作機もこれと同様によく観察すると、なんと全く同じことが起きているのです!

以下2021.1.30 更新させていただきました!:

というわけで、おかしなことだなあと考え込んで、本番機の製作にはとりかかれない状態でした。本日、やっと週末がきて念入りにチェックしたら、タイマーをセットする関数の中にstatic変数初期化のバグを発見して直しました^^;

 ところが、さらに別のことに気づきました。1週間経ったら、ブレッドボードのちょっとしたゆるみだけでDFPlayerが発振するようです。

海外ネットでみつけたノイズ問題(上記のようにツールで調べたケースはなかなか見当たらないようですが)」・・・。Beep音でなくBep Bep Bep Bep、、、

audio - DFPlayer Noise: Researched, Tried, and Bep Bep Bep Bep Bep - Arduino Stack Exchange

この際ということで、本日色々と試すと、DFPlayerはシリアル通信でコントロールしようとする限り、ちょっとしたことで発振が起きやすいようです。

「勝手な電子工作」としてはそこで簡単にはあきらめません。それなら他のもっと安定した方法を考えよう・・・とりあえずシリアル通信を使わない方法を考え、試しにArduino-UNOでコントロールしてみました。ブレッドボードで色々試した限り、それだとノイズ問題は起きずとても安定している感じです。

電源をUNOから共有しても大丈夫ですし、またなんと!上に書いた470μFを外してしまっても問題がないのに気づきました。つまり、月並みにシリアル通信で制御しようすると弱みがありそうなDFPlayerなのですが、そういうわけで意外にしぶとくできているなあと、改めて見直してしまいました^^

f:id:a-tomi:20210126182354j:plain

 

結局はその新しい案で本番機を作ろうと思います。基板など早く作りたいところですが、せっかくここまで読んでいただいたので、「その2」と題して先にその記事を載せてからにしようと思います。少々お待ちくださいね。

 

2021.2.2追記:「その2」に新しい案で作った記事を書いておきました。この勝手なやりかたならとても安定したものが作れてバッチリです。

睡眠タイマー付きMP3プレイヤーをArduinoで作る(その2)これでOK! - 勝手な電子工作・・

 

というわけで、この記事の中ではシリアル通信でのコントロールでしたが、どなたかのご参考になれば幸いです。

 

©2021 Akira Tominaga, All rights reserved.

 

小さな8ピンPICで色々(時計+温湿度計兼RTC書込器)

f:id:a-tomi:20210104153704j:plain



あけましておめでとうございます、

と言っている間に早くも3日になりました。外出自粛の三が日があっという間に終わりそう。それでは・・と、午後から急にPICのプログラムをしあげようと思い立ちました。大晦日に紅白に飽きて着手していたのを完成させるのが早いかと。

他に工作中のものでマイペースでやっているものもありますがすぐには出せないので、「初荷」とするには簡単なプログラムに限るかな、と気づいたわけです^^; その日に完了しましたが、ぼちぼちやってるんで、投稿はこの記事ができた4日です。

前回の記事の応用ですから確実にできそうでした。前回の記事は次:

LCDキャラクターディスプレイを8ピンPICに接続する(コスパ最高?) - 勝手な電子工作・・

丑年にちなみ反芻動物のように粘り強くPICアセンブラーで書いてます(?)。

まずは回路図。毎度の汚い手書きですみませんが。

f:id:a-tomi:20210104154135j:plain

組み合わせた相手は以前に作ったRTC書き込み器で次の記事:

RTC writer(リアルタイムクロック・ライター) 8ピンPICで簡素に - 勝手な電子工作・・

その時の表示装置としてはTM1637LEDを使いましたので、今回はそれを20x4LCDに変え、表示画面が大きいのでついでに温湿度計DHT11をつなぐことにしました。

 DHT11は非常に廉価ながら正確な温湿度センサーで、one-wireプロトコルで動きます。例えば次の記事:

PICアセンブラーで芸当(?)その4)もっと接続-余裕の8ピン! - 勝手な電子工作・・

 

今回のプログラム全ては次のとおりで、この小さなPICの容量の半分ほどしか消費しないつもりで組みましたがそうなりました。

;U210103-RTC-DHT11-LCD-V00.asm			     		As of Jan. 3, 2021
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;										;
;   	Time, Temperature, and Humidity Display with PIC12F1822 V00		;
;	        (C)2014-2021 Akira Tominaga, All rights reserved.		;
;										;
;	  Major revisions							;
;		V00 Initial version    		December 31, 2020		;
;										;
;	  Function								;
;		1.Show temperature, & humidity on LCD				;
;										;
;	  Input/output       							;
;		RA0 DHT11 Temp&Humidity-sensor w/ 1-wire protocol		;
;		RA1 SDA for I2C-RTC  output  usually and input occasionally	;
;		RA2 SCL for I2C-RTC  output					;
;		RA3 Mode switch (swMode) input pulled-up			;
;		RA1 Time switch (swTime) input pulled-up			;
;		RA0 Set switch  (swSet)  input pulled-up			;
;										;
;										;
;	  Remarks								;
;		1. Clock = HFINTOSC (	16MHz)					;
;			Hence 1 step = 0.25 micro seconds			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
	list		p=12F1822      ; list directive to define processor
	#include	"p12F1822.inc" ; p12F1822 specific variables
    __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
    __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_LO & _LVP_OFF
;	page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Macro definitions					;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Device dependent Macros			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
DEVset	macro	
	BANKSEL	OSCCON		; Bank=1
	movlw	B'01111010'	; 16MHz and internal oscillator
	movwf	OSCCON
;
;	BANKSEL	INTCON		; Interrupt Con (in all banks hence comment)
	clrf	INTCON		; Disable all interrupts
;
; PORTA initialization
	BANKSEL	PORTA		; Bank=0
	clrf	PORTA
;	BANKSEL	LATA		; Bank=2
;	clrf	LATA
	BANKSEL	ANSELA		; Bank=3
	clrf	ANSELA		; No use of ADC
	BANKSEL	ADCON0		; Bank=1
	clrf	ADCON0		; No use of ADC
;
	BANKSEL	TRISA		; Bank=1
	movlw	B'11111000'	; RA0,1 and 2 are output
	movwf	TRISA
;
	BANKSEL	OPTION_REG	; Bank=1
	bcf	OPTION_REG,7	; Enable weak pull-up
	BANKSEL	WPUA		; Bank=4
	movlw	B'00111000'	; Weak Pull-up for RA 3,4 and 5
	movwf	WPUA		;  
;
	clrf	BSR		; Bank=0
	InitP			; Initialize ports
	endm
;
InitP	macro			; Initialize ports
	movlw	B'11111110'	; Outputs H excluding DHT11
	movwf	PORTA
	endm
;		
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	I2C Macros for general purpose		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;		
; *** for I2C-Master protocol ***
; Sending data to I2C slave
I2Csnd	macro	slave,dataa,datalen
	movlw	slave
	movwf	I2Cadr
	movlw	dataa
	movwf	FSR0L
	movlw	datalen
	movwf	DataLen
	call	I2Csndr
	endm	
;
; *** Receiving data from I2C slave ***
I2Crcv	macro	slave,dataa,datalen
	movlw	slave
	movwf	I2Cadr
	movlw	dataa
	movwf	FSR0L
	movlw	datalen
	movwf	DataLen
	call	I2Crcvr
	endm	
;
; *** I2C start signal ***
I2Cstat macro
	call	I2Cstar
	endm
;
; *** I2C stop signal ***
I2Cstop	macro
	call	I2Cstpr
	endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	I2C Macros for New_LiquidCrystal_I2C	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ***** for New LiquidCrystal-I2C *****
; *** Start I2C, send LCD adr, and get Ack, without stoP ***
LCDsA	macro
	call	lSndAr		; I2C start and send it
	endm
;
;*** Start, I2C,send LCD adr, and send Literal and stoP ***
LCDl	macro	lcdLit
	movlw	lcdLit
	call	lSndALr
	endm
;
; *** Set cursor (Col, Row) ***
; Remarks: use Decimal(D'n') when value n is 10 or over
LCDsetC	macro	Col,Row
 	if	Row==0
	movlw	H'80'+Col
 	endif
 	if 	Row==1
	movlw	H'C0'+Col
 	endif
 	if 	Row==2
	movlw	H'94'+Col
 	endif
 	if 	Row==3
	movlw	H'D4'+Col
	endif
 	if 	Row>3
	* row error *
	endif
	call	lSetCsr
	endm
;
; *** lcd.write a char ***
LCDw	macro	lcdChr
	movlw	lcdChr
	call	lSetChr
	endm
;
; *** lcd.write a byte specified ***
LCDwb	macro	lcdBs
	movf	lcdBs,W
	call	lSetChr
	endm
;
; *** lcd.clear() ***
LCDclr 	macro
	call	lClr
	endm
;	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Time cosuming macros			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic	macro			;Consume 1 μS only
	goto	$+1
	goto	$+1
	endm
;
Mic2	macro	mic2p		;Consume 2 μS x n
	movlw	mic2p
	call	Mic2r
	endm
;
Mic2p5	macro 	mic25p		; Consume 2.5μS x n
	movlw	mic25p
	call	Mic25r
	endm
;
Mic5	macro	mic5p		; Consume 5μS x n
	movlw	mic5p
	call	Mic25r
	movlw	mic5p
	call	Mic25r
	endm
;
Mic50	macro	mic50p		; Consume 50μS x n
	movlw	mic50p
	call	Mic50r
	endm
;
Milli	macro	millip		; Consume mS x n
	movlw	millip
	call 	Millir
	endm
;
Mil100	macro	mil100p		; Consume 100 mS x n
	movlw	mil100p
	call 	Mil100r
	endm
; 
Secs	macro	secsp		; Consume Second x n
	movlw	secsp
	call	Secsr
	endm
;
Mins	macro	minsp		; Consume Minute x n
	movlw	minsp
	call	Minsr
	endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Logic macros				;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Comparison macros		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Compare A w/ B and branch to Smaller, Equal, or Larger(next statm't line) 
CabSEL	macro	Aadr,Badr,Smladr,Eqladr
	movf	Badr,W		; W=B
	subwf	Aadr,W		; W=A-B
	btfss	STATUS,C	; A≧B? Yes, skip next
	goto	Smladr		; 	If A<B goto Smaladr
	btfsc	STATUS,Z	; A=B? No skip next
	goto	Eqladr		;	If A=B goto Eqladr
;				; 	If A>B then next (here)
	endm
;
;	Compare A w/ B and branch to Smaller or Others (Equal or Larger) 
CabSO	macro	Aadr,Badr,Smladr
	movf	Badr,W		; W=B
	subwf	Aadr,W		; W=A-B
	btfss	STATUS,C	; A≧B? Yes, skip next
	goto	Smladr		; 	If A<B goto Smaladr
;				; 	If A≧B then next (here)
	endm
;
;	Compare A w/ B and branch to Equal, or Other(next statm't line) 
CabEO	macro	Aadr,Badr,Eqladr
	movf	Badr,W		; W=B
	subwf	Aadr,W		; W=A-B
	btfsc	STATUS,Z	; A=B? 
	goto	Eqladr		;	If A=B goto Eqljmp
;				; 	else next (here)
	endm
;
;	Compare A w/ literal and branch to Smaller, Equal, or Larger(next statm't) 
CalSEL	macro	Aadr,Blit,Smladr,Eqladr
	movlw	Blit		; W=B
	subwf	Aadr,W		; W=A-B
	btfss	STATUS,C	; A≧B? Yes, skip next
	goto	Smladr		; 	If A<B goto Smaladr
	btfsc	STATUS,Z	; A=B? No skip next
	goto	Eqladr		;	If A=B goto Eqladr
;				; 	If A>B then next (here)
	endm
;
;	Compare A w/ literal and branch to Smaller, or Others (Equal or Larger) 
CalSO	macro	Aadr,Blit,Smladr
	movlw	Blit		; W=B
	subwf	Aadr,W		; W=A-B
	btfss	STATUS,C	; A≧B? Yes, skip next
	goto	Smladr		; 	If A<B goto Smaladr
;				; 	If A≧B then next (here)
	endm
;
;	Compare A w/ literal and branch to Equal, or Others 
CalEO	macro	Aadr,Blit,Eqladr
	movlw	Blit		; W=B
	subwf	Aadr,W		; W=A-B
	btfsc	STATUS,Z	; A=B? No skip next
	goto	Eqladr		;	If A=B goto Eqladr
;				; 	else next (here)
	endm
;
;	Compare A w/ literal and branch to Large, or Others
CalLO	macro	Aadr,Blit,Ladr
	movlw	Blit		; W=B
	subwf	Aadr,W		; W=A-B
	btfss	STATUS,C	; A≧B? Yes, skip next
	goto	$+3		; 	If A<B goto Others
	btfss	STATUS,Z	; A=B? Yes skip next
	goto	Ladr		;	If A>B goto Laddr
;				; 	If A≦B then next (here)
	endm
;
;	Compare A with Literal and branch to Un-equal, or Others
CalUO	macro	Aadr,Blit,Uneqladr
	movlw	Blit		; W=B literal
	subwf	Aadr,W		; W=A-B	
	btfss	STATUS,Z	; A=B?
	goto	Uneqladr	; No, goto unequal
;				;	If yes then next
	endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Files and Equations					;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Files				;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	cblock	H'20'
; For Variables to be shown
	Moji1			; RTC Mode char byte
	Moji2			; Show =
	Dig10			; Decimal value 10
	Dig1			; Decimal value 1
;
; For RTC support
	ModeN	; Mode to point BCD mem addr of RTC
	ModeChr	; Character to show mode
	RvMax	; Max number of RTC data in ModeN
	RvMin	; Minimum num of RTC data in ModeN
	Byteh	; Work area as high byte of a word
	Bytel	; Work area as low byte of a word
	RTCmem	; RTC memory address
	BCDsec	; RTC memory 0 = Second BCD	00-59
	BCDmin	; RTC memory 1 = Min BCD	00-59
	BCDhr	; RTC memory 2 = Hour BCD	00-23
	BCDdow	; RTC memory 3 = Day of Week 	01-07
	BCDday	; RTC memory 4 = Day BCD	01-31
	BCDmon	; RTC memory 5 = Month BCD 	01-12
	BCDyr	; RTC memory 6 = Year yy BCD 	00-99
;
; For LCD support
	Abyte			; LCD I2C addr with R/W bit
	Dbyte			; Data byte to save Sbyte
	Ebyte			; The same purpose as Dbyte
	Wbyte			; Working byte
;
; For I2C protocols
	I2Cadr			; Destinated slave I2C address
	DataLen			; Number of bytes to be sent/received
;
; For DHT11 input data area
	rhH			; Relative humidity high byte
	rhL			; Relative humidity low byte
	tcH			; Temp-C high byte, also binH (B2D work)
	tcL			; Temp-C low byte, also binL (B2D work)
	chkSum			; Checksum
;	
;For DHT11 work area
	Sbyte			; Byte sent/received
	Bytectr			; Byte coounter of reading data
	Bitctr			; Bit coounter of reading data
;
; Areas for time consuming subroutines
 	Mic25c
	Mic50c
	Millic
	Mil100c
	Secsc
	Minsc
;
	endc
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Equations			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	For PORTA		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;DHT11	equ	0		; PORTdht DHT111 one wire signal
;Cl	equ	1		; PORTI2C SCL
;Dl	equ	2		; PORTI2C SDA
;swMode	equ	3		; PORTsw Mode Switch
;swTime	equ	4		; PORTsw Time switch
;swSet	equ	5		; PORTsw Set switch
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ***	Logical PORTdht		; Change this when port changed
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PORTdht	equ	PORTA
DHT11	equ	0		; DHT11 one-wire signal
LATdht	equ	LATA		; Latch for dht port
TRISdht	equ	TRISA		; TRIS for dht
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ***	Logical PORTI2C		; Change this when port changed
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PORTI2C equ	PORTA		; 
Dl	equ	2		; I2C Data line = SDA
Cl	equ	1		; I2C Clock line = SCL
LATI2C	equ	LATA		; LATch for I2C port
TRISI2C equ	TRISA		; TRIS reg for I2C
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ***	Logical PORTsw		; Change this when port changed
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PORTsw	equ	PORTA
swMode	equ	3		; Mode switch input ulled-up
swTime	equ	4		; Time switch input pulled-up
swSet	equ	5		; Set switch input pulled-up
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Values & Equations		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; *** for RTC	***
RTCi2cA equ	H'68'		; RTC I2C address (for Arduino)
rtcAw	equ	RTCi2cA*2	; RTC I2C address<<1 and Write
rtcAr	equ	RTCi2cA*2+H'01'	; RTC I2C address<<1 and Read
DS3231	equ	rtcAw		; RTC DS3231 address (to write)
;
RTCdata equ	BCDsec		; RTC memory data top
ModeMax	equ	6		; RTC data pointer ModeN max
ModeMin	equ	0		; RTC data pointer ModeN minimum
;
; Max and Minimum values for RTC memory
secMax	equ	H'59'
secMin	equ	0
minMax	equ	H'59'
minMin	equ	0
hrMax	equ	H'23'
hrMin	equ	0
dowMax	equ	H'07'
dowMin	equ	H'01'
dayMax	equ	H'31'
dayMin	equ	H'01'
monMax	equ	H'12'
monMin	equ	H'01'
Modeyr	equ	6
yrMax	equ	H'99'
yrMin	equ	0
;
;Characters to show Mode of RTC access
ChMY	equ	A'Y'
ChMEq	equ	A'='
ChMM	equ	A'M'
ChMd	equ	A'D'
ChMw	equ	A'W'
ChMh	equ	A'h'
ChMm	equ	A'm'
ChMS 	equ	A'S'
; *** for LCD	***
LCDi2cA	equ	H'27'		; LCD I2C address (for Arduino)
lcdAw	equ	LCDi2cA*2	; LCD I2C address<<1 and Write
lcdAr	equ	LCDi2cA*2+H'01' ; LCD I2C address<<1 and Read
LCD2004	equ	lcdAw		; LCD LCD2004 address ( to write)
;
; *** for DHT	***
;address equations
binH	equ	tcH
binL	equ	tcL
;
; *** for I2C ***
Clkt	equ	1	; Clock-time/4 multiplier of 2.5μS
Clkq	equ	1	; Quick time within clock  2μS
;
	page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Initializing						;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	org	0
	goto	Startp		; Go to start entry
	org	4		; This is Interrupt entry
	retfie	
;
Startp	DEVset			; Define ports
	clrf	FSR0H		; Clear FSR0H forever
	clrf	FSR1H		; Clear FSR1H forever
;
	Milli	D'50'		; Wait devices stabilized
	call	LCDinir	 	; Set-up LCD
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Main program loop					;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mainp	call	RTCrdr		; Read clock
	call	DspTime		; Display time
;
	call	DHTrd		; Read DHT11
	call	DspTr		; Display temperature celsium
	call	DspHr		; Disuplay relative humidity
	Secs	1		; for about 1 second
;
	btfss	PORTsw,swSet	; Set switch ?
	call	RTCupdr
	goto	Mainp		; Contilue infinite loop
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	LCDini= LCD initializing routine			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LCDinir	equ	$
	LCDsA			; Send LCD addr
	I2Cstop
;
	LCDl	H'00'		; Start,send adr & 0x00, and Stop
	Mil100	1
;
	LCDl	H'34'
	LCDl	H'30'
	Milli	5
;
	LCDl	H'34'
	LCDl	H'30'
	Mic50	4
;
	LCDl	H'34'
	LCDl	H'30'
	Mic50	4
;
	LCDl	H'24'
	LCDl	H'20'
	Mic50	4
;
	LCDl	H'24'
	LCDl	H'20'
	LCDl	H'84'
	LCDl	H'80'
	Mic50	4
;
	LCDl	H'04'
	LCDl	H'00'
	LCDl	H'C4'
	LCDl	H'C0'
	Mic50	3
;
	LCDl	H'04'
	LCDl	H'00'
	LCDl	H'14'
	LCDl	H'10'
	Milli	2
;
	LCDl	H'04'
	LCDl	H'00'
	LCDl	H'64'
	LCDl	H'60'
	Mic50	3
;
	LCDl	H'08'		; backlight on
	Milli	1
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	RTC reading routine	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
RTCrdr	clrf	RTCmem		; set RTC memory addr 0
	I2Csnd DS3231,RTCmem,1 	; send it to DS3231
	Milli	1		; wait a little (maybe unneeded)
	I2Crcv DS3231,RTCdata,7	; receive 7 byte data from DS3231
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Display-Time routine					;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DspTime equ	$
; Display year
	LCDsetC	0,0		; Set cursor to top
	LCDw	A'2'
	LCDw	A'0'
;
	movf	BCDyr,W		; Get RTC format year
	movwf	Dig1		; Set it to Dig1
	movlw	H'0F'		; Remove upper nibble
	andwf	Dig1,F		;  by AND
	swapf	BCDyr,W		; Get RTC year nibble-swapped
	movwf	Dig10		; Set it to Dig10
	movlw	H'0F'		; Remove upper nibble
	andwf	Dig10,F		; by AND
	call	D2Cr		; convert to characters
	LCDwb	Dig10
	LCDwb	Dig1
	LCDw	A'-'
;	
; Display month
	movf	BCDmon,W	; Same logic for month, as above
	movwf	Dig1
	movlw	H'0F'
	andwf	Dig1,F
	swapf	BCDmon,W
	movwf	Dig10
	movlw	H'0F'
	andwf	Dig10,F
	call	D2Cr		; convert to characters
	LCDwb	Dig10
	LCDwb	Dig1
	LCDw	A'-'	
;
; Display day
	movf	BCDday,W	; Same logic for day, as above
	movwf	Dig1
	movlw	H'0F'
	andwf	Dig1,F
	swapf	BCDday,W
	movwf	Dig10
	movlw	H'0F'
	andwf	Dig10,F
	call	D2Cr		; convert to characters
	LCDwb	Dig10
	LCDwb	Dig1
	LCDw	A' '
;
; Display hour
	movf	BCDhr,W		; Same logic for hour, as above
	movwf	Dig1
	movlw	H'0F'
	andwf	Dig1,F
	swapf	BCDhr,W
	movwf	Dig10
	movlw	H'0F'
	andwf	Dig10,F
	call	D2Cr		; convert to characters
	LCDwb	Dig10
	LCDwb	Dig1
	LCDw	A':'
;
; Display minute
	movf	BCDmin,W	; Same logic for minute, as above
	movwf	Dig1
	movlw	H'0F'
	andwf	Dig1,F
	swapf	BCDmin,W
	movwf	Dig10
	movlw	H'0F'
	andwf	Dig10,F
	call	D2Cr		; convert to characters
	LCDwb	Dig10
	LCDwb	Dig1
	LCDw	A':'
;
; Display second
	movf	BCDsec,W	; Same logic for second, as above
	movwf	Dig1
	movlw	H'0F'
	andwf	Dig1,F
	swapf	BCDsec,W
	movwf	Dig10
	movlw	H'0F'
	andwf	Dig10,F
	call	D2Cr		; convert to characters
	LCDwb	Dig10
	LCDwb	Dig1
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	RTC updating routine					;
;		Display value for current ModeN			;
;		If swMode pushed, display next unit to update	;
;		If swTime pushed, increase value and display it	;
;		If swSet pushed,  update RTC (RTCwtr)		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
RTCupdr	btfss	PORTsw,swSet	; swSet still on?
	goto	$-1		; then wait for off
 	movlw 	Modeyr		; set initial mode year
	movwf	ModeN
;
RTCudm	movf	ModeN,W		; Large loop on ModeN
	brw
	goto	Mdsecr		; case ModeN=0 
	goto	Mdminr		; case ModeN=1 
	goto	Mdhrr		; case ModeN=2 
	goto	Mddowr		; case ModeN=3 
	goto 	Mddayr		; case ModeN=4 
	goto	Mdmonr		; case ModeN=5 
	goto	Mdyrr		; case ModeN=6 
;
; Macro used within  this section
Mdsetup macro	TMc,Rmax,Rmin
	movlw	TMc
	movwf	ModeChr
	movlw	Rmax
	movwf	RvMax
	movlw	Rmin
	movwf	RvMin
	goto	Mdnext
	endm
;
; set up environment for update and display
Mdsecr	Mdsetup	ChMS,secMax,secMin
Mdminr	Mdsetup	ChMm,minMax,minMin
Mdhrr	Mdsetup	ChMh,hrMax,hrMin
Mddowr	Mdsetup	ChMw,dowMax,dowMin
Mddayr	Mdsetup	ChMd,dayMax,dayMin
Mdmonr	Mdsetup	ChMM,monMax,monMin
Mdyrr	Mdsetup	ChMY,yrMax,yrMin
;
Mdnext 	call	Rdspr		; Display X=nn
	btfss	PORTsw,swTime	; Is Time pushed ?
	goto	Rinc		;  Yes, goto  Rinc
	btfss	PORTsw,swMode	; Is Mode pushed ?
	goto	Rnxtm		;  Yes, goto Rnxtm
	btfss	PORTsw,swSet	; Is Set pushed ?
	goto	Rwrite		;  Yes, goto Rwrite
	goto	Mdnext		; If no button, small loop for button
;
; 	Time pushed here
Rinc	call	Rincr		; Increase value in that mode
	Mil100	2		; 0.2 sec for increasing value
	goto	Mdnext		; return to loop for button
;
;	Mode pushed here
Rnxtm	btfss	PORTsw,swMode	; Mode button still pushed
	goto	$-1		; then wait for release
	CalEO	ModeN,0,Msmax	; If current ModeN=0 goto Msmax
	decf	ModeN,F		; set next mode
Rnxtme	goto	RTCudm		; and return to large loop for mode
;
Msmax	movlw	Modeyr		; get maximum mode
	movwf	ModeN		; and set it
	goto	RTCudm		; and return to large loop for mode
;	
Rwrite	btfss	PORTsw,swSet	; Set button still on?
	goto	$-1		; then wait for release
	call	RTCwtr		; and write to RTC
;
	LCDsetC	D'10',3		; Set cursor to Row3, Column 10
	LCDw	A' '		; Clear RTC setting message
	LCDw	A' '
	LCDw	A' '
	LCDw	A' '
	return			; exit from RTC updating routine
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Display value pointed by ModeN	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Rdspr	movf	ModeChr,W
	movwf	Moji1
	movlw	ChMEq
	movwf	Moji2
;
	movlw	BCDsec		; Point BCD area top
	movwf	FSR1L		; set it to FSR1L
	movf	ModeN,W		; Get Mode number
	addwf	FSR1L,F		; Point current BCD area	
	swapf	INDF1,W		; get high nibble to low in W
	movwf	Dig10		; set it to Dig10
	movlw	H'0F'		; Clear high nibble
	andwf	Dig10,F		;  of Dig10
	movf	INDF1,W		; get low nibble to low
	movwf	Dig1		; set it to Dig1
	movlw	H'0F'		; Clear high nibble
	andwf	Dig1		;  of Dig1
	call 	D2Cr		; Convert Decimals to Characters
;
	call	TMdspr
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Time Mode displaying routine		;
;	  	to update RTC			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TMdspr	movlw	Moji1		; Point Byte0 address
	movwf	FSR0L		;  set it to use INDF0
	movlw	4		; Set four chars
	movwf	Bytectr		;  to Byte counter
;
	LCDsetC	D'10',3		; Set cursor to Row3, Column 10
;
TMdspl	movf	INDF0,W		; Get byte content
	movwf	Sbyte		; Set it to Sbyte
	LCDwb	Sbyte		;  and send it
	incf	FSR0L,F		; point next byte
	decfsz	Bytectr,F	; Check if all done
	goto	TMdspl		; No. loop
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Increase value pointed by ModeN	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Rincr	movlw	BCDsec		; Point BCD area top
	movwf	FSR1L		; set it to pointer
	movf	ModeN,W		; get ModeN to add
	addwf	FSR1L,F		; Point current BCD area
;
	CabSO	INDF1,RvMax,Rigo ;If smaller than max, goto Rigo
	movf	RvMin,W		; Else, get minimum value
	movwf	INDF1		; and set it to INDF1 (BCD area)
	return
;
Rigo	movf	INDF1,W		; Get BCD value
	andlw	H'0F'		; clear left nibble
	movwf	Bytel		; and set to Bytel
	swapf	INDF1,W		; Get BCD nibbles swapped
	andlw	H'0F'		; clear left nibble
	movwf	Byteh		; and set to Byteh
;
	incf	Bytel,F		; Bytel+1
	CalSO	Bytel,D'10',Rie ; If Bytel≦9,goto Rie
	movlw	D'16'		; Else increase digit 10
	addwf	INDF1,F		;
	movlw	H'F0'		; and clear digit 1
	andwf	INDF1,F
	return

Rie	incf	INDF1,F		; Increase BCD value
	return			; and return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	RTC writing routine	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
RTCwtr	clrf	RTCmem		; Set memory address zero
	I2Csnd	DS3231,RTCmem,8 ; Send data, includign memory addr in top
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	DHT11 Reading routine				;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DHTrd	movlw	5		; Set # of DHT bytes 5
	movwf	Bytectr		;  to Bytectr
;
	movlw	rhH 		; Point top of DHT data input
	movwf	FSR0L		; Set it to INDF0
;
;	Start signal
	bcf	PORTdht,DHT11	; Set DHT-line L
;
	Milli	D'20'		; for 20mS
	bsf	PORTdht,DHT11	; Set DHT-line H
	Mic2	D'10'		; for 20 micro sec
;
;Header checking from DHT11
	BANKSEL	TRISdht		; Point tris bank
	bsf	TRISdht,DHT11	; Set TRIS-dht input
	BANKSEL	WPUA		; Point WPUA bank
	bsf	WPUA,DHT11	; Pull-up
	clrf	BSR		; Point bank 0
	Mic			; wait 1 micro sec for ready
;
	btfsc	PORTdht,DHT11	; Wait response 1/2 from DHT L
	goto	$-1		;  until L
	Mic5	D'13'		; Wait 65 within 80 micS
;
	btfss	PORTdht,DHT11	; Wait response 2/2 from DHT H
	goto	$-1		;  until H
	Mic5	D'13'		; Wait 65 within 80 micS
;
	btfsc	PORTdht,DHT11 	; Wait Start (L 50 mic sec) from DHT
	goto	$-1
	Mic5	D'6'		; When L, wait for 30 mic sec
;
; Read each byte from DHT11
DHbc	movlw	8		; Set # of bits = 8 in a byte of DHT
	movwf	Bitctr		;  to Bitctr
;
DHbcl	btfss	PORTdht,DHT11	; Wait Data signal H from DHT
	goto	$-1
	Mic50	1		; When H (1=70,0=27 micS), wait 50 micS
;	Trigger			; *** for timing-validation use only ***
;
	btfss	PORTdht,DHT11	; If still on then data is one, else zero
	goto	DHszero
;
DHsone	bsf	Sbyte,0		; Set 1 to Sbyte bit 0
	Mic5	D'4'		; Consume residual H 20 mic S of "1"
	goto	DHeck		; Goto Check end of one byte
;
DHszero	bcf	Sbyte,0		; Set zero to Sbyte bit 0
DHeck	decfsz	Bitctr,F 	; One byte (8 bits) end ?
	goto	DHnxtbi		; No, goto continue bit proc
;
DHbye	movf	Sbyte,W		; If one byte end, here
	movwf	INDF0		; Set data to DHTdata entry
	incf	FSR0L,F		; Point next entry of DHTdata
;
	decfsz	Bytectr,F 	; All bytes end?
	goto	DHbc		; If not end of bytes, next byte
	goto	DHcksr		; If end, checksum validation
;
DHnxtbi	rlf	Sbyte,F		; Bit continues. Shift left.
	goto	DHbcl		; and next bit checking
;
DHcksr	equ	$		; Checksum validation, if needed
;
;  End of receive
;
;Change data line mode to ooutput
;	Wait the last space ending
	Mic2	D'40'		; Residual 28 mic sec space + alpha 
;				; + 50 mic sec until pull-down end
	BANKSEL	LATdht		; Data line high when output mode
	bsf	LATdht,DHT11	; Lat-DHT11 high
	BANKSEL	TRISdht		; Select tris bank
	bcf	TRISdht,DHT11	; Set DHT11 output mode
	clrf	BSR		; Select bank 0
;
	Mic			; Wait one micro Sec
	bsf	PORTdht,DHT11	; Signal high
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Display temperature 					;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DspTr	equ	$
	LCDsetC	1,1
	LCDw	A'T'
	LCDw	A'e'
	LCDw	A'm'
	LCDw	A'p'
	LCDw	A'e'
	LCDw	A'r'
	LCDw	A'a'
	LCDw	A't'
	LCDw	A'u'
	LCDw	A'r'
	LCDw	A'e'
	LCDw	A' '
	LCDw	A'='
	LCDw	A' '
DspTgo	call	B2Dr		; Convert binary data to Decimals
	call	D2Cr		; Convert Decimals to Characters
 	LCDwb	Dig10
	LCDwb	Dig1
	LCDw	H'DF'		; degree
	LCDw	A'C'
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Disuplay relative humidity				;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DspHr	equ	$
	LCDsetC	1,2
	LCDw	A'R'
	LCDw	A'e'
	LCDw	A'l'
	LCDw	A'.'
	LCDw	A'H'
	LCDw	A'u'
	LCDw	A'm'
	LCDw	A'i'
	LCDw	A'd'
	LCDw	A'i'
	LCDw	A't'
	LCDw	A'y'
	LCDw	A' '
	LCDw	A'='
	LCDw	A' '
;
	movf	rhH,W
	movwf	binH
;
	call	B2Dr
	call	D2Cr
 	LCDwb	Dig10
	LCDwb	Dig1
	LCDw	A'%'
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Convert mesured Binary data to Decimal			;
;		from binH to Dig10+Dig1				;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
B2Dr	movf	binH,W		; Move binH
	movwf	Dig1		;  to Dig1
	clrf	Dig10		; Clear Dig10
;
B2Dlp	CalSO	Dig1,D'10',B2De
	movlw	D'10'
	subwf	Dig1,F
	incf	Dig10,F
	goto	B2Dlp
;	
B2De	return
;	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Convert Decimals to Characters				;
;		changing Dec10-1 to characers			;
;		with clearing leading-zero			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
D2Cr	movlw	H'30'		; Left nibble of numeric chars
	iorwf	Dig10,F		; Convert Dig10 to character
	iorwf	Dig1,F		; Convert Dig1 to character
;
	CalEO	Dig10,H'30',D2Czb ; Check leading 0 ?
	return			; No, return
;
D2Czb	movlw	A' '		; If zero, replace with blank
	movwf	Dig10		; 	at Dig10
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	LCD slave-adr sending routine			;
;	   	with address in Sbyte, getting Ack.	;
;		(start-I2C included, without stop-I2C)	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lSndAr	equ	$
	I2Cstat			; start I2C
	movlw	lcdAw		; get LCD slave adr
	movwf	Sbyte		; set it to Sbyte
	call	Sendr		; and send it
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	LCD I2C adr and a Literal sending routine	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lSndALr	movwf	Dbyte		; save literal to Dbyte
	call	lSndAr		; send adr
	movf	Dbyte,W		; get saved literal
	movwf	Sbyte
	call	Sendr		; send it
	I2Cstop			; stop I2C
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Set-cursor routine for LCD called by lcdSetC	;
;	If W=0xab, send 0xaC, 0xa8, 0xbC, and 0xb8	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lSetCsr	movwf	Ebyte		; save Value into Ebyte
	call	lSetCss 	; send left nibble
	swapf	Ebyte,W		; set W w/ swapping nibbles
	call 	lSetCss		; send right nibble
;
	Mic50	1
	return
;
; 	lSetCss subroutine to send a nibble
lSetCss movwf	Wbyte
	movlw	H'0F'
	iorwf	Wbyte,F		; set xF
	movlw	H'FC'
	andwf	Wbyte,W		; change it to xC
	movwf	Wbyte		; set it to Wbyte, too
	call 	lSndALr		; send S, adr, nibble+C, and P
;
	movlw	B'11111011'	; get complement of 0C-08
	andwf	Wbyte,W		; and change C to 8, ie x8
	call	lSndALr		; send S, adr, nibble+8, and P
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	LCD send-char routine			;
;	If W=0xab, send 0xaD, 0xa9, 0xbD, and 0xb9	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lSetChr movwf	Ebyte		; save Value into Ebyte
;	sending left nibble
	call	lSetChs
;
;	sending right nibble
	swapf	Ebyte,W		; replace left nibble w/ right
	call	lSetChs
	return
;
; 	LCD subroutine to send a character  ;
lSetChs	movwf	Wbyte		; W to Wbyte
	movlw	H'0F'		; set right nibble bits of 
	iorwf	Wbyte,F		;   Wbyte on
	movlw	H'FD'		; leave left nibble + right D
	andwf	Wbyte,W		;  into W
	movwf	Wbyte		; save it into Wbyte
	call 	lSndALr		; send S, adr, nibble+D, and P
;
	movf	Wbyte,W
	movlw	B'11111011'	; target bit 2 to off (D to 9)
	andwf	Wbyte,W		; make left nibble + right 9
	call	lSndALr		; send S, adr, nibble+9, and P	
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	LCD.clear routine				;
;	Send 0x8C, 0x88, 0x0C, and 0x08			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lClr	equ	$
	LCDw	H'8C'
	LCDw	H'88'
	LCDw	H'0C'
	LCDw	H'08'
	Mic50	1
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	I2C Send byte-string				;
;         when called,					;
;		I2C device adr in I2Cadr byte		;
;		Data length in DataLen			;
;		Data Addr in FSR0L (INDF0)		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I2Csndr	movf	I2Cadr,W
	movwf	Sbyte
;	rlf	Sbyte,F	; shift leftt (if adr for Arduino)
	bcf	Sbyte,0	; indicate write
;
	I2Cstat		; Start I2C
	call	Sendr

Sdata	movf	INDF0,W	; Get a sending character
	movwf	Sbyte	; Set it to Sbyte
	call	Sendr	; Send it to the device
;
	incf	FSR0L,F	; point next char
	decfsz	DataLen,F ; Have all chars sent ?
	goto	Sdata		; No, loop
;
; Stop signal and return
	I2Cstop
	return	
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	I2C Receive byte-string				;
;         when called,					;
;		I2C device adr in I2Cadr byte		;
;		Data length in DataLen			;
;		Data Addr in FSR0L (INDF0)		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I2Crcvr	equ	$
	I2Cstat		; Start I2C
	movf	I2Cadr,W ; Get I2C dev addr
	movwf	Sbyte	; Set it into Sbyte
;	rlf	Sbyte,F	; Shift left (if adr for Arduino)
	bsf	Sbyte,0	; indicate read
	call	Sendr	; Send slave addr to read
;
I2Crbyt	equ	$
	BANKSEL	TRISI2C	;
	bsf	TRISI2C,Dl ; Set Dline input mode
	clrf	BSR	; Point Bank 0
;
	movlw	8	; Bits in a reciving byte
	movwf	Bitctr	; into loop counter 
I2Crblp	Mic2p5	2*Clkt	; Timing before raising clock
	bsf	PORTI2C,Cl ; Set clock high
	Mic2p5	Clkt	; Timing after raising clock
;
	btfsc	PORTI2C,Dl
	goto	Rbith
;	goto	Rbitl
;
Rbitl	bcf	Sbyte,0	; Clear bit 0
	goto	Rbitnxt	; and goto next
;
Rbith	bsf	Sbyte,0	; Set bit 0
Rbitnxt	Mic2	Clkq	; Timing after checking
	bcf	PORTI2C,Cl ; Set clock low
;	Mic2p5	Clkt	; Timing after clock falling
	decfsz	Bitctr,F ; Still bits?
	goto	Rbcont	; Yes, continue
	goto	Rbend	; No, end of one byte
;
Rbcont	rlf	Sbyte,F	; Shit left
	goto	I2Crblp	; and goto loop
;
Rbend	movf	Sbyte,W	; Get received byte
	movwf	INDF0	; Set it to INDF0
	incf	FSR0L,F	; increase index
	decfsz	DataLen,F ; DataLen-1
	goto	Sackr	; Send Ack and continue
	goto	Snackr	; Send Nack and stop
;
;Set Dl output mode and send Ack to conitinue
Sackr	equ	$
	BANKSEL	LATI2C	; Data line high when output mode
	bsf	LATI2C,Dl ; Lat-Dl on
	BANKSEL	TRISI2C	; 
	bcf	TRISI2C,Dl ; Set Dl output mode
	clrf	BSR	; Point Bank 0
;
	bcf	PORTI2C,Dl ; Send Ack
	Mic2	Clkq	; Timing after clock falling
	bsf	PORTI2C,Cl ; Show Ack
	Mic2p5	2*Clkt
	bcf	PORTI2C,Cl ; Set clock low
	Mic2	Clkq
	bsf	PORTI2C,Dl ; Return Dline to high
	goto	I2Crbyt		; Next byte process
;
;Set Dl output mode and send Nack
Snackr	equ	$
	BANKSEL	LATI2C	; Data line high when output mode
	bsf	LATI2C,Dl ; Lat-Dl on
	BANKSEL	TRISI2C	; 
	bcf	TRISI2C,Dl ; Set Dl output mode
	clrf	BSR	; Point Bank 0
;
	bsf	PORTI2C,Dl ; Send Nack
	Mic2	Clkq	; Timing after clock falling
	bsf	PORTI2C,Cl ; Show Nack
	Mic2p5	2*Clkt
	bcf	PORTI2C,Cl	; Set clock low
	Mic2p5	Clkt
	I2Cstop		; and stop I2C once
	Mic5	D'6'	; for 30 micro sec
;
	I2Cstat		; then start I2C again
	movf	I2Cadr,W ; Get I2C dev addr
	movwf	Sbyte	; Set it into Sbyte
;	rlf	Sbyte,F	; Shift left (if adr for Arduino)
	bcf	Sbyte,0	; indicate write
	call	Sendr	; Send it
;
	I2Cstop
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	I2C Start signal routine 			;
;	   	when dataline mode is output		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I2Cstar	bcf	PORTI2C,Dl ; set SDA low
	Mic2	Clkq
	bcf	PORTI2C,Cl ; set SCL low
	Mic2p5	2*Clkt
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	I2C Stop signal routine 			;
;	   	when dataline mode is output		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I2Cstpr	bcf	PORTI2C,Cl ; set SCL low
	Mic2	Clkq
	bcf	PORTI2C,Dl ; set SDA low
	Mic2p5	2*Clkt
	bsf	PORTI2C,Cl ; Clock line rasing
	Mic2p5	Clkt
	bsf	PORTI2C,Dl ; Data line rasing
	Mic2	Clkq
	return	
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	I2C One-byte sending routine 			;
;	   	with data in Sbyte			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Sendr	movlw	8	; Set bit count in a byte
	movwf	Bitctr	; into loop counter 
;
Sloop	btfsc	Sbyte,7	; Check top bit of Sbyte
	goto	Slpdh	; 
	bcf	PORTI2C,Dl ; If bit low then Data L
	goto	Slpnxt
Slpdh	bsf	PORTI2C,Dl ; If bit high then Data H
;
Slpnxt	Mic2	Clkq
	bsf	PORTI2C,Cl ; Show bit
	Mic2p5	2*Clkt
	bcf	PORTI2C,Cl ;
	Mic2	Clkq
;
	rlf	Sbyte,F	; Shift left 
	decfsz	Bitctr,F ; All bits done?
	goto	Sloop	; No, loop within a byte
;	
;Receive Ack 		
; set data line input mode
	BANKSEL	TRISI2C	; 
	bsf	TRISI2C,Dl ; Set Dline input mode
	clrf	BSR	; Point Bank 0
;
	Mic2	Clkq	; wait for Ack timing
	bsf	PORTI2C,Cl ; Clock H for Acq confirmation
	Mic2p5	2*Clkt	; 
	bcf	PORTI2C,Cl ; Cl L for Dl release by slave
	Mic2p5	2*Clkt
;
; Set Data line output
	BANKSEL	LATI2C	; Data line high when output mode
	bsf	LATI2C,Dl ; Lat-Dl on
	BANKSEL	TRISI2C	; 
	bcf	TRISI2C,Dl ; Set Dl output mode
	clrf	BSR	; Point Bank 0
	return
;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Timing subrooutines for general purposes		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Make 2.0 micro S x n	(Mic2)	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic2r	movwf	Mic25c		; + Wset + call = 1 micro sec 
;
Mic2l	decfsz	Mic25c,F	; If exhausted, 1 micro S hereafter
	goto	Mic2li		; else go out (2nd time 1.75 mic sec)
	return		
;
Mic2li	goto	$+1		;            (2nd time 2.25 mic sec)
	nop			;	     (2nd time 2.5 mic sec)
	goto	Mic2l		; go back    (2nd time 3 micro sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Make 2.5 micro S x n (Mic2p5)	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic25r	movwf	Mic25c		; + Wset + call = 1 micro sec 
	nop			; 1.25 micro sec
;
Mic25l	nop			; 1.5 micro sec (2nd time 4 mic sec)
	decfsz	Mic25c,F	; If exhausted, 1 micro S hereafter
	goto	Mic25li		; else go out (2nd time 2.25 mic sec)
	return		
;
Mic25li	Mic			;	      (2nd time 3.25 mic sec)
	goto	Mic25l		; go back    (2nd time 3.75 micro sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	50 Microseconds	x n	Mic50  	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Mic50r	movwf	Mic50c	 	; set how many 50 microsec (1 micro sec to here)
	nop			; 1.25 micro sec up to here
;
Mic50l	Mic2p5	D'19'		; + 47.5 = 48.75 mic sec (2nd time 98.75 mic sec)
	nop			; + 0.25 = 49 micro sec (2nd time 99 mic sec)
; 
	decfsz	Mic50c,F	; If exhausted then 1 mic S hereafter
	goto	Mic50li		; else go out (2nd time 49.75 mic sec)
	return
;
;
Mic50li	Mic			; 	  (2nd time 50.75 mic sec)
	goto	Mic50l		; go back (2nd time 51.25 mic sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Milliseconds x n	(Milli)	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Millir	movwf	Millic 		; set how many 1 mil sec (1 mic S up to here)
	nop			; 1.25 micro sec
;
Millil	Mic50	D'19'		; + 50 mic x 19 = 951.25 mic S (2nd, 1951.25) 
	Mic2p5	D'19'		; + 47.5 mic = 998.75 micro S  (2nd, 1998.75)
	nop			; +0.25 mic = 999 micro sec    (2nd, 1999)
;
	decfsz	Millic,F	; If  exhausted then 1 micro sec hereafter
	goto	Millili		; else go out (2nd, 999.75 mic S)
	return
;
Millili	Mic			; 		(2nd time 1000.75 mic S)
	goto	Millil		; go back (2nd time 1001.25 mic S)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	100 Milliseconds x n	(Mil100);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mil100r	movwf	Mil100c		;set how many 100 ms(1 micr sec up to here)
	nop			; 1.25 micro sec
;
Milhl	Milli	D'99'		;+1ms x 99 = 99001.25 micS (2nd,199001.25mic)
	Mic50	D'19'		; + 950 mic = 99951.25 micS(2nd.199951.25mic)
	Mic2p5	D'19'		; + 47.5 mic = 99998.75micS(2nd,199998.75mic)
	nop			; + 0.25 mic = 99999 mic S (2nd,199999 micS)
;
	decfsz	Mil100c,F	; If exhausted then 1 micro sec hereafter
	goto	Milhli		; else go out (2nd time, 99999.75 mic S)
	return
;
Milhli	Mic			;  	    	(2nd time, 100000.75 mic S)
	goto	Milhl		; 		(2nd time, 100001.25 mic S)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Seconds x n	 (Secs)		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Secsr	movwf	Secsc 		; set how many sec ( 1 mic sec up to here)
	nop			; 1.25 micro sec
;
Secsl	Mil100	D'9'		; 
	Milli	D'99'		; + 999 milli sec = 999001.25 micro sec
;
	Mic50	D'19'		; + 950 mic = 999951.25 micro sec
	Mic2p5	D'19'		; + 47.5 mic = 999998.75 micro sec
	nop			; + 0.25 mic = 999999 micro sec
;
	decfsz	Secsc,F		; If exhausted then 1 micro sec hereafter
	goto	Secsli		; else, go out 
	return
;
Secsli	Mic
	goto	Secsl		; (Second time, Sec + 1.25 micro sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Minutes	x n	 (Mins)		;
;	 Overhead ignored, that is only	;
;	 751.25 Mic S even when 100 Min	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Minsr	movwf	Minsc		;set how many minutes from parameter
;
Minsl	Secs	D'60'		; 1 Seconds x 60
	decfsz	Minsc,F
	goto	Minsl
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	End of program						;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	end

 

数個のコンパイルエラーを直して試しに実行したら、なんと1回で素直に動いてしまったではありませんか!(びっくり)。何もエラーがない感じ。

まあ、動いているプログラムから作ったコピペが大部分ですからね。そういうわけで、この後で不要なマクロを外したり、Equなどの整頓をしようかと思ってましたが、初版のまま載せておきました。

タクトスイッチは次の写真で、左からMode, Time, Setです。Setを押せば、ModeとTimeのスイッチを使ってカレンダーと時刻の更新ができます。この機能は操作性もよく、気づく問題はありません。とりあえずLCDの4行目を更新専用に使っています。

f:id:a-tomi:20210104155741j:plain

ところで、PICは必ずしもMPLAB X IDEを使わなくともプログラムできます。

この例では単独のMPASMでアセンブリーしてHEXファイルを作り、PICkit2で書き込んでます。(最新のPICkit4で書き込む場合はMPLAB X IPEを使用。) 色々なトラブルにまきこまれないためには、アセンブラーならいまだにこのほうが簡単で単純だと思いますがどうでしょう。

ちなみに最後にアセンブリーリストをつけておきますね。プログラムや変数など、もっと整理して小さくできますが、このままでもプログラムメモリーは小さなPIC12F1822がもつ2048ワード中の856ワード(42%)、データメモリーは128バイト中の69バイト(54%)で収まっています。つまりI2Cセンサーがもっともっとつけられますね。なので、このままにしておきます。

MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE  1


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00001 ;U210103-RTC-DHT11-LCD-V00.asm                                  As of Jan. 3, 2021
                      00002 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00003 ;                                                                               ;
                      00004 ;       Time, Temperature, and Humidity Display with PIC12F1822 V00             ;
                      00005 ;               (C)2014-2021 Akira Tominaga, All rights reserved.               ;
                      00006 ;                                                                               ;
                      00007 ;         Major revisions                                                       ;
                      00008 ;               V00 Initial version             December 31, 2020               ;
                      00009 ;                                                                               ;
                      00010 ;         Function                                                              ;
                      00011 ;               1.Show temperature, & humidity on LCD                           ;
                      00012 ;                                                                               ;
                      00013 ;         Input/output                                                          ;
                      00014 ;               RA0 DHT11 Temp&Humidity-sensor w/ 1-wire protocol               ;
                      00015 ;               RA1 SDA for I2C-RTC  output  usually and input occasionally     ;
                      00016 ;               RA2 SCL for I2C-RTC  output                                     ;
                      00017 ;               RA3 Mode switch (swMode) input pulled-up                        ;
                      00018 ;               RA1 Time switch (swTime) input pulled-up                        ;
                      00019 ;               RA0 Set switch  (swSet)  input pulled-up                        ;
                      00020 ;                                                                               ;
                      00021 ;                                                                               ;
                      00022 ;         Remarks                                                               ;
                      00023 ;               1. Clock = HFINTOSC (   16MHz)                                  ;
                      00024 ;                       Hence 1 step = 0.25 micro seconds                       ;
                      00025 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00026 ;
                      00027         list            p=12F1822      ; list directive to define processor
                      00028         #include        "p12F1822.inc" ; p12F1822 specific variables
                      00001         LIST
                      00002 
                      00003 ;==========================================================================
                      00004 ;  MPASM PIC12F1822 processor include
                      00005 ; 
                      00006 ;  (c) Copyright 1999-2013 Microchip Technology, All rights reserved
                      00007 ;==========================================================================
                      00008 
                      01035         LIST
8007   09A4           00029     __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_
                            OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
8008   1CFF           00030     __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_LO & _LVP_OFF
                      00031 ;       page
                      00032 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00033 ;       Macro definitions                                       ;
                      00034 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00035 ;
                      00036 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00037 ;       Device dependent Macros                 ;
                      00038 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00039 ;
                      00040 DEVset  macro   
                      00041         BANKSEL OSCCON          ; Bank=1
                      00042         movlw   B'01111010'     ; 16MHz and internal oscillator
                      00043         movwf   OSCCON
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE  2


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00044 ;
                      00045 ;       BANKSEL INTCON          ; Interrupt Con (in all banks hence comment)
                      00046         clrf    INTCON          ; Disable all interrupts
                      00047 ;
                      00048 ; PORTA initialization
                      00049         BANKSEL PORTA           ; Bank=0
                      00050         clrf    PORTA
                      00051 ;       BANKSEL LATA            ; Bank=2
                      00052 ;       clrf    LATA
                      00053         BANKSEL ANSELA          ; Bank=3
                      00054         clrf    ANSELA          ; No use of ADC
                      00055         BANKSEL ADCON0          ; Bank=1
                      00056         clrf    ADCON0          ; No use of ADC
                      00057 ;
                      00058         BANKSEL TRISA           ; Bank=1
                      00059         movlw   B'11111000'     ; RA0,1 and 2 are output
                      00060         movwf   TRISA
                      00061 ;
                      00062         BANKSEL OPTION_REG      ; Bank=1
                      00063         bcf     OPTION_REG,7    ; Enable weak pull-up
                      00064         BANKSEL WPUA            ; Bank=4
                      00065         movlw   B'00111000'     ; Weak Pull-up for RA 3,4 and 5
                      00066         movwf   WPUA            ;  
                      00067 ;
                      00068         clrf    BSR             ; Bank=0
                      00069         InitP                   ; Initialize ports
                      00070         endm
                      00071 ;
                      00072 InitP   macro                   ; Initialize ports
                      00073         movlw   B'11111110'     ; Outputs H excluding DHT11
                      00074         movwf   PORTA
                      00075         endm
                      00076 ;               
                      00077 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00078 ;       I2C Macros for general purpose          ;
                      00079 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;               
                      00080 ; *** for I2C-Master protocol ***
                      00081 ; Sending data to I2C slave
                      00082 I2Csnd  macro   slave,dataa,datalen
                      00083         movlw   slave
                      00084         movwf   I2Cadr
                      00085         movlw   dataa
                      00086         movwf   FSR0L
                      00087         movlw   datalen
                      00088         movwf   DataLen
                      00089         call    I2Csndr
                      00090         endm    
                      00091 ;
                      00092 ; *** Receiving data from I2C slave ***
                      00093 I2Crcv  macro   slave,dataa,datalen
                      00094         movlw   slave
                      00095         movwf   I2Cadr
                      00096         movlw   dataa
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE  3


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00097         movwf   FSR0L
                      00098         movlw   datalen
                      00099         movwf   DataLen
                      00100         call    I2Crcvr
                      00101         endm    
                      00102 ;
                      00103 ; *** I2C start signal ***
                      00104 I2Cstat macro
                      00105         call    I2Cstar
                      00106         endm
                      00107 ;
                      00108 ; *** I2C stop signal ***
                      00109 I2Cstop macro
                      00110         call    I2Cstpr
                      00111         endm
                      00112 ;
                      00113 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00114 ;       I2C Macros for New_LiquidCrystal_I2C    ;
                      00115 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00116 ; ***** for New LiquidCrystal-I2C *****
                      00117 ; *** Start I2C, send LCD adr, and get Ack, without stoP ***
                      00118 LCDsA   macro
                      00119         call    lSndAr          ; I2C start and send it
                      00120         endm
                      00121 ;
                      00122 ;*** Start, I2C,send LCD adr, and send Literal and stoP ***
                      00123 LCDl    macro   lcdLit
                      00124         movlw   lcdLit
                      00125         call    lSndALr
                      00126         endm
                      00127 ;
                      00128 ; *** Set cursor (Col, Row) ***
                      00129 ; Remarks: use Decimal(D'n') when value n is 10 or over
                      00130 LCDsetC macro   Col,Row
                      00131         if      Row==0
                      00132         movlw   H'80'+Col
                      00133         endif
                      00134         if      Row==1
                      00135         movlw   H'C0'+Col
                      00136         endif
                      00137         if      Row==2
                      00138         movlw   H'94'+Col
                      00139         endif
                      00140         if      Row==3
                      00141         movlw   H'D4'+Col
                      00142         endif
                      00143         if      Row>3
                      00144         * row error *
                      00145         endif
                      00146         call    lSetCsr
                      00147         endm
                      00148 ;
                      00149 ; *** lcd.write a char ***
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE  4


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00150 LCDw    macro   lcdChr
                      00151         movlw   lcdChr
                      00152         call    lSetChr
                      00153         endm
                      00154 ;
                      00155 ; *** lcd.write a byte specified ***
                      00156 LCDwb   macro   lcdBs
                      00157         movf    lcdBs,W
                      00158         call    lSetChr
                      00159         endm
                      00160 ;
                      00161 ; *** lcd.clear() ***
                      00162 LCDclr  macro
                      00163         call    lClr
                      00164         endm
                      00165 ;       
                      00166 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00167 ;       Time cosuming macros                    ;
                      00168 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00169 Mic     macro                   ;Consume 1 μS only
                      00170         goto    $+1
                      00171         goto    $+1
                      00172         endm
                      00173 ;
                      00174 Mic2    macro   mic2p           ;Consume 2 μS x n
                      00175         movlw   mic2p
                      00176         call    Mic2r
                      00177         endm
                      00178 ;
                      00179 Mic2p5  macro   mic25p          ; Consume 2.5μS x n
                      00180         movlw   mic25p
                      00181         call    Mic25r
                      00182         endm
                      00183 ;
                      00184 Mic5    macro   mic5p           ; Consume 5μS x n
                      00185         movlw   mic5p
                      00186         call    Mic25r
                      00187         movlw   mic5p
                      00188         call    Mic25r
                      00189         endm
                      00190 ;
                      00191 Mic50   macro   mic50p          ; Consume 50μS x n
                      00192         movlw   mic50p
                      00193         call    Mic50r
                      00194         endm
                      00195 ;
                      00196 Milli   macro   millip          ; Consume mS x n
                      00197         movlw   millip
                      00198         call    Millir
                      00199         endm
                      00200 ;
                      00201 Mil100  macro   mil100p         ; Consume 100 mS x n
                      00202         movlw   mil100p
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE  5


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00203         call    Mil100r
                      00204         endm
                      00205 ; 
                      00206 Secs    macro   secsp           ; Consume Second x n
                      00207         movlw   secsp
                      00208         call    Secsr
                      00209         endm
                      00210 ;
                      00211 Mins    macro   minsp           ; Consume Minute x n
                      00212         movlw   minsp
                      00213         call    Minsr
                      00214         endm
                      00215 ;
                      00216 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00217 ;       Logic macros                            ;
                      00218 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00219 ;
                      00220 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00221 ;       Comparison macros               ;
                      00222 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00223 ;       Compare A w/ B and branch to Smaller, Equal, or Larger(next statm't line) 
                      00224 CabSEL  macro   Aadr,Badr,Smladr,Eqladr
                      00225         movf    Badr,W          ; W=B
                      00226         subwf   Aadr,W          ; W=A-B
                      00227         btfss   STATUS,C        ; A≧B? Yes, skip next
                      00228         goto    Smladr          ;       If A<B goto Smaladr
                      00229         btfsc   STATUS,Z        ; A=B? No skip next
                      00230         goto    Eqladr          ;       If A=B goto Eqladr
                      00231 ;                               ;       If A>B then next (here)
                      00232         endm
                      00233 ;
                      00234 ;       Compare A w/ B and branch to Smaller or Others (Equal or Larger) 
                      00235 CabSO   macro   Aadr,Badr,Smladr
                      00236         movf    Badr,W          ; W=B
                      00237         subwf   Aadr,W          ; W=A-B
                      00238         btfss   STATUS,C        ; A≧B? Yes, skip next
                      00239         goto    Smladr          ;       If A<B goto Smaladr
                      00240 ;                               ;       If A≧B then next (here)
                      00241         endm
                      00242 ;
                      00243 ;       Compare A w/ B and branch to Equal, or Other(next statm't line) 
                      00244 CabEO   macro   Aadr,Badr,Eqladr
                      00245         movf    Badr,W          ; W=B
                      00246         subwf   Aadr,W          ; W=A-B
                      00247         btfsc   STATUS,Z        ; A=B? 
                      00248         goto    Eqladr          ;       If A=B goto Eqljmp
                      00249 ;                               ;       else next (here)
                      00250         endm
                      00251 ;
                      00252 ;       Compare A w/ literal and branch to Smaller, Equal, or Larger(next statm't) 
                      00253 CalSEL  macro   Aadr,Blit,Smladr,Eqladr
                      00254         movlw   Blit            ; W=B
                      00255         subwf   Aadr,W          ; W=A-B
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE  6


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00256         btfss   STATUS,C        ; A≧B? Yes, skip next
                      00257         goto    Smladr          ;       If A<B goto Smaladr
                      00258         btfsc   STATUS,Z        ; A=B? No skip next
                      00259         goto    Eqladr          ;       If A=B goto Eqladr
                      00260 ;                               ;       If A>B then next (here)
                      00261         endm
                      00262 ;
                      00263 ;       Compare A w/ literal and branch to Smaller, or Others (Equal or Larger) 
                      00264 CalSO   macro   Aadr,Blit,Smladr
                      00265         movlw   Blit            ; W=B
                      00266         subwf   Aadr,W          ; W=A-B
                      00267         btfss   STATUS,C        ; A≧B? Yes, skip next
                      00268         goto    Smladr          ;       If A<B goto Smaladr
                      00269 ;                               ;       If A≧B then next (here)
                      00270         endm
                      00271 ;
                      00272 ;       Compare A w/ literal and branch to Equal, or Others 
                      00273 CalEO   macro   Aadr,Blit,Eqladr
                      00274         movlw   Blit            ; W=B
                      00275         subwf   Aadr,W          ; W=A-B
                      00276         btfsc   STATUS,Z        ; A=B? No skip next
                      00277         goto    Eqladr          ;       If A=B goto Eqladr
                      00278 ;                               ;       else next (here)
                      00279         endm
                      00280 ;
                      00281 ;       Compare A w/ literal and branch to Large, or Others
                      00282 CalLO   macro   Aadr,Blit,Ladr
                      00283         movlw   Blit            ; W=B
                      00284         subwf   Aadr,W          ; W=A-B
                      00285         btfss   STATUS,C        ; A≧B? Yes, skip next
                      00286         goto    $+3             ;       If A<B goto Others
                      00287         btfss   STATUS,Z        ; A=B? Yes skip next
                      00288         goto    Ladr            ;       If A>B goto Laddr
                      00289 ;                               ;       If A≦B then next (here)
                      00290         endm
                      00291 ;
                      00292 ;       Compare A with Literal and branch to Un-equal, or Others
                      00293 CalUO   macro   Aadr,Blit,Uneqladr
                      00294         movlw   Blit            ; W=B literal
                      00295         subwf   Aadr,W          ; W=A-B 
                      00296         btfss   STATUS,Z        ; A=B?
                      00297         goto    Uneqladr        ; No, goto unequal
                      00298 ;                               ;       If yes then next
                      00299         endm
                      00300 ;
                      00301 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00302 ;       Files and Equations                                     ;
                      00303 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00304 ;
                      00305 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00306 ;       Files                           ;
                      00307 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00308         cblock  H'20'
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE  7


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00309 ; For Variables to be shown
  00000020            00310         Moji1                   ; RTC Mode char byte
  00000021            00311         Moji2                   ; Show =
  00000022            00312         Dig10                   ; Decimal value 10
  00000023            00313         Dig1                    ; Decimal value 1
                      00314 ;
                      00315 ; For RTC support
  00000024            00316         ModeN   ; Mode to point BCD mem addr of RTC
  00000025            00317         ModeChr ; Character to show mode
  00000026            00318         RvMax   ; Max number of RTC data in ModeN
  00000027            00319         RvMin   ; Minimum num of RTC data in ModeN
  00000028            00320         Byteh   ; Work area as high byte of a word
  00000029            00321         Bytel   ; Work area as low byte of a word
  0000002A            00322         RTCmem  ; RTC memory address
  0000002B            00323         BCDsec  ; RTC memory 0 = Second BCD     00-59
  0000002C            00324         BCDmin  ; RTC memory 1 = Min BCD        00-59
  0000002D            00325         BCDhr   ; RTC memory 2 = Hour BCD       00-23
  0000002E            00326         BCDdow  ; RTC memory 3 = Day of Week    01-07
  0000002F            00327         BCDday  ; RTC memory 4 = Day BCD        01-31
  00000030            00328         BCDmon  ; RTC memory 5 = Month BCD      01-12
  00000031            00329         BCDyr   ; RTC memory 6 = Year yy BCD    00-99
                      00330 ;
                      00331 ; For LCD support
  00000032            00332         Abyte                   ; LCD I2C addr with R/W bit
  00000033            00333         Dbyte                   ; Data byte to save Sbyte
  00000034            00334         Ebyte                   ; The same purpose as Dbyte
  00000035            00335         Wbyte                   ; Working byte
                      00336 ;
                      00337 ; For I2C protocols
  00000036            00338         I2Cadr                  ; Destinated slave I2C address
  00000037            00339         DataLen                 ; Number of bytes to be sent/received
                      00340 ;
                      00341 ; For DHT11 input data area
  00000038            00342         rhH                     ; Relative humidity high byte
  00000039            00343         rhL                     ; Relative humidity low byte
  0000003A            00344         tcH                     ; Temp-C high byte, also binH (B2D work)
  0000003B            00345         tcL                     ; Temp-C low byte, also binL (B2D work)
  0000003C            00346         chkSum                  ; Checksum
                      00347 ;       
                      00348 ;For DHT11 work area
  0000003D            00349         Sbyte                   ; Byte sent/received
  0000003E            00350         Bytectr                 ; Byte coounter of reading data
  0000003F            00351         Bitctr                  ; Bit coounter of reading data
                      00352 ;
                      00353 ; Areas for time consuming subroutines
  00000040            00354         Mic25c
  00000041            00355         Mic50c
  00000042            00356         Millic
  00000043            00357         Mil100c
  00000044            00358         Secsc
  00000045            00359         Minsc
                      00360 ;
                      00361         endc
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE  8


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00362 ;
                      00363 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00364 ;       Equations                       ;
                      00365 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00366 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00367 ;       For PORTA               ;
                      00368 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00369 ;DHT11  equ     0               ; PORTdht DHT111 one wire signal
                      00370 ;Cl     equ     1               ; PORTI2C SCL
                      00371 ;Dl     equ     2               ; PORTI2C SDA
                      00372 ;swMode equ     3               ; PORTsw Mode Switch
                      00373 ;swTime equ     4               ; PORTsw Time switch
                      00374 ;swSet  equ     5               ; PORTsw Set switch
                      00375 ;
                      00376 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00377 ; ***   Logical PORTdht         ; Change this when port changed
                      00378 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  0000000C            00379 PORTdht equ     PORTA
  00000000            00380 DHT11   equ     0               ; DHT11 one-wire signal
  0000010C            00381 LATdht  equ     LATA            ; Latch for dht port
  0000008C            00382 TRISdht equ     TRISA           ; TRIS for dht
                      00383 ;
                      00384 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00385 ; ***   Logical PORTI2C         ; Change this when port changed
                      00386 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  0000000C            00387 PORTI2C equ     PORTA           ; 
  00000002            00388 Dl      equ     2               ; I2C Data line = SDA
  00000001            00389 Cl      equ     1               ; I2C Clock line = SCL
  0000010C            00390 LATI2C  equ     LATA            ; LATch for I2C port
  0000008C            00391 TRISI2C equ     TRISA           ; TRIS reg for I2C
                      00392 ;
                      00393 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00394 ; ***   Logical PORTsw          ; Change this when port changed
                      00395 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  0000000C            00396 PORTsw  equ     PORTA
  00000003            00397 swMode  equ     3               ; Mode switch input ulled-up
  00000004            00398 swTime  equ     4               ; Time switch input pulled-up
  00000005            00399 swSet   equ     5               ; Set switch input pulled-up
                      00400 ;
                      00401 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00402 ;       Values & Equations              ;
                      00403 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00404 ; *** for RTC   ***
  00000068            00405 RTCi2cA equ     H'68'           ; RTC I2C address (for Arduino)
  000000D0            00406 rtcAw   equ     RTCi2cA*2       ; RTC I2C address<<1 and Write
  000000D1            00407 rtcAr   equ     RTCi2cA*2+H'01' ; RTC I2C address<<1 and Read
  000000D0            00408 DS3231  equ     rtcAw           ; RTC DS3231 address (to write)
                      00409 ;
  0000002B            00410 RTCdata equ     BCDsec          ; RTC memory data top
  00000006            00411 ModeMax equ     6               ; RTC data pointer ModeN max
  00000000            00412 ModeMin equ     0               ; RTC data pointer ModeN minimum
                      00413 ;
                      00414 ; Max and Minimum values for RTC memory
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE  9


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

  00000059            00415 secMax  equ     H'59'
  00000000            00416 secMin  equ     0
  00000059            00417 minMax  equ     H'59'
  00000000            00418 minMin  equ     0
  00000023            00419 hrMax   equ     H'23'
  00000000            00420 hrMin   equ     0
  00000007            00421 dowMax  equ     H'07'
  00000001            00422 dowMin  equ     H'01'
  00000031            00423 dayMax  equ     H'31'
  00000001            00424 dayMin  equ     H'01'
  00000012            00425 monMax  equ     H'12'
  00000001            00426 monMin  equ     H'01'
  00000006            00427 Modeyr  equ     6
  00000099            00428 yrMax   equ     H'99'
  00000000            00429 yrMin   equ     0
                      00430 ;
                      00431 ;Characters to show Mode of RTC access
  00000059            00432 ChMY    equ     A'Y'
  0000003D            00433 ChMEq   equ     A'='
  0000004D            00434 ChMM    equ     A'M'
  00000044            00435 ChMd    equ     A'D'
  00000057            00436 ChMw    equ     A'W'
  00000068            00437 ChMh    equ     A'h'
  0000006D            00438 ChMm    equ     A'm'
  00000053            00439 ChMS    equ     A'S'
                      00440 ; *** for LCD   ***
  00000027            00441 LCDi2cA equ     H'27'           ; LCD I2C address (for Arduino)
  0000004E            00442 lcdAw   equ     LCDi2cA*2       ; LCD I2C address<<1 and Write
  0000004F            00443 lcdAr   equ     LCDi2cA*2+H'01' ; LCD I2C address<<1 and Read
  0000004E            00444 LCD2004 equ     lcdAw           ; LCD LCD2004 address ( to write)
                      00445 ;
                      00446 ; *** for DHT   ***
                      00447 ;address equations
  0000003A            00448 binH    equ     tcH
  0000003B            00449 binL    equ     tcL
                      00450 ;
                      00451 ; *** for I2C ***
  00000001            00452 Clkt    equ     1       ; Clock-time/4 multiplier of 2.5μS
  00000001            00453 Clkq    equ     1       ; Quick time within clock  2μS
                      00454 ;
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 10


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00455         page
                      00456 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00457 ;       Initializing                                            ;
                      00458 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000                  00459         org     0
0000   2805           00460         goto    Startp          ; Go to start entry
0004                  00461         org     4               ; This is Interrupt entry
0004   0009           00462         retfie  
                      00463 ;
                      00464 Startp  DEVset                  ; Define ports
0005   0021               M         BANKSEL OSCCON          ; Bank=1
0006   307A               M         movlw   B'01111010'     ; 16MHz and internal oscillator
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
0007   0099               M         movwf   OSCCON
                          M ;
                          M ;       BANKSEL INTCON          ; Interrupt Con (in all banks hence comment)
0008   018B               M         clrf    INTCON          ; Disable all interrupts
                          M ;
                          M ; PORTA initialization
0009   0020               M         BANKSEL PORTA           ; Bank=0
000A   018C               M         clrf    PORTA
                          M ;       BANKSEL LATA            ; Bank=2
                          M ;       clrf    LATA
000B   0023               M         BANKSEL ANSELA          ; Bank=3
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
000C   018C               M         clrf    ANSELA          ; No use of ADC
000D   0021               M         BANKSEL ADCON0          ; Bank=1
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
000E   019D               M         clrf    ADCON0          ; No use of ADC
                          M ;
000F   0021               M         BANKSEL TRISA           ; Bank=1
0010   30F8               M         movlw   B'11111000'     ; RA0,1 and 2 are output
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
0011   008C               M         movwf   TRISA
                          M ;
0012   0021               M         BANKSEL OPTION_REG      ; Bank=1
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
0013   1395               M         bcf     OPTION_REG,7    ; Enable weak pull-up
0014   0024               M         BANKSEL WPUA            ; Bank=4
0015   3038               M         movlw   B'00111000'     ; Weak Pull-up for RA 3,4 and 5
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
0016   008C               M         movwf   WPUA            ;  
                          M ;
0017   0188               M         clrf    BSR             ; Bank=0
                          M         InitP                   ; Initialize ports
0018   30FE               M         movlw   B'11111110'     ; Outputs H excluding DHT11
0019   008C               M         movwf   PORTA
001A   0185           00465         clrf    FSR0H           ; Clear FSR0H forever
001B   0187           00466         clrf    FSR1H           ; Clear FSR1H forever
                      00467 ;
                      00468         Milli   D'50'           ; Wait devices stabilized
001C   3032               M         movlw   D'50'
001D   2326               M         call    Millir
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 11


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

001E   2029           00469         call    LCDinir         ; Set-up LCD
                      00470 ;
                      00471 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00472 ;       Main program loop                                       ;
                      00473 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
001F   2074           00474 Mainp   call    RTCrdr          ; Read clock
0020   2086           00475         call    DspTime         ; Display time
                      00476 ;
0021   218F           00477         call    DHTrd           ; Read DHT11
0022   21D6           00478         call    DspTr           ; Display temperature celsium
0023   21FF           00479         call    DspHr           ; Disuplay relative humidity
                      00480         Secs    1               ; for about 1 second
0024   3001               M         movlw   1
0025   2342               M         call    Secsr
                      00481 ;
0026   1E8C           00482         btfss   PORTsw,swSet    ; Set switch ?
0027   20E5           00483         call    RTCupdr
0028   281F           00484         goto    Mainp           ; Contilue infinite loop
                      00485 ;
                      00486 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00487 ;       LCDini= LCD initializing routine                        ;
                      00488 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  00000029            00489 LCDinir equ     $
                      00490         LCDsA                   ; Send LCD addr
0029   2241               M         call    lSndAr          ; I2C start and send it
                      00491         I2Cstop
002A   22DB               M         call    I2Cstpr
                      00492 ;
                      00493         LCDl    H'00'           ; Start,send adr & 0x00, and Stop
002B   3000               M         movlw   H'00'
002C   2246               M         call    lSndALr
                      00494         Mil100  1
002D   3001               M         movlw   1
002E   2333               M         call    Mil100r
                      00495 ;
                      00496         LCDl    H'34'
002F   3034               M         movlw   H'34'
0030   2246               M         call    lSndALr
                      00497         LCDl    H'30'
0031   3030               M         movlw   H'30'
0032   2246               M         call    lSndALr
                      00498         Milli   5
0033   3005               M         movlw   5
0034   2326               M         call    Millir
                      00499 ;
                      00500         LCDl    H'34'
0035   3034               M         movlw   H'34'
0036   2246               M         call    lSndALr
                      00501         LCDl    H'30'
0037   3030               M         movlw   H'30'
0038   2246               M         call    lSndALr
                      00502         Mic50   4
0039   3004               M         movlw   4
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 12


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

003A   231B               M         call    Mic50r
                      00503 ;
                      00504         LCDl    H'34'
003B   3034               M         movlw   H'34'
003C   2246               M         call    lSndALr
                      00505         LCDl    H'30'
003D   3030               M         movlw   H'30'
003E   2246               M         call    lSndALr
                      00506         Mic50   4
003F   3004               M         movlw   4
0040   231B               M         call    Mic50r
                      00507 ;
                      00508         LCDl    H'24'
0041   3024               M         movlw   H'24'
0042   2246               M         call    lSndALr
                      00509         LCDl    H'20'
0043   3020               M         movlw   H'20'
0044   2246               M         call    lSndALr
                      00510         Mic50   4
0045   3004               M         movlw   4
0046   231B               M         call    Mic50r
                      00511 ;
                      00512         LCDl    H'24'
0047   3024               M         movlw   H'24'
0048   2246               M         call    lSndALr
                      00513         LCDl    H'20'
0049   3020               M         movlw   H'20'
004A   2246               M         call    lSndALr
                      00514         LCDl    H'84'
004B   3084               M         movlw   H'84'
004C   2246               M         call    lSndALr
                      00515         LCDl    H'80'
004D   3080               M         movlw   H'80'
004E   2246               M         call    lSndALr
                      00516         Mic50   4
004F   3004               M         movlw   4
0050   231B               M         call    Mic50r
                      00517 ;
                      00518         LCDl    H'04'
0051   3004               M         movlw   H'04'
0052   2246               M         call    lSndALr
                      00519         LCDl    H'00'
0053   3000               M         movlw   H'00'
0054   2246               M         call    lSndALr
                      00520         LCDl    H'C4'
0055   30C4               M         movlw   H'C4'
0056   2246               M         call    lSndALr
                      00521         LCDl    H'C0'
0057   30C0               M         movlw   H'C0'
0058   2246               M         call    lSndALr
                      00522         Mic50   3
0059   3003               M         movlw   3
005A   231B               M         call    Mic50r
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 13


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00523 ;
                      00524         LCDl    H'04'
005B   3004               M         movlw   H'04'
005C   2246               M         call    lSndALr
                      00525         LCDl    H'00'
005D   3000               M         movlw   H'00'
005E   2246               M         call    lSndALr
                      00526         LCDl    H'14'
005F   3014               M         movlw   H'14'
0060   2246               M         call    lSndALr
                      00527         LCDl    H'10'
0061   3010               M         movlw   H'10'
0062   2246               M         call    lSndALr
                      00528         Milli   2
0063   3002               M         movlw   2
0064   2326               M         call    Millir
                      00529 ;
                      00530         LCDl    H'04'
0065   3004               M         movlw   H'04'
0066   2246               M         call    lSndALr
                      00531         LCDl    H'00'
0067   3000               M         movlw   H'00'
0068   2246               M         call    lSndALr
                      00532         LCDl    H'64'
0069   3064               M         movlw   H'64'
006A   2246               M         call    lSndALr
                      00533         LCDl    H'60'
006B   3060               M         movlw   H'60'
006C   2246               M         call    lSndALr
                      00534         Mic50   3
006D   3003               M         movlw   3
006E   231B               M         call    Mic50r
                      00535 ;
                      00536         LCDl    H'08'           ; backlight on
006F   3008               M         movlw   H'08'
0070   2246               M         call    lSndALr
                      00537         Milli   1
0071   3001               M         movlw   1
0072   2326               M         call    Millir
0073   0008           00538         return
                      00539 ;
                      00540 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00541 ;       RTC reading routine     ;
                      00542 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0074   01AA           00543 RTCrdr  clrf    RTCmem          ; set RTC memory addr 0
                      00544         I2Csnd DS3231,RTCmem,1  ; send it to DS3231
0075   30D0               M         movlw   DS3231
0076   00B6               M         movwf   I2Cadr
0077   302A               M         movlw   RTCmem
0078   0084               M         movwf   FSR0L
0079   3001               M         movlw   1
007A   00B7               M         movwf   DataLen
007B   227B               M         call    I2Csndr
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 14


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00545         Milli   1               ; wait a little (maybe unneeded)
007C   3001               M         movlw   1
007D   2326               M         call    Millir
                      00546         I2Crcv DS3231,RTCdata,7 ; receive 7 byte data from DS3231
007E   30D0               M         movlw   DS3231
007F   00B6               M         movwf   I2Cadr
0080   302B               M         movlw   RTCdata
0081   0084               M         movwf   FSR0L
0082   3007               M         movlw   7
0083   00B7               M         movwf   DataLen
0084   2288               M         call    I2Crcvr
0085   0008           00547         return
                      00548 ;
                      00549 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00550 ;       Display-Time routine                                    ;
                      00551 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  00000086            00552 DspTime equ     $
                      00553 ; Display year
                      00554         LCDsetC 0,0             ; Set cursor to top
                          M         if      0==0
0086   3080               M         movlw   H'80'+0
                          M         endif
                          M         if      0==1
                          M         movlw   H'C0'+0
                          M         endif
                          M         if      0==2
                          M         movlw   H'94'+0
                          M         endif
                          M         if      0==3
                          M         movlw   H'D4'+0
                          M         endif
                          M         if      0>3
                          M         * row error *
                          M         endif
0087   224D               M         call    lSetCsr
                      00555         LCDw    A'2'
0088   3032               M         movlw   A'2'
0089   225F               M         call    lSetChr
                      00556         LCDw    A'0'
008A   3030               M         movlw   A'0'
008B   225F               M         call    lSetChr
                      00557 ;
008C   0831           00558         movf    BCDyr,W         ; Get RTC format year
008D   00A3           00559         movwf   Dig1            ; Set it to Dig1
008E   300F           00560         movlw   H'0F'           ; Remove upper nibble
008F   05A3           00561         andwf   Dig1,F          ;  by AND
0090   0E31           00562         swapf   BCDyr,W         ; Get RTC year nibble-swapped
0091   00A2           00563         movwf   Dig10           ; Set it to Dig10
0092   300F           00564         movlw   H'0F'           ; Remove upper nibble
0093   05A2           00565         andwf   Dig10,F         ; by AND
0094   2236           00566         call    D2Cr            ; convert to characters
                      00567         LCDwb   Dig10
0095   0822               M         movf    Dig10,W
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 15


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

0096   225F               M         call    lSetChr
                      00568         LCDwb   Dig1
0097   0823               M         movf    Dig1,W
0098   225F               M         call    lSetChr
                      00569         LCDw    A'-'
0099   302D               M         movlw   A'-'
009A   225F               M         call    lSetChr
                      00570 ;       
                      00571 ; Display month
009B   0830           00572         movf    BCDmon,W        ; Same logic for month, as above
009C   00A3           00573         movwf   Dig1
009D   300F           00574         movlw   H'0F'
009E   05A3           00575         andwf   Dig1,F
009F   0E30           00576         swapf   BCDmon,W
00A0   00A2           00577         movwf   Dig10
00A1   300F           00578         movlw   H'0F'
00A2   05A2           00579         andwf   Dig10,F
00A3   2236           00580         call    D2Cr            ; convert to characters
                      00581         LCDwb   Dig10
00A4   0822               M         movf    Dig10,W
00A5   225F               M         call    lSetChr
                      00582         LCDwb   Dig1
00A6   0823               M         movf    Dig1,W
00A7   225F               M         call    lSetChr
                      00583         LCDw    A'-'    
00A8   302D               M         movlw   A'-'
00A9   225F               M         call    lSetChr
                      00584 ;
                      00585 ; Display day
00AA   082F           00586         movf    BCDday,W        ; Same logic for day, as above
00AB   00A3           00587         movwf   Dig1
00AC   300F           00588         movlw   H'0F'
00AD   05A3           00589         andwf   Dig1,F
00AE   0E2F           00590         swapf   BCDday,W
00AF   00A2           00591         movwf   Dig10
00B0   300F           00592         movlw   H'0F'
00B1   05A2           00593         andwf   Dig10,F
00B2   2236           00594         call    D2Cr            ; convert to characters
                      00595         LCDwb   Dig10
00B3   0822               M         movf    Dig10,W
00B4   225F               M         call    lSetChr
                      00596         LCDwb   Dig1
00B5   0823               M         movf    Dig1,W
00B6   225F               M         call    lSetChr
                      00597         LCDw    A' '
00B7   3020               M         movlw   A' '
00B8   225F               M         call    lSetChr
                      00598 ;
                      00599 ; Display hour
00B9   082D           00600         movf    BCDhr,W         ; Same logic for hour, as above
00BA   00A3           00601         movwf   Dig1
00BB   300F           00602         movlw   H'0F'
00BC   05A3           00603         andwf   Dig1,F
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 16


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

00BD   0E2D           00604         swapf   BCDhr,W
00BE   00A2           00605         movwf   Dig10
00BF   300F           00606         movlw   H'0F'
00C0   05A2           00607         andwf   Dig10,F
00C1   2236           00608         call    D2Cr            ; convert to characters
                      00609         LCDwb   Dig10
00C2   0822               M         movf    Dig10,W
00C3   225F               M         call    lSetChr
                      00610         LCDwb   Dig1
00C4   0823               M         movf    Dig1,W
00C5   225F               M         call    lSetChr
                      00611         LCDw    A':'
00C6   303A               M         movlw   A':'
00C7   225F               M         call    lSetChr
                      00612 ;
                      00613 ; Display minute
00C8   082C           00614         movf    BCDmin,W        ; Same logic for minute, as above
00C9   00A3           00615         movwf   Dig1
00CA   300F           00616         movlw   H'0F'
00CB   05A3           00617         andwf   Dig1,F
00CC   0E2C           00618         swapf   BCDmin,W
00CD   00A2           00619         movwf   Dig10
00CE   300F           00620         movlw   H'0F'
00CF   05A2           00621         andwf   Dig10,F
00D0   2236           00622         call    D2Cr            ; convert to characters
                      00623         LCDwb   Dig10
00D1   0822               M         movf    Dig10,W
00D2   225F               M         call    lSetChr
                      00624         LCDwb   Dig1
00D3   0823               M         movf    Dig1,W
00D4   225F               M         call    lSetChr
                      00625         LCDw    A':'
00D5   303A               M         movlw   A':'
00D6   225F               M         call    lSetChr
                      00626 ;
                      00627 ; Display second
00D7   082B           00628         movf    BCDsec,W        ; Same logic for second, as above
00D8   00A3           00629         movwf   Dig1
00D9   300F           00630         movlw   H'0F'
00DA   05A3           00631         andwf   Dig1,F
00DB   0E2B           00632         swapf   BCDsec,W
00DC   00A2           00633         movwf   Dig10
00DD   300F           00634         movlw   H'0F'
00DE   05A2           00635         andwf   Dig10,F
00DF   2236           00636         call    D2Cr            ; convert to characters
                      00637         LCDwb   Dig10
00E0   0822               M         movf    Dig10,W
00E1   225F               M         call    lSetChr
                      00638         LCDwb   Dig1
00E2   0823               M         movf    Dig1,W
00E3   225F               M         call    lSetChr
00E4   0008           00639         return
                      00640 ;
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 17


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00641 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00642 ;       RTC updating routine                                    ;
                      00643 ;               Display value for current ModeN                 ;
                      00644 ;               If swMode pushed, display next unit to update   ;
                      00645 ;               If swTime pushed, increase value and display it ;
                      00646 ;               If swSet pushed,  update RTC (RTCwtr)           ;
                      00647 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00E5   1E8C           00648 RTCupdr btfss   PORTsw,swSet    ; swSet still on?
00E6   28E5           00649         goto    $-1             ; then wait for off
00E7   3006           00650         movlw   Modeyr          ; set initial mode year
00E8   00A4           00651         movwf   ModeN
                      00652 ;
00E9   0824           00653 RTCudm  movf    ModeN,W         ; Large loop on ModeN
00EA   000B           00654         brw
00EB   28F2           00655         goto    Mdsecr          ; case ModeN=0 
00EC   28F9           00656         goto    Mdminr          ; case ModeN=1 
00ED   2900           00657         goto    Mdhrr           ; case ModeN=2 
00EE   2907           00658         goto    Mddowr          ; case ModeN=3 
00EF   290E           00659         goto    Mddayr          ; case ModeN=4 
00F0   2915           00660         goto    Mdmonr          ; case ModeN=5 
00F1   291C           00661         goto    Mdyrr           ; case ModeN=6 
                      00662 ;
                      00663 ; Macro used within  this section
                      00664 Mdsetup macro   TMc,Rmax,Rmin
                      00665         movlw   TMc
                      00666         movwf   ModeChr
                      00667         movlw   Rmax
                      00668         movwf   RvMax
                      00669         movlw   Rmin
                      00670         movwf   RvMin
                      00671         goto    Mdnext
                      00672         endm
                      00673 ;
                      00674 ; set up environment for update and display
                      00675 Mdsecr  Mdsetup ChMS,secMax,secMin
00F2   3053               M         movlw   ChMS
00F3   00A5               M         movwf   ModeChr
00F4   3059               M         movlw   secMax
00F5   00A6               M         movwf   RvMax
00F6   3000               M         movlw   secMin
00F7   00A7               M         movwf   RvMin
00F8   2923               M         goto    Mdnext
                      00676 Mdminr  Mdsetup ChMm,minMax,minMin
00F9   306D               M         movlw   ChMm
00FA   00A5               M         movwf   ModeChr
00FB   3059               M         movlw   minMax
00FC   00A6               M         movwf   RvMax
00FD   3000               M         movlw   minMin
00FE   00A7               M         movwf   RvMin
00FF   2923               M         goto    Mdnext
                      00677 Mdhrr   Mdsetup ChMh,hrMax,hrMin
0100   3068               M         movlw   ChMh
0101   00A5               M         movwf   ModeChr
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 18


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

0102   3023               M         movlw   hrMax
0103   00A6               M         movwf   RvMax
0104   3000               M         movlw   hrMin
0105   00A7               M         movwf   RvMin
0106   2923               M         goto    Mdnext
                      00678 Mddowr  Mdsetup ChMw,dowMax,dowMin
0107   3057               M         movlw   ChMw
0108   00A5               M         movwf   ModeChr
0109   3007               M         movlw   dowMax
010A   00A6               M         movwf   RvMax
010B   3001               M         movlw   dowMin
010C   00A7               M         movwf   RvMin
010D   2923               M         goto    Mdnext
                      00679 Mddayr  Mdsetup ChMd,dayMax,dayMin
010E   3044               M         movlw   ChMd
010F   00A5               M         movwf   ModeChr
0110   3031               M         movlw   dayMax
0111   00A6               M         movwf   RvMax
0112   3001               M         movlw   dayMin
0113   00A7               M         movwf   RvMin
0114   2923               M         goto    Mdnext
                      00680 Mdmonr  Mdsetup ChMM,monMax,monMin
0115   304D               M         movlw   ChMM
0116   00A5               M         movwf   ModeChr
0117   3012               M         movlw   monMax
0118   00A6               M         movwf   RvMax
0119   3001               M         movlw   monMin
011A   00A7               M         movwf   RvMin
011B   2923               M         goto    Mdnext
                      00681 Mdyrr   Mdsetup ChMY,yrMax,yrMin
011C   3059               M         movlw   ChMY
011D   00A5               M         movwf   ModeChr
011E   3099               M         movlw   yrMax
011F   00A6               M         movwf   RvMax
0120   3000               M         movlw   yrMin
0121   00A7               M         movwf   RvMin
0122   2923               M         goto    Mdnext
                      00682 ;
0123   2148           00683 Mdnext  call    Rdspr           ; Display X=nn
0124   1E0C           00684         btfss   PORTsw,swTime   ; Is Time pushed ?
0125   292B           00685         goto    Rinc            ;  Yes, goto  Rinc
0126   1D8C           00686         btfss   PORTsw,swMode   ; Is Mode pushed ?
0127   292F           00687         goto    Rnxtm           ;  Yes, goto Rnxtm
0128   1E8C           00688         btfss   PORTsw,swSet    ; Is Set pushed ?
0129   293A           00689         goto    Rwrite          ;  Yes, goto Rwrite
012A   2923           00690         goto    Mdnext          ; If no button, small loop for button
                      00691 ;
                      00692 ;       Time pushed here
012B   2169           00693 Rinc    call    Rincr           ; Increase value in that mode
                      00694         Mil100  2               ; 0.2 sec for increasing value
012C   3002               M         movlw   2
012D   2333               M         call    Mil100r
012E   2923           00695         goto    Mdnext          ; return to loop for button
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 19


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00696 ;
                      00697 ;       Mode pushed here
012F   1D8C           00698 Rnxtm   btfss   PORTsw,swMode   ; Mode button still pushed
0130   292F           00699         goto    $-1             ; then wait for release
                      00700         CalEO   ModeN,0,Msmax   ; If current ModeN=0 goto Msmax
0131   3000               M         movlw   0               ; W=B
0132   0224               M         subwf   ModeN,W         ; W=A-B
0133   1903               M         btfsc   STATUS,Z        ; A=B? No skip next
0134   2937               M         goto    Msmax           ;       If A=B goto Eqladr
                          M ;                               ;       else next (here)
0135   03A4           00701         decf    ModeN,F         ; set next mode
0136   28E9           00702 Rnxtme  goto    RTCudm          ; and return to large loop for mode
                      00703 ;
0137   3006           00704 Msmax   movlw   Modeyr          ; get maximum mode
0138   00A4           00705         movwf   ModeN           ; and set it
0139   28E9           00706         goto    RTCudm          ; and return to large loop for mode
                      00707 ;       
013A   1E8C           00708 Rwrite  btfss   PORTsw,swSet    ; Set button still on?
013B   293A           00709         goto    $-1             ; then wait for release
013C   2186           00710         call    RTCwtr          ; and write to RTC
                      00711 ;
                      00712         LCDsetC D'10',3         ; Set cursor to Row3, Column 10
                          M         if      3==0
                          M         movlw   H'80'+D'10'
                          M         endif
                          M         if      3==1
                          M         movlw   H'C0'+D'10'
                          M         endif
                          M         if      3==2
                          M         movlw   H'94'+D'10'
                          M         endif
                          M         if      3==3
013D   30DE               M         movlw   H'D4'+D'10'
                          M         endif
                          M         if      3>3
                          M         * row error *
                          M         endif
013E   224D               M         call    lSetCsr
                      00713         LCDw    A' '            ; Clear RTC setting message
013F   3020               M         movlw   A' '
0140   225F               M         call    lSetChr
                      00714         LCDw    A' '
0141   3020               M         movlw   A' '
0142   225F               M         call    lSetChr
                      00715         LCDw    A' '
0143   3020               M         movlw   A' '
0144   225F               M         call    lSetChr
                      00716         LCDw    A' '
0145   3020               M         movlw   A' '
0146   225F               M         call    lSetChr
0147   0008           00717         return                  ; exit from RTC updating routine
                      00718 ;
                      00719 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 20


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00720 ;       Display value pointed by ModeN  ;
                      00721 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0148   0825           00722 Rdspr   movf    ModeChr,W
0149   00A0           00723         movwf   Moji1
014A   303D           00724         movlw   ChMEq
014B   00A1           00725         movwf   Moji2
                      00726 ;
014C   302B           00727         movlw   BCDsec          ; Point BCD area top
014D   0086           00728         movwf   FSR1L           ; set it to FSR1L
014E   0824           00729         movf    ModeN,W         ; Get Mode number
014F   0786           00730         addwf   FSR1L,F         ; Point current BCD area        
0150   0E01           00731         swapf   INDF1,W         ; get high nibble to low in W
0151   00A2           00732         movwf   Dig10           ; set it to Dig10
0152   300F           00733         movlw   H'0F'           ; Clear high nibble
0153   05A2           00734         andwf   Dig10,F         ;  of Dig10
0154   0801           00735         movf    INDF1,W         ; get low nibble to low
0155   00A3           00736         movwf   Dig1            ; set it to Dig1
0156   300F           00737         movlw   H'0F'           ; Clear high nibble
Message[305]: Using default destination of 1 (file).
0157   05A3           00738         andwf   Dig1            ;  of Dig1
0158   2236           00739         call    D2Cr            ; Convert Decimals to Characters
                      00740 ;
0159   215B           00741         call    TMdspr
015A   0008           00742         return
                      00743 ;
                      00744 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00745 ;       Time Mode displaying routine            ;
                      00746 ;               to update RTC                   ;
                      00747 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
015B   3020           00748 TMdspr  movlw   Moji1           ; Point Byte0 address
015C   0084           00749         movwf   FSR0L           ;  set it to use INDF0
015D   3004           00750         movlw   4               ; Set four chars
015E   00BE           00751         movwf   Bytectr         ;  to Byte counter
                      00752 ;
                      00753         LCDsetC D'10',3         ; Set cursor to Row3, Column 10
                          M         if      3==0
                          M         movlw   H'80'+D'10'
                          M         endif
                          M         if      3==1
                          M         movlw   H'C0'+D'10'
                          M         endif
                          M         if      3==2
                          M         movlw   H'94'+D'10'
                          M         endif
                          M         if      3==3
015F   30DE               M         movlw   H'D4'+D'10'
                          M         endif
                          M         if      3>3
                          M         * row error *
                          M         endif
0160   224D               M         call    lSetCsr
                      00754 ;
0161   0800           00755 TMdspl  movf    INDF0,W         ; Get byte content
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 21


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

0162   00BD           00756         movwf   Sbyte           ; Set it to Sbyte
                      00757         LCDwb   Sbyte           ;  and send it
0163   083D               M         movf    Sbyte,W
0164   225F               M         call    lSetChr
0165   0A84           00758         incf    FSR0L,F         ; point next byte
0166   0BBE           00759         decfsz  Bytectr,F       ; Check if all done
0167   2961           00760         goto    TMdspl          ; No. loop
0168   0008           00761         return
                      00762 ;
                      00763 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00764 ;       Increase value pointed by ModeN ;
                      00765 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0169   302B           00766 Rincr   movlw   BCDsec          ; Point BCD area top
016A   0086           00767         movwf   FSR1L           ; set it to pointer
016B   0824           00768         movf    ModeN,W         ; get ModeN to add
016C   0786           00769         addwf   FSR1L,F         ; Point current BCD area
                      00770 ;
                      00771         CabSO   INDF1,RvMax,Rigo ;If smaller than max, goto Rigo
016D   0826               M         movf    RvMax,W         ; W=B
016E   0201               M         subwf   INDF1,W         ; W=A-B
016F   1C03               M         btfss   STATUS,C        ; A≧B? Yes, skip next
0170   2974               M         goto    Rigo            ;       If A<B goto Smaladr
                          M ;                               ;       If A≧B then next (here)
0171   0827           00772         movf    RvMin,W         ; Else, get minimum value
0172   0081           00773         movwf   INDF1           ; and set it to INDF1 (BCD area)
0173   0008           00774         return
                      00775 ;
0174   0801           00776 Rigo    movf    INDF1,W         ; Get BCD value
0175   390F           00777         andlw   H'0F'           ; clear left nibble
0176   00A9           00778         movwf   Bytel           ; and set to Bytel
0177   0E01           00779         swapf   INDF1,W         ; Get BCD nibbles swapped
0178   390F           00780         andlw   H'0F'           ; clear left nibble
0179   00A8           00781         movwf   Byteh           ; and set to Byteh
                      00782 ;
017A   0AA9           00783         incf    Bytel,F         ; Bytel+1
                      00784         CalSO   Bytel,D'10',Rie ; If Bytel≦9,goto Rie
017B   300A               M         movlw   D'10'           ; W=B
017C   0229               M         subwf   Bytel,W         ; W=A-B
017D   1C03               M         btfss   STATUS,C        ; A≧B? Yes, skip next
017E   2984               M         goto    Rie             ;       If A<B goto Smaladr
                          M ;                               ;       If A≧B then next (here)
017F   3010           00785         movlw   D'16'           ; Else increase digit 10
0180   0781           00786         addwf   INDF1,F         ;
0181   30F0           00787         movlw   H'F0'           ; and clear digit 1
0182   0581           00788         andwf   INDF1,F
0183   0008           00789         return
                      00790 
0184   0A81           00791 Rie     incf    INDF1,F         ; Increase BCD value
0185   0008           00792         return                  ; and return
                      00793 ;
                      00794 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00795 ;       RTC writing routine     ;
                      00796 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 22


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

0186   01AA           00797 RTCwtr  clrf    RTCmem          ; Set memory address zero
                      00798         I2Csnd  DS3231,RTCmem,8 ; Send data, includign memory addr in top
0187   30D0               M         movlw   DS3231
0188   00B6               M         movwf   I2Cadr
0189   302A               M         movlw   RTCmem
018A   0084               M         movwf   FSR0L
018B   3008               M         movlw   8
018C   00B7               M         movwf   DataLen
018D   227B               M         call    I2Csndr
018E   0008           00799         return
                      00800 ;
                      00801 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00802 ;       DHT11 Reading routine                           ;
                      00803 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
018F   3005           00804 DHTrd   movlw   5               ; Set # of DHT bytes 5
0190   00BE           00805         movwf   Bytectr         ;  to Bytectr
                      00806 ;
0191   3038           00807         movlw   rhH             ; Point top of DHT data input
0192   0084           00808         movwf   FSR0L           ; Set it to INDF0
                      00809 ;
                      00810 ;       Start signal
0193   100C           00811         bcf     PORTdht,DHT11   ; Set DHT-line L
                      00812 ;
                      00813         Milli   D'20'           ; for 20mS
0194   3014               M         movlw   D'20'
0195   2326               M         call    Millir
0196   140C           00814         bsf     PORTdht,DHT11   ; Set DHT-line H
                      00815         Mic2    D'10'           ; for 20 micro sec
0197   300A               M         movlw   D'10'
0198   230B               M         call    Mic2r
                      00816 ;
                      00817 ;Header checking from DHT11
0199   0021           00818         BANKSEL TRISdht         ; Point tris bank
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
019A   140C           00819         bsf     TRISdht,DHT11   ; Set TRIS-dht input
019B   0024           00820         BANKSEL WPUA            ; Point WPUA bank
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
019C   140C           00821         bsf     WPUA,DHT11      ; Pull-up
019D   0188           00822         clrf    BSR             ; Point bank 0
                      00823         Mic                     ; wait 1 micro sec for ready
019E   299F               M         goto    $+1
019F   29A0               M         goto    $+1
                      00824 ;
01A0   180C           00825         btfsc   PORTdht,DHT11   ; Wait response 1/2 from DHT L
01A1   29A0           00826         goto    $-1             ;  until L
                      00827         Mic5    D'13'           ; Wait 65 within 80 micS
01A2   300D               M         movlw   D'13'
01A3   2312               M         call    Mic25r
01A4   300D               M         movlw   D'13'
01A5   2312               M         call    Mic25r
                      00828 ;
01A6   1C0C           00829         btfss   PORTdht,DHT11   ; Wait response 2/2 from DHT H
01A7   29A6           00830         goto    $-1             ;  until H
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 23


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00831         Mic5    D'13'           ; Wait 65 within 80 micS
01A8   300D               M         movlw   D'13'
01A9   2312               M         call    Mic25r
01AA   300D               M         movlw   D'13'
01AB   2312               M         call    Mic25r
                      00832 ;
01AC   180C           00833         btfsc   PORTdht,DHT11   ; Wait Start (L 50 mic sec) from DHT
01AD   29AC           00834         goto    $-1
                      00835         Mic5    D'6'            ; When L, wait for 30 mic sec
01AE   3006               M         movlw   D'6'
01AF   2312               M         call    Mic25r
01B0   3006               M         movlw   D'6'
01B1   2312               M         call    Mic25r
                      00836 ;
                      00837 ; Read each byte from DHT11
01B2   3008           00838 DHbc    movlw   8               ; Set # of bits = 8 in a byte of DHT
01B3   00BF           00839         movwf   Bitctr          ;  to Bitctr
                      00840 ;
01B4   1C0C           00841 DHbcl   btfss   PORTdht,DHT11   ; Wait Data signal H from DHT
01B5   29B4           00842         goto    $-1
                      00843         Mic50   1               ; When H (1=70,0=27 micS), wait 50 micS
01B6   3001               M         movlw   1
01B7   231B               M         call    Mic50r
                      00844 ;       Trigger                 ; *** for timing-validation use only ***
                      00845 ;
01B8   1C0C           00846         btfss   PORTdht,DHT11   ; If still on then data is one, else zero
01B9   29C0           00847         goto    DHszero
                      00848 ;
01BA   143D           00849 DHsone  bsf     Sbyte,0         ; Set 1 to Sbyte bit 0
                      00850         Mic5    D'4'            ; Consume residual H 20 mic S of "1"
01BB   3004               M         movlw   D'4'
01BC   2312               M         call    Mic25r
01BD   3004               M         movlw   D'4'
01BE   2312               M         call    Mic25r
01BF   29C1           00851         goto    DHeck           ; Goto Check end of one byte
                      00852 ;
01C0   103D           00853 DHszero bcf     Sbyte,0         ; Set zero to Sbyte bit 0
01C1   0BBF           00854 DHeck   decfsz  Bitctr,F        ; One byte (8 bits) end ?
01C2   29C9           00855         goto    DHnxtbi         ; No, goto continue bit proc
                      00856 ;
01C3   083D           00857 DHbye   movf    Sbyte,W         ; If one byte end, here
01C4   0080           00858         movwf   INDF0           ; Set data to DHTdata entry
01C5   0A84           00859         incf    FSR0L,F         ; Point next entry of DHTdata
                      00860 ;
01C6   0BBE           00861         decfsz  Bytectr,F       ; All bytes end?
01C7   29B2           00862         goto    DHbc            ; If not end of bytes, next byte
01C8   29CB           00863         goto    DHcksr          ; If end, checksum validation
                      00864 ;
01C9   0DBD           00865 DHnxtbi rlf     Sbyte,F         ; Bit continues. Shift left.
01CA   29B4           00866         goto    DHbcl           ; and next bit checking
                      00867 ;
  000001CB            00868 DHcksr  equ     $               ; Checksum validation, if needed
                      00869 ;
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 24


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      00870 ;  End of receive
                      00871 ;
                      00872 ;Change data line mode to ooutput
                      00873 ;       Wait the last space ending
                      00874         Mic2    D'40'           ; Residual 28 mic sec space + alpha 
01CB   3028               M         movlw   D'40'
01CC   230B               M         call    Mic2r
                      00875 ;                               ; + 50 mic sec until pull-down end
01CD   0022           00876         BANKSEL LATdht          ; Data line high when output mode
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
01CE   140C           00877         bsf     LATdht,DHT11    ; Lat-DHT11 high
01CF   0021           00878         BANKSEL TRISdht         ; Select tris bank
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
01D0   100C           00879         bcf     TRISdht,DHT11   ; Set DHT11 output mode
01D1   0188           00880         clrf    BSR             ; Select bank 0
                      00881 ;
                      00882         Mic                     ; Wait one micro Sec
01D2   29D3               M         goto    $+1
01D3   29D4               M         goto    $+1
01D4   140C           00883         bsf     PORTdht,DHT11   ; Signal high
01D5   0008           00884         return
                      00885 ;
                      00886 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00887 ;       Display temperature                                     ;
                      00888 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  000001D6            00889 DspTr   equ     $
                      00890         LCDsetC 1,1
                          M         if      1==0
                          M         movlw   H'80'+1
                          M         endif
                          M         if      1==1
01D6   30C1               M         movlw   H'C0'+1
                          M         endif
                          M         if      1==2
                          M         movlw   H'94'+1
                          M         endif
                          M         if      1==3
                          M         movlw   H'D4'+1
                          M         endif
                          M         if      1>3
                          M         * row error *
                          M         endif
01D7   224D               M         call    lSetCsr
                      00891         LCDw    A'T'
01D8   3054               M         movlw   A'T'
01D9   225F               M         call    lSetChr
                      00892         LCDw    A'e'
01DA   3065               M         movlw   A'e'
01DB   225F               M         call    lSetChr
                      00893         LCDw    A'm'
01DC   306D               M         movlw   A'm'
01DD   225F               M         call    lSetChr
                      00894         LCDw    A'p'
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 25


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

01DE   3070               M         movlw   A'p'
01DF   225F               M         call    lSetChr
                      00895         LCDw    A'e'
01E0   3065               M         movlw   A'e'
01E1   225F               M         call    lSetChr
                      00896         LCDw    A'r'
01E2   3072               M         movlw   A'r'
01E3   225F               M         call    lSetChr
                      00897         LCDw    A'a'
01E4   3061               M         movlw   A'a'
01E5   225F               M         call    lSetChr
                      00898         LCDw    A't'
01E6   3074               M         movlw   A't'
01E7   225F               M         call    lSetChr
                      00899         LCDw    A'u'
01E8   3075               M         movlw   A'u'
01E9   225F               M         call    lSetChr
                      00900         LCDw    A'r'
01EA   3072               M         movlw   A'r'
01EB   225F               M         call    lSetChr
                      00901         LCDw    A'e'
01EC   3065               M         movlw   A'e'
01ED   225F               M         call    lSetChr
                      00902         LCDw    A' '
01EE   3020               M         movlw   A' '
01EF   225F               M         call    lSetChr
                      00903         LCDw    A'='
01F0   303D               M         movlw   A'='
01F1   225F               M         call    lSetChr
                      00904         LCDw    A' '
01F2   3020               M         movlw   A' '
01F3   225F               M         call    lSetChr
01F4   222A           00905 DspTgo  call    B2Dr            ; Convert binary data to Decimals
01F5   2236           00906         call    D2Cr            ; Convert Decimals to Characters
                      00907         LCDwb   Dig10
01F6   0822               M         movf    Dig10,W
01F7   225F               M         call    lSetChr
                      00908         LCDwb   Dig1
01F8   0823               M         movf    Dig1,W
01F9   225F               M         call    lSetChr
                      00909         LCDw    H'DF'           ; degree
01FA   30DF               M         movlw   H'DF'
01FB   225F               M         call    lSetChr
                      00910         LCDw    A'C'
01FC   3043               M         movlw   A'C'
01FD   225F               M         call    lSetChr
01FE   0008           00911         return
                      00912 ;
                      00913 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00914 ;       Disuplay relative humidity                              ;
                      00915 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  000001FF            00916 DspHr   equ     $
                      00917         LCDsetC 1,2
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 26


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                          M         if      2==0
                          M         movlw   H'80'+1
                          M         endif
                          M         if      2==1
                          M         movlw   H'C0'+1
                          M         endif
                          M         if      2==2
01FF   3095               M         movlw   H'94'+1
                          M         endif
                          M         if      2==3
                          M         movlw   H'D4'+1
                          M         endif
                          M         if      2>3
                          M         * row error *
                          M         endif
0200   224D               M         call    lSetCsr
                      00918         LCDw    A'R'
0201   3052               M         movlw   A'R'
0202   225F               M         call    lSetChr
                      00919         LCDw    A'e'
0203   3065               M         movlw   A'e'
0204   225F               M         call    lSetChr
                      00920         LCDw    A'l'
0205   306C               M         movlw   A'l'
0206   225F               M         call    lSetChr
                      00921         LCDw    A'.'
0207   302E               M         movlw   A'.'
0208   225F               M         call    lSetChr
                      00922         LCDw    A'H'
0209   3048               M         movlw   A'H'
020A   225F               M         call    lSetChr
                      00923         LCDw    A'u'
020B   3075               M         movlw   A'u'
020C   225F               M         call    lSetChr
                      00924         LCDw    A'm'
020D   306D               M         movlw   A'm'
020E   225F               M         call    lSetChr
                      00925         LCDw    A'i'
020F   3069               M         movlw   A'i'
0210   225F               M         call    lSetChr
                      00926         LCDw    A'd'
0211   3064               M         movlw   A'd'
0212   225F               M         call    lSetChr
                      00927         LCDw    A'i'
0213   3069               M         movlw   A'i'
0214   225F               M         call    lSetChr
                      00928         LCDw    A't'
0215   3074               M         movlw   A't'
0216   225F               M         call    lSetChr
                      00929         LCDw    A'y'
0217   3079               M         movlw   A'y'
0218   225F               M         call    lSetChr
                      00930         LCDw    A' '
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 27


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

0219   3020               M         movlw   A' '
021A   225F               M         call    lSetChr
                      00931         LCDw    A'='
021B   303D               M         movlw   A'='
021C   225F               M         call    lSetChr
                      00932         LCDw    A' '
021D   3020               M         movlw   A' '
021E   225F               M         call    lSetChr
                      00933 ;
021F   0838           00934         movf    rhH,W
0220   00BA           00935         movwf   binH
                      00936 ;
0221   222A           00937         call    B2Dr
0222   2236           00938         call    D2Cr
                      00939         LCDwb   Dig10
0223   0822               M         movf    Dig10,W
0224   225F               M         call    lSetChr
                      00940         LCDwb   Dig1
0225   0823               M         movf    Dig1,W
0226   225F               M         call    lSetChr
                      00941         LCDw    A'%'
0227   3025               M         movlw   A'%'
0228   225F               M         call    lSetChr
0229   0008           00942         return
                      00943 ;
                      00944 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00945 ;       Convert mesured Binary data to Decimal                  ;
                      00946 ;               from binH to Dig10+Dig1                         ;
                      00947 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
022A   083A           00948 B2Dr    movf    binH,W          ; Move binH
022B   00A3           00949         movwf   Dig1            ;  to Dig1
022C   01A2           00950         clrf    Dig10           ; Clear Dig10
                      00951 ;
                      00952 B2Dlp   CalSO   Dig1,D'10',B2De
022D   300A               M         movlw   D'10'           ; W=B
022E   0223               M         subwf   Dig1,W          ; W=A-B
022F   1C03               M         btfss   STATUS,C        ; A≧B? Yes, skip next
0230   2A35               M         goto    B2De            ;       If A<B goto Smaladr
                          M ;                               ;       If A≧B then next (here)
0231   300A           00953         movlw   D'10'
0232   02A3           00954         subwf   Dig1,F
0233   0AA2           00955         incf    Dig10,F
0234   2A2D           00956         goto    B2Dlp
                      00957 ;       
0235   0008           00958 B2De    return
                      00959 ;       
                      00960 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00961 ;       Convert Decimals to Characters                          ;
                      00962 ;               changing Dec10-1 to characers                   ;
                      00963 ;               with clearing leading-zero                      ;
                      00964 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0236   3030           00965 D2Cr    movlw   H'30'           ; Left nibble of numeric chars
0237   04A2           00966         iorwf   Dig10,F         ; Convert Dig10 to character
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 28


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

0238   04A3           00967         iorwf   Dig1,F          ; Convert Dig1 to character
                      00968 ;
                      00969         CalEO   Dig10,H'30',D2Czb ; Check leading 0 ?
0239   3030               M         movlw   H'30'           ; W=B
023A   0222               M         subwf   Dig10,W         ; W=A-B
023B   1903               M         btfsc   STATUS,Z        ; A=B? No skip next
023C   2A3E               M         goto    D2Czb           ;       If A=B goto Eqladr
                          M ;                               ;       else next (here)
023D   0008           00970         return                  ; No, return
                      00971 ;
023E   3020           00972 D2Czb   movlw   A' '            ; If zero, replace with blank
023F   00A2           00973         movwf   Dig10           ;       at Dig10
0240   0008           00974         return
                      00975 ;
                      00976 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00977 ;       LCD slave-adr sending routine                   ;
                      00978 ;               with address in Sbyte, getting Ack.     ;
                      00979 ;               (start-I2C included, without stop-I2C)  ;
                      00980 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  00000241            00981 lSndAr  equ     $
                      00982         I2Cstat                 ; start I2C
0241   22D4               M         call    I2Cstar
0242   304E           00983         movlw   lcdAw           ; get LCD slave adr
0243   00BD           00984         movwf   Sbyte           ; set it to Sbyte
0244   22E8           00985         call    Sendr           ; and send it
0245   0008           00986         return
                      00987 ;
                      00988 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      00989 ;       LCD I2C adr and a Literal sending routine       ;
                      00990 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0246   00B3           00991 lSndALr movwf   Dbyte           ; save literal to Dbyte
0247   2241           00992         call    lSndAr          ; send adr
0248   0833           00993         movf    Dbyte,W         ; get saved literal
0249   00BD           00994         movwf   Sbyte
024A   22E8           00995         call    Sendr           ; send it
                      00996         I2Cstop                 ; stop I2C
024B   22DB               M         call    I2Cstpr
024C   0008           00997         return
                      00998 ;
                      00999 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01000 ;       Set-cursor routine for LCD called by lcdSetC    ;
                      01001 ;       If W=0xab, send 0xaC, 0xa8, 0xbC, and 0xb8      ;
                      01002 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
024D   00B4           01003 lSetCsr movwf   Ebyte           ; save Value into Ebyte
024E   2254           01004         call    lSetCss         ; send left nibble
024F   0E34           01005         swapf   Ebyte,W         ; set W w/ swapping nibbles
0250   2254           01006         call    lSetCss         ; send right nibble
                      01007 ;
                      01008         Mic50   1
0251   3001               M         movlw   1
0252   231B               M         call    Mic50r
0253   0008           01009         return
                      01010 ;
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 29


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      01011 ;       lSetCss subroutine to send a nibble
0254   00B5           01012 lSetCss movwf   Wbyte
0255   300F           01013         movlw   H'0F'
0256   04B5           01014         iorwf   Wbyte,F         ; set xF
0257   30FC           01015         movlw   H'FC'
0258   0535           01016         andwf   Wbyte,W         ; change it to xC
0259   00B5           01017         movwf   Wbyte           ; set it to Wbyte, too
025A   2246           01018         call    lSndALr         ; send S, adr, nibble+C, and P
                      01019 ;
025B   30FB           01020         movlw   B'11111011'     ; get complement of 0C-08
025C   0535           01021         andwf   Wbyte,W         ; and change C to 8, ie x8
025D   2246           01022         call    lSndALr         ; send S, adr, nibble+8, and P
025E   0008           01023         return
                      01024 ;
                      01025 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01026 ;       LCD send-char routine                   ;
                      01027 ;       If W=0xab, send 0xaD, 0xa9, 0xbD, and 0xb9      ;
                      01028 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
025F   00B4           01029 lSetChr movwf   Ebyte           ; save Value into Ebyte
                      01030 ;       sending left nibble
0260   2264           01031         call    lSetChs
                      01032 ;
                      01033 ;       sending right nibble
0261   0E34           01034         swapf   Ebyte,W         ; replace left nibble w/ right
0262   2264           01035         call    lSetChs
0263   0008           01036         return
                      01037 ;
                      01038 ;       LCD subroutine to send a character  ;
0264   00B5           01039 lSetChs movwf   Wbyte           ; W to Wbyte
0265   300F           01040         movlw   H'0F'           ; set right nibble bits of 
0266   04B5           01041         iorwf   Wbyte,F         ;   Wbyte on
0267   30FD           01042         movlw   H'FD'           ; leave left nibble + right D
0268   0535           01043         andwf   Wbyte,W         ;  into W
0269   00B5           01044         movwf   Wbyte           ; save it into Wbyte
026A   2246           01045         call    lSndALr         ; send S, adr, nibble+D, and P
                      01046 ;
026B   0835           01047         movf    Wbyte,W
026C   30FB           01048         movlw   B'11111011'     ; target bit 2 to off (D to 9)
026D   0535           01049         andwf   Wbyte,W         ; make left nibble + right 9
026E   2246           01050         call    lSndALr         ; send S, adr, nibble+9, and P  
026F   0008           01051         return
                      01052 ;
                      01053 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01054 ;       LCD.clear routine                               ;
                      01055 ;       Send 0x8C, 0x88, 0x0C, and 0x08                 ;
                      01056 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  00000270            01057 lClr    equ     $
                      01058         LCDw    H'8C'
0270   308C               M         movlw   H'8C'
0271   225F               M         call    lSetChr
                      01059         LCDw    H'88'
0272   3088               M         movlw   H'88'
0273   225F               M         call    lSetChr
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 30


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      01060         LCDw    H'0C'
0274   300C               M         movlw   H'0C'
0275   225F               M         call    lSetChr
                      01061         LCDw    H'08'
0276   3008               M         movlw   H'08'
0277   225F               M         call    lSetChr
                      01062         Mic50   1
0278   3001               M         movlw   1
0279   231B               M         call    Mic50r
027A   0008           01063         return
                      01064 ;
                      01065 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01066 ;       I2C Send byte-string                            ;
                      01067 ;         when called,                                  ;
                      01068 ;               I2C device adr in I2Cadr byte           ;
                      01069 ;               Data length in DataLen                  ;
                      01070 ;               Data Addr in FSR0L (INDF0)              ;
                      01071 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
027B   0836           01072 I2Csndr movf    I2Cadr,W
027C   00BD           01073         movwf   Sbyte
                      01074 ;       rlf     Sbyte,F ; shift leftt (if adr for Arduino)
027D   103D           01075         bcf     Sbyte,0 ; indicate write
                      01076 ;
                      01077         I2Cstat         ; Start I2C
027E   22D4               M         call    I2Cstar
027F   22E8           01078         call    Sendr
                      01079 
0280   0800           01080 Sdata   movf    INDF0,W ; Get a sending character
0281   00BD           01081         movwf   Sbyte   ; Set it to Sbyte
0282   22E8           01082         call    Sendr   ; Send it to the device
                      01083 ;
0283   0A84           01084         incf    FSR0L,F ; point next char
0284   0BB7           01085         decfsz  DataLen,F ; Have all chars sent ?
0285   2A80           01086         goto    Sdata           ; No, loop
                      01087 ;
                      01088 ; Stop signal and return
                      01089         I2Cstop
0286   22DB               M         call    I2Cstpr
0287   0008           01090         return  
                      01091 ;
                      01092 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01093 ;       I2C Receive byte-string                         ;
                      01094 ;         when called,                                  ;
                      01095 ;               I2C device adr in I2Cadr byte           ;
                      01096 ;               Data length in DataLen                  ;
                      01097 ;               Data Addr in FSR0L (INDF0)              ;
                      01098 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  00000288            01099 I2Crcvr equ     $
                      01100         I2Cstat         ; Start I2C
0288   22D4               M         call    I2Cstar
0289   0836           01101         movf    I2Cadr,W ; Get I2C dev addr
028A   00BD           01102         movwf   Sbyte   ; Set it into Sbyte
                      01103 ;       rlf     Sbyte,F ; Shift left (if adr for Arduino)
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 31


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

028B   143D           01104         bsf     Sbyte,0 ; indicate read
028C   22E8           01105         call    Sendr   ; Send slave addr to read
                      01106 ;
  0000028D            01107 I2Crbyt equ     $
028D   0021           01108         BANKSEL TRISI2C ;
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
028E   150C           01109         bsf     TRISI2C,Dl ; Set Dline input mode
028F   0188           01110         clrf    BSR     ; Point Bank 0
                      01111 ;
0290   3008           01112         movlw   8       ; Bits in a reciving byte
0291   00BF           01113         movwf   Bitctr  ; into loop counter 
                      01114 I2Crblp Mic2p5  2*Clkt  ; Timing before raising clock
0292   3002               M         movlw   2*Clkt
0293   2312               M         call    Mic25r
0294   148C           01115         bsf     PORTI2C,Cl ; Set clock high
                      01116         Mic2p5  Clkt    ; Timing after raising clock
0295   3001               M         movlw   Clkt
0296   2312               M         call    Mic25r
                      01117 ;
0297   190C           01118         btfsc   PORTI2C,Dl
0298   2A9B           01119         goto    Rbith
                      01120 ;       goto    Rbitl
                      01121 ;
0299   103D           01122 Rbitl   bcf     Sbyte,0 ; Clear bit 0
029A   2A9C           01123         goto    Rbitnxt ; and goto next
                      01124 ;
029B   143D           01125 Rbith   bsf     Sbyte,0 ; Set bit 0
                      01126 Rbitnxt Mic2    Clkq    ; Timing after checking
029C   3001               M         movlw   Clkq
029D   230B               M         call    Mic2r
029E   108C           01127         bcf     PORTI2C,Cl ; Set clock low
                      01128 ;       Mic2p5  Clkt    ; Timing after clock falling
029F   0BBF           01129         decfsz  Bitctr,F ; Still bits?
02A0   2AA2           01130         goto    Rbcont  ; Yes, continue
02A1   2AA4           01131         goto    Rbend   ; No, end of one byte
                      01132 ;
02A2   0DBD           01133 Rbcont  rlf     Sbyte,F ; Shit left
02A3   2A92           01134         goto    I2Crblp ; and goto loop
                      01135 ;
02A4   083D           01136 Rbend   movf    Sbyte,W ; Get received byte
02A5   0080           01137         movwf   INDF0   ; Set it to INDF0
02A6   0A84           01138         incf    FSR0L,F ; increase index
02A7   0BB7           01139         decfsz  DataLen,F ; DataLen-1
02A8   2AAA           01140         goto    Sackr   ; Send Ack and continue
02A9   2ABA           01141         goto    Snackr  ; Send Nack and stop
                      01142 ;
                      01143 ;Set Dl output mode and send Ack to conitinue
  000002AA            01144 Sackr   equ     $
02AA   0022           01145         BANKSEL LATI2C  ; Data line high when output mode
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
02AB   150C           01146         bsf     LATI2C,Dl ; Lat-Dl on
02AC   0021           01147         BANKSEL TRISI2C ; 
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 32


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

02AD   110C           01148         bcf     TRISI2C,Dl ; Set Dl output mode
02AE   0188           01149         clrf    BSR     ; Point Bank 0
                      01150 ;
02AF   110C           01151         bcf     PORTI2C,Dl ; Send Ack
                      01152         Mic2    Clkq    ; Timing after clock falling
02B0   3001               M         movlw   Clkq
02B1   230B               M         call    Mic2r
02B2   148C           01153         bsf     PORTI2C,Cl ; Show Ack
                      01154         Mic2p5  2*Clkt
02B3   3002               M         movlw   2*Clkt
02B4   2312               M         call    Mic25r
02B5   108C           01155         bcf     PORTI2C,Cl ; Set clock low
                      01156         Mic2    Clkq
02B6   3001               M         movlw   Clkq
02B7   230B               M         call    Mic2r
02B8   150C           01157         bsf     PORTI2C,Dl ; Return Dline to high
02B9   2A8D           01158         goto    I2Crbyt         ; Next byte process
                      01159 ;
                      01160 ;Set Dl output mode and send Nack
  000002BA            01161 Snackr  equ     $
02BA   0022           01162         BANKSEL LATI2C  ; Data line high when output mode
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
02BB   150C           01163         bsf     LATI2C,Dl ; Lat-Dl on
02BC   0021           01164         BANKSEL TRISI2C ; 
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
02BD   110C           01165         bcf     TRISI2C,Dl ; Set Dl output mode
02BE   0188           01166         clrf    BSR     ; Point Bank 0
                      01167 ;
02BF   150C           01168         bsf     PORTI2C,Dl ; Send Nack
                      01169         Mic2    Clkq    ; Timing after clock falling
02C0   3001               M         movlw   Clkq
02C1   230B               M         call    Mic2r
02C2   148C           01170         bsf     PORTI2C,Cl ; Show Nack
                      01171         Mic2p5  2*Clkt
02C3   3002               M         movlw   2*Clkt
02C4   2312               M         call    Mic25r
02C5   108C           01172         bcf     PORTI2C,Cl      ; Set clock low
                      01173         Mic2p5  Clkt
02C6   3001               M         movlw   Clkt
02C7   2312               M         call    Mic25r
                      01174         I2Cstop         ; and stop I2C once
02C8   22DB               M         call    I2Cstpr
                      01175         Mic5    D'6'    ; for 30 micro sec
02C9   3006               M         movlw   D'6'
02CA   2312               M         call    Mic25r
02CB   3006               M         movlw   D'6'
02CC   2312               M         call    Mic25r
                      01176 ;
                      01177         I2Cstat         ; then start I2C again
02CD   22D4               M         call    I2Cstar
02CE   0836           01178         movf    I2Cadr,W ; Get I2C dev addr
02CF   00BD           01179         movwf   Sbyte   ; Set it into Sbyte
                      01180 ;       rlf     Sbyte,F ; Shift left (if adr for Arduino)
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 33


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

02D0   103D           01181         bcf     Sbyte,0 ; indicate write
02D1   22E8           01182         call    Sendr   ; Send it
                      01183 ;
                      01184         I2Cstop
02D2   22DB               M         call    I2Cstpr
02D3   0008           01185         return
                      01186 ;
                      01187 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01188 ;       I2C Start signal routine                        ;
                      01189 ;               when dataline mode is output            ;
                      01190 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
02D4   110C           01191 I2Cstar bcf     PORTI2C,Dl ; set SDA low
                      01192         Mic2    Clkq
02D5   3001               M         movlw   Clkq
02D6   230B               M         call    Mic2r
02D7   108C           01193         bcf     PORTI2C,Cl ; set SCL low
                      01194         Mic2p5  2*Clkt
02D8   3002               M         movlw   2*Clkt
02D9   2312               M         call    Mic25r
02DA   0008           01195         return
                      01196 ;
                      01197 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01198 ;       I2C Stop signal routine                         ;
                      01199 ;               when dataline mode is output            ;
                      01200 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
02DB   108C           01201 I2Cstpr bcf     PORTI2C,Cl ; set SCL low
                      01202         Mic2    Clkq
02DC   3001               M         movlw   Clkq
02DD   230B               M         call    Mic2r
02DE   110C           01203         bcf     PORTI2C,Dl ; set SDA low
                      01204         Mic2p5  2*Clkt
02DF   3002               M         movlw   2*Clkt
02E0   2312               M         call    Mic25r
02E1   148C           01205         bsf     PORTI2C,Cl ; Clock line rasing
                      01206         Mic2p5  Clkt
02E2   3001               M         movlw   Clkt
02E3   2312               M         call    Mic25r
02E4   150C           01207         bsf     PORTI2C,Dl ; Data line rasing
                      01208         Mic2    Clkq
02E5   3001               M         movlw   Clkq
02E6   230B               M         call    Mic2r
02E7   0008           01209         return  
                      01210 ;
                      01211 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01212 ;       I2C One-byte sending routine                    ;
                      01213 ;               with data in Sbyte                      ;
                      01214 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
02E8   3008           01215 Sendr   movlw   8       ; Set bit count in a byte
02E9   00BF           01216         movwf   Bitctr  ; into loop counter 
                      01217 ;
02EA   1BBD           01218 Sloop   btfsc   Sbyte,7 ; Check top bit of Sbyte
02EB   2AEE           01219         goto    Slpdh   ; 
02EC   110C           01220         bcf     PORTI2C,Dl ; If bit low then Data L
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 34


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

02ED   2AEF           01221         goto    Slpnxt
02EE   150C           01222 Slpdh   bsf     PORTI2C,Dl ; If bit high then Data H
                      01223 ;
                      01224 Slpnxt  Mic2    Clkq
02EF   3001               M         movlw   Clkq
02F0   230B               M         call    Mic2r
02F1   148C           01225         bsf     PORTI2C,Cl ; Show bit
                      01226         Mic2p5  2*Clkt
02F2   3002               M         movlw   2*Clkt
02F3   2312               M         call    Mic25r
02F4   108C           01227         bcf     PORTI2C,Cl ;
                      01228         Mic2    Clkq
02F5   3001               M         movlw   Clkq
02F6   230B               M         call    Mic2r
                      01229 ;
02F7   0DBD           01230         rlf     Sbyte,F ; Shift left 
02F8   0BBF           01231         decfsz  Bitctr,F ; All bits done?
02F9   2AEA           01232         goto    Sloop   ; No, loop within a byte
                      01233 ;       
                      01234 ;Receive Ack            
                      01235 ; set data line input mode
02FA   0021           01236         BANKSEL TRISI2C ; 
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
02FB   150C           01237         bsf     TRISI2C,Dl ; Set Dline input mode
02FC   0188           01238         clrf    BSR     ; Point Bank 0
                      01239 ;
                      01240         Mic2    Clkq    ; wait for Ack timing
02FD   3001               M         movlw   Clkq
02FE   230B               M         call    Mic2r
02FF   148C           01241         bsf     PORTI2C,Cl ; Clock H for Acq confirmation
                      01242         Mic2p5  2*Clkt  ; 
0300   3002               M         movlw   2*Clkt
0301   2312               M         call    Mic25r
0302   108C           01243         bcf     PORTI2C,Cl ; Cl L for Dl release by slave
                      01244         Mic2p5  2*Clkt
0303   3002               M         movlw   2*Clkt
0304   2312               M         call    Mic25r
                      01245 ;
                      01246 ; Set Data line output
0305   0022           01247         BANKSEL LATI2C  ; Data line high when output mode
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
0306   150C           01248         bsf     LATI2C,Dl ; Lat-Dl on
0307   0021           01249         BANKSEL TRISI2C ; 
Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.
0308   110C           01250         bcf     TRISI2C,Dl ; Set Dl output mode
0309   0188           01251         clrf    BSR     ; Point Bank 0
030A   0008           01252         return
                      01253 ;
                      01254 
                      01255 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01256 ;       Timing subrooutines for general purposes                ;
                      01257 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01258 ;
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 35


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      01259 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01260 ;       Make 2.0 micro S x n    (Mic2)  ;
                      01261 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
030B   00C0           01262 Mic2r   movwf   Mic25c          ; + Wset + call = 1 micro sec 
                      01263 ;
030C   0BC0           01264 Mic2l   decfsz  Mic25c,F        ; If exhausted, 1 micro S hereafter
030D   2B0F           01265         goto    Mic2li          ; else go out (2nd time 1.75 mic sec)
030E   0008           01266         return          
                      01267 ;
030F   2B10           01268 Mic2li  goto    $+1             ;            (2nd time 2.25 mic sec)
0310   0000           01269         nop                     ;            (2nd time 2.5 mic sec)
0311   2B0C           01270         goto    Mic2l           ; go back    (2nd time 3 micro sec)
                      01271 ;
                      01272 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01273 ;       Make 2.5 micro S x n (Mic2p5)   ;
                      01274 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0312   00C0           01275 Mic25r  movwf   Mic25c          ; + Wset + call = 1 micro sec 
0313   0000           01276         nop                     ; 1.25 micro sec
                      01277 ;
0314   0000           01278 Mic25l  nop                     ; 1.5 micro sec (2nd time 4 mic sec)
0315   0BC0           01279         decfsz  Mic25c,F        ; If exhausted, 1 micro S hereafter
0316   2B18           01280         goto    Mic25li         ; else go out (2nd time 2.25 mic sec)
0317   0008           01281         return          
                      01282 ;
                      01283 Mic25li Mic                     ;             (2nd time 3.25 mic sec)
0318   2B19               M         goto    $+1
0319   2B1A               M         goto    $+1
031A   2B14           01284         goto    Mic25l          ; go back    (2nd time 3.75 micro sec)
                      01285 ;
                      01286 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01287 ;       50 Microseconds x n     Mic50   ;
                      01288 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01289 ;
031B   00C1           01290 Mic50r  movwf   Mic50c          ; set how many 50 microsec (1 micro sec to here)
031C   0000           01291         nop                     ; 1.25 micro sec up to here
                      01292 ;
                      01293 Mic50l  Mic2p5  D'19'           ; + 47.5 = 48.75 mic sec (2nd time 98.75 mic sec)
031D   3013               M         movlw   D'19'
031E   2312               M         call    Mic25r
031F   0000           01294         nop                     ; + 0.25 = 49 micro sec (2nd time 99 mic sec)
                      01295 ; 
0320   0BC1           01296         decfsz  Mic50c,F        ; If exhausted then 1 mic S hereafter
0321   2B23           01297         goto    Mic50li         ; else go out (2nd time 49.75 mic sec)
0322   0008           01298         return
                      01299 ;
                      01300 ;
                      01301 Mic50li Mic                     ;         (2nd time 50.75 mic sec)
0323   2B24               M         goto    $+1
0324   2B25               M         goto    $+1
0325   2B1D           01302         goto    Mic50l          ; go back (2nd time 51.25 mic sec)
                      01303 ;
                      01304 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01305 ;       Milliseconds x n        (Milli) ;
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 36


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

                      01306 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01307 ;
0326   00C2           01308 Millir  movwf   Millic          ; set how many 1 mil sec (1 mic S up to here)
0327   0000           01309         nop                     ; 1.25 micro sec
                      01310 ;
                      01311 Millil  Mic50   D'19'           ; + 50 mic x 19 = 951.25 mic S (2nd, 1951.25) 
0328   3013               M         movlw   D'19'
0329   231B               M         call    Mic50r
                      01312         Mic2p5  D'19'           ; + 47.5 mic = 998.75 micro S  (2nd, 1998.75)
032A   3013               M         movlw   D'19'
032B   2312               M         call    Mic25r
032C   0000           01313         nop                     ; +0.25 mic = 999 micro sec    (2nd, 1999)
                      01314 ;
032D   0BC2           01315         decfsz  Millic,F        ; If  exhausted then 1 micro sec hereafter
032E   2B30           01316         goto    Millili         ; else go out (2nd, 999.75 mic S)
032F   0008           01317         return
                      01318 ;
                      01319 Millili Mic                     ;               (2nd time 1000.75 mic S)
0330   2B31               M         goto    $+1
0331   2B32               M         goto    $+1
0332   2B28           01320         goto    Millil          ; go back (2nd time 1001.25 mic S)
                      01321 ;
                      01322 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01323 ;       100 Milliseconds x n    (Mil100);
                      01324 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0333   00C3           01325 Mil100r movwf   Mil100c         ;set how many 100 ms(1 micr sec up to here)
0334   0000           01326         nop                     ; 1.25 micro sec
                      01327 ;
                      01328 Milhl   Milli   D'99'           ;+1ms x 99 = 99001.25 micS (2nd,199001.25mic)
0335   3063               M         movlw   D'99'
0336   2326               M         call    Millir
                      01329         Mic50   D'19'           ; + 950 mic = 99951.25 micS(2nd.199951.25mic)
0337   3013               M         movlw   D'19'
0338   231B               M         call    Mic50r
                      01330         Mic2p5  D'19'           ; + 47.5 mic = 99998.75micS(2nd,199998.75mic)
0339   3013               M         movlw   D'19'
033A   2312               M         call    Mic25r
033B   0000           01331         nop                     ; + 0.25 mic = 99999 mic S (2nd,199999 micS)
                      01332 ;
033C   0BC3           01333         decfsz  Mil100c,F       ; If exhausted then 1 micro sec hereafter
033D   2B3F           01334         goto    Milhli          ; else go out (2nd time, 99999.75 mic S)
033E   0008           01335         return
                      01336 ;
                      01337 Milhli  Mic                     ;               (2nd time, 100000.75 mic S)
033F   2B40               M         goto    $+1
0340   2B41               M         goto    $+1
0341   2B35           01338         goto    Milhl           ;               (2nd time, 100001.25 mic S)
                      01339 ;
                      01340 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01341 ;       Seconds x n      (Secs)         ;
                      01342 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01343 ;
0342   00C4           01344 Secsr   movwf   Secsc           ; set how many sec ( 1 mic sec up to here)
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 37


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

0343   0000           01345         nop                     ; 1.25 micro sec
                      01346 ;
                      01347 Secsl   Mil100  D'9'            ; 
0344   3009               M         movlw   D'9'
0345   2333               M         call    Mil100r
                      01348         Milli   D'99'           ; + 999 milli sec = 999001.25 micro sec
0346   3063               M         movlw   D'99'
0347   2326               M         call    Millir
                      01349 ;
                      01350         Mic50   D'19'           ; + 950 mic = 999951.25 micro sec
0348   3013               M         movlw   D'19'
0349   231B               M         call    Mic50r
                      01351         Mic2p5  D'19'           ; + 47.5 mic = 999998.75 micro sec
034A   3013               M         movlw   D'19'
034B   2312               M         call    Mic25r
034C   0000           01352         nop                     ; + 0.25 mic = 999999 micro sec
                      01353 ;
034D   0BC4           01354         decfsz  Secsc,F         ; If exhausted then 1 micro sec hereafter
034E   2B50           01355         goto    Secsli          ; else, go out 
034F   0008           01356         return
                      01357 ;
                      01358 Secsli  Mic
0350   2B51               M         goto    $+1
0351   2B52               M         goto    $+1
0352   2B44           01359         goto    Secsl           ; (Second time, Sec + 1.25 micro sec)
                      01360 ;
                      01361 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01362 ;       Minutes x n      (Mins)         ;
                      01363 ;        Overhead ignored, that is only ;
                      01364 ;        751.25 Mic S even when 100 Min ;
                      01365 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0353   00C5           01366 Minsr   movwf   Minsc           ;set how many minutes from parameter
                      01367 ;
                      01368 Minsl   Secs    D'60'           ; 1 Seconds x 60
0354   303C               M         movlw   D'60'
0355   2342               M         call    Secsr
0356   0BC5           01369         decfsz  Minsc,F
0357   2B54           01370         goto    Minsl
0358   0008           01371         return
                      01372 ;
                      01373 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01374 ;       End of program                                          ;
                      01375 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                      01376         end
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 38


SYMBOL TABLE
  LABEL                             VALUE 

ABDEN                             00000000
ABDOVF                            00000007
ACKDT                             00000005
ACKEN                             00000004
ACKSTAT                           00000006
ACKTIM                            00000007
ADCON0                            0000009D
ADCON1                            0000009E
ADCS0                             00000004
ADCS1                             00000005
ADCS2                             00000006
ADDEN                             00000003
ADFM                              00000007
ADFVR0                            00000000
ADFVR1                            00000001
ADGO                              00000001
ADIE                              00000006
ADIF                              00000006
ADON                              00000000
ADPREF0                           00000000
ADPREF1                           00000001
ADRES                             0000009B
ADRESH                            0000009C
ADRESL                            0000009B
AHEN                              00000001
AN0                               00000000
AN1                               00000001
AN2                               00000002
AN3                               00000004
ANSA0                             00000000
ANSA1                             00000001
ANSA2                             00000002
ANSA4                             00000004
ANSELA                            0000018C
APFCON                            0000011D
APFCON0                           0000011D
Abyte                             00000032
B2De                              00000235
B2Dlp                             0000022D
B2Dr                              0000022A
BAUDCON                           0000019F
BCDday                            0000002F
BCDdow                            0000002E
BCDhr                             0000002D
BCDmin                            0000002C
BCDmon                            00000030
BCDsec                            0000002B
BCDyr                             00000031
BCL1IE                            00000003
BCL1IF                            00000003
BF                                00000000
BOEN                              00000004
BORCON                            00000116
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 39


SYMBOL TABLE
  LABEL                             VALUE 

BORRDY                            00000000
BRG16                             00000003
BRGH                              00000002
BSR                               00000008
BSR0                              00000000
BSR1                              00000001
BSR2                              00000002
BSR3                              00000003
BSR4                              00000004
BSR_SHAD                          00000FE6
Bitctr                            0000003F
Bytectr                           0000003E
Byteh                             00000028
Bytel                             00000029
C                                 00000000
C1HYS                             00000001
C1IE                              00000005
C1IF                              00000005
C1IN0N                            00000001
C1IN1N                            00000004
C1INP                             00000000
C1INTN                            00000006
C1INTP                            00000007
C1NCH0                            00000000
C1OE                              00000005
C1ON                              00000007
C1OUT_CM1CON0                     00000006
C1OUT_PORTA                       00000002
C1PCH0                            00000004
C1PCH1                            00000005
C1POL                             00000004
C1SP                              00000002
C1SYNC                            00000000
CCP1AS                            00000295
CCP1AS0                           00000004
CCP1AS1                           00000005
CCP1AS2                           00000006
CCP1ASE                           00000007
CCP1CON                           00000293
CCP1IE                            00000002
CCP1IF                            00000002
CCP1M0                            00000000
CCP1M1                            00000001
CCP1M2                            00000002
CCP1M3                            00000003
CCP1SEL                           00000000
CCPR1H                            00000292
CCPR1L                            00000291
CDAFVR0                           00000002
CDAFVR1                           00000003
CFGS                              00000006
CHS0                              00000002
CHS1                              00000003
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 40


SYMBOL TABLE
  LABEL                             VALUE 

CHS2                              00000004
CHS3                              00000005
CHS4                              00000006
CKE                               00000006
CKP                               00000004
CLKIN                             00000005
CLKOUT                            00000004
CLKR                              00000004
CLKRCON                           0000039A
CLKRDC0                           00000003
CLKRDC1                           00000004
CLKRDIV0                          00000000
CLKRDIV1                          00000001
CLKRDIV2                          00000002
CLKREN                            00000007
CLKROE                            00000006
CLKRSLR                           00000005
CM1CON0                           00000111
CM1CON1                           00000112
CMOUT                             00000115
CPS0                              00000000
CPS1                              00000001
CPS2                              00000002
CPS3                              00000004
CPSCH0                            00000000
CPSCH1                            00000001
CPSCON0                           0000001E
CPSCON1                           0000001F
CPSON                             00000007
CPSOUT                            00000001
CPSRM                             00000006
CPSRNG0                           00000002
CPSRNG1                           00000003
CREN                              00000004
CSRC                              00000007
C_SHAD                            00000000
CabEO                             
CabSEL                            
CabSO                             
CalEO                             
CalLO                             
CalSEL                            
CalSO                             
CalUO                             
ChMEq                             0000003D
ChMM                              0000004D
ChMS                              00000053
ChMY                              00000059
ChMd                              00000044
ChMh                              00000068
ChMm                              0000006D
ChMw                              00000057
Cl                                00000001
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 41


SYMBOL TABLE
  LABEL                             VALUE 

Clkq                              00000001
Clkt                              00000001
D2Cr                              00000236
D2Czb                             0000023E
DACCON0                           00000118
DACCON1                           00000119
DACEN                             00000007
DACLPS                            00000006
DACOE                             00000005
DACOUT                            00000000
DACPSS0                           00000002
DACPSS1                           00000003
DACR0                             00000000
DACR1                             00000001
DACR2                             00000002
DACR3                             00000003
DACR4                             00000004
DC                                00000001
DC1B0                             00000004
DC1B1                             00000005
DC_SHAD                           00000001
DEVset                            
DHEN                              00000000
DHT11                             00000000
DHTrd                             0000018F
DHbc                              000001B2
DHbcl                             000001B4
DHbye                             000001C3
DHcksr                            000001CB
DHeck                             000001C1
DHnxtbi                           000001C9
DHsone                            000001BA
DHszero                           000001C0
DS3231                            000000D0
D_NOT_A                           00000005
DataLen                           00000037
Dbyte                             00000033
Dig1                              00000023
Dig10                             00000022
Dl                                00000002
DspHr                             000001FF
DspTgo                            000001F4
DspTime                           00000086
DspTr                             000001D6
ECCP1AS                           00000295
EEADR                             00000191
EEADRH                            00000192
EEADRL                            00000191
EECON1                            00000195
EECON2                            00000196
EEDAT                             00000193
EEDATH                            00000194
EEDATL                            00000193
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 42


SYMBOL TABLE
  LABEL                             VALUE 

EEIE                              00000004
EEIF                              00000004
EEPGD                             00000007
Ebyte                             00000034
F                                 00000001
FERR                              00000002
FLT0                              00000002
FREE                              00000004
FSR0                              00000004
FSR0H                             00000005
FSR0H_SHAD                        00000FE9
FSR0L                             00000004
FSR0L_SHAD                        00000FE8
FSR1                              00000006
FSR1H                             00000007
FSR1H_SHAD                        00000FEB
FSR1L                             00000006
FSR1L_SHAD                        00000FEA
FVRCON                            00000117
FVREN                             00000007
FVRRDY                            00000006
GCEN                              00000007
GIE                               00000007
GO                                00000001
GO_NOT_DONE                       00000001
HFIOFL                            00000003
HFIOFR                            00000004
HFIOFS                            00000000
I2Cadr                            00000036
I2Crblp                           00000292
I2Crbyt                           0000028D
I2Crcv                            
I2Crcvr                           00000288
I2Csnd                            
I2Csndr                           0000027B
I2Cstar                           000002D4
I2Cstat                           
I2Cstop                           
I2Cstpr                           000002DB
INDF0                             00000000
INDF1                             00000001
INTCON                            0000000B
INTE                              00000004
INTEDG                            00000006
INTF                              00000001
IOCAF                             00000393
IOCAF0                            00000000
IOCAF1                            00000001
IOCAF2                            00000002
IOCAF3                            00000003
IOCAF4                            00000004
IOCAF5                            00000005
IOCAN                             00000392
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 43


SYMBOL TABLE
  LABEL                             VALUE 

IOCAN0                            00000000
IOCAN1                            00000001
IOCAN2                            00000002
IOCAN3                            00000003
IOCAN4                            00000004
IOCAN5                            00000005
IOCAP                             00000391
IOCAP0                            00000000
IOCAP1                            00000001
IOCAP2                            00000002
IOCAP3                            00000003
IOCAP4                            00000004
IOCAP5                            00000005
IOCIE                             00000003
IOCIF                             00000000
IRCF0                             00000003
IRCF1                             00000004
IRCF2                             00000005
IRCF3                             00000006
InitP                             
LATA                              0000010C
LATA0                             00000000
LATA1                             00000001
LATA2                             00000002
LATA4                             00000004
LATA5                             00000005
LATI2C                            0000010C
LATdht                            0000010C
LCD2004                           0000004E
LCDclr                            
LCDi2cA                           00000027
LCDinir                           00000029
LCDl                              
LCDsA                             
LCDsetC                           
LCDw                              
LCDwb                             
LFIOFR                            00000001
LWLO                              00000005
MC1OUT                            00000000
MDBIT                             00000000
MDCARH                            0000039F
MDCARL                            0000039E
MDCH0                             00000000
MDCH1                             00000001
MDCH2                             00000002
MDCH3                             00000003
MDCHODIS                          00000007
MDCHPOL                           00000006
MDCHSYNC                          00000005
MDCIN1                            00000002
MDCIN2                            00000004
MDCL0                             00000000
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 44


SYMBOL TABLE
  LABEL                             VALUE 

MDCL1                             00000001
MDCL2                             00000002
MDCL3                             00000003
MDCLODIS                          00000007
MDCLPOL                           00000006
MDCLSYNC                          00000005
MDCON                             0000039C
MDEN                              00000007
MDMIN                             00000001
MDMS0                             00000000
MDMS1                             00000001
MDMS2                             00000002
MDMS3                             00000003
MDMSODIS                          00000007
MDOE                              00000006
MDOPOL                            00000004
MDOUT_MDCON                       00000003
MDOUT_PORTA                       00000000
MDSLR                             00000005
MDSRC                             0000039D
MFIOFR                            00000002
Mainp                             0000001F
Mddayr                            0000010E
Mddowr                            00000107
Mdhrr                             00000100
Mdminr                            000000F9
Mdmonr                            00000115
Mdnext                            00000123
Mdsecr                            000000F2
Mdsetup                           
Mdyrr                             0000011C
Mic                               
Mic2                              
Mic25c                            00000040
Mic25l                            00000314
Mic25li                           00000318
Mic25r                            00000312
Mic2l                             0000030C
Mic2li                            0000030F
Mic2p5                            
Mic2r                             0000030B
Mic5                              
Mic50                             
Mic50c                            00000041
Mic50l                            0000031D
Mic50li                           00000323
Mic50r                            0000031B
Mil100                            
Mil100c                           00000043
Mil100r                           00000333
Milhl                             00000335
Milhli                            0000033F
Milli                             
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 45


SYMBOL TABLE
  LABEL                             VALUE 

Millic                            00000042
Millil                            00000328
Millili                           00000330
Millir                            00000326
Mins                              
Minsc                             00000045
Minsl                             00000354
Minsr                             00000353
ModeChr                           00000025
ModeMax                           00000006
ModeMin                           00000000
ModeN                             00000024
Modeyr                            00000006
Moji1                             00000020
Moji2                             00000021
Msmax                             00000137
NOT_BOR                           00000000
NOT_DONE                          00000001
NOT_MCLR                          00000003
NOT_PD                            00000003
NOT_POR                           00000001
NOT_RI                            00000002
NOT_RMCLR                         00000003
NOT_T1SYNC                        00000002
NOT_TO                            00000004
NOT_WPUEN                         00000007
OERR                              00000001
OPTION_REG                        00000095
OSC1                              00000005
OSC2                              00000004
OSCCON                            00000099
OSCSTAT                           0000009A
OSCTUNE                           00000098
OSFIE                             00000007
OSFIF                             00000007
OSTS                              00000005
P                                 00000004
P1BSEL                            00000001
P1DC0                             00000000
P1DC1                             00000001
P1DC2                             00000002
P1DC3                             00000003
P1DC4                             00000004
P1DC5                             00000005
P1DC6                             00000006
P1M0                              00000006
P1M1                              00000007
P1RSEN                            00000007
PCIE                              00000006
PCL                               00000002
PCLATH                            0000000A
PCLATH_SHAD                       00000FE7
PCON                              00000096
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 46


SYMBOL TABLE
  LABEL                             VALUE 

PEIE                              00000006
PEN                               00000002
PIE1                              00000091
PIE2                              00000092
PIR1                              00000011
PIR2                              00000012
PLLR                              00000006
PORTA                             0000000C
PORTI2C                           0000000C
PORTdht                           0000000C
PORTsw                            0000000C
PR2                               0000001B
PS0                               00000000
PS1                               00000001
PS2                               00000002
PSA                               00000003
PSS1AC0                           00000002
PSS1AC1                           00000003
PSS1BD0                           00000000
PSS1BD1                           00000001
PSTR1CON                          00000296
PWM1CON                           00000294
RA0                               00000000
RA1                               00000001
RA2                               00000002
RA3                               00000003
RA4                               00000004
RA5                               00000005
RCEN                              00000003
RCIDL                             00000006
RCIE                              00000005
RCIF                              00000005
RCREG                             00000199
RCSTA                             0000019D
RD                                00000000
RSEN                              00000001
RTCdata                           0000002B
RTCi2cA                           00000068
RTCmem                            0000002A
RTCrdr                            00000074
RTCudm                            000000E9
RTCupdr                           000000E5
RTCwtr                            00000186
RX9                               00000006
RX9D                              00000000
RXDTSEL                           00000007
R_NOT_W                           00000002
Rbcont                            000002A2
Rbend                             000002A4
Rbith                             0000029B
Rbitl                             00000299
Rbitnxt                           0000029C
Rdspr                             00000148
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 47


SYMBOL TABLE
  LABEL                             VALUE 

Rie                               00000184
Rigo                              00000174
Rinc                              0000012B
Rincr                             00000169
Rnxtm                             0000012F
Rnxtme                            00000136
RvMax                             00000026
RvMin                             00000027
Rwrite                            0000013A
S                                 00000003
SBCDE                             00000002
SBOREN                            00000007
SCIE                              00000005
SCK                               00000001
SCKP                              00000004
SCL                               00000001
SCS0                              00000000
SCS1                              00000001
SDA                               00000002
SDAHT                             00000003
SDI                               00000002
SDO1SEL                           00000006
SDOSEL                            00000006
SEN                               00000000
SENDB                             00000003
SMP                               00000007
SPBRG                             0000019B
SPBRGH                            0000019C
SPBRGL                            0000019B
SPEN                              00000007
SPLLEN                            00000007
SRCLK0                            00000004
SRCLK1                            00000005
SRCLK2                            00000006
SRCON0                            0000011A
SRCON1                            0000011B
SREN                              00000005
SRI                               00000001
SRLEN                             00000007
SRNQ                              00000005
SRNQEN                            00000002
SRPR                              00000000
SRPS                              00000001
SRQ                               00000002
SRQEN                             00000003
SRRC1E                            00000000
SRRCKE                            00000002
SRRPE                             00000003
SRSC1E                            00000004
SRSCKE                            00000006
SRSPE                             00000007
SS1SEL                            00000005
SSP1ADD                           00000212
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 48


SYMBOL TABLE
  LABEL                             VALUE 

SSP1BUF                           00000211
SSP1CON1                          00000215
SSP1CON2                          00000216
SSP1CON3                          00000217
SSP1IE                            00000003
SSP1IF                            00000003
SSP1MSK                           00000213
SSP1STAT                          00000214
SSPADD                            00000212
SSPBUF                            00000211
SSPCON                            00000215
SSPCON1                           00000215
SSPCON2                           00000216
SSPCON3                           00000217
SSPEN                             00000005
SSPM0                             00000000
SSPM1                             00000001
SSPM2                             00000002
SSPM3                             00000003
SSPMSK                            00000213
SSPOV                             00000006
SSPSTAT                           00000214
SSSEL                             00000005
STATUS                            00000003
STATUS_SHAD                       00000FE4
STKOVF                            00000007
STKPTR                            00000FED
STKUNF                            00000006
STR1A                             00000000
STR1B                             00000001
STR1C                             00000002
STR1D                             00000003
STR1SYNC                          00000004
SWDTEN                            00000000
SYNC                              00000004
Sackr                             000002AA
Sbyte                             0000003D
Sdata                             00000280
Secs                              
Secsc                             00000044
Secsl                             00000344
Secsli                            00000350
Secsr                             00000342
Sendr                             000002E8
Sloop                             000002EA
Slpdh                             000002EE
Slpnxt                            000002EF
Snackr                            000002BA
Startp                            00000005
T0CKI                             00000002
T0CS                              00000005
T0IE                              00000005
T0IF                              00000002
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 49


SYMBOL TABLE
  LABEL                             VALUE 

T0SE                              00000004
T0XCS                             00000000
T1CKI                             00000005
T1CKPS0                           00000004
T1CKPS1                           00000005
T1CON                             00000018
T1GCON                            00000019
T1GGO                             00000003
T1GGO_NOT_DONE                    00000003
T1GPOL                            00000006
T1GSEL                            00000003
T1GSPM                            00000004
T1GSS0                            00000000
T1GSS1                            00000001
T1GTM                             00000005
T1GVAL                            00000002
T1OSCEN                           00000003
T1OSCR                            00000007
T1OSI                             00000005
T1OSO                             00000004
T2CKPS0                           00000000
T2CKPS1                           00000001
T2CON                             0000001C
T2OUTPS0                          00000003
T2OUTPS1                          00000004
T2OUTPS2                          00000005
T2OUTPS3                          00000006
TMR0                              00000015
TMR0CS                            00000005
TMR0IE                            00000005
TMR0IF                            00000002
TMR0SE                            00000004
TMR1                              00000016
TMR1CS0                           00000006
TMR1CS1                           00000007
TMR1GE                            00000007
TMR1GIE                           00000007
TMR1GIF                           00000007
TMR1H                             00000017
TMR1IE                            00000000
TMR1IF                            00000000
TMR1L                             00000016
TMR1ON                            00000000
TMR2                              0000001A
TMR2IE                            00000001
TMR2IF                            00000001
TMR2ON                            00000002
TMdspl                            00000161
TMdspr                            0000015B
TOSH                              00000FEF
TOSL                              00000FEE
TRISA                             0000008C
TRISA0                            00000000
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 50


SYMBOL TABLE
  LABEL                             VALUE 

TRISA1                            00000001
TRISA2                            00000002
TRISA3                            00000003
TRISA4                            00000004
TRISA5                            00000005
TRISI2C                           0000008C
TRISdht                           0000008C
TRMT                              00000001
TSEN                              00000005
TSRNG                             00000004
TUN0                              00000000
TUN1                              00000001
TUN2                              00000002
TUN3                              00000003
TUN4                              00000004
TUN5                              00000005
TX9                               00000006
TX9D                              00000000
TXCKSEL                           00000002
TXEN                              00000005
TXIE                              00000004
TXIF                              00000004
TXREG                             0000019A
TXSTA                             0000019E
UA                                00000001
W                                 00000000
WCOL                              00000007
WDTCON                            00000097
WDTPS0                            00000001
WDTPS1                            00000002
WDTPS2                            00000003
WDTPS3                            00000004
WDTPS4                            00000005
WPUA                              0000020C
WPUA0                             00000000
WPUA1                             00000001
WPUA2                             00000002
WPUA3                             00000003
WPUA4                             00000004
WPUA5                             00000005
WR                                00000001
WREG                              00000009
WREG_SHAD                         00000FE5
WREN                              00000002
WRERR                             00000003
WUE                               00000001
Wbyte                             00000035
Z                                 00000002
Z_SHAD                            00000002
_BOREN_NSLEEP                     00003DFF
_BOREN_OFF                        000039FF
_BOREN_ON                         00003FFF
_BOREN_SBODEN                     00003BFF
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 51


SYMBOL TABLE
  LABEL                             VALUE 

_BORV_19                          00003FFF
_BORV_HI                          00003BFF
_BORV_LO                          00003FFF
_CLKOUTEN_OFF                     00003FFF
_CLKOUTEN_ON                      000037FF
_CONFIG1                          00008007
_CONFIG2                          00008008
_CPD_OFF                          00003FFF
_CPD_ON                           00003EFF
_CP_OFF                           00003FFF
_CP_ON                            00003F7F
_DEVID1                           00008006
_FCMEN_OFF                        00001FFF
_FCMEN_ON                         00003FFF
_FOSC_ECH                         00003FFF
_FOSC_ECL                         00003FFD
_FOSC_ECM                         00003FFE
_FOSC_EXTRC                       00003FFB
_FOSC_HS                          00003FFA
_FOSC_INTOSC                      00003FFC
_FOSC_LP                          00003FF8
_FOSC_XT                          00003FF9
_IDLOC0                           00008000
_IDLOC1                           00008001
_IDLOC2                           00008002
_IDLOC3                           00008003
_IESO_OFF                         00002FFF
_IESO_ON                          00003FFF
_LVP_OFF                          00001FFF
_LVP_ON                           00003FFF
_MCLRE_OFF                        00003FBF
_MCLRE_ON                         00003FFF
_PLLEN_OFF                        00003EFF
_PLLEN_ON                         00003FFF
_PWRTE_OFF                        00003FFF
_PWRTE_ON                         00003FDF
_STVREN_OFF                       00003DFF
_STVREN_ON                        00003FFF
_WDTE_NSLEEP                      00003FF7
_WDTE_OFF                         00003FE7
_WDTE_ON                          00003FFF
_WDTE_SWDTEN                      00003FEF
_WRT_ALL                          00003FFC
_WRT_BOOT                         00003FFE
_WRT_HALF                         00003FFD
_WRT_OFF                          00003FFF
__12F1822                         00000001
binH                              0000003A
binL                              0000003B
chkSum                            0000003C
dayMax                            00000031
dayMin                            00000001
dowMax                            00000007
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 52


SYMBOL TABLE
  LABEL                             VALUE 

dowMin                            00000001
hrMax                             00000023
hrMin                             00000000
lClr                              00000270
lSetChr                           0000025F
lSetChs                           00000264
lSetCsr                           0000024D
lSetCss                           00000254
lSndALr                           00000246
lSndAr                            00000241
lcdAr                             0000004F
lcdAw                             0000004E
minMax                            00000059
minMin                            00000000
monMax                            00000012
monMin                            00000001
rhH                               00000038
rhL                               00000039
rtcAr                             000000D1
rtcAw                             000000D0
secMax                            00000059
secMin                            00000000
swMode                            00000003
swSet                             00000005
swTime                            00000004
tcH                               0000003A
tcL                               0000003B
yrMax                             00000099
yrMin                             00000000


MEMORY USAGE MAP ('X' = Used,  '-' = Unused)

0000 : X---XXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
0040 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
0080 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
00C0 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
0100 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
0140 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
0180 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
01C0 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
0200 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
0240 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
0280 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
02C0 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
0300 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
MPASM  5.49    U210103-RTC-DHT11-LCD-V00S.ASM   1-4-2021  10:52:02         PAGE 53


MEMORY USAGE MAP ('X' = Used,  '-' = Unused)


0340 : XXXXXXXXXXXXXXXX XXXXXXXXX------- ---------------- ----------------
8000 : -------XX------- ---------------- ---------------- ----------------

All other memory blocks unused.

Program Memory Words Used:   856
Program Memory Words Free:  1192


Errors   :     0
Warnings :     0 reported,     0 suppressed
Messages :    19 reported,     0 suppressed

 以上、ごく簡単な初荷でした。小サイズのPICが好きな方にもしお役に立てれば幸いです。

 

©2021 Akira Tominaga, All rights reserved.

 

LCDキャラクターディスプレイを8ピンPICに接続する(コスパ最高?)

f:id:a-tomi:20201222124527j:plain

LCDキャラクター・ディスプレイは余り使われなくなってきたかもしれませんが、廉価で、OLEDと比較にならないほど容量を食わず、今でも電子工作に重宝なデバイスだと思いますがどうでしょう?

多くのマイコンでは標準ライブラリーがあり、I2Cで楽に接続できるという点、それに海外ネットで廉価で出回っている点も助かります。そういうわけで、私はESPやArduinoなどではこれをしばしば使うので手持ちが沢山あります。16桁2行と20桁4行が普通で、私の持っているのは1個あたりそれぞれ200円、400円ぐらいでした。

確認のために今eBayをちらとみると次です。もっと廉価なのも多いかもしれませんし、Aliでも廉価なものが多いだろうなと思います。表示色は青に白字が多いですが、黄色や緑に黒字、あるいは緑に白字などもあります。ただしI2C接続でないものもありますから注意が必要です。

f:id:a-tomi:20201221181656j:plain

LCD自体は相当古い日立のHD44780Uドライバーで動かす、日立液晶ディスプレイのコンパチ機です。それにTIのPCF8574(I2Cパラレルポート・エキスパンダーIC)または同等ICを接続して、I2Cで簡単に動くようになっているものです。

LCD自体は今でも日立との互換LCDであるというところがすごい!どれにも基本的には日立のA00という文字セットが含まれ、多数使われている海外でも、なんとカタカナを表示するところがとてもおかしいのですが^^;

古い日立のデータシートを見ると内蔵文字の基本パターンは次です。

f:id:a-tomi:20201221182623j:plain

海外通販で購入したもので全文字を表示してみたら、次のようになっています。

f:id:a-tomi:20201222180845j:plain

全部比較すると日立のと完全に同じですね!

これを表示したときの簡単なテストの様子は次の写真です。

f:id:a-tomi:20201221205318j:plain

Arduinoでは標準的なLiquidCrystalライブラリーを、New_LiquidCrystal_I2Cライブラリーで置き換えることで最近の型も動作します。前に次の記事の最後に書き足したかと思います。。

マイコンとPCのデータ授受ーSmallbasicなら簡単 (2020.12.05 LiquidCrystal_I2Cについて補足しました) - 勝手な電子工作・・

 

ところが、このLCDのイニシャライズの中身は理不尽なほど複雑です^^;  かつデータはドライバーから4ビットパラレル接続となっているため、ライブラリーなしで直接扱うときは1文字を2回に分けて送る必要があったりします。つまりプロトコルも輪をかけて複雑に。

今回はこの廉価なLCDを小さな8ピンPICに簡単につなぐ挑戦です。いつかはPICにつなごうと思っていましたが、他のI2Cデバイスはともかくも、このLCDだけは上に書いたような理由でコードの手書きは敬遠していました。

しかし、この週末にPICでの手作りを遂にやってみました!

 

今回のPICは5~6年前に1個60円ほどで大量購入した12F1822なのですが、手元に残っているので利用。今見ると秋月では110円に値上がりしたようですね。もちろん8ビットPICならどれでもほぼ大丈夫と思います。

この小さなPICはプログラムメモリーが2Kしかなく、RAMはわずか128バイトしかありません。しかし16MHzクロックで動きPIC Assemblerで書けばかなりのことができる優れものです。周辺装置の役割として何にでも便利に使っています。ライブラリーを使わない場合は容量は十分です。

 

まずは複雑プロトコルを解析するために、使う機能だけを選んでArduinoでごく簡単なテストをします。次のスケッチです。

/**********************************************************
      Simple test-A for protocol analysis
                        Dec. 19, 2020  by Akira Tominaga
           Remarks: Use Arduino, ESP32, or ESP8266 etc.
                    Connect SCL and SDA to LCD-I2C pins.
***********************************************************/
#include "LiquidCrystal_I2C.h" // New_LiquidCrystal_I2C library
#define i2cA 0x27           // LCD's I2C address
// addr, LCD-pins, BL  addr,en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(i2cA, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

void setup() { // ***** Arduino setup *****
  delay(10);

  // case #1 lcd.begin
  lcd.begin(20, 4);
  delay(300);

  // case #2 lcd.backlight() (unneeded?)
  lcd.backlight();
  delay (200);

  // case #3 lcd.clear
  lcd.clear();              // clear LCD
  delay(100);

  // case #4 cursor  line 3 ,col 15
  lcd.setCursor(15, 3);
  delay(200);

  // case #5 cursor line 2 ,col 8
  lcd.setCursor(8, 2);
  delay(300);

  // case #6 cursor line 1 ,col 5
  lcd.setCursor(5, 1);
  delay(200);

  // case #7 cursor line 0 ,col 0
  lcd.setCursor(0, 0);
  delay(100);

  // case #8 lcd.print
  lcd.print("ABC");
  lcd.print("123");

  while (true) {}         // stop here
}

void loop() { // ***** Arduino loop *****
  // do nothing
}

 

このプロトコルを記録してロジックアナライザーで解析します。

f:id:a-tomi:20201221185302j:plain

Decode結果は次のとおりです。

Time [s]	 Decoded Protocol Result
0.00000925	Setup Write to [0x4E] + ACK
150μS	1)
0.00014925	Setup Write to [0x4E] + ACK
0.0002445	0x00 + ACK
100mS	2)
0.10040025	Setup Write to [0x4E] + ACK
0.1004955	0x34 + ACK
0.10063475	Setup Write to [0x4E] + ACK
0.10073	0x30 + ACK
5mS	3)
0.105399	Setup Write to [0x4E] + ACK
0.10549425	0x34 + ACK
0.1056335	Setup Write to [0x4E] + ACK
0.10572875	0x30 + ACK
250μS	4)
0.106023	Setup Write to [0x4E] + ACK
0.106118	0x34 + ACK
0.10625725	Setup Write to [0x4E] + ACK
0.1063525	0x30 + ACK
250μS	5)
0.1066465	Setup Write to [0x4E] + ACK
0.10674175	0x24 + ACK
0.10688075	Setup Write to [0x4E] + ACK
0.106976	0x20 + ACK
250μS	6)
0.10727025	Setup Write to [0x4E] + ACK
0.1073655	0x24 + ACK
0.1075045	Setup Write to [0x4E] + ACK
0.10759975	0x20 + ACK
0.10774875	Setup Write to [0x4E] + ACK
0.107844	0x84 + ACK
0.10798325	Setup Write to [0x4E] + ACK
0.10807825	0x80 + ACK
200μS	7)
0.1082825	Setup Write to [0x4E] + ACK
0.10837775	0x04 + ACK
0.10851675	Setup Write to [0x4E] + ACK
0.108612	0x00 + ACK
0.10875625	Setup Write to [0x4E] + ACK
0.10885125	0xC4 + ACK
0.1089905	Setup Write to [0x4E] + ACK
0.10908575	0xC0 + ACK
150μS	8)
0.10922975	Setup Write to [0x4E] + ACK
0.109325	0x04 + ACK
0.10946425	Setup Write to [0x4E] + ACK
0.1095595	0x00 + ACK
0.1097035	Setup Write to [0x4E] + ACK
0.10979875	0x14 + ACK
0.109938	Setup Write to [0x4E] + ACK
0.11003325	0x10 + ACK
2mS	9)
0.11219225	Setup Write to [0x4E] + ACK
0.1122875	0x04 + ACK
0.11242675	Setup Write to [0x4E] + ACK
0.11252175	0x00 + ACK
0.112666	Setup Write to [0x4E] + ACK
0.11276125	0x64 + ACK
0.11290525	Setup Write to [0x4E] + ACK
0.1130005	0x60 + ACK
150μS	10)
0.11313975	Setup Write to [0x4E] + ACK
0.113235	0x08 + ACK
300mS	lcd Backlight
0.4133845	Setup Write to [0x4E] + ACK
0.41347975	0x08 + ACK
200mS	lcd Clear
0.6136425	Setup Write to [0x4E] + ACK
0.61373775	0x0C + ACK
0.613877	Setup Write to [0x4E] + ACK
0.61397225	0x08 + ACK
0.61411625	Setup Write to [0x4E] + ACK
0.6142115	0x1C + ACK
0.61435075	Setup Write to [0x4E] + ACK
0.614446	0x18 + ACK
	Set cursor 15,3
0.716622	Setup Write to [0x4E] + ACK
0.71671725	0xEC + ACK
0.7168565	Setup Write to [0x4E] + ACK
0.71695175	0xE8 + ACK
0.717096	Setup Write to [0x4E] + ACK
0.71719125	0x3C + ACK
0.7173305	Setup Write to [0x4E] + ACK
0.7174255	0x38 + ACK
	Set cursor 8,2
0.9175885	Setup Write to [0x4E] + ACK
0.91768375	0x9C + ACK
0.917823	Setup Write to [0x4E] + ACK
0.91791825	0x98 + ACK
0.91806225	Setup Write to [0x4E] + ACK
0.9181575	0xCC + ACK
0.91829675	Setup Write to [0x4E] + ACK
0.918392	0xC8 + ACK
	Set cursor 5,1
1.2185565	Setup Write to [0x4E] + ACK
1.21865175	0xCC + ACK
1.218791	Setup Write to [0x4E] + ACK
1.21888625	0xC8 + ACK
1.2190305	Setup Write to [0x4E] + ACK
1.21912575	0x5C + ACK
1.21926475	Setup Write to [0x4E] + ACK
1.21936		0x58 + ACK
	Set cursor 0,0
1.419528	Setup Write to [0x4E] + ACK
1.419623	0x8C + ACK
1.41976225	Setup Write to [0x4E] + ACK
1.4198575	0x88 + ACK
1.42000175	Setup Write to [0x4E] + ACK
1.420097	0x0C + ACK
1.42023625	Setup Write to [0x4E] + ACK
1.4203315	0x08 + ACK
	write "ABC123"
1.5204875	Setup Write to [0x4E] + ACK
1.52058275	0x4D + ACK
1.520722	Setup Write to [0x4E] + ACK
1.520817	0x49 + ACK
1.52096125	Setup Write to [0x4E] + ACK
1.5210565	0x1D + ACK
1.52119575	Setup Write to [0x4E] + ACK
1.521291	0x19 + ACK
1.52144025	Setup Write to [0x4E] + ACK
1.52153525	0x4D + ACK
1.5216745	Setup Write to [0x4E] + ACK
1.52176975	0x49 + ACK
1.521919	Setup Write to [0x4E] + ACK
1.52201425	0x2D + ACK
1.5221535	Setup Write to [0x4E] + ACK
1.52224875	0x29 + ACK
1.52239775	Setup Write to [0x4E] + ACK
1.522493	0x4D + ACK
1.52263225	Setup Write to [0x4E] + ACK
1.5227275	0x49 + ACK
1.52287175	Setup Write to [0x4E] + ACK
1.522967	0x3D + ACK
1.52310625	Setup Write to [0x4E] + ACK
1.52320125	0x39 + ACK
1.5233555	Setup Write to [0x4E] + ACK
1.52345075	0x3D + ACK
1.52359		Setup Write to [0x4E] + ACK
1.52368525	0x39 + ACK
1.5238295	Setup Write to [0x4E] + ACK
1.5239245	0x1D + ACK
1.52406375	Setup Write to [0x4E] + ACK
1.524159	0x19 + ACK
1.52430825	Setup Write to [0x4E] + ACK
1.52440325	0x3D + ACK
1.5245425	Setup Write to [0x4E] + ACK
1.52463775	0x39 + ACK
1.524782	Setup Write to [0x4E] + ACK
1.52487725	0x2D + ACK
1.52502125	Setup Write to [0x4E] + ACK
1.5251165	0x29 + ACK
1.52526575	Setup Write to [0x4E] + ACK
1.525361	0x3D + ACK
1.52550025	Setup Write to [0x4E] + ACK
1.52559525	0x39 + ACK
1.5257395	Setup Write to [0x4E] + ACK
1.52583475	0x3D + ACK
1.525974	Setup Write to [0x4E] + ACK
1.52606925	0x39 + ACK

 

Arduinoではこのスレーブ・アドレスは0x27ですが、通信では左に1ビットずらしてWriteの場合はビット0をオフにするので、送出アドレスは0x4Eとなります。

Initialize以外は比較的簡単にわかるプロトコルですが、lcd.setCursor(column,row)のプロトコル解析は、まるでクイズのようで少し手こずってしまいました。結局は連立方程式などを作って解き、やっとわかりました(汗)。

使おうとしているプロトコルを「まとめると、次の手順になっています。

f:id:a-tomi:20210318135940j:plain

つまり、細かい検討をしなくともこの通りに作れば必ず動く!というわけです。

今回、PICは次のように配線することにします。毎度手書きのきたない回路図ですみませんが。今回はピンが限られたハードウェアI2C機構を用いず、RA3以外ならどのピンを使ってもOKとなるようにしました。

f:id:a-tomi:20201221185551j:plain

図に書いたLEDは今は必要がないので特につけていません。I2Cの汎用接続が他に使える利点に加えて、3つのピンが空いており、他のセンサー等を色々つけられます^^

マイコンの容量を消耗しないよう、こういうものはアセンブラーでうまく組みます。

;U201219-I2CLCD-V00.asm			     		As of Dec. 19, 2020
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;										;
; 	Teting I2C-Liquid-Crystal-Display with PIC-12F1822 V00-00 		;
;	        (c)2020 Akira Tominaga, All rights reserved.			;
;	  Major revisions							;
;		00-00	Initial Version Dec.19, 2020				;
;										;
;	  Function								;
;		1.Show characters to LCD (New_LiquidCrystal_I2C 4bit op.)	;
;										;
;	  Input/output       							;
;		RA0 LED output when debugging					;
;		RA1 SCL for I2C  output						;
;		RA2 SDA for I2C  output  usually, and input occasionally	;
;										;
;	  Remarks								;
;		1. Clock = HFINTOSC (	16MHz)					;
;			Hence 1 step = 0.25 micro seconds			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
	list		p=12F1822      ; list directive to define processor
	#include	"p12F1822.inc" ; Device specific variable definitions
    __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
    __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_LO & _LVP_OFF
;	page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Macro definitions					;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Device dependent Macros			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;*** Setting up PIC device ***
DEVset	macro	
	BANKSEL	OSCCON		; Bank=1
	movlw	B'01111010'	; 16MHz and internal oscillator
	movwf	OSCCON
;
;	BANKSEL	INTCON		; Interrupt Con (in all banks hence comment)
	clrf	INTCON		; Disable all interrupts
;
; PORTA initialization
	BANKSEL	PORTA		; Bank=0
	clrf	PORTA
;	BANKSEL	LATA		; Bank=2
;	clrf	LATA
	BANKSEL	ANSELA		; Bank=3
	clrf	ANSELA		; No use of ADC
	BANKSEL	ADCON0		; Bank=1
	clrf	ADCON0		; No use of ADC
;
	BANKSEL	TRISA		; Bank=1
	movlw	B'11111000'	; RA0,1 and 2 are output
	movwf	TRISA
;
	BANKSEL	OPTION_REG	; Bank=1
	bcf	OPTION_REG,7	; Enable weak pull-up
	BANKSEL	WPUA		; Bank=4
	movlw	B'00111000'	; Weak Pull-up for RA3,4,and 5
	movwf	WPUA		;  
;
	clrf	BSR		; Bank=0
	InitP			; Initialize ports
	endm
;
; *** Initializing IO ports ***
InitP	macro			; Initialize ports
	movlw	B'11111110'	; All IOs on, excluding RA0
	movwf	PORTA
	endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	I2C Macros for genral purpose		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;		
; *** for I2C-Master protocol ***
; Sending data to I2C slave
I2Csnd	macro	slave,dataa,datalen
	movlw	slave
	movwf	I2Cadr
	movlw	dataa
	movwf	FSR0L
	movlw	datalen
	movwf	DataLen
	call	I2Csndr
	endm	
;
; *** Receiving data from I2C slave ***
I2Crcv	macro	slave,dataa,datalen
	movlw	slave
	movwf	I2Cadr
	movlw	dataa
	movwf	FSR0L
	movlw	datalen
	movwf	DataLen
	call	I2Crcvr
	endm	
;
; *** I2C start signal ***
I2Cstat macro
	call	I2Cstar
	endm
;
; *** I2C stop signal ***
I2Cstop	macro
	call	I2Cstpr
	endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	I2C Macros for New_LiquidCrystal_I2C	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ***** for New LiquidCrystal-I2C *****
; *** Start I2C, send LCD adr, and get Ack, without stoP ***
LCDsA	macro
	call	lSndAr		; I2C start and send it
	endm
;
;*** Start, I2C,send LCD adr, and send Literal and stoP ***
LCDl	macro	lcdLit
	movlw	lcdLit
	call	lSndALr
	endm
;
; *** Set cursor (Col, Row) ***
LCDsetC	macro	Col,Row
 	if	Row==0
	movlw	H'80'+Col
 	endif
 	if 	Row==1
	movlw	H'C0'+Col
 	endif
 	if 	Row==2
	movlw	H'94'+Col
 	endif
 	if 	Row==3
	movlw	H'D4'+Col
	endif
 	if 	Row>3
	* row error *
	endif
	call	lSetCsr
	endm
;
; *** lcd.write a char ***
LCDw	macro	lcdChr
	movlw	lcdChr
	call	lSetChr
	endm
;
; *** lcd.clear() ***
LCDclr 	macro
	call	lClr
	endm
;	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Time cosuming macros		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic	macro			;Consume 1 μS only
	goto	$+1
	goto	$+1
	endm
;
Mic2	macro	mic2p		;Consume 2 μS x n
	movlw	mic2p
	call	Mic2r
	endm
;
Mic2p5	macro 	mic25p		; Consume 2.5μS x n
	movlw	mic25p
	call	Mic25r
	endm
;
Mic5	macro	mic5p		; Consume 5μS x n
	movlw	mic5p
	call	Mic25r
	movlw	mic5p
	call	Mic25r
	endm
;
Mic50	macro	mic50p		; Consume 50μS x n
	movlw	mic50p
	call	Mic50r
	endm
;
Milli	macro	millip		; Consume mS x n
	movlw	millip
	call 	Millir
	endm
;
Mil100	macro	mil100p		; Consume 100 mS x n
	movlw	mil100p
	call 	Mil100r
	endm
; 
Secs	macro	secsp		; Consume Second x n
	movlw	secsp
	call	Secsr
	endm
;
Mins	macro	minsp		; Consume Minute x n
	movlw	minsp
	call	Minsr
	endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Debug and Abend macros		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LEDon	macro			; LED on macro for debugging
	BANKSEL	TRISdbg		; Select TRIS bank
	btfsc	TRISdbg,LED	; Is LED pin input?
	bsf	Flags,LEDpin	; Yes,show LED pin was input
	bcf	TRISdbg,LED	; Set LED output mode, in any case
	clrf	BSR		; Point Bank 0
	nop			; Timing for PORTdbg changed
	bsf	PORTdbg,LED	; LED on
	goto	$+1		; Timing for PORTdbg changed
	endm
;
LEDoff	macro			; LED off macro for debugging
	goto	$+1		; Timing in case PORTdbg changed
	bcf	PORTdbg,LED	; LED off
	btfss	Flags,LEDpin	; Was LEDpin input before debug?
	goto	$+7		; No, skip the followings
	BANKSEL	TRISdbg		; Select TRIS register
	bsf	TRISdbg,LED	; Set LED input mode again
	nop			; nop for timing
	BANKSEL	WPUdbg		; Bank for WPUx
	bsf	WPUdbg,LED	; Weak Pull-up for LED port
	clrf	BSR		; Point Bank 0
	nop			; Timing for PORTdbg changed
	endm 
;
Udebug	macro 	Addr
	movf	Addr,W
	call	Udbgr
	endm
;
Trigon	macro			; DSO trigger on for debugging
	BANKSEL	TRISdbg		; Select TRIS bank
	btfsc	TRISdbg,Trig	; Is Trig pin input?
	bsf	Flags,Trigpin	; Yes, show Trig pin was input
	bcf	TRISdbg,Trig	; Set Trig output mode, in any case
	clrf	BSR		; Point Bank 0
	nop			; Timing for PORTdbg changed
	bsf	PORTdbg,LED	; Trig on
	goto	$+1		; Timing for PORTdbg changed
	endm
;
Trigoff macro			; DSO trigger off for debugging
	goto	$+1		; Timing in case PORTdbg changed
	bcf	PORTdbg,Trig	; Trig off
	btfss	Flags,Trigpin	; Was Trigpin input before debug?
	goto	$+7		; No, skip the followings
	BANKSEL	TRISdbg		; Select TRIS register
	bsf	TRISdbg,Trig	; Set Trig input mode again
	nop			; nop for timing
	BANKSEL	WPUdbg		; Bank for WPUx
	bsf	WPUdbg,Trig	; Weak Pull-up for Trig port
	clrf	BSR		; Point Bank 0
	nop			; Timing for PORTdbg changed
	endm
;
Uabend	macro	abn		; User Abnormal-end number
	movlw	abn
	goto	Uabendr
	endm
;
Ublink	macro	bno		; Blink LED for specified times
	movlw	bno
	call	Ublinkr
	endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Files and Equations					;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Files				;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	cblock	H'20'
; For Application support
	Abyte		; LCD I2C addr with R/W bit
	Dbyte		; Data byte to save Sbyte
	Ebyte		; The same purpose as Dbyte
	Wbyte		; Working byte
;
; For I2C protocols
	I2Cadr		; Destinated slave I2C address
	DataLen		; Number of bytes to be sent/received
	Sbyte		; One byte to be sent/received
	Bitctr		; Loop counter for bits in a byte 
;
; Areas for time consuming subroutines
; Do not change the sequences from Mic5c to Minsc
;	if co-used with calculation parameters
	Mic25c
	Mic50c
	Millic
	Mil100c
	Secsc
	Minsc
;
; Areas for debugging routines
	DmpA 		; Display byte area 
	Dmp8C 		; Bit counter for loop (Initial Dmp8V =8)
	BlinkC 		; Counter for blinking (set for Debugb or Abendb)
	Abendn		; Abend number
	Ucpc		; User Check point chr to trace 
	Flags
	endc		
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Equations			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	For PORTA		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;LED	equ	0		; PORTdbg LED  for debugging
;Trig	equ	0		; PORTdbg Trig for debugging
;Dl	equ	2		; PORTI2C SDA
;Cl	equ	1		; PORTI2C SCL
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ***	Logical PORTI2C		; Change this when port changed
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PORTI2C equ	PORTA		; 
Dl	equ	2		; I2C Data line = SDA
Cl	equ	1		; I2C Clock line = SCL
LATI2C	equ	LATA		; LATch for I2C port
TRISI2C equ	TRISA		; TRIS reg for I2C
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ***	Logical PORTdbg		; Change this when port changed
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PORTdbg	equ	PORTA
TRISdbg	equ	TRISA
WPUdbg	equ	WPUA
LED	equ	0		; LED when debugging
Trig	equ	0		; Trigger for DSO when debugging
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Values & Symbols	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Equations for LCD 
LCDi2cA	equ	H'27'		; LCD I2C address (for Arduino)
lcdAw	equ	LCDi2cA*2	; LCD I2C address<<1 and Write
lcdAr	equ	LCDi2cA*2+H'01' ; LCD I2C address<<1 and Read
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	For Debug		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PORTdbg	equ	PORTA		;
Trig	equ	0		; DSO trigger pulse port for test use
;
Dmp8V	equ	D'8'		; Debug display bit counter initial value
Debugb	equ	D'8'		; number of blinkings to show Debugging
Abendb	equ	D'25'		; number of blinkings to notify Abend
; Flags byte
LEDsv	equ	0		; LED save bit in Flags byte
LEDpin	equ	1		; LED pin was input when not debugging
Trigpin	equ	2		; Trigger pin was input before debug use
;
	page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Initializing						;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	org	0
	goto	Startp		; Go to start entry
	org	4		; This is Interrupt entry
	retfie			; 
;
Startp	DEVset			; Define ports
	clrf	FSR0H		; Clear FSR0H forever
	clrf	FSR1H		; Clear FSR1H forever
	clrf	Flags		; Clear all bits of Flags
;
	Milli	D'50'		; Wait devices stabilized
	call	LCDinir	 	; Set-up LCD
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Main program loop					;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mainp	equ	$
	LCDsetC	2,0
	LCDw	A'M'
	LCDw	A'e'
	LCDw	A'r'
	LCDw	A'r'
	LCDw	A'y'
	LCDw	A' '
	LCDw	A'C'
	LCDw	A'h'
	LCDw	A'r'
	LCDw	A'i'
	LCDw	A's'
	LCDw	A't'
	LCDw	A'm'
	LCDw	A'a'
	LCDw	A's'
;
	LCDsetC 8,1
	LCDw	A'a'
	LCDw	A'n'
	LCDw	A'd'
;
	LCDsetC 2,2
	LCDw	A'H'
	LCDw	A'a'
	LCDw	A'p'
	LCDw	A'p'
	LCDw	A'y'
	LCDw	A' '
	LCDw	A'H'
	LCDw	A'o'
	LCDw	A'l'
	LCDw	A'i'
	LCDw	A'd'
	LCDw	A'a'
	LCDw	A'y'
	LCDw	A's'
	LCDw	A'!'
;
	LCDsetC 9,3
	LCDw	A'('
	LCDw	A'8'
	LCDw	A'_'
	LCDw	A'p'
	LCDw	A'i'
	LCDw	A'n'
	LCDw	A'_'
	LCDw	A'P'
	LCDw	A'I'
	LCDw	A'C'
	LCDw	A')'
;	
	Secs	1		; delay
	goto	Mainp		; Continue infinite loop
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	LCDini= LCD initializing routine			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LCDinir	equ	$
	LCDsA			; Send LCD addr
	I2Cstop
;
	LCDl	H'00'		; Start,send adr & 0x00, and Stop
	Mil100	1
;
	LCDl	H'34'
	LCDl	H'30'
	Milli	5
;
	LCDl	H'34'
	LCDl	H'30'
	Mic50	4
;
	LCDl	H'34'
	LCDl	H'30'
	Mic50	4
;
	LCDl	H'24'
	LCDl	H'20'
	Mic50	4
;
	LCDl	H'24'
	LCDl	H'20'
	LCDl	H'84'
	LCDl	H'80'
	Mic50	4
;
	LCDl	H'04'
	LCDl	H'00'
	LCDl	H'C4'
	LCDl	H'C0'
	Mic50	3
;
	LCDl	H'04'
	LCDl	H'00'
	LCDl	H'14'
	LCDl	H'10'
	Milli	2
;
	LCDl	H'04'
	LCDl	H'00'
	LCDl	H'64'
	LCDl	H'60'
	Mic50	3
;
	LCDl	H'08'		; backlight on
	Milli	1
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	LCD slave-adr sending routine			;
;	   	with address in Sbyte, getting Ack.	;
;		(start-I2C included, without stop-I2C)	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lSndAr	equ	$
	I2Cstat			; start I2C
	movlw	lcdAw		; get LCD slave adr
	movwf	Sbyte		; set it to Sbyte
	call	Sendr		; and send it
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	LCD I2C adr and a Literal sending routine	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lSndALr	movwf	Dbyte		; save literal to Dbyte
	call	lSndAr		; send adr
	movf	Dbyte,W		; get saved literal
	movwf	Sbyte
	call	Sendr		; send it
	I2Cstop			; stop I2C
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Set-cursor routine for LCD called by lcdSetC	;			;
;	If W=0xab, send 0xaC, 0xa8, 0xbC, and 0xb8	;			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lSetCsr	movwf	Ebyte		; save Value into Ebyte
	call	lSetCss 	; send left nibble
	swapf	Ebyte,W		; set W w/ swapping nibbles 	
	call 	lSetCss		; send right nibble
;
	Mic50	1
	return
;
; 	lSetCss subroutine to send a nibble
lSetCss movwf	Wbyte
	movlw	H'0F'
	iorwf	Wbyte,F		; set xF
	movlw	H'FC'
	andwf	Wbyte,W		; change it to xC
	movwf	Wbyte		; set it to Wbyte, too
	call 	lSndALr		; send S, adr, nibble+C, and P
;
	movlw	B'11111011'	; get complement of 0C-08
	andwf	Wbyte,W		; and change C to 8, ie x8
	call	lSndALr		; send S, adr, nibble+8, and P
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	LCD send-char routine			;
;	If W=0xab, send 0xaD, 0xa9, 0xbD, and 0xb9	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lSetChr movwf	Ebyte		; save Value into Ebyte
;	sending left nibble
	call	lSetChs
;
;	sending right nibble
	swapf	Ebyte,W		; replace left nibble w/ right
	call	lSetChs
	return
;
; 	LCD subroutine to send a character  ;
lSetChs	movwf	Wbyte		; W to Wbyte
	movlw	H'0F'		; set right nibble bits of 
	iorwf	Wbyte,F		;   Wbyte on
	movlw	H'FD'		; leave left nibble + right D
	andwf	Wbyte,W		;  into W
	movwf	Wbyte		; save it into Wbyte
	call 	lSndALr		; send S, adr, nibble+D, and P
;
	movf	Wbyte,W
	movlw	B'11111011'	; target bit 2 to off (D to 9)
	andwf	Wbyte,W		; make left nibble + right 9
	call	lSndALr		; send S, adr, nibble+9, and P	
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	LCD.clear routine				;
;	Send 0x8C, 0x88, 0x0C, and 0x08			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lClr	equ	$
	LCDw	H'8C'
	LCDw	H'88'
	LCDw	H'0C'
	LCDw	H'08'
	Mic50	1
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	I2C Send byte-string for general purpose	;
;         when calling,					;
;		I2C device adr to be set in I2Cadr byte	;
;		Data length in DataLen			;
;		Data Addr in FSR0L (INDF0)		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I2Csndr	movf	I2Cadr,W
	movwf	Sbyte
	bcf	Sbyte,0		; indicate write
;
	I2Cstat			; Start I2C
	call	Sendr

Sdata	movf	INDF0,W		; Get a sending character
	movwf	Sbyte		; Set it to Sbyte
	call	Sendr		; Send it to the device
;
	incf	FSR0L,F		; point next char
	decfsz	DataLen,F	; Have all chars sent ?
	goto	Sdata		; No, loop
;
; Stop signal and return
	I2Cstop
	Mic50	1
	return	
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	I2C Receive byte-string	for general purpose	;
;         when calling,					;
;		I2C device adr to be in I2Cadr byte	;
;		Data length in DataLen			;
;		Data Addr in FSR0L (INDF0)		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I2Crcvr	equ	$
	I2Cstat			; Start I2C
	movf	I2Cadr,W	; Get I2C dev addr
	movwf	Sbyte		; Set it into Sbyte
;	rlf	Sbyte,F		; Shift left (if adr for Arduino)
	bsf	Sbyte,0		; indicate read
	call	Sendr		; Send slave addr to read
;
I2Crbyt	equ	$
	BANKSEL	TRISI2C		; 
	bsf	TRISI2C,Dl	; Set Dline input mode
	clrf	BSR		; Point Bank 0
;
	movlw	8		; Bits in a reciving byte
	movwf	Bitctr		; into loop counter 
I2Crblp	Mic5	1		; Timing before raising clock
	bsf	PORTI2C,Cl	; Set clock high
	Mic2p5	1		; Timing after raising clock
;
	btfsc	PORTI2C,Dl
	goto	Rbith
;	goto	Rbitl
;
Rbitl	bcf	Sbyte,0		; Clear bit 0
	goto	Rbitnxt		; and goto next
;
Rbith	bsf	Sbyte,0		; Set bit 0
Rbitnxt	Mic2p5	1		; Timing after checking
	bcf	PORTI2C,Cl	; Set clock low
;	Mic2p5	1		; Timing after clock falling
	decfsz	Bitctr,F	; Still bits?
	goto	Rbcont		; Yes, continue
	goto	Rbend		; No, end of one byte
;
Rbcont	rlf	Sbyte,F		; Shit left
	goto	I2Crblp		; and goto loop
;
Rbend	movf	Sbyte,W		; Get received byte
	movwf	INDF0		; Set it to INDF0
	incf	FSR0L,F		; increase index
	decfsz	DataLen,F	; DataLen-1
	goto	Sackr		; Send Ack and continue
	goto	Snackr		; Send Nack and stop
;
;Set Dl output mode and send Ack to conitinue
Sackr	equ	$
	BANKSEL	LATI2C		; Data line high when output mode
	bsf	LATI2C,Dl	; Lat-Dl on
	BANKSEL	TRISI2C		; 
	bcf	TRISI2C,Dl	; Set Dl output mode
	clrf	BSR		; Point Bank 0
;
	bcf	PORTI2C,Dl	; Send Ack
	Mic2p5	1		; Timing after clock falling
	bsf	PORTI2C,Cl	; Show Ack
	Mic2p5	2
	bcf	PORTI2C,Cl	; Set clock low
	Mic2p5	1
	bsf	PORTI2C,Dl	; Return Dline to high
	goto	I2Crbyt		; Next byte process
;
;Set Dl output mode and send Nack
Snackr	equ	$
	BANKSEL	LATI2C		; Data line high when output mode
	bsf	LATI2C,Dl	; Lat-Dl on
	BANKSEL	TRISI2C		; 
	bcf	TRISI2C,Dl	; Set Dl output mode
	clrf	BSR		; Point Bank 0
;
	bsf	PORTI2C,Dl	; Send Nack
	Mic2p5	1		; Timing after clock falling
	bsf	PORTI2C,Cl	; Show Nack
	Mic2p5	2
	bcf	PORTI2C,Cl	; Set clock low
	Mic2p5	2
	I2Cstop			; and stop I2C once
	Mic5	D'10'		; for 50 micro sec
;
	I2Cstat			; then start I2C again
	movf	I2Cadr,W	; Get I2C dev addr
	movwf	Sbyte		; Set it into Sbyte
	rlf	Sbyte,F		; Shift left
	bcf	Sbyte,0		; indicate write
	call	Sendr		; Send it
;
	I2Cstop
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	I2C Start signal routine 			;
;	   	when dataline mode is output		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I2Cstar	bcf	PORTI2C,Dl	; set SDA low
	Mic2p5	1
	bcf	PORTI2C,Cl	; set SCL low
	Mic2p5	3
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	I2C Stop signal routine 			;
;	   	when dataline mode is output		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I2Cstpr	bcf	PORTI2C,Cl	; set SCL low
	Mic2p5	1
	bcf	PORTI2C,Dl	; set SDA low
	Mic2p5	4
	bsf	PORTI2C,Cl	; Clock line rasing
	Mic2p5	2
	bsf	PORTI2C,Dl	; Data line rasing
	Mic2p5	1
	return	
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	I2C One-byte sending routine + getting Ack	;
;	   	with data in Sbyte			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Sendr	movlw	8		; Set bit count in a byte
	movwf	Bitctr		; into loop counter 
;
Sloop	btfsc	Sbyte,7		; Check top bit of Sbyte
	goto	Slpdh		; 
	bcf	PORTI2C,Dl	; If bit low then Data L
	goto	Slpnxt
Slpdh	bsf	PORTI2C,Dl	; If bit high then Data H
;
Slpnxt	Mic2p5	1
	bsf	PORTI2C,Cl	; Show bit
	Mic2p5	2
	bcf	PORTI2C,Cl	;
	Mic2p5	1
;
	rlf	Sbyte,F		; Shift left 
	decfsz	Bitctr,F        ; All bits done?
	goto	Sloop		; No, loop within a byte
;	
;Receive Ack 		
; set data line input mode
	BANKSEL	TRISI2C		; 
	bsf	TRISI2C,Dl	; Set Dline input mode
	clrf	BSR		; Point Bank 0
;
	Mic2p5	1		; wait for Ack timing
	bsf	PORTI2C,Cl	; Clock H for Acq confirmation
	Mic2p5	2		; 
	bcf	PORTI2C,Cl	; Cl L for Dl release by slave
	Mic2p5	2
;
; Set Data line output
	BANKSEL	LATI2C		; Data line high when output mode
	bsf	LATI2C,Dl	; Lat-Dl on
	BANKSEL	TRISI2C		; 
	bcf	TRISI2C,Dl	; Set Dl output mode
	clrf	BSR		; Point Bank 0
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Timing subrooutines for general purposes		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Make 2.0 micro S x n	(Mic2)	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic2r	movwf	Mic25c		; + Wset + call = 1 micro sec 
;
Mic2l	decfsz	Mic25c,F	; If exhausted, 1 micro S hereafter
	goto	Mic2li		; else go out (2nd time 1.75 mic sec)
	return		
;
Mic2li	goto	$+1		;            (2nd time 2.25 mic sec)
	nop			;	     (2nd time 2.5 mic sec)
	goto	Mic2l		; go back    (2nd time 3 micro sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Make 2.5 micro S x n (Mic2p5)	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic25r	movwf	Mic25c		; + Wset + call = 1 micro sec 
	nop			; 1.25 micro sec
;
Mic25l	nop			; 1.5 micro sec (2nd time 4 mic sec)
	decfsz	Mic25c,F	; If exhausted, 1 micro S hereafter
	goto	Mic25li		; else go out (2nd time 2.25 mic sec)
	return		
;
Mic25li	Mic			;	      (2nd time 3.25 mic sec)
	goto	Mic25l		; go back    (2nd time 3.75 micro sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	50 Microseconds	x n	Mic50  	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Mic50r	movwf	Mic50c	 	; set how many 50 microsec (1 micro sec to here)
	nop			; 1.25 micro sec up to here
;
Mic50l	Mic2p5	D'19'		; + 47.5 = 48.75 mic sec (2nd time 98.75 mic sec)
	nop			; + 0.25 = 49 micro sec (2nd time 99 mic sec)
; 
	decfsz	Mic50c,F	; If exhausted then 1 mic S hereafter
	goto	Mic50li		; else go out (2nd time 49.75 mic sec)
	return
;
;
Mic50li	Mic			; 	  (2nd time 50.75 mic sec)
	goto	Mic50l		; go back (2nd time 51.25 mic sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Milliseconds x n	(Milli)	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Millir	movwf	Millic 		; set how many 1 mil sec (1 mic S up to here)
	nop			; 1.25 micro sec
;
Millil	Mic50	D'19'		; + 50 mic x 19 = 951.25 mic S (2nd, 1951.25) 
	Mic2p5	D'19'		; + 47.5 mic = 998.75 micro S  (2nd, 1998.75)
	nop			; +0.25 mic = 999 micro sec    (2nd, 1999)
;
	decfsz	Millic,F	; If  exhausted then 1 micro sec hereafter
	goto	Millili		; else go out (2nd, 999.75 mic S)
	return
;
Millili	Mic			; 		(2nd time 1000.75 mic S)
	goto	Millil		; go back (2nd time 1001.25 mic S)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	100 Milliseconds x n	(Mil100);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mil100r	movwf	Mil100c		;set how many 100 ms(1 micr sec up to here)
	nop			; 1.25 micro sec
;
Milhl	Milli	D'99'		;+1ms x 99 = 99001.25 micS (2nd,199001.25mic)
	Mic50	D'19'		; + 950 mic = 99951.25 micS(2nd.199951.25mic)
	Mic2p5	D'19'		; + 47.5 mic = 99998.75micS(2nd,199998.75mic)
	nop			; + 0.25 mic = 99999 mic S (2nd,199999 micS)
;
	decfsz	Mil100c,F	; If exhausted then 1 micro sec hereafter
	goto	Milhli		; else go out (2nd time, 99999.75 mic S)
	return
;
Milhli	Mic			;  	    	(2nd time, 100000.75 mic S)
	goto	Milhl		; 		(2nd time, 100001.25 mic S)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Seconds x n	 (Secs)		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Secsr	movwf	Secsc 		; set how many sec ( 1 mic sec up to here)
	nop			; 1.25 micro sec
;
Secsl	Mil100	D'9'		; 
	Milli	D'99'		; + 999 milli sec = 999001.25 micro sec
;
	Mic50	D'19'		; + 950 mic = 999951.25 micro sec
	Mic2p5	D'19'		; + 47.5 mic = 999998.75 micro sec
	nop			; + 0.25 mic = 999999 micro sec
;
	decfsz	Secsc,F		; If exhausted then 1 micro sec hereafter
	goto	Secsli		; else, go out 
	return
;
Secsli	Mic
	goto	Secsl		; (Second time, Sec + 1.25 micro sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Minutes	x n	 (Mins)		;
;	 Overhead ignored, that is only	;
;	 751.25 Mic S even when 100 Min	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Minsr	movwf	Minsc		;set how many minutes from parameter
;
Minsl	Secs	D'60'		; 1 Seconds x 60
	decfsz	Minsc,F
	goto	Minsl
	return
;
	space
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; User debug subroutine		;
;	Show bit 7 to 0 	;
;	of specified byte	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Udbgr	clrf	BSR		; Set Bank=0
	movwf	DmpA		; move data to Dmpa
;
	btfss	PORTdbg,LED	; Check if LED=on (on=High)
	goto	UdbLoff		;  if LED=off(Low), skip saving process
	bsf	Flags,LEDsv	; Save LEDon status
	LEDoff			; and off LED
	Mil100	D'10'		; wait for a second in case LED has been on
;
UdbLoff	movlw	Dmp8V		; set counter 8
	movwf	Dmp8C		; to Dmp8C
;
Udblp	Ublink	Debugb		; Blink for Debug = 8 times
	btfsc	DmpA,7		; check top bit 7
	goto	UdbOn		; if on then to UdbOn
	goto	UdbOff		; if off then to UdbOff
;
UdbOn	LEDon
	Mil100	D'30'		;
	goto	Udbeck
;
UdbOff	LEDoff
	Mil100	D'30'		;	
;	goto	Udbeck
;
Udbeck	decfsz	Dmp8C,F
	goto	Udbnext
	goto	Udbend
;
Udbnext	rlf	DmpA,F
	goto	Udblp
;
Udbend	Ublink	Debugb		; end blinking and 
	Mil100	D'100'		; blank for 10 seconds to write down
;
	btfss	Flags,LEDsv	; Check if LED was on
	goto	Udbret		;  no, goto return
	LEDon			;  if it was on, then on again
	bcf	Flags,LEDsv	; Clear LED save flag
;
Udbret	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Blinking to show debug or abend	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Ublinkr	movwf	BlinkC
Ublinkl	LEDon			; LED on
	Milli	D'30'		; for 30ms
	LEDoff			; LED off
	Milli	D'200'		; for 200ms
;
	decfsz	BlinkC,F
	goto	Ublinkl
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Abend routine			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Uabendr	clrf	BSR
	movwf	Abendn			; Set Uabend number
;
	Ublink	Abendb			; Blink 25 times
	Udebug	Abendn			; Show Abend number
	goto	$
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	End of program						;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	end

 上のコーディングでは他のI2Cセンサーがつけられるよう汎用I2C対応ができるようにしています(ただしRead String部分は未テスト。とはいえ、1バイトずつ読めばなくてもよいですし)。このLCDではもちろんReadは要りませんが。

ディスプレイが使えることで要らなくなったデバッグ用のコーディング部分(最後のほう)もそのまま含めています。ここはすっぽり外して問題ないもの。

全体594命令から不要なデバッグ用コードをはずせば、僅か350命令です。プログラム容量(2048ワード)の17%に収まります。また、RAMメモリーは128バイトのうち、デバッグ用も含めて20バイトしか使っていませんので、RAM容量も16%未満に収めることができました。

 

これで、今後小型PICからも楽に使えることになったので、今回週末を使った甲斐がありました\(^o^)/。

 センサー装置の基盤としてはコスパ最高かも。なにせ1602LCDの場合なら300円ほどでできる環境ですから。

 

この記事がもしどなたかのお役に立つようであれば幸いです。

 

 

©2020 Akira Tominaga, All rights reserved.