$prog &HFF , &H62 , &HD9 , &HFF 'JTAGEN = 1 ' ' *************************************************** ' * * ' * LCDパネル SP521PR 温度計付き時計 プログラム * ' * * ' * AVR is using ATmega164P * ' * Basic Compiler is BASCOM-AVR * ' * Copyright By O-Family 2013. 7.16 * ' *************************************************** ' ' Ver 0.01 テスト・バージョン 2013. 7.16 ' Ver 1.01 初回公開バージョン。 2013. 7.16 ' ' Const Prgverh = 01 'プログラム・バージョン。(上位桁) Const Prgverl = 01 'プログラム・バージョン。(下位桁) ' ' $regfile = "m164Pdef.dat" '使用するAVRを設定。 $crystal = 1000000 'AVRクロックを設定。 ' $hwstack = 64 'ハードウェア・スタックの容量を設定。 $swstack = 16 'ソフトウェア・スタックの容量を設定。 $framesize = 32 'フレーム領域の容量を設定。 ' ' * ポート名の定義 * ' Sw_1 Alias Pina.1 'スイッチ[1]の接続ポート。 Sw_2 Alias Pinc.5 'スイッチ[2]の接続ポート。 ' ' * 変数の宣言 * ' Dim Dispmode As Byte '表示モード。 Dim Modetemp As Byte '表示モードの保管用。 Dim Time1sf As Byte '1秒経過フラグ。 Dim Colblken As Byte 'コロン点滅許可フラグ。 Dim Timetemp As Byte '[時分]と[温度]を交互表示の秒数。(1〜9秒) Dim Tempsenofs As Word '温度センサーの係数。 [MCP9700-E/TO] = 500 , [LM61BIZ] = 600 Dim Refvolt As Word 'AVRの内部基準電圧較正値。(Eeprefadj * 10 + 1000) Dim Daychgf As Byte '日付変更フラグ。 Dim Keycun As Byte 'キー入力チェック用タイマーカウンター。 Dim Keyflg As Byte 'キー入力検出フラグ。 Dim Keydata As Byte 'キー入力データ。 Dim Keytemp As Byte 'キー入力用テンポラリ。 Dim Colblinksel As Byte 'コロンの点滅を選択。(0=点滅しない , 1=1秒間隔で点滅する) Dim Pmdisp As Byte 'PMのマイナス表示を選択。(0=表示しない , 1=[-]で表示する) Dim Autodisptm As Byte '自動で表示を切り換えるタイマー。 Dim Temperature As Integer '温度値。(x0.1) Dim Tempmax As Integer '温度の最高値。(x0.1) Dim Tempmin As Integer '温度の最低値。(x0.1) ' Dim Segcode1 As Byte 'セグメントコード格納バッファー[1桁]。 Dim Segcode2 As Byte 'セグメントコード格納バッファー[2桁]。 Dim Segcode3 As Byte 'セグメントコード格納バッファー[3桁]。 Dim Segcode4 As Byte 'セグメントコード格納バッファー[4桁]。 Dim Segminus As Byte 'セグメントコード格納バッファー[-(マイナス)]。 ' Dim Lcddta As Byte 'LCD接続ポート[Port A]の出力保管用。 Dim Lcddtb As Byte 'LCD接続ポート[Port B]の出力保管用。 Dim Lcddtc As Byte 'LCD接続ポート[Port C]の出力保管用。 Dim Lcddtd As Byte 'LCD接続ポート[Port D]の出力保管用。 Dim Timecun As Byte '500mSカウンター。(31.25mS × 16) Dim Time500msf As Byte '500mS経過フラグ。 ' 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 Temp10 As Byte '汎用テンポラリ変数 Byte型 No.10 Dim Temp11 As Byte '汎用テンポラリ変数 Byte型 No.11 Dim Tempw1 As Word '汎用テンポラリ変数 Word型 No.1 Dim Tempw2 As Word '汎用テンポラリ変数 Word型 No.2 Dim Tempi1 As Integer '汎用テンポラリ変数 Integer型 No.1 Dim Templ1 As Long '汎用テンポラリ変数 Long型 No.1 ' Dim Dummy As Eram Long 'EEPROM 4バイトのダミーエリア。 Dim Eepextremum As Eram Byte 'EEPROM 最高最低値のリセット選択。 (0=リセットしない , 1=日付変更時) Dim Eepcolblinksel As Eram Byte 'EEPROM コロンの点滅を選択。(0=点滅しない , 1=1秒間隔で点滅する) Dim Eeppmdisp As Eram Byte 'EEPROM PMのマイナス表示を選択。(0=表示しない , 1=[-]で表示する) Dim Eeptimetemp As Eram Byte 'EEPROM 時刻と温度を交互表示する秒数。(1〜9秒) Dim Eepautodisptm As Eram Byte 'EEPROM 自動で[SW2]の表示を切り換える秒数。(2〜60秒) Dim Eeptempsentype As Eram Byte 'EEPROM 温度センサーの種別。(0:MCP9700 , 1:LM61) Dim Eeprefadj As Eram Byte 'EEPROM AVR 1.1V基準電圧の校正値。(1.00〜1.20V) ' ' * ポートの初期設定 * ' Config Porta = &B1111_1100 'A/D,SW1ポートを入力に設定。 Config Portc = &B0001_1111 'TOSC1,2,SW2ポートを入力に設定。 Config Portd = &B1111_1111 'LCD接続ポートを出力に設定。 Config Portb = &B1111_1111 'LCD接続ポートを出力に設定。 Didr0 = &B1111_1101 'デジタル入力禁止レジスタの設定。 Didr1 = &B0000_0011 'デジタル入力禁止レジスタの設定。 Prr0 = &B1001_0110 '電力削減レジスタの設定。(TWI,USART1,SPI,USART0をOFF) ' ' * Timerの設定 * ' Config Clock = User '時計(タイマー)をUserモードに設定。 Config Timer2 = Timer , Async = On , Prescale = 8 , Clear Timer = 1 '32.768KHz / 8 = 4,096Hz Compare2a = 64 - 1 '4,096Hz / 64 = 64Hz (トグル32Hz[31.25mS]) On Compare2a T2int Nosave 'Timer2 比較一致割込ルーチンのラベルを設定。 Enable Compare2a 'Timer2 比較一致割り込みを許可。 ' ' * A/Dコンバーターの設定 * ' Config Adc = Single , Prescaler = Auto , Reference = Internal_1.1 'A/Dコンバータの設定。 Stop Adc 'A/Dコンバータの電源を切る。 Config Aci = Off 'アナログ比較器の電源を切る。 ' ' * EEPROMのデータを確認する * ' If Eepextremum > 1 Then 'If EEPROMが初期値か? Then Eepextremum = 1 '最高最低値のリセット選択。 (0=リセットしない , 1=日付変更時) Eepcolblinksel = 1 'コロンの点滅を選択。(0=点滅しない , 1=1秒間隔で点滅する) Eeppmdisp = 1 'PMのマイナス表示を選択。(0=表示しない , 1=[-]で表示する) Eeptimetemp = 8 '[時分]と[温度]を交互表示の秒数。(1〜9秒) Eepautodisptm = 5 '自動で[SW2]の表示を切り換えるタイマー。(2〜60秒) Eeptempsentype = 0 '温度センサーの種別。(0:MCP9700 , 1:LM61) Eeprefadj = 10 'AVR 1.1V基準電圧の校正値。(0〜20→1.00〜1.20V) End If Colblinksel = Eepcolblinksel Pmdisp = Eeppmdisp Timetemp = Eeptimetemp Gosub Tsentype '温度センサーの係数を選択する。 Temp1 = Eeprefadj 'AVRの内部基準電圧較正値を計算する。 Refvolt = Temp1 * 10 'Eeprefadj(0〜20) * 10 + 1000 Refvolt = Refvolt + 1000 ' ' * 動作の初期設定 * ' Lcddta = &B0000_0010 'SW1ポートをプルアップする。(割り込み内でポートに出力する値) Lcddtc = &B0010_0000 'SW2ポートをプルアップする。(割り込み内でポートに出力する値) ' _year = 13 '年月日の初期値。 _month = 1 _day = 1 Tempmax = -400 '温度の最高値を初期化する。 Tempmin = 1250 '温度の最低値を初期化する。 Enable Interrupts 'すべての割り込みを許可。 ' ' * プログラム・バージョンを表示 * ' Temp1 = Prgverh 'プログラム・バージョンの上位を表示。 Temp2 = &H83 'LCDの左2桁をゼロサプレス+小数点付きで指定。 Gosub Binsegwr 'バイナリ値を2桁のセグメントコードに変換してLCD表示する。 ' Temp1 = Prgverl 'プログラム・バージョンの下位を表示。 Temp2 = 0 'LCDの下位桁を指定。 Temp3 = 0 '設定値の下限。 Temp4 = 99 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 ' ' ******************* ' * メイン ルーチン * ' ******************* ' Main: Power Powersave 'スリープモードへ移行する。(64Hz[15.625mS]割り込みで再起動する) ' Gosub Keychk 'キー(スイッチ)入力を確認する。 Gosub Keycont 'キー入力により表示を切り換える。 ' If Time500msf <> 0 Then 'If 500mS経過したか? Then Time500msf = 0 Toggle Time1sf ' If Time1sf <> 0 Then 'If 1秒経過したか? Then Gosub Timecount '1秒毎に時刻をカウントする。 ' Gosub Thermo '温度値を計測する。 If Daychgf <> 0 Then 'If 日付が変わったか? Then Daychgf = 0 If Eepextremum <> 0 Then 'If 温度湿度の最高最低値を日付変更時に初期化するか? Then Tempmax = Temperature '温度の最高値と最低値を初期化する。 Tempmin = Temperature End If End If ' Gosub Displcd '表示モードに合わせてLCDに情報を表示する。 If Colblken <> 0 Then 'If コロンの点滅が有効か? Then Set Lcddta.3 'コロンを点灯させる。 End If Else If Colblken <> 0 Then 'If コロンの点滅が有効か? Then If Colblinksel <> 0 Then 'If コロンの点滅が選択されているか? Then Reset Lcddta.3 'コロンを消灯させる。 End If End If End If End If Goto Main ' ' ********************************** ' * キー入力により表示を切り換える * ' ********************************** ' Keycont: Select Case Keyflg Case 1 : 'キー入力があった場合。 Select Case Keydata Case &B0000_0001 : '[SW1]が押された場合。 If Dispmode < 5 Then 'If [SW1]の表示モードか Then Dispmode = Dispmode + 1 If Dispmode > 3 Then 'If [SW1]表示の最終値か? Then Dispmode = 0 '[時・分]表示にする。 End If Else : '[日付・最高最低温度]の場合。 Dispmode = Modetemp '[SW2]を押す前の表示に戻す。 End If Autodisptm = 2 '自動表示切り換えタイマーを設定する。 ' Case &B0000_0010 : '[SW2]が押された場合。 If Dispmode < 5 Then 'If [時分秒]または[温度]表示か? Then Modetemp = Dispmode '[SW1]の表示モードを保管する。 Dispmode = 5 '[月・日]表示にする。 Else : '[SW2]の表示モードの場合。 Dispmode = Dispmode + 1 If Dispmode > 7 Then 'If [SW2]表示の最終値か? Then Dispmode = 5 End If End If Autodisptm = Eepautodisptm '自動表示切り換えタイマーを設定する。 ' Case &B0000_0011 : '[SW1+SW2]が押された場合。 Gosub Timeset '時刻設定処理。 End Select Gosub Displcd '表示モードに合わせてLCDに情報を表示する。 ' Case 2 : 'リピートキーの場合。 Select Case Keydata Case &B0000_0010 : '[SW2]のリピートの場合。 Tempmax = Temperature '温度の最高値と最低値を初期化する。 Tempmin = Temperature Dispmode = 8 '[clr]表示にする。 Autodisptm = 1 '自動表示切り換えタイマーを設定する。 ' Case &B0000_0001 : '[SW1]のリピートの場合。 Gosub Modeset 'モード設定処理。 End Select End Select Keyflg = 0 Return ' ' ***************************** ' * 1秒毎に時刻をカウントする * ' ***************************** ' Timecount: _sec = _sec + 1 '[秒]を更新。 If _sec < 60 Then Goto Timecount1 'If 60秒 経過していないか? Then ' _sec = 0 _min = _min + 1 '[分]を更新。 If _min < 60 Then Goto Timecount1 'If 60分 経過していないか? Then ' _min = 0 _hour = _hour + 1 '[時]を更新。 If _hour < 24 Then Goto Timecount1 'If 24時間 経過していないか? Then ' _hour = 0 _day = _day + 1 '[日]を更新。 Daychgf = 1 '日付変更フラグをセットする。 ' Temp1 = Lookup(_month , Monthtab) '月ごとの日にちの最終日を計算する。 If _month = 2 Then 'If 2月か? Then Temp2 = _year And &H03 '閏年の確認。 If Temp2 = 0 Then 'If 閏年か? Then Temp1 = 29 End If End If ' If _day =< Temp1 Then Goto Timecount1 'If 月の最終日を超えていないか? Then ' _day = 1 _month = _month + 1 '[月]を更新。 If _month < 13 Then Goto Timecount1 'If 12ヶ月 経過していないか? Then ' _month = 1 _year = _year + 1 '[年]を更新。 If _year < 100 Then Goto Timecount1 'If 100年 経過していないか? Then _year = 0 ' Timecount1: Return ' ' *********************** ' * LCDに情報を表示する * ' *********************** ' Displcd: On Dispmode Goto Dlmode0 , Dlmode1 , Dlmode2 , Dlmode3 , Dlmode4 , Dlmode5 , Dlmode6 , Dlmode7 , Dlmode8 ' ' * MODE(0) [時・分]を表示 * ' Dlmode0: Temp1 = _min '[分]を表示。 Temp2 = 0 'LCDの右2桁を指定。 Gosub Binsegwr 'バイナリ値を2桁のセグメントコードに変換バッファーに格納する。 Temp1 = _hour '[時]を表示。 Temp2 = 3 'LCDの左2桁をゼロサプレスで指定。 Gosub Hourcvwr '[時]を12時間制でLCDの左2桁に表示する。 If Pmdisp = 0 Then 'If PMの[-]表示が選択されていないか? Then Segminus = 0 '[Minus]セグメントを消灯する。 End If Dlmode01: Colblken = 1 'コロンの点滅を許可する。 Dlmode02: Gosub Segconv 'セグメントコードをSP521PRの接続ポート並びに変換する。 Return ' ' * MODE(1) [分・秒]を表示 * ' Dlmode1: Temp1 = _sec '[秒]を表示。 Temp2 = 0 'LCDの右2桁を指定。 Gosub Binsegwr 'バイナリ値を2桁のセグメントコードに変換してLCD表示する。 Segcode1 = 0 'LCDの左2桁をブランクにする。 Segcode2 = 0 Segminus = 0 '[-]を消灯する。 Goto Dlmode01 ' ' * MODE(2) [温度]を表示 * ' Dlmode2: Tempi1 = Temperature Gosub Thermodisp '温度値を表示する。 Dlmode21: Colblken = 0 'コロンの点滅を禁止する。 Reset Lcddta.3 'コロンを消灯させる。 Goto Dlmode02 ' ' * MODE(3) [ t-c]を表示 * ' Dlmode3: If Autodisptm <> 0 Then 'If [ t-c]の表示期間中か? Then Autodisptm = Autodisptm - 1 Segcode1 = 0 '1桁目を消灯する。 Segcode2 = &B0111_1000 '2桁目に[t]を表示する。 Segcode3 = &B0100_0000 '3桁目に[-]を表示する。 Segcode4 = &B0101_1000 '4桁目に[c]を表示する。 Else Dispmode = 4 End If Segminus = 0 '[-]を消灯する。 Goto Dlmode21 ' ' * MODE(4) [時分]と[温度]を交互表示 * ' Dlmode4: Temp1 = _sec Temp1 = Makebcd(temp1) 'バイナリ値を、BCD(Binary coded decimal)値に変換。 Temp1 = Temp1 And &H0F '下位のBCDコードを取得。 If Temp1 < Timetemp Then Goto Dlmode0 'If [秒]の下位が時刻表示の秒数か? Then Goto Dlmode2 '[秒]の下位が温度表示の秒数の場合。 ' ' * MODE(5) [月・日]を表示 * ' Dlmode5: If Autodisptm <> 0 Then 'If [月・日]の表示期間中か? Then Autodisptm = Autodisptm - 1 Temp1 = _day '[日]を表示。 Temp2 = &H82 'LCDの右2桁をゼロサプレス+小数点付きで指定。 Gosub Binsegwr 'バイナリ値を2桁のセグメントコードに変換してLCD表示する。 Temp1 = _month '[月]を表示。 Temp2 = &H83 'LCDの左2桁をゼロサプレス+小数点付きで指定。 Gosub Binsegwr 'バイナリ値を2桁のセグメントコードに変換してLCD表示する。 Else Dispmode = Modetemp '[SW2]を押す前の表示に戻す。 End If Segminus = 0 '[-]を消灯する。 Goto Dlmode21 ' ' * MODE(6) 温度の最高値を表示 * ' Dlmode6: If Autodisptm <> 0 Then 'If [最高値]の表示期間中か? Then Autodisptm = Autodisptm - 1 Tempi1 = Tempmax Gosub Thermodisp '温度値を表示する。 Else Dispmode = Modetemp '[SW2]を押す前の表示に戻す。 End If Goto Dlmode21 ' ' * MODE(7) 温度の最低値を表示 * ' Dlmode7: If Autodisptm <> 0 Then 'If [最低値]の表示期間中か? Then Autodisptm = Autodisptm - 1 Tempi1 = Tempmin Gosub Thermodisp '温度値を表示する。 Else Dispmode = Modetemp '[SW2]を押す前の表示に戻す。 End If Goto Dlmode21 ' ' * MODE(8) [CLR]を表示 * ' Dlmode8: If Autodisptm <> 0 Then 'If [clr]の表示期間中か? Then Autodisptm = Autodisptm - 1 Segcode1 = 0 '1桁目を消灯する。 Segcode2 = &B0101_1000 '2桁目に[c]を表示する。 Segcode3 = &B0011_1000 '3桁目に[l]を表示する。 Segcode4 = &B0101_0000 '4桁目に[r]を表示する。 Else Dispmode = Modetemp End If Segminus = 0 '[-]を消灯する。 Goto Dlmode21 ' ' ******************************** ' * キー(スイッチ)入力を確認する * (Keyflg = キー入力が有ると1) , (Keydata = キーデータ) ' ******************************** ' Keychk: If Keycun = 0 Then Goto Keychk1 'If キー入力チェック開始か? Then If Keycun < 3 Then Goto Keychk5 'If チャタリング チェック期間か? Then If Keycun = 3 Then Goto Keychk3 'If キー入力再確認か? Then ' Gosub Keyport 'キーオフを確認する。 If Keydata <> Keytemp Then Goto Keychk4 'If キーオフか? Then If Keycun < 103 Then Goto Keychk5 'If リピート期間待ち(1.5Sec)か? Then Keyflg = 2 'リピート入力有り。 Keycun = 92 'リピートを開始。 Return ' ' Keychk1: 'キー入力チェック開始。 Gosub Keyport 'キー接続ポートからデータを入力。 If Keydata <> 0 Then Goto Keychk2 'If キー入力有りか? Then Keychk4: Keycun = 0 Return ' Keychk2: 'キー入力有り。 Keytemp = Keydata 'キー・データを一時保存。 Keychk5: Keycun = Keycun + 1 Return ' Keychk3: 'キー入力再確認。 Gosub Keyport 'キー接続ポートからデータを入力。 If Keydata <> Keytemp Then Goto Keychk4 'If キー入力エラーか? Then Keyflg = 1 Goto Keychk5 ' ' -------------------------------------------------- ' * キー接続ポートからデータを入力するサブルーチン * (Keydat = キー・データ) ' -------------------------------------------------- ' Keyport: Keydata = 0 If Sw_1 = 0 Then Set Keydata.0 'If [SW1]が押されているか? Then If Sw_2 = 0 Then Set Keydata.1 'If [SW2]が押されているか? Then Return ' ' ------------------------------ ' * 温度を計測するサブルーチン * ' ------------------------------ ' Thermo: Start Adc 'A/Dコンバータに電源を供給。 Waitus 150 'A/Dの基準電圧が安定するまでの待ち時間。 Templ1 = Getadc(0) '温度センサー値をA/D変換。 Stop Adc 'A/Dコンバータの電源を切る。 Templ1 = Refvolt * Templ1 '1.100V(較正値)÷1024×1000000×[A/D値]÷1000 Shift Templ1 , Right , 10 , Signed '式を変えて 1.100V(較正値)×1000×[A/D値]÷1024 Temperature = Templ1 - Tempsenofs '温度センサーICの温度変換計算。 ' If Tempmax < Temperature Then 'If 温度の最高値を超えたか? Then Tempmax = Temperature End If ' If Tempmin > Temperature Then 'If 温度の最低値を下回ったか? Then Tempmin = Temperature End If Return ' ' -------------------------------- ' * 温度センサーの係数を選択する * ' -------------------------------- ' Tsentype: If Eeptempsentype = 0 Then 'If 温度センサーは[MCP9700-E/TO]か? Then Tempsenofs = 500 '[MCP9700-E/TO] Else Tempsenofs = 600 '[LM61BIZ] End If Return ' ' -------------------------------- ' * 温度値を表示するサブルーチン * (Tempi1 = 温度値) ' -------------------------------- ' Thermodisp: If Tempi1 >= 0 Then 'If プラスの温度か? Then Segminus = 0 '[-]を消灯する。 Else Segminus = 1 '[-]を表示する。 Tempi1 = Abs(tempi1) '絶対値を求める。 End If ' Gosub Partbin 'バイナリ値を[100の位]と[10と1の位]に分ける。 Segcode3 = Temp9 '10位桁を格納する。 Set Segcode3.7 '3桁目に小数点を表示。 Segcode4 = Temp8 '1位桁を格納する。 ' Temp1 = Tempw1 '100位桁を表示する。 If Temp1 <> 0 Then 'If 10℃以上か? Then Gosub Binseg 'バイナリ値を2桁のセグメントコードに変換する。 Segcode2 = Temp8 '100位桁を格納する。 Else Segcode2 = 0 '100位桁を消灯する。(ゼロサプレス) End If Segcode1 = 0 '左桁を消灯する。 Return ' ' --------------------------------------------- ' * バイナリ値を2桁のセグメントコードに変換し * (Temp1 = バイナリ・データ) ' * バッファーに格納するサブルーチン * (Temp2 = 1: LCDの左2桁へ表示 , 0: LCDの右2桁へ表示) ' --------------------------------------------- (Temp2 = 3: 左2桁へゼロサプレス表示 , 2: 右2桁へゼロサプレス表示) ' (Temp2 = bit7=0: 小数点表示無し , bit7=1: 下位桁に小数点表示する) Binsegwr: Gosub Binseg 'バイナリ値を2桁のセグメントコードに変換する。 ' If Temp2.1 = 1 Then 'If ゼロサプレス有りか? Then If Temp1 < 10 Then 'If バイナリ値が10未満か? Then Temp9 = 0 '上位桁を消灯。 End If End If ' If Temp2.0 = 0 Then 'If LCDの右2桁を指定か? Then Segcode3 = Temp9 '上位桁を格納する。 Segcode4 = Temp8 '下位桁を格納する。 If Temp2.7 = 1 Then 'If 小数点表示有りか? Then Set Segcode4.7 '4桁目に小数点を表示。 End If Else 'LCDの左2桁の場合。 Segcode1 = Temp9 '上位桁を格納する。 Segcode2 = Temp8 '下位桁を格納する。 If Temp2.7 = 1 Then 'If 小数点表示有りか? Then Set Segcode2.7 '2桁目に小数点を表示。 End If End If Return ' ' --------------------------------------- (Temp1 = バイナリ・データ) ' * バイナリ値を2桁のセグメントコードに * (Temp8 = 下位のセグメントコード) ' * 変換するサブルーチン * (Temp9 = 上位のセグメントコード) ' --------------------------------------- (Temp7 = 下位のBCD値) ' Binseg: Temp9 = Makebcd(temp1) 'バイナリ値を、BCD(Binary coded decimal)値に変換。 Temp7 = Temp9 And &H0F '下位のBCDコードを取得。 Temp8 = Lookup(temp7 , Segtab) '数値をセグメントコードへ変換する。 ' Temp9 = Temp9 And &HF0 '上位のBCDコードを取得。 Shift Temp9 , Right , 4 '下位へ移動する。 Temp9 = Lookup(temp9 , Segtab) '数値をセグメントコードへ変換する。 Return ' ' ------------------------------------------------------------- (Tempi1 = 4桁のバイナリ値) ' * 4桁バイナリ値を[100の位]と[10と1の位]に分けるサブルーチン * (Tempw1 = 100の位を保管) ' ------------------------------------------------------------- (Temp8 = 1位のセグメントコード) ' (Temp9 = 10位のセグメントコード) Partbin: Tempw1 = Tempi1 / 100 '100の位を抽出する。(Tempw1) Tempw2 = Tempw1 * 100 '10と1の位を抽出する。(Tempw2) Tempw2 = Tempi1 - Tempw2 Temp1 = Tempw2 Gosub Binseg '10と1の位を2桁のセグメントコードに変換する。 Return ' ' ---------------------------------------------------- ' * [時]を12時間制でLCDの左2桁に表示するサブルーチン * (Temp1 = [時]のバイナリ・データ) ' ---------------------------------------------------- ' Hourcvwr: Temp10 = Temp1 '元データを一時保管する。 If Temp1 = 0 Then Temp1 = 24 '24時間制時刻を12時間制に変換する。 If Temp1 > 12 Then Temp1 = Temp1 - 12 Gosub Binsegwr 'バイナリ値を2桁のセグメントコードに変換バッファーに格納する。 ' Temp1 = Temp10 If Temp1 < 12 Then 'If AM or PM? Segminus = 0 '[Minus]セグメントを消灯する。 Else Segminus = 1 '[Minus]セグメントを点灯する。 End If Return ' ' ************************* ' * 時刻設定 処理ルーチン * ' ************************* ' Timeset: Temp11 = 1 '時刻カウントを停止する。 Segcode1 = 0 '1桁目を消灯する。 Segcode2 = &B1110_1110 '2桁目に[y.]を表示する。 Segcode3 = &B0100_0000 'LCDの右2桁に[-]を表示する。 Segcode4 = &B0100_0000 Segminus = 0 '[-]を消灯する。 Gosub Segconv 'セグメントコードをSP521PRの接続ポート並びに変換する。 Reset Lcddta.3 'コロンを消灯させる。 Gosub Keyoff 'キーが離されるまで待つ。 ' Temp1 = _year '[年]の設定。 Temp2 = 0 'LCDの左2桁を指定。 Temp3 = 0 '設定値の下限。 Temp4 = 99 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 _year = Temp1 ' Temp1 = _day '[月]の設定。 Temp2 = &H82 'LCDの右2桁をゼロサプレス+小数点有りで指定。 Gosub Binsegwr 'バイナリ値を2桁のセグメントコードに変換してLCD表示する。 Temp1 = _month Temp2 = &H83 'LCDの左2桁をゼロサプレス+小数点有りで指定。 Temp3 = 1 '設定値の下限。 Temp4 = 12 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 _month = Temp1 ' Temp1 = _month '[日]の設定。 Temp2 = &H83 'LCDの左2桁をゼロサプレス+小数点有りで指定。 Gosub Binsegwr 'バイナリ値を2桁のセグメントコードに変換してLCD表示する。 Temp1 = _day Temp2 = &H82 'LCDの右2桁をゼロサプレス+小数点有りで指定。 Temp4 = Lookup(_month , Monthtab) '月による設定値の上限を取得する。 If _month = 2 Then 'If 2月か? Then Temp3 = _year And &H03 '閏年の確認。 If Temp3 = 0 Then 'If 閏年か? Then Temp4 = 29 End If End If Temp3 = 1 '設定値の下限。 Gosub Tmskey '時刻設定用のキー入力処理。 _day = Temp1 ' Set Lcddta.3 'コロンを点灯させる。 Temp1 = _min '[時]の設定。 Temp2 = 0 'LCDの左2桁を指定。 Gosub Binsegwr 'バイナリ値を2桁のセグメントコードに変換してLCD表示する。 Temp1 = _hour Temp2 = &H43 'LCDの左2桁をゼロサプレス+小数点有りで指定。 Temp3 = 0 '設定値の下限。 Temp4 = 23 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 _hour = Temp1 ' Temp1 = _hour '[分]の設定。 Temp2 = &H43 'LCDの左2桁をゼロサプレス+小数点有りで指定。 Gosub Hourcvwr '時間を12/24時間制で識別して表示。 Temp1 = _min Temp2 = 0 'LCDの右2桁を指定。 Temp3 = 0 '設定値の下限。 Temp4 = 59 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 _min = Temp1 ' Reset Lcddta.3 'コロンを消灯させる。 Dispmode = 0 '[時・分]表示にする。 Timecun = 0 Time500msf = 0 Time1sf = 0 _sec = 0 '[秒]をリセット。 Return ' ' ------------------------------------ (Temp1 = 設定するデータ値) ' * 時刻設定用 キー入力 サブルーチン * (Temp2 = 設定するデータの桁位置 bit0=0:右2桁 , bit0=1:左2桁 , bit6=0:通常 , bit6=1:[時]12時間制) ' ------------------------------------ (Temp3 = 設定値の下限) ' (Temp4 = 設定値の上限) Tmskey: Temp5 = 1 '点滅用 F/F。 Temp6 = 1 '点滅用タイマー値。 ' Tmskey1: Power Powersave 'スリープモードへ移行する。(64Hz[15.625mS]割り込みで再起動する) Gosub Tset1scun '設定モード用の1秒カウント。 ' Gosub Keychk 'キー入力を確認する。 If Keyflg <> 0 Then Goto Tmskey2 'If キー入力が有りか? Then ' Temp6 = Temp6 - 1 '表示を点滅させる。 If Temp6 <> 0 Then Goto Tmskey1 'If 点滅タイマー カウント終了か? Else If Temp5 = 0 Then '点滅用 F/Fを反転する。 Temp5 = 1 Temp6 = 20 '点滅用のタイマー値。 If Temp2.0 = 0 Then 'If 右2桁を設定中か? Then Segcode3 = 0 'LCDの右2桁をブランクにする。 Segcode4 = 0 Else Segcode1 = 0 'LCDの左2桁をブランクにする。 Segcode2 = 0 End If Else Temp5 = 0 Temp6 = 40 '点滅用のタイマー値。 If Temp2.6 = 1 Then 'If [時]表示か? Then Gosub Hourcvwr '[時]を12時間制でLCDの左2桁に表示する。 Else Gosub Binsegwr 'バイナリ値を2桁のセグメントコードに変換バッファーに格納する。 End If End If Gosub Segconv 'セグメントコードをSP521PRの接続ポート並びに変換する。 Goto Tmskey1 ' ' Tmskey2: Keyflg = 0 'キー入力フラグをリセットする。 If Keydata = &B0000_0001 Then Goto Tmskey4 'If [SW1]が押されたか? Then If Keydata = &B0000_0010 Then Goto Tmskey3 'If [SW2]が押されたか? Then Goto Tmskey1 ' ' Tmskey3: '[SW2] 設定値を加算。 Temp1 = Temp1 + 1 If Temp1 > Temp4 Then 'If 設定値が上限を超えたか? Then Temp1 = Temp3 End If Goto Tmskey ' Tmskey4: '[SW1] 設定終了。 Gosub Keyoff 'キーが離されるまで待つ。 Return ' ' -------------------------------------- ' * キーが離されるまで待つサブルーチン * ' -------------------------------------- ' Keyoff: Gosub Tset1scun '設定モード用の1秒カウント。 Gosub Keyport 'キー接続ポートからデータを入力。 If Keydata <> 0 Then Goto Keyoff 'If キーが離されたか? Else Waitms 30 Return ' ' ------------------------------------------- ' * 設定モード用の1秒カウント・サブルーチン * ' ------------------------------------------- ' Tset1scun: If Time500msf <> 0 Then 'If 500mS経過したか? Then Time500msf = 0 Toggle Time1sf ' If Time1sf <> 0 Then 'If 1秒経過したか? Then If Temp11 = 0 Then 'If 時刻設定中ではないか? Then Gosub Timecount '1秒毎に時刻をカウントする。 End If End If End If Return ' ' *************************** ' * モード設定 処理ルーチン * ' *************************** ' Modeset: Temp11 = 0 '時刻カウントを継続する。 Segcode1 = 0 '1桁目を消灯する。 Segcode2 = &B1000_1001 '2桁目に[最高最低値]を表示する。 Segcode3 = &B0100_0000 'LCDの右2桁に[-]を表示する。 Segcode4 = &B0100_0000 Segminus = 0 '[-]を消灯する。 Gosub Segconv 'セグメントコードをSP521PRの接続ポート並びに変換する。 Reset Lcddta.3 'コロンを消灯させる。 Gosub Keyoff 'キーが離されるまで待つ。 ' Temp1 = Eepextremum '[温度の最高値と最低値の初期化方法]を選択。(0=リセットしない , 1=日付変更時) Temp2 = 2 'LCDの右2桁をゼロサプレスで指定。 Temp3 = 0 '設定値の下限。 Temp4 = 1 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 Eepextremum = Temp1 ' Segcode2 = &B1101_1000 '2桁目に[c.]を表示する。 Temp1 = Eepcolblinksel '[コロンの点滅]を選択。(0=点滅しない , 1=1秒間隔で点滅する) Temp2 = 2 'LCDの右2桁をゼロサプレスで指定。 Temp3 = 0 '設定値の下限。 Temp4 = 1 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 Colblinksel = Temp1 Eepcolblinksel = Temp1 ' Segcode2 = &B1111_0011 '2桁目に[P.]を表示する。 Temp1 = Eeppmdisp '[PMのマイナス表示]を選択。(0=表示しない , 1=[-]で表示する) Temp2 = 2 'LCDの右2桁をゼロサプレスで指定。 Temp3 = 0 '設定値の下限。 Temp4 = 1 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 Pmdisp = Temp1 Eeppmdisp = Temp1 ' Segcode2 = &B1111_1000 '2桁目に[t.]を表示する。 Temp1 = Timetemp '[時分]と[温度]を交互表示の秒数。(1〜9秒) Temp2 = 2 'LCDの右2桁をゼロサプレスで指定。 Temp3 = 1 '設定値の下限。 Temp4 = 9 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 Timetemp = Temp1 Eeptimetemp = Temp1 ' Segcode2 = &B1111_0111 '2桁目に[A.]を表示する。 Temp1 = Eepautodisptm '自動で[SW2]の表示を切り換える秒数。(2〜60秒) Temp2 = 2 'LCDの右2桁をゼロサプレスで指定。 Temp3 = 2 '設定値の下限。 Temp4 = 60 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 Eepautodisptm = Temp1 ' Segcode2 = &B1110_1100 '2桁目に[S.]を表示する。 Temp1 = Eeptempsentype '温度センサーの種別。(0:MCP9700 , 1:LM61) Temp2 = 2 'LCDの右2桁をゼロサプレスで指定。 Temp3 = 0 '設定値の下限。 Temp4 = 1 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 Eeptempsentype = Temp1 Gosub Tsentype '温度センサーの係数を選択する。 ' Start Adc 'A/Dコンバータに電源を供給。 Segcode2 = &B1000_0110 '2桁目に[1.]を表示する。 Temp1 = Eeprefadj 'AVR 1.1V基準電圧の校正値。(1.00〜1.20V) Temp2 = 0 'LCDの右2桁を指定。 Temp3 = 0 '設定値の下限。 Temp4 = 20 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 Eeprefadj = Temp1 Refvolt = Temp1 * 10 'AVRの内部基準電圧較正値を計算する。 Refvolt = Refvolt + 1000 Stop Adc 'A/Dコンバータの電源を切る。 ' Return ' ' ------------------------------------------------------------------- ' * セグメントコードをSP521PRの接続ポート並びに変換するサブルーチン * ' ------------------------------------------------------------------- ' Segconv: $asm LDS R16,{Segcode1} 'セグメントコード・バッファーを読み込む。 LDS R17,{Segcode2} LDS R18,{Segcode3} LDS R19,{Segcode4} LDS R20,{Lcddta} 'LCD接続ポート[Port A]の出力保管用。 LDS R21,{Lcddtb} 'LCD接続ポート[Port B]の出力保管用。 LDS R22,{Lcddtc} 'LCD接続ポート[Port C]の出力保管用。 LDS R23,{Lcddtd} 'LCD接続ポート[Port D]の出力保管用。 ; BST R16,1 '[1bc] BLD R21,2 ; BST R17,0 '[2a] BLD R20,5 BST R17,1 '[2b] BLD R20,4 BST R17,2 '[2c] BLD R21,5 BST R17,3 '[2d] BLD R21,6 BST R17,4 '[2e] BLD R21,7 BST R17,5 '[2f] BLD R20,7 BST R17,6 '[2g] BLD R20,6 BST R17,7 '[2DP] BLD R21,4 ; BST R18,0 '[3a] BLD R22,3 BST R18,1 '[3b] BLD R22,2 BST R18,2 '[3c] BLD R23,1 BST R18,3 '[3d] BLD R23,0 BST R18,4 '[3e] BLD R21,3 BST R18,5 '[3f] BLD R22,4 BST R18,6 '[3g] BLD R20,2 BST R18,7 '[3DP] BLD R23,2 ; BST R19,0 '[4a] BLD R23,7 BST R19,1 '[4b] BLD R23,6 BST R19,2 '[4c] BLD R23,5 BST R19,3 '[4d] BLD R23,4 BST R19,4 '[4e] BLD R23,3 BST R19,5 '[4f] BLD R22,0 BST R19,6 '[4g] BLD R22,1 ; LDS R16,{Segminus} '[Minus] BST R16,0 BLD R21,1 ; STS {Lcddta},R20 'LCD接続ポート[Port A]の出力保管用。 STS {Lcddtb},R21 'LCD接続ポート[Port B]の出力保管用。 STS {Lcddtc},R22 'LCD接続ポート[Port C]の出力保管用。 STS {Lcddtd},R23 'LCD接続ポート[Port D]の出力保管用。 $end Asm Return ' ' *************************************************** ' * Timer2 32.768KHz → 64Hz[15.625mS] 割り込み処理 * ' *************************************************** ' T2int: $asm PUSH R0 IN R0,SREG 'ステータス・レジスタを待避。 PUSH R24 ; SBIS Pinb,0 'If [COMMON]端子が[0]か? Then RJMP t2int01 ; LDS R24,{Lcddta} '[COMMON]端子が[1]の場合。 Out Porta , R24 ; LDS R24,{Lcddtc} Out Portc , R24 ; LDS R24,{Lcddtd} Out Portd , R24 ; LDS R24,{Lcddtb} '[COMMON]端子を[0]にする。 Out Portb , R24 ; LDS R24,{timecun} '500mSをカウントする。 INC R24 CPI R24,16 BRCS t2int02 'If 500mS経過したか? Then STS {time500msf},R24 '500mS経過フラグを立てる。 CLR R24 T2int02: STS {timecun},R24 ; T2int03: POP R24 Out Sreg , R0 'ステータス・レジスタを復帰。 POP R0 $end Asm Return ' ' $asm T2int01: LDS R24,{Lcddta} '[COMMON]端子が[0]の場合。 COM R24 '論理反転する。 ANDI R24,&B1111_1110 'A/Dポートをマスクする。 ORI R24,&B0000_0010 'SW1ポートをプルアップする。 Out Porta , R24 ; LDS R24,{Lcddtc} COM R24 '論理反転する。 ANDI R24,&B0011_1111 'TOSC1,2ポートをマスクする。 ORI R24,&B0010_0000 'SW2ポートをプルアップする。 Out Portc , R24 ; LDS R24,{Lcddtd} COM R24 '論理反転する。 Out Portd , R24 ; LDS R24,{Lcddtb} COM R24 '論理反転する。 Out Portb , R24 '[COMMON]端子を[1]にする。 RJMP t2int03 $end Asm ' ' End ' ' ********************************************* ' * 数値から7セグメントコードへの変換テーブル * ' ********************************************* ' Segtab: Data &B0011_1111 '0 Data &B0000_0110 '1 Data &B0101_1011 '2 Data &B0100_1111 '3 Data &B0110_0110 '4 Data &B0110_1101 '5 Data &B0111_1101 '6 Data &B0000_0111 '7 Data &B0111_1111 '8 Data &B0110_1111 '9 ' ' ************************************ ' * 月ごとの最終日を取得するテーブル * ' ************************************ ' Monthtab: Data 0 , 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31