リンク

  • ninja analize
  • にほんブログ村

  • ジオターゲティング
  • ヤドカリ図鑑
  • リーフリング
  • NinjaTool
  • カウンター
    無料カウンター

AVRマイコン関連 Feed

2015年2月26日 (木)

重量計 完成

http://masax.blog.eonet.jp/default/2014/07/post-bd20.html
からの続き


昨年に自宅群が逃去し、必要性に迫られていなかったので

昨年の夏から随分長期間放置してた重量計の作製ですが・・・・・・


以前にノイズを拾っている原因が分かったので、それを取り除く事で

値のブレが非常に小さくする事ができていた。

でも、小さくても、やはりブレが出ると見苦しいので、できるところまでノイズをを除去しようと、アンプへの入力端子やアンプからマイコンへの入力端子へコンデンサーを繋いでみて、オシロスコープで様子を見ると、アンプへの入力端子2ヶ所は良くなったけれども、アンプからマイコンへの入力端子はコンデンサを付けると共振のような状態が見えたので、取り外した。

そして、回路的(ハード)には、もうこれ以上、私の技術や知識では改良する事はできないと判断し、先はプログラム(ソフト)で対処する事に。

アンプからの出力に商用電源の60Hzのノイズらしき波が常に乗ってる感じで、単発で瞬間の電圧測定では、その波の上下分のブレが出てしまうので、プログラムで、60Hzの一周期あたり100回のペースで2000回続けて(1秒間に6000回のペースで1/3秒間)電圧を測定し、その平均値を結果として取り出すプログラムを作ってみた。これでフィルターできるはず。

これで、いつものようにテストしてみると、

偶にブレが出るけれども、ブレが出る回数も非常に少なくなり、ブレの幅も小さくなり、許容範囲に収まった感じなので、測定部分はこれで完成とし、使い勝手や省電力の部分の自動電源OFFなどのプログラムを仕上げ、そして最後に、実際の重量と測定値が一致するようにアンプの増幅巾の調整をして、回路としては完成となり、その勢いでケースも完成した!!

P2260318

使い勝手としてはボタンが一つ存在するだけで、スイッチOFFの状態からボタンを押すと、現在の状況を0㎏としてリセットし、リセット後に増えた重量を測定する事になる。例えば単純に巣箱の重量を測る場合はセンサーの上に何も載せずにボタンを押してリセットしてから巣箱を載せると、巣箱の重量が表示されるし、巣箱を載せてからボタンを押すと、その状態で0㎏となり、その上に巣箱に継箱などを載せれば載せた継箱の重量だけが表示されるようになる。

実際にいろいろ測ってテストしてみたところ、特に問題はなし

完成したようだ!!





しばらく家に蜂がいない日が続いてますが

もうすぐミツバチの分蜂シーズンになるので楽しみ!!

 

2015年2月 9日 (月)

マイコンのテストボード

フォルス用のオリジナルコントローラー回路も完成し、ここ近々では作りたい電気回路が無くなったので、この機会に以前から作っておきたかったマイコンのテストボードを作る事にした。

テストボードというのは、マイコンにプログラムを書き込んで、そのプログラムが思うように機能するかどうかなどのテストをする為の基板で、言ってみれば実験用基板。


テストボードなど無くても、いきなり本番の回路から作成しても全く問題なく作成できるし、最初に作る時などは、その方が早く作れるので今まではそうしてきた。テスト用の基板を作るのも本番用の基板を作るのも同じ事だし・・・・・

でも、今までいくつかのマイコン回路を作ってきて思うのが、一つの回路を作って完成してからバージョンアップせずに最初のままで使ってる回路は一つもなくて、どの回路も使ってるうちに新しい機能が欲しくなるのでバージョンアップを重ねる事になってきているけれども、そんな風に一度出来上がったマイコンのプログラムをバージョンアップする時などは本番の基板だとプログラムの変更のテストに、いちいち稼働中の装置を外してテストする必要があるので、書き換えのテストをしてる最中は本来の機能を果たす事ができなかったり(例えばサーモスタット変温くんのプログラムを書き換えるときにはサーモスタットを外す事になるし、ウェーブコントローラー激波のプログラム書き換え時には波が立たなくなる)、また外して書き換えて装着し、また外すという繰り返しが結構面倒なので、これから先のマイコン回路の開発や、今までに作った回路のバージョンアップのために、今回テストボードを作る事にした。

