Nゲージの部屋にようこそ

2022/01/03 昨年Nゲージ用PWMコントローラを作成したので回路等を公開ます。

2022/01/04 回路を公開。

2022/01/05 プログラムを公開。

2022/01/06 プログラムの説明。

2022/01/16 完成品の表示。

概要
コントローラにRaspberry Pi Picoを使用。
Raspberry pi picoのプログラムはMicroPython。
モータドライバーにTA7291Pを使用。
Nゲージの制御はPWM,PWFを選択、出力電圧は12V。

回路図
電源は、Nゲージで使用する12Vから3端子レギュレータを使って回路用の5Vを作っています。
今回作成した回路には操作SWおよびLEDでの動作モニタができるようにしていますが、そこは今回省略しています。
速度の入力は、ロータリーエンコーダからの入力になります。
モニターには16X2のLCDをI2Cで接続してモニタ出来るようにしています。
最初トランジスタでPicoの出力を受けていましたがトランジスタアレイに変更しました。トランジスタアレイの存在を知らなっかた。
TBD62003APGは吸い込みで使用しているので、Picoがオンのときに切る、オフのときに電流が流れます。
GP16ピンをRaspberry Pi PicoでPWM制御すればTA7291Pの出力がPWMで出力される仕組みです。
Nゲージの進行方向は、GP21ピン,GP22ピンのオン、オフで制御します、同時にオンをしないように。

import time
import machine
from esp8266_i2c_lcd import I2cLcd
from machine import Pin
import utime
import random

AUTO_OPERATION = False
KeepSpeed = False
LoopCount = 0

#方向
DIR_CW = 1
DIR_CCW = 2

PP_PWM=0
PG_PFM=1
PG_PFMS=2

#モード
MODE_MANUAL=1
MODE_AUTO=2
MODE_ACC=3
MODE_BRACK=4
MODE_COAST=5
MODE_MAX=6
MODE_STOP=7
MODE_LIGHT=8
MODE_FREQ=9
MODE_PG=10
MODE_PFMMIN=11
MODE_PFMMAX=12
MODE_EXT1=13
MODE_EXT2=14
MODE_EXT3=15
MODE_XMAS=16

MODE = MODE_MANUAL
DIR = DIR_CW
OFF = False
ESTOP = False

VALUE=[0,0,0,10,20,1,100,5,5,100,0,5,25,3,30,40,0]

I2C_ADDR = 0x27

MODE_TITLE=["", "MANAL:", "OFF  :", "*ACC :", "*DEC :", "*COAT:", "*MAX :", "*STOP:", "*LIGT:", "*FREQ:", "*PG MODE:", "*PFM MIN-FREQ:", "*PFM MAX-FREQ:", "*EXT 1:", "*EXT 2:", "*EXT 3:"]
AUTO_TITLE=["OFF   ", "ACC  :", "DEC  :"]
DIR_MSG=[" - ", " UP", " DN"]
PGMODE_MSG=["PWM ", "PFM ", "PFMS"]
#GPIO
cw=21
ccw=20
ref=16
dt=19
clk=18
mode=26
dir=27
off=22
estop=28
sda=0
scl=1
led = 25
ex1=12
ex2=13
ex3=14

led_power=2
led_manual=3
led_auto=4
led_setmode=5
led_cw=6 
led_ccw=7
led_acc=8
led_off=9
led_deac=10
led_estop=11

LED_OFF = 0
LED_ON = 32768
LED_ON = 10000
ledPin = machine.Pin(led, machine.Pin.OUT)
cwPin = machine.Pin(cw, Pin.OUT)
ccwPin = machine.Pin(ccw, Pin.OUT)
# ledCwPin = machine.Pin(led_cw, Pin.OUT)
# ledCcwPin = machine.Pin(led_ccw, Pin.OUT)
modePin = machine.Pin(mode, Pin.IN, Pin.PULL_UP)
dirPin = machine.Pin(dir, Pin.IN, Pin.PULL_UP)
offPin = machine.Pin(off, Pin.IN, Pin.PULL_UP)
estopPin = machine.Pin(estop, Pin.IN, Pin.PULL_UP)

