JH7UBCブログ

アマチュア無線 電子工作 家庭菜園など趣味のブログです

micro:bit MicroPython ロータリーエンコーダ テスト

2019-12-06 15:12:17 | micro:bit

 micro:bitで、ロータリーエンコーダを使うテストをしました。

 これには、割り込みを使う方法と使わない方法があります。

 今回は、後者の割り込みを使わない方法をテストします。

 pin0とpin1をプルアップして、下の図のようにロータリーエンコーダを接続します。

 ロータリーエンコーダを回すと、A,Bがずれながら、3.3Vと0Vを繰り返します。

 そのパターンで回転方向を判定します。具体的な方法は、JH7UBCホームページのここで解説していますので、ご覧ください。

 スクリプトです。ロータリーエンコーダを右側(時計回り)に回すとカウンタの値がUPし、左側(反時計回り)に回すとカウンタの値がDOWNします。その値は、シリアル通信でTeraTermに表示します。

-------------------------------------------

'''
micro:bit MicroPython ロータリーエンコーダ テスト
2019.12.06
JH7UBC Keiji Hata
'''
from microbit import *
 
# シリアル通信初期化
uart.init(baudrate=9600, bits=8, parity=None, stop=1)
 
# pin0とpin1をプルアップ
pin0.set_pull(pin0.PULL_UP)
pin1.set_pull(pin1.PULL_UP)
 
# ロータリーエンコーダ関係定義
befDat = 0
inputMatch = 0
matchCnt = 0
rotPat = 0
Count = 0
 
# エンコーダの回転方向判定
def CheckEnc(dat):
    global rotPat
    rotPat <<= 2  # 左に2ビットシフト
    rotPat &= 0xFF  # 下位8ビットを取り出す
    rotPat |= dat  # datを加える
    if rotPat == 0x4B:
        return 1   # 時計回り(CW))
    elif rotPat == 0x87:
        return -1  # 反時計回り(CCW)
    else:
        return 0  # どちらでもない
 
# ロータリーエンコーダ初期値設定
if pin0.read_digital() == 0:
    befDat |= 2
if pin1.read_digital() == 0:
    befDat |= 1
 
while True:
    # ロータリーエンコーダ処理
    val = 0
    curDat = 0
    if pin0.read_digital():
        curDat |= 2
    if pin1.read_digital():
        curDat |= 1
    if befDat == curDat:
        # befDatとcurDatが一致したときの処理
        if inputMatch == 0:
            matchCnt += 1
            if matchCnt >= 2:  # 2回以上一致したらフラッグを立てる
                inputMatch = 1
                val = CheckEnc(curDat)
                if val != 0:
                    Count += val
                    uart.write(str(Count) + '\r\n')
    else:
        # befDatとcuDatが一致しなかった時の処理
        sleep(1)  # 1ms待つ
        befDat = curDat
        matchCnt = 0
        inputMatch = 0

-------------------------------------------

 micro:bitにロータリーエンコーダを接続した様子です。

 TeraTermの画面です。

 時計回りに回してから、半時計回りに回しました。

 良く動作します。

 


micro:bit MicroPython i2c scan

2019-12-03 13:07:49 | micro:bit

 micro:bit のi2cについて勉強します。

 micro:bit でi2cに使うピンは、デフォルトで、SCLがpin19、SDAがpin20です。

 micro:bitでは、加速度センサーと磁気センサーがI2C接続されていますので、ピン割り当ては変更しない方が良いです。

 MicroPythonには、i2c.scan()という関数があり、検出したI2Cアドレスを返してくれます。これを利用して、micro:bit内蔵のI2Cデバイスのアドレスと、I2C LCD AQM0802Aのアドレスを調べてみます。

 micro:bitとAQM0802Aモジュールを下のように接続します。

 スクリプトです。

 このプログラムを走らせると、micro:bitのLEDマトリクスにI2Cアドレスのリストがスクロール表示されます。

 私の場合の結果は、[25,30,62]と表示されました。これは、16進表示なら[0x19,0x1E,0x3E]です。

 25(0x19)が磁気センサーMAG3110、30(0x1E)が加速度センサーMMA8653FCのI2Cアドレス、62(0x3E)がAQM0802Aのアドレスです。

 Web上で調べると磁気センサーが0x0E、加速度センサーが0x1Dとなっていますが、micro:bitのバージョンにより、若干アドレスが違っているのかも知れません。


micro:bit MicroPython HC-SR04による距離の測定

2019-11-29 14:11:38 | micro:bit

 最もポピュラーな超音波センサーHC-SR04を使って、距離を測定する実験を行いました。

 HC-SR04で、センサーと物体までの距離を測定する手順は、次のとおりです。

 1) micro:bitのpin0から10us幅以上のトリガパルスをHC-SR04のTrig端子に加えます。

 2) HC-SR04から40KHzの超音波が発信され、物体に反射されて戻ってきます。Echo端子には、発信から受信に対応するEchoパルスが出力されます。

 3) Echoパルスのパルス幅の時間t(s)を測定します。超音波は、センサーと物体の間の距離L(m)の2倍を進んだので、音速をV(m/s)とすると、2L = V * t より、L = (V*t)/2 となります。音速は、温度によって変化し、V(m/s)=331.5+0.6*temp(℃)で近似されます。精度を求めなければ、V=340m/sとすれば良いと思います。センサーと物体間の距離Lを下の図の式で、cm単位で計算します。

 接続回路図です。HC-SR04は、5V動作ですので、HC-SR04のECHO出力を分圧して、micro:bitのpin1に入れています。

 Trigパルスは、10us以上とされています。pin0からパルスを出力するには、

 pin0.write_digital(1)

 pin0.write_digital(0)

