' ' ************************************************************* ' * * ' * ATmega88 + NUMITRON DA-2900 4桁 デジタル時計 プログラム * ' * * ' * AVR is using ATmega88 * ' * Basic Compiler is BASCOM-AVR * ' * Copyright By O-Family 2008. 9.15 * ' ************************************************************* ' ' Ver 1.01 初回公開バージョン ' Ver 1.02 [C]キーに、表示ON/OFF機能を追加。 ' ' $regfile = "m88def.dat" $crystal = 8000000 $eepleave ' Const Prgver = &H0102 'プログラム・バージョン。 ' ' Dim Temppb As Byte 'PORT B 出力データ テンポラリ。 Dim Temppc As Byte 'PORT C 出力データ テンポラリ。 Dim Temppd As Byte 'PORT D 出力データ テンポラリ。 ' Dim Tempsec As Byte '[秒]更新用テンポラリ。 Dim Mf1224h As Byte 'モード・フラグ 0=24時間制 / 1=12時間制 Dim Mf82ds As Byte 'モード・フラグ 0=通常表示 / 1=8秒時間-2秒日付表示 Dim Dpblkt As Byte 'D.P点滅 500mSタイマー。 Dim Disponf As Byte '時刻表示 ON/OFF フラグ。 Dim Monend As Byte '月の最終日 計算用。 Dim Keycun As Byte 'キー入力チェック用タイマーカウンター。 Dim Keyflg As Byte 'キー入力検出フラグ。 Dim Keydat As Byte 'キー入力データ。 Dim Keytemp As Byte 'キー入力用テンポラリ。 Dim Keytemp2 As Byte 'キー入力用テンポラリ2。 ' Dim Temp1 As Byte '汎用テンポラリ変数 Byte型 No.1 Dim Temp2 As Byte '汎用テンポラリ変数 Byte型 No.2 Dim Temp3 As Byte '汎用テンポラリ変数 Byte型 No.3 Dim Temp4 As Byte '汎用テンポラリ変数 Byte型 No.4 Dim Temp5 As Byte '汎用テンポラリ変数 Byte型 No.5 Dim Temp6 As Byte '汎用テンポラリ変数 Byte型 No.6 Dim Temp7 As Byte '汎用テンポラリ変数 Byte型 No.7 Dim Temp8 As Byte '汎用テンポラリ変数 Byte型 No.8 Dim Temp9 As Byte '汎用テンポラリ変数 Byte型 No.9 Dim Tempw1 As Word '汎用テンポラリ変数 Word型 No.1 Dim Ltemp1 As Byte 'ローカル専用、汎用テンポラリ変数 Byte型 No.1 ' ' ' ' * ポートの初期設定 * ' Config Portb = Output 'すべてのポートを出力に設定。 Config Portc = Output Config Portd = Output Config Pinc.0 = Input 'スイッチ接続ポートを入力に設定。 ' Temppb = &B00111111 '表示をすべて消灯。 Portb = Temppb Temppc = &B00111110 Portc = Temppc Temppd = &B11111111 Portd = Temppd ' ' * 時計用のライブラリを組み込む * ' Config Clock = Soft '時計(タイマー)をSoftモードに設定。 Config Date = Ymd , Separator = / '日付の表現方法(形式)を設定。 ' ' * タイマーを設定 * ' Config Timer0 = Timer , Prescale = 1024 , Clear Timer = 1 'Timer0 = 7,812Hz Ocr0a = 77 '10mS タイマーを設定。 ' ' * A/Dコンバーターを設定 * ' Config Adc = Single , Prescaler = Auto 'A/Dコンバーターの初期設定。 Start Adc 'A/Dコンバータに電源を供給。 ' ' * 変数の初期値設定 * ' Tempsec = 99 '[秒]更新用テンポラリに、ダミー値を格納。 _year = 8 _month = 1 _day = 1 Disponf = 1 '時刻表示 ON/OFF フラグ。 ' ' ****************************** ' * EEPROM 保存データ 読み込み * ' ****************************** ' Readeeprom Mf1224h , 1 'EEPROM (1) 12/24時間制 表示フラグ。 Readeeprom Mf82ds , 2 'EEPROM (2) 8秒時間-2秒日付 表示フラグ。 ' If Mf1224h > 1 Then 'If EEPROMが初期状態? Then Mf1224h = 0 '0=24時間制 / 1=12時間制 Mf82ds = 0 '0=通常表示 / 1=8秒時間-2秒日付表示 Gosub Eepwrs 'EEPROMに書き込み。 End If ' ' ******************************** ' * プログラム・バージョンを表示 * ' ******************************** ' Prgvds: Temp6 = 1 '表示を点滅してキー入力待ち。 Prgvds3: Temp7 = 20 Prgvds1: If Tifr0.ocf0a = 0 Then Goto Prgvds1 'If 10mS経過したか? Else Set Tifr0.ocf0a 'Timer0 比較A一致フラグをリセット。 ' Gosub Keyin If Keyflg <> 0 Then Goto Prgvds2 'If キー入力有り? Then Temp7 = Temp7 - 1 If Temp7 <> 0 Then Goto Prgvds1 'If 点滅タイマー カウント終了? Else If Temp6 = 0 Then '点滅用 F/Fを反転。 Temp6 = 1 Temp3 = &HFF '上位桁を消灯。 Temp2 = &H05 Gosub Segcver Temp3 = &HFF '下位桁を消灯。 Temp2 = &H03 Gosub Segcver Else Temp6 = 0 Temp3 = High(prgver) 'プログラム・バージョンの上位を表示。 Temp2 = &H05 Gosub Segcvwp Temp3 = Low(prgver) 'プログラム・バージョンの下位を表示。 Temp2 = &H03 Gosub Segcvwp End If Goto Prgvds3 ' Prgvds2: Gosub Keyoff 'キーが離されるまで待つ。 ' ' Enable Interrupts '割り込みを許可。 ' ' ******************* ' * メイン ルーチン * ' ******************* ' Main: Gosub T10msec '10mSタイマー処理 & キー入力チェック。 Gosub Timdisp '時刻表示 処理。 Goto Main ' End ' ' ************************************************ ' * 10mSタイマー処理 & キー入力チェック ルーチン * ' ************************************************ ' T10msec: If Tifr0.ocf0a = 0 Then Return 'If 10mS経過したか? Else Set Tifr0.ocf0a 'Timer0 比較A一致フラグをリセット。 ' If Dpblkt = 0 Then Goto Keyin 'If D.P点滅タイマー カウント終了? Then Dpblkt = Dpblkt - 1 If Dpblkt <> 0 Then Goto Keyin 'If D.P点灯から500mS経過? Else Gosub Coloff 'コロンを消灯。 ' ' ************************* ' * キー入力 サブルーチン * (Keyflg = キー入力が有ると1) ' ************************* (Keydat = キーデータ) ' Keyin: If Keycun = 0 Then Goto Keyin01 'If キー入力チェック開始? Then If Keycun < 3 Then Goto Keyin05 'If チャタリング チェック期間? Then If Keycun = 3 Then Goto Keyin03 'If キー入力再確認? Then ' Gosub Keyport 'キーオフを確認 If Keydat <> Keytemp Then Goto Keyin04 'If キーオフ? Then If Keycun < 103 Then Goto Keyin05 'If リピート期間待ち(1Sec)? Then Keyflg = 1 Keycun = 92 'リピート開始 Return ' ' Keyin01: 'キー入力チェック開始。 Gosub Keyport 'キー接続ポートからデータを入力。 If Keydat <> 0 Then Goto Keyin02 'If キー入力有り? Then Keyin04: Keycun = 0 Return ' Keyin02: 'キー入力有り。 Keytemp = Keydat 'キー・データを一時保存。 Keyin05: Keycun = Keycun + 1 Return ' Keyin03: 'キー入力再確認 Gosub Keyport 'キー接続ポートからデータを入力。 If Keydat <> Keytemp Then Goto Keyin04 'If キー入力エラー? Then Keyflg = 1 Goto Keyin05 ' ' *********************************************** ' * キー接続ポートからデータを入力 サブルーチン * (Keydat = キー・データ) ' *********************************************** ' Keyport: Tempw1 = Getadc(0 , &H20) 'アナログ入力0、左揃えモードを設定。 Keytemp2 = High(tempw1) 'ワード型変数の上位を取り出し。 Select Case Keytemp2 Case 198 To 209 : Keydat = 1 'スイッチ A Case 147 To 158 : Keydat = 2 'スイッチ B Case 99 To 109 : Keydat = 3 'スイッチ C Case 127 To 138 : Keydat = 4 'スイッチ A+B Case 76 To 86 : Keydat = 5 'スイッチ B+C Case 88 To 98 : Keydat = 6 'スイッチ A+C Case Else : Keydat = 0 '上記以外の場合。 End Select Return ' ' *************************************** ' * キーが離されるまで待つ サブルーチン * ' *************************************** ' Keyoff: Gosub Keyport 'キー接続ポートからデータを入力。 If Keytemp2 < 245 Then Goto Keyoff 'If キーが離されたか? Else Waitms 100 Return ' ' *************************************** ' * コロンを消灯する サブルーチン * ' *************************************** ' Coloff: Set Temppd.5 'コロンを消灯。 Portd = Temppd 'ポートへデータを出力。 Return ' ' *************************************** ' * (AM.PM)を消灯する サブルーチン * ' *************************************** ' Ampmoff: Set Temppc.1 '[AM] ランプを消灯。 Set Temppc.2 '[PM] ランプを消灯。 Portc = Temppc 'ポートへデータを出力。 Return ' ' ************************* ' * 時刻表示 処理ルーチン * ' ************************* ' Timdisp: If Keyflg <> 0 Then Goto Timdsp01 'If キー入力有り? Then Gosub Keyport If Keydat <> 0 Then Return 'If キーが押されている? Then ' If Tempsec = _sec Then Return 'If [秒]が更新されたか? Else Reset Temppd.5 'コロンを点灯にセット。 Dpblkt = 50 'D.P点滅 500mSタイマーセット。 Timdsp02: Tempsec = _sec '[秒]更新用テンポラリに、現在の[秒]を保存。 If Disponf = 0 Then Goto Timdsp05 'If 時刻表示 消灯モード? Then ' If Mf82ds = 1 Then Goto Timdsp03 'If 8秒時間-2秒日付表示モード? Then Timdsp04: Gosub Segcvw Temp1 = _min '[分]を表示。 Temp2 = &H03 '桁を3,4にセット。 Gosub Segcvw Temp1 = _hour '[時]を表示。 Temp2 = &H85 '桁を5,6にセット。 Gosub Hourcv Portd = Temppd 'コロンの状態をポートへ出力。 Return ' ' Timdsp05: '時刻表示をすべて消灯。 Temp2 = &H03 '桁を3,4にセット。 Temp3 = &HFF '指定[桁]を消灯。 Gosub Segcver Temp2 = &H05 '桁を5,6にセット。 Temp3 = &HFF '指定[桁]を消灯。 Gosub Segcver Gosub Ampmoff 'AM,PMを消灯。 Portd = Temppd 'コロンの状態をポートへ出力。 Return ' ' Timdsp03: '8秒時間-2秒日付表示モード。 Temp1 = Makebcd(_sec) Temp1 = Temp1 And &H0F If Temp1 > 7 Then Goto Timdsp11 'If [秒]の下位が8-9? Then Goto Timdsp04 ' ' Timdsp01: 'キー入力有り Keyflg = 0 'キー入力フラグをリセット。 If Keydat = 1 Then Goto Timdsp11 'If [A]キーが押された? Then If Keydat = 2 Then Goto Timdsp21 'If [B]キーが押された? Then If Keydat = 3 Then Goto Timdsp31 'If [C]キーが押された? Then If Keydat = 4 Then Goto Timdsp41 'If [A+B]キーが押された? Then If Keydat = 6 Then Goto Timdsp61 'If [A+C]キーが押された? Then If Keydat = 5 Then Goto Timdsp51 'If [B+C]キーが押された? Then Return ' ' Timdsp11: '[A]キーが押された。(月・日を表示) Gosub Coloff 'コロンを消灯。 Gosub Ampmoff 'AM,PMを消灯。 Temp1 = _day '[日]を表示。 Temp2 = &H83 '桁を3,4にセット。 Gosub Segcvw Temp1 = _month '[月]を表示。 Temp2 = &H85 '桁を5,6にセット。 Gosub Segcvw Return ' ' Timdsp21: '[B]キーが押された。(分・秒を表示) Gosub Coloff 'コロンを消灯。 Gosub Ampmoff 'AM,PMを消灯。 Temp1 = _sec '[秒]を表示。 Temp2 = &H03 '桁を3,4にセット。 Gosub Segcvw Temp1 = _min '[分]を表示。 Temp2 = &H05 '桁を5,6にセット。 Gosub Segcvw Return ' ' Timdsp31: '[C]キーが押された。(時刻表示のON/OFF) Toggle Disponf.0 '時刻表示 ON/OFF フラグを反転。 Goto Timdsp02 ' ' Timdsp41: '[A+B]キーが押された。(12/24時間制の切り換え) Toggle Mf1224h.0 '12/24時間制モード・フラグを反転。 Gosub Eepwrs 'EEPROMに書き込み。 Goto Timdsp02 ' ' Timdsp61: '[A+C]キーが押された。(表示モードの切り換え) Toggle Mf82ds.0 '8秒時間-2秒日付表示モード・フラグを反転。 Gosub Eepwrs 'EEPROMに書き込み。 Goto Timdsp02 ' ' Timdsp51: '[B+C]キーが押された。(時刻設定モード) Waitms 10 '10mSの待ち時間。 Gosub Keyin If Keydat <> 5 Then Goto Timdsp02 'If [B+C]キーが押されている? Else If Keyflg = 0 Then Goto Timdsp51 'If 1秒以上押された? Else ' ' ************************* ' * 時刻設定 処理ルーチン * ' ************************* ' Timset: Disable Timer2 '1秒割り込みを禁止。 Gosub Coloff 'コロンを消灯。 Gosub Ampmoff 'AM,PMを消灯。 ' Temp1 = 20 '[年]設定。 Temp2 = &H05 '桁を5,6にセット。 Gosub Segcvw Temp2 = &H03 '桁を3,4にセット。 Temp3 = &HFF '指定[桁]を消灯。 Gosub Segcver Gosub Keyoff 'キーが離されるまで待つ。 ' Temp1 = _year 'Temp1 = 設定するデータ値。 Temp2 = &H03 '桁を3,4にセット。 ' Timset21: Temp4 = 0 'Temp4 = 設定値の下限。 Temp5 = 99 'Temp5 = 設定値の上限。 Gosub Tmskey If Keydat <> 1 Then Goto Timset21 'If [A]キーが押された? Else _year = Temp1 Gosub Keyoff 'キーが離されるまで待つ。 ' ' Temp1 = _day '[月]設定。 Temp2 = &H83 '桁を3,4にセット。 Gosub Segcvw Temp1 = _month 'Temp1 = 設定するデータ値。 Temp2 = &H85 '桁を5,6にセット。 ' Timset31: Temp4 = 1 'Temp4 = 設定値の下限。 Temp5 = 12 'Temp5 = 設定値の上限。 Gosub Tmskey If Keydat <> 1 Then Goto Timset31 'If [A]キーが押された? Else _month = Temp1 Gosub Keyoff 'キーが離されるまで待つ。 ' ' Temp1 = _month '[日]設定。 Temp2 = &H85 '桁を5,6にセット。 Gosub Segcvw Gosub Monchk '月ごとの日にちの最終日を計算 Temp1 = _day 'Temp1 = 設定するデータ値。 Temp2 = &H83 '桁を3,4にセット。 ' Timset41: Temp4 = 1 'Temp4 = 設定値の下限。 Temp5 = Monend 'Temp5 = 設定値の上限。 Gosub Tmskey If Keydat <> 1 Then Goto Timset41 'If [A]キーが押された? Else _day = Temp1 Gosub Keyoff 'キーが離されるまで待つ。 ' ' Temp1 = _min '[時]設定。 Temp2 = &H03 '桁を3,4にセット。 Gosub Segcvw Temp1 = _hour 'Temp1 = 設定するデータ値。 Temp2 = &HC5 '桁を5,6にセット。 ' Timset51: Temp4 = 0 'Temp4 = 設定値の下限。 Temp5 = 23 'Temp5 = 設定値の上限。 Gosub Tmskey If Keydat <> 1 Then Goto Timset51 'If [A]キーが押された? Else _hour = Temp1 Gosub Keyoff 'キーが離されるまで待つ。 ' ' Temp1 = _hour '[分]設定。 Temp2 = &H85 '桁を5,6にセット。 Gosub Hourcv Temp1 = _min 'Temp1 = 設定するデータ値。 Temp2 = &H03 '桁を3,4にセット。 ' Timset61: Temp4 = 0 'Temp4 = 設定値の下限。 Temp5 = 59 'Temp5 = 設定値の上限。 Gosub Tmskey If Keydat <> 1 Then Goto Timset61 'If [A]キーが押された? Else _min = Temp1 ' _sec = 0 '[秒]をリセット。 Enable Timer2 '1秒割り込みを許可。 Goto Timdsp02 ' ' ************************************ (Temp1 = 設定するデータ値) ' * 時刻設定用 キー入力 サブルーチン * (Temp2 = 設定するデータの桁位置) ' ************************************ (Temp4 = 設定値の下限) ' (Temp5 = 設定値の上限) Tmskey: Temp6 = 1 '点滅用 F/F。 Temp7 = 1 '点滅用タイマー値。 ' Tmskey1: If Tifr0.ocf0a = 0 Then Goto Tmskey1 'If 10mS経過したか? Else Set Tifr0.ocf0a 'Timer0 比較A一致フラグをリセット。 ' Gosub Keyin If Keyflg <> 0 Then Goto Tmskey2 'If キー入力有り? Then Temp7 = Temp7 - 1 If Temp7 <> 0 Then Goto Tmskey1 'If 点滅タイマー カウント終了? Else If Temp6 = 0 Then '点滅用 F/Fを反転。 Temp6 = 1 Temp7 = 20 '点滅用タイマー値。 Temp3 = &HFF '指定[桁]を消灯。 Gosub Segcver Else Temp6 = 0 Temp7 = 40 '点滅用タイマー値。 If Temp2.6 = 1 Then 'If [時]表示? Then Gosub Hourcv '指定[桁]を点灯。 Else Gosub Segcvw '指定[桁]を点灯。 End If End If Goto Tmskey1 ' ' Tmskey2: Keyflg = 0 'キー入力フラグをリセット。 If Keydat = 1 Then Return 'If [A]キーが押された? Then If Keydat = 2 Then Goto Tmskey3 'If [B]キーが押された? Then If Keydat = 3 Then Goto Tmskey4 'If [C]キーが押された? Then Goto Tmskey1 ' ' Tmskey3: '設定値を加算。 Temp1 = Temp1 + 1 If Temp1 > Temp5 Then Temp1 = Temp4 'If 設定値が上限を超えたか? Then Return ' Tmskey4: '設定値を減算。 If Temp1 = Temp4 Then 'If 設定値が下限を超えるか? Then Temp1 = Temp5 Else Temp1 = Temp1 - 1 End If Return ' ' ************************************************ ' * 月ごとの日にちの最終日を計算するサブルーチン * (Monend = その月の最終日) ' ************************************************ ' Monchk: Select Case _month '月をチェック。 Case 2 : Ltemp1 = _year And &H03 If Ltemp1 = 0 Then 'If 閏年? Then Monend = 29 Else Monend = 28 End If Case 4 : Monend = 30 Case 6 : Monend = 30 Case 9 : Monend = 30 Case 11 : Monend = 30 Case Else : Monend = 31 End Select Return ' ' **************************************** ' * バイナリ値を2桁のBCDデータに変換して * (Temp1 = バイナリ・データ) ' * ポートに出力するサブルーチン * (Temp2 bit3-0 = 書き込む桁番号 (3,5) ' **************************************** (Temp2 Bit7 = (1)でゼロサプレス制御。 ' Segcvw: Temp3 = Makebcd(temp1) 'バイナリ値を、BCD(Binary coded decimal)値に変換。 Segcvwp: If Temp2.7 = 1 Then 'If ゼロサプレスが有効? Then If Temp3 < 10 Then 'If 上位桁の値が0? Then Temp3 = Temp3 Or &HF0 '上位桁を消灯。 End If End If ' Segcver: Temp8 = Temp2 And &H0F 'Temp4 = 書き込む桁番号。(03,05) If Temp8 = 5 Then Goto Segcvw1 'If [時]桁? Then ' $asm LDS R16,{temp3} 'BCDデータを、[分]桁のポート並びに変換。 LDS R17,{Temppb} LDS R18,{Temppd} ' BST R16,0 '指定ビットを[T]フラグへ読み込む。 BLD R17,4 '並び替えるビットにコピー。 BST R16,1 BLD R17,1 BST R16,2 BLD R17,2 BST R16,3 BLD R17,3 ' BST R16,4 BLD R18,6 BST R16,5 BLD R17,5 BST R16,6 BLD R17,0 BST R16,7 BLD R18,7 ' STS {Temppb},R17 STS {Temppd},R18 $end Asm ' Segcvw2: 'ポートへデータを出力。 Portb = Temppb Portc = Temppc Portd = Temppd Return ' ' Segcvw1: $asm LDS R16,{temp3} 'BCDデータを、[時]桁のポート並びに変換。 LDS R17,{Temppc} LDS R18,{Temppd} ' BST R16,0 '指定ビットを[T]フラグへ読み込む。 BLD R18,1 '並び替えるビットにコピー。 BST R16,1 BLD R18,4 BST R16,2 BLD R18,3 BST R16,3 BLD R18,2 ' BST R16,4 BLD R17,4 BST R16,5 BLD R18,0 BST R16,6 BLD R17,3 BST R16,7 BLD R17,5 ' STS {Temppc},R17 STS {Temppd},R18 $end Asm Goto Segcvw2 ' ' ****************************************** (Temp1 = バイナリ・データ) ' * 時間 12/24時間制 識別表示 サブルーチン * (Temp2 bit3-0 = 書き込む桁番号 (3,5) ' ****************************************** (Temp2 Bit7 = (1)でゼロサプレス制御。 ' Hourcv: If Mf1224h = 1 Then Goto Hourcv1 'If 12時間制? Then ' Gosub Ampmoff 'AM,PMを消灯。 Gosub Segcvw '24時間制表示。 Return ' ' Hourcv1: '12時間制表示。 Temp9 = Temp1 '24時間制時刻を12時間制に変換。 If Temp1 = 0 Then Temp1 = 24 If Temp1 > 12 Then Temp1 = Temp1 - 12 Gosub Segcvw ' If Temp9 < 12 Then 'If AM or PM? Set Temppc.2 '[PM] ランプを消灯。 Reset Temppc.1 '[AM] ランプを点灯。 Else Set Temppc.1 '[AM] ランプを消灯。 Reset Temppc.2 '[PM] ランプを点灯。 End If Portc = Temppc 'ポートへデータを出力。 Temp1 = Temp9 Return ' ' ******************************** ' * EEPROM 書き込み サブルーチン * ' ******************************** ' Eepwrs: Writeeeprom Mf1224h , 1 Writeeeprom Mf82ds , 2 Return ' End