refPin = machine.PWM(machine.Pin(ref, Pin.OUT))
ex1Pin = machine.PWM(machine.Pin(ex1, Pin.OUT))
ex2Pin = machine.PWM(machine.Pin(ex2, Pin.OUT))
ex3Pin = machine.PWM(machine.Pin(ex3, Pin.OUT))
dtPin = machine.Pin(dt, Pin.IN, Pin.PULL_UP)
clkPin = machine.Pin(clk, Pin.IN, Pin.PULL_UP)
sdaPin = machine.Pin(sda)
sclPin = machine.Pin(scl)

ledPowerPin = machine.PWM(machine.Pin(led_power, Pin.OUT))
ledManualPin = machine.PWM(machine.Pin(led_manual, Pin.OUT))
ledAutoPin = machine.PWM(machine.Pin(led_auto, Pin.OUT))
ledSetModePin = machine.PWM(machine.Pin(led_setmode, Pin.OUT))
ledCWPin = machine.PWM(machine.Pin(led_cw, Pin.OUT))
ledCCWPin = machine.PWM(machine.Pin(led_ccw, Pin.OUT))
ledOFFPin = machine.PWM(machine.Pin(led_off, Pin.OUT))
ledEStopPin = machine.PWM(machine.Pin(led_estop, Pin.OUT))
ledAccPin = machine.PWM(machine.Pin(led_acc, Pin.OUT))
ledDeacPin = machine.PWM(machine.Pin(led_deac, Pin.OUT))
refPin.freq(20000)
ex1Pin.freq(20000)
ex2Pin.freq(20000)
ex3Pin.freq(20000)

ledPowerPin.freq(20000)
ledManualPin.freq(20000)
ledAutoPin.freq(20000)
ledSetModePin.freq(20000)
ledCWPin.freq(20000)
ledCCWPin.freq(20000)
ledOFFPin.freq(20000)
ledEStopPin.freq(20000)
ledAccPin.freq(20000)
ledDeacPin.freq(20000)

ledPowerPin.duty_u16(LED_OFF)
ledManualPin.duty_u16(LED_OFF)
ledAutoPin.duty_u16(LED_OFF)
ledSetModePin.duty_u16(LED_OFF)
ledCWPin.duty_u16(LED_OFF)
ledCCWPin.duty_u16(LED_OFF)
ledOFFPin.duty_u16(LED_OFF)
ledEStopPin.duty_u16(LED_OFF)
ledAccPin.duty_u16(LED_OFF)
ledDeacPin.duty_u16(LED_OFF)


i2c = machine.I2C(0,sda=sdaPin, scl=sclPin, freq=400000)
lcd = I2cLcd(i2c, I2C_ADDR, 2, 16)
lcd.clear()
vol = 0
last_status = dtPin.value() << 1 | clkPin.value()
last_position = last_status
CNT = 0
DIR = DIR_CW
CNT_MAX = 100
CNT_MIN = -100

#エンコーダ変化
rDIR = 0
def rataryChange(pin):
    global CNT, rDIR
    global last_status, last_last_status, last_position
    new_status = dtPin.value() << 1 | clkPin.value()
    position = new_status
    if(new_status == last_status):
        return
    transition = (last_status << 2) | new_status
    if(transition == 0b0010 or transition == 0b1101):
        rDIR=-1
    elif(transition == 0b1110 or transition == 0b0001):
        rDIR=1
    if(position == 0b11 or position == 0b00):
        if(last_position != position):
            last_position = position
            CNT+=rDIR
    if(CNT > CNT_MAX):
        CNT = CNT_MAX
    if(CNT < CNT_MIN):
        CNT = CNT_MIN
    last_status = new_status

