' ' ********************************************** ' * * ' * AVR & BASCOM-AVR トレーニング・ボード * ' * 初期設定 Ver.1.01 * ' * * ' * AVR is using ATmega88P * ' * Basic Compiler is BASCOM-AVR * ' * Copyright By O-Family 2010.10.29 * ' ********************************************** ' $regfile = "m88pdef.dat" '使用するAVRを設定。 $crystal = 16000000 'AVRクロックを設定。 ' $hwstack = 64 'ハードウェア・スタックの容量を設定。 $swstack = 10 'ソフトウェア・スタックの容量を設定。 $framesize = 24 'フレーム領域の容量を設定。 ' ' * ポート名の定義 * ' Sw_1 Alias Pind.0 'スイッチ[1]の接続ポート。 Sw_2 Alias Pind.1 'スイッチ[2]の接続ポート。 Sw_3 Alias Pind.2 'スイッチ[3]の接続ポート。 Sw_4 Alias Pind.3 'スイッチ[4]の接続ポート。 ' Led_1r Alias Portd.4 'LED1[赤]の接続ポート。 Led_2g Alias Portd.5 'LED2[緑]の接続ポート。 Led_3y Alias Portd.6 'LED3[黄]の接続ポート。 Led_4b Alias Portd.7 'LED4[青]の接続ポート。 Sp_out Alias Portc.5 'スピーカーの接続ポート。 ' Ad_photo Alias 0 '光センサーのA/Dコンバータ・チャネル番号。 Ad_thermo Alias 1 '温度センサーのA/Dコンバータ・チャネル番号。 Ad_ain1 Alias 2 '測定入力[1]のA/Dコンバータ・チャネル番号。 Ad_ain2 Alias 3 '測定入力[2]のA/Dコンバータ・チャネル番号。 Ad_ain3 Alias 4 '測定入力[3]のA/Dコンバータ・チャネル番号。 Ad_spin Alias 5 'スピーカー入力のA/Dコンバータ・チャネル番号。 ' ' * ポートの初期設定 * ' Config Led_1r = Output 'LED1の接続ポートを出力に設定する。 Config Led_2g = Output 'LED2の接続ポートを出力に設定する。 Config Led_3y = Output 'LED3の接続ポートを出力に設定する。 Config Led_4b = Output 'LED4の接続ポートを出力に設定する。 Config Sp_out = Output 'スピーカーの接続ポートを出力に設定する。 ' Set Portd.0 'スイッチ[1]の接続ポートをプルアップする。 Set Portd.1 'スイッチ[2]の接続ポートをプルアップする。 Set Portd.2 'スイッチ[3]の接続ポートをプルアップする。 Set Portd.3 'スイッチ[4]の接続ポートをプルアップする。 Didr0 = &B0010_0011 'デジタル入力禁止レジスタの設定。 ' ' * LCDの初期設定 * ' Config Lcdmode = Port 'LCDを4ビットのポートモードに設定。 Config Lcdbus = 4 'LCDデータバスを4bitに設定。 Config Lcdpin = Pin , Db4 = Portb.3 , Db5 = Portb.2 'LCDのポート割り当て。 Config Lcdpin = Pin , Db6 = Portb.1 , Db7 = Portb.0 Config Lcdpin = Pin , E = Portb.4 , Rs = Portb.5 Config Lcd = 16 * 2 'LCD表示を16文字2行に設定。 Cls 'LCD表示をすべて消去。 ' ' * A/Dコンバータの初期設定 * ' Config Adc = Single , Prescaler = Auto , Reference = Avcc 'A/Dコンバータの設定。 Start Adc 'A/Dコンバータに電源を供給。 ' ' ↓********************************************↓ ' ↓ これ以降に各自のプログラムを作成して下さい ↓ ' ↓********************************************↓ ' '-------------------------------------------------------------------------------------------------- ' *********************************** ' * AVRトレーニング・ボード * ' * I2C RTC(時計)の接続 [DS3231] * ' *********************************** ' ' Ver. 1.01 新規作成バージョン。 2017. 3.30 ' Ver. 1.02 [SQW]ピン(PC4)の検出バグ修正。 2017. 4.21 ' ' ' * 変数の宣言 * ' Dim I2cbuff(20) As Byte 'I2Cの送受信バッファー。 Dim Timebuff(8) As Byte '時刻データバッファー。(秒,分,時,日,月,年,曜日,ofs) Dim Hourmode As Byte '12/24時間制表示選択。(0:12時間制 , 1:24時間制) Dim Sqw1hzflag As Byte 'DS3231の[SQW]ピンの1Hz確認フラグ。 ' Dim Temp1 As Byte '汎用テンポラリ変数 Byte型 No.1 Dim Temp2 As Byte '汎用テンポラリ変数 Byte型 No.2 Dim Tempts1 As Byte '汎用テンポラリ変数 時刻設定用 Byte型 No.1 Dim Tempts2 As Byte '汎用テンポラリ変数 時刻設定用 Byte型 No.2 Dim Tempts3 As Byte '汎用テンポラリ変数 時刻設定用 Byte型 No.3 Dim Tempts4 As Byte '汎用テンポラリ変数 時刻設定用 Byte型 No.4 Dim Tempts5 As Byte '汎用テンポラリ変数 時刻設定用 Byte型 No.5 Dim Tempts6 As Byte '汎用テンポラリ変数 時刻設定用 Byte型 No.6 ' Dim Dummy As Eram Long 'EEPROM 4バイトのダミーエリア。 Dim Eephourmode As Eram Byte 'EEPROM 12/24時間制表示選択。(0:12時間制 , 1:24時間制) Dim Eepagingoffset As Eram Byte 'EEPROM [DS3231] Aging Offset値。 ' ' * ポートの初期設定 * ' Set Portc.4 'DS3231の[SQW]ピンの接続ポートをプルアップする。 Cursor Off 'LCDのカーソルをオフにする。 ' ' * I2Cの初期設定 * ' Config Scl = Portc.3 'I2CバスのSCLラインを接続するポートピンを設定。 Config Sda = Portc.2 'I2CバスのSDAラインを接続するポートピンを設定。 I2cinit 'I2Cバスを初期化する。 ' ' * EEPROMのデータを確認する * ' If Eephourmode > 1 Then 'If EEPROMが初期値か? Then Eephourmode = 0 'EEPROM 12/24時間制表示選択。(0:12時間制 , 1:24時間制) Eepagingoffset = 0 'EEPROM [DS3231] Aging Offset 値。 End If Hourmode = Eephourmode ' ' * RTC [DS3231]の初期設定 * ' Wait 1 '[DS3231]のパワーオン時間を待つ。 I2cbuff(1) = &H0F '[0Fh] ステータス・レジスターのアドレスを指定する。 I2creceive &HD0 , I2cbuff(1) , 1 , 1 'I2Cバスで、1バイトのコマンドを送信し、1バイトのデータを受信する。 Locate 2 , 1 If Err <> 0 Then 'If [DS3231]の応答が無いか? Then Lcd "# DS3231 Error!" '[DS3231]のエラーを表示する。 Sound Sp_out , 100 , 6666 '200Hzの音を500mS鳴らす。 Stop '機能停止。 End If If I2cbuff(1).7 = 1 Then 'If [DS3231]のバッテリー切れ[OSF=1]か? Then Lcd "# Battery dead!" 'バッテリーの電圧が下がった警告を表示する。 Sound Sp_out , 100 , 6666 '200Hzの音を500mS鳴らす。 Wait 3 End If Temp2 = I2cbuff(1).7 '[DS3231]のバッテリー状態bit[OSF]を取り出す。 If Sw_3 = 0 Then 'If [DS3231]を強制的に初期化するか? Then Temp2 = 1 End If If Temp2 <> 0 Then 'If [DS3231]を初期化するか? Then Gosub Ds3231init '[DS3231]を初期化する。 Eepagingoffset = 0 'EEPROM [DS3231] Aging Offset値。 Locate 2 , 1 Lcd "# DS3231 Init! " '[DS3231]の強制的な初期化を表示する。 Sound Sp_out , 2000 , 333 '4000Hzの音を500mS鳴らす。 Wait 1 Bitwait Sw_3 , Set '[SW3]が離されるまで待つ。 Waitms 30 'チャタリングの待ち時間。 Cls 'LCD表示をすべて消去。 End If ' Sound Sp_out , 50 , 1333 '1000Hzの音を50mS鳴らす。 ' ' ******************* ' * メイン ルーチン * ' ******************* ' Main: ' ' * 時刻の表示 * ' If Sqw1hzflag = 0 Then 'If 1Hz出力の[H]チェック中か? Then If Pinc.4 = 1 Then 'If 1Hz出力が[H]か?Then Sqw1hzflag = 1 Gosub Ds3231read '[DS3231]から日時を読み出す。 Gosub Datedisp '日付をLCDに表示する。 Locate 2 , 3 Gosub Timedisp '時刻をLCDに表示する。 End If Else '1Hz出力の[L]チェック中。 If Pinc.4 = 0 Then 'If 1Hz出力が[L]か?Then Sqw1hzflag = 0 End If End If ' ' * スイッチの確認 * ' Debounce Sw_3 , 0 , Sw3on '[SW3]の検出。 Temp1 = Sw_1 Or Sw_3 If Temp1 = 0 Then Goto Sw13on 'If [SW1 + SW3] 時刻設定モードか? Then ' Goto Main '-------------------------------------------------------------------------------------------------- ' ' * [SW3]が押された場合 (12/24時間制の切り替え) * ' Sw3on: If Sw_1 = 1 Then 'If [SW1]が押されていないか? Then Toggle Hourmode.0 '12/24時間制表示を切り替える。 Eephourmode = Hourmode 'EEPROMに保存する。 End If Sw3on1: Gosub Datedisp '日付をLCDに表示する。 Locate 2 , 3 Gosub Timedisp '時刻をLCDに表示する。 Goto Main ' ' * [SW1 + SW3]が押された場合 (時刻設定モード) * ' Sw13on: Cls 'LCD表示をすべて消去。 Timebuff(8) = Eepagingoffset 'EEPROM [DS3231] Aging Offset値。 Gosub Timesetdisp '時刻設定用の日時を表示する。 Sound Sp_out , 200 , 333 '4000Hzの音を50mS鳴らす。 Waitms 30 'チャタリングの待ち時間。 Bitwait Sw_1 , Set '[SW1]が離されるまで待つ。 Bitwait Sw_3 , Set '[SW3]が離されるまで待つ。 Waitms 30 'チャタリングの待ち時間。 ' Gosub Timeset '時刻設定処理。 ' Eepagingoffset = Timebuff(8) '[Aging Offset]値データをEEPROMに保管する。 Sound Sp_out , 200 , 333 '4000Hzの音を50mS鳴らす。 Cls 'LCD表示をすべて消去。 Goto Sw3on1 '-------------------------------------------------------------------------------------------------- ' ' ----------------------------------- ' * 日付をLCDに表示するサブルーチン * ' ----------------------------------- ' Datedisp: Locate 1 , 1 Lcd "20" ; Hex(timebuff(6)) ; "/" ; '[年]を表示。 Temp1 = Timebuff(5) '[月]を表示。 Gosub Zerosup '上位桁をゼロサプレスして表示。 Lcd "/" ; Temp1 = Timebuff(4) '[日]を表示。 Gosub Zerosup '上位桁をゼロサプレスして表示。 Temp1 = Timebuff(7) Temp1 = Temp1 - 1 '1〜7を0〜6に変換する。 Lcd " " ; Lookupstr(temp1 , Weekdata) '[曜日]を表示する。 Return ' ' ----------------------------------- ' * 時刻をLCDに表示するサブルーチン * ' ----------------------------------- ' Timedisp: If Hourmode = 0 Then 'If 12時間制表示か? Then Temp1 = Makedec(timebuff(3)) 'BCDを10進数の数値に変換。 If Temp1 < 12 Then 'If AM or PM? Lcd "am "; '[AM]を表示する。 Else Lcd "pm "; '[PM]を表示する。 End If ' If Temp1 = 0 Then Temp1 = 24 '24時間制時刻を12時間制に変換する。 If Temp1 > 12 Then Temp1 = Temp1 - 12 Temp1 = Makebcd(temp1) '10進数の数値をBCD値に変換。 Else '24時間制の場合。 Lcd " " ; '[AM/PM]マークを消去する。 Temp1 = Timebuff(3) '[時]を表示。 End If Gosub Zerosup '上位桁をゼロサプレスして表示。 Lcd ":" ; Hex(timebuff(2)) ; '[分]を表示。 Lcd ":" ; Hex(timebuff(1)) ; '[秒]を表示。 Return ' ' * 上位桁をゼロサプレスして表示するサブルーチン * (Temp1 = 表示データ) ' Zerosup: Temp2 = Temp1 And &HF0 If Temp2 = 0 Then 'If 上位桁が0か? Then Lcd " " ; Temp1 ; Else Lcd Hex(temp1) ; End If Return '################################################################################################## ' ' **************** ' * 時刻設定処理 * ' **************** ' Timeset: Cursor Blink 'LCDのカーソルを点滅にする。 ' Tempts1 = 6 '[年]の設定。 Tempts2 = 1 'LCDの[Y]アドレス。 Tempts3 = 3 'LCDの[X]アドレス。 Tempts4 = 0 '設定の下限値。 Tempts5 = 99 '設定の上限値。 Gosub Setswin ' Tempts1 = 5 '[月]の設定。 Tempts3 = 6 'LCDの[X]アドレス。 Tempts4 = 1 '設定の下限値。 Tempts5 = 12 '設定の上限値。 Gosub Setswin ' Tempts1 = 4 '[日]の設定。 Tempts3 = 9 'LCDの[X]アドレス。 Tempts5 = 31 '設定の上限値。 Gosub Setswin ' Tempts1 = 7 '[曜日]の設定。 Tempts3 = 12 'LCDの[X]アドレス。 Tempts4 = 1 '設定の下限値。 Tempts5 = 7 '設定の上限値。 Gosub Setswin ' Tempts1 = 3 '[時]の設定。 Tempts2 = 2 'LCDの[Y]アドレス。 Tempts3 = 4 'LCDの[X]アドレス。 Tempts4 = 0 '設定の下限値。 Tempts5 = 23 '設定の上限値。 Gosub Setswin ' Tempts1 = 2 '[分]の設定。 Tempts3 = 7 'LCDの[X]アドレス。 Tempts5 = 59 '設定の上限値。 Gosub Setswin ' Tempts1 = 1 '[秒]の設定。 Tempts3 = 10 'LCDの[X]アドレス。 Gosub Setswin ' Tempts1 = 8 '[DS3231] Aging Offset値。 Tempts3 = 13 'LCDの[X]アドレス。 Gosub Setswin ' ' * 時刻設定の終了 * ' I2cbuff(1) = &H00 'レジスター[00h] Secondsのアドレスを指定する。 I2cbuff(2) = Timebuff(1) '[秒]データを保存する。 I2cbuff(3) = Timebuff(2) '[分]データを保存する。 I2cbuff(4) = Timebuff(3) '[時]データを保存する。 I2cbuff(5) = Timebuff(7) '[曜日]データを保存する。 I2cbuff(6) = Timebuff(4) '[日]データを保存する。 I2cbuff(7) = Timebuff(5) '[月]データを保存する。 I2cbuff(8) = Timebuff(6) '[年]データを保存する。 I2csend &HD0 , I2cbuff(1) , 8 'I2Cバスで、8バイトのデータを送信する。 ' I2cbuff(1) = &H10 'レジスター[10h] Aging Offsetのアドレスを指定する。 I2cbuff(2) = Timebuff(8) '[Aging Offset]値データを[DS3231]に保存する。 I2csend &HD0 , I2cbuff(1) , 2 'I2Cバスで、2バイトのデータを送信する。 Bitwait Sw_1 , Set 'ボタン[A]が離されるまで待つ。 Waitms 30 'チャタリングの待ち時間。 Cursor Off Noblink 'LCDのカーソル点滅をオフする。 Return ' ' * 設定用のスイッチ入力処理 * ' Setswin: Gosub Timesetdisp '時刻設定用の日時を表示する。 Locate Tempts2 , Tempts3 'LCDのカーソルを移動する。 Setswin4: Debounce Sw_1 , 0 , Setswin1 '[SW1]の検出。 Debounce Sw_2 , 0 , Setswin2 '[SW2]の検出。 Debounce Sw_3 , 0 , Setswin3 '[SW3]の検出。 Goto Setswin4 ' ' * [SW1]が押された場合 * ' Setswin1: '次の項目へ移動する。 Sound Sp_out , 50 , 1333 '1000Hzの音を50mS鳴らす。 Return ' ' * [SW2]が押された場合 * ' Setswin2: If Tempts1 <> 8 Then 'If [DS3231] Aging Offset値以外か? Then Tempts6 = Makedec(timebuff(tempts1)) 'BCDを10進数の数値に変換。 Tempts6 = Tempts6 + 1 '設定値を加算する。 If Tempts6 > Tempts5 Then 'If 上限値か? Then Tempts6 = Tempts4 End If Timebuff(tempts1) = Makebcd(tempts6) '10進数の数値をBCD値に変換。 Else Timebuff(8) = Timebuff(8) + 1 '[DS3231] Aging Offset値を加算する。 End If Goto Setswin ' ' * [SW3]が押された場合 * ' Setswin3: If Tempts1 <> 8 Then 'If [DS3231] Aging Offset値以外か? Then Tempts6 = Makedec(timebuff(tempts1)) 'BCDを10進数の数値に変換。 If Tempts6 = Tempts4 Then 'If 下限値か? Then Tempts6 = Tempts5 Else Tempts6 = Tempts6 - 1 '設定値を減算する。 End If Timebuff(tempts1) = Makebcd(tempts6) '10進数の数値をBCD値に変換。 Else Timebuff(8) = Timebuff(8) - 1 '[DS3231] Aging Offset値を減算する。 End If Goto Setswin ' ' ------------------------------------------ ' * 時刻設定用の日時を表示するサブルーチン * ' ------------------------------------------ ' Timesetdisp: Gosub Datedisp '日付をLCDに表示する。 Locate 2 , 1 Gosub Timedisp '時刻をLCDに表示する。 ' Locate 2 , 13 Temp1 = Timebuff(8) '[DS3231] Aging Offset値。 If Temp1.7 = 0 Then 'If [+]の値か? Then Lcd "+" ; Temp1 ; '[+]の場合。 Else '[-]の場合。 Temp1 = Not Temp1 Temp1 = Temp1 + 1 Lcd "-" ; Temp1 ; End If Lcd " " Return '################################################################################################## ' ' ******************************************* ' * [DS3231]から日時を読み出すサブルーチン * ' ******************************************* ' Ds3231read: I2cbuff(1) = &H00 'レジスター[00h] Seconds のアドレスを指定する。 I2creceive &HD0 , I2cbuff(1) , 1 , 7 'I2Cバスで、1バイトのコマンドを送信し、7バイトのデータを受信する。 Timebuff(1) = I2cbuff(1) '[秒]データを保存する。 Timebuff(2) = I2cbuff(2) '[分]データを保存する。 Timebuff(3) = I2cbuff(3) '[時]データを保存する。 Timebuff(7) = I2cbuff(4) '[曜日]データを保存する。 Timebuff(4) = I2cbuff(5) '[日]データを保存する。 Timebuff(5) = I2cbuff(6) And &H1F '[月]データを保存する。 Timebuff(6) = I2cbuff(7) '[年]データを保存する。 Return ' ' ************************************ ' * [DS3231]を初期化するサブルーチン * ' ************************************ ' Ds3231init: Restore Ds3231initdata '[DS3231]の初期設定データ・テーブル。 For Temp1 = 1 To 18 '初期設定データの18バイトをバッファーへ転送する。 Read I2cbuff(temp1) Next Temp1 ' I2csend &HD0 , I2cbuff(1) , 18 'I2Cバスで、18バイトのデータを送信する。 Return End ' ' * RTC [DS3231]の初期設定データ・テーブル * ' Ds3231initdata: Data &H00 '[DS3231]レジスターのスタートアドレス Data &H00 '[00] Seconds Data &H00 '[01] Minutes Data &H00 '[02] Hours Data &H01 '[03] Weekday Data &H01 '[04] Date Data &H01 '[05] Months Data &H17 '[06] Year Data &H00 '[07] Alarm 1 Seconds Data &H00 '[08] Alarm 1 Minutes Data &H00 '[09] Alarm 1 Hours Data &H00 '[0A] Alarm 1 Day,Date Data &H00 '[0B] Alarm 2 Minutes Data &H00 '[0C] Alarm 2 Hours Data &H00 '[0D] Alarm 2 Day,Date Data &B0000_0000 '[0E] Control (/EOSC=0, BBSQW=0, CONV=0, RS2-RS1=00(1Hz), INTCN=0, A2IE=0, A1IE=0) Data &B0000_0000 '[0F] Control/Status (OSF=0, Bit6=0, Bit5=0, Bit4=0, EN32kHz=0, BSY=x, A2F=0, A1F=0) Data &H00 '[10] Aging Offset ' ' * 曜日 データ・テーブル * ' Weekdata: Data "SUN" , "MON" , "TUE" , "WED" , "THU" , "FRI" , "SAT"