第1章:Python基础回顾(一)——变量与数据类型、列表与字典、条件判断与循环、函数定义与调用

各位同学,欢迎来到《从零搭建水质监测数据采集系统》的第一课。

说实话,很多做硬件的朋友一听到「学Python」就头大。我当年也一样,觉得C语言才是嵌入式世界的通行证。但后来做物联网项目,发现Python在处理数据、快速验证、甚至直接控制硬件方面,效率高得惊人。今天我们就来快速过一遍Python的核心基础,重点放在——这些语法怎么跟硬件打交道。

1.1 变量与数据类型:传感器数据的第一站

变量,说白了就是给数据贴个标签。在嵌入式世界里,这个标签背后往往对应着某个寄存器的值,或者某个传感器的读数。

# 从温度传感器读到的原始值
temperature_raw = 0x1A3F  # 十六进制,来自I2C总线
voltage = 3.3             # 浮点数,ADC参考电压
sensor_id = "DS18B20"     # 字符串,传感器型号
is_connected = True       # 布尔值,连接状态

这里有个坑,我踩过好几次。Python是动态类型语言,但硬件通信时数据格式必须明确。比如你从串口读到一串字节,Python默认当成字符串处理,但实际它可能是二进制数据。

⚠️ 我曾经犯过的错: 从STM32发来的温度值是int16类型,Python直接当成字符串拼接,结果算出来的温度差了十万八千里。记住:从硬件来的数据,一定要先确认类型。

常用的数据类型,我列个表,大家对照着看:

类型 示例 硬件场景
int 1024 ADC原始读数、计数器
float 23.5 温度、pH值、电压
str "CH1" 传感器ID、AT指令
bytes b'\x01\x02' 串口/Modbus报文
bool True/False 继电器状态、报警标志

1.2 列表与字典:管理多路传感器数据

做水质监测,你不可能只接一个传感器。温度、pH、浊度、溶解氧……少说四五个。这时候列表和字典就派上用场了。

列表适合存同一类数据。比如连续采集的100个温度值:

temperature_log = []  # 空列表,准备存数据
for i in range(100):
    # 模拟从传感器读数据
    temp = 25.0 + (i * 0.1)
    temperature_log.append(temp)

print(f"最高温度:{max(temperature_log):.2f}°C")
print(f"最低温度:{min(temperature_log):.2f}°C")

字典更适合描述一个传感器的完整状态。我个人习惯用字典来打包一个传感器的所有信息:

sensor_node = {
    "id": "TEMP_01",
    "type": "DS18B20",
    "value": 23.8,
    "unit": "°C",
    "timestamp": 1695000000,
    "alarm": False
}

# 更新传感器读数
sensor_node["value"] = read_temperature()
sensor_node["timestamp"] = get_current_time()
💡 我的经验: 在嵌入式Python中,字典比列表好用得多。因为硬件数据往往带有很多属性(单位、时间戳、阈值),字典一目了然。我在做多参数水质监测仪时,就是用字典列表来管理所有传感器节点的。

1.3 条件判断与循环:控制采集逻辑

硬件编程里,条件判断和循环是灵魂。没有它们,你的设备就是个死循环的傻瓜机。

条件判断——说白了就是「如果……就……」。比如判断水温是否超标:

temperature = read_sensor("TEMP_01")

if temperature > 35.0:
    print("⚠️ 水温过高,开启散热风扇!")
    gpio_write(FAN_PIN, HIGH)
elif temperature < 5.0:
    print("⚠️ 水温过低,开启加热器!")
    gpio_write(HEATER_PIN, HIGH)
else:
    print("✅ 水温正常")
    gpio_write(FAN_PIN, LOW)
    gpio_write(HEATER_PIN, LOW)

循环——硬件里最常见的就是「一直读数据」。while True是嵌入式Python的标配:

# 主循环:每隔1秒采集一次数据
while True:
    temp = read_temperature()
    ph = read_ph()
    turbidity = read_turbidity()
    
    # 检查是否需要报警
    if temp > 40.0 or ph < 6.0 or ph > 9.0:
        trigger_alarm()
    
    # 上传到服务器
    upload_data(temp, ph, turbidity)
    
    time.sleep(1)  # 别跑太快,给硬件一点喘息时间
⚠️ 注意: while True里一定要加sleep!我见过有人忘了加,结果CPU占用100%,树莓派直接过热关机。硬件不是PC,要省着点用。

for循环在硬件里也常用,比如批量初始化传感器:

sensor_pins = [18, 23, 24, 25]  # GPIO引脚列表

for pin in sensor_pins:
    gpio_setup(pin, OUTPUT)
    gpio_write(pin, LOW)
    print(f"引脚 {pin} 初始化完成")

1.4 函数定义与调用:把硬件操作封装起来

函数,说白了就是把一段重复用的代码包起来,起个名字。在硬件编程里,函数就是你的「硬件驱动」。

我习惯把每个传感器的操作封装成一个函数。这样主程序看起来特别清爽:

def read_temperature(sensor_id):
    """读取DS18B20温度传感器"""
    # 这里模拟硬件通信
    raw_data = i2c_read(sensor_id, 0x00, 2)
    temp = (raw_data[0] << 8 | raw_data[1]) * 0.0625
    return temp

def read_ph(sensor_id):
    """读取pH传感器"""
    raw_data = i2c_read(sensor_id, 0x01, 2)
    ph = 7.0 + (raw_data[0] - 128) * 0.01
    return ph

def upload_data(temp, ph, turbidity):
    """上传数据到云平台"""
    payload = {
        "temperature": temp,
        "ph": ph,
        "turbidity": turbidity,
        "device_id": "WQ_001"
    }
    # 这里调用MQTT或HTTP上传
    mqtt_publish("sensor/data", payload)

主程序就变成了这样:

while True:
    t = read_temperature("TEMP_01")
    p = read_ph("PH_01")
    tu = read_turbidity("TURB_01")
    
    print(f"温度:{t:.1f}°C, pH:{p:.2f}, 浊度:{tu:.1f}NTU")
    
    upload_data(t, p, tu)
    time.sleep(5)
🎯 核心思想: 函数就是硬件的「说明书」。把复杂的I2C、SPI、UART通信细节藏在函数里,主程序只关心「读温度」「上传数据」这些业务逻辑。这样代码好维护,也好调试。

1.5 避坑指南:硬件交互的Python陷阱

最后,分享几个我踩过的坑,你们提前避开:

  1. 浮点数精度问题——硬件传过来的数据往往是整数,Python计算时转成浮点数,比较时别用==,用abs(a-b) < 0.001。
  2. 全局变量滥用——我见过有人把所有传感器值都定义成全局变量,最后代码乱成一锅粥。用函数参数和返回值,或者用字典封装。
  3. 忘记关闭资源——打开串口、I2C总线后,程序退出前一定要关闭。不然下次运行会报错。
  4. 异常处理缺失——硬件随时可能掉线。用try-except包住硬件操作,别让一个传感器故障导致整个系统崩溃。
def safe_read_temperature(sensor_id):
    """带异常处理的温度读取"""
    try:
        return read_temperature(sensor_id)
    except Exception as e:
        print(f"读取温度传感器 {sensor_id} 失败:{e}")
        return None  # 返回None,让上层逻辑处理

好了,这一章就到这里。Python基础其实不难,关键是带着「硬件思维」去理解。下一章我们讲字符串处理、文件操作和异常处理——这些都是跟硬件日志、配置文件打交道的必备技能。

记住:代码是写给硬件看的,也是写给未来的自己看的。写得清晰一点,调试的时候就少掉几根头发。