NT35510的LCD函数详解02(洋桃电子-触摸屏开发者笔记)

NT35510的LCD函数详解02(洋桃电子-触摸屏开发者笔记)

矢量图形绘制函数

绘制单点函数


void LCD_Vector_Point(uint16_t x,uint16_t y){//绘制单像素点(参数:X坐标,Y坐标)
	LCD_Write_Cursor(x,y);//设置光标位置
	LCD_Write_COM(SET_GRAM);//开始写入GRAM
	HAL_SRAM_Write_16b(&hsram1,LCD_DAT,&ForeColor,1);//向LCD写16位数据(句柄,指令COM/数据DAT,存放寄存器,数量)
}

void LCD_Vector_Point2(uint16_t x,uint16_t y,uint16_t COLOR){//绘制单像素点(参数:X坐标,Y坐标,颜色)
	if(LCD_ID==LCD_ID_OTM8009){//判断LCD ID OTM8009A(不同型号的指令有差异)
		LCD_Write_COM(SET_X);LCD_Write_DAT(x>>8);//写入
		LCD_Write_COM(SET_X+1);LCD_Write_DAT(x&0xFF);
		LCD_Write_COM(SET_X+2);LCD_Write_DAT(x>>8);
		LCD_Write_COM(SET_X+3);LCD_Write_DAT(x&0xFF);
		LCD_Write_COM(SET_Y);LCD_Write_DAT(y>>8);
		LCD_Write_COM(SET_Y+1);LCD_Write_DAT(y&0xFF);
		LCD_Write_COM(SET_Y+2);LCD_Write_DAT(y>>8);
		LCD_Write_COM(SET_Y+3);LCD_Write_DAT(y&0XFF);
	}else{//判断LCD ID NT35510/RM68120
		LCD_Write_COM(SET_X);LCD_Write_DAT(x>>8);//写入
		LCD_Write_COM(SET_X+1);LCD_Write_DAT(x&0xFF);
		LCD_Write_COM(SET_Y);LCD_Write_DAT(y>>8);
		LCD_Write_COM(SET_Y+1);LCD_Write_DAT(y&0xFF);
	}
	HAL_SRAM_Write_16b(&hsram1,LCD_COM,&SET_GRAM,1);//向LCD写16位数据(句柄,指令COM/数据DAT,存放寄存器,数量)
	HAL_SRAM_Write_16b(&hsram1,LCD_DAT,&COLOR,1);//向LCD写16位数据(句柄,指令COM/数据DAT,存放寄存器,数量)
}

该函数的功能是在LCD屏幕上绘制一个单像素点。函数接受两个参数,分别是像素点的X坐标和Y坐标。具体实现步骤如下:

  1. 调用LCD_Write_Cursor​函数,将光标位置设置为给定的X坐标和Y坐标。
  2. 调用LCD_Write_COM​函数,设置开始写入GRAM。
  3. 调用HAL_SRAM_Write_16b​函数,向LCD写入16位数据。该数据即为前景色ForeColor​。通过指定的句柄&hsram1​、指令类型LCD_DAT​以及存放寄存器&ForeColor​,写入1个数据。

绘制线段函数

绘制算法理解参考:Bresenham算法理解-CSDN博客

graph TD A[开始] --> B[初始化参数x1, y1, x2, y2] B --> C[计算增量delta_x = x2 - x1] B --> D[计算增量delta_y = y2 - y1] B --> E[设置初始位置uRow = x1, uCol = y1] C --> F D --> F E --> F F --> G[确定x方向增量incx] F --> H[确定y方向增量incy] G --> I{delta_x > 0?} G --> J{delta_x == 0?} G --> K[delta_x < 0] I --> L[incx = 1] J --> M[incx = 0] K --> N[incx = -1<br>delta_x = -delta_x] H --> O{delta_y > 0?} H --> P{delta_y == 0?} H --> Q[delta_y < 0] O --> R[incy = 1] P --> S[incy = 0] Q --> T[incy = -1<br>delta_y = -delta_y] L --> U M --> U N --> U R --> U S --> U T --> U U --> V[确定主增量轴distance] V --> W{delta_x > delta_y?} W -- 是 --> X[distance = delta_x] W -- 否 --> Y[distance = delta_y] X --> Z Y --> Z Z --> AA[初始化循环变量t = 0] Z --> AB[循环t从0到distance] AB --> AC[绘制点LCD_Vector_Point函数] AB --> AD[xerr += delta_x] AB --> AE[yerr += delta_y] AD --> AF{检查xerr是否大于distance} AE --> AG{检查yerr是否大于distance} AF -- 是 --> AH[xerr -= distance<br>uRow += incx] AF -- 否 --> AG AG -- 是 --> AI[yerr -= distance<br>uCol += incy] AG -- 否 --> AJ[继续循环] AH --> AJ AI --> AJ AJ --> AK{循环结束?} AK -- 是 --> AL[结束] AK -- 否 --> AB

