专栏名称: 安信可科技
全球领先的联网模组、智能家居等物联网硬件方案提供商。
目录
相关文章推荐
Java知音  ·  池化技术:让真实业务效率飙升的利器 ·  3 天前  
Java知音  ·  池化技术:让真实业务效率飙升的利器 ·  3 天前  
51好读  ›  专栏  ›  安信可科技

用小安派 DSL做一个天气站

安信可科技  · 公众号  ·  · 2025-01-02 12:01

正文




用小安派 DSL做天气站

用户分享DIY


前言

小安派-DSL(AiPi-DSL) 是安信可开源团队专门为Ai-M61-32S设计的一款屏幕驱动开发板,支持2.8/3.5寸等30Pin SPI显示屏、2.4寸及1.28寸等18Pin SPI显示屏。


小安派-DSL目前已测试通过的有3.5寸电容触摸屏(GC9307)、2.4寸电容触摸屏(GC9307)、1.28寸圆形电容触摸屏(GC9A01)。


这次采用小安派 dsl 板子,屏幕为 2.4 寸 320 *240 分辨率屏幕,外接 sht30 温湿度传感器,做一个天气站。





01

主要功能



 时间显示(已完成)

 天气显示(已完成)

 温湿度显示(已完成)

 wifi 密码保存(已完成)

 b 站粉丝数显示(已完成)

 U 盘模拟设置(已完成)

 电脑性能显示(已完成)

 web server(已完成)

 自动息屏(放弃)

 微信小程序接入(放弃)

 温湿度 mqtt 上报(放弃)



02

方案进度


由于笔者接触小安派时间较短,可能只能实现部分功能,目前完成logo界面设计,ttf 矢量字体显示及U盘模拟功能。电脑性能上位机开发 80%(wpf 实在太占用资源类,先凑合用),基本功能已完善:


✔初步完成界面布局及 wifi 扫描和连接

✔完成时间获取更新

✔获取心知天气完成

✔完成 https 获取 b 站粉丝数

✔sht30 温湿度传感器调试完成

✔添加 pwm 亮度调节

✔完善多界面管理

✔性能监控调试完成



03

功能说明


软件说明

所有信息保存在 sys_info 的结构体中,该结构体为全局变量,下图所示。


