' ' ************************************************** ' * * ' * SHT11 / DHT22 温度・湿度計 + 時計 プログラム * ' * * ' * AVR is using ATmega168P * ' * Basic Compiler is BASCOM-AVR * ' * Copyright By O-Family 2011.12.24 * ' ************************************************** ' ' Ver 1.01 初回公開バージョン。2011. 9.22 ' Ver 1.02 FT232RL接続時にTXD端子が[H]レベルのままで、バックアップ時間が短くなる。2011.12.24 ' 32.768kHz Xtal調整用の16.384kHz出力モードを追加。 ' ' Const Prgverh = 01 'プログラム・バージョン。(上位桁) Const Prgverl = 02 'プログラム・バージョン。(下位桁) ' ' $regfile = "m168pdef.dat" '使用するAVRを設定。 $crystal = 8000000 'AVRクロックを設定。 ' $hwstack = 64 'ハードウェア・スタックの容量を設定。 $swstack = 10 'ソフトウェア・スタックの容量を設定。 $framesize = 24 'フレーム領域の容量を設定。 ' $baud = 9600 'ハードウェアUARTの通信速度(ボーレート)を設定。 Const Thfdtime = 2 '温度・湿度フェードイン・アウトの時間。(x10mS) Const Mndytime = 300 '時日の表示時間設定。(x10mS) ' ' * ポート名の定義 * ' Sw_1 Alias Pind.5 'スイッチ[1]の接続ポート。 Sw_1pu Alias Portd.5 'スイッチ[1]の接続ポート(プルアップ用)。 Sw_2 Alias Pind.6 'スイッチ[2]の接続ポート。 Sw_2pu Alias Portd.6 'スイッチ[2]の接続ポート(プルアップ用)。 Sw_3 Alias Pind.7 'スイッチ[3]の接続ポート。 Sw_3pu Alias Portd.7 'スイッチ[3]の接続ポート(プルアップ用)。 Led_segstb Alias Portb.2 'LEDのセグメント用[NJU3711D]の[/STB]ポート。 Led_segstb_p Alias Portb Led_segstb_b Alias 2 Const Led_comc0 = &B1100_0011 'LEDのコモンポート[C]を0にするビット位置。 Const Led_comc1 = &B0011_1100 'LEDのコモンポート[C]を1にするビット位置。 Const Led_comd0 = &B1110_0010 'LEDのコモンポート[D]を0にするビット位置。 Const Led_comd1 = &B0001_1101 'LEDのコモンポート[D]を1にするビット位置。 Pt_power Alias Pinc.1 '電源電圧監視用のポート。 Ad_power Alias 1 '電源電圧監視用A/Dコンバータのチャネル番号。 Pt_cds Alias Portc.0 'CDSセンサーを[L]制御するポート。 Thsen_do Alias Portb.0 '温度湿度センサーの[DATA]ポート。 Thsen_di Alias Pinb.0 '温度湿度センサーの[DATA]ポート。 Thsen_di_p Alias Pinb Thsen_di_b Alias 0 Thsen_sck Alias Portb.1 '温度湿度センサーの[SCK]ポート。 Excont_1in Alias Pinb.4 '外部制御[入力1]端子。 ' ' * LEDのセグメント・コードを指定する * ' Const Seg_blank = &B1111_1111 '[空白] Const Seg_minus = &B1011_1111 '[-] Const Seg_t = &B1000_0111 '[t] Const Seg_h = &B1000_1011 '[h] Const Seg_c = &B1010_0111 '[c] Const Seg_e = &B1000_0110 '[E] Const Seg_r = &B1010_1111 '[r] Const Seg_percent = &B1010_1101 '[%] Const Seg_am = &B1101_1111 '[AM] Const Seg_pm = &B1110_1111 '[PM] Const Seg_dpon = &B0111_1111 '[D.P On] Const Seg_dpoff = &B1000_0000 '[D.P Off] ' ' * 変数の宣言 * ' Dim Dispmode As Byte '表示モード。 Dim Modetemp As Byte '表示モードの保管用。 Dim Sectemp As Byte '[秒]更新用テンポラリ。 Dim Mintemp As Byte '[分]更新用テンポラリ。 Dim Daytemp As Byte '[日]更新用テンポラリ。 Dim Dpblken As Byte 'D.P点滅許可フラグ。 Dim Tim500ms As Byte '500mSタイマー。 Dim Brightchf As Byte 'LEDの表示輝度変更フラグ。 Dim Swsleep As Byte 'スイッチでスリープしている状態フラグ。 Dim Keycun As Byte 'キー入力チェック用タイマーカウンター。 Dim Keyflg As Byte 'キー入力検出フラグ。 Dim Keydata As Byte 'キー入力データ。 Dim Keytemp As Byte 'キー入力用テンポラリ。 Dim Thdstime As Word '温度・湿度フェード表示中の固定表示時間。(x10mS) Dim Fadedsf As Byte 'フェード表示フラグ。 Dim Fdtimer As Word 'フェード表示中の固定表示時間タイマー。(x10mS) Dim Thdssel As Byte 'フェード表示中の温度/湿度選択。 Dim Thmeaf As Byte '温度と湿度の計測開始フラグ。 Dim Temperature As Integer '温度値。(x0.1) Dim Humidity As Word '湿度値。(x0.1) Dim Tempmax As Integer '温度の最高値。(x0.1) Dim Tempmin As Integer '温度の最低値。(x0.1) Dim Hummax As Word '湿度の最高値。(x0.1) Dim Hummin As Word '湿度の最低値。(x0.1) ' Dim Led_counter As Byte 'ダイナミック点灯の桁カウンター。 Dim Led_buff(8) As Byte 'ダイナミック点灯のセグメントデータ。 Dim Dimmer As Byte '輝度の調光値。 Dim Bright1 As Byte 'LED1〜4の輝度調整用Timer値。 Dim Bright2 As Byte 'LED5〜8の輝度調整用Timer値。 ' Dim Mf1224h As Byte '時間表示モード 0=12時間制 , 1=24時間制 Dim Sentype As Byte 'センサーの種別。(1=SHT11 , 2=DHT22) Dim Extremum As Byte '最高最低値のリセット選択。 (0=リセットしない , 1=日付変更時 , 2=強制リセット) Dim Seritime As Byte 'シリアル出力の間隔。(1=1秒 , 2=1分) ' Dim Thsen_rxbuf(6) As Byte '[DHT22][SHT11]の受信バッファー。 Dim Thsen_err As Byte '[DHT22][SHT11]のエラーフラグ。 Dim Thsen_timer As Byte '[DHT22]の信号期間タイマー。 ' Dim Sht11_sta As Byte 'SHT11の起動状態。(0:待機中, 1:測定中) Dim Rh As Single '湿度の補正値保管用。 Dim Tso As Single '湿度の補正値保管用。 Dim Trh As Single '湿度の補正値保管用。 ' 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 Tempw1 As Word '汎用テンポラリ変数 Word型 No.1 Dim Tempw2 As Word '汎用テンポラリ変数 Word型 No.2 Dim Tempw3 As Word '汎用テンポラリ変数 Word型 No.3 Dim Tempi1 As Integer '汎用テンポラリ変数 Integer型 No.1 Dim Tempseg1 As Byte 'セグメントデータ保管用 (1桁) Dim Tempseg2 As Byte 'セグメントデータ保管用 (10桁) Dim Tempseg3 As Byte 'セグメントデータ保管用 (100桁) Dim Tempseg4 As Byte 'セグメントデータ保管用 (1000桁) Dim Tempstr As String * 11 '汎用テンポラリ変数 String型 No.1 ' Dim Dummy As Eram Long '4バイトのダミーエリア。 Dim Eep1224h As Eram Byte 'EEPROM 時間表示モード (0=12時間制 , 1=24時間制) Dim Eepsentype As Eram Byte 'EEPROM センサーの種別 (1=SHT11 , 2=DHT22) Dim Eepthdstime As Eram Byte 'EEPROM 温度・湿度フェード表示中の固定表示時間。(秒) Dim Eepextremum As Eram Byte 'EEPROM 最高最低値のリセット選択。 (0=リセットしない , 1=日付変更時) Dim Eepseritime As Eram Byte 'EEPROM シリアル出力の間隔。(1=1秒 , 2=1分) ' ' * ポートの初期設定 * ' Config Clockdiv = 1 'AVRの動作クロックを8MHzに変更する。 Reset Ucr.rxen0 'USART受信許可を取り消す(禁止)。 Gosub Portinit 'ポートの初期設定を行う。 If Sw_3 = 0 Then Goto Xtalcal 'If 32.768KHz 水晶較正モードか? Then Gosub Inispi 'ハードウェアSPIの初期設定を行う。 ' ' * スイッチ割り込みの設定 * ' On Pcint2 Swint Nosave 'スイッチ割り込みルーチンのラベルを設定。 Set Pcmsk2.5 '[SW1](PD5)割り込みを有効にする。 ' ' * Timerの設定 * ' Config Timer0 = Timer , Prescale = 64 , Clear Timer = 1 'LEDのDMA用 8,000,000Hz / 64 = 125,000Hz Compare0a = 125 - 1 'スキャン周波数。(125,000Hz ÷ 125カウント = 1,000Hz) Bright1 = 120 'パルス幅 (暗0〜明120) 1カウントは8μS。 Bright2 = 120 'パルス幅 (暗0〜明120) 1カウントは8μS。 On Compare0a Tint0a Nosave 'TIMER0比較一致A割り込みルーチンのラベルを設定。 Enable Compare0a 'TIMER0比較一致A割り込みを許可。 On Compare0b Tint0b Nosave 'TIMER0比較一致B割り込みルーチンのラベルを設定。 Enable Compare0b 'TIMER0比較一致B割り込みを許可。 ' Config Timer1 = Timer , Prescale = 8 , Clear Timer = 1 '10mSタイマー 8,000,000Hz / 8 = 1,000,000Hz Compare1a = 10000 - 1 '1,000,000Hz / 10,000 = 100Hz (10mS) ' ' * A/Dコンバーターの設定 * ' Config Adc = Single , Prescaler = Auto , Reference = Avcc 'A/Dコンバータの設定。 Start Adc 'A/Dコンバータに電源を供給。 Config Aci = Off 'アナログ比較器の電源を切る。 ' ' * 時計用のライブラリを組み込む * ' Config Clock = Soft '時計(Timer2を使用)をSoftモードに設定。 Config Date = Ymd , Separator = / '日付の表現方法(形式)を設定。 ' ' * EEPROMのデータを確認する * ' If Eep1224h > 1 Then 'If EEPROMが初期値か? Then Eep1224h = 0 '時間表示モードを[12時間制]に設定する。 Eepsentype = 1 'センサーの種別をSHT11に設定する。 Eepthdstime = 4 '温度・湿度フェード表示中の固定表示時間。(4秒) Eepextremum = 1 '最高最低値のリセット選択。 (1=日付変更時) Eepseritime = 1 'シリアル出力の間隔。(1=1秒 , 2=1分) End If Mf1224h = Eep1224h 'EEPROM値を変数に読み込む。 Sentype = Eepsentype Temp1 = Eepthdstime Thdstime = Temp1 * 100 Extremum = Eepextremum Seritime = Eepseritime ' ' * 変数の初期設定 * ' Thsen_rxbuf(1) = 0 'ステータスレジスタのデフォルト値。 Thsen_rxbuf(2) = &B0000_0101 '測定コマンドの初期値。(湿度) Sht11_sta = 0 'SHT11の起動状態。(待機中) Led_counter = 0 'ダイナミック点灯の桁カウンター初期値。 Dimmer = 120 'LEDの輝度調光値を最大に設定する。 Dispmode = 1 '表示モードの初期値。 Sectemp = 255 '[秒]の更新テンポラリの初期化。 Mintemp = 255 '[分]の更新テンポラリの初期化。 Tempmax = -400 '温度の最高値を初期化する。 Tempmin = 1250 '温度の最低値を初期化する。 Hummax = 0 '湿度の最高値を初期化する。 Hummin = 1000 '湿度の最低値を初期化する。 _year = 11 _month = 1 _day = 1 Daytemp = _day '[日]の更新テンポラリの初期化。 Gosub Displed 'LEDの初期値を表示する。 Enable Interrupts 'すべての割り込みを許可。 ' Print : Print 'シリアル出力を初期化(改行)する。 ' ' ******************* ' * メイン ルーチン * ' ******************* ' Main: Gosub Expower '外部電源の電圧を監視する。(スリープモードに移行する) Gosub Dispren1s '1秒ごとに表示を更新する。 Gosub Every10ms '10mSごとの処理を行う。(キーチェック) Gosub Keycont 'キー入力により表示を切り換える。 Gosub Ledbright 'LEDの輝度を調整する。 Gosub Thmeasur '温度と湿度をセンサーから計測する。 Goto Main ' ' **************************************** ' * 1秒ごとにLEDの表示を更新するルーチン * ' **************************************** ' Dispren1s: If Sectemp = _sec Then Return 'If [秒]が更新されたか? Else Sectemp = _sec Tim500ms = 0 '500mSタイマーを初期化。 ' If Extremum <> 0 Then 'If 温度湿度の最高最低値を日付変更時に初期化するか? Then If Daytemp <> _day Then 'If 日付が変わったか? Then Daytemp = _day Gosub Rstmaxmin '温度と湿度の最高値と最低値を初期化する。 End If End If ' ' * シリアル出力に送信する間隔を確認する * ' If Seritime = 1 Then 'If 送信間隔が1秒か? Then Gosub Seriout 'シリアル出力に測定値を送信する。 Else If Mintemp <> _min Then 'If 1分経過したか? Then Mintemp = _min Gosub Seriout 'シリアル出力に測定値を送信する。 End If End If ' ' * LEDに情報を表示する * ' Displed: On Dispmode Goto Dsmode0 , Dsmode1 , Dsmode2 , Dsmode3 , Dsmode4 , Dsmode5 , Dsmode6 , Dsmode7 , Dsmode8 ' ' * MODE(0) 表示オフ * ' Dsmode0: Return ' ' * MODE(1) 上段[時分]・下段[温度/湿度を交互] 表示 * ' Dsmode1: If Fadedsf = 0 Then 'If フェード動作以外のモードか? Then Led_buff(5) = Seg_t '[t-h]を表示する。 Led_buff(6) = Seg_minus Led_buff(7) = Seg_h Led_buff(8) = Seg_blank Fadedsf = 1 '固定表示中に設定。 Fdtimer = 10 '固定表示時間のタイマーを設定する。 Thdssel = 1 '次は温度からフェード表示する。 End If ' Dsmode11: Temp1 = _hour '[時]を表示。 Gosub Hourconv '時間 12/24時間制を識別変換する。 Led_buff(1) = Tempseg2 '上位のセグメントコードを書き込む。 Led_buff(2) = Tempseg1 '下位のセグメントコードを書き込む。 Temp1 = _min '[分]を表示。 Gosub Binseg 'バイナリ値を2桁のセグメントコードに変換する。 Led_buff(3) = Tempseg2 '上位のセグメントコードを書き込む。 Led_buff(4) = Tempseg1 '下位のセグメントコードを書き込む。 ' If Tim500ms < 50 Then 'If [D.P]点灯期間か? Then Led_buff(2) = Led_buff(2) And Seg_dpon '3桁目に小数点を表示。 End If Dpblken = 1 '[D.P]の点滅を許可する。 Return ' ' * MODE(2) 上段[時分]・下段[秒] 表示 * ' Dsmode2: Temp1 = _sec '下段に[秒]を表示。 Gosub Binseg 'バイナリ値を2桁のセグメントコードに変換する。 Led_buff(7) = Tempseg2 '上位のセグメントコードを書き込む。 Led_buff(8) = Tempseg1 '下位のセグメントコードを書き込む。 Led_buff(5) = Seg_blank Led_buff(6) = Seg_blank Goto Dsmode11 ' ' * MODE(3) 上段[時分]・下段[温度] 表示 * ' Dsmode3: Gosub Tempdispl '下段に[温度]を表示する。 Goto Dsmode11 ' ' * MODE(4) 上段[時分]・下段[湿度] 表示 * ' Dsmode4: Gosub Humidispl '下段に[湿度]を表示する。 Goto Dsmode11 ' ' * MODE(5) 上段[温度]・下段[湿度] 表示 * ' Dsmode5: Tempw1 = Temperature '上段に[温度]を表示する Gosub Tempdispu 'LED上段に温度を表示する。 ' Gosub Humidispl '下段に[湿度]を表示する。 Return ' ' * MODE(6) 上段[時分]・下段[月日] 表示 * ' Dsmode6: Temp1 = _month '[月]を表示。 Gosub Binsegzs 'バイナリ値を2桁のセグメントコードに変換する。 Led_buff(5) = Tempseg2 '上位のセグメントコードを書き込む。 Led_buff(6) = Tempseg1 '下位のセグメントコードを書き込む。 Temp1 = _day '[日]を表示。 Gosub Binsegzs 'バイナリ値を2桁のセグメントコードに変換する。 Led_buff(7) = Tempseg2 '上位のセグメントコードを書き込む。 Led_buff(8) = Tempseg1 '下位のセグメントコードを書き込む。 Goto Dsmode11 ' ' * MODE(7) 上段[温度最高値]・下段[温度最低値] 表示 * ' Dsmode7: Tempw1 = Tempmax '上段に[温度最高値]を表示する Gosub Tempdispu 'LED上段に温度を表示する。 ' Tempw1 = Tempmin '上段に[温度最低値]を表示する Gosub Tempdispl1 'LED下段に温度を表示する。 Return ' ' * MODE(8) 上段[湿度最高値]・下段[湿度最低値] 表示 * ' Dsmode8: Tempw1 = Hummax '上段に[湿度最高値]を表示する Gosub Humidispu 'LED上段に湿度を表示する。 ' Tempw1 = Hummin '上段に[湿度最低値]を表示する Gosub Humidispl1 'LED下段に湿度を表示する。 Return ' ' --------------------------------------- ' * LED上段に温度を表示するサブルーチン * (Tempw1 = 温度値) ' --------------------------------------- ' Tempdispu: Gosub Wordsegdp 'Word値を4桁のセグメント値に変換する。 Led_buff(4) = Seg_c '単位[c]を表示する。 Tempdispu1: Led_buff(1) = Tempseg3 Led_buff(2) = Tempseg2 Led_buff(3) = Tempseg1 Dpblken = 0 '[D.P]の点滅を禁止する。 Return ' ' --------------------------------------- ' * LED下段に温度を表示するサブルーチン * ' --------------------------------------- ' Tempdispl: If Thsen_err <> 0 Then Goto Tempdispl3 'If センサーのエラー発生か? Then Tempw1 = Temperature Tempdispl1: Gosub Wordsegdp 'Word値を4桁のセグメント値に変換する。 Led_buff(8) = Seg_c '単位[c]を表示する。 Tempdispl2: Led_buff(5) = Tempseg3 Led_buff(6) = Tempseg2 Led_buff(7) = Tempseg1 Return ' ' Tempdispl3: 'エラーが発生した場合。 Led_buff(5) = Seg_e '[E] Led_buff(6) = Seg_r '[r] Led_buff(7) = Seg_r '[r] Led_buff(8) = Lookup(thsen_err , Segtab) 'エラー番号。 Return ' ' --------------------------------------- ' * LED上段に湿度を表示するサブルーチン * (Tempw1 = 湿度値) ' --------------------------------------- ' Humidispu: Gosub Wordsegdp 'Word値を4桁のセグメント値に変換する。 Led_buff(4) = Seg_percent '単位[/]を表示する。 Goto Tempdispu1 ' ' --------------------------------------- ' * LED下段に湿度を表示するサブルーチン * ' --------------------------------------- ' Humidispl: If Thsen_err <> 0 Then Goto Tempdispl3 'If センサーのエラー発生か? Then Tempw1 = Humidity Humidispl1: Gosub Wordsegdp 'Word値を4桁のセグメント値に変換する。 Led_buff(8) = Seg_percent '単位[/]を表示する。 Goto Tempdispl2 ' ' ************************************************ ' * 10mSごとに処理を行うルーチン (キーチェック)* ' ************************************************ ' Every10ms: If Tifr1.ocf1a = 0 Then Return 'If 10mS経過したか? Else Set Tifr1.ocf1a 'Timer1 比較A一致フラグをリセット。 ' Tim500ms = Tim500ms + 1 '500mSタイマーを加算。 Select Case Tim500ms Case 50 : '[D.P]点灯から500mS経過した。 Thmeaf = Thmeaf + 1 '温度と湿度の計測開始を指示する。 If Dpblken = 1 Then 'If [D.P]の点滅が許可されているか? Then Led_buff(2) = Led_buff(2) Or Seg_dpoff '3桁目の小数点を消灯する。 End If Case 25 : '500mSごとにLEDの輝度を調整する。 Brightchf = 1 Case 75 : '500mSごとにLEDの輝度を調整する。 Brightchf = 1 End Select ' Gosub Fadedsp '温度/湿度をフェード表示する。 ' ' * キー入力を確認する * (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 リピート期間待ち(1Sec)か? Then Keyflg = 1 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 If Sw_3 = 0 Then Set Keydata.2 'If [SW3]が押されているか? Then Return ' ' ****************************************** ' * キー入力により表示を切り換えるルーチン * ' ****************************************** ' Keycont: If Keyflg = 0 Then Return 'If キー入力が有ったか? Else Keyflg = 0 Fadedsf = 0 'フェード動作を停止する。 Bright2 = Dimmer 'LEDの輝度調光値を戻す。 ' If Keydata = &B00000001 Then Goto Keyslp '[SW1]が押された(スリープに入る)か? Then Select Case Keydata Case &B00000010 : '[SW2]が押された場合。 If Dispmode > 5 Then 'If [月日]or[最高最低値]表示中か? Then Dispmode = Modetemp '以前の状態に戻す。 Else Dispmode = Dispmode + 1 If Dispmode > 5 Then 'If 表示モードの上限か? Then Dispmode = 1 End If End If ' Case &B00000100 : '[SW3]が押された場合。 Select Case Dispmode Case 6 : Dispmode = 7 '[温度の最高最低値]表示にする。 Case 7 : Dispmode = 8 '[湿度の最高最低値]表示にする。 Case 8 : 'If [湿度の最高最低値]表示中か? Then Dispmode = Modetemp '以前の状態に戻す。 Case Else : Modetemp = Dispmode '現在のモードを保管する。 Dispmode = 6 '[月日]表示にする。 Fadedsf = 1 '固定表示中に設定。 Fdtimer = Mndytime '固定表示時間のタイマーを設定する。 End Select ' Case &B00000011 : '[SW1+SW2]が押された場合。 Gosub Modeset 'モード設定処理。 ' Case &B00000101 : '[SW1+SW3]が押された場合。 Gosub Timeset '時刻設定処理。 ' Case &B00000110 : '[SW2+SW3]が押された場合。 Toggle Mf1224h.0 '時間表示モードを変更。 Eep1224h = Mf1224h 'EEPROMに保存する。 ' End Select Gosub Displed 'LEDに情報を表示する。 Return ' ' ******************************************** ' * 温度と湿度をセンサーから計測するルーチン * ' ******************************************** ' Thmeasur: If Sentype = 2 Then 'If センサーがDHT22か? Then If Thmeaf > 1 Then 'If 2秒経過したか? Then Thmeaf = 0 Gosub Thsen_dht22 '[DHT22]の湿度・温度を測定する。(2秒間隔で計測する) End If Else 'SHT11の場合。 Gosub Sht11_measure 'SHT11の温度・湿度 測定処理。 End If Return ' ' ****************************** ' * DHT22の湿度・温度 測定処理 * (Temperature = 温度データ , Humidity = 湿度データ) ' ****************************** (Thsen_err = [DHT22]の通信状態) ' Thsen_dht22: Config Thsen_do = Output '[DHT22]に[スタート信号]を送信する。 Waitms 1 '1mSの信号幅を維持する。 Config Thsen_do = Input '[DHT22]のDATAポートを入力にする。(プルアップで[H]) Gosub Thsen_loin '[DHT22]からの[L]信号を待つ。(センサーからの応答信号を待つ) If Thsen_err <> 0 Then Goto Thsen_dht223 'If エラーが発生したか? Then ' Temp1 = 1 '5バイト(40bit)のデータを受信する。 Thsen_dht221: Temp2 = 8 '8bitカウンター。 Temp3 = 0 'bitデータを保管用。 Thsen_dht222: Gosub Thsen_loin '[DHT22]からの[L]信号を待つ。(ビットの同期信号を受信する) If Thsen_err <> 0 Then Goto Thsen_dht223 'If エラーが発生したか? Then Gosub Thsen_hiin '[DHT22]からの[H]信号の長さを計測する。 If Thsen_err <> 0 Then Goto Thsen_dht223 'If エラーが発生したか? Then ' Temp3 = Temp3 + Temp3 'bitデータを左へシフトする。(Shift Temp3 , Left , 1) If Thsen_timer > 13 Then 'If [DATA]が[1]か? Then Set Temp3.0 End If Temp2 = Temp2 - 1 If Temp2 <> 0 Then Goto Thsen_dht222 'If 8ビット受信終了か? Else ' Thsen_rxbuf(temp1) = Temp3 '受信バッファーへ格納する。 Temp1 = Temp1 + 1 If Temp1 < 6 Then Goto Thsen_dht221 'If 5バイト受信終了か? Else ' Temp2 = 0 'チェックサムを合計する。 For Temp1 = 1 To 4 Temp2 = Temp2 + Thsen_rxbuf(temp1) Next Temp1 If Temp2 = Thsen_rxbuf(5) Then 'If チェックサムが一致したか? Then Temperature = Makeint(thsen_rxbuf(4) , Thsen_rxbuf(3)) '2バイトの受信データを1ワードに変換する。 Gosub Tmaxmin '温度の最高値と最低値を確認する。 Humidity = Makeint(thsen_rxbuf(2) , Thsen_rxbuf(1)) '2バイトの受信データを1ワードに変換する。 Gosub Hmaxmin '湿度の最高値と最低値を確認する。 Else Thsen_err = 2 'チェックサム(CRC)エラーが発生した。 End If Thsen_dht223: Return ' ' * [DHT22]からの[L]信号を待つサブルーチン * ( H -> L -> H) ' Thsen_loin: Gosub Thsen_hiin '[DHT22]からの[H]信号の長さを計測する。(DATAが[L]になるのを待つ) If Thsen_err <> 0 Then Return 'If エラーが発生したか? Then ' $asm 'DATAが[H]になるのを検出する。 CLR R24 'Thsen_timer = 0 Thsen_loin1: @genus(2) '10uSの待ち時間。 INC R24 SBIC Thsen_di_p , Thsen_di_b 'If [DHT22]のDATAが[L]か? Then RJMP Thsen_loin2 '[DHT22]のDATAが[H]になった。 ; CPI R24,50 BRCS Thsen_loin1 'If タイムアウト(100uS)が発生していないか? Then LDI R25,$01 'タイムアウトエラーが発生。 Thsen_loin3: STS {Thsen_err},R25 RET ; Thsen_loin2: '[DHT22]のDATAが[H -> L -> H]の信号を検出完了。 STS {Thsen_timer} ,R24 CLR R25 RJMP Thsen_loin3 $end Asm ' ' * [DHT22]からの[H]信号の長さを計測するサブルーチン * (thsen_timer = [H]信号の長さ x 10uS) ' Thsen_hiin: $asm CLR R24 'Thsen_timer = 0 Thsen_hiin1: @genus(2) '10uSの待ち時間。 INC R24 SBIS Thsen_di_p , Thsen_di_b 'If [DHT22]のDATAが[H]か? Then RJMP Thsen_hiin2 '[DHT22]のDATAが[L]になった。 ; CPI R24,50 BRCS Thsen_hiin1 'If タイムアウト(100uS)が発生していないか? Then LDI R25,$01 'タイムアウトエラーが発生。 Thsen_hiin3: STS {Thsen_err},R25 RET ; Thsen_hiin2: '[DHT22]のDATAが[L]になったのを検出完了。 STS {Thsen_timer} ,R24 CLR R25 RJMP Thsen_hiin3 $end Asm ' ' ****************************** ' * SHT11の温度・湿度 測定処理 * (Temperature = 温度データ , Humidity = 湿度データ) ' ****************************** (Thsen_err = [SHT11]の通信状態) ' Sht11_measure: If Sht11_sta <> 0 Then Goto Sht11_mea1 'If SHT11の測定中か? Then If Thmeaf = 0 Then Return 'If 1秒経過していないか? Then ' Thmeaf = 0 Gosub Sht11_start 'SHT11に[Tr Start]通信開始シーケンスを送信する。 If Thsen_rxbuf(2) = &B0000_0101 Then 'If 前回の測定が(湿度)か? Then Temp1 = &B0000_0011 '温度測定コマンド。 Else Temp1 = &B0000_0101 '湿度測定コマンド。 End If Gosub Sht11_comtx 'SHT11にコマンドを送信する。 ' If Thsen_err <> 0 Then Goto Sht11_mea21 'If 通信エラー(ACKが返らない)か? Then Sht11_sta = 1 'SHT11の起動状態を[測定中]に変更する。 Return ' ' * SHT11 測定中の処理 * ' Sht11_mea1: If Thmeaf <> 0 Then Goto Sht11_mea23 'If 測定開始から1秒経過したか(タイムアウト)? Then If Thsen_di = 1 Then Return 'If SHT11が測定中か? Then ' ' * SHT11 測定終了で温度・湿度データを受信する * ' Gosub Sht11_datarx 'SHT11からデータを3バイト受信する。 Gosub Sht11_crc 'SHT11用のCRC8を計算する。 If Thsen_rxbuf(5) <> Thsen_rxbuf(6) Then Goto Sht11_mea22 'If CRCエラーか? Then ' Tempw1 = Makeint(thsen_rxbuf(4) , Thsen_rxbuf(3)) '2バイトの受信データを1ワードに変換する。 If Thsen_rxbuf(2) = &B0000_0011 Then 'If 測定結果は(温度)か? Then ' ' * 温度値の変換と電源電圧補正 * (T = d1 + d2 * SOT) ' Const D1 = -40.1 'Vdd = 5V Const D2 = 0.01 ' Trh = D2 * Tempw1 'SHT11の電源電圧により温度値を係数で補正する。 Trh = D1 + Trh 'T = d1 + d2 * SO ' Tso = Trh * 10 '小数点以下を1桁に変更する。 Temperature = Int(tso) '整数化する。 Gosub Tmaxmin '温度の最高値と最低値を確認する。 Else ' ' * 湿度センサーの非線形性を補正する (V4) * (SO = Tempw1) ' Const C1 = -2.0468 'C1 = -2.0468 Const C2 = 0.0367 'C2 = 0.0367 Const C3 = -1.5955e-6 'C3 = -1.5955E-6 ' Rh = C2 * Tempw1 'RH = C1 + C2 * SO + C3 * (SO * SO) Rh = C1 + Rh Tso = Tempw1 * Tempw1 Tso = C3 * Tso Rh = Rh + Tso ' ' * 湿度値の温度補償をする * ' Const T1 = 0.01 'T1 = 0.01 Const T2 = 0.00008 'T2 = 0.00008 ' Trh = Trh - 25 'RH = (Temperature - 25) * (T1 + T2 * SO) + RH Tso = T2 * Tempw1 Tso = T1 + Tso Trh = Trh * Tso Rh = Trh + Rh If Rh > 100 Then 'If 湿度が100%を越えたか? Then Rh = 100 End If ' Rh = Rh * 10 '小数点以下を1桁に変更する。 Humidity = Int(rh) '整数化する。 Gosub Hmaxmin '湿度の最高値と最低値を確認する。 End If ' Sht11_mea3: Sht11_sta = 0 'SHT11の起動状態を[待機中]に戻す。 Return ' ' Sht11_mea21: '通信エラー(ACKが返らない)処理。 Gosub Sht11_rst 'SHT11との通信をリセットする。 Goto Sht11_mea3 ' ' Sht11_mea22: 'チェックサム(CRC)エラー。 Thsen_err = 2 Goto Sht11_mea21 ' ' Sht11_mea23: 'タイムアウト・エラー。 Thsen_err = 3 Thmeaf = 0 Goto Sht11_mea21 ' ' * SHT11に、[Tr Start] 通信開始シーケンスを送信する * ' Sht11_start: Gosub Sht11_dh 'SHT11のDATAを[H]にする。 Gosub Sht11_ch 'SHT11のSCKを[H]にする。 Gosub Sht11_dl 'SHT11のDATAを[L]にする。 Gosub Sht11_cl 'SHT11のSCKを[L]にする。 Gosub Sht11_ch 'SHT11のSCKを[H]にする。 Gosub Sht11_dh 'SHT11のDATAを[H]にする。 Gosub Sht11_cl 'SHT11のSCKを[L]にする。 Return ' ' * SHT11に、コマンドを送信する * [Temp1 = コマンド] ' Sht11_comtx: Thsen_rxbuf(2) = Temp1 'CRC計算にコマンドを追加する。 For Temp2 = 0 To 7 '1バイトのコマンドを送信する。 If Temp1.7 = 0 Then 'If 送信するビットが[0]か ? Then Gosub Sht11_dl 'SHT11のDATAを[L]にする。 Else '送信するビットが[1]。 Gosub Sht11_dh 'SHT11のDATAを[H]にする。 End If Gosub Sht11_ch 'SHT11のSCKを[H]にする。 Gosub Sht11_cl 'SHT11のSCKを[L]にする。 Temp1 = Temp1 + Temp1 'Shift Temp1 , Left , 1 Next Temp2 Gosub Sht11_dh 'SHT11のDATAを[H]にする。 ' '[ACK]の受信。 Gosub Sht11_ch 'SHT11のSCKを[H]にする。 If Thsen_di = 0 Then 'If [ACK]が返ったか? Then Thsen_err = 0 Else Thsen_err = 1 '[ACK]エラー。 End If Gosub Sht11_cl 'SHT11のSCKを[L]にする。 Return ' ' * SHT11から、データを3バイト受信する * [thsen_rxbuf(3,4,5) = 受信データ] ' Sht11_datarx: For Temp3 = 1 To 3 '3バイトのデータを受信する。 Temp1 = 0 For Temp2 = 0 To 7 '8ビットのデータを受信する。 Temp1 = Temp1 + Temp1 'Shift Temp1 , Left , 1 Gosub Sht11_ch 'SHT11のSCKを[H]にする。 If Thsen_di = 1 Then 'If [DATA]が[1]か? Then Set Temp1.0 End If Gosub Sht11_cl 'SHT11のSCKを[L]にする。 Next Temp2 Thsen_rxbuf(temp3 + 2) = Temp1 '受信データをバッファに格納する。 ' If Temp3 < 3 Then 'If [ACK]の送信か? Then Gosub Sht11_dl 'SHT11のDATAを[L]にする。 Else '[ACK]をスキップする。 Gosub Sht11_dh 'SHT11のDATAを[H]にする。 End If Gosub Sht11_ch 'SHT11のSCKを[H]にする。 Gosub Sht11_cl 'SHT11のSCKを[L]にする。 Gosub Sht11_dh 'SHT11のDATAを[H]にする。 Next Temp3 Return ' ' * SHT11との通信をリセットする * ' Sht11_rst: Gosub Sht11_dh 'SHT11のDATAを[H]にする For Temp1 = 1 To 10 Gosub Sht11_ch 'SHT11のSCKを[H]にする。 Gosub Sht11_cl 'SHT11のSCKを[L]にする。 Next Temp1 Return ' ' * SHT11の[SCK]を[L]にする * ' Sht11_cl: Reset Thsen_sck 'SHT11のSCKを[L]にする。 Sht11_wait: Waitus 100 'クロックとデータのパルス幅。 Return ' ' * SHT11の[SCK]を[H]にする * ' Sht11_ch: Set Thsen_sck 'SHT11のSCKを[H]にする。 Goto Sht11_wait ' ' * SHT11の[DATA]を[L]にする * ' Sht11_dl: Config Thsen_do = Output 'SHT11のDATAを[L]にする。 Goto Sht11_wait ' ' * SHT11の[DATA]を[H]にする * ' Sht11_dh: Config Thsen_do = Input 'SHT11のDATAを[H]にする。 Goto Sht11_wait ' ' * SHT11用のCRC8を計算する * ' Sht11_crc: Loadadr Thsen_rxbuf(1) , Z $asm LDI R24,$04 '計算するバイト数。 CLR R16 LDI R22,$8C Sht11_crc1: LD R23,Z+ LDI R25,$08 Sht11_crc2: LSR R16 ROL R23 SBRS R23,0 BRCC Sht11_crc3 ; SBRC R23,0 BRCS Sht11_crc3 ; EOR R16,R22 Sht11_crc3: DEC R25 BRNE Sht11_crc2 ; DEC R24 BRNE Sht11_crc1 ADIW R30,1 '受信CRCバイトの次に計算CRC値を格納する。 ST Z,R16 $end Asm Return ' ' ---------------------------------- ' * 温度の最高値と最低値を確認する * ' ---------------------------------- ' Tmaxmin: If Tempmax < Temperature Then 'If 温度の最高値を超えたか? Then Tempmax = Temperature End If ' If Tempmin > Temperature Then 'If 温度の最低値を下回ったか? Then Tempmin = Temperature End If Return ' ' ---------------------------------- ' * 湿度の最高値と最低値を確認する * ' ---------------------------------- ' Hmaxmin: If Hummax < Humidity Then 'If 湿度の最高値を超えたか? Then Hummax = Humidity End If ' If Hummin > Humidity Then 'If 湿度の最低値を下回ったか? Then Hummin = Humidity End If Return ' ' ------------------------------------------ ' * 温度と湿度の最高値と最低値を初期化する * ' ------------------------------------------ ' Rstmaxmin: Tempmax = Temperature Tempmin = Temperature Hummax = Humidity Hummin = Humidity Return ' ' **************************** ' * フェード表示するルーチン * (Fadedsf: 0=フェード無し , 1=固定表示中) ' **************************** (2=フェードイン , 3=フェードアウト) ' Fadedsp: Select Case Fadedsf Case 0 : 'フェードを使用しない。 ' Case 3 : 'フェードアウト。 Fdtimer = Fdtimer - 1 If Fdtimer = 0 Then 'If フェード時間か? Then Fdtimer = Thfdtime 'フェード期間のタイマーを設定する。 Bright2 = Bright2 - 1 If Bright2 < 4 Then 'If 最低輝度になったか? Then If Dispmode = 1 Then 'If [温度/湿度]を交互表示中か? Then If Thdssel = 0 Then 'If 温度表示中か? Then Gosub Humidispl '湿度を表示する。 Thdssel = 1 Else Gosub Tempdispl '温度を表示する。 Thdssel = 0 End If Fadedsf = 2 'フェードインに変更する。 Fdtimer = Thfdtime 'フェード期間のタイマーを設定する。 Else Dispmode = Modetemp '[月日]以前の状態に戻す。 Fadedsf = 0 'フェード動作を停止する。 Bright2 = Dimmer 'LEDの輝度調光値を戻す。 Gosub Displed 'LEDに情報を表示する。 End If End If End If ' Case 2: 'フェードイン。 Fdtimer = Fdtimer - 1 If Fdtimer = 0 Then 'If フェード時間か? Then Fdtimer = Thfdtime 'フェード期間のタイマーを設定する。 Bright2 = Bright2 + 1 If Bright2 >= Dimmer Then 'If 最高輝度になったか? Then Fadedsf = 1 '固定表示中に変更する。 Fdtimer = Thdstime '固定表示時間のタイマーを設定する。 End If End If ' Case Else : '固定表示中。 Fdtimer = Fdtimer - 1 If Fdtimer = 0 Then Fadedsf = 3 'フェードアウトに変更する。 Fdtimer = Thfdtime 'フェード期間のタイマーを設定する。 End If End Select Return ' ' --------------------------------------- (Temp1 = バイナリ・データ) ' * バイナリ値を2桁のセグメントコードに * (Tempseg1 = 下位のセグメントコード) ' * 変換するサブルーチン * (Tempaeg2 = 上位のセグメントコード) ' --------------------------------------- ' Binseg: Tempseg2 = Makebcd(temp1) 'バイナリ値をBCD(Binary coded decimal)値に変換。 Tempseg1 = Tempseg2 And &H0F '下位のBCDコードを取得。 Tempseg1 = Lookup(tempseg1 , Segtab) '数値をセグメントコードへ変換する。 ' Tempseg2 = Tempseg2 And &HF0 '上位のBCDコードを取得。 Shift Tempseg2 , Right , 4 '下位へ移動する。 Tempseg2 = Lookup(tempseg2 , Segtab) '数値をセグメントコードへ変換する。 Return ' ' --------------------------------------------- (Temp1 = バイナリ・データ) ' * バイナリ値を2桁のセグメントコードに * (Tempseg1 = 下位のセグメントコード) ' * 変換するサブルーチン (ゼロサプレス有り) * (Tempaeg2 = 上位のセグメントコード) ' --------------------------------------------- ' Binsegzs: Gosub Binseg 'バイナリ値を2桁のセグメントコードに変換する。 If Temp1 < 10 Then 'If バイナリ値が10未満か? Then Tempseg2 = Seg_blank '消灯。 End If Return ' ' ------------------------------------------ (Temp1 = バイナリ・データ) ' * 時間 12/24時間制 識別変換 サブルーチン * (Tempseg1 = 下位のセグメントコード) ' ------------------------------------------ (Tempaeg2 = 上位のセグメントコード) ' Hourconv: If Mf1224h = 1 Then 'If 24時間制か? Then Gosub Binseg '24時間制で表示する。 Else '12時間制表示。 Temp2 = Temp1 '24時間制時刻を12時間制に変換する。 If Temp1 = 0 Then Temp1 = 24 If Temp1 > 12 Then Temp1 = Temp1 - 12 Gosub Binsegzs 'バイナリ値を2桁のセグメントコードに変換する。(ゼロサプレス有り) Temp1 = Temp2 ' If Temp1 < 12 Then 'If AM or PM? Tempseg2 = Tempseg2 And Seg_am '[AM] セグメントを点灯する。 Else Tempseg2 = Tempseg2 And Seg_pm '[PM] セグメントを点灯する。 End If End If Return ' ' --------------------------------------------------- ' * Word値を4桁のセグメント値に変換するサブルーチン * (Tempw1 -> Tempseg4 , Tempseg3 , Tempseg2 , Tempseg1) ' --------------------------------------------------- ' Wordseg: Tempw2 = Tempw1 / 100 '100の位を抽出する。 Tempw3 = Tempw2 * 100 '10と1の位を抽出する。 Tempw3 = Tempw1 - Tempw3 ' Temp1 = Tempw2 '100の位を変換する。 Gosub Binseg 'バイナリ値を2桁のセグメントコードに変換する。 Tempseg4 = Tempseg2 Tempseg3 = Tempseg1 Temp1 = Tempw3 '10と1の位を変換する。 Gosub Binseg 'バイナリ値を2桁のセグメントコードに変換する。 ' Select Case Tempw1 'ゼロサプレスを行う。 Case Is < 10 : '0〜9。 Tempseg4 = Seg_blank Tempseg3 = Seg_blank Tempseg2 = Seg_blank Case Is < 100 : '10〜99。 Tempseg4 = Seg_blank Tempseg3 = Seg_blank Case Is < 1000 : '100〜999。 Tempseg4 = Seg_blank End Select Return ' ' ---------------------------------------------------------- ' * Word値を4桁のセグメント値(D.P付)に変換するサブルーチン * (Tempw1 -> Tempseg4 , Tempseg3 , Tempseg2 , Tempseg1) ' ---------------------------------------------------------- ' Wordsegdp: If Tempw1.15 = 0 Then 'If プラス値か? Then Temp2 = 0 Else Temp2 = 1 If Sentype = 2 Then 'If センサーがDHT22か? Then Reset Tempw1.15 '符号を消去する。 Else Tempw1 = 0 - Tempw1 'SHT11の場合。 End If End If ' Tempw2 = Tempw1 / 100 '100の位を抽出する。 Tempw3 = Tempw2 * 100 '10と1の位を抽出する。 Tempw3 = Tempw1 - Tempw3 ' Temp1 = Tempw2 '100の位を変換する。 Gosub Binseg 'バイナリ値を2桁のセグメントコードに変換する。 Tempseg4 = Tempseg2 Tempseg3 = Tempseg1 Temp1 = Tempw3 '10と1の位を変換する。 Gosub Binseg 'バイナリ値を2桁のセグメントコードに変換する。 ' If Temp2 = 0 Then 'If プラス値か? Then Select Case Tempw1 'ゼロサプレスを行う。 Case Is < 100 : '0〜99 -> __0.0〜__9.9 Tempseg3 = Seg_blank Tempseg2 = Tempseg2 And Seg_dpon Case Is < 1000 : '100〜999 -> _10.0〜_99.9 Tempseg2 = Tempseg2 And Seg_dpon Case Else : '1000〜9999 -> _100〜_999 Tempseg1 = Tempseg2 Tempseg2 = Tempseg3 Tempseg3 = Tempseg4 End Select Else 'マイナスの場合。 If Tempw1 < 100 Then 'If -0.0〜-9.9か? Then Tempseg2 = Tempseg2 And Seg_dpon '-0〜-99 -> _-0.0〜_-9.9 Else Tempseg1 = Tempseg2 '-100〜-999 -> _-10〜_-99 Tempseg2 = Tempseg3 End If Tempseg3 = Seg_minus '[-]符号を付ける。 End If Tempseg4 = Seg_blank Return ' ' ************************************ ' * 外部電源の電圧を監視するルーチン * ' ************************************ ' Expower: Tempw1 = Getadc(ad_power) '外部電源の電圧値をA/D変換する。 If Tempw1 > 920 Then Return 'If 外部電源の電圧が4.5V以上あるか? Then ' Tempw1 = Getadc(ad_power) '外部電源の電圧値をA/D変換する。(2度チェックする) If Tempw1 > 920 Then Return 'If 外部電源の電圧が4.5V以上あるか? Then ' ' * スリープモードへ移行する * ' Slpmode: Reset Ucsr0b.txen0 'USART送信許可を無効にする。 Stop Adc 'A/Dコンバータの電源を切る。 Stop Timer0 'タイマー0を停止させる。 Stop Timer1 'タイマー1を停止させる。 Spcr = &H00 'ハードウェアSPIを停止する。(/SSポートを入力にすると、SPIがスレーブに変わるため) ' Config Portb = Input 'PORTBをすべて入力に設定する。 Config Portc = Input 'PORTCをすべて入力に設定する。 Config Portd = Input 'PORTDをすべて入力に設定する。 Portb = 0 'PORTBのプルアップをすべて解除する。 Portc = 0 'PORTCのプルアップをすべて解除する。 Portd = 0 'PORTDのプルアップをすべて解除する。 Didr0 = &B0011_1101 'デジタル入力禁止レジスタの設定。(外部電源の監視のみ有効にする) Disable Interrupts 'すべての割り込みを禁止。 Config Clockdiv = 8 'AVRの動作クロックを1MHzに変更する。 Enable Interrupts 'すべての割り込みを許可。 ' Slploop: Power Powersave 'スリープモードへ移行する。(1秒割り込みで再起動する) If Pt_power = 0 Then Goto Slploop 'If 外部電源が切れているか? Then ' ' * 外部電源が復旧後、通常動作へ移行する * ' Disable Interrupts 'すべての割り込みを禁止。 Config Clockdiv = 1 'AVRの動作クロックを8MHzに変更する。 Enable Interrupts 'すべての割り込みを許可。 Gosub Portinit 'ポートの初期設定を行う。 Gosub Inispi 'ハードウェアSPIの初期設定を行う。 Set Ucsr0b.txen0 'USART送信許可を有効にする。 If Swsleep <> 0 Then Goto Keyslp 'If スイッチでスリープしている状態か? Then Start Adc 'A/Dコンバータに電源を供給。 Gosub Displed 'LEDに情報を表示する。 Led_counter = 0 'ダイナミック点灯の桁カウンター初期値。 Start Timer0 'タイマー0を再始動させる。 Start Timer1 'タイマー1を再始動させる。 Tim500ms = 0 '500mSタイマーを初期化する。 Thmeaf = 0 '温度と湿度の計測開始フラグを初期化する。 Return ' ' ***************************************** ' * [SW1]表示オフが押されてスリープに入る * ' ***************************************** ' Keyslp: Swsleep = 1 'スイッチでスリープしている状態。 Stop Adc 'A/Dコンバータの電源を切る。 Stop Timer0 'タイマー0を停止させる。 Stop Timer1 'タイマー1を停止させる。 Waitms 5 $asm IN R24,PORTD '全てのLEDコモン信号をオフにする。 ANDI R24,Led_comd0 Out Portd , R24 IN R24,PORTC ANDI R24,Led_comc0 Out Portc , R24 $end Asm Spcr = &H00 'ハードウェアSPIを停止する。 Reset Portb.3 '[MOSI]ポートを[L]レベルにする。 Reset Portb.5 '[SCK]ポートを[L]レベルにする。 Reset Led_segstb '[NJU3711D]の[/STB]ポートを[L]レベルにする。 ' Bitwait Sw_1 , Set '[SW1]が離されるまで待つ。 Waitms 30 'チャタリング除去。 Didr0 = &B0011_1101 'デジタル入力禁止レジスタの設定。(外部電源監視のみ有効にする) Enable Pcint2 '[SW1]のピン変化割込を許可する。 ' Keyslp1: Power Powersave 'スリープモードへ移行する。(1秒割り込みまたはPCINT2で再起動する) $asm CLR R24 '32.768KHzの1サイクル(30.517uS)以内に再スリープしてはいけない。 Out Ocr2b , R24 'AVRの動作クロックが1MHzならOKだが8MHzではNG。 Keyslp2: LDS R24,ASSR 'Timer2のレジスタにダミー書き込みを行い、ASSRのフラグが0になるのを待つ。 SBRC R24,Ocr2bub 'If ASSR.OCR2BUBが0になったか? Then RJMP Keyslp2 $end Asm ' If Pt_power = 0 Then Goto Keyslp3 'If 外部電源が切れているか? Then If Sw_1 = 1 Then Goto Keyslp1 'If [SW1]が押されていないか? Then ' Disable Pcint2 '[SW1]のピン変化割込を禁止する。 Didr0 = &B0011_1111 'デジタル入力禁止レジスタの設定。(PORTCを全て禁止する) ) Gosub Inispi 'ハードウェアSPIの初期設定を行う。 Start Adc 'A/Dコンバータに電源を供給。 Gosub Displed 'LEDに情報を表示する。 Led_counter = 0 'ダイナミック点灯の桁カウンター初期値。 Start Timer0 'タイマー0を再始動させる。 Start Timer1 'タイマー1を再始動させる。 Waitms 30 'チャタリング除去。 Tim500ms = 0 '500mSタイマーを初期化する。 Thmeaf = 0 '温度と湿度の計測開始フラグを初期化する。 Swsleep = 0 'スイッチでスリープを解除すろ。 Return ' ' Keyslp3: Disable Pcint2 '[SW1]のピン変化割込を禁止する。 Goto Slpmode '電源オフのスリープモードに入る。 ' ' -------------------------------------- ' * ポートの初期設定を行うサブルーチン * ' -------------------------------------- ' Portinit: Config Portd = Led_comd1 'LEDのコモン接続ポートを出力に設定。 Config Portd.1 = Output 'シリアル出力ポート。 Config Portc = Led_comc1 'LEDのコモン接続ポートを出力に設定。 Set Sw_1pu 'スイッチ[1]の接続ポートをプルアップ。 Set Sw_2pu 'スイッチ[2]の接続ポートをプルアップ。 Set Sw_3pu 'スイッチ[3]の接続ポートをプルアップ。 Didr0 = &B0011_1111 'デジタル入力禁止レジスタの設定。(PORTCを全て禁止する) Config Thsen_sck = Output '温度湿度センサーの[SCK]ポートを出力に設定する。 Reset Thsen_sck '温度湿度センサーの[SCK]ポートを[L]にする。 Config Thsen_do = Input '温度湿度センサーの[DATA]ポートを入力にする。(外部プルアップで[H]) Reset Thsen_do '温度湿度センサーの[DATA]を出力時に[L]にする。 Reset Pt_cds 'CDSセンサーの制御ポートを出力時に[L]にする。 Return ' ' ----------------------------------------------- ' * ハードウェアSPIの初期設定を行うサブルーチン * ' ----------------------------------------------- ' Inispi: Config Led_segstb = Output 'LEDのセグメント用[NJU3711D]の[/STB]ポートを出力に設定。 Set Led_segstb '[NJU3711D]の[/STB]ポートを[H]に設定。 Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 4 , Noss = 1 Spiinit 'SPIポートを初期化する。 Set Spsr.spi2x 'SPIクロックの倍速指定。 Return ' ' ******************************* ' * LEDの輝度を調整するルーチン * ' ******************************* ' Ledbright: If Brightchf = 0 Then Return 'If 500mS経過したか? Else Brightchf = 0 ' Config Pt_cds = Output 'CDSセンサーの制御ポートを出力[L]にする。 Waitus 10 Tempw1 = Getadc(ad_power) 'CDSセンサーをA/D変換する。(電源監視Ch.と共用) Config Pt_cds = Input 'CDSセンサーの制御ポートを入力[オープン]にする。 ' If Tempw1 > 800 Then 'If 上限値を超えたか? Then Tempw1 = 800 End If If Tempw1 < 100 Then 'If 下限値を超えたか? Then Tempw1 = 100 End If ' Tempw1 = 800 - Tempw1 '[暗800〜明100]値をパルス幅[3〜120]に変換する。 Tempw1 = Tempw1 * 10 Tempw1 = Tempw1 / 60 Tempw1 = Tempw1 + 3 ' Dimmer = Tempw1 'パルス幅を設定する。 Bright1 = Dimmer If Fadedsf = 0 Then 'If フェード動作以外か? Then Bright2 = Dimmer End If Return ' ' ************************* ' * 時刻設定 処理ルーチン * ' ************************* ' Timeset: Disable Timer2 '1秒割り込みを禁止。 ' Bright1 = 120 'LEDの輝度を最大にする。 Bright2 = 120 Restore Segtset Gosub Titledsp '設定項目を表示する。 Led_buff(5) = Seg_blank '下段の表示を消す。 Led_buff(6) = Seg_blank Led_buff(7) = Seg_blank Led_buff(8) = Seg_blank Gosub Keyoff 'キーが離されるまで待つ。 ' Led_buff(5) = Lookup(2 , Segtab) '左桁に年[20]を表示する。 Led_buff(6) = Lookup(0 , Segtab) Temp1 = _year '[年]の設定。 Temp2 = 0 '右桁のゼロサプレス無しを指定。 Temp3 = 0 '設定値の下限。 Temp4 = 99 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 _year = Temp1 ' Gosub Titledsp '設定項目を表示する。 Temp1 = _day '右桁に[日]を表示する。 Gosub Binsegzs 'バイナリ値を2桁のセグメントコードに変換する。(ゼロサプレス有り) Led_buff(7) = Tempseg2 Led_buff(8) = Tempseg1 Temp1 = _month '[月]の設定。 Temp2 = 3 '左桁のゼロサプレス有りを指定。 Temp3 = 1 '設定値の下限。 Temp4 = 12 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 _month = Temp1 ' Gosub Titledsp '設定項目を表示する。 Temp1 = _month '左桁に[月]を表示する。 Gosub Binsegzs 'バイナリ値を2桁のセグメントコードに変換する。(ゼロサプレス有り) Led_buff(5) = Tempseg2 Led_buff(6) = Tempseg1 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 Temp1 = _day '[日]の設定。 Temp2 = 2 '右桁のゼロサプレス有りを指定。 Temp3 = 1 '設定値の下限。 Gosub Tmskey '時刻設定用のキー入力処理。 _day = Temp1 ' Gosub Titledsp '設定項目を表示する。 Temp1 = _min '右桁に[分]を表示する。 Gosub Binseg 'バイナリ値を2桁のセグメントコードに変換する。 Led_buff(7) = Tempseg2 Led_buff(8) = Tempseg1 Temp1 = _hour '[時]の設定。 Temp2 = 3 '左桁のゼロサプレス有りを指定。 Temp3 = 0 '設定値の下限。 Temp4 = 23 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 _hour = Temp1 ' Gosub Titledsp '設定項目を表示する。 Temp1 = _hour '左桁に[時]を表示する。 Gosub Binsegzs 'バイナリ値を2桁のセグメントコードに変換する。(ゼロサプレス有り) Led_buff(5) = Tempseg2 Led_buff(6) = Tempseg1 Temp1 = _min '[分]の設定。 Temp2 = 0 '右桁のゼロサプレス無しを指定。 Temp3 = 0 '設定値の下限。 Temp4 = 59 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 _min = Temp1 ' _sec = 0 '[秒]をリセット。 Timer2 = 0 Set Tifr2.tov2 'Timer2 オーバーフローフラグをリセットする。 Enable Timer2 '1秒割り込みを許可。 Return ' ' *************************** ' * モード設定 処理ルーチン * ' *************************** ' Modeset: Bright1 = 120 'LEDの輝度を最大にする。 Bright2 = 120 Restore Segmset Gosub Titledsp '設定項目を表示する。 Read Led_buff(5) '下段の項目を表示する。 Read Led_buff(6) Gosub Keyoff 'キーが離されるまで待つ。 ' Temp1 = Extremum '最高最低値のリセットを選択。 (0=リセットしない , 1=日付変更時 , 2=強制リセット) Temp2 = 2 '右桁のゼロサプレス有りを指定。 Temp3 = 0 '設定値の下限。 Temp4 = 2 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 If Temp1 = 2 Then 'If 最高最低値の強制リセットか? Then Gosub Rstmaxmin '温度と湿度の最高値と最低値を初期化する。 Else Extremum = Temp1 Eepextremum = Temp1 End If ' Gosub Titledsp '設定項目を表示する。 Read Led_buff(5) '下段の項目を表示する。 Read Led_buff(6) ' Temp1 = Eepthdstime '温度・湿度フェード表示中の固定表示時間設定。(秒) Temp2 = 2 '右桁のゼロサプレス有りを指定。 Temp3 = 1 '設定値の下限。 Temp4 = 20 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 Eepthdstime = Temp1 Thdstime = Temp1 * 100 ' Gosub Titledsp '設定項目を表示する。 Read Led_buff(5) '下段の項目を表示する。 Read Led_buff(6) ' Temp1 = Seritime 'シリアル出力の間隔。(1=1秒 , 2=1分) Temp2 = 2 '右桁のゼロサプレス有りを指定。 Temp3 = 1 '設定値の下限。 Temp4 = 2 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 Seritime = Temp1 Eepseritime = Temp1 ' Gosub Titledsp '設定項目を表示する。 Read Led_buff(5) '下段の項目を表示する。 Read Led_buff(6) ' Temp1 = Sentype 'センサーの種別を選択。 (1=SHT11 , 2=DHT22) Temp2 = 2 '右桁のゼロサプレス有りを指定。 Temp3 = 1 '設定値の下限。 Temp4 = 2 '設定値の上限。 Gosub Tmskey '時刻設定用のキー入力処理。 If Sentype <> Temp1 Then 'If センサーの種別が変更されたか? Then Sentype = Temp1 Eepsentype = Temp1 Thsen_rxbuf(1) = 0 'ステータスレジスタのデフォルト値。 Thsen_rxbuf(2) = &B0000_0101 '測定コマンドの初期値。(湿度) Sht11_sta = 0 'SHT11の起動状態。(待機中) End If Return ' ' ---------------------------------- ' * 設定項目を表示するサブルーチン * ' ---------------------------------- ' Titledsp: For Temp1 = 1 To 4 '4文字分を表示する。 Read Temp2 Led_buff(temp1) = Temp2 Next Temp1 Return ' ' ------------------------------------ (Temp1 = 設定するデータ値) ' * 時刻設定用 キー入力 サブルーチン * (Temp2 = 表示位置とゼロサプレス 0:右桁, 1:左桁, 2:右桁ゼロサプレス, 3:左桁ゼロサプレス) ' ------------------------------------ (Temp3 = 設定値の下限) ' (Temp4 = 設定値の上限) Tmskey: Temp5 = 1 '点滅用 F/F。 Temp6 = 1 '点滅用タイマー値。 ' Tmskey1: If Tifr1.ocf1a = 0 Then Goto Tmskey1 'If 10mS経過したか? Else Set Tifr1.ocf1a 'Timer1 比較A一致フラグをリセットする。 ' Gosub Keychk 'スイッチ入力を確認する。 If Keyflg <> 0 Then Goto Tmskey2 'If スイッチ入力が有ったか? Then ' Temp6 = Temp6 - 1 '表示を点滅させる。 If Temp6 = 0 Then 'If 点滅タイマー カウント終了か? Then If Temp5 = 0 Then 'If 消灯期間か? Then Temp5 = 1 Temp6 = 20 '点滅用のタイマー値。 If Temp2.0 = 0 Then 'If 右桁か? Then Led_buff(7) = Seg_blank '下段の右桁を消灯する。 Led_buff(8) = Seg_blank Else Led_buff(5) = Seg_blank '下段の左桁を消灯する。 Led_buff(6) = Seg_blank End If Else '点灯期間。 Temp5 = 0 Temp6 = 40 '点滅用のタイマー値。 If Temp2.1 = 0 Then 'If ゼロサプレス無しか? Then Gosub Binseg 'バイナリ値を2桁のセグメントコードに変換する。 Else Gosub Binsegzs 'バイナリ値を2桁のセグメントコードに変換する。(ゼロサプレス有り) End If If Temp2.0 = 0 Then 'If 右桁か? Then Led_buff(7) = Tempseg2 '下段の右桁に設定中の表示をする。 Led_buff(8) = Tempseg1 Else Led_buff(5) = Tempseg2 '下段の左桁に設定中の表示をする。 Led_buff(6) = Tempseg1 End If End If End If Goto Tmskey1 ' ' Tmskey2: 'スイッチが押された場合。 Keyflg = 0 If Keydata = &B00000001 Then Goto Keyoff 'If [SW1]が押されたか? Then If Keydata = &B00000010 Then Goto Tmskey3 'If [SW2]が押されたか? Then If Keydata = &B00000100 Then Goto Tmskey4 'If [SW3]が押されたか? Then Goto Tmskey1 ' ' ' Tmskey3: '[SW2] 設定値を加算。 Temp1 = Temp1 + 1 If Temp1 > Temp4 Then 'If 設定値が上限を超えたか? Then Temp1 = Temp3 End If Goto Tmskey ' Tmskey4: '[SW3] 設定値を減算。 If Temp1 = Temp3 Then 'If 設定値が下限を超えるか? Then Temp1 = Temp4 Else Temp1 = Temp1 - 1 End If Goto Tmskey ' Keyoff: '[SW1] 設定終了。 Gosub Keyport 'キー接続ポートからデータを入力。 If Keydata <> 0 Then Goto Keyoff 'If キーが離されたか? Else Waitms 100 Return ' ' ********************************** ' * シリアル出力に測定値を送信する * ' ********************************** ' Seriout: Tempstr = Str(_hour) 'シリアル出力へ[時]の送信。 Print Format(tempstr , "00") ; ":"; Tempstr = Str(_min) 'シリアル出力へ[分]の送信。 Print Format(tempstr , "00") ; ":"; Tempstr = Str(_sec) 'シリアル出力へ[秒]の送信。 Print Format(tempstr , "00") ; " "; If Thsen_err = 0 Then 'If エラーは無いか? Then If Sentype = 2 Then 'If センサーがDHT22か? Then If Temperature.15 = 0 Then 'If 温度がプラス値か? Then Tempstr = Str(temperature) '数値変数を文字変数に変換する。 Print Format(tempstr , " 0.0") ; '[+]温度値を送信する。 Else '温度値がマイナスの場合。 Tempw1 = Temperature Reset Tempw1.15 '温度の符号を消去する。 Tempstr = Str(tempw1) '数値変数を文字変数に変換する。 If Tempw1 < 100 Then 'If -40.0〜-10.0か? Then Print " -" ; Format(tempstr , "0.0") ; '[-]温度値を送信する。 Else Print "-" ; Format(tempstr , " 0.0") ; '[-]温度値を送信する。 End If End If Else 'SHT11の場合。 Tempstr = Str(temperature) '数値変数を文字変数に変換する。 If Temperature < 0 Then 'If [-]値か? Then Print Format(tempstr , " 0.0") ; '[-]温度値を送信する。 Else Print Format(tempstr , " 0.0") ; '[+]温度値を送信する。 End If End If Tempstr = Str(humidity) '数値変数を文字変数に変換する。 Print " " ; Format(tempstr , " 0.0") '湿度値を送信する。 Else Print "-50.0 0.0" 'センサーがエラーの場合。 End If Return ' ' ********************************************************* ' * 32.768KHz 水晶較正用 16.384KHz出力 [PB3:17pin (MOSI)] * ' ********************************************************* ' Xtalcal: Set Portb.2 '未使用ポートをプルアップする。 Set Portb.4 Set Portb.5 Config Timer2 = Timer , Prescale = 1 , Async = On , Clear Timer = 1 , Compare A = Toggle Ocr2a = 0 End ' ' *************************************** ' * TIMER0 比較一致(A) 割り込みルーチン * ' *************************************** ' $notransform On 'R23またはR0を使用する命令に自動修正させない。 ' $asm Tint0a: PUSH R1 IN R1,SREG 'ステータス・レジスタを待避。 PUSH R24 PUSH R25 PUSH ZL PUSH ZH ; LDS R24,{LED_counter} 'LEDの1〜4と5〜8で調光値を変える。 CPI R24,4 BRCC Tint0a4 'If 5〜8か? Then LDS R25,{Bright1} '1〜4の場合。 RJMP Tint0a5 ; Tint0a4: '5〜8の場合。 LDS R25,{Bright2} Tint0a5: Out Ocr0b , R25 'TIMER0の比較器Bにパルス幅を設定する。 ; Loadadr Led_buff(1) , Z 'LEDのセグメントデータをNJU3711に送信する。 CLR R25 ADD ZL,R24 ADC ZH,R25 LD R25,Z 'セグメント・バッファーからデータを取り出す。 Out Spdr , R25 'ハードウェアSPIで送信する。 Tint0a7: IN R25,Spsr 'ハードウェアSPIの送信ステータスを確認する。 SBRS R25 , Spif 'If 送信が完了したか? Then RJMP Tint0a7 ; CBI Led_segstb_p,Led_segstb_b 'NJU3711の/STBにストローブ信号を送る。(H -> L -> H) SBI Led_segstb_p,Led_segstb_b ; LDI ZL,Low(Tintjpt) 'LEDのコモン接続ポートを指定してONにする。 LDI ZH,High(Tintjpt) CLR R25 ADD ZL,R24 ADC ZH,R25 IJMP ; Tintjpt: RJMP Tintcom1 'ジャンプ・テーブル。 RJMP Tintcom2 RJMP Tintcom3 RJMP Tintcom4 RJMP Tintcom5 RJMP Tintcom6 RJMP Tintcom7 RJMP Tintcom8 ; Tintcom1: SBI PORTD,0 'LEDのコモン[1]接続ポートをONにする。 RJMP Tintjpend ; Tintcom2: SBI PORTD,2 'LEDのコモン[2]接続ポートをONにする。 RJMP Tintjpend ; Tintcom3: SBI PORTD,3 'LEDのコモン[3]接続ポートをONにする。 RJMP Tintjpend ; Tintcom4: SBI PORTD,4 'LEDのコモン[4]接続ポートをONにする。 RJMP Tintjpend ; Tintcom5: SBI PORTC,5 'LEDのコモン[5]接続ポートをONにする。 RJMP Tintjpend ; Tintcom6: SBI PORTC,4 'LEDのコモン[6]接続ポートをONにする。 RJMP Tintjpend ; Tintcom7: SBI PORTC,3 'LEDのコモン[7]接続ポートをONにする。 RJMP Tintjpend ; Tintcom8: SBI PORTC,2 'LEDのコモン[8]接続ポートをONにする。 ; Tintjpend: INC R24 'ダイナミック点灯の桁カウンターを更新する。 ANDI R24,$07 STS {LED_counter},R24 ; POP ZH POP ZL POP R25 POP R24 Out Sreg , R1 'ステータス・レジスタを復帰 POP R1 RETI $end Asm ' ' *************************************** ' * TIMER0 比較一致(B) 割り込みルーチン * ' *************************************** ' $asm Tint0b: PUSH R1 IN R1,SREG 'ステータス・レジスタを待避。 PUSH R24 ; IN R24,PORTD '全ての桁のコモン信号をオフにする。 ANDI R24,Led_comd0 Out Portd , R24 IN R24,PORTC ANDI R24,Led_comc0 Out Portc , R24 ; POP R24 Out Sreg , R1 'ステータス・レジスタを復帰 POP R1 RETI $end Asm ' ' **************************** ' * スイッチ割り込みルーチン * ' **************************** ' $asm Swint: 'スイッチ割り込みでは何も処理しない。 RETI $end Asm ' ' $notransform Off ' ' End ' ' ***************************************** ' * LEDのセグメントコードへの変換テーブル * ' ***************************************** ' Segtab: Data &B1100_0000 '0 Data &B1111_1001 '1 Data &B1010_0100 '2 Data &B1011_0000 '3 Data &B1001_1001 '4 Data &B1001_0010 '5 Data &B1000_0010 '6 Data &B1111_1000 '7 Data &B1000_0000 '8 Data &B1001_0000 '9 ' ' Segtset: Data &H91 , &H86 , &H88 , &HAF 'YEAR Data &HC8 , &HA3 , &HAB , &H87 'MONTH Data &HA1 , &H88 , &H91 , &HFF 'DAY Data &H8B , &HA3 , &HE3 , &HAF 'HOUR Data &HC8 , &HFB , &HAB , &HFF 'MIN ' Segmset: Data &H86 , &H89 , &H87 , &HAF , &HF6 , &HF6 'extr __ Data &H8E , &H87 , &HFB , &HC8 , &H93 , &HA7 'ftim sc Data &H93 , &HA3 , &HE3 , &H87 , &H93 , &HC8 'sout sm Data &H93 , &H86 , &HAB , &H93 , &H87 , &H8C 'sens tp ' ' ************************************ ' * 月ごとの最終日を取得するテーブル * ' ************************************ ' Monthtab: Data 0 , 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31