⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tft_lcd.c

📁 STM32手持式示波器源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
* Copyright (C), 2009-2010, www.armfly.com
*
* 文件名: tft_lcd.c
* 内容简述: 本模块包含TFT LCD显示器的驱动函数。
*
*	安富莱开发板标配的TFT显示器的驱动芯片为 SPFD5420A,分辨率为400x240
*	驱动芯片的访问地址为
*		(1) 0x60000000
*
* 文件历史:
* 版本号  日期       作者    说明
* v0.1    2010-01-02 armfly  创建该文件
*
*/

#include "stm32f10x.h"
#include <stdio.h>
#include "systick.h"
#include "tft_lcd.h"
#include "fonts.h"

typedef struct
{
	__IO uint16_t LCD_REG;
	__IO uint16_t LCD_RAM;
}
LCD_TypeDef;

/* 定义LCD驱动器的访问地址 */
#define LCD_BASE        ((uint32_t)(0x60000000 | 0x0C000000))
#define LCD             ((LCD_TypeDef *) LCD_BASE)

static __IO uint16_t s_TextColor = 0x0000;
static __IO uint16_t s_BackColor = 0xFFFF;

/* armfly添加透明标志
	s_Transparent = 1 表示显示文字时,不修改背景颜色
*/
static __IO uint8_t s_Transparent = 0;

