2009年7月17日金曜日

フォトインタラプタの実験


錠剤が落ちたかどうかを判定する簡単な方法は、発光ダイオードから放射される光をフォトトランジスタで受光しておき、モノが通ると光が遮られることを利用した、通過型センサを用いることでしょう。
さっそくブレッドボード上に作ってみました。左が発光部、右が受光部です。


TPS616のデータシートにあるスイッチング時間測定回路を、R=180Ω(LED電流を28mA)、RL=1kΩとして構成。このときのTLN119とTPS616の距離は、約15mm。





出力の部分には、動作確認のために2SC1815を介したモニタ用LEDを接続するとともに、完成品で使用する予定の十進カウンタにも接続。
あっさりと動作。



ピンセット、抵抗の足、耳掻きを順に通してみた。カウンタは16F84Aで構成し、シュミットトリガを内蔵したINT線を入力に用いているためか、意外にもチャタらずに大人しくカウントしている。抵抗の足のような細いモノでも反応してくれるのは少し感動するところである(すばやく動かした場合にはさすがに反応しないが)。

実験中、通過させる際にLEDやフォトトランジスタに触ってしまい、少し光軸がずれただけで動かなくなり、何回か動画を撮り直した。

なお、光入力時に出力端子に出ている電圧は、0.80Vであった。このときフォトトランジスタに流れている電流は約0.8mAということになる。

この実験から分かったことは、
  • 蛍光灯下でもフリッカに影響されず期待したように動く
  • TLN119とTPS616のペアは実用的な指向性が見られる
  • ちいさな錠剤の検出にも期待が持てる
  • とりあえずチャタリングは起こさなさそうである
といったところか。

自動錠剤分包装置


自動錠剤分包装置、と言われてすぐにわかる人は少ないだろうから、なにをするための装置なのかを紹介しておこう。


中には、錠剤が入ったカセットがたくさん並んでいる。


カセット裏側:0.8モジュールのポリアセタール歯車を介して内部のロータを駆動される。
回転により、歯車上部のスリットから錠剤が1つ単位で落下する。

本体側:駆動用の歯車と、錠剤が落下するため孔部。面実装型のフォトトランジスタが8個並んでおり、反対側に設置されたLEDからの光を落下する錠剤が遮断することにより、錠剤の落下を検知する仕組み。


指示を出すPCの画面。ここで落下させる錠剤の種類、数、用法、パターンの指示を行う。


これが実際に分包された見本。朝に服用する分、昼に服用する分、夕方に服用する分それぞれに必要な薬が必要な数だけ含まれる。
これをワンドーズパッケージまたは一包化製剤と呼ぶ。

この一包化を行うための装置が、自動錠剤分包装置なのだ。

2009年7月16日木曜日

沖縄のパイナップル


旬楽膳へ行ったら、沖縄パイナップルというのを売っていた。たまに沖縄バナナというのは見かけたのだが・・・

ずいぶん小さなパイナップルだが、香り、甘みともによく見かけるパイナップルよりもずっと上質であった。
パイナップルは、あのような形の種の上から芽が出ているように見えるのだけれども、実は小さな花の集合体らしい。この小型のパイナップル、花をひとつひとつ切り離すこともできるので、やはり花の集合なのだろうと実感する。なにより芯も柔らかく食べられるので、豪快にスイカ切りにして、そのまま食するのがもっとも贅沢な食べ方ではないだろうか。

口の中がチクチクしないので、パイナップルが苦手な人でも食べられるかもしれない。

2009年7月15日水曜日

ワイヤリングペンの作成


カウンタ部分をブレッドボード上に作成したのだけれど、4つの7SEG LEDを配置するときの配線が面倒だった。ユニバーサル基板においても、バスの配線は基本的に面倒な作業になる。

そこで、ワイヤリングペンを作ってみた。


材料
・0.5mm シャープペン(ミツビシ・M5-108 Uni Aqua Touch)
・プラスチックボビン(サンヒット・メリーホビー)
・アルミ針金(エコー金属・1.5mm×7.5m)
・0.2mm UEW線(SUNCO Corp.20m)

ポリウレタン線以外は、百円ショップSeriaで購入。

シャープペンを選ぶときのポイントは、1)半透明で中が見やすいこと、2)頭の部分を回転させて外せること、3)中の機構部を取り除けること、4)おしりを取り外せること である。

まずシャープペンを加工します。
外せるところは、全部外してみます。







芯を押し出した状態で、芯をホールドする機構部を突出させます。
そして、電工ニッパーで切り落とします。





