[ Arduino+Python ] 做一个串口屏,显示CPU使用率

 更多内容,请访问我的网站:https://jiangge12.github.io/

Arduino 和 Python 虽然是不同的编程语言,但并不影响共同实现一个制作。(传统说法就是一个在上位机编程,一个给下位机编程)

只需要下图所示的两个常见零件 UNO 和 LCD 盾板( 2.4‘ TFT 驱动 ILI9341 ),如果你手里正好有,那么不妨用起来, Arduino Python 都熟悉的话,copy 一下代码,分分钟。

即插即用,不用面包板,不用杜邦线,不用嘉立创打板,不用焊接,你还等什么?

像 Lego 一样,LCD 和 UNO 都可以拆为他用,不损耗一丁点材料。

经过几天使用,不断完善,基本可以投入实用了。

串口命令里可以调整 字体和背景颜色,字号,具体用法看后面的python实例。

【 上篇 --- DIY一个 串口屏 】

刚入坑就有了一个 LCD 盾板,虽然有触摸屏,做完例程就一直在吃灰,因为TA把 UNO 的端口几乎占完了,就剩下串口,还不方便插其他串口模块。最近一直折腾 0.96’OLED,实在太小,于是又想起这块2.4‘的屏。因为端口的原因,可以做的有限,那就先做个串口屏。虽然市面也有成品 串口屏 ,不过自己做的控制命令定制方便。

首先,给 UNO 写入 arduino 代码:

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library
#include <string.h>
#define LCD_CS A3    // Chip Select goes to Analog 3
#define LCD_CD A2    // Command/Data goes to Analog 2
#define LCD_WR A1    // LCD Write goes to Analog 1
#define LCD_RD A0    // LCD Read goes to Analog 0
#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin 
#define USE_ADAFRUIT_SHIELD_PINOUT
#define	BLACK   0x0000
#define	BLUE    0x001F
#define	RED     0xF800
#define	GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
String str;
int background_color;

void setup(void) {
  background_color=BLACK;
  
  Serial.begin(115200); 
  uint16_t identifier = tft.readID();   // (16进制) 37697 =(10进制)9341
  tft.begin(identifier);
  Serial.print(identifier,HEX);         // 以16进制打印
  Serial.print("TFT size is "); Serial.print(tft.width()); Serial.print("x"); Serial.println(tft.height());

  tft.fillScreen(background_color);                // 假假来个欢迎界面
  tft.setRotation(3);
  tft.setCursor(0, 40);
  tft.setTextColor(CYAN);  
  tft.setTextSize(5);
  tft.print("Hello T800");            
  tft.setCursor(0, 110);
  tft.setTextColor(MAGENTA); 
  tft.setTextSize(3);
  tft.print("Feed me something");
  delay(2000);
  tft.fillScreen(background_color);
  tft.setCursor(0, 0);


}

void loop(void) {  
  
  while (Serial.available() > 0)        // 检查串口是否有数据,有就一个一个字符读出来,合并为字符串 str
  {                 
    str += char(Serial.read());
    delay(2);
  }

  if (str.length() > 0)                 // 如字符串 str 非空,表示收到了些内容。显示之前先判断是否是设置命令。
  {    
    if(str == "cls"){                   // 收到 cls 清屏命令 
      tft.fillScreen(background_color); // 清屏(就是全色填充,默认黑色)
      tft.setCursor(0, 0);              // 光标返回左上角
      str = "";                         // 命令无需显示
    } 
    else if(str == "setback_white"){    // 设置背景 白色
      background_color = WHITE;
      str = "";
    }
    else if(str == "setback_black"){    // 设置背景 黑色
      background_color = BLACK;
      str = "";
    }
    else if(str == "setback_green"){    // 设置背景 绿色
      background_color = GREEN;
      str = "";
    }
    else if(str == "setback_red"){      // 设置背景 红色
      background_color = RED;
      str = "";
    }
    else if(str == "setback_blue"){     // 设置背景 蓝色
      background_color = BLUE;
      str = "";
    }
    else if(str == "setback_yellow"){   // 设置背景 黄色
      background_color = YELLOW;
      str = "";
    }
    else if(str == "setback_cyan"){     // 设置背景 青色
      background_color = CYAN; 
      str = "";
    }
    else if(str == "setback_magenta"){  // 设置背景 洋红色
      background_color = MAGENTA;
      str = "";
    }

    else if(str == "setfont_1"){        // 设置字号1
      tft.setTextSize(1);
      str = "";
    }
    else if(str == "setfont_2"){        // 设置字号2
      tft.setTextSize(2);
      str = "";
    }
    else if(str == "setfont_3"){        // 设置字号3
      tft.setTextSize(3);
      str = "";
    }
    else if(str == "setfont_4"){        // 设置字号4
      tft.setTextSize(4);
      str = "";
    }    
    else if(str == "setfont_5"){        // 设置字号5
      tft.setTextSize(5);
      str = "";
    }
    else if(str == "setfont_white"){    // 设置字体颜色 白
      tft.setTextColor(WHITE);
      str = "";
    }
    else if(str == "setfont_black"){    // 设置字体颜色 黑
      tft.setTextColor(BLACK);
      str = "";
    }
    else if(str == "setfont_green"){    // 设置字体颜色 绿
      tft.setTextColor(GREEN);
      str = "";
    }
    else if(str == "setfont_red"){      // 设置字体颜色 红
      tft.setTextColor(RED);
      str = "";
    }   
    else if(str == "setfont_blue"){     // 设置字体颜色 蓝
      tft.setTextColor(BLUE);
      str = "";
    }
    else if(str == "setfont_yellow"){   // 设置字体颜色 黄 
      tft.setTextColor(YELLOW); 
      str = "";
    }    
    else if(str == "setfont_cyan"){     // 设置字体颜色 青 
      tft.setTextColor(CYAN); 
      str = "";
    }
    else if(str == "setfont_magenta"){   // 设置字体颜色 洋红
      tft.setTextColor(MAGENTA); 
      str = "";
    }  
             
    else{                               // 前面都是设置命令,执行完并不显示,下面才是把收到的字符串显示出来,显示后换行并清空变量,
      tft.println(str);
      Serial.println(str);
      str = "";
    }
  }
}