/*******************************************************************************
*	函数名: LCD_Init
*	参  数: 无
*	返  回: 无
*	功  能: 初始化TFT显示器
*/
void LCD_Init(void)
{
	/* 配置LCD控制口线GPIO */
	LCD_CtrlLinesConfig();

	/* 配置FSMC接口,数据总线 */
	LCD_FSMCConfig();

	/* FSMC重置后必须加延迟才能访问总线设备  */
	DelayMS(20);

	/* 初始化LCD,写LCD寄存器进行配置 */
	LCD_WriteReg(0x0000, 0x0000);
	LCD_WriteReg(0x0001, 0x0100);
	LCD_WriteReg(0x0002, 0x0100);

	/*
		R003H 寄存器很关键, Entry Mode ,决定了扫描方向
		参见:SPFD5420A.pdf 第15页

		240x400屏幕物理坐标(px,py)如下:
		    R003 = 0x1018                  R003 = 0x1008
		  -------------------          -------------------
		 |(0,0)              |        |(0,0)              |
		 |                   |        |
		 |  ^           ^    |        |   ^           ^   |
		 |  |           |    |        |   |           |   |
		 |  |           |    |        |   |           |   |
		 |  |           |    |        |   |           |   |
		 |  |  ------>  |    |        |   | <------   |   |
		 |  |           |    |        |   |           |   |
		 |  |           |    |        |   |           |   |
		 |  |           |    |        |   |           |   |
		 |  |           |    |        |   |           |   |
		 |                   |        |
		 |                   |        |                   |
		 |      (x=239,y=399)|        |      (x=239,y=399)|
		 |-------------------|        |-------------------|
		 |                   |        |                   |
		  -------------------          -------------------

		按照安富莱开发板LCD的方向,我们期望的虚拟坐标和扫描方向如下:(和上图第1个吻合)
		 --------------------------------
		|  |(0,0)                        |
		|  |     --------->              |
		|  |         |                   |
		|  |         |                   |
		|  |         |                   |
		|  |         V                   |
		|  |     --------->              |
		|  |                    (399,239)|
		 --------------------------------

		虚拟坐标(x,y) 和物理坐标的转换关系
		x = 399 - py;
		y = px;

		py = 399 - x;
		px = y;

	*/
	LCD_WriteReg(0x0003, 0x1018); /* 0x1018 1030 */

	LCD_WriteReg(0x0008, 0x0808);
	LCD_WriteReg(0x0009, 0x0001);
	LCD_WriteReg(0x000B, 0x0010);
	LCD_WriteReg(0x000C, 0x0000);
	LCD_WriteReg(0x000F, 0x0000);
	LCD_WriteReg(0x0007, 0x0001);
	LCD_WriteReg(0x0010, 0x0013);
	LCD_WriteReg(0x0011, 0x0501);
	LCD_WriteReg(0x0012, 0x0300);
	LCD_WriteReg(0x0020, 0x021E);
	LCD_WriteReg(0x0021, 0x0202);
	LCD_WriteReg(0x0090, 0x8000);
	LCD_WriteReg(0x0100, 0x17B0);
	LCD_WriteReg(0x0101, 0x0147);
	LCD_WriteReg(0x0102, 0x0135);
	LCD_WriteReg(0x0103, 0x0700);
	LCD_WriteReg(0x0107, 0x0000);
	LCD_WriteReg(0x0110, 0x0001);
	LCD_WriteReg(0x0210, 0x0000);
	LCD_WriteReg(0x0211, 0x00EF);
	LCD_WriteReg(0x0212, 0x0000);
	LCD_WriteReg(0x0213, 0x018F);
	LCD_WriteReg(0x0280, 0x0000);
	LCD_WriteReg(0x0281, 0x0004);
	LCD_WriteReg(0x0282, 0x0000);
	LCD_WriteReg(0x0300, 0x0101);
	LCD_WriteReg(0x0301, 0x0B2C);
	LCD_WriteReg(0x0302, 0x1030);
	LCD_WriteReg(0x0303, 0x3010);
	LCD_WriteReg(0x0304, 0x2C0B);
	LCD_WriteReg(0x0305, 0x0101);
	LCD_WriteReg(0x0306, 0x0807);
	LCD_WriteReg(0x0307, 0x0708);
	LCD_WriteReg(0x0308, 0x0107);
	LCD_WriteReg(0x0309, 0x0105);
	LCD_WriteReg(0x030A, 0x0F04);
	LCD_WriteReg(0x030B, 0x0F00);
	LCD_WriteReg(0x030C, 0x000F);
	LCD_WriteReg(0x030D, 0x040F);
	LCD_WriteReg(0x030E, 0x0300);
	LCD_WriteReg(0x030F, 0x0701);
	LCD_WriteReg(0x0400, 0x3500);
	LCD_WriteReg(0x0401, 0x0001);
	LCD_WriteReg(0x0404, 0x0000);
	LCD_WriteReg(0x0500, 0x0000);
	LCD_WriteReg(0x0501, 0x0000);
	LCD_WriteReg(0x0502, 0x0000);
	LCD_WriteReg(0x0503, 0x0000);
	LCD_WriteReg(0x0504, 0x0000);
	LCD_WriteReg(0x0505, 0x0000);
	LCD_WriteReg(0x0600, 0x0000);
	LCD_WriteReg(0x0606, 0x0000);
	LCD_WriteReg(0x06F0, 0x0000);
	LCD_WriteReg(0x07F0, 0x5420);
	LCD_WriteReg(0x07DE, 0x0000);
	LCD_WriteReg(0x07F2, 0x00DF);
	LCD_WriteReg(0x07F3, 0x0810);
	LCD_WriteReg(0x07F4, 0x0077);
	LCD_WriteReg(0x07F5, 0x0021);
	LCD_WriteReg(0x07F0, 0x0000);
	LCD_WriteReg(0x0007, 0x0173);

	/* 设置显示窗口 WINDOWS */
	LCD_WriteReg(0x0210, 0);	/* 水平起始地址 */
	LCD_WriteReg(0x0211, 239);	/* 水平结束坐标 */
	LCD_WriteReg(0x0212, 0);	/* 垂直起始地址 */
	LCD_WriteReg(0x0213, 399);	/* 垂直结束地址 */
}

/*******************************************************************************
*	函数名: LCD_SetTextColor
*	参  数: Color : 文本颜色
*	返  回: 无
*	功  能: 设置文本颜色,保存在全部变量s_TextColor
*/
void LCD_SetTextColor(__IO uint16_t Color)
{
	s_TextColor = Color;
}

/*******************************************************************************
*	函数名: LCD_SetBackColor
*	参  数: Color : 背景颜色
*	返  回: 无
*	功  能: 设置背景颜色,保存在全部变量 s_BackColor
*/
void LCD_SetBackColor(__IO uint16_t Color)
{
	s_BackColor = Color;
}