last_mode_ticks_ms = 0
ModeInc=False
#モードボタン    
def modeChange(pin):
    global MODE, CNT, ModeInc
    global last_mode_ticks_ms
    ticks_ms = time.ticks_ms()
    if last_mode_ticks_ms + 100 < ticks_ms:
        ModeInc=True
        # print("modeChange:{0}".format(MODE))
    last_mode_ticks_ms = ticks_ms

def Manual():
    global CNT,CNT_MAX,CNT_MIN,VALUE
    ledSetModePin.duty_u16(LED_OFF)
    ledManualPin.duty_u16(LED_ON)
    CNT = 0
    CNT_MAX = 100
    CNT_MIN = -100
    VALUE[MODE]=0

def Auto():
    global CNT,CNT_MAX,CNT_MIN,VALUE
    ledManualPin.duty_u16(LED_OFF)
    ledAutoPin.duty_u16((int)(LED_ON))
    CNT = 0
    CNT_MAX = 10
    CNT_MIN = -10

def Acc():
    global CNT_MAX,CNT_MIN,VALUE
    ledAutoPin.duty_u16(LED_OFF)
    ledSetModePin.duty_u16(LED_ON)
    CNT_MAX = 100
    CNT_MIN = 0

def Brack():
    global CNT_MAX,CNT_MIN,VALUE
    CNT_MAX = 100
    CNT_MIN = 0

def Coast():
    global CNT_MAX,CNT_MIN,VALUE
    CNT_MAX = 100
    CNT_MIN = 0
    # set_mode(refPin)

def Max():
    global CNT_MAX,CNT_MIN,VALUE
    CNT_MAX = 100
    CNT_MIN = 0

def Stop():
    global CNT_MAX,CNT_MIN,VALUE
    CNT_MAX = 100
    CNT_MIN = 0

def Light():
    global CNT_MAX,CNT_MIN,VALUE
    CNT_MAX = 100
    CNT_MIN = 0

def Freq():
    global CNT_MAX,CNT_MIN,VALUE
    CNT_MAX = 400
    CNT_MIN = 1

def Pg():
    global CNT_MAX,CNT_MIN,VALUE
    CNT_MAX = PG_PFMS
    CNT_MIN = PP_PWM

def Pfmmin():
    global CNT_MAX,CNT_MIN,VALUE
    CNT_MAX = 400
    CNT_MIN = 1

def Pfmmax():
    global CNT_MAX,CNT_MIN,VALUE
    CNT_MAX = 400
    CNT_MIN = 1

def Ext1():
    global CNT_MAX,CNT_MIN,VALUE
    CNT_MAX = 100
    CNT_MIN = 0

def Ext2():
    global CNT_MAX,CNT_MIN,VALUE
    CNT_MAX = 100
    CNT_MIN = 0

def Ext3():
    global CNT_MAX,CNT_MIN,VALUE
    CNT_MAX = 100
    CNT_MIN = 0

def modeInc():
    global MODE, CNT, ModeInc, CNT_MAX, CNT_MIN,LED_ON, LED_OFF, KeepSpeed

    if ModeInc==True:
        AUTO_OPERATION=False
        ledPowerPin.duty_u16(LED_ON)
        KeepSpeed = False
        lcd.backlight_on()
        ledCWPin.duty_u16(LED_OFF)
        ledCCWPin.duty_u16(LED_OFF)
        ledOFFPin.duty_u16(LED_OFF)
        ledEStopPin.duty_u16(LED_OFF)
        ledAccPin.duty_u16(LED_OFF)
        ledDeacPin.duty_u16(LED_OFF)
        lcd.clear()
        ModeInc=False
        VALUE[MODE] = CNT
        MODE += 1
        if MODE > MODE_EXT3:
            MODE = MODE_MANUAL

        if(MODE== MODE_MANUAL):
            Manual()
        elif(MODE == MODE_AUTO):
            Auto()
        elif(MODE == MODE_ACC):
            Acc()
        elif(MODE == MODE_BRACK):
            Brack()
        elif(MODE == MODE_COAST):
            Coast()
            # set_mode(refPin)
        elif(MODE == MODE_MAX):
            Max()
        elif(MODE == MODE_STOP):
            Stop()
        elif(MODE == MODE_LIGHT):
            Light()
        elif(MODE == MODE_FREQ):
            Freq()
        elif(MODE == MODE_PG):
            Pg()
        elif(MODE == MODE_PFMMIN):
            Pfmmin()
        elif(MODE == MODE_PFMMAX):
            Pfmmax()
        elif(MODE == MODE_EXT1):
            Ext1()
        elif(MODE == MODE_EXT2):
            Ext2()
        elif(MODE == MODE_EXT3):
            Ext3()

        if(CNT > CNT_MAX):
            CNT = CNT_MAX
        if(CNT < CNT_MIN):
            CNT = CNT_MIN

        CNT = VALUE[MODE]

