如何用OLED、ESP32及SH1106 MicroPython库绘制图表?求助
在ESP32的SH1106 OLED上绘制图表与数据计算方案
一、数据预处理:映射原始数据到OLED坐标
SH1106 OLED通常为128×64分辨率,原始数据的数值范围(比如传感器读数)和屏幕像素范围不匹配,需要先做归一化映射,把数据转换为屏幕可识别的坐标。核心公式如下:y = 屏幕Y轴上限 - ((当前数据 - 数据最小值) / (数据最大值 - 数据最小值)) * (屏幕Y轴范围)
注:OLED坐标原点在左上角,所以Y值越大越靠近屏幕底部,需反向映射。
实现映射函数:
def map_data(data, data_min, data_max, screen_y_min, screen_y_max): # 处理数据全部相同的边界情况 if data_max == data_min: return (screen_y_min + screen_y_max) // 2 return screen_y_max - int(((data - data_min) / (data_max - data_min)) * (screen_y_max - screen_y_min))
二、基础图表绘制示例
1. 折线图
通过连接预处理后的坐标点实现,适合展示数据趋势:
from machine import I2C, Pin from sh1106 import SH1106_I2C # 初始化OLED i2c = I2C(0, scl=Pin(22), sda=Pin(21), freq=400000) oled = SH1106_I2C(128, 64, i2c, addr=0x3c, rotate=0) # 模拟传感器数据 sensor_data = [12, 15, 18, 14, 20, 17, 19, 13] def draw_line_chart(data, x_start=5, y_start=5, width=118, height=54): data_min = min(data) data_max = max(data) points = [] # 计算每个数据点的屏幕坐标 for idx, val in enumerate(data): x = x_start + int((idx / (len(data)-1)) * width) y = map_data(val, data_min, data_max, y_start, y_start + height) points.append((x, y)) # 绘制连线 for i in range(len(points)-1): oled.line(points[i][0], points[i][1], points[i+1][0], points[i+1][1], 1) # 绘制数据点(增强可读性) for (x, y) in points: oled.fill_rect(x-1, y-1, 3, 3, 1) oled.show() # 执行绘图 oled.fill(0) draw_line_chart(sensor_data)
2. 柱状图
用矩形块展示单组数据的分布:
def draw_bar_chart(data, x_start=5, y_start=5, width=118, height=54): data_min = min(data) data_max = max(data) bar_width = width // len(data) - 2 # 柱子间留空隙 for idx, val in enumerate(data): bar_height = int(((val - data_min) / (data_max - data_min)) * height) x = x_start + idx * (bar_width + 2) y = y_start + height - bar_height oled.fill_rect(x, y, bar_width, bar_height, 1) oled.show() # 执行绘图 oled.fill(0) draw_bar_chart(sensor_data)
三、常用数据计算示例
结合Python基础语法实现统计计算,可将结果与图表同屏显示:
# 计算平均值 def calc_average(data): return sum(data) / len(data) # 计算方差 def calc_variance(data): avg = calc_average(data) return sum((x - avg)**2 for x in data) / len(data) # 示例:显示计算结果+折线图 avg_val = calc_average(sensor_data) var_val = calc_variance(sensor_data) oled.fill(0) oled.text(f"Avg: {avg_val:.1f}", 0, 0) oled.text(f"Var: {var_val:.1f}", 0, 10) draw_line_chart(sensor_data, y_start=20) oled.show()
四、优化技巧
- 减少全屏刷新:仅更新图表区域而非整个屏幕,降低资源消耗;
- 控制刷新频率:数据采集频率过高时,间隔1-2秒刷新一次即可;
- 缓存计算结果:周期性采集的数据可缓存坐标映射结果,避免重复计算;
- 异常处理:提前判断数据为空、数值溢出等情况,避免程序崩溃。
内容的提问来源于stack exchange,提问作者Mr.Programmer
相关产品推荐
相关产品推荐