/*******************************************************************************
*	函数名: LCD_ClearLine
*	参  数: Line : 文本行号0 - 9
*	返  回: 无
*	功  能: 清除选定的文本行
*/
void LCD_ClearLine(uint8_t Line)
{
	LCD_DisplayString(0, Line, "                    ");
}

/*******************************************************************************
*	函数名: LCD_Clear
*	参  数: Color : 背景色
*	返  回: 无
*	功  能: 根据输入的颜色值清屏
*/
void LCD_Clear(uint16_t Color)
{
	uint32_t index = 0;

	LCD_SetCursor(0, 0);	/* 设置光标位置 */

	LCD_WriteRAM_Prepare(); 	/* 准备写显存 */

	for (index = 0; index < 400 * 240; index++)
	{
		LCD->LCD_RAM = Color;
	}
}

/*******************************************************************************
*	函数名: LCD_SetCursor
*	参  数: Xpos : X坐标; Ypos: Y坐标
*	返  回: 无
*	功  能: 设置光标位置
*/
void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{
	/*
		px,py 是物理坐标, x,y是虚拟坐标
		转换公式:
		py = 399 - x;
		px = y;
	*/

	LCD_WriteReg(0x0200, Ypos);  		/* px */
	LCD_WriteReg(0x0201, 399 - Xpos);	/* py */
}

/*******************************************************************************
*	函数名: LCD_SetTransparent
*	参  数: _mode ; 透明标志,1表示透明 0 表示不透明
*	返  回: 无
*	功  能: 设置光标位置
*/
void LCD_SetTransparent(uint8_t _mode)
{
	if (_mode == 0)
	{
		s_Transparent = 0;	/* 设置为背景不透明 */
	}
	else
	{
		s_Transparent = 1;	/* 设置为背景透明 */
	}
}

/*******************************************************************************
*	函数名: LCD_DrawChar
*	参  数:
*		Xpos : X坐标;
*		Ypos: Y坐标;
*		c : 指向字符点阵的指针
*		width : 点阵的宽度,字符是8,汉字是16
*	返  回: 无
*	功  能: 在LCD上显示一个字符(16x24)
*/
void LCD_DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c, uint8_t width)
{
	uint32_t index = 0, i = 0;
	uint8_t Yaddress;

	Yaddress = Ypos;

	LCD_SetCursor(Xpos, Ypos);

	if (s_Transparent == 0)
	{
		for (index = 0; index < 16; index++)	/* 字符高度 */
		{
			LCD_WriteRAM_Prepare();
			for (i = 0; i < width; i++)	/* 字符宽度 */
			{
				if ((c[index * (width / 8) + i / 8] & (0x80 >> (i % 8))) == 0x00)
				{
					LCD_WriteRAM(s_BackColor);
				}
				else
				{
					LCD_WriteRAM(s_TextColor);
				}
			}
			Yaddress++;
			LCD_SetCursor(Xpos, Yaddress);
		}
	}
	else	/* armfly 添加:实现文字叠加在图片上的功能 */
	{
		for (index = 0; index < 16; index++)	/* 字符高度 */
		{
			uint16_t x = Xpos;

			for (i = 0; i < width; i++)	/* 字符宽度 */
			{
				if ((c[index * (width / 8) + i / 8] & (0x80 >> (i % 8))) != 0x00)
				{
					LCD_SetCursor(x, Yaddress);

					LCD->LCD_REG = 0x202;
					LCD->LCD_RAM = s_TextColor;
				}
				x++;
			}
			Yaddress++;
		}
	}
}