#方向ボタン
def dirChange(pin):
    global CNT,DIR,vol
    DIR = DIR_CW if DIR == DIR_CCW else DIR_CCW
    if MODE == MODE_AUTO:
        vol = VALUE[MODE_STOP] * 10
        CNT=0

swOFF = False
#切ボタン
def offChange(pin):
    global swOFF,AUTO_OPERATION
    swOFF = True
    AUTO_OPERATION=False

swESTOP=False
#非常停止ボタン
def estopChange(pin):
    global swESTOP, AUTO_OPERATION
    swESTOP = True
    AUTO_OPERATION=False

#割り込み設定
dtPin.irq(handler=rataryChange, trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING)
clkPin.irq(handler=rataryChange, trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING)
modePin.irq(handler=modeChange, trigger=Pin.IRQ_FALLING)
dirPin.irq(handler=dirChange, trigger=Pin.IRQ_FALLING)
offPin.irq(handler=offChange, trigger= Pin.IRQ_FALLING)
estopPin.irq(handler=estopChange, trigger=Pin.IRQ_FALLING)

def startup():
    ccwPin.value(0)
    cwPin.value(0)
    ex1Pin.duty_u16((int)(VALUE[MODE_EXT1] * 655.35))
    ex2Pin.duty_u16((int)(VALUE[MODE_EXT2] * 655.35))
    ex3Pin.duty_u16((int)(VALUE[MODE_EXT3] * 655.35))
    ledPowerPin.duty_u16(LED_ON)
    ledAutoPin.duty_u16(LED_OFF)
    ledSetModePin.duty_u16(LED_OFF)
    ledCWPin.duty_u16(LED_OFF)
    ledCCWPin.duty_u16(LED_OFF)
    ledOFFPin.duty_u16(LED_OFF)
    ledEStopPin.duty_u16(LED_OFF)
    ledAccPin.duty_u16(LED_OFF)
    ledDeacPin.duty_u16(LED_OFF)
    ledManualPin.duty_u16(LED_ON)
    for c in "POWERD By \n      K.Sasaki":
        lcd.putchar(c)
        time.sleep(0.1)
    time.sleep(1)
    lcd.clear()

