« ATtiny402マイコン サンプル:I2Cで液晶表示 | トップページ | ATtiny402サンプル:I2Cで液晶表示 SCL周波数を設定できるようにしたら »

2025年9月 8日 (月)

ATtiny402マイコン サンプル:I2Cで液晶表示(Wire.hを使わないで)

ATtiny402マイコン サンプル:I2Cで液晶表示 この続き。

ATtiny402での液晶表示、ちょっとでも「軽く」する
(メモリ使用量を減らす)ため、"Wire.h"を使わない
液晶表示ルーチンを仕立ててみました。

■LCD_TEST0 : "Wire.h"を使った場合

// "Wire.h"を使ってのACM0802液晶テスト
// ATtiny402 20MHz Arduino IDE環境
// PA0 6pin UPDI
// PA1 4pin - SDA I2C液晶
// PA2 5pin - SCL I2C液晶
// PA3 7pin out
// PA6 2pin out
// PA7 3pin out
// ボードマネージャー:
// http://drazzy.com/package_drazzy.com_index.json
#include "Wire.h" // I2C ACM0802液晶
#include "i2c_lcd_acm0802.h" // LCD制御ヘッダーファイル
i2c_lcd_acm0802 LCD(0x3C); // LCD I2Cアドレスを設定
/***** SETUP *****/
void setup() {
cli(); // 割込禁止
PORTA.DIR = 0b11001000; //ポート出力指定
// || |||+---- PA0 6pin UPDI
// || ||+----- PA1 4pin in SDA
// || |+------ PA2 5pin in SCL
// || +------- PA3 7pin out
// |+---------- PA6 2pin out
// +----------- PA7 3pin out
// PIT 1秒タイミング
RTC.CLKSEL = 0b00000001;
// ++---- INT1K 1024Hz
RTC.CTRLA = 0b00000001;
// ||||| +---- RTCEN RTC周辺機能許可
// |++++------- CLK_RTC DIV1 1/1
// +----------- RUNSTBY
RTC.PITCTRLA = 0b01001001;
// |||| +-- PITEN
// ++++----- PERIOD 1/1024 →1秒
// I2C液晶
Wire.begin(); // I2C開始
LCD.begin(8, 2); // 液晶初期化 8文字x2行
}
/***** LOOP ******/
void loop() {
byte c = '0';
LCD.setCursor(0, 0); // LCD上段
LCD.strdisp("Test LCD"); // タイトル
while(1){
if(RTC_PITINTFLAGS & 0x01){ // 1秒経過
RTC_PITINTFLAGS = 1; // PIフラグクリア
LCD.setCursor(7, 1); // LCD右下段
LCD.write(c); // 0~9
c++;
if(c > '9') c = '0';
}
}
}

結果。
  スケッチが1523バイト(37%)
  グローバル変数が100バイト(39%)

~~~~~~~~~~~~~~~~~~~~~~~~~~
■LCD_TEST1 : "Wire.h"を使わない場合

// "Wire.h"を使わないACM0802液晶テスト
#include "i2c_lcd_acm0802_tn.h" // LCD制御ヘッダーファイル
// ★wire.hは使わない
i2c_lcd_acm0802_tn LCD(0x3C); // LCD I2Cアドレスを設定
/***** SETUP *****/
void setup() {
cli(); // 割込禁止
PORTA.DIR = 0b11001000; //ポート出力指定
// || |||+---- PA0 6pin UPDI
// || ||+----- PA1 4pin in SDA
// || |+------ PA2 5pin in SCL
// || +------- PA3 7pin out
// |+---------- PA6 2pin out
// +----------- PA7 3pin out
// PIT 1秒タイミング
RTC.CLKSEL = 0b00000001;
// ++---- INT1K 1024Hz
RTC.CTRLA = 0b00000001;
// ||||| +---- RTCEN RTC周辺機能許可
// |++++------- CLK_RTC DIV1 1/1
// +----------- RUNSTBY
RTC.PITCTRLA = 0b01001001;
// |||| +-- PITEN
// ++++----- PERIOD 1/1024 →1秒
// I2C液晶
// Wire.begin(); // I2C開始 ★wire.hは使わない
LCD.begin(8, 2); // 液晶初期化 8文字x2行
}
/***** LOOP ******/
void loop() {
byte c = 'A';
LCD.setCursor(0, 0); // LCD上段
LCD.strdisp("Test LCD"); // タイトル
while(1){
if(RTC_PITINTFLAGS & 0x01){ // PIT 1秒経過
RTC_PITINTFLAGS = 1; // PIフラグクリア
LCD.setCursor(7, 1); // LCD右下段
LCD.write(c); // A~Z
c++;
if(c > 'Z') c = 'A';
}
}
}