バラバラになりました。
内部の機構は捨てますが、頭に残る白い軸のようなものはワイヤーのガイドとして残すことにします。






次に、ボビンにUEW線を巻きます。
菜箸を2本つかうと早く、綺麗に、楽に巻くことが出来ます。
1本はボビンに通して回転軸とし、もう一本はUEW線が絡まらないよう吊るために用います。










ポリウレタン線のコイルが詰まってきたり、絡み始めたら、ボビンを中心にして1-2回、巻線をほどく方へ回転させると、自然にポリウレタン線はほどけてきます。無理に引っ張ったりすると終了です。











 上手く巻くと、20mでこのぐらいになります。








先端からUEW線を引き出します。
まだボビンから箸を外さない方が賢明です。







最後に、アルミ針金で固定します。ボビンが軽く回るように調整します。UEW線を交換する毎に折り曲げることになるため、消耗品と考えたほうが楽です。



ポリウレタン線は、

・細くて丈夫
・ポリウレタン塗装されており絶縁線として使える
・半田ごての熱で被覆が取れるためそのまま半田付けしやすい


というメリットがありますが、

・細いので大電流は流せない
・バス配線とする場合クロストークが出る(周波数が上がるほど強くなりやすい)
・熱に弱く、被覆が薄いためショートを起こす場合がある


というデメリットも存在します。

自分用や試作には大変便利なのですが、商品に使用するのは不適と思います。

フォトトランジスタと赤外線LEDの購入



大須のタケイムセンで、フォトトランジスタと赤外線LEDを購入。
フォトトランジスタがTPS616(可視光カットタイプ)、赤外LEDがTLN119(非カットタイプ)。



最近の型番を知らなかったものだからお店で「可視光カット」「3φ」という条件で購入したのだが、帰ってから型番を忘れてしまい、お店へ電話して教えて貰った次第。

可視光カットのPTrを選ぶ理由は、電灯からの電灯線周波数の変調光の影響を減らすため。他の光源からの影響を避けるとき、簡単に思い浮かぶのは、

1) 一定帯域のLED-PTrの組み合わせを使う
2) 発光に変調を掛け、変調光のみを検出する

という方式。2)の方式にすればエアコンやテレビのリモコン類との干渉も防ぐことができるのだが、今回は落下する錠剤を数えるためのセンサなので、簡単な1)を選んだ。完成品は遮光することになるのだけれど、微調整を行うときには電灯下で行うことになるため、できるだけノイズを減らしたいという意図がある。


2009年7月14日火曜日

SyntaxHighlighter を PIC Assembler に対応させてみた

ブログに表示するソースコードをハイライトし、見やすくする方法はいろいろ公開されているが、MicroChip社のPIC Assembler に対応しているものは見当たりません。

そこで、Fazibear氏が公開している、Blogger Syntax Highlighter Widget に、PIC Assembler を追加してみました。



1.Fazibear氏のページから、widget を導入します。

2.[レイアウト]-[ページの要素]から、そのwidgetの編集を選びます。

3.変更箇所は2カ所です。まず1ヶ所目は、

.dp-highlighter .preprocessor { color: gray; background-color: inherit; }
</style>

の部分を、

