Bladeren bron

Add: TM1637 MicroPython version.

Satoshi Yoneda 2 dagen geleden
bovenliggende
commit
7dc8439ac0
3 gewijzigde bestanden met toevoegingen van 193 en 0 verwijderingen
  1. 17 0
      TM1637_pio/micropython/README.md
  2. 157 0
      TM1637_pio/micropython/tm1637.py
  3. 19 0
      TM1637_pio/micropython/tm1637_test.py

+ 17 - 0
TM1637_pio/micropython/README.md

@@ -0,0 +1,17 @@
+# おまけ
+
+MicroPythonにTM1637のPIO制御を移植したおまけ版です。tm1637.pyをMicroPythonの仮想ストレージにアップロードしてください。DIOをGPIO4に、CLKをGPIO5に接続して次のようにすれば、TM1637使用7セグモジュール(4桁版)に表示できます。
+
+```python
+from tm1637 import TM1637
+
+SDA = 4
+COLMNS = 4
+CONTRAST = 3
+
+tm = TM1637(SDA, COLMNS, CONTRAST)
+tm.show_str("1234")
+```
+
+MicroPythonはそもそも低速なので、PIOで制御する恩恵はCより大きいでしょう。
+

+ 157 - 0
TM1637_pio/micropython/tm1637.py

