Files
TencentOS-tiny/board/ALIENTEK_Pandora_STM32L475/BSP/Hardware/LCD/lcd.c
2019-09-26 14:35:02 +08:00

800 lines
17 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "mcu_init.h"
#include "font.h"
#include "cmsis_os.h"
/*********************************************************************************
___ _ _____ _____ _ _ _____ _____ _ __
/ _ \ | | |_ _|| ___|| \ | ||_ _|| ___|| | / /
/ /_\ \| | | | | |__ | \| | | | | |__ | |/ /
| _ || | | | | __| | . ` | | | | __| | \
| | | || |_____| |_ | |___ | |\ | | | | |___ | |\ \
\_| |_/\_____/\___/ \____/ \_| \_/ \_/ \____/ \_| \_/
* ******************************************************************************
* 本程序只供学习使用,未经作者许可,不得用于其它任何用途
* ALIENTEK Pandora STM32L475 IOT开发板
* LCD TFT驱动代码
* 正点原子@ALIENTEK
* 技术论坛:www.openedv.com
* 创建日期:2018/10/27
* 版本V1.0
* 版权所有,盗版必究。
* Copyright(C) 广州市星翼电子科技有限公司 2014-2024
* All rights reserved
* ******************************************************************************
* 初始版本
* ******************************************************************************/
//LCD缓存大小设置修改此值时请注意修改这两个值时可能会影响以下函数 LCD_Clear/LCD_Fill/LCD_DrawLine
#define LCD_TOTAL_BUF_SIZE (240 * 240 * 2)
#define LCD_Buf_Size 1152
static uint8_t lcd_buf[LCD_Buf_Size];
uint16_t POINT_COLOR = BLACK; //画笔颜色 默认为黑色
uint16_t BACK_COLOR = WHITE; //背景颜色 默认为白色
/**
* @brief LCD控制接口初始化
*
* @param void
*
* @return void
*/
static void LCD_Gpio_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/*
LCD_PWR: PB7
LCD_RST: PB6
LCD_DC: PB4
LCD_CS: PD7
*/
GPIO_InitStruct.Pin = GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_7, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = GPIO_PIN_7;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_7, GPIO_PIN_RESET);
LCD_CS(0);
LCD_PWR(0);
LCD_RST(0);
HAL_Delay(120);
LCD_RST(1);
}
/**
* @brief LCD底层SPI发送数据函数
*
* @param data 数据的起始地址
* @param size 发送数据大小
*
* @return void
*/
static void LCD_SPI_Send(uint8_t *data, uint16_t size)
{
HAL_SPI_Transmit(&hspi3,data,size,1000);
}
/**
* @brief 写命令到LCD
*
* @param cmd 需要发送的命令
*
* @return void
*/
static void LCD_Write_Cmd(uint8_t cmd)
{
LCD_DC(0);
LCD_SPI_Send(&cmd, 1);
}
/**
* @brief 写数据到LCD
*
* @param cmd 需要发送的数据
*
* @return void
*/
static void LCD_Write_Data(uint8_t data)
{
LCD_DC(1);
LCD_SPI_Send(&data, 1);
}
/**
* @brief 写半个字的数据到LCD
*
* @param cmd 需要发送的数据
*
* @return void
*/
void LCD_Write_HalfWord(const uint16_t da)
{
uint8_t data[2] = {0};
data[0] = da >> 8;
data[1] = da;
LCD_DC(1);
LCD_SPI_Send(data, 2);
}
/**
* 设置数据写入LCD缓存区域
*
* @param x1,y1 起点坐标
* @param x2,y2 终点坐标
*
* @return void
*/
void LCD_Address_Set(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
LCD_Write_Cmd(0x2a);
LCD_Write_Data(x1 >> 8);
LCD_Write_Data(x1);
LCD_Write_Data(x2 >> 8);
LCD_Write_Data(x2);
LCD_Write_Cmd(0x2b);
LCD_Write_Data(y1 >> 8);
LCD_Write_Data(y1);
LCD_Write_Data(y2 >> 8);
LCD_Write_Data(y2);
LCD_Write_Cmd(0x2C);
}
/**
* 打开LCD显示
*
* @param void
*
* @return void
*/
void LCD_DisplayOn(void)
{
LCD_PWR(1);
}
/**
* 关闭LCD显示
*
* @param void
*
* @return void
*/
void LCD_DisplayOff(void)
{
LCD_PWR(0);
}
/**
* 以一种颜色清空LCD屏
*
* @param color 清屏颜色
*
* @return void
*/
void LCD_Clear(uint16_t color)
{
uint16_t i, j;
uint8_t data[2] = {0};
data[0] = color >> 8;
data[1] = color;
LCD_Address_Set(0, 0, LCD_Width - 1, LCD_Height - 1);
for (j = 0; j < LCD_Buf_Size / 2; j++)
{
lcd_buf[j * 2] = data[0];
lcd_buf[j * 2 + 1] = data[1];
}
LCD_DC(1);
for (i = 0; i < (LCD_TOTAL_BUF_SIZE / LCD_Buf_Size); i++)
{
LCD_SPI_Send(lcd_buf, LCD_Buf_Size);
}
}
/**
* 用一个颜色填充整个区域
*
* @param x_start,y_start 起点坐标
* @param x_end,y_end 终点坐标
* @param color 填充颜色
*
* @return void
*/
void LCD_Fill(uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end, uint16_t color)
{
uint16_t i = 0;
uint32_t size = 0, size_remain = 0;
size = (x_end - x_start + 1) * (y_end - y_start + 1) * 2;
if (size > LCD_Buf_Size)
{
size_remain = size - LCD_Buf_Size;
size = LCD_Buf_Size;
}
LCD_Address_Set(x_start, y_start, x_end, y_end);
while (1)
{
for (i = 0; i < size / 2; i++)
{
lcd_buf[2 * i] = color >> 8;
lcd_buf[2 * i + 1] = color;
}
LCD_DC(1);
LCD_SPI_Send(lcd_buf, size);
if (size_remain == 0)
break;
if (size_remain > LCD_Buf_Size)
{
size_remain = size_remain - LCD_Buf_Size;
}
else
{
size = size_remain;
size_remain = 0;
}
}
}
/**
* 画点函数
*
* @param x,y 画点坐标
*
* @return void
*/
void LCD_Draw_Point(uint16_t x, uint16_t y)
{
LCD_Address_Set(x, y, x, y);
LCD_Write_HalfWord(POINT_COLOR);
}
/**
* 画点带颜色函数
*
* @param x,y 画点坐标
*
* @return void
*/
void LCD_Draw_ColorPoint(uint16_t x, uint16_t y, uint16_t color)
{
LCD_Address_Set(x, y, x, y);
LCD_Write_HalfWord(color);
}
/**
* @brief 画线函数(直线、斜线)
*
* @param x1,y1 起点坐标
* @param x2,y2 终点坐标
*
* @return void
*/
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
uint16_t t;
int xerr = 0, yerr = 0, delta_x, delta_y, distance;
int incx, incy, row, col;
uint32_t i = 0;
if (y1 == y2)
{
/*快速画水平线*/
LCD_Address_Set(x1, y1, x2, y2);
for (i = 0; i < x2 - x1; i++)
{
lcd_buf[2 * i] = POINT_COLOR >> 8;
lcd_buf[2 * i + 1] = POINT_COLOR;
}
LCD_DC(1);
LCD_SPI_Send(lcd_buf, (x2 - x1) * 2);
return;
}
delta_x = x2 - x1;
delta_y = y2 - y1;
row = x1;
col = y1;
if (delta_x > 0)
incx = 1;
else if (delta_x == 0)
incx = 0;
else
{
incx = -1;
delta_x = -delta_x;
}
if (delta_y > 0)
incy = 1;
else if (delta_y == 0)
incy = 0;
else
{
incy = -1;
delta_y = -delta_y;
}
if (delta_x > delta_y)
distance = delta_x;
else
distance = delta_y;
for (t = 0; t <= distance + 1; t++)
{
LCD_Draw_Point(row, col);
xerr += delta_x;
yerr += delta_y;
if (xerr > distance)
{
xerr -= distance;
row += incx;
}
if (yerr > distance)
{
yerr -= distance;
col += incy;
}
}
}
/**
* @brief 画一个矩形
*
* @param x1,y1 起点坐标
* @param x2,y2 终点坐标
*
* @return void
*/
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
LCD_DrawLine(x1, y1, x2, y1);
LCD_DrawLine(x1, y1, x1, y2);
LCD_DrawLine(x1, y2, x2, y2);
LCD_DrawLine(x2, y1, x2, y2);
}
/**
* @brief 画一个圆
*
* @param x0,y0 圆心坐标
* @param r 圆半径
*
* @return void
*/
void LCD_Draw_Circle(uint16_t x0, uint16_t y0, uint8_t r)
{
int a, b;
int di;
a = 0;
b = r;
di = 3 - (r << 1);
while (a <= b)
{
LCD_Draw_Point(x0 - b, y0 - a);
LCD_Draw_Point(x0 + b, y0 - a);
LCD_Draw_Point(x0 - a, y0 + b);
LCD_Draw_Point(x0 - b, y0 - a);
LCD_Draw_Point(x0 - a, y0 - b);
LCD_Draw_Point(x0 + b, y0 + a);
LCD_Draw_Point(x0 + a, y0 - b);
LCD_Draw_Point(x0 + a, y0 + b);
LCD_Draw_Point(x0 - b, y0 + a);
a++;
if (di < 0)
di += 4 * a + 6;
else
{
di += 10 + 4 * (a - b);
b--;
}
LCD_Draw_Point(x0 + a, y0 + b);
}
}
/**
* @brief 显示一个ASCII码字符
*
* @param x,y 显示起始坐标
* @param chr 需要显示的字符
* @param size 字体大小(支持16/24/32号字体)
*
* @return void
*/
void LCD_ShowChar(uint16_t x, uint16_t y, char chr, uint8_t size)
{
uint8_t temp, t1, t;
uint8_t csize; //得到字体一个字符对应点阵集所占的字节数
uint16_t colortemp;
uint8_t sta;
chr = chr - ' '; //得到偏移后的值ASCII字库是从空格开始取模所以-' '就是对应字符的字库)
if ((x > (LCD_Width - size / 2)) || (y > (LCD_Height - size)))
return;
LCD_Address_Set(x, y, x + size / 2 - 1, y + size - 1); //(x,y,x+8-1,y+16-1)
if ((size == 16) || (size == 32)) //16和32号字体
{
csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2);
for (t = 0; t < csize; t++)
{
if (size == 16)
temp = asc2_1608[chr][t]; //调用1608字体
else if (size == 32)
temp = asc2_3216[chr][t]; //调用3216字体
else
return; //没有的字库
for (t1 = 0; t1 < 8; t1++)
{
if (temp & 0x80)
colortemp = POINT_COLOR;
else
colortemp = BACK_COLOR;
LCD_Write_HalfWord(colortemp);
temp <<= 1;
}
}
}
else if (size == 12) //12号字体
{
csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2);
for (t = 0; t < csize; t++)
{
temp = asc2_1206[chr][t];
for (t1 = 0; t1 < 6; t1++)
{
if (temp & 0x80)
colortemp = POINT_COLOR;
else
colortemp = BACK_COLOR;
LCD_Write_HalfWord(colortemp);
temp <<= 1;
}
}
}
else if (size == 24) //24号字体
{
csize = (size * 16) / 8;
for (t = 0; t < csize; t++)
{
temp = asc2_2412[chr][t];
if (t % 2 == 0)
sta = 8;
else
sta = 4;
for (t1 = 0; t1 < sta; t1++)
{
if (temp & 0x80)
colortemp = POINT_COLOR;
else
colortemp = BACK_COLOR;
LCD_Write_HalfWord(colortemp);
temp <<= 1;
}
}
}
}
/**
* @brief m^n函数
*
* @param m,n 输入参数
*
* @return m^n次方
*/
static uint32_t LCD_Pow(uint8_t m, uint8_t n)
{
uint32_t result = 1;
while (n--)
result *= m;
return result;
}
/**
* @brief 显示数字,高位为0不显示
*
* @param x,y 起点坐标
* @param num 需要显示的数字,数字范围(0~4294967295)
* @param len 需要显示的位数
* @param size 字体大小
*
* @return void
*/
void LCD_ShowNum(uint16_t x, uint16_t y, uint32_t num, uint8_t len, uint8_t size)
{
uint8_t t, temp;
uint8_t enshow = 0;
for (t = 0; t < len; t++)
{
temp = (num / LCD_Pow(10, len - t - 1)) % 10;
if (enshow == 0 && t < (len - 1))
{
if (temp == 0)
{
LCD_ShowChar(x + (size / 2) * t, y, ' ', size);
continue;
}
else
enshow = 1;
}
LCD_ShowChar(x + (size / 2) * t, y, temp + '0', size);
}
}
/**
* @brief 显示数字,高位为0,可以控制显示为0还是不显示
*
* @param x,y 起点坐标
* @param num 需要显示的数字,数字范围(0~999999999)
* @param len 需要显示的位数
* @param size 字体大小
* @param mode 1:高位显示0 0:高位不显示
*
* @return void
*/
void LCD_ShowxNum(uint16_t x, uint16_t y, uint32_t num, uint8_t len, uint8_t size, uint8_t mode)
{
uint8_t t, temp;
uint8_t enshow = 0;
for (t = 0; t < len; t++)
{
temp = (num / LCD_Pow(10, len - t - 1)) % 10;
if (enshow == 0 && t < (len - 1))
{
if (temp == 0)
{
if (mode)
LCD_ShowChar(x + (size / 2) * t, y, '0', size);
else
LCD_ShowChar(x + (size / 2) * t, y, ' ', size);
continue;
}
else
enshow = 1;
}
LCD_ShowChar(x + (size / 2) * t, y, temp + '0', size);
}
}
/**
* @brief 显示字符串
*
* @param x,y 起点坐标
* @param width 字符显示区域宽度
* @param height 字符显示区域高度
* @param size 字体大小
* @param p 字符串起始地址
*
* @return void
*/
void LCD_ShowString(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t size, char *p)
{
uint8_t x0 = x;
width += x;
height += y;
while ((*p <= '~') && (*p >= ' ')) //判断是不是非法字符!
{
if (x >= width)
{
x = x0;
y += size;
}
if (y >= height)
break; //退出
LCD_ShowChar(x, y, *p, size);
x += size / 2;
p++;
}
}
/**
* @brief 显示图片
*
* @remark Image2Lcd取模方式 C语言数据/水平扫描/16位真彩色(RGB565)/高位在前 其他的不要选
*
* @param x,y 起点坐标
* @param width 图片宽度
* @param height 图片高度
* @param p 图片缓存数据起始地址
*
* @return void
*/
void LCD_Show_Image(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint8_t *p)
{
if (x + width > LCD_Width || y + height > LCD_Height)
{
return;
}
LCD_Address_Set(x, y, x + width - 1, y + height - 1);
LCD_DC(1);
LCD_SPI_Send((uint8_t *)p, width * height * 2);
}
/**
* @brief LCD初始化
*
* @param void
*
* @return void
*/
void LCD_Init(void)
{
LCD_Gpio_Init();
LCD_CS(0);
LCD_PWR(0);
LCD_RST(0);
HAL_Delay(120);
LCD_RST(1);
HAL_Delay(120);
/* Sleep Out */
LCD_Write_Cmd(0x11);
/* wait for power stability */
HAL_Delay(120);
/* Memory Data Access Control */
LCD_Write_Cmd(0x36);
LCD_Write_Data(0x00);
/* RGB 5-6-5-bit */
LCD_Write_Cmd(0x3A);
LCD_Write_Data(0x65);
/* Porch Setting */
LCD_Write_Cmd(0xB2);
LCD_Write_Data(0x0C);
LCD_Write_Data(0x0C);
LCD_Write_Data(0x00);
LCD_Write_Data(0x33);
LCD_Write_Data(0x33);
/* Gate Control */
LCD_Write_Cmd(0xB7);
LCD_Write_Data(0x72);
/* VCOM Setting */
LCD_Write_Cmd(0xBB);
LCD_Write_Data(0x3D); //Vcom=1.625V
/* LCM Control */
LCD_Write_Cmd(0xC0);
LCD_Write_Data(0x2C);
/* VDV and VRH Command Enable */
LCD_Write_Cmd(0xC2);
LCD_Write_Data(0x01);
/* VRH Set */
LCD_Write_Cmd(0xC3);
LCD_Write_Data(0x19);
/* VDV Set */
LCD_Write_Cmd(0xC4);
LCD_Write_Data(0x20);
/* Frame Rate Control in Normal Mode */
LCD_Write_Cmd(0xC6);
LCD_Write_Data(0x0F); //60MHZ
/* Power Control 1 */
LCD_Write_Cmd(0xD0);
LCD_Write_Data(0xA4);
LCD_Write_Data(0xA1);
/* Positive Voltage Gamma Control */
LCD_Write_Cmd(0xE0);
LCD_Write_Data(0xD0);
LCD_Write_Data(0x04);
LCD_Write_Data(0x0D);
LCD_Write_Data(0x11);
LCD_Write_Data(0x13);
LCD_Write_Data(0x2B);
LCD_Write_Data(0x3F);
LCD_Write_Data(0x54);
LCD_Write_Data(0x4C);
LCD_Write_Data(0x18);
LCD_Write_Data(0x0D);
LCD_Write_Data(0x0B);
LCD_Write_Data(0x1F);
LCD_Write_Data(0x23);
/* Negative Voltage Gamma Control */
LCD_Write_Cmd(0xE1);
LCD_Write_Data(0xD0);
LCD_Write_Data(0x04);
LCD_Write_Data(0x0C);
LCD_Write_Data(0x11);
LCD_Write_Data(0x13);
LCD_Write_Data(0x2C);
LCD_Write_Data(0x3F);
LCD_Write_Data(0x44);
LCD_Write_Data(0x51);
LCD_Write_Data(0x2F);
LCD_Write_Data(0x1F);
LCD_Write_Data(0x1F);
LCD_Write_Data(0x20);
LCD_Write_Data(0x23);
/* Display Inversion On */
LCD_Write_Cmd(0x21);
LCD_Write_Cmd(0x29);
LCD_Address_Set(0, 0, LCD_Width - 1, LCD_Height - 1);
LCD_Clear(WHITE);
/*打开显示*/
LCD_DisplayOn();
}