based-on-stm32-taxi-meter/Bootloader/Core/Src/ili9341.c
2024-05-02 14:03:11 +08:00

494 lines
15 KiB
C
Raw Permalink 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.

/**
******************************************************************************
* @文件名 : 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++;
}
}