这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【Let'sdo第1期-DIY功率检测与控制系统】5、过程贴:绘制电流曲线图

共1条 1/1 1 跳转至

【Let'sdo第1期-DIY功率检测与控制系统】5、过程贴:绘制电流曲线图

工程师
2025-05-25 11:12:50     打赏

通过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)//文字页
{
    //显示电流、电压、功率的文字信息
}


9.jpg


https://www.bilibili.com/video/BV1qpjuzjEyb?share_source=copy_web







关键词: Let'sdo第1期-DIY功率检测与控制系统    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]