とすれば良く、これで下の図のように約70us幅のパルスが発生します。

TrigerパルスをHC-SR04に加えると、下の図のように物体までの距離に対応したEchoパルス(赤色)が帰ってきます。

 スクリプトです。

 ECHOパルスは、立ち上がりの時刻t1と立下りの時刻t2をutime_us()で測定し、その差をutime.ticks_diff(t2,t1)でパルス幅t(us)を求めます。

 測定した距離Lは、cm単位でLEDにスクロール表示しています。

------------------------------------------------------

'''
micro:bit HC-SR04による距離の測定
2019.11.28
JH7UBC Keiji Hata
'''
from microbit import *
import utime
# pin0初期化
pin0.write_digital(0)
while True:
    # 音速を計算する
    V = 0.6 * temperature() + 331.5
    # トリガパルス
    pin0.write_digital(1)
    pin0.write_digital(0)
    # 距離の測定と表示
    while pin1.read_digital() == 0:
        utime.sleep_us(1)
    t1 = utime.ticks_us()
    while pin1.read_digital():
        utime.sleep_us(1)
    t2 = utime.ticks_us()
    t = utime.ticks_diff(t2, t1)
    L = int(t * V / 20000)
    display.scroll(L)
    sleep(100)
-----------------------------------------------------------------------

測定の様子です。

実測の結果です。

L(cm)   測定値(cm)

10        8

20       19~21

30       30

40       38~40

50       49

60       57~60

70       68~70

80       78~79

90       88~90

100     98

110    109

120    117

130    122~124

140    122~124

といった具合でした。

1m程度までなら1~2cmの誤差で測定できました。1m以内ならほぼ実用になると思います。


micro:bit MicroPython モールス符号解読器の試作

2019-11-21 13:00:50 | micro:bit

 micro:bitでモールス符号解読器を試作しました。

 符号解読のアルゴリズムは、Rspberry Piでモールス符号解読器を作った時と基本的に同じですが、簡単に説明します。

 pin0をプルアップしておき、信号をpin0に加えます。したがって、モールス信号のdot(短点)またはdash(長点)の時にLowレベル(0)になります。

 下の図はAの符号が入力された場合で、スタートビット1をMcodeにセットし、信号が入力される度に1ビット左にシフトして(2倍して)dotのとき0,dashのとき1を加えます。これによって、モールス符号をコード化します。

 Aの場合は、101ですから、10進数で5になります。この方法で、A~Z,0~9,/をコード化し、10進数の順に並べてoubunというリストを作っておきます。

 実際に入力されたモールス符号をコード化し、コードに応じた文字をリストから表示すれば、でコードされたことになります。

 デコードのタイミングは、Hレベルが短点時間の1.5倍程度になった時としました。

 

 スクリプトです。

自作のキーヤーにパドルを接続して、テストしました。

 

 普通の速度のモールス信号なら解読できます。

 ただ、文字表示が1文字だけですので、同じ文字が続いた時に前の文字と区別がつきません。

 やはり、文字を横に表示していくタイプの表示器(例えばLCD1602)の方が解読器には適していると思います。


micro:bit MicroPython utimeを使ったレシプロカル式周波数カウンタ

2019-11-16 12:10:08 | micro:bit

 MicroPythonのutimeモジュールには、現在の時刻の取得、時間間隔の測定、遅延などの関数があります。

 詳細は、ドキュメンテーションを見ていただくとして、この関数を利用して、周波数カウンタを試作してみます。

 タイトルのレシプロカル式とは「逆数式」のことで、信号の周期を測定して、f=1/Tの関係から、周期の逆数を計算して周波数を求める方式です。

 pin0のデジタル入力を利用し、その前に簡単なアンプをつけました。

 pin0の電圧が1から0に変化する時の時刻(start_timeとend_time)を測定して、時刻の差をとれば、1周期の時間を測定できます。

 周期をus単位で測定し、f(Hz)=1000000/T(us)で計算すると周波数f(Hz)を測定することができます。

 スクリプトです。

 呼び出した時点でのmicro:bitの稼働時間をusで返す関数が、utime.ticks_us()です。

 1周期は、start_timeとend_timeを測定し、utime.ticks_diff(end_time, start_time)関数で、その時間差(周期)を計算します。

 計算したperiod(周期)は、小数点がついていますので、int()で整数化してからスクロール表示します。

 自作SGから100Hzの信号を出して、micro:bitで実測してみました。

 97Hz~103Hz程度(誤差3%)の値を表示しました。

 周波数がほぼ、正しく表示されるのは、10Hz~200Hz程度で、500Hz程度までは、それらしい数値を表示します。

 この周波数カウンタは、実用になるものではありませんが、utimeを使えば、こんなこともできるのでは、と思って作ってみました。