デジタル回転計キット新バージョン

デジタル回転計キットが全部売り切れてしまったので新バージョンを作成します。旧バージョンも引き続き販売しますが低回転版やプロペラ版などソフトが増えすぎたのでちょっとやり方を変更。

改良点
 ・旧バージョンは 最低計測回転数を20rpmに固定
  プロペラ版や低回転版、カウンター改造キットなどの亜種を全て廃止
 ・もっと小さな小型版を追加
  価格は旧バージョンの回転計と同じ
 ・USB経由でプログラムを書き換えられる高機能版を追加
  プロペラの回転数やカウンターとして使用したいときはこちらを使用する
  ソフトはホームページで公開
  PIC18F2550やUSBコネクターを使用するため価格はちょっと高くなる


2010-01-25

OLIMEXで試作基板を作成。

PICT1518.jpg

小型版。幅52mm

PICT1520.jpg

USBでプログラムを書き換えられる多機能版の試作基板

2010-01-31

プログラムを移植して動作確認。桁あふれするまで高速回転するモーターがないのでファンクションジェネレーターを信号源にして実験。

PICT1603.jpg

ブレッドボード上の回路はファンクションジェネレーターの信号をTTLレベルに変換する回路

回路図とプログラム暫定版
ファイル ファイルタイプ 添付ファイルの解説
kaitenkeiMINI.zip mikroBasic プログラム暫定版一式
kaitenminiSCH.PNG PNG 回路図

2010-02-03

多機能版も組み立てた。ソフトが無いのでまだ動かない。

PICT1661.jpg

USBコネクターが2つ有るが並列に繋がっている。基板パターン確認のため2つ付けた。

2010-02-04

mikrobasicで書いた回転計のプログラムをPIC18F専用のBASICコンパイラ Swordfish compiler に移植。ブートローダーに対応させるための修正がmikrobasicでは無理。

PICT1668.jpg

ここまで来れば後は単純作業が残っているだけ

