#include "clock_macro.inc" cblock clockflg swflg pcflg tcheckflg currentkey prevkey dlaycnt key_temp sw_temp posi posi_temp posi_temp2 posicnt ckposi_9 ckposi_12 ckposi_15 bcddata1 ;1の位 bcddata2 ;10の位 bcddata3 ;100の位 a_h ;温度変換用レジスタ a_m a_l a_h_temp a_m_temp b_h b_l c_h c_mh c_ml c_l d_h d_mh d_ml d_l avect ;平均回数カウント ave_h ;平均用レジスタ ave_l ave_tmp ave_tmp_l ave_tmp_h interval msg_lp pc_temp endc #define E PORTD,0 ;LCDの E ピンの指定 #define RW PORTD,1 ;LCDの RW ピンの指定 #define RS PORTD,2 ;LCDの RS ピンの指定 org 0x0000 goto ini org 0x0004 goto intrupt org 0x0008 ini bcf INTCON,GIE ;割り込み禁止 ;ポートの初期化 banksel TRISA movlf b'00000001',TRISA ;RA0を入力に clrf TRISB ;PORTBを出力に movlf b'10001111',TRISC ;RC0~3とRXを入力に clrf TRISD banksel PORTB clrf PORTB clrf PORTC clrf PORTD ;フラグ初期化 clrf clockflg clrf swflg clrf pcflg clrf tcheckflg ;変数初期化 clrf dlaycnt clrf currentkey clrf prevkey clrf key_temp clrf sw_temp clrf posi clrf posi_temp clrf posi_temp2 clrf bcddata1 clrf bcddata2 clrf bcddata3 clrf a_h ;温度変換用レジスタ clrf a_m clrf a_l clrf a_h_temp clrf a_m_temp clrf ave_h clrf ave_l clrf ave_tmp_l clrf ave_tmp_h clrf pc_temp movlf 02h,posicnt movlf 09h,ckposi_9 movlf 0ch,ckposi_12 movlf 0fh,ckposi_15 movlf d'128',avect movlf d'7',ave_tmp movlf 010h,interval enable_txrc b'00100100',d'82',b'10000000' ;USARTの初期化 ;演算マクロ初期化 mul_ini div_ini mul_16_32_ini ;AD変換初期化 banksel ADCON1 movlf b'10001110',ADCON1 ;AN0をアナログ banksel ADCON0 movlf b'10000001',ADCON0 ;変換クロックをFosc/32,12.8MHz busy_dlay_ini ;遅延の初期化 lcd_ini DLY4 ;LCDの初期化 ccp_ini b'00001011',07fh,03eh ;CCPの初期化,コンペアモード、スペシャルイベント設定 ;比較値(15999)=3E7Fの設定 tmr1_ini b'00110001',00h,00h ;タイマ1の初期化,プリスケーラ8,内部クロック,フリーラン設定 intrupt_ini d'25' ;割り込みの初期化 timeup_ini ;時刻表示の初期化 settimeup_ini ;修正時刻の初期化 call lcd_data1 ;"INITIALIZATION"表示 call lcd_data2 ;"OK!"表示 call DLY7 ;約2秒遅延 call DLY7 call lcd_clr ;ディスプレークリア call lcd_disp call lcd_tdisp ;温度表示 call lcd_pcdisp ;通信状態表示 start bsf INTCON,PEIE ;周辺割り込み許可 bsf INTCON,GIE ;グローバル割り込み許可 startlp btfss clockflg,0 ;フラグが1かどうか goto switch_sta bcf clockflg,0 ;時間用フラグのクリア btfss clockflg,1 ;setモードになったらlcd更新をストップ call lcd_disp switch_sta movf PORTC,0 andlw 0fh movwf currentkey ;スイッチ状態の読み込み call DLY5 ;20msec待ち movf PORTC,0 ;再読み込み andlw 0fh subwf currentkey,0 ;チャタリング防止 btfss STATUS,Z goto startlp ;ノイズ btfsc currentkey,3 goto setck btfsc currentkey,2 goto adjust btfsc currentkey,1 goto select ;以下スイッチ1の長押し用処理 btfsc pcflg,0 ;通信モードかどうか goto usart_mode control ;スイッチ1 btfsc swflg,2 goto control_hold btfsc swflg,1 goto control_click btfsc swflg,0 goto active1 idle comf prevkey,0 ;立ち上がり(0→1の状態)をチェック movwf key_temp movf currentkey,0 andwf key_temp,0 andlw b'00000001' ;0bit目がスイッチ1 btfsc STATUS,Z goto $+5 ;入力なし bsf swflg,0 movlf d'15',dlaycnt goto keymemo btfsc clockflg,1 ;setモードかどうか goto keymemo call ad ;AD変換 call bcdchange ;bcd変換 btfsc tcheckflg,0 ;温度が負かどうか goto $+7 decfsz interval,1 goto keymemo movlf 010h,interval ;表示のふらつき防止のためのインターバル call lcd_tdisp goto keymemo call lcd_error ;温度がマイナスなら goto keymemo active1 btfss currentkey,0 goto active2 ;押されていない call DLY6 ;100msec decfsz dlaycnt,1 ;長押し判定用タイマ作動 goto keymemo bsf swflg,2 ;100m+α×15=約2sec経過 bcf swflg,0 goto keymemo active2 comf currentkey,0 ;立下り(1→0の状態)をチェック movwf key_temp movf prevkey,0 andwf key_temp,0 andlw b'00000001' ;0bit目がスイッチ1 btfsc STATUS,Z goto keymemo bsf swflg,1 ;放された bcf swflg,0 keymemo movf currentkey,0 ;直前を保存 movwf prevkey goto startlp usart_mode ;PCとの通信 btfsc pcflg,1 call boot_msg ;通信開始時メッセージ bcf pcflg,1 rc_lp btfss PIR1,RCIF ;1バイト受信待ち goto startlp ;スイッチ2の状態確認へ btfsc RCSTA,FERR ;受信エラーチェック フレーミングエラーか? goto ferr btfsc RCSTA,OERR goto oerr movf RCREG,0 ;正常受信 movwf pc_temp ;一時保存 cmd_check sublw '\r' ;Enterキー入力か? btfsc STATUS,Z call set_info movf pc_temp,0 sublw 'e' btfss STATUS,Z goto $+4 call end_msg bcf pcflg,0 ;フラグクリア bcf RCSTA,4 ;受信禁止 call lcd_pcdisp goto startlp ad movlf b'10000001',ADCON0 ;チャンネル0選択、AD設定on call DLY1 ;コンデンサ充電時間10bitで約20μsec call DLY1 ;余裕を持って40μsec bsf ADCON0,GO ;AD変換開始 wtad btfsc ADCON0,GO ;AD変換が完了したか? GO=0で完了 goto wtad banksel ADRESL ;温度平均化 movf ADRESL,0 ;データ取り出し banksel ADRESH movwf ave_tmp_l movf ADRESH,0 movwf ave_tmp_h add_16 ave_h,ave_l,ave_tmp_h,ave_tmp_l decfsz avect,1 ;128回 goto ad bcf ADCON0,0 ;AD設定off call t_ave ;1/128 movlf d'128',avect ;再設定 movlf d'7',ave_tmp movf ave_l,0 ;下位データ取り出し movwf a_m movwf a_m_temp movf ave_h,0 ;上位データ取り出し movwf a_h movwf a_h_temp return t_ave bcf STATUS,C rrf ave_h,1 rrf ave_l,1 decfsz ave_tmp,1 ;右へ6bitシフト=1/64 goto t_ave return ;ad変換後のバイナリデータを bcdchange ;計算式に代入し温度を求めBCDに変換 clrf bcddata1 ;一の位 clrf bcddata2 ;十の位 clrf bcddata3 ;百の位 clrf b_h clrf b_l clrf c_h clrf c_mh clrf c_ml clrf c_l clrf d_h clrf d_mh clrf d_ml clrf d_l clrf tcheckflg mul_prg a_h,a_m,d'2' ;a_h,a_mを4倍 add_16 a_h,a_m,a_h_temp,a_m_temp ;4+1倍=5倍 div_prg a_h,a_m,a_l,d'10' ;1/1024 movlf 080h,b_h ;aの設定 movlf 02h,b_l ;小数部8bit mul_16_32_prg a_m,a_l,b_h,b_l,c_h,c_mh,c_ml,c_l ;a×vo movlf 00h,d_h ;bの設定 movlf 0E0h,d_mh movlf 062h,d_ml ;小数部16bit movlf 0A9h,d_l sub_32 d_h,d_mh,d_ml,d_l,c_h,c_mh,c_ml,c_l ;b-a×vo=T btfss STATUS,C ;測定温度が<0の時 goto t_error bcdchangelp movlw d'100' ;100の桁を求める subwf d_mh,0 ;100を引く btfss STATUS,C ;正負判断 <0ならC=0 goto bcdchange_1 ;引けないので十の位へ movwf d_mh ;演算結果を反映 incf bcddata3,1 ;100位に+1 goto bcdchangelp bcdchange_1 movlw d'10' ;10の桁を求める subwf d_mh,0 ;10を引く btfss STATUS,C goto bcdchange_2 movwf d_mh incf bcddata2,1 ;10の位に+1 goto bcdchange_1 bcdchange_2 movf d_mh,0 ;1の桁を求める movwf bcddata1 ;残り return t_error ;温度がマイナスの時 clrf a_h ;リセット clrf a_m clrf a_l movlf '?',bcddata1 movlf '?',bcddata2 movlf '?',bcddata3 bsf tcheckflg,0 ;エラーフラグセット return control_click ;押された時の処理 btfsc clockflg,1 ;setモードかどうか goto startlp ;setモードなら何もしない bcf swflg,1 movlw b'00000100' ;2bitをマスク xorwf clockflg,1 ;2bit目を反転 call lcd_disp goto startlp control_hold ;長押し後の処理、setモード bcf swflg,2 btfsc clockflg,1 ;setモードかどうか goto startlp ;setモードなら何もしない bsf clockflg,1 ;setモードに call lcd_setdisp movlw 09h movwf posi movwf posi_temp movlw 080h addwf posi_temp,0 call lcd_cmd movlw 0fh call lcd_cmd goto startlp select ;修正位置選択 btfss clockflg,1 ;setモードかどうか goto select_pc btfsc PORTC,1 ;スイッチが離されるのを待つ goto $-1 movlw 03h addwf posi_temp,0 movwf posi_temp movwf posi movlw 080h addwf posi_temp,0 movwf posi_temp2 call lcd_cmd movlw 0fh ;カーソル表示、ブリンクon call lcd_cmd decfsz posicnt goto startlp movlf 06h,posi_temp movlf 03h,posicnt goto startlp select_pc ;setモードではない時 btfsc PORTC,1 ;スイッチが離されるのを待つ goto $-1 movlw b'00000001' ;0bitをマスク xorwf pcflg,1 ;0bit目を反転 btfsc pcflg,0 goto $+5 call end_msg ;終了メッセージ送信 bcf pcflg,1 bcf RCSTA,4 ;受信禁止 goto $+3 bsf pcflg,1 bsf RCSTA,4 ;受信許可 call lcd_pcdisp goto startlp adjust ;時刻修正 btfss clockflg,1 ;setモードかどうか goto startlp ;何もしない movlw 0ch ;ブリンクoff call lcd_cmd call DLY6 ;押し続けると call DLY6 ;0.2sec間隔でカウント movf posi,0 movwf sw_temp ;修正位置読み込み movf sw_temp,0 subwf ckposi_9,0 btfsc STATUS,Z goto shour movf sw_temp,0 subwf ckposi_12,0 btfsc STATUS,Z goto smin movf sw_temp,0 subwf ckposi_15,0 btfsc STATUS,Z goto ssec goto startlp setck ;設定反映 btfss clockflg,1 ;setモードかどうか goto startlp ;何もしない btfsc PORTC,3 ;スイッチが離されるのを待つ goto $-1 bcf clockflg,1 ;フラグリセット bcf INTCON,GIE ;全ての割り込み禁止 ccp_ini b'00001011',07fh,03eh ;CCPの再設定 tmr1_ini b'00110001',00h,00h ;タイマ1の再設定 movlf d'25',post_count ;割り込みカウント数の再設定 movf setsec,0 ;時刻設定 movwf sec movf setmint,0 movwf mint movf sethour_12,0 movwf hour_12 movf sethour_24,0 movwf hour_24 btfsc clockflg,4 ;4bit目が1? goto $+3 bcf clockflg,3 ;そうでなければ0に goto $+2 bsf clockflg,3 ;3bit目を1に movf setap,0 movwf ap bsf INTCON,GIE ;割り込み許可 movlw 0ch ;ブリンクoff call lcd_cmd call lcd_clr ;表示リセット call lcd_disp call lcd_tdisp call lcd_pcdisp goto startlp shour call sethorup_12 call lcd_setdisp movf posi_temp2,0 ;現在のLCDアドレスの位置 call lcd_cmd movlw 0fh ;カーソル表示、ブリンクon call lcd_cmd goto startlp smin call setminup call lcd_setdisp movf posi_temp2,0 ;現在のLCDアドレスの位置 call lcd_cmd movlw 0fh ;カーソル表示、ブリンクon call lcd_cmd goto startlp ssec call settimeup call lcd_setdisp movf posi_temp2,0 ;現在のLCDアドレスの位置 call lcd_cmd movlw 0fh ;カーソル表示、ブリンクon call lcd_cmd goto startlp set_info tx_mov_char '2' tx_mov_char '4' tx_mov_char 'H' tx_mov_char ' ' swapf hour_24,0 call tx_charcon movf hour_24,0 ;時刻送信 call tx_charcon tx_mov_char ':' swapf mint,0 call tx_charcon movf mint,0 call tx_charcon tx_mov_char ':' swapf sec,0 call tx_charcon movf sec,0 call tx_charcon tx_mov_char ' ' call ad ;AD変換 call bcdchange ;bcd変換 movf bcddata3,0 ;温度送信 call tx_charcon movf bcddata2,0 call tx_charcon movf bcddata1,0 call tx_charcon tx_mov_char b'11011111' tx_mov_char 'C' tx_mov_char '\r' tx_mov_char '\n' return ferr movf RCREG,0 ;エラーリセット btfss RCSTA,OERR goto startlp oerr bcf RCSTA,CREN ;エラーリセット bsf RCSTA,CREN goto startlp boot_msg clrf msg_lp bm_lp movf msg_lp,0 call msg_start addlw 00h ;メッセージ終了かどうか btfsc STATUS,Z return call txchar ;1文字送信 incf msg_lp,1 goto bm_lp end_msg ;終了メッセージ clrf msg_lp em_lp movf msg_lp,0 call msg_end addlw 00h ;メッセージ終了かどうか btfsc STATUS,Z goto $+4 call txchar ;1文字送信 incf msg_lp,1 goto em_lp return lcd_disp ;ディスプレイ表示 btfsc clockflg,2 goto lcd_disp_24 lcd_disp_12 movlw b'10000001' call lcd_cmd mov_char '1' mov_char '2' mov_char 'H' mov_char ' ' movf ap,0 call lcd_char mov_char 'M' mov_char ' ' swapf hour_12,0 ;上位と下位を入れ替え call lcd_charcon movf hour_12,0 call lcd_charcon mov_char ':' swapf mint,0 call lcd_charcon movf mint,0 call lcd_charcon mov_char ':' swapf sec,0 call lcd_charcon movf sec,0 call lcd_charcon return lcd_disp_24 ;ディスプレイ表示 movlw b'10000001' call lcd_cmd mov_char '2' mov_char '4' mov_char 'H' mov_char ' ' mov_char ' ' swapf hour_24,0 ;上位と下位を入れ替え call lcd_charcon movf hour_24,0 call lcd_charcon mov_char ':' swapf mint,0 call lcd_charcon movf mint,0 call lcd_charcon mov_char ':' swapf sec,0 call lcd_charcon movf sec,0 call lcd_charcon mov_char ' ' mov_char ' ' return lcd_setdisp call lcd_clr movlw b'10000001' call lcd_cmd mov_char 'S' mov_char 'E' mov_char 'T' mov_char ' ' movf setap,0 call lcd_char mov_char 'M' mov_char ' ' swapf sethour_12,0 ;上位と下位を入れ替え call lcd_charcon movf sethour_12,0 call lcd_charcon mov_char ':' swapf setmint,0 call lcd_charcon movf setmint,0 call lcd_charcon mov_char ':' swapf setsec,0 call lcd_charcon movf setsec,0 call lcd_charcon movlw b'11000001' call lcd_cmd mov_char ' ' mov_char 'C' mov_char 'l' mov_char 'o' mov_char 'c' mov_char 'k' mov_char ' ' mov_char 'A' mov_char 'd' mov_char 'j' mov_char 'u' mov_char 's' mov_char 't' return lcd_tdisp movlw b'11000001' ;2行目 call lcd_cmd mov_char 'T' mov_char ':' movf bcddata3,0 call get_number call lcd_char movf bcddata2,0 call get_number call lcd_char movf bcddata1,0 call get_number call lcd_char mov_char b'11011111' mov_char 'C' return lcd_pcdisp movlw b'11001010' ;2行目 call lcd_cmd mov_char 'P' mov_char 'C' mov_char ':' btfsc pcflg,0 goto pc_on mov_char 'O' mov_char 'F' mov_char 'F' return pc_on mov_char 'O' mov_char 'N' mov_char ' ' return lcd_data1 movlw b'10000001' ;1行目1番地から開始 call lcd_cmd mov_char 'I' mov_char 'N' mov_char 'I' mov_char 'T' mov_char 'I' mov_char 'A' mov_char 'L' mov_char 'I' mov_char 'Z' mov_char 'A' mov_char 'T' mov_char 'I' mov_char 'O' mov_char 'N' return lcd_data2 movlw b'11000111' ;2行目7番地から開始 call lcd_cmd mov_char 'O' mov_char 'K' mov_char '!' return lcd_error movlw b'11000001' ;2行目7番地から開始 call lcd_cmd mov_char 'T' mov_char ':' mov_char 'E' mov_char 'R' mov_char 'R' mov_char 'O' mov_char 'R' return settimeup_prg ;時刻修正 intrupt_prg timeup ;25回割り込み後、timeupへ timeup_prg ;1秒ごとの時刻表示 lcd_charcon_prg ;アスキーコードに変換 lcd_cmd_prg ;コマンド送信 lcd_char_prg ;文字データ送信 lcd_busyck_prg ;LCDのビジーチェック lcd_clr_prg DLY3 ;液晶表示をクリア tx_char_prg ;1文字シリアル通信 tx_charcon_prg ;アスキーコードに変換しシリアル通信 busy_dlay1 ;約20μsecタイマ busy_dlay2 ;約100μsecタイマ busy_dlay3 ;約1msecタイマ busy_dlay4 ;約5msecタイマ busy_dlay5 ;約20msecタイマ busy_dlay6 ;約100msecタイマ busy_dlay7 ;約1secタイマ org 0x500 get_number ;アドレス0ff以降は注意! clrf PCLATH bsf PCLATH,0 bsf PCLATH,2 ;101=5 PCLATHに5代入 andlw 0fh ;下位4bitマスク addwf PCL,1 DT "0123456789" msg_start clrf PCLATH bsf PCLATH,0 bsf PCLATH,2 ;101=5 PCLATHに5代入 addwf PCL,1 DT "Hello\r\n" DT "-----------------------------\r\n" DT "Command\r\n" DT "Enter : Clock and temperature\r\n" DT " E : Exit\r\n" DT "-----------------------------\r\n" DT "Standby ok\r\n\n",0 ;終わりは0を返す msg_end clrf PCLATH bsf PCLATH,0 bsf PCLATH,2 ;101=5 PCLATHに5代入 addwf PCL,1 DT "\nSee you\r\n\n",0 ;終わりは0を返す end