/*******************************************************************************
*	函数名: LCD_DisplayString
*	参  数:
*		Xpos : X坐标 0 - 399
*		Ypos : Y坐标 0 - 239
*		ptr  : 字符串指针;
*	返  回: 无
*	功  能: 在LCD指定文本行显示一个字符串
*/
void LCD_DisplayString(uint16_t Xpos, uint16_t Ypos, uint8_t *ptr)
{
	uint32_t i = 0;
	uint8_t code1;
	uint8_t code2;
	uint32_t address;
	uint32_t k;


	while ((*ptr != 0) & (i < 50))
	{
		code1 = *ptr;	/* ascii代码 或者汉字代码的高字节 */
		if (code1 < 0x80)
		{
			LCD_DrawChar(Xpos, Ypos, &Ascii16[code1 * 16], 8);	/* 16 表示1个字符字模的字节数 */
			Xpos += 8;		/* 列地址+8 */
		}
		else	/* 汉字内码 */
		{
			code2 = *++ptr;
			if (code2 == 0)
			{
				break;
			}

			/* 计算16点阵汉字点阵地址
				ADDRESS = [(code1-0xa1) * 94 + (code2-0xa1)] * 32
				;
			*/
			#ifdef USE_SMALL_FONT
				for (k = 0; k < HZ_COUNT; k++)
				{
					address = k * 34;

					if ((code1 == g_Hz16[address + 0]) && (code2 == g_Hz16[address + 1]))
					{
						address += 2;
						break;
					}				
				}
			    address = (uint32_t)&g_Hz16[address];
			#else
				address = ((code1-0xa1) * 94 + (code2-0xa1)) * 32 + HZK16_ADDR;
			#endif

			LCD_DrawChar(Xpos, Ypos, (const uint8_t *)address, 16);
			Xpos += 16;		/* 列地址+16 */
		}
		ptr++;			/* 指向下一个字符 */
		i++;
	}
}

/*******************************************************************************
*	函数名: LCD_SetDisplayWindow
*	参  数:
*		Xpos : 显示行号
*		Ypos  : 字符串指针;
*		Height: 窗口高度
*		Width : 窗口宽度
*	返  回: 无
*	功  能: 设置显示窗口
*/
void LCD_SetDisplayWindow(uint16_t Xpos, uint16_t Ypos, uint16_t Height, uint16_t Width)
{
	/* 水平起始地址 */
	if (Xpos >= Height)
	{
		LCD_WriteReg(R80, (Xpos - Height + 1));
	}
	else
	{
		LCD_WriteReg(R80, 0);
	}

	/* 水平结束地址 */
	LCD_WriteReg(R81, Xpos);

	/* 垂直起始地址 */
	if (Ypos >= Width)
	{
		LCD_WriteReg(R82, (Ypos - Width + 1));
	}
	else
	{
		LCD_WriteReg(R82, 0);
	}

	/* 垂直结束地址 */
	LCD_WriteReg(R83, Ypos);

	LCD_SetCursor(Xpos, Ypos);
}

/*******************************************************************************
*	函数名: LCD_WindowModeDisable
*	参  数: 无
*	返  回: 无
*	功  能: 退出窗口显示模式,变为全屏显示模式
*/
void LCD_WindowModeDisable(void)
{
	LCD_SetDisplayWindow(239, 399, 240, 400);
	LCD_WriteReg(R3, 0x1018);	/* 这个寄存器改变扫描方向 */
}

/*******************************************************************************
*	函数名: LCD_PutPixel
*	参  数: x,y : 像素坐标
*			Color : 像素颜色
*	返  回: 无
*	功  能: 画1个像素
*/
void LCD_PutPixel(uint16_t x, uint16_t y, uint16_t Color)
{
	LCD_SetCursor(x, y);	/* 设置光标位置 */

	LCD_WriteRAM1(Color);
}

/*******************************************************************************
*	函数名: BresenhamLine
*	参  数: x1, y1 :起始点坐标
*			x2, y2 :终止点Y坐标
*			Length    :长度
*			Direction :方向(Horizontal,Vertical)
*	返  回: 无
*	功  能: 在两点间画一条直线。
*/
void LCD_BresenhamLine (uint16_t x1 , uint16_t y1 , uint16_t x2 , uint16_t y2 , int c)
{
	int dx , dy ;
	int tx , ty ;
	int inc1 , inc2 ;
	int d , iTag ;
	int x , y ;

	LCD_PutPixel(x1 , y1 , c);

	/* 如果两点重合,结束后面的动作。*/
	if ( x1 == x2 && y1 == y2 )
	{
		return;
	}

	iTag = 0 ;
	/* dx = abs ( x2 - x1 ); */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -