本帖最后由 xiaoxiaoyudu 于 2024-1-4 09:13 编辑
本帖最后由 xiaoxiaoyudu 于 2024-1-4 09:07 编辑
本帖最后由 xiaoxiaoyudu 于 2023-12-17 13:04 编辑
桌面助手
1.主要功能
- [x] 时间显示(已完成)
- [x] 天气显示(已完成)
- [x] 温湿度显示(已完成)
- [x] wifi密码保存(已完成)
- [x] b站粉丝数显示(已完成)
- [x] U盘模拟设置(已完成)
- [x] 电脑性能显示(已完成)
- [x] web server(已完成)
- [ ] 自动息屏(放弃)
- [ ] 微信小程序接入(放弃)
- [ ] 温湿度mqtt上报(放弃)
2.目前进度
由于接触小安派时间较短,可能只能实现部分功能,目前完成logo界面设计,ttf矢量字体显示及u盘模拟功能。电脑性能上位机开发80%(wpf实在太占用资源类,算了,先凑合用了,之后再改),基本功能以完善。
10.29 初步完成界面布局及wifi扫描和连接。
11.01 完成时间获取更新。
11.02 获取心知天气完成。
11.03 完成https获取b站粉丝数
11.04 sht30温湿度传感器调试完成
11.05 添加pwm亮度调节
11.14完善多界面管理
11.18性能监控调试完成
3.硬件说明
采用小安派dsl板子,屏幕为2.4寸320 *240分辨率屏幕,外接sht30温湿度传感器。
4.界面展示
![gif.jpg gif.jpg](data/attachment/forum/202311/18/232441xricchchj0vz8n0c.jpg)
[b站视频]
<iframe src="https://player.bilibili.com/player.html?aid=278539119&bvid=BV1cw411K7mn&cid=1336618924&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"> </iframe>
5.功能说明
软件说明
所有信息保存在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;
主要为四个任务,一个任务用于刷新lvgl界面,一个任务用于管理wifi,另一个任务为定时器任务,定时更新sys_info中的信息内容,最后一个任务用于接收电脑发送的监控信息并进行处理。
时间更新
在连接到wifi获取并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的程序优化,所以暂时只能将就使用。
然后是下位机,小安派连接wifi后开启tcp_server,然后监听8124端口,上位机连接成功后,会首先发送pc信息,包括cpu型号,gpu型号,采用json字符串的格式发送。然后上位机定时向小安派发送内存,cpu,gpu,网速相关信息,小安派将其解析并更新ui。
尚未解决的问题
哔哩哔哩账户id及天气地址代码固化在代码中,需要更改源码,之后将会使用web server功能,通过post修改上述参数,将相应参数保存至文件。
源代码
代码放在gitlab上->https://gitee.com/wangpeng25/desktop-ornaments
跳转