typedef struct{    union {        uint32_t state;        struct{            uint32_t state_wifi : 2; // 0:未连接 ;1:连接;2:断开连接            uint32_t state_upan : 2; // 0:未开启 ;1:连接;        };    };    lv_obj_t *last_src;    struct tm* timeinfo_t;    uint8_t   backlight;    blbl_follow_t blbl_info_t;    weather_t weather[3];    char * city;    char * weather_key;    wifi_info_t wifi;    uint8_t brightness;    sht30_t sht;    pc_info_t pc;    monitor_info_t *monitor;} blbl_sys_t;


主要为四个任务:
(1)用于刷新 lvgl 界面
(2)用于管理 Wi-Fi
(3)为定时器任务,定时更新 sys_info 中的信息内容
(4)用于接收电脑发送的监控信息并进行处理



时间更新

连接到 Wi-Fi 获取并 ip 地址时,采用 http 从网易 api 接口获取时间戳,保存时间戳信息,开启 rtc 计时,这里有一个小 bug,官方提供的设置 rtc 函数不能设置计数值,只能从 0 开始计数。当前时间戳即为 rtc 时间 +http 获取的时间戳。然后通过 localtime 将时间戳转换为年月日。


struct bflb_device_s *rtc;static uint64_t base_time;
void rtc_init(uint64_t timetemp){ rtc = bflb_device_get_by_name("rtc"); //此函数,只能开启⏲ bflb_rtc_set_time(rtc, BFLB_RTC_SEC2TIME(1)); base_time = timetemp;}
uint64_t rtc_get_time(){ return (BFLB_RTC_TIME2SEC(bflb_rtc_get_time(rtc)) + base_time);}
void time_update(){ time_t time = rtc_get_time(); localtime(&time);}



天气显示

使用心知天气 api,使用 tcp 模拟 http 请求,返回最近三日天气状态的 json 字符串,使用 cjson 对字符串进行解析,存储到系统变量 sys_info 中。


温湿度时间显示

采用 sht30 温湿度传感器模块,i2c 接口,bl618 一共两组 i2c,一组提供给屏幕的触摸 ic,并且没有引出该 io,故只能选用另一组 i2c,根据芯片手册,貌似每个 gpio 均支持 i2c 复用,只不过只能复用 scl 或者其中一个 sda 。然后初始化 gpio,复用 i2c1,通过 i2c 初始化 sht30,如下所示。


struct bflb_i2c_msg_s msgs;    uint8_t subaddr[2] = { CMD_FETCH_DATA_H, CMD_FETCH_DATA_L};
board_i2c1_gpio_init();
i2c1 = bflb_device_get_by_name("i2c1");
bflb_i2c_init(i2c1, 400000);
msgs.addr = SHT30_WRITE_ADDR; msgs.flags = 0; msgs.buffer = subaddr; msgs.length = 2;
bflb_i2c_transfer(i2c1, &msgs, 1);


然后便可以读出原始数据,经过处理,可以获得温湿度信息。


int sht30_get_value(){    unsigned char sht30_buf[6]={0};     uint32_t date;    int ret;    struct bflb_i2c_msg_s msgs;    //配置SHT30的寄存器    msgs.addr = SHT30_WRITE_ADDR;    msgs.flags = I2C_M_READ;    msgs.buffer = sht30_buf;    msgs.length = 6;
bflb_i2c_transfer(i2c1, &msgs, 1); //校验读出来的数据,算法参考sht30 datasheet if( (!SHT3X_CheckCrc(sht30_buf,2,sht30_buf[2])) && (!SHT3X_CheckCrc(sht30_buf+3,2,sht30_buf[5])) ) { ret = 0;//成功 date=(sht30_buf[0]<<8|sht30_buf[1]); sys_info_t.sht.temp =(uint8_t) ( ((float)date *175)/65535 -50 ); sys_info_t.sht.humi =(uint8_t)( ( (sht30_buf[3]*256) + (sht30_buf[4]) )*100/65535.0) ; } return ret;}



b 站粉丝数显示


之前b 站提供粉丝数获取的 http 接口,最近由于安全考虑,b 站的 http 均不能使用,需要使用 https 发起请求。为了方便,这里只使用单向验证,不对服务器返回信息进行验证。


U盘模拟


官方提供了USB存储设备模拟的代码,但是是基于RAM模拟的,一旦掉电,数据将会丢失,可以选用将数据存储到片上Flash 内,Flash 大小一共有 8M,选用后4M作为文件管理系统。只需要实现读写Flash 的操作即可,即以下接口。需要注意的是经过测试,Flash最小读写单位为4K,小于4K会出现问题。


void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint16_t *block_size){    *block_num = BLOCK_COUNT; //Pretend having so many buffer,not has actually.    *block_size = BLOCK_SIZE;}

int usbd_msc_sector_read(uint32_t sector, uint8_t *buffer, uint32_t length){ if (sector < BLOCK_COUNT){ bflb_flash_read(CONFIG_FLASH_USB_ADDRESS + sector*BLOCK_SIZE, buffer, length); } return 0;}int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length){ if (sector < BLOCK_COUNT){ bflb_flash_erase(CONFIG_FLASH_USB_ADDRESS + sector*BLOCK_SIZE,length); bflb_flash_write(CONFIG_FLASH_USB_ADDRESS + sector*BLOCK_SIZE, buffer, length); } return 0;}


之后调用USB初始化,电脑便会识别到该设备,但是由于没有文件系统,系统会建议格式化U盘,建议不要使用 Window 自带的格式化,将会格式化为 fat16 文件系统,在之后的 gif 显示中发现 fat16 文件系统读取 gif 文件并显示会卡住,而 fat32 文件系统则没有该问题。故使用第三方工具 diskgenius 格式化为 fat32.


到此已经完成USB存储设备模拟,个功能有什么用?当然是方便传输文件给程序使用,所有程序也要可以识别该文件系统,官方已经做了 FatFS 文件系统的移植,但是是基于SD卡的,将其改为基于 Flash 的,同样也是只需要实现 Flash 读写接口。


int fs_flash_read(BYTE *buff, LBA_t sector, UINT count){    if(!count)        return RES_PARERR;    if(bflb_flash_read(FS_ADDR + sector*BLOCK_SIZE, buff, count * BLOCK_SIZE)){        return RES_PARERR;    }    return 0;}
int fs_flash_write(const BYTE *buff, LBA_t sector, UINT count){ bflb_flash_erase(FS_ADDR + sector*BLOCK_SIZE,count); bflb_flash_write(FS_ADDR + sector*BLOCK_SIZE, (uint8_t *)buff, count * BLOCK_SIZE); return 0;}
int fs_flash_ioctl(BYTE cmd, void *buff){ switch (cmd) { // Get R/W sector size (WORD) case GET_SECTOR_SIZE: *(WORD *)buff = BLOCK_SIZE; break;
// Get erase block size in unit of sector (DWORD) case GET_BLOCK_SIZE: *(DWORD *)buff = 1; break;
case GET_SECTOR_COUNT: *(DWORD *)buff = 1024; break;
case CTRL_SYNC: break;
default: break; }
return 0;}


从USB模拟可知,我们将文件系统放到后4M的位置,如果我们将FatFS的地址也设置为4M的位置,将会发现,程序检测不到Fat32文件系统,这是因为在用电脑格式化的时候,会在Fat32文件系统前添加一段额外的表头信息,这段表头位于 4M的位置,真正的Fat32文件系统位于0x3f000处。具体为什么会这样,笔者还没有深入研究。


FS_ADDR (CONFIG_FLASH_USB_ADDRESS + 0x3F000)
至此,程序便可以直接访问 Fat32 文件系统的文件。


电脑性能监控


电脑性能监控需要使用上位机不断的给小安派发送电脑相关信息,关于上位机的选择,首先先到的是使用 ada64,但是发现,这个软件居然要几百块钱,于是便打算使用开源项目,这里使用的是 OpenHardwareMonitor,一个电脑性能检测的开源项目,基于 c#开发,提供 dll 动态链接库文件。

然后是界面的设计,首先选择的是和 OpenHardwareMonitor 一样的框架 Winform,但受限于本人技术较菜,一些复杂功能无法实现,便选择使用wpf 框架,wpf 框架功能更加强大,但是问题在于使用 wpf 开发的程序占用资源过于庞大,本人又不太了解 wpf 的程序优化,所以暂时只能将就使用。

接着是下位机,小安派连接 Wi-Fi 后开启 tcp_server,然后监听 8124 端口,上位机连接成功后,会首先发送 pc 信息,包括CPU型号,GPU型号,采用 json 字符串的格式发送。然后上位机定时向小安派发送内存、CPU、GPU、网速相关信息,小安派将其解析并更新UI。



尚未解决的问题


哔哩哔哩账户ID及天气地址代码固化在代码中,需要更改源码,之后将会使用 web server 功能,通过 post 修改上述参数,将相应参数保存至文件。




04

视频演示








请到「今天看啥」查看全文