
wokwi.toml
bash
[wokwi]
version = 1
firmware = "cmake-build-debug-pico/pipo_project.uf2"
elf = "cmake-build-debug-pico/pipo_project.elf"
diagram.json
{
"version": 1,
"author": "Uri Shaked",
"editor": "wokwi",
"parts": [
{
"type": "wokwi-pi-pico",
"id": "pico",
"top": -137.55,
"left": 3.6,
"attrs": { "builder": "pico-sdk" }
},
{
"type": "wokwi-74hc595",
"id": "sr1",
"top": -10.94,
"left": 140.5,
"rotate": 270,
"attrs": {}
},
{
"type": "wokwi-led-bar-graph",
"id": "bargraph1",
"top": 72,
"left": 321.6,
"attrs": { "color": "lime" }
},
{ "type": "wokwi-gnd", "id": "gnd1", "top": 182.4, "left": 345, "attrs": {} },
{ "type": "wokwi-gnd", "id": "gnd2", "top": -38.4, "left": 297, "attrs": {} },
{ "type": "wokwi-vcc", "id": "vcc1", "top": 58.36, "left": 96, "attrs": {} }
],
"connections": [
[ "pico:GP0", "$serialMonitor:RX", "", [] ],
[ "pico:GP1", "$serialMonitor:TX", "", [] ],
[ "sr1:Q0", "bargraph1:A1", "green", [ "h-18", "v28.8", "h67.2", "v-86.4" ] ],
[ "sr1:Q1", "bargraph1:A2", "green", [ "h38.4", "v-57.6" ] ],
[ "sr1:Q2", "bargraph1:A3", "green", [ "h28.8", "v-38.4" ] ],
[ "sr1:Q3", "bargraph1:A4", "green", [ "h9.6", "v-19.2" ] ],
[ "sr1:Q4", "bargraph1:A5", "green", [ "h86.4", "v105.61" ] ],
[ "sr1:Q5", "bargraph1:A6", "green", [ "h9.6", "v-48", "h67.2", "v67.2" ] ],
[ "sr1:Q6", "bargraph1:A7", "green", [ "h57.6", "v48" ] ],
[ "sr1:Q7", "bargraph1:A8", "green", [ "h48", "v57.6" ] ],
[ "bargraph1:C1", "bargraph1:C2", "green", [ "v0" ] ],
[ "bargraph1:C3", "bargraph1:C4", "green", [ "h0" ] ],
[ "bargraph1:C5", "bargraph1:C6", "green", [ "h0" ] ],
[ "bargraph1:C7", "bargraph1:C8", "green", [ "h0" ] ],
[ "bargraph1:C9", "bargraph1:C10", "green", [ "h0" ] ],
[ "bargraph1:C8", "bargraph1:C9", "green", [ "h0" ] ],
[ "bargraph1:C2", "bargraph1:C3", "green", [ "h0" ] ],
[ "bargraph1:C4", "bargraph1:C5", "green", [ "h0" ] ],
[ "bargraph1:C6", "bargraph1:C7", "green", [ "h0" ] ],
[ "gnd1:GND", "bargraph1:C10", "black", [ "v0" ] ],
[ "pico:GP2", "sr1:DS", "green", [ "h-48", "v-76.8", "h172.8", "v9.6" ] ],
[ "sr1:SHCP", "pico:GP3", "green", [ "h-18", "v-182.4", "h-211.2", "v86.4", "h0", "v38.4" ] ],
[ "sr1:STCP", "pico:GP4", "green", [ "h-66", "v-153.6", "h-115.2", "v76.8" ] ],
[ "gnd2:GND", "sr1:GND", "black", [ "v-19.2", "h-86.4", "v28.8" ] ],
[ "vcc1:VCC", "sr1:VCC", "red", [ "v19.2", "h57.6", "v-9.6" ] ],
[ "sr1:MR", "vcc1:VCC", "green", [ "h-37.2", "v96" ] ]
],
"dependencies": {}
}
main.cpp IO 模拟
c
#include <stdio.h>
#include "pico/stdlib.h"
// 74HC595 接线 GPIO
#define DS_PIN 2 // 数据输入
#define SHCP_PIN 3 // 移位寄存器时钟
#define STCP_PIN 4 // 输出寄存器锁存
// 延时微秒
static inline void pulse_pin(uint pin) {
gpio_put(pin, 1);
sleep_us(1);
gpio_put(pin, 0);
}
// 初始化 GPIO
void hc595_init() {
gpio_init(DS_PIN);
gpio_set_dir(DS_PIN, true);
gpio_init(SHCP_PIN);
gpio_set_dir(SHCP_PIN, true);
gpio_init(STCP_PIN);
gpio_set_dir(STCP_PIN, true);
}
// 向 74HC595 发送一个字节
void hc595_write_byte(uint8_t data) {
for (int i = 7; i >= 0; i--) {
gpio_put(DS_PIN, (data >> i) & 1); // 发送最高位到最低位
pulse_pin(SHCP_PIN); // 上升沿移位
}
pulse_pin(STCP_PIN); // 更新输出寄存器
}
int main() {
stdio_init_all();
hc595_init();
printf("Pico 74HC595 demo start\n");
uint8_t pattern = 0x01;
while (1) {
hc595_write_byte(pattern++);
sleep_ms(1000);
}
return 0;
}
PIO
CMakeLists.txt
bash
cmake_minimum_required(VERSION 3.13)
# Set Pico SDK path
set(PICO_SDK_PATH "D:/Program Files/Raspberry Pi/Pico SDK v1.5.1/pico-sdk")
# Include the Pico SDK CMake configuration
include(pico_sdk_import.cmake)
project(pipo_project C CXX ASM)
pico_sdk_init()
add_executable(pipo_project
main.c
)
pico_generate_pio_header(pipo_project ${CMAKE_CURRENT_LIST_DIR}/hc595.pio)
target_link_libraries(
pipo_project
pico_stdlib
hardware_pio
)
# Enable USB output, disable UART output
pico_enable_stdio_usb(pipo_project 0)
pico_enable_stdio_uart(pipo_project 1)
pico_add_extra_outputs(pipo_project)
hc595.pio
bash
;
; HC595 PIO 程序
; 驱动 74HC595 移位寄存器
; DS -> 普通 OUT PIN
; SHCP -> side-set bit0
; STCP -> side-set bit1
;
; FIFO 写入字节,每次从 FIFO 拉取 8 bit
; 输出到 DS 并自动产生 SHCP 时钟脉冲
; 输出完成后产生一次 STCP 锁存脉冲
;
.program hc595
.side_set 2 opt ; bit0=SHCP, bit1=STCP
;=============================
; 主循环
;=============================
.wrap_target
pull block ; 从 FIFO 拉取一个字节
set y, 7 ; 位计数 7 -> 0
bitloop:
out pins, 1 ; 输出一位到 DS
nop side 0 ; SHCP=0, STCP=0
nop side 1 ; SHCP=1, STCP=0 (产生移位脉冲)
jmp y-- bitloop side 0 ; SHCP=0, STCP=0
; 发送完成,产生锁存脉冲
nop side 2 ; SHCP=0, STCP=1
nop side 0 ; SHCP=0, STCP=0
.wrap
;========================================================
% c-sdk {
//========================================================
// 初始化 HC595 PIO 状态机
// 参数:
// pio - PIO 控制器
// sm - 状态机编号
// offset - PIO 程序偏移地址
// ds_pin - DS 引脚
// shcp_pin - SHCP 引脚
// stcp_pin - STCP 引脚
//========================================================
static inline void hc595_program_init(PIO pio, uint sm, uint offset,
uint ds_pin, uint shcp_pin, uint stcp_pin) {
pio_sm_config c = hc595_program_get_default_config(offset);
// 设置输出引脚
sm_config_set_out_pins(&c, ds_pin, 1); // DS
sm_config_set_sideset_pins(&c, shcp_pin); // side-set 起始 pin = SHCP
sm_config_set_set_pins(&c, 0, 0); // 没有使用 SET 指令
// shift 配置 LSB first, autopull
sm_config_set_out_shift(&c, true, true, 8);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
// 初始化 GPIO
pio_gpio_init(pio, ds_pin);
pio_gpio_init(pio, shcp_pin);
pio_gpio_init(pio, stcp_pin);
// 所有引脚都设置为输出
pio_sm_set_consecutive_pindirs(pio, sm, ds_pin, 1, true);
pio_sm_set_consecutive_pindirs(pio, sm, shcp_pin, 2, true); // SHCP+STCP
// 初始化状态机
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
static inline void hc595_write(PIO pio, uint sm, uint8_t data) {
pio_sm_put_blocking(pio, sm, data);
}
%}
main.c
c
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "hc595.pio.h"
#define DS_PIN 2
#define SHCP_PIN 3
#define STCP_PIN 4
int main() {
stdio_init_all();
PIO pio = pio0;
uint sm = 0;
uint offset = pio_add_program(pio, &hc595_program);
hc595_program_init(pio, sm, offset, DS_PIN, SHCP_PIN, STCP_PIN);
uint8_t pattern = 0x0;
while (1) {
hc595_write(pio, sm, pattern++);
if (pattern == 0) pattern = 0x11;
sleep_ms(500);
}
}