Arduino 和 Python 虽然是不同的编程语言,但并不影响共同实现一个制作。(传统说法就是一个在上位机编程,一个给下位机编程)
只需要下图所示的两个常见零件 UNO 和 LCD 盾板( 2.4‘ TFT 驱动 ILI9341 ),如果你手里正好有,那么不妨用起来, Arduino Python 都熟悉的话,copy 一下代码,分分钟。
即插即用,不用面包板,不用杜邦线,不用嘉立创打板,不用焊接,你还等什么?
像 Lego 一样,LCD 和 UNO 都可以拆为他用,不损耗一丁点材料。
经过几天使用,不断完善,基本可以投入实用了。
串口命令里可以调整 字体和背景颜色,字号,具体用法看后面的python实例。
刚入坑就有了一个 LCD 盾板,虽然有触摸屏,做完例程就一直在吃灰,因为TA把 UNO 的端口几乎占完了,就剩下串口,还不方便插其他串口模块。最近一直折腾 0.96’OLED,实在太小,于是又想起这块2.4‘的屏。因为端口的原因,可以做的有限,那就先做个串口屏。虽然市面也有成品 串口屏 ,不过自己做的控制命令定制方便。
首先,给 UNO 写入 arduino 代码:
#include // Core graphics library
#include // Hardware-specific library
#include
#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 后面的 绿色关键字 ,在串口调试工具里输入试试看,注意大小写。
之前写过 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)
暂停测试 CPU 回落,刷新原因拍照没抓住全屏,意思到了就行。
下面是完善后的实图,比较符合我的预期了。