JH7UBCブログ

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

Raspberry Pi Pico MicroPython BME280 温度・気圧・湿度計

2021-11-30 10:23:05 | Raspberry Pi Pico
  Raspberry Pi Picoに温度・気圧・湿度センサーBME280を接続し、温度・気圧・湿度をOLEDに表示します。

 BME280とOLEDは、いずれもI2C接続です。接続回路図です。



 電源は、電池2本(3V)とし、スタンドアローンで動作します。

 スクリプトです。これまでのBME280のテストとOLED表示テストの結果を利用します。小数点以下の数値は、けっこう変動しますので、小数点1位を四捨五入しています。測定は5秒ごとに行い、数値が変わった時だけ表示を変更します。
--------------------------------------------------------------------------------------
"""
Raspberry Pi Pico BME280 TPH meter
2021.11.29
JH7UBC Keiji Hata
"""

from machine import I2C,Pin
import bme280
import ssd1306
import utime

i2c=I2C(0,sda=Pin(16),scl=Pin(17),freq=400000)
bme=bme280.BME280(i2c=i2c)
oled=ssd1306.SSD1306_I2C(128,64,i2c)

oled.text("BME280 TPH meter",0,0)
oled.text("T :      C",8,16)
oled.text("P :      hPa",8,32)
oled.text("H :      %",8,47)
oled.show()

old_ti=0
old_pi=0
old_hi=0

def TPH_disp():
    global ti,pi,hi
    global old_ti,old_pi,old_hi

    if ti != old_ti:
        oled.fill_rect(48,16,24,8,0)
        oled.show()
        oled.text(str(ti),48,16)
        oled.show()
        old_ti = ti
    if pi != old_pi:
        oled.fill_rect(40,32,32,8,0)
        oled.show()
        oled.text(str(pi),40,32)
        oled.show()
        old_pi = pi
    if hi != old_hi:
        oled.fill_rect(48,48,24,8,0)
        oled.show()
        oled.text(str(hi),48,48)
        oled.show()
        old_hi = hi

while True:
    #補正された温度t・気圧p・湿度hデータを読み込む
    t,p,h=bme.read_compensated_data()
    ti=int(t/100 + 0.5)
    p=p//256
    pi=int(p/100 + 0.5)
    hi=int(h/1024 + 0.5)
    TPH_disp()#t,p,hを表示
    utime.sleep(5)#5sec待つ

--------------------------------------------------------------------------------------
 ブレッドボードです。

 測定値を市販の温度・湿度計の値と比べてみました。温度、湿度ともほぼ同じ値を示しました。

 

Raspberry Pi Pico MicroPython BME280テスト

2021-11-29 13:13:50 | Raspberry Pi Pico
 Raspberry Pi Picoで、温度・気圧・湿度センサーBME280のテストをします。
 BME280は、秋月電子のAE-BME280モジュールを使います。I2C接続で温度・気圧・湿度の測定データを読み出すことができます。I2Cアドレスは、SDOをGNDに接続した場合0x76、VDDに接続した場合は、0x77です。


接続回路図です。

 Raspberry Pi PicoのI2Cは、id=0、sda=GP16、scl=GP17に設定します。

 BME280の測定値から実際の温度、気圧、湿度を求めるには、補償値も含め複雑な計算が必要です。そこで、利用できるライブラリを探してみます。

 Thonny IDEにおいて、ツール→Manage packages MicroPython deviceを開き、BME280で検索します。
 ESP8266/ESP32用ですが、「micropython-bme280」が使えそうです。Picoにインストールします。

 次のスクリプトでテストしてみました。bme.valuesで温度、気圧、湿度の測定値を読み出すことができます。 
 1secごとにshellに表示させてみると、測定値が小数点以下は細かく変動することが分かります。

 このままでも利用できますが、生データを保証した値も読み出すことができます。bme.read_compensated_data()で、温度、気圧、湿度の順に補正後の値を読み出すことができます。


 温度tは、t/100で実際の温度になります。
 気圧pは、p/256/100で実際の気圧になります。
 湿度hは、h/1024で実際の湿度になります。

 次は、OLED表示器と組み合わせて、温度・気圧・湿度計を作ってみます。

Raspberry Pi Pico MicroPython モールス符号練習機