@@ -0,0 +1,157 @@
+import rp2
+from machine import Pin
+import time
+
+class TM1637:
+    # 割り当て可能なステートマシンID管理
+    _available_ids = list(range(8))
+    
+    # セグメントデータ定義 (Cコードの digit_seg / letter_seg に対応)
+    _DIGIT_SEG = [0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f]
+    _LETTER_SEG = {
+        'A': 0x77, 'b': 0x7c, 'C': 0x39, 'd': 0x5e, 'E': 0x79, 'F': 0x71,
+        'G': 0x3d, 'H': 0x76, 'i': 0x04, 'J': 0x0e, 'L': 0x38, 'n': 0x54,
+        'o': 0x5c, 'P': 0x73, 'q': 0x67, 'r': 0x50, 'S': 0x6d, 't': 0x78,
+        'u': 0x1c, 'y': 0x6e, '-': 0x40, ' ': 0x00
+    }
+
+    # PIOプログラム定義
+    @rp2.asm_pio(
+        out_init=(rp2.PIO.IN_HIGH),
+        set_init=(rp2.PIO.IN_HIGH),
+        sideset_init=(rp2.PIO.OUT_HIGH),
+        out_shiftdir=rp2.PIO.SHIFT_RIGHT,
+        autopull=False,
+        fifo_join=rp2.PIO.JOIN_TX
+    )
+    def _tm1637_pio():
+        wrap_target()
+        # --- Start Condition ---
+        pull(block)
+        set(pindirs, 0b00)          # SDA/SCL input
+        nop()                   [7]
+        set(pindirs, 0b01)          # SDA output/SCL input
+        set(pins, 0)                # SDA is Low
+        nop()                   [7]
+        set(pindirs, 0b11)             # SDA/SCL output
+        set(x, 7)               .side(0)    # CLK is Low
+        jmp("output")
+        
+        label("byte_loop")
+        set(x, 7)       .side(0)    # CLK is Low
+        pull(block)
+        
+        label("output")
+        nop()                   [3]
+        out(pins, 1)            [4] # LSB output
+        nop()                   .side(1) # CLK is High
+        nop()                   [7]
+        nop()                   .side(0)    # CLK is Low
+        jmp(x_dec, "output")
+        
+        # --- ACK Check ---
+        set(pindirs, 0b10)      [7] # SDA input/SCL output
+        nop()                   .side(1) # SCL = High
+        jmp(pin, "nack")            # SDA High (NACK) なら分岐
+        jmp("ack")
+        
+        label("nack")
+        irq(rel(0))                 # NACK通知
+        
+        label("ack")
+        nop()                   [6]
+        nop()                   .side(0) # CLK is Low (ACK cycle end)
+        set(pindirs, 0b11)      [7] # SDA/SCL Output
+        out(x, 1)                   # 9bit目を読み取って判定
+        jmp(not_x, "byte_loop")     # 0なら次のバイトへ
+        
+        # --- Stop Condition ---
+        set(pins, 0)            [7] # SDA is Low
+        nop()                   .side(1) # SCL is High
+        nop()                   [7]
+        set(pindirs, 0b00)      [7] # SDA/SCL Input (STOP)
+        wrap()
+
+    def __new__(cls, *args, **kwargs):
+        if not cls._available_ids:
+            raise RuntimeError("Maximum TM1637 instances (8) reached")
+        instance = super().__new__(cls)
+        instance.sm_id = cls._available_ids.pop(0)
+        return instance
+
+    def __init__(self, sda_pin, columns=6, contrast=3):
+        # SDAの次のピンをSCLとする仕様を再現 (sda_base_pin + 1)
+        self.sda_pin = Pin(sda_pin, Pin.IN, pull=Pin.PULL_UP)
+        self.scl_pin = Pin(sda_pin + 1, Pin.IN, pull=Pin.PULL_UP)
+        self.columns = columns
+        
+        # PIO初期化 (2MHz)
+        self.sm = rp2.StateMachine(
+            self.sm_id,
+            self._tm1637_pio,
+            freq=2000000,
+            sideset_base=self.scl_pin,
+            set_base=self.sda_pin, # SDA(bit0) & SCL(bit1) をまとめて制御
+            out_base=self.sda_pin,
+            jmp_pin=self.sda_pin
+        )
+        self.sm.active(1)
+        
+        # 初期表示設定
+        self.clear()
+        self.set_contrast(contrast)
+
+    def _send_cmd(self, data, keep_going=False):
+        # 9ビット目に「終了(1)」か「継続(0)」のフラグを立てる
+        val = (data & 0xFF) | (0 if keep_going else 0x100)
+        self.sm.put(val)
+
+    def set_contrast(self, level):
+        # 0x88 (Display ON) | 0~7
+        cmd = 0x88 | (level & 0x07)
+        self._send_cmd(cmd)
+
+    def _chr_to_seg(self, char):
+        if '0' <= char <= '9':
+            return self._DIGIT_SEG[int(char)]
+        return self._LETTER_SEG.get(char, 0x00)
+
+    def show_str(self, s):
+        # 文字列を解析してセグメントデータのリストを作成
+        segments = []
+        i = 0
+        s_len = len(s)
+        
+        # カラム数または文字列が終わるまでループ
+        while i < s_len and len(segments) < self.columns:
+            char = s[i]
+            base_seg = self._chr_to_seg(char)
+            
+            # 次の文字が存在し、かつドットかコロンの場合
+            if (i + 1) < s_len and s[i + 1] in ('.', ':'):
+                base_seg |= 0x80  # 8ビット目(ドット)を立てる
+                i += 1            # ドット文字分インデックスを進める(スキップ)
+            
+            segments.append(base_seg)
+            i += 1
+
+        # 2. 生成したデータを出力
+        # データセット(自動アドレスインクリメント)
+        self._send_cmd(0x40) # TM1637_AUTOINC
+        # アドレス設定 (0)
+        self._send_cmd(0xC0, keep_going=True) # TM1637_ADDRSET
+        
+        # リストの内容を送信
+        for j, seg in enumerate(segments):
+            # 最後かどうかを判定 (リストの最後 かつ カラム最大)
+            is_last = (j == len(segments) - 1)
+            self._send_cmd(seg, keep_going=not is_last)
+
+    def clear(self):
+        self.show_str(' ' * self.columns)
+
+    def release(self):
+        self.sm.active(0)
+        if self.sm_id not in self.__class__._available_ids:
+            self.__class__._available_ids.append(self.sm_id)
+            self.__class__._available_ids.sort()

+ 19 - 0
TM1637_pio/micropython/tm1637_test.py

@@ -0,0 +1,19 @@
+from tm1637 import TM1637
+import time
+
+SDA = 4
+MY1637_COLMNS = 4
+CONTRAST = 3
+
+tm = TM1637(SDA, MY1637_COLMNS, CONTRAST)
+tm.show_str("12:34")
+time.sleep(5)
+tm.show_str("5555")
+time.sleep(5)
+i = 0
+while(True):
+    tm.show_str('%4d' % i)
+    i += 1
+    if i > 9999:
+        i = 0
+    time.sleep(1)