ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

随手记录 利用全志T153,点亮OLED屏幕,显示当地天气

2026/8/27 10:47:55 拓冰建站 浏览量
随手记录 利用全志T153,点亮OLED屏幕,显示当地天气 学习了正点原子的imx6ull 好几遍有了思路框架后想试试自己不靠教程点亮个屏幕试试手上有两块创龙的开发板先玩玩T153吧。我用的是docker 容器当开发环境在Windows上远程开发。需要先执行提供的脚本安装好LinuxSDK 开发包依赖软件感觉就算安装好编译sdk也不会一帆风顺的1、Linux SDK安装环境路径不同仅供参考先将Linux SDK放到环境中我是放到如下路径之后解压到如下目录当工作区从提供的资料包中将如下文件解压放到工作区指定目录中需提前建立好-C后面的文件夹2、Linux SDK 配置与编译2.1 配置编译选项后面的选项参考3.1手册编译遇到个问题原因找到了应该解压到aiot*****的buildroot文件夹里不是并列关系。执行如下命令挺喜欢看编译榨干性能的~执行如下命令编译中需要连接GitHub编译结束2.2 编译配置设备树设备树位于device/config/chips/t153/configs/tlt15 3-minievm-xxxx/linux-5.10-xx/下提供了三种文件按需选择这里我选第一个参考文件夹内容及分级关系2.3 内核配置 打开SSD1306先补充好menuconfig的环境sudo apt-get install libncurses5-dev libncursesw5-dev打开menuconfig./build.sh menuconfig找到SSD1306在哪这里先打开SSD1307打开之后保存退出找到这个SSD1307的readme文件同时看看驱动怎么写的是否支持SSD1306先参考图中目录打开说明文件由说明文档可知这个驱动支持三款chips所以不找驱动文件读了直接支持SSD1306同时参考末尾的example直接参考写入设备树中即可打开前面提到的设备树位置在原理图里考虑复用什么引脚同时结合dts这里我选择如下引脚3V3使用1 GND使用13下面修改设备树将上图与前面第三张图结合补充一下注释系统正常工作时使用这一组PD22、PD23复用为 twi4。在这个节点下添加ssd1306的节点可以参考前面的example和文档说明3、编译内核设备树烧录进开发板先编译内核./build.sh kernel从上图可以得知ssd1307被编译进了内核。接下来编译./build.sh./build.sh pack第二条指令遇到如下问题先找路径再添加到环境变量打包结果如下所示试试烧录情况关于安装USB驱动我这是报错的参考内容https://bbs.aw-ol.com/topic/6262/%E8%A7%A3%E5%86%B3win11%E4%B8%8B-%E5%85%A8%E5%BF%97usb%E9%A9%B1%E5%8A%A8%E6%84%9F%E5%8F%B9%E5%8F%B7%E9%97%AE%E9%A2%98%E5%8A%9E%E6%B3%95/12安装之后只烧录内核按照内容烧写。可见OLED屏幕驱动和设备树已经正确安装适配。4、适配USB网卡这里参考一下原子相关章节 这里用的是正点原子提供的USB网卡4.1屏蔽原来的驱动 放弃此方法文档说旧版本的内核驱动有问题但是当前新版本是否有问题我没研究直接参考原子的驱动文档替换了。直接删掉Realtek文件夹4.2 将 rtl81xx 驱动添加到 Linux 内核中 放弃此方法将 realtek 整个目录返回上一级文件夹拷贝拷贝到 ubuntu 下 Linux 内核源码中的 drivers/net/wireless 目录下此目录下存放着所有 WIFI 驱动文件。4.3 配置menuconfig试了一圈貌似通过内核里的驱动不能实现USB网卡。下面另辟蹊径首先根据资料 配置好交叉编译环境同时去网上下载好驱动链接 注意区别型号原子的网卡好像有两种可以先看Windows上写的是什么型号再找驱动这里仅提供一种https://github.com/lwfinger/rtl8188eu下面给出我的方法懒得溯源了直接让豆包生成的笔记!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleT153 交叉编译 rtl8188eu(8188eu.ko) 完整流程笔记/title style * {box-sizing: border-box;} body {font-family: Microsoft YaHei, Consolas, monospace; max-width:1100px; margin:20px auto; padding:0 16px; background:#f7f9fc; color:#222;} h1 {color:#1f2937; font-size:22px;} h2 {font-size:18px; color:#2563eb; margin-top:28px; border-left:4px solid #2563eb; padding-left:10px;} h3 {font-size:16px; color:#374151; margin-top:20px;} pre {background:#1e293b; color:#e2e8f0; padding:14px; border-radius:6px; overflow-x:auto; font-size:13px;} code {background:#e5e7eb; padding:2px 6px; border-radius:3px; font-family:Consolas;} .warn {background:#fffbeb; border:1px solid #fbbf24; padding:12px; border-radius:6px; margin:10px 0;} .success {background:#ecfdf5; border:1px solid #34d399; padding:12px; border-radius:6px; margin:10px 0;} .step {margin:12px 0;} /style /head body h1T153 全志平台rtl8188eu WiFi驱动交叉编译完整笔记/h1 div classwarn strong环境说明/strongDocker容器SDK: aiot‑t153‑linux‑v1.0内核 Linux‑5.10工具链 gcc‑linaro‑11.3.1‑2022.06‑x86_64_arm‑linux‑gnueabihfbr 驱动仓库rtl8188eu 第三方开源驱动编译输出模块名称strong8188eu.ko/strong不是rtl8188eu.ko /div h2一、核心概念 KSRC 要求/h2 ul liKSRC 指向strong内核编译输出工作目录/strong不是原始只读内核源码目录 linux‑5.10‑origin/li li本SDK正确KSRC路径code/share/TL_T153/T153/aiot-t153-linux-v1.0/out/t153/kernel/build/code/li liKSRC目录必须具备.config、scripts/basic/fixdep、include/generated/*/li li内核配置必须开启codeCONFIG_WIRELESS_EXTy/code/li liout目录执行SDK clean会全部清空clean后需要重新准备编译环境/li /ul h2二、前期检查步骤/h2 h31.确认KSRC目录产物是否齐全/h3 precd /share/TL_T153/T153/aiot-t153-linux-v1.0/out/t153/kernel/build ls -la .config ls scripts/basic/fixdep ls include/generated/ grep CONFIG_WIRELESS_EXT .config /pre div classsuccess预期输出CONFIG_WIRELESS_EXTy所有文件存在代表内核kbuild环境就绪。/div h32.配置交叉编译器PATH/h3 preexport PATH/share/TL_T153/T153/gcc-linaro-11.3.1-2022.06-x86_64_arm-linux-gnueabihf/bin:$PATH #校验 which arm-linux-gnueabihf-gcc arm-linux-gnueabihf-gcc --version /pre div classwarnexport PATH 仅当前docker shell会话生效关闭终端失效。/div h2三、执行交叉编译驱动/h2 precd /share/TL_T153/T153/rtl8188eu make \ KSRC/share/TL_T153/T153/aiot-t153-linux-v1.0/out/t153/kernel/build \ ARCHarm \ CROSS_COMPILEarm-linux-gnueabihf- /pre div classsuccess编译成功产物当前目录生成 strong8188eu.ko/strong/div h2四、板子端部署与配置/h2 h31.拷贝模块到板子加载/h3 pre# 加载驱动 insmod 8188eu.ko # 或者 modprobe 8188eu #查看模块 lsmod | grep 8188eu /pre h32.固件必做否则设备未就绪/h3 p固件文件rtl8188eufw.bin放到板子路径/p pre/lib/firmware/rtlwifi/rtl8188eufw.bin/pre pdmesg出现 firmware not found 代表固件缺失。/p h33.NetworkManager 搜不到SSID问题修复/h3 p创建文件 code/etc/NetworkManager/conf.d/80-wifi.conf/code/p pre[device] wifi.scan-rand-mac-addressno /pre presystemctl restart NetworkManager/pre h2五、调试命令板子上执行/h2 pre# 查看驱动打印日志 dmesg | grep -E 8188eu|rtl8188 # 查看网卡设备 ip link show # 查看已加载模块 lsmod | grep 8188eu /pre h2六、常见报错汇总/h2 div classstep strong1. arm‑linux‑gnueabihf‑gcc: command not found/strong p原因PATH没有加入交叉编译器bin目录解决export PATH指向linaro工具链bin。/p /div div classstep strong2. version magic mismatch/strong p原因.config/工具链版本和板子运行内核不一致必须使用out/t153/kernel/build作为KSRC。/p /div div classstep strong3. scripts/basic/fixdep: No such file or directory/strong p原因没有执行modules_prepare在out/t153/kernel/build执行 make ARCHarm CROSS_COMPILExxx‑ modules_prepare/p /div div classstep strong4. dmesg firmware rtl8188eufw.bin not found/strong p解决拷贝固件到 /lib/firmware/rtlwifi//p /div div classstep strong5. NetworkManager 设备未就绪 / 扫描不到WiFi/strong p解决部署固件 关闭wifi.scan‑rand‑mac‑address/p /div h2七、后续优化建议/h2 ul liBuildroot工程将rtl8188eu制作为外部模块.mk自动编译打包ko进rootfs开机自动加载。/li liSDK执行make clean后out/t153/kernel/build会被删除需要重新modules_prepare再编译ko。/li /ul /body /html之后我是通过sd卡转移.ko文件的终于显示网卡了还好默认根文件系统自带了 wpa_supplicant后面进行连接顺序如下#写wifi配置替换成你的wifi名称、密码 cat /tmp/wpa.conf EOF network{ ssid你的WIFI名字 psk你的WIFI密码 } EOF # 后台启动-D wext 指定老式无线扩展接口 wpa_supplicant -B -D wext -i wlan0 -c /tmp/wpa.conf # 请求DHCP获取ip udhcpc -i wlan0 # 查看wlan0是否拿到ip ifconfig wlan0我的情况如下成功 完美5、使用OLED屏幕联网显示一些内容这里显示当地天气5 .1 /dev/fb1 怎么使用开发板支持scp可以直接通过网络传编译后的文件fbdev详解参考https://geek-blogs.com/blog/linux-fbdev/先改一下设备树编译烧录用之前的不能显存和屏幕位置对应。先把全屏幕点亮#include stdio.h #include stdlib.h #include fcntl.h #include sys/mman.h #include linux/fb.h #include unistd.h #include stdint.h #include sys/ioctl.h int main() { int fd; struct fb_var_screeninfo var; struct fb_fix_screeninfo fix; char *fbp; long screensize; // 1. 打开设备文件 fd open(/dev/fb1, O_RDWR); if (fd 0) { perror(open /dev/fb0 failed); return 1; } // 2. 获取屏幕参数 if (ioctl(fd, FBIOGET_VSCREENINFO, var) 0) { perror(FBIOGET_VSCREENINFO failed); close(fd); return 1; } if (ioctl(fd, FBIOGET_FSCREENINFO, fix) 0) { perror(FBIOGET_FSCREENINFO failed); close(fd); return 1; } printf(屏幕信息分辨率 %dx%d像素格式 %d BPP行字节数 %d\n, var.xres, var.yres, var.bits_per_pixel, fix.line_length); // 3. 映射帧缓冲内存 screensize fix.smem_len; fbp mmap(NULL, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (fbp MAP_FAILED) { perror(mmap failed); close(fd); return 1; } uint8_t *fbp_8 (uint8_t *)fbp; int line_pixels fix.line_length; for (int y 0; y var.yres; y) { for (int x 0; x var.xres; x) { int idx y * line_pixels x; fbp_8[idx] 0xff; // 黑色 } } // fbp_8[0] 0x00; return 0; }再试试关闭开头的8个像素点#include stdio.h #include stdlib.h #include fcntl.h #include sys/mman.h #include linux/fb.h #include unistd.h #include stdint.h #include sys/ioctl.h int main() { int fd; struct fb_var_screeninfo var; struct fb_fix_screeninfo fix; char *fbp; long screensize; // 1. 打开设备文件 fd open(/dev/fb1, O_RDWR); if (fd 0) { perror(open /dev/fb0 failed); return 1; } // 2. 获取屏幕参数 if (ioctl(fd, FBIOGET_VSCREENINFO, var) 0) { perror(FBIOGET_VSCREENINFO failed); close(fd); return 1; } if (ioctl(fd, FBIOGET_FSCREENINFO, fix) 0) { perror(FBIOGET_FSCREENINFO failed); close(fd); return 1; } printf(屏幕信息分辨率 %dx%d像素格式 %d BPP行字节数 %d\n, var.xres, var.yres, var.bits_per_pixel, fix.line_length); // 3. 映射帧缓冲内存 screensize fix.smem_len; fbp mmap(NULL, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (fbp MAP_FAILED) { perror(mmap failed); close(fd); return 1; } uint8_t *fbp_8 (uint8_t *)fbp; int line_pixels fix.line_length; // for (int y 0; y var.yres; y) { // for (int x 0; x var.xres; x) { // int idx y * line_pixels x; // fbp_8[idx] 0xff; // 黑色 // } // } fbp_8[0] 0x00; return 0; }如图成功现在操作什么位置的bit就相当于控制什么位置的像素点了。参考stm32 OLED驱动完成一下APIoled.c 注意 oledfont.h要用引号#include stdio.h #include stdlib.h #include unistd.h #include fcntl.h #include sys/mman.h #include sys/stat.h #include sys/types.h #include linux/fb.h #include sys/ioctl.h #include stdint.h #include oledfont.h static int fb_fd -1; static uint8_t *fbp NULL; void oled_draw_point(uint8_t x, uint8_t y, uint8_t dot) { if (x 128 || y 64) return; uint8_t x_idx x / 8; uint8_t bit_x x % 8; uint8_t mask 1U bit_x; uint8_t *p (uint8_t *)fbp y * 16U x_idx; if(dot) *p | mask; else *p ~mask; } // 填充整个屏幕为黑色背景 void oled_clear_screen(void) { for(int y0; y64; y) { for(int x0; x128; x) { oled_draw_point(x, y, 0); } } } int fb_open(void) { fb_fd open(/dev/fb1, O_RDWR); if (fb_fd 0) { perror(open /dev/fb1); return -1; } struct fb_var_screeninfo vinfo; ioctl(fb_fd, FBIOGET_VSCREENINFO, vinfo); size_t fb_size (size_t)vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8U; fbp mmap(NULL, fb_size, PROT_READ|PROT_WRITE, MAP_SHARED, fb_fd, 0); if(fbp MAP_FAILED){ perror(mmap fb1); close(fb_fd); return -1; } printf(fb1 ok: w%d h%d bpp%d\n,vinfo.xres,vinfo.yres,vinfo.bits_per_pixel); return 0; } void fb_close(void) { if(fbp){ struct fb_var_screeninfo vinfo; ioctl(fb_fd, FBIOGET_VSCREENINFO, vinfo); size_t sz(size_t)vinfo.xres*vinfo.yres*vinfo.bits_per_pixel/8U; munmap(fbp, sz); } if(fb_fd 0) close(fb_fd); fbp NULL; fb_fd -1; } void oled_show_char(uint8_t x, uint8_t y, uint8_t chr, uint8_t size, uint8_t mode) { uint8_t temp, t, t1; uint8_t y0 y; uint8_t *pfont 0; uint8_t csize (size / 8 ((size % 8) ? 1 : 0)) * (size / 2); /* 得到字体一个字符对应点阵集所占的字节数 */ chr chr - ; /* 得到偏移后的值,因为字库是从空格开始存储的,第一个字符是空格 */ if (size 12) /* 调用1206字体 */ { pfont (uint8_t *)oled_asc2_1206[chr]; } else if (size 16) /* 调用1608字体 */ { pfont (uint8_t *)oled_asc2_1608[chr]; } else if (size 24) /* 调用2412字体 */ { pfont (uint8_t *)oled_asc2_2412[chr]; } else /* 没有的字库 */ { return; } for (t 0; t csize; t) { temp pfont[t]; for (t1 0; t1 8; t1) { if (temp 0x80)oled_draw_point(x, y, mode); else oled_draw_point(x, y, !mode); temp 1; y; if ((y - y0) size) { y y0; x; break; } } } } /** * brief 平方函数, m^n * param m: 底数 * param n: 指数 * retval 无 */ static uint32_t oled_pow(uint8_t m, uint8_t n) { uint32_t result 1; while (n--) { result * m; } return result; } /** * brief 显示len个数字 * param x,y : 起始坐标 * param num : 数值(0 ~ 2^32) * param len : 显示数字的位数 * param size: 选择字体 12/16/24 * retval 无 */ void oled_show_num(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size) { uint8_t t, temp; uint8_t enshow 0; for (t 0; t len; t) /* 按总显示位数循环 */ { temp (num / oled_pow(10, len - t - 1)) % 10; /* 获取对应位的数字 */ if (enshow 0 t (len - 1)) /* 没有使能显示,且还有位要显示 */ { if (temp 0) { oled_show_char(x (size / 2)*t, y, , size, 1); /* 显示空格,站位 */ continue; /* 继续下个一位 */ } else { enshow 1; /* 使能显示 */ } } oled_show_char(x (size / 2)*t, y, temp 0, size, 1); /* 显示字符 */ } } /** * brief 显示字符串 * param x,y : 起始坐标 * param size: 选择字体 12/16/24 * param *p : 字符串指针,指向字符串首地址 * retval 无 */ void oled_show_string(uint8_t x, uint8_t y, const char *p, uint8_t size) { while ((*p ~) (*p )) /* 判断是不是非法字符! */ { if (x (128 - (size / 2))) /* 宽度越界 */ { x 0; y size; /* 换行 */ } if (y (64 - size)) /* 高度越界 */ { y x 0; oled_clear_screen(); } oled_show_char(x, y, *p, size, 1); /* 显示一个字符 */ x size / 2; /* ASCII字符宽度为汉字宽度的一半 */ p; } } int main(void) { if(fb_open() 0) return -1; oled_clear_screen(); // oled_show_char(1,1,a,16,1); oled_show_string(1,1,hello world,16); fb_close(); return 0; }oledfont.h 参考原子例程实现效果5.2 联网获取天气用的是腾讯地图 API需要Buildroot支持crul可以在buildroot的menuconfig打开交叉编译遇到这个问题root535b56740ee3:/share/TL_T153/T153/app/01_OLED# arm-linux-gnueabihf-gcc test.c -o test -lcurl test.c:1:10: fatal error: curl/curl.h: No such file or directory 1 | #include curl/curl.h | ^~~~~~~~~~~~~ compilation terminated.解决方案查找头文件目录和查找库文件目录root535b56740ee3:/share/TL_T153/T153/aiot-t153-linux-v1.0# find . -name curl.h ./out/t153/tlt153-minievm-nand/buildroot/buildroot/build/buildroot-config/br2/package/libcurl/curl.h ./out/t153/tlt153-minievm-nand/buildroot/buildroot/build/buildroot-config/swupdate/config/curl.h ./out/t153/tlt153-minievm-nand/buildroot/buildroot/build/buildroot-config/swupdate/config/channel/curl.h ./out/t153/tlt153-minievm-nand/buildroot/buildroot/build/swupdate-2019.11/include/config/curl.h ./out/t153/tlt153-minievm-nand/buildroot/buildroot/build/swupdate-2019.11/include/config/channel/curl.h ./out/t153/tlt153-minievm-nand/buildroot/buildroot/build/libcurl-7.83.1/include/curl/curl.h ./out/t153/tlt153-minievm-nand/buildroot/buildroot/build/host-cmake-3.18.6/Utilities/cmcurl/include/curl/curl.h ./out/t153/tlt153-minievm-nand/buildroot/buildroot/build/host-cmake-3.18.6/Utilities/cm3p/curl/curl.h ./out/t153/tlt153-minievm-nand/buildroot/buildroot/host/arm-buildroot-linux-gnueabihf/sysroot/usr/include/curl/curl.h root535b56740ee3:/share/TL_T153/T153/aiot-t153-linux-v1.0# find . -name jansson.h ./out/t153/tlt153-minievm-nand/buildroot/buildroot/build/jansson-2.14/src/jansson.h ./out/t153/tlt153-minievm-nand/buildroot/buildroot/build/buildroot-config/br2/package/jansson.h ./out/t153/tlt153-minievm-nand/buildroot/buildroot/host/arm-buildroot-linux-gnueabihf/sysroot/usr/include/jansson.hroot535b56740ee3:/share/TL_T153/T153/aiot-t153-linux-v1.0# find . -name libcurl.so* find . -name libjansson.so* ./out/t153/tlt153-minievm-nand/buildroot/buildroot/target/usr/lib/libcurl.so.4 ./out/t153/tlt153-minievm-nand/buildroot/buildroot/target/usr/lib/libcurl.so.4.8.0 ./out/t153/tlt153-minievm-nand/buildroot/buildroot/target/usr/lib/libcurl.so ./out/t153/tlt153-minievm-nand/buildroot/buildroot/build/libcurl-7.83.1/lib/.libs/libcurl.so.4 ./out/t153/tlt153-minievm-nand/buildroot/buildroot/build/libcurl-7.83.1/lib/.libs/libcurl.so.4.8.0 ./out/t153/tlt153-minievm-nand/buildroot/buildroot/build/libcurl-7.83.1/lib/.libs/libcurl.so ./out/t153/tlt153-minievm-nand/buildroot/buildroot/host/arm-buildroot-linux-gnueabihf/sysroot/usr/lib/libcurl.so.4 ./out/t153/tlt153-minievm-nand/buildroot/buildroot/host/arm-buildroot-linux-gnueabihf/sysroot/usr/lib/libcurl.so.4.8.0 ./out/t153/tlt153-minievm-nand/buildroot/buildroot/host/arm-buildroot-linux-gnueabihf/sysroot/usr/lib/libcurl.so ./out/t153/tlt153-minievm-nand/buildroot/buildroot/target/usr/lib/libjansson.so ./out/t153/tlt153-minievm-nand/buildroot/buildroot/target/usr/lib/libjansson.so.4.14.0 ./out/t153/tlt153-minievm-nand/buildroot/buildroot/target/usr/lib/libjansson.so.4 ./out/t153/tlt153-minievm-nand/buildroot/buildroot/build/jansson-2.14/src/.libs/libjansson.so ./out/t153/tlt153-minievm-nand/buildroot/buildroot/build/jansson-2.14/src/.libs/libjansson.so.4.14.0 ./out/t153/tlt153-minievm-nand/buildroot/buildroot/build/jansson-2.14/src/.libs/libjansson.so.4 ./out/t153/tlt153-minievm-nand/buildroot/buildroot/host/arm-buildroot-linux-gnueabihf/sysroot/usr/lib/libjansson.so ./out/t153/tlt153-minievm-nand/buildroot/buildroot/host/arm-buildroot-linux-gnueabihf/sysroot/usr/lib/libjansson.so.4.14.0 ./out/t153/tlt153-minievm-nand/buildroot/buildroot/host/arm-buildroot-linux-gnueabihf/sysroot/usr/lib/libjansson.so.4解析一下这个命令/share/TL_T153/T153/app/01_OLED# arm-linux-gnueabihf-gcc test.c -o test \ --sysroot/share/TL_T153/T153/aiot-t153-linux-v1.0/out/t153/tlt153-minievm-nand/buildroot/buildroot/host/arm-buildroot-linux-gnueabihf/sysroot \ -lcurl -ljansson解释下关键参数--sysroot/xxx/host/arm-buildroot-linux-gnueabihf/sysroot编译的时候头文件$sysroot/usr/include/库文件$sysroot/usr/lib/并不是你 docker 主机的根/是交叉编译虚拟的目标设备根目录。 这个 sysroot 目录只有 buildroot 完整编译 SDK 之后才会生成单独编译某个包仅 make jansson‑rebuild不会完整生成这套 sysroot。sysroot 来自哪里host/arm-buildroot-linux-gnueabihf/sysroot是 buildroot 产出的工具链配套 sysroot✅只有 buildroot 执行完整顶层make之后才会生成完整这套 sysroot。区分两个 sysroot 概念buildroot host 下面的 sysroot编译侧out/.../host/arm-buildroot-linux-gnueabihf/sysroot给交叉编译用存放头文件、.so、.pc编译阶段使用不会烧写到板子。target 目录目标板子根文件系统out/.../target/这就是板子上跑的根文件系统内容你拷贝到开发板的libjansson.so*就是从这里拿。接着写代码先加入了 #include curl/curl.h但是编译执行后报错这里需要把编译后的一些链接库放到开发板上通过scprootT153-Tronlong:~# ./oled ./oled: error while loading shared libraries: libjansson.so.4: cannot open shared object file: No such file or directory我这里提供参考root535b56740ee3:/share/TL_T153/T153/aiot-t153-linux-v1.0# # SDK主机执行 scp ./out/t153/tlt153-minievm-nand/buildroot/buildroot/target/usr/lib/libjansson.so* 192.168.31.116:/usr/lib libjansson.so 100% 41KB 4.7MB/s 00:00 libjansson.so.4 100% 41KB 5.1MB/s 00:00 libjansson.so.4.14.0 100% 41KB 1.2MB/s 00:00之后编写应用层代码#include stdio.h #include stdlib.h #include unistd.h #include fcntl.h #include sys/mman.h #include sys/stat.h #include sys/types.h #include linux/fb.h #include sys/ioctl.h #include stdint.h #include string.h #include oledfont.h #include curl/curl.h #include jansson.h static int fb_fd -1; static uint8_t *fbp NULL; typedef struct { char *buf; size_t len; } ResponseData; size_t curl_write_cb(void *ptr, size_t size, size_t nmemb, void *userdata) { ResponseData *resp (ResponseData *)userdata; size_t add_sz size * nmemb; char *new_buf realloc(resp-buf, resp-len add_sz 1); if (!new_buf) return 0; resp-buf new_buf; memcpy(resp-buf resp-len, ptr, add_sz); resp-len add_sz; resp-buf[resp-len] \0; return add_sz; } int get_weather_json(char **out_json) { CURL *curl; CURLcode res; ResponseData resp {NULL, 0}; *out_json NULL; curl_global_init(CURL_GLOBAL_ALL); curl curl_easy_init(); if (!curl) { printf(curl_easy_init fail\n); curl_global_cleanup(); return -1; } const char *url https://apis.map.qq.com/ws/weather/v1/?keykeyadcode340504typenow; curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_cb); curl_easy_setopt(curl, CURLOPT_WRITEDATA, resp); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); res curl_easy_perform(curl); if(res ! CURLE_OK) { printf(curl_easy_perform error: %s\n, curl_easy_strerror(res)); } curl_easy_cleanup(curl); curl_global_cleanup(); if (res ! CURLE_OK || resp.buf NULL) { free(resp.buf); return -1; } *out_json resp.buf; return 0; } //天气中文转英文 static void weather_cn2en(const char *cn, char *out, int out_len) { if(strstr(cn, 晴)) snprintf(out, out_len, Sunny); else if(strstr(cn, 多云)) snprintf(out, out_len, Cloudy); else if(strstr(cn, 阴)) snprintf(out, out_len, Overcast); else if(strstr(cn, 雨)) snprintf(out, out_len, Rain); else if(strstr(cn, 雪)) snprintf(out, out_len, Snow); else if(strstr(cn, 雾)) snprintf(out, out_len, Fog); else snprintf(out, out_len, Unknown); } //风向中文转英文 static void wind_dir_cn2en(const char *cn, char *out, int out_len) { if(strstr(cn,东)) snprintf(out,out_len,East); else if(strstr(cn,西)) snprintf(out,out_len,West); else if(strstr(cn,南)) snprintf(out,out_len,South); else if(strstr(cn,北)) snprintf(out,out_len,North); else snprintf(out,out_len,--); } typedef struct{ int temp; char weather[16]; char wind_dir[16]; char wind_power[16]; int humidity; int pressure; }WeatherInfo; int parse_weather(const char *json_str, WeatherInfo *info) { json_error_t err; json_t *root json_loads(json_str, 0, err); if (!root) { printf(json parse err: %s\n, err.text); return -1; } json_t *status json_object_get(root, status); if (!json_is_integer(status) || json_integer_value(status) ! 0) { printf(api status error, status%lld\n, json_integer_value(status)); json_decref(root); return -1; } json_t *result json_object_get(root, result); json_t *realtime_arr json_object_get(result, realtime); json_t *realtime_obj json_array_get(realtime_arr, 0); json_t *infos json_object_get(realtime_obj, infos); //温度 json_t *temp_val json_object_get(infos, temperature); info-temp json_is_integer(temp_val) ? (int)json_integer_value(temp_val) : -99; //天气 json_t *w_val json_object_get(infos, weather); if(json_is_string(w_val)){ weather_cn2en(json_string_value(w_val), info-weather, sizeof(info-weather)); }else strcpy(info-weather,Unknown); //风向 json_t *wd_val json_object_get(infos, wind_direction); if(json_is_string(wd_val)){ wind_dir_cn2en(json_string_value(wd_val), info-wind_dir, sizeof(info-wind_dir)); }else strcpy(info-wind_dir,--); //风力 json_t *wp_val json_object_get(infos, wind_power); if(json_is_string(wp_val)){ strncpy(info-wind_power, json_string_value(wp_val), sizeof(info-wind_power)-1); }else strcpy(info-wind_power,--); //湿度 json_t *hum_val json_object_get(infos, humidity); info-humidity json_is_integer(hum_val) ? (int)json_integer_value(hum_val) : -1; //气压 json_t *press_val json_object_get(infos, air_pressure); info-pressure json_is_integer(press_val) ? (int)json_integer_value(press_val) : -1; json_decref(root); return 0; } void oled_draw_point(uint8_t x, uint8_t y, uint8_t dot) { if (x 128 || y 64) return; uint8_t x_idx x / 8; uint8_t bit_x x % 8; uint8_t mask 1U bit_x; uint8_t *p (uint8_t *)fbp y * 16U x_idx; if(dot) *p | mask; else *p ~mask; } void oled_clear_screen(void) { for(int y0; y64; y) { for(int x0; x128; x) { oled_draw_point(x, y, 0); } } } int fb_open(void) { fb_fd open(/dev/fb1, O_RDWR); if (fb_fd 0) { perror(open /dev/fb1); return -1; } struct fb_var_screeninfo vinfo; ioctl(fb_fd, FBIOGET_VSCREENINFO, vinfo); size_t fb_size (size_t)vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8U; fbp mmap(NULL, fb_size, PROT_READ|PROT_WRITE, MAP_SHARED, fb_fd, 0); if(fbp MAP_FAILED){ perror(mmap fb1); close(fb_fd); return -1; } printf(fb1 ok: w%d h%d\n,vinfo.xres,vinfo.yres); return 0; } void fb_close(void) { if(fbp){ struct fb_var_screeninfo vinfo; ioctl(fb_fd, FBIOGET_VSCREENINFO, vinfo); size_t sz(size_t)vinfo.xres*vinfo.yres*vinfo.bits_per_pixel/8U; munmap(fbp, sz); } if(fb_fd 0) close(fb_fd); fbp NULL; fb_fd -1; } void oled_show_char(uint8_t x, uint8_t y, uint8_t chr, uint8_t size, uint8_t mode) { uint8_t temp, t, t1; uint8_t y0 y; uint8_t *pfont 0; uint8_t csize (size / 8 ((size % 8) ? 1 : 0)) * (size / 2); chr chr - ; if (size 12) { pfont (uint8_t *)oled_asc2_1206[chr]; } else return; for (t 0; t csize; t) { temp pfont[t]; for (t1 0; t1 8; t1) { if (temp 0x80)oled_draw_point(x, y, mode); else oled_draw_point(x, y, !mode); temp 1; y; if ((y - y0) size) { y y0; x; break; } } } } void oled_show_string(uint8_t x, uint8_t y, const char *p) { while ((*p ~) (*p )) { if (x (128 - 6)) { x 0; y 12; } if (y (64 -12)) break; oled_show_char(x, y, *p, 12, 1); x 6; p; } } int main(void) { if(fb_open() 0) return -1; WeatherInfo wi; char buf[64]; while(1) { oled_clear_screen(); oled_show_string(0,0,Fetching...); char *json_buf NULL; if(get_weather_json(json_buf) 0) { printf(JSON:\n%s\n,json_buf); if(parse_weather(json_buf, wi)0) { oled_clear_screen(); //行0 oled_show_string(0, 0, AD:340504); //行1 Temp snprintf(buf,sizeof(buf),Temp:%d C,wi.temp); oled_show_string(0,12,buf); //行2 Weather snprintf(buf,sizeof(buf),Weather:%s,wi.weather); oled_show_string(0,24,buf); //行3 Wind snprintf(buf,sizeof(buf),Wind:%s %s,wi.wind_dir, wi.wind_power); oled_show_string(0,36,buf); //行4 Humidity snprintf(buf,sizeof(buf),Hum:%d %%,wi.humidity); oled_show_string(0,48,buf); //行5 Pressure snprintf(buf,sizeof(buf),Press:%d hPa,wi.pressure); oled_show_string(0,60,buf); } free(json_buf); }else{ oled_clear_screen(); oled_show_string(0,0,Net Fail); } sleep(60); } fb_close(); return 0; }成果如下达成目标中间遇到一个问题 jansson明明在menuconfig打开了却没烧录到开发板去研究一下我先menuconfig 然后再 save再 ./build.sh buildroot_rootfs再 ./build.sh pack 烧录重启看看情况找不到但是先在编译目录里查找相关文件再试试这个顺序先 ./build.sh 再./build.sh pack 再烧录成功了再试试能不能直接运行刚才的程序成功仅供参考