作为一个常年折腾硬件的玩家,我总喜欢在桌面上放些能实时显示电脑状态的小玩意儿。以前用AIDA64的悬浮窗,但总觉得不够酷——直到发现可以用STM32+OLED打造专属性能看板。这玩意儿不仅能实时显示CPU温度、内存占用,还能让桌面瞬间充满极客感。
传统软件监控的痛点在于:占用屏幕空间、依赖操作系统、视觉效果单一。而硬件看板的优势很明显:独立显示不遮挡内容、断电后立即恢复、自定义显示样式。我实测下来,0.96寸OLED在日光下依然清晰,STM32F103的功耗不到0.5W,整套方案成本不超过50元。
在AIDA64中配置LCD输出其实很简单,但有几个关键点容易踩坑。首先进入【文件】→【设置】→【LCD】,选择Pertelian作为设备类型——这个选项决定了数据包的格式。端口号要选STM32实际连接的COM口,屏幕尺寸建议选16x4(对应128x64的OLED)。
添加监控项时有个隐藏技巧:按住Ctrl键可以批量选择多个参数。我常用的配置组合是:
注意一定要在Unit栏加上"@"符号,这个符号会作为数据包的结束标志,后续解析时会用到。
用串口调试工具抓包,会发现AIDA64发送的数据非常规律。每个数据包的结构如下:
| 字节位置 | 含义 | 示例值 |
|---|---|---|
| 0 | 起始标志 | 0xFE |
| 1 | 行号标识 | 0x80~0xD4 |
| 2~n-1 | 实际数据 | ASCII字符 |
| n | 结束标志 | 0x40 (@) |
比如第二行内存数据可能长这样:
FE C0 35 25 40 → 表示内存使用率35%
原始代码用了9个状态来处理数据包,其实可以用更优雅的方式实现。我的改进方案是定义结构体数组:
c复制typedef struct {
uint8_t lineID;
char* pBuffer;
} LineConfig;
LineConfig lines[] = {
{0x80, Serial_RxPacket_CPU},
{0xC0, Serial_RxPacket_Mem},
{0x94, Serial_RxPacket_CPUTemp},
{0xD4, Serial_RxPacket_GPUTemp}
};
这样中断处理函数可以简化为:
c复制void USART1_IRQHandler() {
static uint8_t state = 0;
static uint8_t currentLine = 0;
static uint8_t index = 0;
uint8_t data = USART_ReceiveData(USART1);
switch(state) {
case 0: // 等待起始位
if(data == 0xFE) state = 1;
break;
case 1: // 识别行号
for(int i=0; i<4; i++) {
if(data == lines[i].lineID) {
currentLine = i;
state = 2;
index = 0;
break;
}
}
break;
case 2: // 接收数据
if(data == 0x40) {
lines[currentLine].pBuffer[index] = '\0';
RxFlag = 1;
state = 0;
} else {
lines[currentLine].pBuffer[index++] = data;
}
break;
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
实际使用中可能会遇到数据错乱的问题,我总结了几个加固措施:
0.96寸OLED的分辨率是128x64,合理布局能让信息更清晰。我的设计方案是:
实现进度条效果的代码片段:
c复制void drawProgressBar(uint8_t row, uint8_t percent) {
OLED_DrawRectangle(30, row*16-1, 100, row*16+6);
uint8_t length = (100-30)*percent/100;
OLED_FillRectangle(30, row*16-1, 30+length, row*16+6);
}
默认的I2C传输速度可能限制刷新率,可以通过这些方法提升:
实测优化后,全屏刷新速度从120ms提升到35ms,完全看不出闪烁。
如果觉得串口线太乱,可以改用ESP-01S WiFi模块:
用CAN总线连接多个STM32,实现:
外接SPI Flash存储历史数据,实现:
我在实际项目中发现,STM32的硬件SPI配合DMA传输,可以轻松实现每秒1000次的数据记录。