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
相关产品推荐
相关产品推荐

