You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Raspberry Pi Pico W如何将PNG文件写入color565格式帧缓冲?

在Raspberry Pi Pico W上将PNG写入color565帧缓冲及UDP传输方案

一、本地PNG转color565并写入帧缓冲

Pico W资源有限,选择轻量工具链解决PNG解码和格式转换问题:

1. 引入轻量PNG解码库lodepng

lodepng是单文件实现的PNG解码库,无额外依赖,适合嵌入式场景:

  • 下载lodepng.h和lodepng.c,添加到你的Pico项目目录
  • 在CMakeLists.txt中添加编译规则:
target_sources(your_project_name PRIVATE
    main.c
    lodepng.c
)

2. 核心解码与转换代码

假设你已初始化好uint16_t frame_buffer[](尺寸SCREEN_WIDTH * SCREEN_HEIGHT),以下是关键实现:

#include "lodepng.h"
#include "pico/stdlib.h"

extern uint16_t frame_buffer[];
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240

// RGB888转color565
static uint16_t rgb_to_color565(uint8_t r, uint8_t g, uint8_t b) {
    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
}

// 解码PNG并写入帧缓冲
bool load_png_to_framebuffer(const char* png_path) {
    uint8_t* rgb_data;
    unsigned int width, height;
    // 解码PNG到RGB888数组
    unsigned int error = lodepng_decode24_file(&rgb_data, &width, &height, png_path);
    if (error) {
        printf("PNG解码失败: %s\n", lodepng_error_text(error));
        return false;
    }

    if (width != SCREEN_WIDTH || height != SCREEN_HEIGHT) {
        printf("图片尺寸与屏幕不匹配\n");
        free(rgb_data);
        return false;
    }

    // 逐像素转换并写入帧缓冲
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            int idx = y * width + x;
            uint8_t r = rgb_data[idx * 3];
            uint8_t g = rgb_data[idx * 3 + 1];
            uint8_t b = rgb_data[idx * 3 + 2];
            frame_buffer[idx] = rgb_to_color565(r, g, b);
        }
    }

    free(rgb_data);
    return true;
}

3. 调用示例

在主函数中集成:

int main() {
    stdio_init_all();
    init_display_and_framebuffer(); // 你的显示屏初始化函数

    if (load_png_to_framebuffer("/sd/image.png")) { // 假设PNG存在SD卡
        update_display(); // 更新显示屏显示帧缓冲内容
    }

    while (1) {
        sleep_ms(1000);
    }
}

二、UDP传输图片从RPI4到Pico W

推荐RPI4预转color565后传输,减少Pico端计算压力,以下是具体实现:

1. Pico W端UDP接收代码

#include "pico/cyw43_arch.h"
#include "lwip/udp.h"

#define UDP_PORT 12345
#define ROW_DATA_SIZE SCREEN_WIDTH * 2 // 每行color565数据(每个像素2字节)

static struct udp_pcb* udp_pcb;
static int current_row = 0;

// UDP接收回调
static void udp_receive_callback(void* arg, struct udp_pcb* pcb, struct pbuf* p, const ip_addr_t* addr, u16_t port) {
    if (!p) return;

    if (p->len == ROW_DATA_SIZE) {
        // 拷贝当前行数据到帧缓冲
        memcpy(&frame_buffer[current_row * SCREEN_WIDTH], p->payload, ROW_DATA_SIZE);
        current_row++;

        // 所有行接收完成后更新显示屏
        if (current_row >= SCREEN_HEIGHT) {
            update_display();
            current_row = 0;
        }
    }

    pbuf_free(p);
}

// 初始化UDP服务器
void init_udp_server() {
    udp_pcb = udp_new();
    if (!udp_pcb) {
        printf("UDP PCB创建失败\n");
        return;
    }

    err_t err = udp_bind(udp_pcb, IP_ADDR_ANY, UDP_PORT);
    if (err != ERR_OK) {
        printf("UDP绑定失败\n");
        udp_remove(udp_pcb);
        return;
    }

    udp_recv(udp_pcb, udp_receive_callback, NULL);
    printf("UDP服务器启动,端口%d\n", UDP_PORT);
}

主函数中集成WiFi和UDP初始化:

int main() {
    stdio_init_all();
    if (cyw43_arch_init()) {
        printf("WiFi初始化失败\n");
        return 1;
    }
    cyw43_arch_enable_sta_mode();
    if (cyw43_arch_wifi_connect_timeout_ms("你的WiFi名称", "WiFi密码", CYW43_AUTH_WPA2_AES_PSK, 30000)) {
        printf("WiFi连接失败\n");
        return 1;
    }

    init_display_and_framebuffer();
    init_udp_server();

    while (1) {
        cyw43_arch_poll();
        sleep_ms(10);
    }
}

2. RPI4端UDP发送代码(Python示例)

import socket
import numpy as np
from PIL import Image

SCREEN_WIDTH = 320
SCREEN_HEIGHT = 240
PICO_IP = "192.168.x.x" # 替换为Pico W的IP地址
UDP_PORT = 12345

# 加载图片并转换为color565
img = Image.open("待传输图片.png").resize((SCREEN_WIDTH, SCREEN_HEIGHT))
rgb_data = np.array(img.convert("RGB"))

# 转换为小端字节序的color565数据
color565_bytes = bytearray()
for r, g, b in rgb_data.reshape(-1, 3):
    r5 = (r >> 3) & 0x1F
    g6 = (g >> 2) & 0x3F
    b5 = (b >> 3) & 0x1F
    color565 = (r5 << 11) | (g6 << 5) | b5
    color565_bytes.extend(color565.to_bytes(2, byteorder='little'))

# 分块发送每行数据
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for y in range(SCREEN_HEIGHT):
    start = y * SCREEN_WIDTH * 2
    end = start + SCREEN_WIDTH * 2
    sock.sendto(color565_bytes[start:end], (PICO_IP, UDP_PORT))
sock.close()

注意事项

  • 内存限制:Pico W仅264KB RAM,处理大尺寸图片时建议分块加载,避免内存溢出
  • 传输可靠性:UDP无连接,可在传输时加入简单校验(如每行加序号),防止数据乱序或丢失
  • 文件系统:若Pico W本地PNG存储在SD卡,需先初始化SD卡驱动(使用pico-sdk的sd_card库)

内容的提问来源于stack exchange,提问作者Buldes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 10:27:49