与 Raspberry Pi Pico 和 Python 的串口通信

问题描述 投票:0回答:2

我正在尝试通过 USB(COM 端口)在 Raspberry Pi Pico 和 Windows PC(Python)之间实现双向通信。 关键是,我无法将任何内容从我的 PC 发送到树莓派,也无法返回。 不会影响面包板上的 LED,也不会在终端中打印消息。

这是PC端的代码:

import serial
import time

# open a serial connection
s = serial.Serial("COM7", 115200)

print(s)
# blink the led
while True:
    s.write(b"on\n")
    time.sleep(1)
    s.readline().strip()
    s.write(b"off\n")
    time.sleep(1)
    s.readline().strip()

这是 Raspberry Pi Pico 上的一段代码:

import time
from machine import Pin
import sys

led = Pin(0, machine.Pin.OUT)
led2 = Pin(2, machine.Pin.OUT)
led2.value(0)
led.value(0)

def led_on():
    led.value(1)

def led_off():
    led.value(0)


while True:
    # read a command from the host
    v = sys.stdin.readline().strip()

    # perform the requested action
    if v.lower() == "on":
        led_on()
        print("Turned on!")
    elif v.lower() == "off":
        led_off()
        print("Turned off!")

另外 - 在 Raspberry Pi Pico 上调试代码的最聪明的方法是什么? 获得串行连接后,标准打印调试? 有没有办法在 Thonny IDE 中使用序列调试器?

致以诚挚的问候!

我已经尝试了串行或标准库库中的许多方法,但没有任何结果。 同样重要的是 - 对于脚本的 PC 端我使用 PyCharm,对于 Raspberry 端 - Thonny。 刷新 Raspberry Pico 后,我断开串行并开始在 PyCharm 中运行脚本,使用不同的解释器。

python micropython usbserial raspberry-pi-pico
2个回答
0
投票

最简单的解决方案

串行通信是纯粹双向的。给定的串行端口上不能有超过 2 个设备。在 Thonny(和 micropython)中,这是专门用于加载代码的。当程序运行时,您不能直接从您的计算机写入串口。但是,当程序未在 pico 上运行时,您可以访问 REPL。您可以在 here 阅读更多相关信息。这允许您直接在 pico 上调用函数。所以你可以写一个这样的程序:

from machine import pin

led = Pin(0, machine.Pin.OUT)
led2 = Pin(2, machine.Pin.OUT)
led2.value(0)
led.value(0)

def led_on():
    led.value(1)

def led_off():
    led.value(0)

并通过发送从 REPL 中调用它

>>> led_on()

这绝对是最简单的解决方案,还可以让您访问 microPython 中的任何功能,这可能对调试有用,因为您可以打印任何您想要的值。

更强大的解决方案

上面的代码代码没有错。它只是不会与 Thonny 一起工作,因为 Thonny 已经接管了串口。如果您将代码作为 .u2f 文件上传或使用单独的调试器(例如 pi 或第二个 pico 作为 picoprobe)使用 UART 外围设备之一,那么您可以将 USB 端口用作串行连接。在 raspberry pi 表单上有一个 thread,其中显示了功能性 2-way 串行代码。同样,这个 tutorial 将引导您在后台线程中完成它。


0
投票