ソードフィッシュSEで書いたプログラム。ネット上にサンプルが少ないので最終版ではないが載せておく。当方がこの言語で書いた最初のプログラムなので書式のお作法がソードフィッシュ流でないところが有る可能性大
0001  Program kaitenkeiBOOT
0002
0003 Device = 18F2550
0004 Clock = 48
0005
0006 Config
0007 USBDIV = 1,
0008 PLLDIV = 5,
0009 FOSC = HSPLL_HS,
0010 MCLRE = OFF
0011
0012
0013 Include "Convert.bas"
0014
0015 // #option org_reset = $1000
0016 // #option vector_isr_hi = $1008
0017 // #option vector_isr_lo = $1018
0018
0019
0020 Const ipLow = 1
0021 Const ipHigh = 2
0022
0023
0024 Const CONST_MIN = 720000000 ' TMR1 count 1 min @ 11.776MHz
0025 Const ZERO_CLEAR_TIME = 1500 ' 1500 x 2ms = 3.0 sec
0026 Const HALF_SECOND = 91 ' timer1 overflow @ 0.5sec
0027
0028
0029 '---- 7segment LED const definitions ----------------
0030 Const Digit_N = $FF ' Blank
0031 Const Digit_0 = $03
0032 Const Digit_1 = $9F
0033 Const Digit_2 = $25
0034 Const Digit_3 = $0D
0035 Const Digit_4 = $99
0036 Const Digit_5 = $49
0037 Const Digit_6 = $41
0038 Const Digit_7 = $1F
0039 Const Digit_8 = $01
0040 Const Digit_9 = $09
0041
0042 Const INT0IF = 1
0043
0044 Const LED_ON = 0
0045 Const LED_OFF = 1
0046
0047 Const High_priority = 1
0048 Const Low_priority = 0
0049
0050 Structure LWBstruc
0051 LongwordVal As LongWord Union
0052 WordVal(2) As Word Union
0053 ByteVal(4) As Byte Union
0054 End Structure
0055
0056 Dim tempLWB As LWBstruc
0057
0058 Dim LED_DEV5 As PORTA.4
0059 Dim LED_DEV4 As PORTA.3
0060 Dim LED_DEV3 As PORTA.2
0061 Dim LED_DEV2 As PORTA.1
0062 Dim LED_DEV1 As PORTA.0
0063
0064 Dim LED_SEG_PORT As PORTB
0065 Dim LED_SEG_A As PORTB.7
0066 Dim LED_SEG_B As PORTB.6
0067 Dim LED_SEG_C As PORTB.5
0068 Dim LED_SEG_D As PORTB.4
0069 Dim LED_SEG_E As PORTB.3
0070 Dim LED_SEG_F As PORTB.2
0071 Dim LED_SEG_G As PORTB.1
0072
0073 Dim PHOTO_REF_PORT As PORTB.0
0074
0075
0076 Dim led_val1 As Byte
0077 Dim led_val2 As Byte
0078 Dim led_val3 As Byte
0079 Dim led_val4 As Byte
0080 Dim led_val5 As Byte
0081 Dim led_pos As Byte
0082
0083 Dim start_flag As Boolean
0084 Dim display_flag As Boolean
0085 Dim of_count As Word ' over flow counter
0086
0087 Dim TMR1L_value As Byte
0088 Dim TMR1H_value As Byte
0089 Dim TMR1_OVF_value As Word
0090
0091 Dim rpm As LongWord
0092 Dim tmr1_count As LongWord
0093 Dim count_div As LongWord
0094 Dim count_tmp1 As LongWord
0095 Dim count_tmp2 As LongWord
0096 Dim rotate As LongWord
0097 Dim rotate_value As LongWord
0098
0099 Dim zero_display_counter As Word
0100
0101 '-------- INT0 ------------------------------------------
0102 Dim PortB0_changed As INTCON.booleans(1)
0103 Dim PortB0_int_enable As INTCON.booleans(4)
0104 Dim PortB0_int_rising_edge As INTCON2.booleans(6)
0105
0106 '-------- TMR0 ------------------------------------------
0107 Dim Timer0_overflowd As INTCON.booleans(2)
0108 Dim Timer0_interrupt_enable As INTCON.booleans(5)
0109 Dim Timer0_priority As INTCON2.bits(2)
0110 Dim Timer0_enable As T0CON.booleans(7)
0111 Dim Timer0_mode_8bit As T0CON.booleans(6)
0112 Dim Timer0_use_external_clock As T0CON.booleans(5)
0113 Dim Timer0_prescale_NOT_assign As T0CON.booleans(3)
0114 Dim Timer0_prescale_bit2 As T0CON.bits(2)
0115 Dim Timer0_prescale_bit1 As T0CON.bits(1)
0116 Dim Timer0_prescale_bit0 As T0CON.bits(0)
0117
0118
0119 '-------- TMR1 ------------------------------------------
0120 Dim Timer1_overflowd As PIR1.booleans(0)
0121 // Dim Timer1_peripheral_int_enable as INTCON.booleans(6)
0122 Dim Timer1_interrupt_enable As PIE1.booleans(0)
0123 Dim Timer1_prescale_bit0 As T1CON.bits(4)
0124 Dim Timer1_prescale_bit1 As T1CON.bits(5)
0125 Dim Timer1_use_external_clock As T1CON.booleans(1)
0126 Dim Timer1_enable As T1CON.booleans(0)
0127 Dim Timer1_priority As IPR1.bits(0)
0128
0129 '-------- A/D converter ---------------------------------
0130 Dim ADconfig3 As ADCON1.3
0131 Dim ADconfig2 As ADCON1.2
0132 Dim ADconfig1 As ADCON1.1
0133 Dim ADconfig0 As ADCON1.0
0134
0135 '-------- comparator ------------------------------------
0136 Dim Comparator_mode2 As CMCON.bits(2)
0137 Dim Comparator_mode1 As CMCON.bits(1)
0138 Dim Comparator_mode0 As CMCON.bits(0)
0139
0140 '-------- PORTB -----------------------------------------
0141 Dim PortB_pullups_disable As INTCON2.booleans(7)
0142
0143 '-------- interrupt -------------------------------------
0144 Dim Interrupt_HIGH_enable As INTCON.booleans(7)
0145 Dim Interrupt_LOW_enable As INTCON.booleans(6)
0146 Dim Interrupt_priority As RCON.booleans(7)
0147
0148
0149 '===============================================================================
0150 ' interrupt priority HIGH
0151 '===============================================================================
0152 Interrupt OnChangePORTB(ipHigh)
0153 '---- signal was detected
0154 If PortB0_changed Then
0155 If start_flag = true Then ' save TMR1 value
0156 TMR1L_value = TMR1L
0157 TMR1H_value = TMR1H
0158 rotate = rotate + 1
0159 If of_count >= HALF_SECOND Then
0160 TMR1_OVF_value = of_count
0161 TMR1L = 0
0162 TMR1H = 0
0163 rotate_value = rotate
0164 of_count = 0
0165 rotate = 0
0166 display_flag = true
0167 End If
0168 Else
0169 TMR1L = 0
0170 TMR1H = 0
0171 of_count = 0
0172 rotate = 0
0173 start_flag = true
0174 End If
0175 zero_display_counter = 0
0176 PortB0_changed = false
0177 End If
0178 End Interrupt
0179
0180
0181 '===============================================================================
0182 ' interrupt priority LOW
0183 '===============================================================================
0184 Interrupt OnTimer(ipLow)
0185
0186 '---- TMR1 overflow ----------
0187 If Timer1_overflowd Then
0188 Timer1_overflowd = false
0189 of_count = of_count + 1
0190 End If
0191
0192 '--- TMR0 overflow (7SEG_LED storobe) 2 msec
0193 If Timer0_overflowd Then
0194 TMR0L = 69
0195 Select led_pos
0196 Case 1
0197 LED_DEV5 = LED_OFF
0198 LED_SEG_PORT = led_val1
0199 LED_DEV1 = LED_ON
0200 led_pos = led_pos + 1
0201 Case 2
0202 LED_DEV1 = LED_OFF
0203 LED_SEG_PORT = led_val2
0204 LED_DEV2 = LED_ON
0205 led_pos = led_pos + 1
0206 Case 3
0207 LED_DEV2 = LED_OFF
0208 LED_SEG_PORT = led_val3
0209 LED_DEV3 = LED_ON
0210 led_pos = led_pos + 1
0211 Case 4
0212 LED_DEV3 = LED_OFF
0213 LED_SEG_PORT = led_val4
0214 LED_DEV4 = LED_ON
0215 led_pos = led_pos + 1
0216 Case 5
0217 LED_DEV4 = LED_OFF
0218 LED_SEG_PORT = led_val5
0219 LED_DEV5 = LED_ON
0220 led_pos = 1
0221 EndSelect
0222 zero_display_counter = zero_display_counter + 1
0223 Timer0_overflowd = false ' Clear interrupt flag
0224 End If
0225 End Interrupt
0226
0227
0228 '===============================================================================
0229 ' decode ascii-char -> 7segment-LED
0230 '===============================================================================
0231 Function led7seg_decode( ascii_char As Char ) As Byte
0232 Select ascii_char
0233 Case " " result = Digit_N
0234 Case "0" result = Digit_0
0235 Case "1" result = Digit_1
0236 Case "2" result = Digit_2
0237 Case "3" result = Digit_3
0238 Case "4" result = Digit_4
0239 Case "5" result = Digit_5
0240 Case "6" result = Digit_6
0241 Case "7" result = Digit_7
0242 Case "8" result = Digit_8
0243 Case "9" result = Digit_9
0244 Else result = Digit_N
0245 EndSelect
0246 End Function
0247
0248
0249 '*******************************************************************************
0250 ' Program main
0251 '*******************************************************************************
0252 Dim led_txt As String(6)
0253
0254 PortB_pullups_disable = true
0255
0256 PortB0_int_enable = true
0257 PortB0_int_rising_edge = true
0258
0259 ADconfig0 = 1 ' PortA Digital I/O
0260 ADconfig1 = 1
0261 ADconfig2 = 1
0262 ADconfig3 = 1
0263
0264 Comparator_mode2 = 1 ' compatator off
0265 Comparator_mode1 = 1 ' compatator off
0266 Comparator_mode0 = 1 ' compatator off
0267
0268
0269 Input(PHOTO_REF_PORT)
0270
0271 Output(LED_DEV5)
0272 Output(LED_DEV4)
0273 Output(LED_DEV3)
0274 Output(LED_DEV2)
0275 Output(LED_DEV1)
0276
0277 Output(LED_SEG_A)
0278 Output(LED_SEG_B)
0279 Output(LED_SEG_C)
0280 Output(LED_SEG_D)
0281 Output(LED_SEG_E)
0282 Output(LED_SEG_F)
0283 Output(LED_SEG_G)
0284
0285
0286 LED_DEV5 = LED_OFF
0287 LED_DEV4 = LED_OFF
0288 LED_DEV3 = LED_OFF
0289 LED_DEV2 = LED_OFF
0290 LED_DEV1 = LED_OFF
0291
0292 led_val1 = Digit_8
0293 led_val2 = Digit_8
0294 led_val3 = Digit_8
0295 led_val4 = Digit_8
0296 led_val5 = Digit_8
0297 led_pos = 1
0298
0299
0300 '---- TMR0(8bitMODE) initialize --------------
0301 Timer0_prescale_bit2 = 1 ' PreScaler 1:128
0302 Timer0_prescale_bit1 = 1 ' PreScaler 1:128
0303 Timer0_prescale_bit0 = 0 ' PreScaler 1:128
0304 Timer0_prescale_NOT_assign = false
0305 Timer0_mode_8bit = true
0306 Timer0_interrupt_enable = true
0307 Timer0_use_external_clock = false
0308 Timer0_enable = true
0309 Timer0_priority = Low_priority
0310
0311 '---- TMR1(16bit) initialize -----------------
0312 // Timer1_peripheral_int_enable = true
0313 Timer1_interrupt_enable = true
0314 Timer1_prescale_bit0 = 0
0315 Timer1_prescale_bit1 = 0
0316 Timer1_use_external_clock = false
0317 Timer1_enable = true
0318 Timer1_priority = Low_priority
0319
0320 '---- interrpt -------------------------------
0321 Enable(OnChangePORTB)
0322 Enable(OnTimer)
0323 Interrupt_priority = true
0324 Interrupt_HIGH_enable = true
0325 Interrupt_LOW_enable = true
0326
0327 rpm = 0
0328 DelayMS(1000)
0329 led_val1 = Digit_0
0330 led_val2 = Digit_N
0331 led_val3 = Digit_N
0332 led_val4 = Digit_N
0333 led_val5 = Digit_N
0334
0335 TMR1L_value = 0
0336 TMR1H_value = 0
0337 TMR1_OVF_value = 0
0338 rotate_value = 0
0339
0340 zero_display_counter = 0
0341 start_flag = false
0342 display_flag = false
0343 While( true )
0344 If zero_display_counter >= ZERO_CLEAR_TIME Then
0345 led_val1 = Digit_0
0346 led_val2 = Digit_N
0347 led_val3 = Digit_N
0348 led_val4 = Digit_N
0349 led_val5 = Digit_N
0350 zero_display_counter = 0
0351 start_flag = false
0352 End If
0353 If display_flag Then
0354 tempLWB.ByteVal(0) = TMR1L_value
0355 tempLWB.ByteVal(1) = TMR1H_value
0356 tempLWB.WordVal(1) = TMR1_OVF_value
0357 tmr1_count = tempLWB.LongwordVal
0358
0359 count_div = CONST_MIN / tmr1_count
0360 count_tmp1 = count_div * rotate_value
0361 count_tmp2 = CONST_MIN Mod tmr1_count
0362 count_tmp2 = count_tmp2 * rotate_value
0363 count_tmp2 = count_tmp2 / tmr1_count
0364 rpm = count_tmp1 + count_tmp2
0365
0366 led_txt = DecToStr( rpm, 5, " " )
0367 led_val1 = led7seg_decode( led_txt(4) )
0368 led_val2 = led7seg_decode( led_txt(3) )
0369 led_val3 = led7seg_decode( led_txt(2) )
0370 led_val4 = led7seg_decode( led_txt(1) )
0371 led_val5 = led7seg_decode( led_txt(0) )
0372
0373 display_flag = false
0374 End If
0375 Wend
0376
0377 '--------- E N D O F P R O G R A M -------------------------------------------
行番号
解説
特に解説は
なし

