项目介绍
项目采用rp2040外接传感器来完成色彩识别并显示,可至少识别五种颜色以上。
板卡支持micropython 、c sdk,也支持circuitpython等很多种开发语言,本次使用的是开发环境c sdk,ide使用vscode。
环境搭建在官方有非常详细的指导,包括vscode下如何使用插件,编译以及各种demo,给开发带来非常多的便利。
官方介绍:https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf
设计思路
项目主要用到的就是屏幕与rgb颜色传感器,另外没有调试功能,需要将串口打印功能打开,可以使用usb cdc的功能,将usb模拟为串口设备。
一、屏幕部分跑默认例程pio/st7789_lcd/st7789_lcd.c
展示pico的图片logo
二、串口打印功能,根据demo:hello_world/usb/hello_usb.c
,通过它开启开发板串口打印的功能,方便调试
三、i2c通信,通过hardware_i2c,硬件i2c,完成与rgb颜色传感器的调试。
将以上三个功能分别跑通后就可以进入最终的设计,将rgb传感器的颜色读出来,通过一系列的计算,将计算的结果转换为rgb565的屏幕色深,再通过屏幕全屏刷新展示出来。
办卡的演示在视频的33s处
屏幕
屏幕采用st7789这个经典芯片,在pico的c sdk中有他的例程,使用的是PIO(可编程IO)来驱动,具体位置在
pio/st7789_lcd/st7789_lcd.c
我们现将这个程序跑起来(例程可移植性很好,只需要改一点点内容就可以跑起来)
//修改Pin脚
#define PIN_DIN 3
#define PIN_CLK 2
#define PIN_CS 4
#define PIN_DC 1
#define PIN_RESET 0
// #define PIN_BL 5
//注释调不需要的引脚操作
gpio_init(PIN_CS);
gpio_init(PIN_DC);
gpio_init(PIN_RESET);
// gpio_init(PIN_BL);
gpio_set_dir(PIN_CS, GPIO_OUT);
gpio_set_dir(PIN_DC, GPIO_OUT);
gpio_set_dir(PIN_RESET, GPIO_OUT);
// gpio_set_dir(PIN_BL, GPIO_OUT);
gpio_put(PIN_CS, 1);
gpio_put(PIN_RESET, 1);
lcd_init(pio, sm, st7789_init_seq);
// gpio_put(PIN_BL, 1);
然后编译并将uf2放到板卡中,就驱动起来了。效果如下(旋转的rp2040 logo):
还记得官方在这里文档的描述很有意思,说别人驱动屏幕只是简单的显示,他们的是旋转
串口
使用c sdk貌似没有调试功能,这时候串口打印就尤为重要了,我们可以通过芯片usb的cdc模拟一个usb串口设备以在屏幕上打印日志。
具体可以参考hello_world/usb/hello_usb.c
这个项目,非常经典的在串口打印Hello, world!
,具体实现没有深究。
RGB颜色识别
驱动ltr381
颜色识别用的是ltr381这个传感器,它采用i2c接口,识别rgb颜色并存放在rgb三个寄存器中。参考了一个c++的lib:https://github.com/Rombutan/ltr381_pico_lib.git
也封装了获取r g b寄存器的函数(以red为例):
uint32_t ltr381_red() {
uint32_t red = 0;
uint8_t addr, buf;
addr = 0x10;
i2c_write_blocking(i2c_default, REG_DEVID, &addr, 1, true);
i2c_read_blocking(i2c_default, REG_DEVID, &buf, 1, false);
red = buf;
addr = 0x11;
i2c_write_blocking(i2c_default, REG_DEVID, &addr, 1, true);
i2c_read_blocking(i2c_default, REG_DEVID, &buf, 1, false);
red |= buf << 8;
addr = 0x12;
i2c_write_blocking(i2c_default, REG_DEVID, &addr, 1, true);
i2c_read_blocking(i2c_default, REG_DEVID, &buf, 1, false);
red |= buf << 16;
return red;
}
颜色校准
实际上色彩识别是有很多门道的,比如光照强度,色温等等都会影响颜色,我们要做的只是忽略其他因素,识别颜色。
简单了解原理后就开始手动校准。
- 采样RGB颜色在一开始就有很大差异,g颜色值高很多,b又很低,首先将他们统一到一个尺度(屋内环境得到r近似120,让gb等比例放大到r)
r = ltr381_red();
g = ltr381_green() * 0.74;
b = ltr381_blue() * 1.8; - 亮度过高影响识别效果(设置采样颜色的上限与下限)
r = fmin(120, r);
g = fmin(120, g);
b = fmin(120, b);
if(r < 60 && g < 60 && b < 60) {
printf("ingore\n");
continue;
} - 将获取到的最亮的颜色作为基准,把其他颜色按照比例缩小,并按照rgb565格式的色深进行扩大。
if ((r > g) && (r > b)) {
rate = 31.0 / r;
r = 31;
g = g * rate * 2;
b = b * rate;
} else if ((g > r) && (g > b)) {
rate = 31.0 / g;
r = r * rate;
g = 63;
b = b * rate;
} else {
rate = 31.0 / b;
r = r * rate;
g = g * rate * 2;
b = 31;
}
r = fmin(r, 31);
g = fmin(g, 63);
b = fmin(b, 31);
以上的校准纯属原创哈哈哈哈,肯定有更好的算法或识别模式,但在找这个芯片的资料的时候只能找到用来肤色识别的算法,无奈只能自己尝试,但识别效果感觉也还可以~
项目编译
采用vscode,与其他那些ide不同,c sdk采用cmake进行项目构建(虽然cmake比单纯的makefile负责了亿点点,但构建的方式也还是比采用其他自家ide那些更浮在表面,包括编译依赖等等),对于想了解构建过程还是很友好的。
因为没有其他ide的一键导入库,所以这里重点也讲一下编译的配置。
项目是基于hello_world/usb二次开发,CMakeLists.txt代码如下:
if (TARGET tinyusb_device)
add_executable(hello_usb)
pico_generate_pio_header(hello_usb ${CMAKE_CURRENT_LIST_DIR}/st7789_lcd.pio)
# pull in common dependencies
target_link_libraries(hello_usb pico_stdlib hardware_interp hardware_pio hardware_i2c)
target_sources(hello_usb PRIVATE
hello_usb.c
)
# enable usb output, disable uart output
pico_enable_stdio_usb(hello_usb 1)
pico_enable_stdio_uart(hello_usb 0)
# create map/bin/hex/uf2 file etc.
pico_add_extra_outputs(hello_usb)
# add url via pico_set_program_url
example_auto_set_url(hello_usb)
elseif(PICO_ON_DEVICE)
message(WARNING "not building hello_usb because TinyUSB submodule is not initialized in the SDK")
endif()
其中屏幕采用可编程IO,因此导入st7789_lcd.pio(大概就是配置pio的fifo实现数据输出)这里值得深入研究。
# enable usb output, disable uart output
pico_enable_stdio_usb(hello_usb 1)
pico_enable_stdio_uart(hello_usb 0)
短短两行就配置好了usb cdc 用于串口打印,非常便捷。
最后就是使用vscode cmake插件编译啦。
还有一些其他的库pico_stdlib hardware_interp hardware_pio hardware_i2c
未来计划
rp2040真的是一个很经典的设计,大量diy玩家用它作各种脑洞打开的创意,这个带屏的rp2040很精致,可拓展的功能也很多,很开心得到这样一块板卡,未来计划是将其中的各种传感器驱动,将信息显示到屏幕上,并研究pio相关知识,以及c sdk这个庞然大物却有很好用的构建方式。