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坐标。具体实现步骤如下:
- 调用
LCD_Write_Cursor
函数,将光标位置设置为给定的X坐标和Y坐标。 - 调用
LCD_Write_COM
函数,设置开始写入GRAM。 - 调用
HAL_SRAM_Write_16b
函数,向LCD写入16位数据。该数据即为前景色ForeColor
。通过指定的句柄&hsram1
、指令类型LCD_DAT
以及存放寄存器&ForeColor
,写入1个数据。
绘制线段函数
绘制算法理解参考:Bresenham算法理解-CSDN博客
变量介绍:
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
:当前绘制点的坐标。
思路介绍:
想象一下,你在一张大纸上画一条直线,从一点(我们称之为起点)画到另一点(我们称之为终点)。现在,这张纸非常特别,它是由很多很多小方块组成的,每个小方块我们称之为“像素”。我们的任务就是用彩色笔在这些像素上画线,确保我们的直线只穿过这些小方块的中心,而不碰到方块的边缘。
-
第一步:确定起点和终点
首先,我们需要知道起点
(x1, y1)
和终点(x2, y2)
的坐标。这就像是告诉你从纸上的哪个角落开始画,以及在哪里停止。 -
第二步:看看我们要走多远
接下来,我们计算从起点到终点在左右(x方向)和上下(y方向)上各要走多远。这就像是量一下从开始到结束需要走多长的路。代码中用
delta_x
来表示左右的距离,用delta_y
来表示上下的距离。 -
第三步:决定我们朝哪个方向走
我们知道了要去哪里,现在要决定怎么走。如果终点在起点的右边,我们就向右走;如果在左边,我们就向左走。同样的,如果终点在起点的上面,我们就向上走;如果在下面,我们就向下走。代码中用
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转换成正数 }
-
第四步:选择主要的画线方向
我们决定是主要沿着x方向(左右)画线,还是沿着y方向(上下)画线。这取决于左右距离和上下距离哪个更长。这个距离我们称之为
distance
。if (delta_x > delta_y) distance = delta_x; // 如果x方向的距离更远,我们就以x为基准 else distance = delta_y; // 否则以y为基准
-
第五步:开始画线
现在,我们开始画线。我们从起点开始,一小步一小步地移动。每一步,我们都检查一下:“我现在是不是应该转向,开始画下一部分线了?”这个“转向”的决定是基于我们左右和上下的移动距离。
-
第六步:决定下一步怎么走
我们用两个“尺子”(变量
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坐标 } }
-
第七步:重复步骤五和六
我们重复第五步和第六步,直到我们的线从起点画到了终点。
-
第八步:完成画作
当我们到达终点时,我们就完成了整条直线的绘制。
绘制圆形
【计算机图形学】中点画圆算法和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
函数绘制四条线段,构成矩形的四个边:- 从(
x1
,y1
)到(x2
,y1
)的上边 - 从(
x1
,y1
)到(x1
,y2
)的左边 - 从(
x1
,y2
)到(x2
,y2
)的下边 - 从(
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位颜色数据,重复执行直到填充整个矩形区域。