Ref = 0
vol= 0
def manual_mode(ref):
    global Ref, vol, swESTOP, CNT
    lcd.putstr(MODE_TITLE[MODE])

    if swESTOP == True:
        swESTOP = False
        CNT = 0
        
    vol = CNT
    dVol = Vol = vol if vol >= 0 else -vol
    span = 100 - VALUE[MODE_STOP]
    if Vol < VALUE[MODE_STOP]:
        freq = VALUE[MODE_PFMMIN] * 100
    else:
        freq = ((VALUE[MODE_PFMMAX] - VALUE[MODE_PFMMIN]) * (Vol - VALUE[MODE_STOP]) / span + VALUE[MODE_PFMMIN]) * 100
        if VALUE[MODE_PG]==PG_PFMS:
            freq = ((VALUE[MODE_PFMMAX] - VALUE[MODE_PFMMIN]) * int(((Vol - VALUE[MODE_STOP]) / 10)) / int(span / 10) + VALUE[MODE_PFMMIN]) * 100

    loop = (Vol + 1) / 10
    if MODE == MODE_MANUAL:
        if(vol > 0):
            ccwPin.value(0)
            cwPin.value(1)
            ledCWPin.duty_u16(LED_ON)
            ledCCWPin.duty_u16(LED_OFF)
        elif(vol < 0):
            cwPin.value(0)
            ccwPin.value(1)
            ledCWPin.duty_u16(LED_OFF)
            ledCCWPin.duty_u16(LED_ON)
        else:
            cwPin.value(0)
            ccwPin.value(0)
            ledCWPin.duty_u16(LED_OFF)
            ledCCWPin.duty_u16(LED_OFF)
        Vol = 100 - Vol
    else:
        cwPin.value(0)
        ccwPin.value(0)
        ledCWPin.duty_u16(LED_OFF)
        ledCCWPin.duty_u16(LED_OFF)
        Vol = Vol

    duty = (int)(Vol * 655.35)
    if(MODE == MODE_MANUAL and (VALUE[MODE_PG]==PG_PFM or VALUE[MODE_PG]==PG_PFMS)):
        ref.freq((int)(freq))
        ref.duty_u16(duty)
    else:
        freq = VALUE[MODE_FREQ] * 100
        ref.freq((int)(freq))
        ref.duty_u16(duty)
    # print("freq:{0}  duty:{1}".format(freq, duty))

    if(loop >= 10):
        loop = 10
    for i in range(loop):
        if dVol >= (i + 1) * 10:
            if(vol == 0):
                lcd.putchar(' ')
            elif(vol > 0):
                lcd.putchar('\xff')
            else:
                lcd.putchar('#')
        else:
            lcd.putchar(chr(ord('0') + dVol % 10))
    for i in range(9-(loop)):
        lcd.putchar(" ")
    lcd.move_to(0, 1)
    lcd.putstr('POWER:{:+04}'.format(vol))