テストボードがあれば、プログラムを書き換えたくなったときも、稼働中の装置はそのまま稼動させておいて、新しく別のマイコンチップにプログラムを書き込んでテストボードで思うように作動するかを十分にチェックしてから本装置のマイコンチップと入れ換えれば良いだけなので、慌てて作業する必要が無くなるし、ゆっくり落ち着いてプログラムできるので自分で納得できる物を作る事ができる。・・・・・・はず

これから先、どんな回路を作るかは分からないし、今までに作った回路の構造も違うし、使ってるマイコンチップもそれぞれ違うので、これからもきっと使うであろう40ピン、28ピン、20ピン、8ピンと4種類のマイコンに対応できる回路にし、また、多くの場合に使うであろうボタンスイッチ、LED、ボリュームを複数と表示用のLCDを装備しておき、クロック用のクリスタルもワンタッチで脱着が可能なようにしてみた。

P2090014 
あ、そうそう、デバッグ時にマイコンの動きをPCで確認する為に、PCへデータを送信できるようにシリアル出力用のケーブルも追加装備してPCと接続できるようにおこう!!


これできっと多くの場合に対処出来ると思うけど、こんなの作るのは初めてなので実際は使ってみないと分からないのが正直なところ・・・・・


さて、どんな風に仕上がるか   ??

2012年5月12日 (土)

プログラム書き換え

久しぶりにサーモスタット「変温君」とウェーブコントローラー「激波」のプログラムを一部書き換えた。

サーモスタットやウェーブコントローラーとしての主要な仕事をする部分ではなく スイッチ操作に関する部分のプログラムで 単に押すだけではなく、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

 

2012年3月 6日 (火)

プログラムを整理

今まで 少ないながらも AVRマイコンのプログラムを書いてきて

つい最近まで知らなかった事があって


それは プログラムを書き込むプログラマー(BASCOM AVR)に

プログラムコードだけではなくて そのプログラムコードの意味を書いたり

説明書きを書いたり プログラムとは関係ない文字を

コメントとして書き込んでおく事ができるのですが

以前は書き込もうとしても 英数でしか書き込めなかったので

正直なところ 私には使い物にならなかった。


このBASCOM AVRは外国製のものですから 仕方がない事だと思ってたのですが

最近、いつもAVRでお世話になっていたO-Familyさんのところで

日本語のコメントが書き込める事を教えて頂いた事をきっかけに

今まで書いてきていた サーモスタット「変温君」のプログラムに

後で、自分でコードを見たときに何をしてるコードなのかが分かり易いように

コードに順番にコメントを書き込んでいた。

Book1001

右側に緑色の文字で書いてあるのが コメントですが

こんな風に書いておかないと

自分で書いたプログラムでも 後で見た時には

何の意味があるプログラムなのかが 理解するのに難儀する事がよくあるから

なのですが

こうして コメントを書くには 書いたコードの意味(仕事)をもう一度

思い出す必要があり 同時に もう一度コード全体を見直す事にもなる。


そうやって順番に見直してると

たくさん書いてるプログラムコードの中に 全く使っていないコードが残っていたり

間違っているのに 影響なく動作しているコードがあったり

書き直した方が良い部分がたくさん有る事に気付く事になる。

実際のところは マイコンとしては 正常に作動してるので

書き直す必要性は無いけれども 無駄なコードが入ってるのは

気分的によろしくないのと 無駄なコードを省けば

それだけ マイコンのメモリーの空きも増える。


そんなところで 一通りコードを見直してみて

気付いたところは 全て書き直してみたところ

それまで フラッシュメモリーの93%を使っていたプログラムでしたが

整理する事で 90%まで節約する事ができた。



とは言っても 容量の大きなマイコンのメモリーを

ほとんど目一杯使ってる(笑)

 

2011年6月25日 (土)

もうちょっと 頑張ってみた

昨日、作り替えた サイン波作成プログラム