.dp-highlighter .preprocessor { color: gray; background-color: inherit; }
.dp-highlighter .pasm_builtins { color: #069; font-weight: bold; background-color: inherit; }
</style>

と、02行目を加えます。これはPIC Assembler の疑似命令の色を決定しています。

もう1ヶ所は、

dp.sh.Brushes.Delphi.prototype=new dp.sh.Highlighter();dp.sh.Brushes.Delphi.Aliases=['delphi','pascal'];
dp.sh.Brushes.Python=function()

の2行の間に、


dp.sh.Brushes.Delphi.prototype=new dp.sh.Highlighter();dp.sh.Brushes.Delphi.Aliases=['delphi','pascal'];
dp.sh.Brushes.Pasm=function()
{var keywords='addwf andwf clrf clrw comf decf decfsz incfincfsz iorwf movf movwf '+'nop rlf rrf subwf swapf xorwf bcf bsf btfsc btfss addlw andlw '+'call clrwdt goto iorlw movlw retfie retlw return sleep sublw '+'xorlw movfw';
var builtins='__badram bankisel banksel cblock '+'endc code __config constant da data '+'db de #define #undefine dt dw end equ '+'error errorlevel exitm expand noexpand extern '+'fill global idata __idlocs #if #else #endif #ifndef '+'include list nolist local macro endm __maxram messg org '+'page pagesel processor radix res set space title subtitle '+'udata udata_acs udata_ovr udata_shr variable while endw';
this.regexList=[{regex:new RegExp('\;.*$','gm'),css:'comment'},{regex:dp.sh.RegexLib.DoubleQuotedString,css:'string'},{regex:dp.sh.RegexLib.SingleQuotedString,css:'string'},{regex:new RegExp(this.GetKeywords(builtins),'gm'),css:'pasm_builtins'},{regex:new RegExp('^\\s*#.*','gm'),css:'preprocessor'},{regex:new RegExp(this.GetKeywords(keywords),'gm'),css:'keyword'}];this.CssClass='dp-pasm';}
dp.sh.Brushes.Pasm.prototype=new dp.sh.Highlighter();dp.sh.Brushes.Pasm.Aliases=['asm','pasm'];
dp.sh.Brushes.Python=function()

と、02行~06行を加えます。ここでPIC Assemblerの命令と疑似命令、コメントや文字列の色をブラシしています。

5.保存します。

これで対応されます。

投稿する場合には、ソースコードを、
<pre name="code" class="pasm"> ・・・・・ </pre>
で囲んでください。

元々のWidgetに加える形を取っているので、次のように、他のコードに対してもこのWidgetを使うことが出来ます。

Pythonの場合:


#!/usr/bin/env python

def hello():
print "Hello World!"

hello()



PIC Assemblerの場合:

;テスト

list P=12F675
include P12F675.INC

org 0 ;RESET VECTOR
goto MAIN
org 4 ;INTERRUPT VECTOR
goto MAIN
org 5
MAIN
movlw b'10010111'
btfss GPIO,GP5
goto MAIN
sleep


参考にしたページ:
Fazibear
クリボウの Blogger Tips
Yet Another Coding Blog
Damien Learns Perl


2009年7月12日日曜日

10進カウンタの試作


錠剤カウンタで使用する10進カウンタを、16F84Aで作ってみました。


友人から教えていただいた、7セグメントLEDをダイナミック点灯する方式の回路をそのまま流用することにし、入力にシュミットトリガを持つINT線の割込を使いたかったので、プログラムの部分は作りました。

RA0~3でPNPトランジスタをスイッチすることでセグメントを選択し、RB1-7で各セグメントa-gを点灯させます。RB0はINTの入力とし、信号の立ち上がりでカウンタをインクリメントします。74138あたりのデコーダを用いれば桁数はもっと増やせそうな気がします。

以下、プログラムの内容です。

;
; for 16F84A Decimal Counter
;
; Ver 0.01 6, Jul 2009
; Ver 0.02 10, Jul 2009 カウンタ各桁の表示はループを使わず展開して行う
;
;
;
;


LIST P=16F84A

INCLUDE P16F84A.INC
ERRORLEVEL -302,-306

;
; configration bit
;
__CONFIG _HS_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF

__IDLOCS H'FFFF'


;*********************************************************
; Label definition
;*********************************************************

;RAM領域のマッピング(0x20-0x4f)

VARIABLES equ 0x20 ;プログラム中で使用するレジスタ群
COUNT_DATA equ 0x30 ;BCDカウンタ 表示用RAM領域
SEG_DATA equ 0x40 ;7セグメント駆動用パターン領域


;-----------------------------------
; プログラムで使用する変数領域の確保
;-----------------------------------

cblock VARIABLES

;Disp_Seg ;
t1mc ; 1ms確保するサブルーチン内でのカウンタ

w_save ; INT 開始に伴うメインルーチンのWレジスタ値保管領域
s_save ; INT 開始に伴うメインルーチンのStatusレジスタ値保管領域

endc

;-----------------------------------
; 表示用10進数の保管領域(BCD値)の確保
;-----------------------------------

cblock COUNT_DATA

DEG_100 ;1の位
DEG_101 ;10の位
DEG_102 ;100の位
DEG_103 ;1000の位

endc

;-----------------------------------
; 7セグメント表示データの保管領域
;-----------------------------------

; 7セグの表示はテーブルを作成し、
; 先頭アドレス(SEG_DATA)+indexで読む
;
; SEG_DATA
; ↓
; 0123456789

; Anode Common にて駆動する
; 0:点灯 1:消灯

; b'gfedcba-'
SEG_0 equ b'10000001'
SEG_1 equ b'11110011'
SEG_2 equ b'01001001'
SEG_3 equ b'01100001'
SEG_4 equ b'00110011'
SEG_5 equ b'00100101'
SEG_6 equ b'00000101'
SEG_7 equ b'10110001'
SEG_8 equ b'00000001'
SEG_9 equ b'00100001'


; 16F84にはEEPROMが無いため、RAM領域へ作成
; Initial Process にて、LW→seg_xへ格納される

cblock SEG_DATA

seg_0
seg_1
seg_2
seg_3
seg_4
seg_5
seg_6
seg_7
seg_8
seg_9

endc

;*********************************************************
; EEPROM Data definition
;*********************************************************


; 16F84にはEEPROMは存在しない



;*********************************************************
; Program Start
;*********************************************************

ORG 0 ;Reset Vector
GOTO INIT
ORG 4 ;Interrupt Vector
GOTO INT

;*********************************************************
; Initial Process
;*********************************************************

INIT
;WPUを無効
bsf STATUS,RP0 ;change to bank 1
movlw b'11010111' ;PU OFF, PosEDG, INTCLK, NegEDG, TMR0, 1/256
movwf OPTION_REG ;set option registor

;Port の 設定
;
;Port A
;RA0 OUT: LED 1の位 選択
;RA1 OUT: LED 10の位 選択
;RA2 OUT: LED 100の位 選択
;RA3 OUT: LED 1000の位 選択
;RA4 IN: Counter Reset

bsf STATUS,RP0
movlw b'00010000'
movwf TRISA

;Port B
;RB0 IN: Counter Input(INT 立ち下がり)
;RB1 OUT: Seg A 選択
;RB2 OUT: Seg B 選択
;RB3 OUT: Seg C 選択
;RB4 OUT: Seg D 選択
;RB5 OUT: Seg E 選択
;RB6 OUT: Seg F 選択
;RB7 OUT: Seg G 選択

bsf STATUS,RP0
movlw b'00000001'
movwf TRISB

;Bank 0 に戻す
bcf STATUS,RP0

;GPIO 初期化
clrf PORTA
clrf PORTB


; test

movlw DEG_100
movlw seg_0


;7セグメントの表示パターンをRAM領域へ展開

movlw SEG_0
movwf seg_0
movlw SEG_1
movwf seg_1
movlw SEG_2
movwf seg_2
movlw SEG_3
movwf seg_3
movlw SEG_4
movwf seg_4
movlw SEG_5
movwf seg_5
movlw SEG_6
movwf seg_6
movlw SEG_7
movwf seg_7
movlw SEG_8
movwf seg_8
movlw SEG_9
movwf seg_9

;各桁を0にリセット
clrf DEG_100
clrf DEG_101
clrf DEG_102
clrf DEG_103


;割り込みの設定

bcf STATUS,RP0
movlw b'10010000' ;GIE ON, EEPROM OFF, TMR0 OFF, INTE ON, RBIE OFF, IF CLR
movwf INTCON

;Bank 0 に戻す
bcf STATUS,RP0



;*********************************************************
; Main Routine
;*********************************************************

MAIN
;-----------------------------------
; 数値表示部
;-----------------------------------

;千の位のセグメントを表示
movlw b'00001110' ; 千の位のA1015をONにする
movwf PORTA ; A1015 ON

movfw COUNT_DATA+3; W に 千の位の値をロード
addlw SEG_DATA ; W に 点灯パターンの先頭値にIndex値を加える
movwf FSR ; テーブルのアドレスをセット
movfw INDF ; テーブルの数値を得る
movwf PORTB ; 点灯パターンをPORT B に出力

call T1ms ;1msの表示ウェイト

;百の位のセグメントを表示
movlw b'00001101' ; 百の位のA1015をONにする
movwf PORTA ; A1015 ON

movfw COUNT_DATA+2; W に 百の位の値をロード
addlw SEG_DATA ; W に 点灯パターンの先頭値にIndex値を加える
movwf FSR ; テーブルのアドレスをセット
movfw INDF ; テーブルの数値を得る
movwf PORTB ; 点灯パターンをPORT B に出力

call T1ms ;1msの表示ウェイト

;十の位のセグメントを表示
movlw b'00001011' ; 十の位のA1015をONにする
movwf PORTA ; A1015 ON

movfw COUNT_DATA+1; W に 十の位の値をロード
addlw SEG_DATA ; W に 点灯パターンの先頭値にIndex値を加える
movwf FSR ; テーブルのアドレスをセット
movfw INDF ; テーブルの数値を得る
movwf PORTB ; 点灯パターンをPORT B に出力

call T1ms ;1msの表示ウェイト

;一の位のセグメントを表示
movlw b'00000111' ; 一の位のA1015をONにする
movwf PORTA ; A1015 ON

movfw COUNT_DATA+0; W に 一の位の値をロード
addlw SEG_DATA ; W に 点灯パターンの先頭値にIndex値を加える
movwf FSR ; テーブルのアドレスをセット
movfw INDF ; テーブルの数値を得る
movwf PORTB ; 点灯パターンをPORT B に出力

call T1ms ;1msの表示ウェイト

;-----------------------------------
; リセットスイッチ判定
;-----------------------------------

btfss PORTA, 4 ; RA4が1なら次の命令をスキップ
goto MAIN ; そうでないならMAINの継続
goto INIT ; 初期化へ


;*********************************************************
; 1ms wait routine
;*********************************************************

T1ms ;1000命令こなす Routine
movlw .249 ; 1
movwf t1mc ; 1
t1mlp nop ; 1*249
decfsz t1mc,f ; 1*249 + 1(skip)
goto t1mlp ; 2*248
nop ; 1
return ; 2 sum 1000

;*********************************************************
; Interrupt Routine
;*********************************************************

;-----------------------------------
; レジスタ情報保存 と 割り込み分岐
;-----------------------------------
INT
movwf w_save ;Wレジスタを保存
movfw STATUS
movwf s_save ;STATUSレジスタを保存
bcf STATUS,RP0
btfss INTCON,INTF ;GPIFの変化なら次の命令をスキップ
goto INIT ;不正終了は初期化へ

;-----------------------------------
; カウンタのインクリメント
;-----------------------------------

; カウンタは1ずつ増加

intmain
; 1の位の処理
incf DEG_100 ;1の位を+1
movfw DEG_100 ;比較のためワークレジスタへコピー
xorlw .10 ;10になったらゼロフラグ=1
btfss STATUS,Z ;ゼロフラグが0なら次の命令をスキップ
goto intend ;メインルーチンへ復帰するプロセスへ

; 10の位の処理
clrf DEG_100 ;1の位を0にする
incf DEG_101 ;10の位を+1
movfw DEG_101 ;比較のためワークレジスタへコピー
xorlw .10 ;10になったらゼロフラグ=1
btfss STATUS,Z ;ゼロフラグが0なら次の命令をスキップ
goto intend ;メインルーチンへ復帰するプロセスへ

; 100の位の処理
clrf DEG_100 ;1の位を0にする
clrf DEG_101 ;10の位を0にする
incf DEG_102 ;100の位を+1
movfw DEG_102 ;比較のためワークレジスタへコピー
xorlw .10 ;10になったらゼロフラグ=1
btfss STATUS,Z ;ゼロフラグが0なら次の命令をスキップ
goto intend ;メインルーチンへ復帰するプロセスへ

; 1000の位の処理
clrf DEG_100 ;1の位を0にする
clrf DEG_101 ;10の位を0にする
clrf DEG_102 ;100の位を0にする
incf DEG_103 ;1000の位を+1
movfw DEG_103 ;比較のためワークレジスタへコピー
xorlw .10 ;10になったらゼロフラグ=1
btfss STATUS,Z ;ゼロフラグが0なら次の命令をスキップ
goto intend ;メインルーチンへ復帰するプロセスへ

; 9999を超えた場合の処理
clrf DEG_100 ;1の位を0にする
clrf DEG_101 ;10の位を0にする
clrf DEG_102 ;100の位を0にする
clrf DEG_103 ;100の位を0にする

intend
bcf STATUS,RP0
bcf INTCON,INTF ;GPIFクリア
movfw s_save
movwf STATUS ;STATUSレジスタ復帰
swapf w_save,f ;Wレジスタの復帰
swapf w_save,w ;フラグを変化させないで戻す
retfie ;INT routineの終了

END


メモリにも余裕がありますし、わざと冗長に作ってあります。あとで改造したりするときに読みやすい方が好ましいからです。
MAIN部は永遠に10進数を保管しているレジスタを表示し続けるだけで、割込が入ったときに、そのレジスタをインクリする処理にしています。プログラムで立ち上がり/立ち下がりを検出するのは面倒だと思ったからです。

PICを焼き、可変周波数発生回路から信号となるパルスをいれてみました。同じ信号を以前に作成したステッピングモータドライバにも入れてみたので、回ります。



このカウンタ、FFFFまでカウントできる16進カウンタにもすぐに改造出来ると思うので、4桁表示のままでも60000回越えのカウントができますね。