具体怎么操作,注意看程序里 str 后面的 绿色关键字 ,在串口调试工具里输入试试看,注意大小写。

在串口调试软件里面发送些测试文字,效果如下:

【 下篇 --- 串口屏 使用实例:显示CPU使用率 】

之前写过 python 获取硬件信息 的文章,那就用python好了。

先用 python 熟悉下串口操作: 

import serial  # 导入模块 ,没有 pip3 install pyserial
import time

try:
    portx="COM5"
    bps=9600
    timex=5
    ser=serial.Serial(portx,bps,timeout=timex)

    while True:
        ser.write("cls".encode("ascii"))
        time.sleep(0.12)      # 没有延时和后面一波字符串连接一块了,不被识别
        
        ser.write("setfont_red".encode("ascii"))
        time.sleep(0.12)
        ser.write("1234567890ABCDEF".encode("ascii"))
        time.sleep(0.12)
        ser.write("setfont_green".encode("ascii"))
        time.sleep(0.12)
        ser.write("!@#$%^&*()_+=".encode("ascii"))
        time.sleep(0.12) 
        ser.write("setfont_yellow".encode("ascii"))
        time.sleep(0.12)
        ser.write("when all the winds agains you".encode("ascii"))
        
        time.sleep(1)        
        
    ser.close() #关闭串口

except Exception as e:
    print("---异常---:",e)

 接下来开始实战,实现显示CPU各核心的使用率

python 代码:

import serial  
import time
import psutil
import re
import serial.tools.list_ports

com_auto_detect = 'Null'

port_list = list(serial.tools.list_ports.comports())  # print(port_list) 获得的列表不太容易看得懂

if len(port_list) == 1:                               # 通常这里 ==0,表示列表空。不过我的笔记本扩展坞已有个硬件串口占用COM1.USB串口默认COM3开始,所以+1
    print('没有可用的USB串口设备')
else:
    for i in range(1,len(port_list)):                 # 从1开始,忽略0 即扩展坞 COM1 
        com_auto_detect = str(port_list[i])[0:4]      # 转换为字符串,再截取其前5位
        print("找到可用的USB串口设备:  ",com_auto_detect)       # 循环完保留最后一个串口号,只有一个串口设备的情况下就是串口屏,至于怎么准确判断,还需要进一步考虑,比如发个设备名查询

send_interval = 0.05                                  # 两次发送如没有间隔会和后面一波字符串连接一块。实测最低值 UNO=0.13  ESP8266=0.88(有些奇异,都是CH340芯片) 

try:
    ser=serial.Serial(com_auto_detect,115200,timeout=5)   # 串口初始化, 手工指定 替换c om_auto_detect 为 COM5"
    
    while True:
        ser.write("cls".encode("ascii"))
        time.sleep(0.13)                              # 前两次需要间隔长些,原因不明        
     
        f = psutil.cpu_freq() 
        # print(type(f))                              # f 是个 类
        f = str(f)                                    # 先转换为字符串,方便处理
        f = f.split(",",1)[0]                         # 取 逗号 前
        f = f.split("=",1)[1]                         # 再取 等号 后
        f = "Freq: " + f + " MHz"
        ser.write("setfont_magenta".encode("ascii"))  # 前两次需要间隔长些,原因不明  
        time.sleep(0.13)  
        ser.write("setfont_3".encode("ascii"))     
        time.sleep(send_interval)                              
        ser.write(str(f).encode("ascii"))        
        time.sleep(send_interval)     
        
        ser.write("setfont_green".encode("ascii"))    # CPU 总使用率
        time.sleep(send_interval)
        ser.write("setfont_5".encode("ascii"))
        time.sleep(send_interval)

        a = psutil.cpu_percent()
        a = "CPU:" + str(a) + "%"        
        ser.write(str(a).encode("ascii"))        
        time.sleep(send_interval)  
        
        ser.write("setfont_cyan".encode("ascii"))     # 各核心使用率
        time.sleep(send_interval)
        ser.write("setfont_2".encode("ascii"))
        time.sleep(send_interval)
        a = psutil.cpu_percent(percpu=True)  
        for i in range(8):                             # 8核心 (4T8C)
          a[i] = " CPU"+ str(i) +": "+ str(a[i]) +"%"  # 更直观显示a[i]
          ser.write(str(a[i]).encode("ascii"))
          time.sleep(send_interval)   
         
        time.sleep(1.5)                                # cls 前保留时间
        
    ser.close()                                        # 关闭串口

except Exception as e:
    e = str(e).split(":",1)[0]   
    print("遇到一点意外:",e)

 下图是 AIDA64 压力测试,CPU 飙到 100 

 暂停测试 CPU 回落,刷新原因拍照没抓住全屏,意思到了就行。

下面是完善后的实图,比较符合我的预期了。

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值