大家好,我是无垠的广袤,今天分享的是树莓派 CM0 Dev Kit 单板计算机扩展板 PCB 设计,包括原理图、资源参数、环境搭建 、工程测试等。
项目介绍
扩展板设计:PCB、资源分布、参数特点、原理图等;
环境搭建:安装所需 python 库;
工程测试:驱动 DHT11、ADC、AHT10、LM75、数码管、步进电机等。
扩展板
树莓派 Easy 扩展板
立创开源硬件平台地址:
https://oshwhub.com/jinleili/project_ibrftmtn
资源
DHT11 温湿度
4 路独立按键
4 颗单色 LED
6 颗 WS2812 彩色 LED
HX1838 红外接收
GL5528 光敏电阻
旋转电位器
接口
硬件 I2C 接口
0.96 寸 I2C OLED 接口
超声波模块接口
CH340E 芯片 USB 转 TTL 串口
预留数字拓展引脚
模拟拓展通道
原理图
环境搭建
创建并激活虚拟环境
python -m venv .venvsource .venv/bin/activate
终端执行如下指令,安装所需 python 库
pip install pillow # image processing librarypip install adafruit-circuitpython-ssd1306 # oled librarypip install adafruit-circuitpython-dht # dht11 driver librarypip install adafruit-circuitpython-pcf8591 # pcf8591 librarypip install adafruit-circuitpython-ahtx0 # aht10 librarypip install adafruit-circuitpython-pct2075 # lm75 library
DHT11
使用 adafruit_dht 库函数和单总线协议读取 DHT11 温湿度数据,并通过 adafruit_ssd1306 或 luma.oled 库函数实现 OLED 显示。
代码
import timeimport boardimport busioimport adafruit_dhtimport adafruit_ssd1306from PIL import Image, ImageDraw, ImageFont# 初始化DHT11 物理引脚7dht = adafruit_dht.DHT11(board.D4, use_pulseio=False)# 初始化I2C OLED 物理3/5i2c = busio.I2C(board.SCL, board.SDA)oled = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c)w, h = oled.width, oled.heightimg = Image.new("1", (w, h))draw = ImageDraw.Draw(img)# 加载字体try:# 系统矢量字体,支持缩放big_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 20)except:# 默认字体big_font = ImageFont.load_default()def screen_clear():draw.rectangle((0,0,w,h), fill=0)try:while True:screen_clear()try:temp = dht.temperaturehum = dht.humiditydraw.text((0, 0), f"Temp: {temp:.1f} C", font=big_font, fill=255)draw.text((0, 28), f"Humi: {hum} %RH", font=big_font, fill=255)except RuntimeError as e:draw.text((0, 0), "Read Error", font=big_font, fill=255)oled.image(img)oled.show()time.sleep(2)except KeyboardInterrupt:passfinally:dht.exit()oled.fill(0)oled.show()
保存代码。
效果
终端执行指令 python dht11_oled.py 运行程序;
板载 OLED 显示 DHT11 采集的环境温湿度数据;
ADC
使用 adafruit_pcf8591 库函数和 IIC 总线协议读取 A1 引脚(旋转电位器)输入的模拟电压,并通过串口 打印。
代码
import timeimport boardimport adafruit_pcf8591.pcf8591 as PCFfrom adafruit_pcf8591.analog_in import AnalogIn# 初始化I2C总线i2c = board.I2C()# 创建PCF8591实例,默认地址0x48pcf = PCF.PCF8591(i2c)# 绑定Ax输入通道adc = AnalogIn(pcf, PCF.A1)# 循环打印电压while True:# 原始归一化数值(0~65535)raw = adc.value# 换算实际电压volt = (raw / 65535) * adc.reference_voltageprint(f"A1通道电压:{volt:.2f} V,原始值:{raw}")time.sleep(1)
保存代码。
效果
终端执行指令 python pcf8591_print.py 运行程序;
旋转电位器旋钮,调整 ADC 输入电压;
终端打印 A1 采样电压值和原始值;
呼吸灯
结合 PCF8591 芯片控制 AOUT 模拟输出,实现 LED 渐变效果。
代码
import timeimport boardimport adafruit_pcf8591.pcf8591 as PCFfrom adafruit_pcf8591.analog_out import AnalogOut# I2C初始化i2c = board.I2C()pcf = PCF.PCF8591(i2c)dac_out = AnalogOut(pcf, PCF.OUT)# 阈值参数VOLT_THRESHOLD = 2.3 # LED点亮电压阈值V_REF = 3.3 # PCF8591基准电压DAC_THRESHOLD = round(VOLT_THRESHOLD / V_REF * 65535) # 45676DAC_MAX = 65535print(f"LED点亮DAC阈值:{DAC_THRESHOLD},对应电压{VOLT_THRESHOLD}V")try:while True:# 渐亮:从阈值升到最大for dac_val in range(DAC_THRESHOLD, DAC_MAX + 1, 256):dac_out.value = dac_valvolt = (dac_val / 65535) * V_REF#print(f"DAC:{dac_val:5d} 电压:{volt:.2f}V LED亮")time.sleep(0.02)# 渐暗:从最大降到阈值,低于阈值直接归零,LED熄灭for dac_val in range(DAC_MAX, DAC_THRESHOLD - 1, -256):dac_out.value = dac_valvolt = (dac_val / 65535) * V_REF#print(f"DAC:{dac_val:5d} 电压:{volt:.2f}V LED亮")time.sleep(0.02)# 完全熄灭阶段(保持0V,停顿0.5秒)dac_out.value = 0#print("DAC:0 电压:0.00V LED熄灭")time.sleep(0.5)except KeyboardInterrupt:# Ctrl+C退出,关闭LEDdac_out.value = 0print("n程序结束,DAC清零")
保存代码。
效果
终端执行指令 python aout_breath.py 运行程序;
板载 LED 呈现呼吸灯效果;
AHT10
使用杜邦线连接板载 IIC 排针接口和 AHT10 传感器模块,实现环境温湿度的串口打印。
代码
import timeimport boardimport adafruit_ahtx0# Create sensor object, communicating over the board's default I2C busi2c = board.I2C() # uses board.SCL and board.SDAsensor = adafruit_ahtx0.AHTx0(i2c)try:while True:print("nTemperature: %0.1f C" % sensor.temperature)print("Humidity: %0.1f %%" % sensor.relative_humidity)time.sleep(2)except KeyboardInterrupt:passfinally:print("Exiting....")
保存代码。
效果
终端执行指令 python aht_print.py 运行程序;
终端连续打印环境温湿度数据;
LM75
使用杜邦线连接板载 IIC 排针接口和 LM75 传感器模块,实现环境温度的串口打印。
LM75模块 - 立创开源硬件平台:
https://oshwhub.com/jinleili/project_icnlzyno
由于板载 PCF8591 默认地址 0x48,与 LM75 默认 IIC 地址相同,因此需短接 A1(或 A2) 与 VCC,对应地址为 0x4a (0x4c)。
代码
import timeimport boardimport adafruit_pct2075# 初始化 I2C 总线i2c = board.I2C()sensor = adafruit_pct2075.PCT2075(i2c, address=0x4c)try:while True:temp = sensor.temperatureprint(f"温度:{temp:.2f} ℃")time.sleep(0.5)except KeyboardInterrupt:print("程序退出")
保存代码。
效果
终端执行指令 python lm75_print.py 运行程序;
终端打印实时温度数据;
数码管
代码
import RPi.GPIO as GPIOimport timeimport threading# ==================== 74HC595 引脚定义 ====================# 使用 BCM 编号,可根据实际接线修改LATCH = 9 # RCLK (STCP)CLOCK = 10 # SRCLK (SHCP)DATA = 11 # DS (SER)GPIO.setmode(GPIO.BCM)GPIO.setwarnings(False)GPIO.setup(LATCH, GPIO.OUT)GPIO.setup(CLOCK, GPIO.OUT)GPIO.setup(DATA, GPIO.OUT)# ==================== 共阳数码管段码 ====================# 段码:dp g f e d c b aSMG_DUAN = [0b11000000, # 00b11111001, # 10b10100100, # 20b10110000, # 30b10011001, # 40b10010010, # 50b10000010, # 60b11111000, # 70b10000000, # 80b10010000, # 9]# ==================== 595 移位发送 ====================def shift_out(byte):for i in range(8):bit = (byte >> (7 - i)) & 1GPIO.output(DATA, bit)GPIO.output(CLOCK, GPIO.HIGH)GPIO.output(CLOCK, GPIO.LOW)# ==================== 显示函数 ====================def show(left, right, dot=False):seg_l = SMG_DUAN[left % 10]seg_r = SMG_DUAN[right % 10]if dot:seg_r &= 0b01111111 # 共阳:点亮小数点(dp 拉低)GPIO.output(LATCH, GPIO.LOW)shift_out(seg_r) # 先送右边(级联时后到高位)shift_out(seg_l)GPIO.output(LATCH, GPIO.HIGH)# ==================== 读取 CPU 温度 ====================def get_cpu_temp():try:with open('/sys/class/thermal/thermal_zone0/temp', 'r') as f:temp_str = f.read().strip()return int(temp_str) / 1000.0 # 转为摄氏度except Exception as e:print("读取温度失败:", e)return 0.0# ==================== 全局变量与锁 ====================current_left = 0current_right = 0current_dot = Falselock = threading.Lock()# ==================== 刷新线程(防止闪烁)====================def display_loop():"""独立线程持续刷新数码管,避免主循环 sleep 导致闪烁"""while running:with lock:l, r, d = current_left, current_right, current_dotshow(l, r, d)time.sleep(0.005) # 5ms 刷新一次,视觉无闪烁# ==================== 主程序 ====================running = Truetry:# 启动显示刷新线程t = threading.Thread(target=display_loop, daemon=True)t.start()while True:temp = get_cpu_temp()print("CPU 温度: {:.1f} °C".format(temp))with lock:if temp >= 10:# 两位数:显示整数,如 42t_round = round(temp, 0)current_left = int(t_round // 10)current_right = int(t_round % 10)current_dot = Falseelse:# 个位数:显示一位小数,如 8.5t_round = round(temp * 10) / 10current_left = int(t_round)current_right = int((t_round * 10) % 10)current_dot = Truetime.sleep(1) # 每秒更新一次温度数值except KeyboardInterrupt:print("n程序已停止")finally:running = Falset.join(timeout=0.5)GPIO.output(LATCH, GPIO.LOW)GPIO.cleanup()
保存代码。
效果
终端执行指令 python segment_cpu.py 运行程序;
数码管显示 CPU 温度值;
步进电机
树莓派 CM0 控制 GPIO 输出电平,结合 A4988 模块实现 42 步进电机驱动,并显示旋转状态,包括转速、角度和方向。
模块 PCB 设计详见:42步进电机A4988扩展板 - 立创开源硬件平台:
https://oshwhub.com/jinleili/arduinouno-expansion-board
代码
终端执行指令 touch stepmotor_oled.py 新建文件,并添加如下代码
import boardimport busioimport adafruit_ssd1306from PIL import Image, ImageDraw, ImageFontimport osimport timeimport datetimeimport threadingimport RPi.GPIO as GPIO# ---------------------- OLED 初始化 ----------------------# I2C 总线初始化,树莓派默认SDA=GPIO2(SDA), SCL=GPIO3(SCL)i2c = busio.I2C(board.SCL, board.SDA)# SSD1306 128*64 0x3C地址WIDTH = 128HEIGHT = 64oled = adafruit_ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c, addr=0x3C)# 清空屏幕缓存oled.fill(0)oled.show()# 创建绘图缓冲区image = Image.new("1", (WIDTH, HEIGHT))draw = ImageDraw.Draw(image)# 字体font_main = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 14)font_small = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 12)# ---------------------- 运行状态变量 ----------------------current_angle = 180speed_ms = 0.2direct_text = "CW"running = True# 独立屏幕刷新线程def screen_task():while running:now = datetime.datetime.now()date_str = now.strftime("%Y-%m-%d")time_str = now.strftime("%H:%M:%S")# 每次刷新前清空画布draw.rectangle((0, 0, WIDTH, HEIGHT), fill=0)# 左侧时间信息draw.text((0, 0), date_str, font=font_small, fill=1)draw.text((0, 11), time_str, font=font_main, fill=1)# 左侧电机运行状态info_dir = f"Dir: {direct_text}"info_speed = f"V: {speed_ms}ms"info_angle = f"Ang: {abs(current_angle)}deg"draw.text((2, 24), info_dir, font=font_small, fill=1)draw.text((2, 36), info_speed, font=font_small, fill=1)draw.text((2, 48), info_angle, font=font_small, fill=1)# 将PIL图像写入OLED并刷新oled.image(image)oled.show()time.sleep(0.1)# ---------------------- 电机驱动函数 ----------------------STEP = 9DIR = 10EN = 11PULSE_PER_360DEG = 1600 # 8 细分PULSE_PER_DEG = PULSE_PER_360DEG / 360GPIO.setmode(GPIO.BCM)GPIO.setup(STEP, GPIO.OUT)GPIO.setup(DIR, GPIO.OUT)GPIO.setup(EN, GPIO.OUT)GPIO.output(EN, GPIO.LOW)def run_angle(degree, speed):global direct_textpulses = int(abs(degree) * PULSE_PER_DEG)if degree > 0:GPIO.output(DIR, GPIO.HIGH)direct_text = "CW"else:GPIO.output(DIR, GPIO.LOW)direct_text = "CCW"delay_s = speed / 1000.0# 脉冲输出for _ in range(pulses):GPIO.output(STEP, GPIO.HIGH)time.sleep(delay_s)GPIO.output(STEP, GPIO.LOW)time.sleep(delay_s)if __name__ == "__main__":# 启动后台屏幕线程t = threading.Thread(target=screen_task, daemon=True)t.start()try:while True:current_angle = 180run_angle(current_angle, speed_ms)time.sleep(1)current_angle = -180run_angle(current_angle, speed_ms)time.sleep(1)except KeyboardInterrupt:running = Falsetime.sleep(0.2)# 清屏oled.fill(0)oled.show()# 电机释放GPIO.output(EN, GPIO.HIGH)GPIO.cleanup()print("程序退出,屏幕与电机已释放")
保存代码。
效果
终端执行指令 python a4988_run.py 运行程序;
OLED 显示日期、时间、步进电机状态,包括方向、速度、角度等;
步进电机正反交替旋转;
本文介绍了树莓派 CM0 Dev Board 单板计算机扩展板 PCB 设计,包括原理图、资源参数、环境搭建、工程测试等,为相关产品的快速开发和应用设计提供了参考。
如果你想查阅原文,可以点击文章尾部的【阅读全文】。
一起学习、讨论更多的树莓派知识?扫码加入树莓派交流群!
Tip:对于刚接触树莓派的新手来说,面对英文文档、零散教程和复杂配置,很容易无从下手。pidoc.cn( https://pidoc.cn/ )就是为解决这些痛点而生的树莓派中文一站式学习平台,界面清晰、内容系统、更新及时,堪称新手入门的“保姆级” 网站,让零基础用户也能轻松上手树莓派。
163