def auto_mode(ref):
    global Ref,vol,DIR,DIR_MSG, CNT, swOFF, swESTOP, KeepSpeed, AUTO_OPERATION

    if AUTO_OPERATION:
        if LoopCount % 2 == 1:
            ledAutoPin.duty_u16(LED_ON)
        else:
            ledAutoPin.duty_u16(LED_OFF)
        motion = LoopCount % 1000
        if motion == 1:
            CNT = 7
        if motion == 150:
            CNT = 0
        elif motion == 240:
            KeepSpeed = True
        elif motion == 300:
            CNT = -3
        elif motion == 320:
            CNT = 7
        elif motion == 400:
            CNT = 10
        elif motion == 450:
            CNT = -9
        elif motion == 480:
            CNT = 3
        elif motion == 500:
            CNT = 5
        elif motion == 550:
            CNT = 7
        elif motion == 600:
            KeepSpeed = True
        elif motion == 700:
            KeepSpeed = False
            CNT = 5
        elif motion == 800:
            KeepSpeed = True
        elif motion == 900:
            CNT = -3
        elif motion == 980:
            CNT = -10
        elif motion == 995:
            if DIR == DIR_CW:
                DIR = DIR_CCW
            else:
                DIR = DIR_CW
    else:
        ledAutoPin.duty_u16(LED_ON)

    pitch = (VALUE[MODE_MAX] - VALUE[MODE_STOP])
    if swOFF == True:
        swOFF = False
        CNT = 0
    if swESTOP == True:
        swESTOP = False
        CNT = -10

    if CNT > 0:             # 加速
        KeepSpeed = False
        ledOFFPin.duty_u16(LED_OFF)
        if vol >= VALUE[MODE_MAX] * 10:
            if LoopCount % 2 == 1:
                ledAccPin.duty_u16(LED_ON)
            else:
                ledAccPin.duty_u16(LED_OFF)
        else:
            ledAccPin.duty_u16(LED_ON)
        ledEStopPin.duty_u16(LED_OFF)
        ledDeacPin.duty_u16(LED_OFF)
        if VALUE[MODE_STOP] * 10 + pitch * CNT >= vol: 
            vol += CNT * VALUE[MODE_ACC] / 10
        else:
            vol -= VALUE[MODE_COAST]
    elif CNT == -10:        # 非常停止
        KeepSpeed = False
        ledOFFPin.duty_u16(LED_OFF)
        ledAccPin.duty_u16(LED_OFF)
        ledEStopPin.duty_u16(LED_ON)
        ledDeacPin.duty_u16(LED_OFF)
        vol = VALUE[MODE_STOP]
    elif CNT < 0:           # 減速
        KeepSpeed = False
        ledOFFPin.duty_u16(LED_OFF)
        ledDeacPin.duty_u16(LED_ON)
        ledEStopPin.duty_u16(LED_OFF)
        ledAccPin.duty_u16(LED_OFF)
        if(vol > 0):
            vol += CNT * VALUE[MODE_BRACK] / 10
    elif CNT == 0: 
        if KeepSpeed == True:
            if LoopCount % 2 == 1:
                ledOFFPin.duty_u16(LED_ON)
            else:
                ledOFFPin.duty_u16(LED_OFF)
        else:
            ledOFFPin.duty_u16(LED_ON)
            vol -= VALUE[MODE_COAST]
        ledAccPin.duty_u16(LED_OFF)
        ledEStopPin.duty_u16(LED_OFF)
        ledDeacPin.duty_u16(LED_OFF)

    if(vol < VALUE[MODE_STOP] * 10):
        vol = VALUE[MODE_STOP] * 10 
    if(vol > VALUE[MODE_MAX] * 10):
        vol = VALUE[MODE_MAX] * 10 

    Vol = vol if vol >= 0 else -vol
    span = 1000 - VALUE[MODE_STOP] * 10
    if Vol <= VALUE[MODE_STOP] * 10:
        freq = VALUE[MODE_PFMMIN] * 100
    else:
        freq = ((VALUE[MODE_PFMMAX] - VALUE[MODE_PFMMIN]) * 100 * (Vol - VALUE[MODE_STOP] * 10) / span) + VALUE[MODE_PFMMIN] * 100
        if VALUE[MODE_PG]==PG_PFMS:
            freq = (((VALUE[MODE_PFMMAX] - VALUE[MODE_PFMMIN]) * 100 * int(((Vol - VALUE[MODE_STOP] * 10) / 100)) / int(span / 100)) + VALUE[MODE_PFMMIN] * 100)

    # print("freq:{0}  Vol:{1}  span:{2}".format(freq, Vol, span))
    dir = 0 if CNT == 0 else 1 if CNT > 0 else 2
    lcd.putstr(AUTO_TITLE[dir])
    Ref = (int)(vol / 10.0)

    loop = CNT if CNT > 0 else -CNT
    if(DIR == DIR_CW):
        ccwPin.value(0)
        cwPin.value(1)
        ledCWPin.duty_u16(LED_ON)
        ledCCWPin.duty_u16(LED_OFF)
    elif(DIR == DIR_CCW):
        cwPin.value(0)
        ccwPin.value(1)
        ledCWPin.duty_u16(LED_OFF)
        ledCCWPin.duty_u16(LED_ON)
    duty = (int)((1000 - vol) * 65.535)
    # print("freq:{0}  duty:{1}  Vol:{2}  span:{3}".format(freq, duty, Vol, span))
    if(MODE == MODE_AUTO and (VALUE[MODE_PG]==PG_PFM or VALUE[MODE_PG]==PG_PFMS)):
        ref.freq((int)(freq))
        ref.duty_u16(duty)
    else:
        freq = VALUE[MODE_FREQ] * 100
        ref.freq((int)(freq))
        ref.duty_u16((int)(duty))

    if(loop >= 10):
        loop = 10
    for i in range(loop):
        lcd.putchar('\xff')
    for i in range(10-(loop)):
        lcd.putchar(" ")
    lcd.move_to(0, 1)
    lcd.putstr('POWER:{:+04}{}'.format(Ref, DIR_MSG[DIR]))