变量介绍:

uint16_t t;
int xerr = 0, yerr = 0, delta_x, delta_y, distance;
int incx, incy, uRow, uCol;
  • t​:循环计数器。
  • xerr​和yerr​:用于累加误差,避免浮点数运算。
  • delta_x​和delta_y​:表示终点与起点在x和y方向上的距离(增量)。
  • distance​:主增量轴的距离,用于循环次数。
  • incx​和incy​:步长,根据直线方向确定是增加还是减少。
  • uRow​和uCol​:当前绘制点的坐标。

思路介绍:

想象一下,你在一张大纸上画一条直线,从一点(我们称之为起点)画到另一点(我们称之为终点)。现在,这张纸非常特别,它是由很多很多小方块组成的,每个小方块我们称之为“像素”。我们的任务就是用彩色笔在这些像素上画线,确保我们的直线只穿过这些小方块的中心,而不碰到方块的边缘。

  1. 第一步:确定起点和终点

    首先,我们需要知道起点(x1, y1)​和终点(x2, y2)​的坐标。这就像是告诉你从纸上的哪个角落开始画,以及在哪里停止。

  2. 第二步:看看我们要走多远

    接下来,我们计算从起点到终点在左右(x方向)和上下(y方向)上各要走多远。这就像是量一下从开始到结束需要走多长的路。代码中用delta_x​来表示左右的距离,用delta_y​来表示上下的距离。

  3. 第三步:决定我们朝哪个方向走

    我们知道了要去哪里,现在要决定怎么走。如果终点在起点的右边,我们就向右走;如果在左边,我们就向左走。同样的,如果终点在起点的上面,我们就向上走;如果在下面,我们就向下走。代码中用incx​和incy​来表示我们走的方向。

    if (delta_x > 0)
        incx = 1; // 如果终点x大于起点x,我们向右移动
    else if (delta_x == 0)
        incx = 0; // 如果x没有变化,说明是垂直线,不动x
    else
    {
        incx = -1; // 如果终点x小于起点x,我们向左移动
        delta_x = -delta_x; // 把delta_x转换成正数,方便后面的计算
    }
    if (delta_y > 0)
        incy = 1; // 如果终点y大于起点y,我们向下移动
    else if (delta_y == 0)
        incy = 0; // 如果y没有变化,说明是水平线,不动y
    else
    {
        incy = -1; // 如果终点y小于起点y,我们向上移动
        delta_y = -delta_y; // 把delta_y转换成正数
    }
    
  4. 第四步:选择主要的画线方向

    我们决定是主要沿着x方向(左右)画线,还是沿着y方向(上下)画线。这取决于左右距离和上下距离哪个更长。这个距离我们称之为 distance​。

    if (delta_x > delta_y)
        distance = delta_x; // 如果x方向的距离更远,我们就以x为基准
    else
        distance = delta_y; // 否则以y为基准
    
  5. 第五步:开始画线

    现在,我们开始画线。我们从起点开始,一小步一小步地移动。每一步,我们都检查一下:“我现在是不是应该转向,开始画下一部分线了?”这个“转向”的决定是基于我们左右和上下的移动距离。

  6. 第六步:决定下一步怎么走

    我们用两个“尺子”(变量xerr​和yerr​)来帮助我们决定下一步怎么走。如果“左右尺子”告诉我们走得太远了,我们就需要向上或向下移动一点。如果“上下尺子”告诉我们走得太远了,我们就需要向左或向右移动一点。

    在循环的每一次迭代中,我们都会先尝试在 x 方向上移动。如果 x 方向的误差 xerr​ 变得比 distance​ 大,说明我们应该转向 y 方向了。这时我们更新 x 方向的位置 uRow​,然后调整 xerr​。如果 yerr​ 也变得比 distance​ 大,我们做同样的操作更新 y 方向的位置 uCol​。

    这个过程会一直重复,直到我们完成整个 distance​ 的移动,或者画完直线。

    for (t = 0; t <= distance + 1; t++)
    {
        // 画点函数,这里画在LCD上
        LCD_Vector_Point(uRow, uCol);
    
        // 更新x方向的误差值
        xerr += delta_x;
        if (xerr > distance)
        {
            xerr -= distance; // 调整误差值
            uRow += incx;    // 根据方向增加或减少x坐标
        }
    
        // 更新y方向的误差值
        yerr += delta_y;
        if (yerr > distance)
        {
            yerr -= distance; // 调整误差值
            uCol += incy;    // 根据方向增加或减少y坐标
        }
    }
    
  7. 第七步:重复步骤五和六

    我们重复第五步和第六步,直到我们的线从起点画到了终点。

  8. 第八步:完成画作

    当我们到达终点时,我们就完成了整条直线的绘制。

