• 正文
  • 相关推荐
申请入驻 产业图谱

树莓派CM0 扩展板设计全攻略:原理图 + 代码 + 驱动!

11小时前
163
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

大家好,我是无垠的广袤,今天分享的是树莓派 CM0 Dev Kit 单板计算机扩展板 PCB 设计,包括原理图、资源参数、环境搭建 、工程测试等。

项目介绍

扩展板设计:PCB、资源分布、参数特点、原理图等;

环境搭建:安装所需 python 库;

工程测试:驱动 DHT11ADC、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.temperature            hum = dht.humidity            draw.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_voltage    print(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_val            volt = (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_val            volt = (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退出,关闭LED    dac_out.value = 0    print("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.temperature        print(f"温度:{temp:.2f} ℃")        time.sleep(0.5)except KeyboardInterrupt:    print("程序退出")

保存代码。

效果

终端执行指令 python lm75_print.py 运行程序;

终端打印实时温度数据;


数码管

使用 GPIO 控制数码管显示 CPU 温度。

代码

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,  # 0    0b11111001,  # 1    0b10100100,  # 2    0b10110000,  # 3    0b10011001,  # 4    0b10010010,  # 5    0b10000010,  # 6    0b11111000,  # 7    0b10000000,  # 8    0b10010000,  # 9]# ==================== 595 移位发送 ====================def shift_out(byte):    for i in range(8):        bit = (byte >> (7 - i)) & 1        GPIO.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_dot        show(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:                # 两位数:显示整数,如 42                t_round = round(temp, 0)                current_left = int(t_round // 10)                current_right = int(t_round % 10)                current_dot = False            else:                # 个位数:显示一位小数,如 8.5                t_round = round(temp * 10) / 10                current_left = int(t_round)                current_right = int((t_round * 10) % 10)                current_dot = True        time.sleep(1)   # 每秒更新一次温度数值except KeyboardInterrupt:    print("n程序已停止")finally:    running = False    t.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_text    pulses = 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 = 180            run_angle(current_angle, speed_ms)            time.sleep(1)            current_angle = -180            run_angle(current_angle, speed_ms)            time.sleep(1)    except KeyboardInterrupt:        running = False        time.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/ )就是为解决这些痛点而生的树莓派中文一站式学习平台,界面清晰、内容系统、更新及时,堪称新手入门的“保姆级” 网站,让零基础用户也能轻松上手树莓派。

相关推荐