可以使用Pico的双核,创建一个线程来监听COM。看看这个页面给你一个解决方案(https://forums.raspberrypi.com//viewtopic.php?t=302889)。上传一个main.py到Pico,释放COM串口(一般是COM3,也可以用PC python查询)。连接Pico MicroUSB,运行Pico中的main.py。 然后就可以使用PC python操作COM发送数据了

''' main.py in Pico
#comming from https://forums.raspberrypi.com//viewtopic.php?t=302889
from sys import stdin, exit
from _thread import start_new_thread
from utime import sleep
# 
# global variables to share between both threads/processors
# 
bufferSize = 1024                 # size of circular buffer to allocate
buffer = [' '] * bufferSize       # circuolar incomming USB serial data buffer (pre fill)
bufferEcho = True                 # USB serial port echo incooming characters (True/False) 
bufferNextIn, bufferNextOut = 0,0 # pointers to next in/out character in circualr buffer
terminateThread = False           # tell 'bufferSTDIN' function to terminate (True/False)
#
# bufferSTDIN() function to execute in parallel on second Pico RD2040 thread/processor
#
def bufferSTDIN():
    global buffer, bufferSize, bufferEcho, bufferNextIn, terminateThread
    
    while True:                                 # endless loop
        if terminateThread:                     # if requested by main thread ...
            break                               #    ... exit loop
        buffer[bufferNextIn] = stdin.read(1)    # wait for/store next byte from USB serial
        if bufferEcho:                          # if echo is True ...
            print(buffer[bufferNextIn], end='') #    ... output byte to USB serial
        bufferNextIn += 1                       # bump pointer
        if bufferNextIn == bufferSize:          # ... and wrap, if necessary
            bufferNextIn = 0
#
# instantiate second 'background' thread on RD2040 dual processor to monitor and buffer
# incomming data from 'stdin' over USB serial port using ‘bufferSTDIN‘ function (above)
#
bufferSTDINthread = start_new_thread(bufferSTDIN, ())

#
# function to check if a byte is available in the buffer and if so, return it
#
def getByteBuffer():
    global buffer, bufferSize, bufferNextOut, bufferNextIn
    
    if bufferNextOut == bufferNextIn:           # if no unclaimed byte in buffer ...
        return ''                               #    ... return a null string
    n = bufferNextOut                           # save current pointer
    bufferNextOut += 1                          # bump pointer
    if bufferNextOut == bufferSize:             #    ... wrap, if necessary
        bufferNextOut = 0
    return (buffer[n])                          # return byte from buffer

#
# function to check if a line is available in the buffer and if so return it
# otherwise return a null string
#
# NOTE 1: a line is one or more bytes with the last byte being LF (\x0a)
#      2: a line containing only a single LF byte will also return a null string
#
def getLineBuffer():
    global buffer, bufferSize, bufferNextOut, bufferNextIn

    if bufferNextOut == bufferNextIn:           # if no unclaimed byte in buffer ...
        return ''                               #    ... RETURN a null string

    n = bufferNextOut                           # search for a LF in unclaimed bytes
    while n != bufferNextIn:
        if buffer[n] == '\x0a':                 # if a LF found ... 
            break                               #    ... exit loop ('n' pointing to LF)
        n += 1                                  # bump pointer
        if n == bufferSize:                     #    ... wrap, if necessary
            n = 0
    if (n == bufferNextIn):                     # if no LF found ...
            return ''                           #    ... RETURN a null string

    line = ''                                   # LF found in unclaimed bytes at pointer 'n'
    n += 1                                      # bump pointer past LF
    if n == bufferSize:                         #    ... wrap, if necessary
        n = 0

    while bufferNextOut != n:                   # BUILD line to RETURN until LF pointer 'n' hit
        
        if buffer[bufferNextOut] == '\x0d':     # if byte is CR
            bufferNextOut += 1                  #    bump pointer
            if bufferNextOut == bufferSize:     #    ... wrap, if necessary
                bufferNextOut = 0
            continue                            #    ignore (strip) any CR (\x0d) bytes
        
        if buffer[bufferNextOut] == '\x0a':     # if current byte is LF ...
            bufferNextOut += 1                  #    bump pointer
            if bufferNextOut == bufferSize:     #    ... wrap, if necessary
                bufferNextOut = 0
            break                               #    and exit loop, ignoring (i.e. strip) LF byte
        line = line + buffer[bufferNextOut]     # add byte to line
        bufferNextOut += 1                      # bump pointer
        if bufferNextOut == bufferSize:         #    wrap, if necessary
            bufferNextOut = 0
    return line                                 # RETURN unclaimed line of input

#
# main program begins here ...
#
# set 'inputOption' to either  one byte ‘BYTE’  OR one line ‘LINE’ at a time. Remember, ‘bufferEcho’
# determines if the background buffering function ‘bufferSTDIN’ should automatically echo each
# byte it receives from the USB serial port or not (useful when operating in line mode when the
# host computer is running a serial terminal program)
#
# start this MicroPython code running (exit Thonny with code still running) and then start a
# serial terminal program (e.g. putty, minicom or screen) on the host computer and connect
# to the Raspberry Pi Pico ...
#
#    ... start typing text and hit return.
#
#    NOTE: use Ctrl-C, Ctrl-C, Ctrl-D then Ctrl-B on in the host computer terminal program 
#           to terminate the MicroPython code running on the Pico 
#
try:
    inputOption = 'LINE'                    # get input from buffer one BYTE or LINE at a time
    while True:

        if inputOption == 'BYTE':           # NON-BLOCKING input one byte at a time
            buffCh = getByteBuffer()        # get a byte if it is available?
            if buffCh:                      # if there is...
                print (buffCh, end='')      # ...print it out to the USB serial port

        elif inputOption == 'LINE':         # NON-BLOCKING input one line at a time (ending LF)
            buffLine = getLineBuffer()      # get a line if it is available?
            if buffLine:                    # if there is...
                print (buffLine)            # ...print it out to the USB serial port

        sleep(0.1)

except KeyboardInterrupt:                   # trap Ctrl-C input
    terminateThread = True                  # signal second 'background' thread to terminate 
    exit()
'''
© www.soinside.com 2019 - 2024. All rights reserved.