久しぶりにサーモスタット「変温君」とウェーブコントローラー「激波」のプログラムを一部書き換えた。
サーモスタットやウェーブコントローラーとしての主要な仕事をする部分ではなく スイッチ操作に関する部分のプログラムで 単に押すだけではなく、5つのボタンを「長押し」だったり 2つのボタンを同時に押す「同時押し」だったり そう言ったボタン操作を組み合わせる事でボタンの数より多くの操作をできるようにするプログラムで 今までのプログラムでもそんなに問題は無かったのですが 1回押しただけなのに2回分進んだり 仕事が忙しい時だとスイッチが反応しなかったり、という誤動作が出る事が 偶~~~~に発生してたので以前から改良したかった部分でした。
ただ このスイッチ操作のプログラムに関しては 普通に押すだけのプログラムなら当たり前の定番プログラムがあるのですが 「長押し」や「同時押し」などのプログラムに関してはサンプルになるプログラムが見つからなったので 元々、自前で作ったプログラムだったのですが どうもスッキリしないプログラムだったので これをじっくりと作り直していた。
動作としては非常に単純な事なのですが これが意外と難しい部分で 例えば「同時押し」なんかの場合で AボタンとBボタンを同時に押す場合、AとBを同時に押した時にある動作をさせるのは簡単な事なんですが 普通に作ると この時にAボタンを押す動作も Bボタンを押す動作も同時に出てくる訳ですから この時にはAボタンだけを押した時の動作とBボタンだけを押した時の動作に関しては出てこないようにキャンセルする必要がある。
この時に 何を持ってAB「同時押し」なのか、それとも「単独押し」なのかを判断するか?、またどうやって どのタイミングでABボタンの単独押しをキャンセルするか?
長押しの場合もそうで 単に「長押し」を検出するのは簡単ですが この場合も「短押し」との区別をどうやって判断するか、またどうやって「短押し」をキャンセルするか?
また これに加えて 電気回路のスイッチの動作を検出するのが難しい部分で「チャタリング」という現象があって これは電気の接点であるスイッチを押した時に1回押しただけの動作であるにも関わらずスイッチの接点が繋がる時ににマクロ秒単位で接点のON、OFFが繰り返される瞬間があって 自分では1回しかスイッチを押していないのに 3回押した事になってしまったり10回押した事になってしまったり、そんな現象があります。
AVRマイコンには このチャタリングに関しても1回の単押しの場合には これを検出して防止するコードが用意されてるのですが これも「長押し」や「同時押し」に使おうとすると そのままでは使えない。
私にとっては このあたりのプログラムがメインのサーモスタットやウェーブコントローラーのプログラムよりも難しい部分だと感じておりましたが あ~でもない、こ~でもない、といろいろやってるうちに ようやく自分で納得できる操作性のプログラムになったので サーモスタット「変温君」と ウェーブコントローラー「激波」のプログラム内のボタン操作の部分を書き換えたところ、どちらもボタン操作が気持ち良く反応するようになった。
やっと今一だったプログラムが改良できたので すっきりしました。
あんまり マイコンのプログラムのコードに興味のある方はいないかも知れませんが 一応、公開しておきます。
パワー、モード、アップ、ダウン、エンター と5つのボタンを 単なる「押す」だけの5つの動作に それぞれの「長押し」の動作を5つ、それから 「パワー、モード」「パワー、アップ」「パワー、ダウン」「モード、アップ」「モード、ダウン」「モード、エンター」「アップ、ダウン」「アップ、エンター」「ダウン、モード」の同時押し9つの動作を加えた 合計19種類の動作を検知するプログラムで AVRマイコン用のBASIC言語です。
完全な自前のプログラムですので まったく何の保証もありませんが。
↓ここから
Const Simul = 1 'シミュレーションの場合は 1を 本番では0を入れる
#if Simul = 1
$sim
#endif
$regfile = "m644pdef.DAT"
$crystal = 8000000
Initlcd
Config Lcdmode = Port
Config Lcdbus = 4
Config Lcdpin = Pin , Db4 = Porta.1 , Db5 = Porta.4 , Db6 = Porta.2 , Db7 = Porta.3 , E = Porta.5 , Rs = Porta.6
Config Lcd = 16 * 2
Cursor Off
Cls
Config Timer1 = Timer , Prescale = 256 , Clear Timer = 1
Compare1a = 31250 - 1
On Compare1a Tim_2
Enable Compare1a
'***************
Enable Interrupts
Config Porta = &B11111111
Config Portb = &B11111111
Config Portc = &B11111100
Config Portd = &B00011111
Porta = &B00000000
Portb = &B00000000
Portc = &B00000011
Portd = &B11100000
Sw_power Alias Pind.7
Sw_mode Alias Pind.6
Sw_up Alias Pind.5
Sw_down Alias Pinc.1
Sw_enter Alias Pinc.0
Dim C_p_tim As Byte
Dim C_m_tim As Byte
Dim C_u_tim As Byte
Dim C_d_tim As Byte
Dim C_e_tim As Byte
Dim C_keep_sp As Long
Dim Fg_p_on As Bit
Dim Fg_m_on As Bit
Dim Fg_u_on As Bit
Dim Fg_d_on As Bit
Dim Fg_e_on As Bit
Dim Fg_p_cou As Bit
Dim Fg_m_cou As Bit
Dim Fg_u_cou As Bit
Dim Fg_d_cou As Bit
Dim Fg_e_cou As Bit
Dim Fg_p_moto As Bit
Dim Fg_m_moto As Bit
Dim Fg_u_moto As Bit
Dim Fg_d_moto As Bit
Dim Fg_e_moto As Bit
Dim Fg_p_keep_sumi As Bit
Dim Fg_m_keep_sumi As Bit
Dim Fg_u_keep_sumi As Bit
Dim Fg_d_keep_sumi As Bit
Dim Fg_e_keep_sumi As Bit
Dim Fg_fullcancel As Bit
Dim P_tim As Byte
Dim M_tim As Byte
Dim U_tim As Byte
Dim D_tim As Byte
Dim E_tim As Byte
Dim Speed_p As Byte
Dim Speed_m As Byte
Dim Speed_u As Byte
Dim Speed_d As Byte
Dim Speed_e As Byte
Dim C_speed_p As Byte
Dim C_speed_m As Byte
Dim C_speed_u As Byte
Dim C_speed_d As Byte
Dim C_speed_e As Byte
P_tim = 2
M_tim = 3
U_tim = 2
D_tim = 2
E_tim = 2
Speed_p = 1
Speed_m = 1
Speed_u = 1
Speed_d = 1
Speed_e = 1
Dim Test_count As Long
Do 'メインループ
Gosub Eventcheck
#if Simul = 1
Gosub Tim_2 'シミュレーションではタイマーが動作しないので シミュレーション時のみタイマーの代わりに動作させる
#endif
Loop
End
'*******************
Eventcheck:
If Fg_p_on = 0 Then
Debounce Sw_power , 0 , P_on , Sub 'パワーボタンを押せば・・・
Else
Debounce Sw_power , 1 , P_off , Sub 'パワーボタンを離せば・・・
End If
If Fg_m_on = 0 Then
Debounce Sw_mode , 0 , M_on , Sub 'モードボタンを押せば・・・
Else
Debounce Sw_mode , 1 , M_off , Sub 'モードボタンを離せば・・・
End If
If Fg_u_on = 0 Then
Debounce Sw_up , 0 , U_on , Sub 'アップボタンを押せば・・・
Else
Debounce Sw_up , 1 , U_off , Sub 'アップボタンを離せば・・・
End If
If Fg_d_on = 0 Then
Debounce Sw_down , 0 , D_on , Sub 'ダウンボタンを押せば・・・
Else
Debounce Sw_down , 1 , D_off , Sub 'ダウンボタンを離せば・・・
End If
If Fg_e_on = 0 Then
Debounce Sw_enter , 0 , E_on , Sub 'エンターボタンを押せば・・・
Else
Debounce Sw_enter , 1 , E_off , Sub 'エンターボタンを離せば・・・
End If
Gosub Button_check 'ボタンの状態を確認するサブルーチン
Gosub Count_check 'ボタンの長押しを確認するサブルーチン
Return
'************************
P_on:
Fg_p_on = 1 'パワーボタンのフラグを立てる
Return
M_on:
Fg_m_on = 1 'モードボタンのフラグを立てる
Return
U_on:
Fg_u_on = 1 'アップボタンのフラグを立てる
Return
D_on:
Fg_d_on = 1 'ダウンボタンのフラグを立てる
Return
E_on:
Fg_e_on = 1 'エンターボタンのフラグを立てる
Return
P_off:
Fg_p_on = 0 'パワーボタンのフラグを下げる
Return
M_off:
Fg_m_on = 0 'モードボタンのフラグを下げる
Return
U_off:
Fg_u_on = 0 'アップボタンのフラグを下げる
Return
D_off:
Fg_d_on = 0 'ダウンボタンのフラグを下げる
Return
E_off:
Fg_e_on = 0 'エンターボタンのフラグを下げる
Return
'******************
Count_check:
If C_p_tim >= P_tim Then 'パワースイッチを押してる時間のカウントが設定値を越えれば
' Incr C_speed_u '(長押しキープのイベント使わない場合はコメントアウト)
' If C_speed_u > Speed_p Then '(↓は長押し1回きりのイベント)
' C_speed_p = 0
' If Fg_fullcancel = 0 Then
' Gosub Sw_p_keep
' End If
' End If
If Fg_p_keep_sumi = 0 Then 'キープイベントフラグが立っていなければ
Fg_p_keep_sumi = 1 'フラグを降ろして
If Fg_fullcancel = 0 Then 'フルキャンセルフラグが立っていなければ
Gosub Sw_p_keep 'パワースイッチキープのサブルーチンへ(1度だけ)
End If
End If
End If
If C_m_tim >= M_tim Then
' Incr c_speed_m 'モードスイッチ長押しキープのイベント(使わない場合はコメントアウト)
' If c_speed_m > Speed_m Then
' c_speed_m = 0
' Gosub Sw_m_keep
' End If
If Fg_m_keep_sumi = 0 Then 'モードスイッチ長押し1回きりのイベント
Fg_m_keep_sumi = 1
If Fg_fullcancel = 0 Then
Gosub Sw_m_keep
End If
End If
End If
If C_u_tim >= U_tim Then 'アップスイッチを押してる時間のカウントが設定値を越えれば
Incr C_speed_u 'アップするスピードを調整する為のカウント
If C_speed_u > Speed_u Then 'カウントが設定値を超える度に
C_speed_u = 0
If Fg_fullcancel = 0 Then 'フルキャンセルのフラグが立っていなければ
Gosub Sw_u_keep 'アップキープのサーブルーチンへ
End If
End If
' If Fg_u_keep_sumi = 0 Then 'アップスイッチ長押し1回きりのイベント(使わない場合はコメントアウト)
' Fg_u_keep_sumi = 1
' Gosub Sw_u_keep
' End If
End If
If C_d_tim >= D_tim Then
Incr C_speed_d
If C_speed_d > Speed_d Then 'ダウンスイッチ長押しキープのイベント(↑のアップスイッチと同じ)
C_speed_d = 0
If Fg_fullcancel = 0 Then
Gosub Sw_d_keep
End If
End If
' If Fg_d_keep_sumi = 0 Then 'ダウンスイッチ長押し1回きりのイベント(使わない場合はコメントアウト)
' Fg_d_keep_sumi = 1
' Gosub Sw_d_keep
' End If
End If
If C_e_tim >= E_tim Then
' Incr C_speed_e 'エンタースイッチ長押しキープのイベント(使わない場合はコメントアウト)
' If C_speed_e > Speed_e Then
' C_speed_e = 0
' If Fg_fullcancel = 0 Then
' Gosub Sw_e_keep
' End If
' End If
If Fg_e_keep_sumi = 0 Then 'エンタースイッチ長押し1回きりのイベント
Fg_e_keep_sumi = 1
If Fg_fullcancel = 0 Then
Gosub Sw_e_keep
End If
End If
End If
Return
'******************
Button_check: '各ボタンのイベントを監視
If Fg_p_moto <> Fg_p_on Then 'パワーボタンの状態が変われば
If Fg_p_on = 1 Then 'パワーボタンONフラグが立てば
Fg_fullcancel = 0 'フルキャンセルのフラグを下げる
If Fg_m_on = 1 Then '同時にモードボタンONフラグが立っていれば
Gosub Sw_p_m 'パワー、モード同時押しのイベントへ
Fg_fullcancel = 1 'それぞれのボタンの単独押しのイベントをキャンセルする為にフルキャンセルのフラグを立てる
End If '↓以下同じ
If Fg_u_on = 1 Then
Gosub Sw_p_u
Fg_fullcancel = 1
End If
If Fg_d_on = 1 Then
Gosub Sw_p_d
Fg_fullcancel = 1
End If
If Fg_e_on = 1 Then
Gosub Sw_p_e
Fg_fullcancel = 1
End If
C_p_tim = 0 'パワーボタンのカウントをクリア
Fg_p_cou = 1 'カウントを開始するフラグを立てる
Fg_p_keep_sumi = 0 'キープイベント済みのフラグを下げる
Else 'パワーボタンOFFになれば
If C_p_tim < P_tim Then 'それまでの時間が設定値までならば
If Fg_fullcancel = 0 Then 'フルキャンセルフラグが立っていなければ
Gosub Sw_p 'パワースイッチONのイベントへ
End If
End If
C_p_tim = 0
Fg_p_cou = 0
End If
Fg_p_moto = Fg_p_on '現在のボタンの状況を変数に入れておく
End If
If Fg_m_moto <> Fg_m_on Then '↓ モードボタンの状態が変われば
If Fg_m_on = 1 Then 以下同じ
Fg_fullcancel = 0
If Fg_p_on = 1 Then
Gosub Sw_p_m
Fg_fullcancel = 1
End If
If Fg_u_on = 1 Then
Gosub Sw_m_u
Fg_fullcancel = 1
End If
If Fg_d_on = 1 Then
Gosub Sw_m_d
Fg_fullcancel = 1
End If
If Fg_e_on = 1 Then
Gosub Sw_m_e
Fg_fullcancel = 1
End If
C_m_tim = 0
Fg_m_cou = 1
Fg_m_keep_sumi = 0
Else
If C_m_tim < M_tim Then
If Fg_fullcancel = 0 Then
Gosub Sw_m
End If
End If
C_m_tim = 0
Fg_m_cou = 0
End If
Fg_m_moto = Fg_m_on
End If
If Fg_u_moto <> Fg_u_on Then '↓ アップボタンの状態が変われば
If Fg_u_on = 1 Then
Fg_fullcancel = 0
If Fg_p_on = 1 Then
Gosub Sw_p_u
Fg_fullcancel = 1
End If
If Fg_m_on = 1 Then
Gosub Sw_m_u
Fg_fullcancel = 1
End If
If Fg_d_on = 1 Then
Gosub Sw_u_d
Fg_fullcancel = 1
End If
If Fg_e_on = 1 Then
Gosub Sw_u_e
Fg_fullcancel = 1
End If
C_u_tim = 0
Fg_u_cou = 1
Fg_u_keep_sumi = 0
Else
If C_u_tim < U_tim Then
If Fg_fullcancel = 0 Then
Gosub Sw_u
End If
End If
C_u_tim = 0
Fg_u_cou = 0
End If
Fg_u_moto = Fg_u_on
End If
If Fg_d_moto <> Fg_d_on Then '↓ ダウンボタンの状態が変われば
If Fg_d_on = 1 Then
Fg_fullcancel = 0
If Fg_p_on = 1 Then
Gosub Sw_p_d
Fg_fullcancel = 1
End If
If Fg_m_on = 1 Then
Gosub Sw_m_d
Fg_fullcancel = 1
End If
If Fg_u_on = 1 Then
Gosub Sw_u_d
Fg_fullcancel = 1
End If
If Fg_e_on = 1 Then
Gosub Sw_d_e
Fg_fullcancel = 1
End If
C_d_tim = 0
Fg_d_cou = 1
Fg_d_keep_sumi = 0
Else
If C_d_tim < D_tim Then
If Fg_fullcancel = 0 Then
Gosub Sw_d
End If
End If
C_d_tim = 0
Fg_d_cou = 0
End If
Fg_d_moto = Fg_d_on
End If
If Fg_e_moto <> Fg_e_on Then '↓ エンターボタンの状態が変われば
If Fg_e_on = 1 Then
Fg_fullcancel = 0
If Fg_p_on = 1 Then
Gosub Sw_p_e
Fg_fullcancel = 1
End If
If Fg_m_on = 1 Then
Gosub Sw_m_e
Fg_fullcancel = 1
End If
If Fg_u_on = 1 Then
Gosub Sw_u_e
Fg_fullcancel = 1
End If
If Fg_d_on = 1 Then
Gosub Sw_d_e
Fg_fullcancel = 1
End If
C_e_tim = 0
Fg_e_cou = 1
Fg_e_keep_sumi = 0
Else
If C_e_tim < E_tim Then
If Fg_fullcancel = 0 Then
Gosub Sw_e
End If
End If
C_e_tim = 0
Fg_e_cou = 0
End If
Fg_e_moto = Fg_e_on
End If
Return
'******************
Tim_2: '↓1秒毎にボタンそれぞれのカウントをする
If Fg_p_cou = 1 Then 'カウント開始のフラグが立てば
Incr C_p_tim 'カウントを開始する
End If
If Fg_m_cou = 1 Then '↓以下それぞれのボタンに同じ動作
Incr C_m_tim
End If
If Fg_u_cou = 1 Then
Incr C_u_tim
End If
If Fg_d_cou = 1 Then
Incr C_d_tim
End If
If Fg_e_cou = 1 Then
Incr C_e_tim
End If
Return
'***********************
Sw_p: '↓ボタンそれぞれのイベント
Cls
Lcd "Power_ON"
Return
Sw_m:
Cls
Lcd "Mode_ON"
Return
Sw_u:
Incr Test_count
Cls
Lcd "Count_" ; Test_count
Return
Sw_d:
Decr Test_count
Cls
Lcd "Count_" ; Test_count
Return
Sw_e:
Cls
Lcd "Enter_ON"
Return
Sw_p_m:
Cls
Lcd "P_M"
Return
Sw_p_u:
Cls
Lcd "P_U"
Return
Sw_p_d:
Cls
Lcd "P_D"
Return
Sw_p_e:
Cls
Lcd "P_E"
Return
Sw_m_u:
Cls
Lcd "M_U"
Return
Sw_m_d:
Cls
Lcd "M_D"
Return
Sw_m_e:
Cls
Lcd "M_E"
Return
Sw_u_d:
Cls
Lcd "U_D"
Return
Sw_u_e:
Cls
Lcd "U_E"
Return
Sw_d_e:
Cls
Lcd "D_E"
Return
Sw_p_keep:
Cls
Lcd "Power_Keep"
Return
Sw_m_keep:
Cls
Lcd "Mode Keep"
Return
Sw_u_keep:
Gosub Sw_u
Return
Sw_d_keep:
Gosub Sw_d
Return
Sw_e_keep:
Cls
Lcd "Enter Keep"
Return