ATtiny13AでI2C接続キャラクタLCDを利用する(3)
ATtiny13A用のI2C通信部コードをAVRアセンブラの勉強がてら
アセンブラに書き直してました(まだ汚いコードですが..)
動作はこの前のC言語バージョンとほぼ同じです(たぶん)。
前回、ATtiny13Aで作成した時計のスケッチのサイズは1000バイトだったのですが、
I2C接続部をアセンブラすることで884バイト(116バイトのダイエット)になりました。
初めてのAVRアセンブラですが、奇跡的にそれなりに動いているようです。
これなら、時計の時刻設定機能も追加できるかも。取りあえずソースを公開します。
ダウンロード tinyI2C.zip (2.6K)
(関数名は C言語バージョンの各関数名の頭にtinyをつけています)
解凍後、スケッチ保存用のディレクトリの\librariesに入れて利用できます。
アセンブラの学習で参考にしたサイト
・えるむ by ChaN - アセンブラ関数の書き方(avr-gcc)
・AVR Wiki - avrgccでアセンブラを使う
・弘前大学教育学部 AVRマイコンで学ぶ コンピュータの仕組み
・AVR.jp tiny13Aのデータシート、AVR命令セット、AVRGCCでのアセンブリとCの混合など
(直リンク禁止のためトップページのみリンクを貼ります)
アセンブラの開発環境はarduino IDEを使っています。
ライブラリ登録した(libraries)ソースはアセンブラ(拡張子.S)もコンパイルしてくれるので
テキストエディタでコードを作成すればOKなわけです。
ヘッダーファイル
#ifndef _TINYI2C_H_ #define _TINYI2C_H_ #include <avr/io.h> #define T100_US ((F_CPU/1000000)*100/10) #define T200_US ((F_CPU/1000000)*200/10) #define T1_MS ((F_CPU/1000000)*1000/10) #define T5_MS ((F_CPU/1000000)*5000/10) #define T10_MS ((F_CPU/1000000)*10000/10) #define T15_MS ((F_CPU/1000000)*15000/10) #define T20_MS ((F_CPU/1000000)*20000/10) extern "C" { int16_t sum(int16_t, int16_t); void delay_10cyc(uint16_t); void blink(unsigned char); void tinyI2C_DATA_HI(void); void tinyI2C_DATA_LO(void); void tinyI2C_CLOCK_HI(void); void tinyI2C_CLOCK_LO(void); void tinyI2C_WriteBit(unsigned char); void tinyI2C_Stop(void); void tinyI2C_Start(void); void tinyI2C_Init(void); void tinyI2C_Write(unsigned char c); unsigned char tinyI2C_ReadBit(void); unsigned char tinyI2C_Read(unsigned char ack); } #define delay_100us() delay_10cyc(T100_US) #define delay_200us() delay_10cyc(T200_US) #define delay_1ms() delay_10cyc(T1_MS) #define delay_5ms() delay_10cyc(T5_MS) #define delay_10ms() delay_10cyc(T10_MS) #define delay_15ms() delay_10cyc(T15_MS) #define delay_20ms() delay_10cyc(T20_MS) #endif
ライブラリソース
#include <avr/io.h> ;delay用設定 #if F_CPU == 9600000UL #define T100_US 96 #define T200_US 192 #elif F_CPU == 8000000UL #define T100_US 80 #define T200_US 160 #elif F_CPU ==16000000UL #define T100_US 160 #define T200_US 320 #endif ;-------------------------------------------------------; ;アセンブラ関数 void delay_10cyc(uint16_t t) ; 10サイクル x tの時間待ちを行う ; 引数 t(r25:r24) ; 本関数はr24,r25の変更を行う ; 0でも10サイクル時間待ち ; 実際の呼び出しでは rcall+ret-1 =5サイクル加算される ; 呼び出し側で引数で1引くこと ;--------------------------------------------------------; .global delay_10cyc .func delay_10cyc counter = 24 delay_10cyc: loop: ; 10サイクルのループ nop nop nop nop nop nop sbiw counter,1 ; 1づつ減算 brne loop ; 0でループ抜け ret .endfunc ;-------------------------------------------------------; ;アセンブラ関数 void _delay_100us(void) ; 100usの時間待ちを行う ; 本関数はr24,r25の変更を行う ; 呼び出し時のサイクル数の補正済み(20サイクル) ;-------------------------------------------------------; .global delay_100us .func delay_100us delay_100us: ldi r25, 0 ; delay_100us ldi r24, T100_US-2 rcall delay_10cyc ret .endfunc ;-------------------------------------------------------------------; ;I/OポートのON/OFF ;void blink(uint8_t led_val) ;Lチカ 動作確認用 ;-------------------------------------------------------------------; ; #ifdef test_port #define LED 5 #define DDR_LED (DDRB-0x20) #define PORT_LED (PORTB-0x20) led_val = 24 .global blink .func blink blink: cpi led_val,0 brne reset_hi sbi DDR_LED, LED cbi PORT_LED,LED ret reset_hi: sbi DDR_LED, LED sbi PORT_LED,LED ret .endfunc #endif ;-------------------------------------------------------------------; ; tinyI2Cライブラリ ;-------------------------------------------------------------------; ; #define I2C_DDR (DDRB-0x20) #define I2C_PIN (PINB-0x20) #define I2C_PORT (PORTB-0x20) #define I2C_CLK 3 #define I2C_DAT 4 ;-------------------------------------------------------------------; ; 関数 void I2C_DATA_HI(void) ;-------------------------------------------------------------------; ; .global tinyI2C_DATA_HI .func tinyI2C_DATA_HI tinyI2C_DATA_HI: cbi I2C_DDR ,I2C_DAT sbi I2C_PORT,I2C_DAT ret .endfunc ; ;-------------------------------------------------------------------; ; 関数 void I2C_DATA_LO(void) ;-------------------------------------------------------------------; ; .global tinyI2C_DATA_LO .func tinyI2C_DATA_LO tinyI2C_DATA_LO: sbi I2C_DDR ,I2C_DAT cbi I2C_PORT,I2C_DAT ret .endfunc ;-------------------------------------------------------------------; ; 関数 void I2C_CLOCK_HI(void) ;-------------------------------------------------------------------; ; .global tinyI2C_CLOCK_HI .func tinyI2C_CLOCK_HI tinyI2C_CLOCK_HI: cbi I2C_DDR ,I2C_CLK sbi I2C_PORT,I2C_CLK ret .endfunc ;-------------------------------------------------------------------; ; 関数 void I2C_CLOCK_LO(void) ;-------------------------------------------------------------------; ; .global tinyI2C_CLOCK_LO .func tinyI2C_CLOCK_LO tinyI2C_CLOCK_LO: sbi I2C_DDR ,I2C_CLK cbi I2C_PORT,I2C_CLK ret .endfunc ;-------------------------------------------------------------------; ; 関数 void tinyI2C_WriteBit(uint8_t c) ; 引数 r24: 書き込みデータ ; r25:r23 内容破壊される ;-------------------------------------------------------------------; .global tinyI2C_WriteBit .func tinyI2C_WriteBit value_c = 24 tinyI2C_WriteBit: cpi value_c, 0 breq IC2_DATA_LO ; 0なら0出力へ IC2_DATA_HI: rcall tinyI2C_DATA_HI ; I2C_DATA_HI() rjmp STEP2 IC2_DATA_LO: rcall tinyI2C_DATA_LO ; I2C_DATA_LO() STEP2: rcall tinyI2C_CLOCK_HI L1: sbis I2C_PIN,I2C_CLK ; I2C_CLK=1待ち rjmp L1 mov r23, value_c rcall delay_100us ; delay_100us rcall tinyI2C_CLOCK_LO rcall delay_100us ; delay_100us cpi r23, 0 breq STEP3 rcall tinyI2C_DATA_LO STEP3: rcall delay_100us ; delay_100us ret .endfunc ;-------------------------------------------------------------------; ; 関数 void tinyI2C_Stop(void) ; r25:r24 内容破壊される ; ;-------------------------------------------------------------------; .global tinyI2C_Stop .func tinyI2C_Stop tinyI2C_Stop: rcall tinyI2C_CLOCK_HI rcall delay_100us ; delay_100us rcall tinyI2C_DATA_HI rcall delay_100us ; delay_100us ret .endfunc ;-------------------------------------------------------------------; ; 関数 void tinyI2C_Start(void) ; r25:r24 内容破壊される ;-------------------------------------------------------------------; .global tinyI2C_Start .func tinyI2C_Start tinyI2C_Start: in r25,I2C_DDR andi r25, ~((1 << I2C_DAT) | (1 << I2C_CLK)); out I2C_DDR,r25 rcall delay_100us ; delay_100us rcall tinyI2C_DATA_LO rcall delay_100us ; delay_100us rcall tinyI2C_CLOCK_LO ret .endfunc ;-------------------------------------------------------------------; ; 関数 void tinyI2C_Init(void) ; r25 内容破壊される ;-------------------------------------------------------------------; .global tinyI2C_Init .func tinyI2C_Init tinyI2C_Init: in r25, I2C_PORT andi r25,~((1 << I2C_DAT) | (1 << I2C_CLK)); rcall tinyI2C_CLOCK_HI rcall tinyI2C_DATA_HI ret .endfunc ;-------------------------------------------------------------------; ; 関数 void tinyI2C_Write(uint8_t data) ; 引数: r24 :data ; r25:r21 内容破壊される ;-------------------------------------------------------------------; .global tinyI2C_Write .func tinyI2C_Write data = 22 count= 21 tinyI2C_Write: mov data, r24 ldi count, 8 LOOP: ;8ビット書き込みループ lsl data ldi r24,0 rol r24 rcall tinyI2C_WriteBit dec count brne LOOP ret .endfunc ;-------------------------------------------------------------------; ; 関数 uint8_t tinyI2C_ReadBit(void) ; ; 戻り値 r24: 読み取りビット ; r25,r23:r22 内容破壊される ;-------------------------------------------------------------------; .global tinyI2C_ReadBit .func tinyI2C_ReadBit tinyI2C_ReadBit: rcall tinyI2C_DATA_HI rcall tinyI2C_CLOCK_HI LOOP1: sbis I2C_PIN,I2C_CLK ; I2C_CLKのHI待ち rjmp LOOP1 rcall delay_100us ; delay_100us in r22,I2C_PIN rcall tinyI2C_CLOCK_LO rcall delay_100us ; delay_100us bst r22,I2C_DAT ;r22のI2C_DATビットをr24の0ビットに設定 ldi r24,0 bld r24,0 ret .endfunc ;------------------------------------------------------------------; ; 関数 unsigned char tinyI2C_Read(unsigned char ack) ; ; 引数 r24: ack ; 戻り値 r24: 取得データ ; r25:r19 内容破壊される ;------------------------------------------------------------------; value_ack = 21 ;引数用 value_res = 19 ;戻り値用 count = 20 ;ループ用 .global tinyI2C_Read .func tinyI2C_Read tinyI2C_Read: mov value_ack, r24 ; ldi count,8 ldi value_res,0 LOOP4: ;8ビット分データ取得ループ rcall tinyI2C_ReadBit ;r24に読み込みビットを返す lsl value_res ;左シフト add value_res,r24 ;読んだビットを挿入 dec count brne LOOP4 STEP4: ;value_ack が1ならtinyI2C_WriteBit(0) cp value_ack,0 ; 0ならtinyI2C_WriteBit(1) breq STEP5 ldi r24,0 rjmp STEP6 STEP5: ldi r24,1 STEP6: rcall tinyI2C_WriteBit ; ackの送信 mov r24, value_res ret .endfunc ;--------------------------------------------------------------------;
« Arduino IDE 1.0.6 では行番号が表示できりようになった | トップページ | 秋月電子の「お楽しみ袋」を買ってみた »
「arduino」カテゴリの記事
- Arduino IDE+Arduino STM32環境で指定と異なるgccが使われてしまう(2025.01.23)
- Zorin OSでArduino Uno互換機(CH340)が認識しない(2025.01.19)
- Arduino IDE 2.3.4でArduino STM32を利用する(2025.01.12)
- Arduino用 SKK日本語変換ライブラリの開発 その1(2024.12.28)
- NeoPixel(WS2812B)の制御 その5(2024.09.15)
「AVR」カテゴリの記事
- NeoPixel(WS2812B)の制御 その5(2024.09.15)
- Arduino用SJIS漢字フォントライブラリ SDカード版を作成しました(2018.10.30)
- ATtiny13AでI2C接続キャラクタLCDを利用する(4)(2018.04.16)
- ATtiny13Aで赤外線リモコン受信センサーを使う(2)(2018.04.15)
- ATtiny13AでHC-SR04を使った距離計測(2018.04.14)
「ATtiny13A」カテゴリの記事
- ATtiny13AでI2C接続キャラクタLCDを利用する(4)(2018.04.16)
- ATtiny13Aで赤外線リモコン受信センサーを使う(2)(2018.04.15)
- ATtiny13AでHC-SR04を使った距離計測(2018.04.14)
- Arduino 1.8.5環境でATtiny13Aを利用する(2018.04.14)
- Arduino IDEを使ったATtiny13用スケッチの開発について(2016.08.30)
「表示器制御関連」カテゴリの記事
- NeoPixel(WS2812B)の制御 その5(2024.09.15)
- Arduino用 美咲フォントライブラリを更新しました(2024.03.21)
- Raspberry Pi Pico(MicroPython)でLEDドットマトリックスを使ってみる(2024.03.14)
- Raspberry Pi Pico MicroPython用のマルチフォントライブラリ(2023.02.09)
- MicroPython(Raspberry Pi pico)で8x8ドットNeoPixcel文字表示(2023.02.08)
« Arduino IDE 1.0.6 では行番号が表示できりようになった | トップページ | 秋月電子の「お楽しみ袋」を買ってみた »
コメント