ハードウェア主体にしたけれども 最後に残った「割り算」が一つ
これが有るのと 無いのとでは大きな違いで 「掛け算」は「足し算」の2~5倍 「割り算」は「掛け算」の5~10倍くらいの時間が掛かるし 「割り算」は「足し算」の何十倍掛かる事もある


そんな事で 実のところ 計算式が無い「禁断の手法」では 出力している周波数をモニターしてLCDに表示するプログラムが組めたのですが この「割り算」が一つ入ったプログラムで このモニタープログラムを追加すると パンク状態になって表示できなかった




これでは 面白くないので もう一工夫

よく考えれば 「割り算」で出せる答なら 工夫すれば「掛け算」に換えられるはずだ!!





そんな事で 最後の悪あがき!!・・・・いつも悪あがきですが






と 思ったけど

でも やったらできるんですね!!



最後に残った「割り算」一つを「掛け算」に書き換えました




昨日まではセットしていなかったフィルターをセットして波形を確認すると

P6240398

どちらのプログラムも それはそれは綺麗な まったく傷のない

ツルツル、ピカピカのサイン波が出てきた!!




ソフトウェアでON、OFFせずに ハードウェアに任せるだけで これだけピカピカになるとは 驚きと共に

早く、こうすれば良かった、と後悔しました




これで どれだけのキャリア周波数まで追従できるのかテストしてみると



ぱっと見は 結構上まで追従できてるように見えてたのですが

よくよく見ると 追従できていないようで徐々に割り込みが遅れるようになってくる(周波数が合わなくなってくる)

しっかりと追従できるのは 12KHzまで

最後に残った「掛け算」一つがブレーキになったようだ



もう一つの「禁断の手法」では プログラム内に計算式が一つもない分 余裕があるのか?

43KHzまで乱れもなく綺麗な波形のままで追従できた


これも これ以上キャリアを上げると 割り込みが遅れてくるようになる




どちらにしても 今回、そんなに高いキャリアを求めてる訳ではなく

単に正弦波フェチが 綺麗な正弦波を求めてただけなので

充分に満足できる仕上がりになった

これで 今度こそ仕上げに向かっていきます

2011年6月24日 (金)

こんな方法が有ったのか

今まで私が作ってきた サイン波を作成するプログラムは マイコンのタイマーの機能を利用したソフトウェア主体のプログラムでした 


これは 私が思ってた信号の出力方法が ハードウェア主体ではできない、と思ってたからなんですが

いや単なる私の知識が無かっただけで 実はそんな機能も有ったんです!! 



またまたO-Familyさんが 気付かせてくださいました






そんな事なら・・・・・・・・





今までのプログラムではPWMを OCR1Aでキャリア周波数を制御する為の割込み OCR1Bでデューティー比を制御する為の割込みを発生させて 主にソフトウェアでポートの出力を制御しておりました

これはハードウェア主体では 一つのタイマーでOCR1AとOCR1Bの設定だけで 別々の2つの波形を出力する方法が思いつかなかったからなんですが

よくよく勉強してみると OCR1AとOCR1Bの他にタイマーのモードによってICR1という値が設定できる事がわかった

今までは OCR1Aでタイマーカウント値の上限(TOP)を設定して OCR1Bで途中の割り込み地点を設定できるだけだと思ってたので どう考えても 2つの別々の出力をする方法が思いつかなかったのですが

ICR1という値で TOPを設定する事ができる事がわかった

これができればICR1でキャリア周波数を設定して OCR1AとOCR1BでOC1AとOC1Bからの出力のデューティー比を別々に設定する事ができるので 2つの違った波形を出力する事が可能になる



なんだ そうだったのか!!

という内容ではありますが マイコンの機能は いっぱい有り過ぎて

ちょっとや そっと マニュアルを見たところで なかなか理解できるものではない


特に私のような原始人には・・・・・・・・



そんな時に いつも助けてくださるのが O-Familyさん

いつもありがとうございます




そんな事で ハードウェア主体のサイン波生成プログラムを2種類 作ってみた



一つ目は  一般的な本来の手法で キャリア周波数を固定して 周波数の調整は使うキャリア数で制御する方法

もう一つは 使うキャリア数を固定しておいて 周波数の調整はキャリアの周期で調整する方法で これは禁断の手法のようですが 今まで私が続けてきた手法です