2010-02-08

多機能版の試作機はOLIMEXについでに発注したので使用した部品がかなり小型。必要と思われる部品
 ・ロータリーエンコーダ1個
 ・プッシュスイッチ2個
 ・メカニカルリレー1個
 ・3mmLED3個
を並べたら28ピンのPICの足が足りなくなった。40ピンのPIC18F4550に変更。試作基板を作るのは面倒なのでブレッドボードで動作確認して量産してしまおう。

PICT1696.jpg

多機能版の基板レイアウト。水晶はPIC用とは別にタイマー用にもう一個使っている。校正しないと時計としての精度は望めないが(キットなので校正は無理)最大1時間を計測できるストップウォッチとして使える精度は確保しておきたい。

2010-02-09

KTXO-18Sを使おうと思ったが振幅が2V程度と小さい。プリスケーラーの分周比が大きく取れるタイマー0に繋ぎたいのだがタイマー0の入力はシュミットトリガなので振幅が大きくないとダメ。PICの発振子としては使えるのだが周波数が12.8MHzと中途半端でUSBに合わない。使うの止めようか...1時間の精度が有れば十分だし。
実現したい機能は
 ・回転計
 ・カウンター
 ・ストップウォッチ
 ・ON/OFFタイマー
の4種。ブートローダーさえ書き込んでしまえばソフトはUSB経由で自由に書き換えられるので4種を基本形として亜種を多数作っても配布の手間がかからない。

