based-on-stm32-taxi-meter/Bootloader/Core/Src/ili9341.c

494 lines
15 KiB
C
Raw Permalink Normal View History

2024-05-02 14:03:11 +08:00
/**
******************************************************************************
* @ : ili9341.c
* @ : 13552
* @brief : None
* @ : None
* @ : 2024/1/31
******************************************************************************
*/
#include "ili9341.h"
#include "lcdfont.h"
_LCD xLCD;
__inline void wrtieCmd(uint16_t usCmd) {
*ILI9341_CMD_ADDR = usCmd;
}
__inline void writeData(uint16_t usData) {
*ILI9341_DATA_ADDR = usData;
}
uint16_t readData(void) {
return (*(__IO uint16_t *)0x60020000);
}
void LCD_DisplayDir(uint8_t scanDir) {
uint16_t regval = 0;
if (scanDir == 0 || scanDir == 3) // 竖屏
{
xLCD.dir = 0;
xLCD.width = LCD_WIDTH;
xLCD.height = LCD_HIGH;
}
if (scanDir == 5 || scanDir == 6) // 横屏
{
xLCD.dir = 1;
xLCD.width = LCD_HIGH;
xLCD.height = LCD_WIDTH;
}
if (scanDir == 0) regval |= (0 << 7) | (0 << 6) | (0 << 5); // 从左到右,从上到下
if (scanDir == 3) regval |= (1 << 7) | (1 << 6) | (0 << 5); // 从右到左,从下到上
if (scanDir == 5) regval |= (0 << 7) | (1 << 6) | (1 << 5); // 从上到下,从右到左
if (scanDir == 6) regval |= (1 << 7) | (0 << 6) | (1 << 5); // 从下到上,从左到右
wrtieCmd(0X36); // 读写方向,颜色模式
writeData(regval | 0x08); //
}
void setCursor(uint16_t x, uint16_t y, uint16_t width, uint16_t height) {
wrtieCmd(0X2A); // 发送指令设置x坐标
writeData(x >> 8);
writeData(x & 0xFF);
writeData((x + width - 1) >> 8);
writeData((x + width - 1) & 0xFF);
wrtieCmd(0X2B);
writeData(y >> 8);
writeData(y & 0xFF);
writeData((y + height - 1) >> 8);
writeData((y + height - 1) & 0xFF);
// 发送写GRAM指令
wrtieCmd(0X2C);
}
void LCD_Fill(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color) {
uint32_t num = width * height;
setCursor(x, y, width, height);
while (num--)
writeData(color);
}
void ILI9341_Init(void) {
HAL_GPIO_WritePin(LCD_BK_GPIO_Port, LCD_BK_Pin, GPIO_PIN_SET);
//尝试9341 ID的读取
wrtieCmd(0XD3); // 指令读ID
readData(); // 第1个参数dummy
readData(); // 第2个参数IC版本号
xLCD.id = readData(); // 第3个参数IC名字(93)
xLCD.id <<= 8;
xLCD.id |= readData(); // 第4个参数IC名字(41)
//printf("显示屏 检测... %x\r\n",xLCD.id); // 打印LCD ID
if (xLCD.id != 0X9341) // 9341初始化失败
return; // 注意如果FSMC配置不正确有可能可显示但刷新速度慢且读取不到正确型号
// Power control B (CFh)
wrtieCmd(0xCF);
writeData(0x00);
writeData(0xC1); //-81
writeData(0x30);
// Power on sequence control (EDh)
wrtieCmd(0xED);
writeData(0x64);
writeData(0x03);
writeData(0x12);
writeData(0x81);
// Driver timing control A (E8h)
wrtieCmd(0xE8); //
writeData(0x85);
writeData(0x10);
writeData(0x7A); //-78
// Power control A (CBh)
wrtieCmd(0xCB);
writeData(0x39);
writeData(0x2C);
writeData(0x00);
writeData(0x34);
writeData(0x02);
// Pump ratio control (F7h)
wrtieCmd(0xF7);
writeData(0x20);
// Driver timing control B
wrtieCmd(0xEA);
writeData(0x00);
writeData(0x00);
// Frame Rate Control (In Normal Mode/Full Colors) (B1h) */
wrtieCmd(0xB1);
writeData(0x00);
writeData(0x1A); //-1B
// Display Function Control (B6h) */
wrtieCmd(0xB6);
writeData(0x0A);
writeData(0xA2);
// Power Control 1 (C0h)
wrtieCmd(0xC0);
writeData(0x1B); //-35
// Power Control 2 (C1h)
wrtieCmd(0xC1);
writeData(0x01); //-11
// VCOM 控制 1 (C5h)
wrtieCmd(0xC5);
writeData(0x30); // 45
writeData(0x30); // 45
// VCOM 控制 2 (C7h)
wrtieCmd(0xC7);
writeData(0xB7); //-A2
// 使能3 伽马控制 (F2h)
wrtieCmd(0xF2);
writeData(0x00);
// 伽马设置 (26h)
wrtieCmd(0x26);
writeData(0x01);
// 正极伽马校准 (E0H)
wrtieCmd(0xE0);
writeData(0x0F);
writeData(0x2A); // 26
writeData(0x28); // 24
writeData(0x08); //0B
writeData(0x0E);
writeData(0x08); // 09
writeData(0x54);
writeData(0xA9); // A8
writeData(0x43); // 46
writeData(0x0A); // 0c
writeData(0x0F); // 17
writeData(0x00); // 00
writeData(0x00); // 00
writeData(0x00); // 00
writeData(0x00);
// 负极伽马校准 (E1h)
wrtieCmd(0XE1);
writeData(0x00);
writeData(0x15); // 19
writeData(0x17); // 1B
writeData(0x07); // 04
writeData(0x11); // 10
writeData(0x06); // 07
writeData(0x2B); // 2A
writeData(0x56); // 47
writeData(0x3C); // 39
writeData(0x05); // 03
writeData(0x10); // 06
writeData(0x0F); // 06
writeData(0x3F); // 30
writeData(0x3F); // 38
writeData(0x0F); //
// 列地址设置
wrtieCmd(0x2A);
writeData(0x00);
writeData(0x00);
writeData(0x00);
writeData(0xEF);
// 页地址设置
wrtieCmd(0x2B);
writeData(0x00);
writeData(0x00);
writeData(0x01);
writeData(0x3F);
// 像素格式设置 (3Ah)
wrtieCmd(0x3a); // 像素格式设置
writeData(0x55); // 16位接口16位数据
// 退出睡眠模式 (11h)
wrtieCmd(0x11); // 等待5ms待电路稳定再执行其它指令
HAL_Delay(10);
// 打开显示(29h)
wrtieCmd(0x29); // 不会改变帧存储器数据
LCD_DisplayDir(LCD_DIR); // 设置显示方向
LCD_BK_GPIO_Port->BSRR |= LCD_BK_Pin;
LCD_Fill(0, 0, xLCD.width, xLCD.height, LCD_BGCOLOR);
xLCD.FlagInit = 1;
}
/*****************************************************************
* LCD_DrawPoint
*
* x坐标y坐标, 16
*
*
* https://demoboard.taobao.com
* Q群文件夹262901124 _2020年09月01日
******************************************************************/
void LCD_DrawPoint(uint16_t x, uint16_t y, uint16_t color) {
setCursor(x, y, 1, 1); //设置光标位置
writeData(color);
}
/*****************************************************************
* LCD_Line
* 线 ()
* xStart x坐标
* yStart y坐标
* xEnd x坐标
* yEnd y坐标
* color
*
*
* https://demoboard.taobao.com
* Q群文件夹262901124 _2020年09月01日
******************************************************************/
void LCD_Line(uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd, uint16_t color) {
uint16_t us;
uint16_t usX_Current, usY_Current;
int32_t lError_X = 0, lError_Y = 0, lDelta_X, lDelta_Y, lDistance;
int32_t lIncrease_X, lIncrease_Y;
lDelta_X = xEnd - xStart; //计算坐标增量
lDelta_Y = yEnd - yStart;
usX_Current = xStart;
usY_Current = yStart;
if (lDelta_X > 0)
lIncrease_X = 1; //设置单步方向
else if (lDelta_X == 0)
lIncrease_X = 0;//垂直线
else {
lIncrease_X = -1;
lDelta_X = -lDelta_X;
}
if (lDelta_Y > 0)
lIncrease_Y = 1;
else if (lDelta_Y == 0)
lIncrease_Y = 0;//水平线
else {
lIncrease_Y = -1;
lDelta_Y = -lDelta_Y;
}
if (lDelta_X > lDelta_Y)
lDistance = lDelta_X; //选取基本增量坐标轴
else
lDistance = lDelta_Y;
for (us = 0; us <= lDistance + 1; us++)//画线输出
{
LCD_DrawPoint(usX_Current, usY_Current, color);//画点
lError_X += lDelta_X;
lError_Y += lDelta_Y;
if (lError_X > lDistance) {
lError_X -= lDistance;
usX_Current += lIncrease_X;
}
if (lError_Y > lDistance) {
lError_Y -= lDistance;
usY_Current += lIncrease_Y;
}
}
}
/*****************************************************************
* LCD_GetPointPixel
*
* x x坐标
* y y坐标
* 16
*
* https://demoboard.taobao.com
* Q群文件夹262901124 _2020年09月01日
******************************************************************/
uint16_t LCD_GetPoint(uint16_t x, uint16_t y) {
uint16_t r = 0, g = 0, b = 0;
setCursor(x, y, 1, 1);
wrtieCmd(0x2E); // 读GRAN
r = readData(); // 第1个返回的是无效值
r = readData();
b = readData();
g = readData();
return (((r >> 11) << 11) | ((g >> 10) << 5) | (b >> 11));
}
/*****************************************************************
* LCD_DisplayOn
*
*
*
*
*
* https://demoboard.taobao.com
* Q群文件夹262901124 _2020年09月01日
******************************************************************/
void LCD_DisplayOn(void) {
wrtieCmd(0X29); //开启显示
LCD_BK_GPIO_Port->BSRR |= LCD_BK_Pin;
}
/*****************************************************************
* LCD_DisplayOff
* ,
*
*
*
*
* https://demoboard.taobao.com
* Q群文件夹262901124 _2020年09月01日
******************************************************************/
void LCD_DisplayOff(void) {
wrtieCmd(0X28); //关闭显示
LCD_BK_GPIO_Port->BSRR |= (uint32_t)LCD_BK_Pin << 16;
}
/*****************************************************************
* LCD_Rectangle
* ()
* x x坐标
* y y坐标
* width
* height
* color
* filled
*
*
* https://demoboard.taobao.com
* Q群文件夹262901124 _2020年09月01日
******************************************************************/
void LCD_Rectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color, uint8_t filled) {
if (filled) {
LCD_Fill(x, y, width, height, color);
} else {
LCD_Line(x, y, x + width - 1, y, color);
LCD_Line(x, y + height - 1, x + width - 1, y + height - 1, color);
LCD_Line(x, y, x, y + height - 1, color);
LCD_Line(x + width - 1, y, x + width - 1, y + height - 1, color);
}
}
/*****************************************************************
* LCD_Circle
* ()
* x x坐标
* y y坐标
* radius
* color
* filled
*
*
* https://demoboard.taobao.com
* Q群文件夹262901124 _2020年09月01日
******************************************************************/
void LCD_Circle(uint16_t x, uint16_t y, uint16_t radius, uint16_t color, uint8_t filled) {
int16_t sCurrentX, sCurrentY;
int16_t sError;
sCurrentX = 0;
sCurrentY = radius;
sError = 3 - (radius << 1); //判断下个点位置的标志
while (sCurrentX <= sCurrentY) {
int16_t sCountY;
if (filled)
for (sCountY = sCurrentX; sCountY <= sCurrentY; sCountY++) {
LCD_DrawPoint(x + sCurrentX, y + sCountY, color); //1研究对象
LCD_DrawPoint(x - sCurrentX, y + sCountY, color); //2
LCD_DrawPoint(x - sCountY, y + sCurrentX, color); //3
LCD_DrawPoint(x - sCountY, y - sCurrentX, color); //4
LCD_DrawPoint(x - sCurrentX, y - sCountY, color); //5
LCD_DrawPoint(x + sCurrentX, y - sCountY, color); //6
LCD_DrawPoint(x + sCountY, y - sCurrentX, color); //7
LCD_DrawPoint(x + sCountY, y + sCurrentX, color); //0
}
else {
LCD_DrawPoint(x + sCurrentX, y + sCurrentY, color); //1研究对象
LCD_DrawPoint(x - sCurrentX, y + sCurrentY, color); //2
LCD_DrawPoint(x - sCurrentY, y + sCurrentX, color); //3
LCD_DrawPoint(x - sCurrentY, y - sCurrentX, color); //4
LCD_DrawPoint(x - sCurrentX, y - sCurrentY, color); //5
LCD_DrawPoint(x + sCurrentX, y - sCurrentY, color); //6
LCD_DrawPoint(x + sCurrentY, y - sCurrentX, color); //7
LCD_DrawPoint(x + sCurrentY, y + sCurrentX, color); //0
}
sCurrentX++;
if (sError < 0)
sError += 4 * sCurrentX + 6;
else {
sError += 10 + 4 * (sCurrentX - sCurrentY);
sCurrentY--;
}
}
}
void LCD_Draw_Hline(uint16_t x, uint16_t y, uint16_t len, uint16_t color) {
if ((len == 0) || (x > xLCD.width) || (y > xLCD.height))return;
LCD_Fill(x, y, x + len - 1, y, color);
}
void LCD_Fill_Circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color) {
uint32_t i;
uint32_t imax = ((uint32_t)r * 707) / 1000 + 1;
uint32_t sqmax = (uint32_t)r * (uint32_t)r + (uint32_t)r / 2;
uint32_t xr = r;
LCD_Draw_Hline(x - r, y, 2 * r, color);
for (i = 0; i <= imax; i++) {
if ((i * i + xr * xr) > sqmax) {
if (xr > imax) {
LCD_Draw_Hline(x - i + 1, y + xr, 2 * (i - 1), color);
LCD_Draw_Hline(x - i + 1, y - xr, 2 * (i - 1), color);
}
xr--;
}
LCD_Draw_Hline(x - xr, y + i, 2 * xr, color);
LCD_Draw_Hline(x - xr, y - i, 2 * xr, color);
}
}
void LCD_Show_Char(uint16_t x, uint16_t y, char chr, uint8_t size, uint8_t mode, uint16_t color) {
uint8_t temp, t1, t;
uint16_t y0 = y;
uint8_t csize = 0;
uint8_t *pfont = 0;
csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2);
chr = chr - ' ';
switch (size) {
case 12: pfont = (uint8_t *)asc2_1206[chr];
break;
case 16: pfont = (uint8_t *)asc2_1608[chr]; /* 调用1608字体 */
break;
case 24: pfont = (uint8_t *)asc2_2412[chr]; /* 调用2412字体 */
break;
case 32: pfont = (uint8_t *)asc2_3216[chr]; /* 调用3216字体 */
break;
default: return;
}
for (t = 0; t < csize; t++) {
temp = pfont[t];
for (t1 = 0; t1 < 8; t1++) /* 一个字节8个点 */
{
if (temp & 0x80) /* 有效点,需要显示 */
{
LCD_DrawPoint(x, y, color); /* 画点出来,要显示这个点 */
} else if (mode == 0) /* 无效点,不显示 */
{
LCD_DrawPoint(x, y, LCD_BGCOLOR); /* 画背景色,相当于这个点不显示(注意背景色由全局变量控制) */
}
temp <<= 1; /* 移位, 以便获取下一个位的状态 */
y++;
if (y >= xLCD.height)return; /* 超区域了 */
if ((y - y0) == size) /* 显示完一列了? */
{
y = y0; /* y坐标复位 */
x++; /* x坐标递增 */
if (x >= xLCD.width)return; /* x坐标超区域了 */
break;
}
}
}
}
void LCD_Show_String(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t size, char *p, uint16_t color)
{
uint8_t x0 = x;
width += x;
height += y;
while ((*p <= '~') && (*p >= ' ')) /* 判断是不是非法字符! */
{
if (x >= width)
{
x = x0;
y += size;
}
if (y >= height)break; /* 退出 */
LCD_Show_Char(x, y, *p, size, 0, color);
x += size / 2;
p++;
}
}