2021-11-27 21:18:12 | Raspberry Pi Pico
 今まで勉強してきたRaspberry Pi Picoの機能活用とMicroPythonのプログラミングの練習としてモールス符号練習機(Morse Trainer)を作ってみました。

 電池2本でスタンドアローンで動作します。モードはランダムモードとABC順モードの2つです。速度は10kΩボリュームで6wpm~24wpmの間で調整できます。文字はOLEDに表示します。モールス音は、GPIO0に接続したスピーカーから出ます。周波数は700Hz固定としました。スタートボタンを押すと符号の送出が始まり、途中でこのボタンを押すと止まります。
  

 プログラミングの前に、モールス符号について説明します。モールス符号は、短点(dot)と長点(dash)の組み合わせで文字を表現します。文字内のdotまたはdashの間は1dotの時間、文字間は3dotの時間、語間は、7dotの時間と定められています。

 モールス通信の速度は、語/分(wpm(word per minute) )で表します。1語として「PARIS」という語を使い、下の図のように語間スペースも含めると50dot分になります。
 従って、1dotの時間(ms)は、1200/wpmで計算できます。逆に速度wpmは、1200/1dot(ms)で計算できます。良く使われる字/分は、wpm×5字/分となります。

 今回速度の可変範囲は、6wpm(30字/分)~24wpm(120字/分)としました。コンテストなどでも20wpmを聞き取れれば大丈夫です。

 スクリプトです。音を出すときは、pwm.duty_u16(0x8000)とし、700Hzデューティ比50%のPWM信号をGPIO0に出力します。spaceなど音を出さないときは、pwm.duty_u16(0)としてPWM信号を出しません。
 Picoの出力ポートは力持ちで、直接スピーカーをつないで音を出すことができます。ただし、音量は変えられません。
 なお、スクリプトは、main.pyとしてPicoに保存します。ssd1306というライブラリーを利用しますので、前のOLEDテストの記事に記載したようにダウンロードしてPicoにインストールしておきます。
-----------------------------------------------------------------------------------
"""
Morse Trainer Ver1
2021.11.27
JH7UBC Keiji Hata
"""

from machine import I2C,Pin,PWM,ADC
import random
import utime
import ssd1306

M_code = [".-","-...","-.-.","-..",".","..-.","--.","....","..",
           ".---","-.-",".-..","--","-.","---",".--.","--.-",".-.",
           "...","-","..-","...-",".--","-..-","-.--","--.."]
