通过OLED显示电流曲线图,可以更直观地观测电流的变化情况
1、平滑滚动显示ADC曲线函数(点间距4像素)
主要的思路是用画线的方式擦除之前屏幕的线段,再绘制上新的线段。
没有使用显示缓冲,为了减少闪烁,直接在屏幕擦点,画点
OLED_DrawPixe、OLED_DrawLine、OLED_ClearLine函数均已重写为在在屏幕上直接绘制。
static uint8_t prev_point_count = 0; // 上一次的点数(用于清除旧线)
参数adc_value:采集的电流值
void Draw_ADCCurve_4px_Scroll(uint16_t adc_value) { static uint8_t y_buffer[MAX_POINTS]; // 存储历史Y坐标 static uint8_t point_count = 0; // 已存储的点数 static uint8_t start_index = 0; // 起始索引(用于滚动) // 计算当前Y坐标 uint8_t current_y = OLED_HEIGHT - 1 - (adc_value * (OLED_HEIGHT - 1)) / ADC_MAX; // 存储当前点 if(point_count < MAX_POINTS) { y_buffer[point_count] = current_y; point_count++; } else { // 缓冲区已满,滚动显示 for(uint8_t i = 0; i < MAX_POINTS - 1; i++) { y_buffer[i] = y_buffer[i+1]; } y_buffer[MAX_POINTS-1] = current_y; } // 清除旧线,画上新线 if(prev_point_count > 1) { for(uint8_t i = 0; i < prev_point_count-1; i++) { uint8_t x1 = i * POINT_INTERVAL; uint8_t x2 = (i + 1) * POINT_INTERVAL; uint8_t y1 = y_buffer[i]; uint8_t y2 = y_buffer[i + 1]; // 清除旧线 OLED_ClearLine(x1, y1, x2, y2); if(i<prev_point_count-2) { y1=y_buffer[i + 1]; y2 = y_buffer[i + 2]; OLED_DrawLine(x1, y1, x2, y2); } } } // 更新上一次的点数 prev_point_count = point_count; }
2、OLED_DrawPixel函数
参数:color 1:画点;2:檫除
// 绘制像素点 void OLED_DrawPixel(uint8_t x, uint8_t y, uint8_t color) { if(x >= 128 || y >= 64) return; uint8_t page = y / 8; uint8_t mask = 1 << (y % 8); OLED_SetCursor(x, page); uint8_t data; // 这里需要读取当前数据,修改后再写回 // 由于I2C OLED通常不支持读取,需要维护一个显示缓冲区 if(color) { data |= mask; } else { data &= ~mask; } OLED_WriteData(data); }
3、OLED_DrawLine函数
/** * @brief 清除两点之间的线段 */ void OLED_DrawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) { // 简单实现:逐点清除 if(x1 == x2) { // 垂直线 uint8_t y_start = (y1 < y2) ? y1 : y2; uint8_t y_end = (y1 < y2) ? y2 : y1; for(uint8_t y = y_start; y <= y_end; y++) { //OLED_DrawPoint(x1, y); OLED_DrawPixel(x1,y,1); } } else { // 非垂直线,使用Bresenham算法 int dx = abs(x2 - x1); int dy = abs(y2 - y1); int sx = (x1 < x2) ? 1 : -1; int sy = (y1 < y2) ? 1 : -1; int err = dx - dy; while(1) { //OLED_DrawPoint(x1, y1); OLED_DrawPixel(x1,y1,1); if(x1 == x2 && y1 == y2) break; int e2 = 2 * err; if(e2 > -dy) { err -= dy; x1 += sx; } if(e2 < dx) { err += dx; y1 += sy; } } } }
4、调用
float current = INA219_ReadCurrent(); if(Cur_Page==0)//曲线页 { //绘制曲线图 Draw_ADCCurve_4px_Scroll(current * 1000); HAL_Delay(200); } else if(Cur_Page==1)//文字页 { //显示电流、电压、功率的文字信息 }
https://www.bilibili.com/video/BV1qpjuzjEyb?share_source=copy_web