def pg_mode(ref):
    global Ref,vol,CNT,CNT_MAX,CNT_MIN
    if(CNT > CNT_MAX):
        CNT = CNT_MAX
    if(CNT < CNT_MIN):
        CNT = CNT_MIN
    lcd.putstr(MODE_TITLE[MODE])
    lcd.putstr(PGMODE_MSG[CNT])

def freq_mode(ref):
    global Ref,vol
    lcd.putstr(MODE_TITLE[MODE])

    vol = CNT * 100
    lcd.move_to(0, 1)
    lcd.putstr('FREQ:{:06}'.format(vol))

def set_mode(ref):
    global Ref,vol
    lcd.putstr(MODE_TITLE[MODE])
    vol = CNT
    Vol = 0
    Ref = (int)(Vol * 655.35)

    Vol = vol if vol >= 0 else -vol
    loop = (Vol + 1) / 10

    cwPin.value(0)
    ccwPin.value(0)
    ref.duty_u16(0)

    if(loop >= 10):
        loop = 10
    for i in range(loop):
        if Vol >= (i + 1) * 10:
            if(vol > 0):
                lcd.putchar('\xff')
            else:
                lcd.putchar('#')
        else:
            lcd.putchar(chr(ord('0') + Vol % 10))
    for i in range(9-(loop)):
        lcd.putchar(" ")
    lcd.move_to(0, 1)
    lcd.putstr('POWER:{:+04}'.format(vol))

def XMAS():
    lcd.backlight_off()
    val = 0
    if(random.random() > 0.5):
        val = LED_ON
    else:
        val = LED_OFF
    ledPowerPin.duty_u16(val)

    if(random.random() > 0.5):
        val = LED_ON
    else:
        val = LED_OFF
    ledManualPin.duty_u16(val)
    if(random.random() > 0.5):
        val = LED_ON
    else:
        val = LED_OFF
    ledAutoPin.duty_u16(val)
    if(random.random() > 0.5):
        val = LED_ON
    else:
        val = LED_OFF
    ledSetModePin.duty_u16(val)
    if(random.random() > 0.5):
        val = LED_ON
    else:
        val = LED_OFF
    ledCWPin.duty_u16(val)
    if(random.random() > 0.5):
        val = LED_ON
    else:
        val = LED_OFF
    ledCCWPin.duty_u16(val)
    if(random.random() > 0.5):
        val = LED_ON
    else:
        val = LED_OFF
    ledOFFPin.duty_u16(val)
    if(random.random() > 0.5):
        val = LED_ON
    else:
        val = LED_OFF
    ledEStopPin.duty_u16(val)
    if(random.random() > 0.5):
        val = LED_ON
    else:
        val = LED_OFF
    ledAccPin.duty_u16(val)
    if(random.random() > 0.5):
        val = LED_ON
    else:
        val = LED_OFF
    ledDeacPin.duty_u16(val)

ledVal = 1
ledPin.value(ledVal)
startup()
SwDIRCount = 0
SwOFFCount = 0
SwESTOPCount = 0
lastMode = 0