PICT1704.jpg

秋月電子で¥200のKTXO-18S 自作スピードメーターから取り外したもの。

PICT1700.jpg

波形。スイープ速度は当方のオシロの限界でこれ以上速くできない。リードアウトの電圧表示も20%近く狂っているし何とかしなければ...

2010-02-10

KTXO-18Sのかわりに今まで回転計で使用していた水晶発振器が使えないか精度を調べてみた。当方の工作では定番の発信器なので数時間の計測なら殆ど誤差を気にしないで済む精度を持っていることは知っていたのだが直接周波数を計測したことは無かった。結果10個計測して
 11.77620MHz
 11.77597
 11.77629
 11.77612
 11.77618
 11.77625
 11.77619
 11.77625
 11.77617
 11.77623
であった。十分使える。この手の計測器は30分程度暖めてから使用する物だがそんな面倒なことはしていない、ばらつきの計測ならたぶん問題ないだろう。計測時の室温、ちょっと低くて16℃。
 

PICT1758.jpg

A&Dの周波数カウンター AD-5184 韓国製 ラジオデパート1F奥の東映無線で¥39800

PICT1762.jpg

秋月電子で安売りしている11.776MHzの水晶発振器。

2010-02-11

20MHzの水晶発振子の精度も調べてみた、結果は周波数カウンターのページのとおり精度も良かった。追加の発振子は取り外した。

