如何修改代码实现树莓派与Arduino同步的3分钟定频LED闪烁数据采集
代码修改方案与同步建议
树莓派Python代码修改(实现3分钟定时采集+同步指令发送)
以下代码实现3分钟定点数据采集,同时通过串口向Arduino发送LED频率与启停指令,确保两者同步:
import time import csv from ina219 import INA219 import serial # 硬件配置参数 SHUNT_OHMS = 0.1 # 按你的INA219分流电阻实际值调整 MAX_EXPECTED_AMPS = 3.2 COLLECTION_DURATION = 180 # 采集时长:3分钟=180秒 LED_FREQUENCY = 100 # 可选值:1/5/10/50/100Hz SERIAL_PORT = '/dev/ttyACM0' # Arduino串口号,可能是ttyUSB0 BAUD_RATE = 9600 # 初始化传感器与串口 ina = INA219(SHUNT_OHMS, MAX_EXPECTED_AMPS) ina.configure() ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) time.sleep(2) # 等待Arduino完成初始化 # 发送配置与启动指令 ser.write(f"FREQ:{LED_FREQUENCY}\n".encode()) time.sleep(0.1) ser.write(b"START\n") # 写入CSV数据 with open('sensor_data.csv', 'w', newline='') as csvfile: fieldnames = ['timestamp', 'shunt_voltage(mV)', 'bus_voltage(V)', 'current(mA)', 'power(mW)'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() start_time = time.time() while time.time() - start_time < COLLECTION_DURATION: # 采集传感器数据 shunt_v = ina.shunt_voltage() bus_v = ina.bus_voltage() current = ina.current() power = ina.power() # 写入CSV writer.writerow({ 'timestamp': time.strftime('%Y-%m-%d %H:%M:%S'), 'shunt_voltage(mV)': round(shunt_v, 4), 'bus_voltage(V)': round(bus_v, 4), 'current(mA)': round(current, 2), 'power(mW)': round(power, 2) }) # 控制采集频率(可根据需求调整,示例为每秒10次) time.sleep(0.1) # 发送停止指令,结束同步 ser.write(b"STOP\n") ser.close() print("采集完成,LED已停止闪烁")
核心要点
- 用
time.time()计算运行时长,确保严格执行3分钟采集 - 串口先发送频率参数,再发送启动信号,保证Arduino与采集同步开始
- 采集循环的
time.sleep(0.1)可按需调整数据采样密度 - 采集结束后发送停止信号,LED同步终止闪烁
Arduino代码修改(实现指定频率闪烁+同步启停)
采用非阻塞式逻辑实现精准频率闪烁,避免高频率下的延迟误差:
const int LED_PIN = 13; // LED连接引脚(需串联220Ω限流电阻) unsigned long previousMillis = 0; long interval = 500; // 默认闪烁周期(对应1Hz) bool ledState = LOW; bool isRunning = false; int targetFreq = 1; void setup() { pinMode(LED_PIN, OUTPUT); Serial.begin(9600); while (!Serial) {} // 等待USB串口连接(仅用于电脑调试) } void loop() { // 处理串口指令 if (Serial.available() > 0) { String cmd = Serial.readStringUntil('\n'); cmd.trim(); if (cmd.startsWith("FREQ:")) { targetFreq = cmd.substring(5).toInt(); // 计算闪烁周期:1次闪烁=亮+暗,所以单状态时长为(1000ms/频率)/2 interval = 500 / targetFreq; if (interval < 1) interval = 1; // 最小周期限制,避免溢出 } else if (cmd == "START") { isRunning = true; previousMillis = millis(); } else if (cmd == "STOP") { isRunning = false; digitalWrite(LED_PIN, LOW); // 停止后熄灭LED } } // 非阻塞式闪烁逻辑 if (isRunning) { unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; ledState = !ledState; digitalWrite(LED_PIN, ledState); } } }
核心要点
- 用
millis()替代delay(),避免高频率下的阻塞问题,保证闪烁次数精准 - 自动根据接收的频率计算闪烁周期,亮暗状态各占一半时长
- 严格响应树莓派的启停指令,实现完全同步
关键注意事项
- 树莓派与Arduino的串口波特率必须完全一致(示例为9600)
- 树莓派需赋予串口权限:执行
sudo usermod -a -G dialout pi后重启生效 - 高频率(50/100Hz)闪烁人眼无法察觉,可通过示波器验证闪烁次数
- 若需更高同步精度,可改用树莓派GPIO引脚发送硬件触发信号替代串口
内容的提问来源于stack exchange,提问作者ZSupreme
相关产品推荐
相关产品推荐

