You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Arduino通过Python串口接收Firebase数据驱动7段数码管,测试始终显示0

问题根因排查与落地修改方案

核心问题定位(数码管始终显示0的原因)

  • 最核心的逻辑错误:Arduino端的串口比较逻辑写法存在致命问题。原代码中if(Serial.readString() == Serial.readString())的判断里,第一次调用Serial.readString()时就已经将串口缓冲区的所有数据读出,第二次调用时缓冲区已为空,两次读取结果永远无法相等,判断分支永远无法进入,程序始终走else分支点亮数字0。
  • 无固定串口帧格式约定:直接调用Serial.readString()会依赖默认1秒超时机制读取数据,容易混入上一轮的残留数据、触发读取超时返回空值,导致数据解析不稳定。
  • Python端串口通信无缓冲区清理步骤,容易将历史残留的无效数据传给Arduino。
  • 多余全局变量int a = 2无实际作用,且容易和函数内部参数命名冲突,干扰逻辑判断。

可直接运行的修改后代码

Arduino端修改版

// 保持原硬件接线对应的引脚定义不变
#define A PA0
#define B PA1
#define C PA2
#define D PA3
#define E PA4
#define F PA5
#define G PA6

// 七段码段码表:对应数字0-9的引脚电平,匹配原sevenSeg函数参数顺序(g f e d c b a)
const int segTable[10][7] = {
  {1,1,1,1,1,1,0}, // 0
  {0,0,0,1,1,0,0}, // 1
  {1,0,1,1,0,1,1}, // 2
  {1,0,0,1,1,1,1}, // 3
  {0,0,0,1,1,0,1}, // 4
  {0,1,0,1,1,1,1}, // 5
  {0,1,1,1,1,1,1}, // 6
  {1,0,0,1,1,0,0}, // 7
  {1,1,1,1,1,1,1}, // 8
  {1,0,0,1,1,1,1}  // 9
};

// 预期匹配的测试值,需和实际从Firebase拉到的字符串完全一致
const String EXPECTED_VALUE = "37.0";

void setup() {
  Serial.begin(9600);
  // 清空开机时串口的残留数据
  while(Serial.available()) Serial.read();
  
  // 初始化所有引脚为输出模式
  pinMode(A, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);
  pinMode(D, OUTPUT);
  pinMode(E, OUTPUT);
  pinMode(F, OUTPUT);
  pinMode(G, OUTPUT);
}

void loop() {
  if(Serial.available()){
    // 以换行符作为帧结束标记读取串口数据,避免无意义的超时等待
    String receivedData = Serial.readStringUntil('\n');
    // 清除字符串首尾的空白字符、不可见字符,避免匹配失败
    receivedData.trim();
    
    // 匹配到预期值时显示数字1
    if(receivedData == EXPECTED_VALUE){
      sevenSeg(segTable[1][0], segTable[1][1], segTable[1][2], segTable[1][3], segTable[1][4], segTable[1][5], segTable[1][6]);
    } else {
      // 收到不匹配的数据时显示数字0
      sevenSeg(segTable[0][0], segTable[0][1], segTable[0][2], segTable[0][3], segTable[0][4], segTable[0][5], segTable[0][6]);
    }
  } else {
    // 无串口数据时默认显示0
    sevenSeg(segTable[0][0], segTable[0][1], segTable[0][2], segTable[0][3], segTable[0][4], segTable[0][5], segTable[0][6]);
  }
}

void sevenSeg (int g, int f, int e, int d, int c, int b, int a)
{
  digitalWrite(A, a);
  digitalWrite(B, b);
  digitalWrite(C, c);
  digitalWrite(D, d);
  digitalWrite(E, e);
  digitalWrite(F, f);
  digitalWrite(G, g);
}

代码修改说明:

  • 删除了无意义的全局变量int a = 2
  • 调整串口读取逻辑,单次读取后存入变量再做比较,彻底解决重复读缓冲区的问题
  • 增加字符串trim()方法清除传输过程中混入的不可见字符
  • 用段码表统一管理数字对应的电平值,避免手写段码出错

Python端修改版

import pyrebase
import argparse
import datetime
import time
import serial

time_str = datetime.datetime.now().strftime("%Y%b%d_%I:%M:%S%p").upper()

ap = argparse.ArgumentParser()
ap.add_argument("-t", "--temp", help="Patient temperature at time of reading") 
ap.add_argument("-r", "--heart", help="Patient heart rate at the time of reading")
args = vars(ap.parse_args())

# 保持原Firebase配置不变
firebaseConfig = {
    "apiKey": "",
    "authDomain": "heartrate-firebase.firebaseapp.com",
    "databaseURL": "https://heartrate-firebase-default-rtdb.firebaseio.com/",
    "projectId": "heartrate-firebase",
    "storageBucket": "heartrate-firebase.appspot.com",
    "messagingSenderId": "851991577466",
    "appId": "1:851991577466:web:daaf323d9af64fd3318cc3",
}

firebase = pyrebase.initialize_app(firebaseConfig)
db = firebase.database()

# 保持原数据写入逻辑不变
if args.get("temp", None) is not None:
    data = {"Temperature": args.get("temp", None)}
    db.child("Temperature").child(time_str).set(data)

if args.get("heart", None) is not None:
    data = {"HeartRate": args.get("heart", None)}
    db.child("HeartRate").child(time_str).set(data)

# 拉取温度值逻辑,增加空值判断
latest_temp = None
userTemp = db.child("Temperature").get()
for x in userTemp.each():
    temp_val = db.child("Temperature").child(x.key()).child("Temperature").get().val()
    if temp_val is not None:
        latest_temp = str(temp_val)
        print("Temperature: " + latest_temp)

# 串口通信逻辑优化
with serial.Serial('COM4', 9600, timeout=5) as ser:
    time.sleep(2)
    # 清空串口残留缓冲区,避免历史数据干扰
    ser.reset_input_buffer()
    ser.reset_output_buffer()
    
    if latest_temp is not None:
        # 固定加换行符作为帧结束标记,和Arduino端的读取逻辑匹配
        send_data = (latest_temp + '\n').encode()
        ser.write(send_data)
        print(f"已发送数据到Arduino: {latest_temp}")
    
    time.sleep(1)
    y = ser.read(ser.inWaiting())
    print(f"Arduino返回数据: {y}")

代码修改说明:

  • 增加空值判断,避免数据库无数据时取到None导致串口写入报错
  • 打开串口后先重置输入输出缓冲区,清除历史残留数据
  • 明确打印实际发送的内容,方便和Arduino端的预期匹配值对齐

联调验证步骤

  • 第一步:脱离Firebase和Python脚本,打开电脑串口助手,波特率设为9600,手动发送内容37.0\n到Arduino,观察数码管是否切换到显示数字1,确认硬件和Arduino逻辑正常。
  • 第二步:单独运行Python脚本,临时把发送内容硬编码为37.0\n,观察Arduino反应,确认串口链路和Python发送逻辑正常。
  • 第三步:接入Firebase取数逻辑,确认取到的数值和Arduino端设置的EXPECTED_VALUE完全一致(无多余空格、无换行、数值格式匹配),即可触发显示1的逻辑。
  • 常见调试踩坑点:
    • 两边波特率必须完全一致,原代码两边都是9600是匹配的,不要随意改动
    • 串口发送的字符串如果是带小数的温度值,要和Arduino端存的预期值格式完全一致(比如Python发的是37.0,Arduino端就不要写37做匹配)
    • 不要在Arduino的loop循环里加长时间的delay(),会漏读串口缓冲区的数据

内容的提问来源于stack exchange,提问作者jaiv24

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.29 13:15:03