moji = ["A","B","C","D","E","F","G","H","I","J","K","L","M",
         "N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
mode_txt=["RAND","ABCD"]

def text_clr():
     oled.fill_rect(0,8,127,63,0)

def random_txt():
    global x0
    global y0
    column = 0
    row=0
    count=0
    while True:
         speed_read()
        x = x0 + 8 * column
        y = y0 + 8 * row
         i=int(random.random() * 26)
         oled.text(moji[i],x,y)
         oled.show()
         morse_out(i)
         column =column + 1
         count = count +1
        if count > 3:
             column = column +1
             count =0
        if column >14:
             column = 0
             row = row + 1
        if row > 5:
             break
        if start_sw.value()==0:
             break

def abcd_txt():
    global x0
    global y0
    column = 0
    row=0
    count=0
    for i in range(26):
        speed_read()
        x = x0 + 8 * column
        y = y0 + 8 * row
         oled.text(moji[i],x,y)
         oled.show()
         morse_out(i)
         column =column + 1
         count = count +1
        if count > 3:
             column = column +1
             count =0
        if column >14:
             column = 0
             row = row + 1
        if start_sw.value()==0:
             break

def dot():
     pwm.duty_u16(0x8000)
     utime.sleep_ms(dot_time)

def space():
     pwm.duty_u16(0)
    utime.sleep_ms(dot_time)

def dash():
     pwm.duty_u16(0x8000)
     utime.sleep_ms(dot_time)
     utime.sleep_ms(dot_time)
     utime.sleep_ms(dot_time)

def char_space():
     pwm.duty_u16(0)
     utime.sleep_ms(dot_time)
     utime.sleep_ms(dot_time)

def morse_out(n):
     m=M_code[n]
     l=len(m)
    for j in range(l):
         s=m[j]
        if s==".":
             dot()
         elif s=="-":
             dash()
         space()
     char_space()


def mode_disp(m):
     oled.fill_rect(16,0,32,8,0)
    oled.show()
     oled.text(mode_txt[m],16,0)
     oled.show()

def mode_change():
     utime.sleep_ms(10)
    global mode
    mode = mode +1
    if mode>1:
         mode=0
     mode_disp(mode)

def start_morse():
    global mode
     utime.sleep_ms(10)
     text_clr()
    if mode==0:
         mode_disp(mode)
         random_txt()
    elif mode==1:
         abcd_txt()

def speed_read():
    global wpm
    global dot_time
    global dash_time
     dot_time=speed.read_u16() >> 8
    if dot_time < 50:
         dot_time=50
    if dot_time >200:
         dot_time=200
     wpm=int(1200/dot_time)
     wpm_disp()

def wpm_disp():
    global wpm
    global old_wpm
    if wpm != old_wpm:
         oled.fill_rect(96,0,32,8,0)
         oled.show()
         oled.text(str(wpm),96,0)
         oled.show()
     old_wpm=wpm        

#setup
i2c=I2C(0,sda=Pin(16),scl=Pin(17),freq=400000)
oled=ssd1306.SSD1306_I2C(128,64,i2c)

#ピン割り当てと設定
start_sw=Pin(15,Pin.IN,Pin.PULL_UP)
mode_set=Pin(14,Pin.IN,Pin.PULL_UP)
speed=ADC(0)

#PWM設定
pwm=PWM(Pin(0))#morse音をPin0に出力
pwm.freq(700)   #tone=700Hz
pwm.duty_u16(0)#最初、音を出さない

x0 = 8
y0 = 16
mode = 0
mvalue=0
old_mvalue= 0
svalue=0
old_svalue=0
wpm = 10
old_wpm =0

#初期画面表示
oled.text("M:      WPM:",0,0)
oled.show()   
mode_disp(mode)
wpm_disp()


#main loop
while True:
     speed_read()
     mvalue=mode_set.value()
    if mvalue==0 and old_mvalue==1:
         mode_change()
     old_mvalue=mvalue
     svalue=start_sw.value()
    if svalue==0 and old_svalue==1:
         start_morse()
     old_svalue=svalue
     utime.sleep_ms(10)

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

 ブレッドボードです。


 ABC順モードです。

 白いボタンがSTART/STOP、青いボタンがモードボタンです。速度は右上に表示されます。

 電池は、39番ピンVSYSに接続します。

Raspberry Pi Pico MicroPython OLED表示テスト

2021-11-23 20:03:02 | Raspberry Pi Pico
 Raspberry Pi Picoで、0.96インチのI2C接続OLED(128×64ドット)の表示テストをします。(秋月電子で580円)

 このOLEDのコントローラは、SSD1306で、I2Cアドレスは、0x3Cです。

 今回は、SSD1306用のライブラリーを利用します。その方法は、メタエレ実験室というサイトの記事を参考にさせていただきました。

  まず、Thonny IDEで、ツール→Manage packages for MIcroPython deviceを開きます。
 SSD1306で検索し、検索結果から「micropython-ssd1306」をインストールします。Pico内のlibというフォルダにssd1306.pyというファイルが保存されます。
 これで、準備完了です。

 PicoとOLEDの配線回路図です。SDA=GPIO16,SCL=GPIO17とします。


 テストスクリプトです。main.pyとしてPicoにsaveします。
---------------------------------------------------------
from machine import I2C,Pin
from utime import sleep
import ssd1306

i2c=I2C(0,sda=Pin(16),scl=Pin(17),freq=400000)
oled=ssd1306.SSD1306_I2C(128,64,i2c)

oled.text("Hello World!", 0, 5)
oled.show()
---------------------------------------------------------
ブレッドボードです。「Hello World!」が表示されました。

 このライブラリでは、簡単なグラフィックスを描画することができます。
 tom's HARDWAREというサイトに説明がありました。

 oled.pixel(x,y,c)    x,yにdotを表示します。c=1で表示、c=0で消去です。
 oled.hline(x,y,w,c)  x,yを始点として長さwの水平な線を引きます。
 oled.vline(x,y,h,c)  x,yを始点として長さwの垂直な線を引きます。
 oled.line(x1,y1,x2,y2,c) x1,y1からx2,y2まで線を引きます。
 oled.rect(x,y,w,h,c)  x,yを始点(左上)として、幅w、高さhの四角形を描きます。
 oled.fill_rect (x,y,w,h,c)  x,yを始点(左上)として、幅w、高さhの四角形を描き、中を塗りつぶします。
 oled.fill(c) 画面全体をc色で塗りつぶします。つまり、c=0で全画面クリア、c=1で全画面白になります。

 Hello World!を四角形で囲み、1秒ごとに数字をカウントアップさせるスクリプトを書いて動かしてみました。
 スクリプトです。
------------------------------------------------------------------------------------
from machine import I2C,Pin
from utime import sleep
import ssd1306

i2c=I2C(0,sda=Pin(16),scl=Pin(17),freq=400000)

oled=ssd1306.SSD1306_I2C(128,64,i2c)

oled.rect(10,0,100,18,1)
oled.show()
oled.text("Hello World!",13,5)
oled.show()

n=0

while True:
    oled.fill_rect(20,40,30,10,0)
    oled.show()
    oled.text(str(n),20,40)
    oled.show()
    n=n+1
    sleep(1)
------------------------------------------------------------------------------------
ブレッドボードです。


 このライブラリでは、残念ながらフォントの大きさは変えられないようです。

Raspberry Pi Pico MicroPython I2C LCD1602表示テスト

2021-11-21 19:58:22 | Raspberry Pi Pico
 LCD1602は、従来から最も利用されている表示器です。最近は、配線数の少ないパラレルシリアルインターフェース付きのI2C用LCD1602が主流になってきました。

 今回は、そのインターフェース付きのI2C LCD1602の表示テストをします。今回もライブラリーを使わずにスクリプトを作ってみます。以前、Raspberry Piでテストしたスクリプトを元にしています。記事はこちら

  Raspberry Pi PicoにこのI2C LCD1602を接続する場合に問題点があります。Picoの電圧が3.3Vなのに対し、I2C LCD1602の電源電圧は、5Vなのです。ネット上のサイトや動画では、直接接続している例が多いのですが、LCD1602側で5VでプルアップされているI2Cラインを見てみました。ピークで約4.3Vの電圧がPicoにかかることが分かりました。



 Picoの入力電圧は、-0.5V~+4.13Vで、Picoが入力となる場合(スレーブ側になる場合)最大定格電圧を越えてしまいます。今回の場合、Picoはマスターとしてだけの動作ですので、大丈夫だと思うのですが、どうも精神衛生上よくありません。そこで、秋月電子のI2Cバス用の双方向電圧レベル変換モジュールPCA9306をPicoとLCD1602の間に入れることにしました。

 接続回路図です。PicoのI2Cポートは、id=1,SDA=GP14,SCL=GP15を使いました。

 スクリプトです。
---------------------------------------------------------------------------------------
"""
I2C LCD1602 test
2021.11.19
JH7UBC Keiji Hata
"""
from machine import I2C,Pin
from utime import sleep

i2c=I2C(1,sda=Pin(14),scl=Pin(15),freq=100000)

LCD_addr=0x27
LCD_EN=0x04 #LCD Enable
LCD_BL=0x08 #Back Light
CMD=0x00 #command mode
CHR=0x01 #character mode
LINE1=0x80 #Line1 top address
LINE2=0xC0 #Line2 top address

buf=bytearray(2)

def LCD_write(bits,mode):
    #High 4bits
    data=(bits & 0xF0)|mode
    buf[0]=data|LCD_EN|LCD_BL
    buf[1]=data|LCD_BL
    i2c.writeto(LCD_addr,buf)
    sleep(0.0001)#wait 100us
    #Low 4bits
    data=((bits<<4)&0xF0)|mode
    buf[0]=data|LCD_EN|LCD_BL
    buf[1]=data|LCD_BL
    i2c.writeto(LCD_addr,buf)
    sleep(0.0001)#wait 100us

def LCD_init():
    LCD_write(0x33,CMD)#8bit mode 0x03を2回送る
    LCD_write(0x32,CMD)#8bit mode,4bit mode 0x02を送る
    LCD_write(0x06,CMD)#Entry modeセット
    LCD_write(0x0C,CMD)#表示ON,カーソルOFF,カーソル点滅OFF
    LCD_write(0x28,CMD)#2桁表示,7ドットモード
    LCD_write(0x01,CMD)#Display clear
    sleep(0.002)#waite 2ms

def LCD_clear():
    LCD_write(0x01,CMD)
    sleep(0.002)#waite 2ms

def LCD_home():
    LCD_write(0x02,CMD)
    sleep(0.002)#waite 2ms

def LCD_cursor(x,y):
    if y==0:
        LCD_write(LINE1+x,CMD)
   if y==1:
       LCD_write(LINE2+x,CMD)

def LCD_print(str):
    for c in str:
       LCD_write(ord(c),CHR)

LCD_init()
LCD_clear()
LCD_home()
LCD_cursor(1,0)
LCD_print("Hello World!")
count=0

while True:
    LCD_cursor(1,1)
    LCD_print(str(count))
    count=count+1
    sleep(1)

---------------------------------------------------------------------------------------
 1行目に「Hello World!」が表示され、2行目に数字が0からカウントアップされます。

 ブレッドボードです。コントラストはインターフェース基板のボリュームで調整します。