PICT1814.jpg

少し小さくなった

P版.comに発注をかける予定だが2月中は休みのようだ。

PICT1811.jpg

2月中は異種面付が出来ないので発注できない

2010-02-12

面付は実寸に切った紙を使う。とても面倒。プログラムでは面付困難。「面積が最小になるように」ということだけではなく「出来るだけ無駄がないように」という条件もある。この基板をもう一枚面付すると無駄が無いといったことが発生する。製造工程のことも考慮しなければならない。ルーター切り出しならどんな面付レイアウトでも切れるが、シャーリングやVカットではレイアウトに制約を受ける。

PICT1831.jpg

このレイアウトはちょっと無駄が多い

PICT1833.jpg

回転計を2個面付すれば無駄が小さくなりそう

最終レイアウト完成。2月末まで待つ。

PICT1834.jpg

CADで最終レイアウトを画く

2010-03-03

ガーバーデータの確認をして基板を発注。基板が届くのは3/12頃

PICT2115.jpg

2010-03-04

いつもは問題なく製造が始まるのだが、今回は送ったデータに問題有りの連絡がP板.comから来た。全てそのまま作ってもらって問題なかったがデータを訂正して再送。正式な発注がかかるのは明日になる。

PICT2118.jpg

パターンが接近しすぎでくっついてしまう可能性があるという問題。この上下のパターンは別の層で繋がっているので問題ないがデータを修正した。

PICT2117.jpg