まだ フィルターを付けていないので どんな波形になったのかは確認できませんが

パルスの波形を見る限りでは どちらも 一応仕上がったかな?、という感じで

P6240392

ハードウェア主体にした事で どこまで高いキャリアに追従できるのかを確認していきたいところですが 上記のキャリア周波数固定の手法では どうしてもプログラム内に「割り算」が入ってしまうので これが どれだけの重荷になるか?
出来る限りプログラム内から計算式を省いてみたのですが どうしても割り算が一つ残ってしまう
マイコンの中で「割り算」という計算は かなり時間を使う計算で しかも小数以下の計算だと尚更ですが これがどれだけの足かせになるか


もう一つの禁断の手法では プログラム内から一切の計算式を省く事ができたので こちらは まあまあのキャリア周波数まで追従できるのではないか、と思われるけれども
何でも そうで 良いところが有れば悪いところもあって 一長一短



波形を確認してからになりますが

完成すれば また どちらを使うか迷う事になりそうな気がする!!  

2011年6月22日 (水)

ハードウェアタイマーの使い方

サイン波を作るプログラムは 既に完成していて

ポンプの駆動も問題なく

このまま完成させようとしてたところですが



O-Familyさんより PWMを作るハードウェアタイマーの使い方の問題点を御指摘頂き

考え直しておりました


既に作っていたプログラムは先日、記事にしたように 確かに アブノーマルな手法で

シビアな目で見ると 正確な時間を刻むハードウェアタイマーの使い方ではない



そんなところで もう一度 ハードウェアタイマーの使い方(モード)を考え直す事にした



今までのタイマーの設定は

Config Timer1 = Timer , Prescale = 1 , Clear Timer = 1
Compare1a = Koma1 - 1
Compare1b = 1500
On Compare1a Tim2
On Compare1b Tim3
Enable Compare1a
Enable Compare1b

「比較一致 CTC動作」というモードで

PWMの波長や周波数を調整するCompare1AやCompare1Bの値を プログラムで書き換えると その場で書き換わるらしくて このタイミングが悪いとタイミングが悪いまま書き換わってしまうらしくて そこに問題が有るとの事 



そんな事で 他にもいろいろなモードがある中で

まず重要なのが 「比較器[OCR1x]の更新」のタイミングらしくて これがBOTTOMになるモードを使うと良いらしい

それから「TIMER1[TCNT1]TOP値」が「OCR1A」あるいは「ICR1」になるモードを選ぶ

この条件で選んでみると

「位相・周波数基準PWM動作」で2つのモード

「高速PWM動作」で2つのモード

合計4つのモードがリストに挙がる


元々 今のサイン波プログラムを作り始めた時に上記「高速PWM動作」モードでやり始めたのですが まったくサイン波にならずに 勝手に「こういう使い方はできないんだ」と思い込んで やめてしまってた


そんな事で もう一度 今までのプログラムのままでタイマーの設定だけを変えてみると

やっぱり まったくサイン波にならない



これではまったく進まないので まずは 上記の4つのモードの簡単なプログラムを書いてみて

波長、周波数を調整する方法を確認してみると どれも そうも問題なく 同じ様な使い方で 波長も周波数も制御できるじゃないか!

問題なく制御できているので 最低限サイン波だけ出力するプログラムだけを取り出して入れてみると 問題なく サイン波が出力されている

どうして 前のプログラムでサイン波が出なかったのか?



これを確かめる為に 現在のプログラムのタイマーのモード設定を「高速PWM動作」の

TOPを「ICR1」にするモードに書き換えて実行してみると やっぱりダメ

ここから 順番に引っかかりそうなコードを省いていきながら サイン波が出るか確認していく


とことんコードを省略していって テストでサイン波が出たプログラムと もう何も違いは無いところまで省略したのに サイン波が出ない!

2つのプログラムの違いになる部分が解らないし もう省けるところも無い



なぜだ!!





この状態から かれこれ30分は まぶたが腫れてあんまり見えない目で コードを睨み続けていた気がする・・・・





そこでやっと 違いに気付いた



以前のプログラムでは タイマーの設定のコードの後 すぐに 「Stop Timer1」でタイマーを止めておいて メインループの寸前で再スタートさせていた