绘制圆形

Bresenham 画圆算法原理-CSDN博客

【计算机图形学】中点画圆算法和Bresenham画圆算法_用中点法和bresenham法完成以下内容。 整圆的生成 算法思想-CSDN博客


void LCD_Vector_Circle(uint16_t x0, uint16_t y0, uint8_t r)
{ // 绘制矢量正圆形(参数:圆心X坐标,圆心Y坐标,半径)
	int a, b, di;
	if (x0 > r && y0 > r && x0 < (LCD_Height - r) && y0 < (LCD_Width - r))
	{ // 判断坐标+半径后不要超出绘制区域
		a = 0;
		b = r;
		di = 3 - (r << 1); // 判断下个点位置的标志
		while (a <= b)
		{									  // 使用Bresenham直线算法
			LCD_Vector_Point(x0 + a, y0 - b); //
			LCD_Vector_Point(x0 + b, y0 - a); //
			LCD_Vector_Point(x0 + b, y0 + a); //
			LCD_Vector_Point(x0 + a, y0 + b); //
			LCD_Vector_Point(x0 - a, y0 + b); //
			LCD_Vector_Point(x0 - b, y0 + a); //
			LCD_Vector_Point(x0 - a, y0 - b); //
			LCD_Vector_Point(x0 - b, y0 - a); //
			a++;
			if (di < 0)
				di += 4 * a + 6;
			else
			{
				di += 10 + 4 * (a - b);
				b--;
			}
		}
	}
}

这里不详讲了,我也不是很懂。

绘制空心矩形

void LCD_Vector_Rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{									 // 绘制矢量空心矩形(参数:左上角X,左上角Y,右下角X,右下角Y坐标)
	LCD_Vector_Line(x1, y1, x2, y1); // 调用绘制线段函数
	LCD_Vector_Line(x1, y1, x1, y2);
	LCD_Vector_Line(x1, y2, x2, y2);
	LCD_Vector_Line(x2, y1, x2, y2);
}

该函数用于在LCD屏幕上绘制一个矢量空心矩形。

  • 输入参数:

    • x1​、y1​:矩形左上角的坐标
    • x2​、y2​:矩形右下角的坐标
  • 函数内部逻辑:

    • 调用LCD_Vector_Line​函数绘制四条线段,构成矩形的四个边:

      1. 从(x1​, y1​)到(x2​, y1​)的上边
      2. 从(x1​, y1​)到(x1​, y2​)的左边
      3. 从(x1​, y2​)到(x2​, y2​)的下边
      4. 从(x2​, y1​)到(x2​, y2​)的右边

通过这四条线段的绘制,最终在LCD屏幕上呈现出一个空心矩形。

绘制实心矩形

void LCD_Vector_Rectangle_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t COLOR)
{ // 绘制矢量实心矩形(参数:左上角X,左上角Y,右下角X,右下角Y坐标,颜色)
	uint16_t i, j, xlen = 0;
	xlen = ex - sx + 1;
	for (i = sy; i <= ey; i++)
	{
		LCD_Write_Cursor(sx, i);							 // 设置光标位置
		LCD_Write_COM(SET_GRAM);							 // 开始写入GRAM
		for (j = 0; j < xlen; j++)							 // 显示颜色
			HAL_SRAM_Write_16b(&hsram1, LCD_DAT, &COLOR, 1); // 向LCD写16位数据(句柄,指令COM/数据DAT,存放寄存器,数量)
	}
}

该函数用于在LCD屏幕上绘制一个实心矩形。参数包括矩形左上角坐标(sx, sy)、右下角坐标(ex, ey)和矩形的颜色。函数通过计算矩形的宽度,然后使用两层循环来填充矩形区域的每个像素点。首先设置光标位置,然后写入GRAM,最后使用HAL_SRAM_Write_16b函数向LCD写入16位颜色数据,重复执行直到填充整个矩形区域。

  • 18
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值