レジストの幅が0.127mm以下になっているという問題。何故かEAGLEのレジスト幅の設定が間違っていたので訂正。このまま作っていたら不細工な物が出来てしまっていた。P板.comのテスト機能に救われる。

PICT2116.jpg

パターンが接近しすぎてレジストが上手く乗らない。これはこのまま作ってもらう事にした。

2010-03-09

回転計以外の部品も纏めて購入したら段ボール箱1個分あった。AC-DCアダプターも購入する予定だったのだが在庫切れ。秋月電子で売っているアダプターは他店でも取り扱うようになって品薄になっているようだ。

PICT2133.jpg

段ボール箱に満載。全部で19万円。

2010-03-13

基板が届いたので組立。1個組み立てて確認して、キットの作り方のページを作って、部品を袋詰めして......単純作業なので面白くない。

PICT2245.jpg

最近は真空パックされてくるようになった。

PICT2244.jpg

回転計小型版

2010-03-15

通常版と小型版のサイズ比較。

PICT2273.jpg

2010-03-17

多機能版を組み立てた。組立中に未配線に気がつく。

PICT2381.jpg

繋がっていない!!!

PICT2382.jpg

半田付けほぼ完了

2010-03-19

ブートローダーと回転計プログラムを移植。あと5~6本プログラムを書かないといけない。

PICT2444.jpg

USB接続でプログラムを書き込む。ブートローダーを書き込んでしまえばPICKit2無しでプログラムが更新できる。スイッチを押しながらUSBケーブルを差し込めばブートローダーが動く。

2010-03-20

ダウンカウンターとダウンタイマーを書いた。
ダウンカウンターは適当な値を設定しておいて、センサーが磁石を検知する毎に1ずつ値が減っていき、ゼロになるとリレーが動作する。
ダウンタイマーはセンサーを全く使用しない。設定した時間が経過するとリレーが動作する。リレーは2接点スイッチなのでONタイマーにもOFFタイマーにもなる。亜種を含めると最終的に10本程度になりそう。

PICT2456.jpg

2カ所基板の修正が入った

PICT2461.jpg

ダウンタイマーの設定。エンコーダーを回すとドットが点灯している桁の値が変わる。これは2時間21分00秒を表している。

2010-03-21

ストップウォッチを書いた。同時にスタートボタンを押しているがマルマンのストップウォッチの表示更新は1/100秒単位ではなくもっと大雑把なので表示が一致しない。ストップスイッチを押すと表示値が同じであることが解る。

PICT2470.jpg

2010-03-23

磁石センサーは回転体の計測に限ってはとても便利。回転体以外の物では遮光センサーやマイクロスイッチの方が適していることがあるのでセンサーを充実させることにする。

PICT2530.jpg

マイクロスイッチ回路の実験。フリップフロップでチャタリングを除去している。

回路図

microswsch.PNG

2010-03-28

光学式センサー基板は以前に作った物の焼き直し。少しレイアウトを変更したらLEDとコンパレータが干渉してしまってLEDが斜めに付く。

PICT2601.jpg

光学式センサーの基板

PICT2624.jpg

マイクロスイッチ基板

2010-03-30

回転計プログラムのバグで変なアドレスに処理が飛ぶとブートローダーが書き込み機能を持っているが故に自分自身を破壊してしまう可能性がある。調べるとPIC18F4550はプログラム領域の一部を書き込み禁止に出来る。これはHEXコードを読み込んで逆アセンブルによるプログラム解析を防止するための機能ではない。プログラムの自己書き込みを防止する機能。方法はコンフィグレーションビットの操作だけで済む。禁止領域はかなり大きなブロック単位でしか出来ないがブートローダーはhex0~2000としてあるので丁度ブロック境界と一致している。キットの袋詰めは済んでいるのでPICを取り出して全部書き直し。

PICT2634.jpg

PIC18シリーズはブロック単位に書き込み禁止機能を持っている。書き込み禁止、読み出し禁止は別々に設定できる。

2011-06-02

回転計の測定限界は999999rpmを超えている。高速回転している回転体はノイズを発生していることが多くセンサーケーブルがノイズを拾ったりして本体の限界まで計測できない。

R0011852.jpg

オシロスコープの上に乗っているファンクションジェネレーターを入力にしている