テストプログラムでは これをやっていない


試しに タイマーを止めるのをやめて メインループの寸前でタイマーを設定するようにしてみると サイン波が出た!!

「比較一致 CTC動作」モードでは タイマーを止めてもまったく問題は無かったけれども

「位相・周波数基準PWM動作」

「高速PWM動作」

のモードではタイマーを一度止めると正常に機能しなくなるのかも知れない


ここは深くは解らないけど 先に進む事にする


タイマーを止めなければ サイン波が出る事が解ったので もう一度最初のプログラムで タイマーを止めないコードに書き換えると これも問題なくサイン波が出力された!!

P6220386

これで一つ解決!!



でも よく見ると サイン波の線が あまり綺麗ではないし

半波を200コマ割りにしたキャリア周波数だと 凸凹になる(画像は100コマ割り)


「反則技」を使っていた元の「比較一致 CTC動作」を使ったプログラムも 反則技を使わずに波形が繋がる比較器の設定タイミングが分かったので やってみると

P6220388

画像では分かり辛いが ±の切り替わり部分以外の線は こちらの方が滑らかで綺麗に仕上がっている
でも これも 200コマ割りにすると少々凸凹になる 



反則技を使った 元のプログラムが 一番綺麗な波形だったりするのと

これだと 500コマ割りでも 波形が大きく丸くなるけれども 凸凹が出ずに綺麗なカーブを描いてくれる 

P6220390




さてと

結局のところ どれを使う事にしようか?


オーディオの音質に拘ってるなら いざ知らず
ポンプをコントロールするのに きっと この程度の違いは どれを使っても差は出ないと思うけれども

正弦波フェチとしては悩むところです(笑)!!

 

2011年6月19日 (日)

ちょっと試しに

PMWのキャリア周波数も少し上げる事ができたので

ちょっと試しに先日組んだフルブリッジ回路とフィルター回路で フィルターできるかやってみた

線が細くなってるので フィルターとしては できてる事になるんだろうか?

でもスイッチONで周波数を上げると とんでもなく電圧が上がってるのと

OFFにしてから 電圧が一気に落ちずに ゆっくりと落ちてるのが分かる


これは ひょっとしてスイッチングで電圧を調整する スイッチング電源の原理みたいなものなんだろうか?



よく分からないけど どっちにしても これでは使い物にならない

そもそも この方法は難しかったのかも知れないな!!

2011年6月18日 (土)

改良

昨日のプログラムの改良で サイン波の波形が綺麗に繋がるようになったけれども

よく考えると ある部分でタイマーを止めてるのと 無理やりカウントを0にしてる部分がある訳だから 細かい事を言うと PWMの1周期毎に 実際はタイマーを止めていた分の時間が加わる事になる

またPWMのキャリア周波数を上げれば上げるほど狂いも大きくなる

これを計算をするとキャリア周波数が12KHz時で 60Hzを作ったつもりが 実際には約55.4Hzになる計算になった


これは ちょっと面白くないので このタイマーを止めてる時間がどれくらいになるのか再度、測定してみると およそ140カウントなので


PWMの1周期を設定するCompare1aの値を はじめから140引いておく事にした

これで 60Hzに設定すれば ほぼ正確に60Hzで出力されるようになる



と思ったところで・・・・・




ちょっと待てよ!!

何の為にマイコン使ってんだ?




わざわざ この140カウントを計らなくても

マイコンに計算させて 何カウント引けば ぴったり60Hzになるのか出してくれるプログラムを作れば良いんだ!!



という事で 

まずは簡単な周波数カウンターの機能をプログラムに入れてみると

出力してる周波数は54Hz




54Hzでは そのままだと ポンプがはっきりと弱くなる


そんな事で 周波数補正プログラムも作って組み込んでみると

これでCompare1aの値を177引いておけば 60Hzになってくれる

という事です 




今日は ここまで!!

2011年6月17日 (金)

なるほど そういう事か

先日から サイン波になぜか傷ができる件で いろいろ考える中

そらさんが 実際に同じ様なプログラムでテストして下さって

原因を特定して頂いたので 自分でもプログラムの動きを分析してみた

