Python与Arduino串口读写

24 投票
3 回答
143545 浏览
提问于 2025-04-18 08:49

我正在尝试在一些Python代码和Arduino代码之间来回“乒乓”信息。我想定期(比如每分钟)向Arduino发送两个设定值,然后在Arduino上读取这些值并更新变量,接着再定期(比如在每分钟的30秒时)从Arduino发送状态信息回到Python。最终,Python会从一个MySQL数据库中发送和获取信息(这是后续开发的内容)。

现在我无法让信息可靠地来回传递。我在搜索中没有找到类似的内容,尝试修改的所有方法都没有效果。我目前的代码是这样的(但它实际上并没有在发送和接收之间切换):

Python

#!/usr/bin/python
import serial
import syslog
import time

#The following line is for serial over GPIO
port = '/dev/ttyS0'


ard = serial.Serial(port,9600,timeout=5)

i = 0

while (i < 4):
    # Serial write section

    setTempCar1 = 63
    setTempCar2 = 37
    ard.flush()
    setTemp1 = str(setTempCar1)
    setTemp2 = str(setTempCar2)
    print ("Python value sent: ")
    print (setTemp1)
    ard.write(setTemp1)
    time.sleep(4)

    # Serial read section
    msg = ard.readline()
    print ("Message from arduino: ")
    print (msg)
    i = i + 1
else:
    print "Exiting"
exit()

Arduino:

// Serial test script

int setPoint = 55;
String readString;

void setup()
{

  Serial.begin(9600);  // initialize serial communications at 9600 bps

}

void loop()
{
  while(!Serial.available()) {}
  // serial read section
  while (Serial.available())
  {
    if (Serial.available() >0)
    {
      char c = Serial.read();  //gets one byte from serial buffer
      readString += c; //makes the string readString
    }
  }

  if (readString.length() >0)
  {
    Serial.print("Arduino received: ");  
    Serial.println(readString); //see what was received
  }

  delay(500);

  // serial write section

  char ard_sends = '1';
  Serial.print("Arduino sends: ");
  Serial.println(ard_sends);
  Serial.print("\n");
  Serial.flush();
}

结果我得到的只是重复的相同值(不是实际发送的内容,不确定是字符串问题还是字节问题),而且没有任何信息返回给Python脚本。任何帮助或建议都非常感谢。谢谢。

编辑:根据下面的建议修改了代码,现在Arduino接收正常,使用minicom验证了串口通信。但是Python脚本在“来自Arduino的消息:”后仍然打印出一个空行。

3 个回答

1

我发现用命令 Serial.readString() 来替代 Serial.read() 更好,这样可以更方便地获取Arduino的连续输入输出。

2

首先,你需要安装一个叫做Serial的模块。要做到这一点,先找到一个叫做Scripts的文件夹,这个文件夹在你安装Python的目录里。如果你使用的是Python 3版本,通常这个文件夹的位置如下:

C:\Python34\Scripts  

打开那个文件夹后,按住Shift键,然后右键点击这个文件夹。接着选择“在此处打开命令窗口”。这样就会弹出一个cmd窗口。在这个cmd窗口里,输入下面的代码:

pip install PySerial

然后按下回车键。这样PySerial模块就会被安装上。记住,安装模块的时候你必须有网络连接。


模块安装成功后,打开Python的IDLE,输入下面的代码并运行它。

import serial
# "COM11" is the port that your Arduino board is connected.set it to port that your are using        
ser = serial.Serial("COM11", 9600)
while True:
    cc=str(ser.readline())
    print(cc[2:][:-5])   
15

在Python中,写数据和读数据之间不应该关闭串口。因为如果在Arduino回应的时候串口还没打开,那数据就会丢失。

while running:  
    # Serial write section
    setTempCar1 = 63
    setTempCar2 = 37
    setTemp1 = str(setTempCar1)
    setTemp2 = str(setTempCar2)
    print ("Python value sent: ")
    print (setTemp1)
    ard.write(setTemp1)
    time.sleep(6) # with the port open, the response will be buffered 
                  # so wait a bit longer for response here

    # Serial read section
    msg = ard.read(ard.inWaiting()) # read everything in the input buffer
    print ("Message from arduino: ")
    print (msg)

Python的 Serial.read 函数默认只会返回一个字节,所以你要么在循环中多次调用它,要么等数据传输完再读取整个缓冲区。

在Arduino那边,你需要考虑在 loop 函数中当没有数据可用时会发生什么。

void loop()
{
  // serial read section
  while (Serial.available()) // this will be skipped if no data present, leading to
                             // the code sitting in the delay function below
  {
    delay(30);  //delay to allow buffer to fill 
    if (Serial.available() >0)
    {
      char c = Serial.read();  //gets one byte from serial buffer
      readString += c; //makes the string readString
    }
  }

相反,你应该在 loop 函数开始时等到数据到达再继续:

void loop()
{
  while (!Serial.available()) {} // wait for data to arrive
  // serial read section
  while (Serial.available())
  {
    // continue as before

编辑 2

这是我在用Python和你的Arduino应用程序交互时得到的结果:

>>> import serial
>>> s = serial.Serial('/dev/tty.usbmodem1411', 9600, timeout=5)
>>> s.write('2')
1
>>> s.readline()
'Arduino received: 2\r\n'

看起来一切正常。

在测试你的Python脚本时,发现问题是当你打开串口时,Arduino会重置(至少我的Uno是这样),所以你需要等几秒钟让它启动。此外,你只读取了一行作为回应,所以我在下面的代码中也修正了这个问题:

#!/usr/bin/python
import serial
import syslog
import time

#The following line is for serial over GPIO
port = '/dev/tty.usbmodem1411' # note I'm using Mac OS-X


ard = serial.Serial(port,9600,timeout=5)
time.sleep(2) # wait for Arduino

i = 0

while (i < 4):
    # Serial write section

    setTempCar1 = 63
    setTempCar2 = 37
    ard.flush()
    setTemp1 = str(setTempCar1)
    setTemp2 = str(setTempCar2)
    print ("Python value sent: ")
    print (setTemp1)
    ard.write(setTemp1)
    time.sleep(1) # I shortened this to match the new value in your Arduino code

    # Serial read section
    msg = ard.read(ard.inWaiting()) # read all characters in buffer
    print ("Message from arduino: ")
    print (msg)
    i = i + 1
else:
    print "Exiting"
exit()

现在上面的输出是这样的:

$ python ardser.py
Python value sent:
63
Message from arduino:
Arduino received: 63
Arduino sends: 1


Python value sent:
63
Message from arduino:
Arduino received: 63
Arduino sends: 1


Python value sent:
63
Message from arduino:
Arduino received: 63
Arduino sends: 1


Python value sent:
63
Message from arduino:
Arduino received: 63
Arduino sends: 1


Exiting

撰写回答