第1章:Python基础回顾(一)——变量与数据类型、列表与字典、条件判断与循环、函数定义与调用
各位同学,欢迎来到《从零搭建水质监测数据采集系统》的第一课。
说实话,很多做硬件的朋友一听到「学Python」就头大。我当年也一样,觉得C语言才是嵌入式世界的通行证。但后来做物联网项目,发现Python在处理数据、快速验证、甚至直接控制硬件方面,效率高得惊人。今天我们就来快速过一遍Python的核心基础,重点放在——这些语法怎么跟硬件打交道。
1.1 变量与数据类型:传感器数据的第一站
变量,说白了就是给数据贴个标签。在嵌入式世界里,这个标签背后往往对应着某个寄存器的值,或者某个传感器的读数。
# 从温度传感器读到的原始值
temperature_raw = 0x1A3F # 十六进制,来自I2C总线
voltage = 3.3 # 浮点数,ADC参考电压
sensor_id = "DS18B20" # 字符串,传感器型号
is_connected = True # 布尔值,连接状态
这里有个坑,我踩过好几次。Python是动态类型语言,但硬件通信时数据格式必须明确。比如你从串口读到一串字节,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()
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) # 别跑太快,给硬件一点喘息时间
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)
1.5 避坑指南:硬件交互的Python陷阱
最后,分享几个我踩过的坑,你们提前避开:
- 浮点数精度问题——硬件传过来的数据往往是整数,Python计算时转成浮点数,比较时别用==,用abs(a-b) < 0.001。
- 全局变量滥用——我见过有人把所有传感器值都定义成全局变量,最后代码乱成一锅粥。用函数参数和返回值,或者用字典封装。
- 忘记关闭资源——打开串口、I2C总线后,程序退出前一定要关闭。不然下次运行会报错。
- 异常处理缺失——硬件随时可能掉线。用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基础其实不难,关键是带着「硬件思维」去理解。下一章我们讲字符串处理、文件操作和异常处理——这些都是跟硬件日志、配置文件打交道的必备技能。
记住:代码是写给硬件看的,也是写给未来的自己看的。写得清晰一点,调试的时候就少掉几根头发。