まずは フィルターを通した出力と 通さない出力をオシロスコープで同時に測定してみた

P6170355

確かに間違いなく Compare1aの割り込み時に起こっている

一コマ分、ONのままになってる時間があるようだ



次にCompare1aの割り込み(ポートをセットする)に入ってから ポートのリセットをするCompare1bの割り込みに入るまでのカウントを測ってみると およそ138あたりになる

それから サイン波の半波の両端部分のサイン波データを取り出すと 半波を100コマ割りの時で 始めと終わりの5コマ分ほどは138を下回ってる




この事からプログラムを解析してみると



↓今までのプログラム

Incr C_cycle
If C_cycle > Koma Then
  C_cycle = 1
  Toggle Fg_out1

  If Sw_on = 1 Then
    Compare1a = Compa1a_hi ’およそ1666
  Else
    Compare1a = Compa1a_low ’およそ5000
  End If
End If

If Sw_on = 1 Then
  Compare1b = Sinha_hi(c_cycle) ’サイン波データ半波分のデータを入れた配列
Else
  Compare1b = Sinha_low(c_cycle) ’Sinha_hi(c_cycle)のデータを何パーセントか減じた値の配列
End If

↑実際には(サイン波半波の両端付近では)この時点で Timer1のカウントはCompare1b を超えている

※Timer1=0  ’ここでタイマーをクリアすると治まる

↓Timer1がCompare1bを超えてからポート出力をONにするものだから 次の割込みに入るまでONのままで もしも次の割込みでもCompare1bより小さい場合には もう一コマONのまま進んでしまう 

If Fg_out1 = 0 Then
  Reset Out2
  Reset Swit2

  Set Out1
  Set Swit1
Else
  Reset Out1
  Reset Swit1

  Set Out2
  Set Swit2
End If



それなら サイン波両端の0に近い部分では ポート出力をONにせず(どうせ小さな電圧だし) 無視して走っていけば解決するんじゃないか?

Compare1aの割り込みに入ってからCompare1bの割り込みでポートをリセットするまでのカウントが 凡そ138だったので 余裕を見て サイン波データが150以下の場合は無視するようにしてみた

という事で 書き直してみたのが これ↓

     Incr C_cycle
     If C_cycle > Koma Then
       C_cycle = 1
       Toggle Fg_out1

       If Sw_on = 1 Then
          Compare1a = Compa1a_hi
       Else
          Compare1a = Compa1a_low
       End If
     End If

     If Sw_on = 1 Then
        Compare1b = Sinha_hi(c_cycle)
     Else
        Compare1b = Sinha_low(c_cycle)
     End If

     If Compare1b > Timplus Then ’このTimplusを150に設定
        If Fg_out1 = 0 Then
          Reset Out2
          Reset Swit2

          Set Out1
          Set Swit1
        Else
          Reset Out1
          Reset Swit1

          Set Out2
          Set Swit2
        End If

     End If

少々仕事が増えた事になりますが

これで どうだっ!!

低いコマ数ほど 強く出てた症状ですが

P6170367

30コマ割の 少ないコマ数でも スムーズに繋がるようになった

0V付近で スキップしてるデータがあるので 少し歪みが出てますが

今回は理由が分かってるのと ポンプを回すに当たってこの程度の歪みは

まったく影響の無いレベルなので 合格とします

フィルターを弱くしたので ぱっと見は昨日の波形の方が滑らかですが

こっちの方が正確です


どうしてタイマー1をクリアすれば解決したのかも理解できた



そらさん ありがとうございます!!




ここで面白いのが 乱れた波形を見ると どう見てもCompare1aの割り込み時(0V時)に見えないタイミングなのですが これはフィルターのコンデンサで 周期が送れて出てきてるものだったのも分かった



もう少し 波形を綺麗にする事もできる気がするので もう少しだけ頑張ってみる 

追記

最終的には

 Stop Timer1
   上記サブルーチン
 Timer1 = 0
 Start Timer1

として 上記Timplusを20に設定し

20以下のサイン波データだけを無視する事にした

P6170370_2

波形が歪むけれども キャリア周波数は高い方で40KHzでも追従できるようになった

(上記画像は8KHz 下の画像が40KHz)

P6170371