結果。
  スケッチが773バイト(18%)
  グローバル変数が14バイト(5%)

8文字×2行の液晶、1行目にタイトルを表示して
右下に1文字の数字(TEST0)あるいは大文字英字
(TEST1)を1秒サイクルでインクリメント。

例題の違いはWire.hを使うか使わないか。
TEST0の下請けルーチン、i2c_lcd_acm0802は
これまでどおりにWire.hとtwi.hで制御。

TEST1のi2c_lcd_acm0802_tnはtiny402の
TWIレジスタを直接操作。
手抜きで、I2Cの制御にエラーが生じても(ACKが来ない
ゾ)そこでストップさせずにそのまま最後まで進んじゃ
います。

その結果、Wire.h仕様のTEST0だと、
  スケッチが1523バイト(37%)
  グローバル変数が100バイト(39%)

それがTEST1だと
  スケッチが773バイト(18%)
  グローバル変数が14バイト(5%)
と、大幅に使用メモリが少なくなりました。
RAMの使用量を減らせたのが大きいかと。

スケッチと下請けルーチンはダウンロードで。(zip圧縮)

 ・ダウンロード - lcd_test0.zip Wire.h使用

 ・ダウンロード - lcd_test1.zip TWIレジスタ直書きで


TEST1(i2c_lcd_acm0802_tn)で使ったTWIレジスタ
のアクセス方法。

/********************************/
/* TWIモジュールのアクセス */
/********************************/
// ATtiny402のTWIハードウェアを制御
// 割り込みを使わなない
// タイムアウトチェックカウンタを設けて異常でも抜けるように
// 正しくACKが帰ってこない場合も処理を続行
/***** TWI 初期化 *****/
// TWI周波数を設定 100kHz
void twiInit(void )
{
TWI0.MBAUD = 100; // 20MHz/2/fSCL
// 100kHz→100
// 400kHz→25
TWI0.MCTRLA = 0b00000001;
// || ||||+----- ENABLE 主装置許可
// || |||+------ SMEN 簡便動作しない
// || |++------- TIMEOUT 使わない
// || +--------- QCEN 迅速指令 しない
// |+----------- WIEN 書き込み割り込み なし
// +------------ RIEN 読み込み割り込み なし
TWI0.MSTATUS = 0b00000001;
// ||||||++----- BUSSTATE アイドル状態に
// |||||+------- BUSERR
// ||||+-------- ARBLOST
// |||+--------- RXACK
// ||+---------- CLKHOLD
// |+----------- WIF
// +------------ RIF
}
/***** TWI 書込み送出開始 *****/
void twiStartW(uint8_t adrs)
{
uint16_t tt; // time out check counter
TWI0.MADDR = adrs << 1; // アドレス 書き込みで(0)
tt = 2000; // 2000 loop
while(tt){ // time out?
if(TWI0.MSTATUS & TWI_WIF_bm) break; // WIF=1を待つ
tt--;
}
}
/***** TWI データ書き込み *****/
void twiWrite(uint8_t data)
{
uint16_t tt; // time out check counter
TWI0.MDATA = data; // データ書き込み
tt = 2000; // 2000 loop
while(tt){ // time out?
if(TWI0.MSTATUS & TWI_WIF_bm) break; // WIF=1を待つ
tt--;
}
}
/***** TWI 送出終了 *****/
void twiStop(void)
{
TWI0.MCTRLB = TWI_MCMD_STOP_gc; // Stop Condition
}

 

|

« ATtiny402マイコン サンプル:I2Cで液晶表示 | トップページ | ATtiny402サンプル:I2Cで液晶表示 SCL周波数を設定できるようにしたら »

Arduino」カテゴリの記事

AVRマイコン」カテゴリの記事

ATtiny」カテゴリの記事

コメント

「if(TWI0.MSTATUS & TWI_WIF_bm) break;」としてWIFビットが「立つ」のをタイムアウトチェックしながら待ってますが、タイムアウトをチェックする必要はなさそうです。
  アドレス不一致
  ACKが返ってこない
  従装置切断
など、異常が生じても、所定の時間経過後、とりあえずTWIビットはオンしてくれます。
ということで、処理を軽く(短く)するため、このタイムアウトチェックは外して良さそうです。 

投稿: 居酒屋ガレージ店主(JH3DBO) | 2025年9月 8日 (月) 19時56分

コメントを書く



(ウェブ上には掲載しません)




« ATtiny402マイコン サンプル:I2Cで液晶表示 | トップページ | ATtiny402サンプル:I2Cで液晶表示 SCL周波数を設定できるようにしたら »