while(True):
    LoopCount += 1
    modeInc()
    lastMode=MODE
    if(modePin.value() == 0):
        if(lastMode==MODE):
            SwCount+=1
        else:
            SwCount=0
    else:
        SwCount=0
    if(SwCount > 0 and SwCount % 20 == 0):
        if MODE != MODE_AUTO:
            MODE = MODE_AUTO
            Auto()
            CNT=0
        else:
            MODE = MODE_MANUAL
            Manual()
            CNT=0

    if(dirPin.value() == 0):
        SwDIRCount+=1
    else:
        SwDIRCount=0

    if(SwDIRCount > 0 and SwDIRCount % 20 == 0):
        AUTO_OPERATION = True
        LoopCount=0

    if(MODE == MODE_AUTO and offPin.value() == 0):
        SwOFFCount+=1
    else:
        SwOFFCount=0

    if(SwOFFCount > 0 and SwOFFCount % 20 == 0):
        if KeepSpeed == True:
            KeepSpeed = False
        else:
            KeepSpeed = True

    if(estopPin.value() == 0):
        SwESTOPCount+=1
    else:
        SwESTOPCount=0
    if(SwESTOPCount > 0 and SwESTOPCount % 20 == 0):
        MODE = MODE_XMAS

    # print("SwCount:{0}".format(SwCount))
    # print("modePin.value():{0}".format(modePin.value()))
    
    ledVal = 1 if ledVal == 0 else 0
    ledPin.value(ledVal)
    lcd.move_to(0,0)
    if(MODE== MODE_XMAS):
        XMAS()
    if(MODE== MODE_MANUAL):
        manual_mode(refPin)
    elif(MODE == MODE_AUTO):
        auto_mode(refPin)
    elif(MODE == MODE_ACC):
        set_mode(refPin)
    elif(MODE == MODE_BRACK):
        set_mode(refPin)
    elif(MODE == MODE_COAST):
        set_mode(refPin)
    elif(MODE == MODE_MAX):
        set_mode(refPin)
    elif(MODE == MODE_STOP):
        set_mode(refPin)
    elif(MODE == MODE_LIGHT):
        set_mode(refPin)
    elif(MODE == MODE_FREQ):
        freq_mode(refPin)
    elif(MODE == MODE_PG):
        pg_mode(refPin)
    elif(MODE == MODE_PFMMIN):
        freq_mode(refPin)
    elif(MODE == MODE_PFMMAX):
        freq_mode(refPin)
    elif(MODE == MODE_EXT1):
        manual_mode(ex1Pin)
    elif(MODE == MODE_EXT2):
        manual_mode(ex2Pin)
    elif(MODE == MODE_EXT3):
        manual_mode(ex3Pin)
    time.sleep(0.1)

プログラムの環境はPaspberry pi picoでPythonを使う方法が説明されたページがあるので参照してください。
1 - 7 行:プログラムで使用するモジュールの読み込み
esp8266_i2c_lcdモジュール以外は標準の状態で読み込みできます。
esp8266_i2c_lcdは、python_lcdという名前のモジュールでGitHubに公開されているモジュールの一部です。
8 - 51行:プログラムのグローバル変数を定義
51 - 78行:Paspberry pi picoのGPIOのピン番号を名前に割り当てています。
80 - 82行:今回LEDの点灯もPWMで点灯させているので、LEDオンとオフのときのデュティーを定義しています。0:消灯 65536:点灯(最大)
83行:Paspberry pi pico基板上のLEDを設定
84 - 92行:外部のスイッチの設定(回路図には記載していない)
93行:Nゲージのデュティー信号を出力するGPIOの設定
94 - 95行:その他のデュティー信号を出力するGPIOの設定(今回駅のホームのLED等に使用)
97行:Nゲージのデュティー信号を出力するGPIOの設定
96 - 97行:ロータリエンコーダの信号を取り込むGPIOの設定
99 - 100行:LCD(i2C)のデータを書き込むGPIOの設定
111 - 111行:外部LEDのPWMの設定(回路図には記載していない)
112 - 126行:PWMに設定した初期カウンターの周期を設定
128 - 137行:PWMに設定した初期のデュティーを設定
140行:I2Cの初期化
141行:I2C LCDの設定
142行:LCDの画面クリア
151 - 173行:ロータリエンコーダの回転方向、回転数の取り込み。回転数はCNT変数に保持 この関数はロータリエンコーダDT、CLKの変化時に割り込みで呼び出される。 データの取りこぼしは、ほぼないです、Nゲージの制御には支障ないです。 割り込み定義は#355、#356行で定義しています。