序号 | 管脚 | 功能 |
1 | CS | TFTLCD片选信号 |
2 | WR | 向TFTLCD写入数据 |
3 | RD | 从TFTLCD读取数据 |
4 | D[15:0] | 16位双向数据线 |
5 | RST | 硬复位TFTLCD |
6 | RS | 命令/数据标志(0:读写命令;1:读写数据) |
9341总线 | D17 | D16 | D15 | D14 | D13 | D12 | D11 | D10 | D9 | D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
MCU数据线 (16位) |
D15 | D14 | D13 | D12 | D11 | NC | D10 | D9 | D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | NC |
LCD_GRAM (16位) |
R[4] | R[3] | R[2] | R[1] | R[0] | NC | G[5] | G[4] | G[3] | G[2] | G[1] | G[0] | B[4] | B[3] | B[2] | B[1] | B[0] | NC |
Bank1所选区 | 片选信号 | 地址范围 | HADDR | |
[27:26] | [25:0] | |||
第一区 | FSMC_NE1 | 0x6000 0000~0x63ff ffff | 00 | FSMC_A[25:0] |
第二区 | FSMC_NE2 | 0x6400 0000~0x67ff ffff | 01 | |
第三区 | FSMC_NE3 | 0x6800 0000~0x6Bff ffff | 10 | |
第四区 | FSMC_NE4 | 0x6c00 0000~0x6fff ffff | 11 |
Bank1接的存储器位宽 | HADDR[]和FSMC_A[]的关系 |
16 | HADDR[25:1] -> FSMC_A[24:0] |
8 | HADDR[25:0] -> FSMC_A[25:0] |
内部控制器 | 存储块 | 管理的地址范围 | 支持的设备类型 | 配置寄存器 |
NOR FLASH 控制器 |
Bank1 | 0x6000 0000~0x6fff ffff | SRAM/ROM NOR FLASH PSRAM |
FSMC_BCR 1/2/3/4 FSMC_BTR 1/2/2/3 FSMC_BWTR 1/2/3/4 |
NAND FLASH/ PC CARD 控制器 |
Bank2 | 0X7000 0000~0X7fff ffff | NAND FLASH |
FSMC_PCR 2/3/4
FSMC_SR 2/3/4
FSMC_PMEM 2/3/4
FSMC_PATT 2/3/4
FSMC_PIO 4
|
Bank3 | 0X8000 0000~0X8fff ffff | |||
Bank4 | 0X9000 0000~0X9fff ffff | PC Card |
时序模型 | 简单描述 | 需要设置的时间参数 | |
异步 | Mode1 | SRAM/ CRAM时序 | DATAST、ADDSET |
ModeA | SRAM/ CRAM OE选通时序 | DATAST、ADDSET | |
Mode2/B | NOR FLASH时序 | DATAST、ADDSET | |
ModeC | NOR FLASH OE选通时序 | DATAST、ADDSET | |
ModeD | 延长地址保持时间的异步时序 | DATAST、ADDSET、ADDHLK | |
同步突发 | 根据同步时钟FSMC_CK读取多个顺序单元的数据 | CLKDIV、DATLAT |
序号 | 位域 | 功能 |
1 | EXTMOD | 扩展模式使能位,即是否允许读写不同的时序。 本章需要,所以该位为1。 |
2 | WREN | 写使能位。 本章要向LCD写数据,所以该位为1。 |
3 | MWID[1:0] | 存储器数据总线宽度。00:8位;01:16位;10和11保留。 本章用16位数据线,所以该位为01。 |
4 | MTYP[1:0] | 存储器类型。00:SRAM\ROM;01:PSRAM;10:NOR FLASH;11:保留。 本章把LCD当作SRAM使用,所以设置为00。 |
5 | MBKEN | 存储块是能位。 本章需要用该存储块控制LCD,所以使能这个存储块。 |
序号 | 位域 | 功能 |
1 | ACCMOD[1:0] | 访问模式。 00:模式A;01:模式B;10:模式C;11:模式D。 本章用到模式A,所以设置为00. |
2 | DATAST[7:0] | 数据保持时间。 0为保留设置,其他设置则代表保持时间为:DATAST个HCLK时钟周期,最大为255个HCLK周期。 对于ILI9341来说,其实就是RD低电平持续时间,一般为355ns。而一个HCLK时钟周期为13.8ns左右(1/72Mhz),为了兼容其它屏,这里设置DATAST为15,即16个HCLK周期,时间大约为234ns(未计算数据存储的2个HCLK时间,对于9341来说超频了,但实际可以正常使用)。 |
3 | ADDSET[3:0] | 地址建立时间。 其建立时间为:ADDSET个HCLK周期,最大为15个HCLK周期。对ILI9341来说,这里相当于RD高电平持续时间,为90ns,本来这里应该设置为和DATAST一样,但由于stm32f103 FSMC的性能问题,就算设置ADDSET为0,RD的高电平持续时间也达到了190ns以上,故此处设置ADDSET为较小值。 本章设置ADDSET为1,即2个HCLK周期,实际RD高电平大于200ns。 |
序号 | 位域 | 功能 |
1 | ACCMOD[1:0] | 同FSMC_BTRx一样,选择模式A |
2 | DATAST[7:0] | 对应低电平持续时间,设置为3. |
3 | ADDSET[3:0] | 对应高电平持续时间,设置为0. |
BTCR[7] | BTCR[6] | BTCR[5] | BTCR[4] | BTCR[3] | BTCR[2] | BTCR[1] | BTCR[0] |
FSMC_BTR4 | FSMC_BCR4 | FSMC_BTR3 | FSMC_BCR3 | FSMC_BTR2 | FSMC_BCR2 | FSMC_BTR1 | FSMC_BCR1 |
BWTR[6] | BWTR[5] | BWTR[4] | BWTR[3] | BWTR[2] | BWTR[1] | BWTR[0] |
FSMC_BWTR4 | reserved | FSMC_BWTR3 | reserved | FSMC_BWTR2 | reserved | FSMC_BWTR1 |
FSMC_NORSRAMInit(); //初始化NOR和SRAM
FSMC_NANDInit();
FSMC_PCCARDInit();
void FSMC_NORSRAMInit(FSMC_NORSRAMInitTypeDef* FSMC_NORSRAMInitStruct);
typedefstruct
{
uint32_t FSMC_Bank;
uint32_t FSMC_DataAddressMux;
uint32_t FSMC_MemoryType;
uint32_t FSMC_MemoryDataWidth;
uint32_t FSMC_BurstAccessMode;
uint32_t FSMC_AsynchronousWait;
uint32_t FSMC_WaitSignalPolarity;
uint32_t FSMC_WrapMode;
uint32_t FSMC_WaitSignalActive;
uint32_t FSMC_WriteOperation;
uint32_t FSMC_WaitSignal;
uint32_t FSMC_ExtendedMode;
uint32_t FSMC_WriteBurst;
FSMC_NORSRAMTimingInitTypeDef* FSMC_ReadWriteTimingStruct;
FSMC_NORSRAMTimingInitTypeDef* FSMC_WriteTimingStruct;
}FSMC_NORSRAMInitTypeDef;
序号 | 参数 | 设置 |
1 | FSMC_Bank | 设置使用到的存储块标号和区号。 此处使用的是存储块1区号4,所以选择值为FSMC_Bank1_NORSRAM4。 |
2 | FSMC_MemoryType | 设置存储类型。 此处使用SRAM,所以选择值为FSMC_MemoryType_SRAM。 |
3 | FSMC_MemoryDataWidth | 设置数据宽度。 这里用的16位,所以选择值为FSMC_MemoryDataWidth_16b。 |
4 | FSMC_WriteOperation | 设置写是能。 此处要向TFT写数据,所以要写使能,选择值为FSMC_WriteOperation_Enable。 |
5 | FSMC_ExtendedMode | 设置扩展模式使能,即是否允许读写不同的时序。 此处使用读写不同时序,所以设置值为FSMC_ExtendedMode_Enable。 |
6 | FSMC_DataAddressMux | 设置地址/数据复用使能,若设置为使能,则地址的低16位和数据将共用数据总线,仅对NOR和PSRAM有效。 此处设置为默认值不复用,值为FSMC_DataAddressMux_Disable。 |
上面这些参数都是和模式A相关。 | ||
7 | FSMC_BurstAccessMode FSMC_AsynchronousWait FSMC_WaitSignalPolarity FSMC_WaitSignalActive FSMC_WrapMode FSMC_WaitSignal FSMC_WriteBurst |
这些参数在组成模式同步模式才需要设置,参考中文参考手册。 |
8 | FSMC_ReadWriteTimingStruct | 初始化片选控制寄存器FSMC_BTRx。 |
9 | FSMC_WriteTimingStruct | 初始化写操作时序寄存器FSMC_BWTRx。 |
typedefstruct
{
uint32_t FSMC_AddressSetupTime;
uint32_t FSMC_AddressHoldTime;
uint32_t FSMC_DataSetupTime;
uint32_t FSMC_BusTurnAroundDuration;
uint32_t FSMC_CLKDivision;
uint32_t FSMC_DataLatency;
uint32_t FSMC_AccessMode;
}FSMC_NORSRAMTimingInitTypeDef;
void FSMC_NORSRAMCmd(uint32_t FSMC_Bank,FunctionalStateNewState);
void FSMC_NANDCmd (uint32_t FSMC_Bank,FunctionalStateNewState);
void FSMC_PCCARDCmd (FunctionalStateNewState);
LCD_BL -> PB0
LCD_CS -> PG12(FSMC_NE4)
LCD_RS -> PG0 (FSMC_A10)
LCD_WR -> PD5 (FSMC_NWE)
LCD_RD -> PD4 (FSMC_NOE)
LCD_D[15:0] -> FSMC_D15:FSMC_D0
//LCD操作结构体
typedef sturct
{
vu16 LCD_REG;
vu16 LCD_RAM;
}LCD_TypeDef;
//使用NOR/SRAM的Bank1.sector4,地址位HADDR[27,26] = 11,A10作为数据命令区分线
//注意:16位数据总线时,stm32内部地址会右移一位对齐!
#define LCD_BASE ((u32)(0x6C000000 | 0x000007fe))
#define LCD ((LCD_TypeDef*)LCD_BASE)
LCD->LCD_REG = CMD;//写命令
LCD->LCD_RAM = DATA;//写数据
CMD = LCD->LCD_REG;//读LCD寄存器
DATA = LCD->LCD_RAM;//读LCD数据
//LCD重要参数集
typedefstruct
{
u16 width;//LCD宽度
u16 height;//LCD高度
u16 id;//LCD ID
u8 dir;//横屏还是竖屏控制:0,竖屏;1:横屏。
u16 wramcmd;//开始写gram指令
u16 setxcmd;//设置x坐标指令
u16 setycmd;//设置y坐标指令
}_lcd_dev;
//LCD参数
extern _lcd_dev lcddev;//管理LCD重要参数
//写寄存器函数
//regval:寄存器值
void LCD_WR_REG(u16 regval)
{
LCD->LCD_REG = regval;//写入要写的寄存器序号
}
//写LCD数据
//data:要写入的数据
void LCD_WR_DATA(u16 data)
{
LCD->LCD_RAM = data;
}
//读LCD数据
//返回值:读到的数据
u16 LCD_RD_DATA(void)
{
vu16 ram;//防止被优化
ram = LCD->LCD_RAM;
return ram;
}
//写寄存器
//LCD_Reg:寄存器地址
//LCD_RegValue:要写入的数据
void LCD_WriteReg(u16 LCD_Reg, u16 LCD_RegValue)
{
LCD->LCD_REG = LCD_Reg;//要写入的寄存器序号
LCD->LCD_RAM = LCD_RegValue;//要写入的数据
}
//读寄存器
//LCD_Reg:寄存器地址
//返回值:读到的数据
u16 LCD_ReadReg(u16 LCD_Reg)
{
LCD_WR_REG(LCD_Reg);//写入要读的寄存器序号
delay_us(5);
return LCD_RD_DATA();//返回读到的值
}
//开始写GRAM
void LCD_WriteRAM_Prepare(void)
{
LCD->LCD_REG = lcddev.wramcmd;
}
//LCD写GRAM
//RGB_Code:颜色值
void LCD_WriteRAM(u16 RGB_Code)
{
LCD->LCD_RAM = RGB_Code;//写十六位GRAM
}
//设置光标位置
//Xpos:横坐标
//Ypos:纵坐标
void LCD_SetCursor(u16 Xpos, u16 Ypos)
{
if(lcddev.id ==0x9341|| lcddev.id ==0x5310)
{
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(Xpos>>8);
LCD_WR_DATA(Xpos&0xff);
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(Ypos>>8);
LCD_WR_DATA(Ypos&0xff);
}
elseif(lcddev.id ==0x6804)
{
if(lcddev.dir ==1)
Xpos= lcddev.width -1-Xpos;//横屏时处理
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(Xpos>>8);
LCD_WR_DATA(Xpos&0xff);
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(Ypos>>8);
LCD_WR_DATA(Ypos&0xff);
}
elseif(lcddev.id ==0x1963)
{
if(lcddev.dir ==0)//X坐标需要变换
{
Xpos= lcddev.width -1-Xpos;//横屏时处理
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(0);
LCD_WR_DATA(0);
LCD_WR_DATA(Xpos>>8);
LCD_WR_DATA(Xpos&0xff);
}
else
{
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(Xpos>>8);
LCD_WR_DATA(Xpos&0xff);
LCD_WR_DATA((lcddev.width -1)>>8);
LCD_WR_DATA((lcddev.width -1)&0xff);
}
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(Ypos>>8);
LCD_WR_DATA(Ypos&0XFF);
LCD_WR_DATA((lcddev.height-1)>>8);
LCD_WR_DATA((lcddev.height-1)&0XFF);
}
elseif(lcddev.id ==0x5510)
{
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(Xpos>>8);
LCD_WR_REG(lcddev.setxcmd+1);
LCD_WR_DATA(Xpos&0XFF);
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(Ypos>>8);
LCD_WR_REG(lcddev.setycmd+1);
LCD_WR_DATA(Ypos&0XFF);
}
else
{
if(lcddev.dir==1)
Xpos=lcddev.width-1-Xpos;//横屏其实就是调转 x,y 坐标
LCD_WriteReg(lcddev.setxcmd,Xpos);
LCD_WriteReg(lcddev.setycmd,Ypos);
}
}
//画点
//x,y:坐标
//POINT_COLOR:此点的颜色
void LCD_DrawPoint(u16 x, u16 y)
{
LCD_SetCursor(x, y);//设置光标位置
LCD_WriteRAM_Prepare();//开始写入GRAM
LCD->LCD_RAM = POINT_COLOR;
}
//func:读取某个点的颜色值
//入参:x, y:坐标
//出参:此点的颜色
u16 LCD_ReadPoint(u16 x, u16 y)
{
vu16 r = 0, g = 0, b = 0;
if(x >= lcddev.width || y >= lcddev.height)
return 0; //超过了范围,直接返回
LCD_SetCursor(x, y);
if(lcddev.id == 0x9341 || lcddev.id == 0x6804 ||
lcddev.id == 0x5310 || lcddev.id == 0x1963)
LCD_WR_REG(0x2e); //9341、6804、3510、1963 发送读GRAM指令
else if(lcddev.id == 0x5510)
LCD_WR_REG(0x2e00); //5510 发送读GRAM指令
else
LCD_WR_REG(0x22); //其他IC,发送读GRAM指令
if(lcddev.id == 0x9320)
opt_delay(2); //for 9320,延时2us
r = LCD_RD_DATA(); //dummy Read 假读
if(lcddev.id == 0x1963)
return r; //1963直接读就可以
opt_delay(2);
r = LCD_RD_DATA(); //实际坐标颜色
if(lcddev.id == 0x9341 || lcddev.id == 0x5310 || lcddev.id == 0x5510) //这些LCD要分2次读出
{
opt_delay(2);
b = LCD_RD_DATA();
g = r & 0xff; //对于9341、5310、5510,第一次读取的是RG值,先R后G,各占8位
g <<= 8;
}
if(lcddev.id == 0x9325 || lcddev.id == 0x4535 || lcddev.id == 0x4531 ||
lcddev.id == 0xb505 || lcddev.id == 0xc505)
return r; //这几种IC,直接返回颜色值
else if(lcddev.id == 0x9341 || lcddev.id == 0x5310 || lcddev.id == 0x5510)
return (((r >> 11) << 11) | ((g >> 10) << 5) | (b >> 11)); //ILI9341、NT35310、NT3510需要公式转换一下
else
return LCD_BGR2RGB(r); //其他IC
}
//在指定地址显示一个字符
//x,y:起始坐标
//num:要显示的字符:“ ”--->"~"
//size:字体大小 12/16/24
//mode:叠加方式(1),或非叠加方式(0)
void LCD_ShowChar(u16 x, u16 y, u8 num, u8 size, u8 mode)
{
u8 temp, t1, t;
u16 y0 = y;
u8 csize = (size/8 + ((size % 8) ? 1:0) * (size/2)); //得到字体一个字符对应点阵集所占的字节数
num = num - ''; //ASCII字库从空格开始取模,所以-' '即得到对应字符的字库(点阵)
for(t = 0; t < csize; t++)
{
if(size == 12)
temp = asc2_1206[num][t]; //调用1206字体
else if(size == 16)
temp = asc2_1608[num][t]; //调用1608字体
else if(size == 24)
temp = asc2_2412[num][t]; //调用2412字体
else
return; //没有字库
for(t1 = 0; t1 < 8; t1++)
{
if(temp & 0x80)
LCD_Fast_DrawPoint(x, y, POINT_COLOR);
else if(mode == 0)
LCD_Fast_DrawPoint(x, y, BACK_COLOR);
temp <<= 1;
y++;
if(y >= lcddev.height)
return; //超区域了
if((y - y0) == size)
{
y = y0;
x++;
if(x >= lcddev.width)
return; //超区域了
break;
}
}
}
}
//初始化LCD
//注:改初始化函数可以初始化各种ILI93XX液晶,但是其他函数是基于ILI9320的!!!
//在其他型号的驱动芯片上没有测试!
void LCD_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
FSMC_NORSRAMInitTypeDef FSMC_NSInitStructure;
FSMC_NORSRAMTimingInitTypeDef readWriteTiming;
FSMC_NORSRAMTimingInitTypeDef writeTiming;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE); //使能 FSMC 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOD|
RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOG|
RCC_APB2Periph_AFIO, ENABLE); // ①使能GPIO 以及AFIO 复用功能时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PB0 推挽输出 背光
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //②初始化 PB0
//PORTD 复用推挽输出
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5|
GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure); //②初始化 PORTD
//PORTE 复用推挽输出
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|
GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &GPIO_InitStructure); //②初始化 PORTE
//PORTG12 复用推挽输出 A0
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_12; //PORTD
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_12; //PORTD 复用推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOG, &GPIO_InitStructure); //②初始化 PORTG
readWriteTiming.FSMC_AddressSetupTime = 0x01; //地址建立时间 2 个 HCLK 1
readWriteTiming.FSMC_AddressHoldTime = 0x00; //地址保持时间模式 A 未用到
readWriteTiming.FSMC_DataSetupTime = 0x0f; // 数据保存时间为 16 个 HCLK
readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;
readWriteTiming.FSMC_CLKDivision = 0x00;
readWriteTiming.FSMC_DataLatency = 0x00;
readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_A; //模式 A
writeTiming.FSMC_AddressSetupTime = 0x00; //地址建立时间为 1 个 HCLK
writeTiming.FSMC_AddressHoldTime = 0x00; //地址保持时间( A
writeTiming.FSMC_DataSetupTime = 0x03; //数据保存时间为 4 个 HCLK
writeTiming.FSMC_BusTurnAroundDuration = 0x00;
writeTiming.FSMC_CLKDivision = 0x00;
writeTiming.FSMC_DataLatency = 0x00;
writeTiming.FSMC_AccessMode = FSMC_AccessMode_A; //模式 A
FSMC_NSInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM4; //这里我们使用NE4,也就对应BTCR[6],[7]。
FSMC_NSInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; //不复用数据地址
FSMC_NSInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM; // SRAM
FSMC_NSInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b; //存储器数据宽度为 16bit
FSMC_NSInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
FSMC_NSInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
FSMC_NSInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;
FSMC_NSInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
FSMC_NSInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
FSMC_NSInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable; //存储器写使能
FSMC_NSInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
FSMC_NSInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Enable;
// 读写使用不同的时序
FSMC_NSInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
FSMC_NSInitStructure.FSMC_ReadWriteTimingStruct = &readWriteTiming;
FSMC_NSInitStructure.FSMC_WriteTimingStruct = &writeTiming; //写时序
FSMC_NORSRAMInit(&FSMC_NSInitStructure); //③初始化FSMC 配置
FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE); //④使能BANK1
delay_ms(50); // delay 50 ms
lcddev.id = LCD_ReadReg(0x0000); //读ID(9320\9325\9328\4531\4535等IC)
if(lcddev.id < 0xff || lcddev.id == 0xffff || lcddev.id == 0x9300)
//ID不正确,新增0x9300判断,因为9341在未被复位时,会被读成9300
{
//尝试9341 ID的读取
LCD_WR_REG(0xd3);
lcddev.id = LCD_RD_DATA(); //dummy read
lcddev.id = LCD_RD_DATA(); //读到0x00
lcddev.id = LCD_RD_DATA(); //读到93
lcddev.id <<= 8;
lcddev.id |= LCD_RD_DATA(); //读取41
if(lcddev.id != 0x9341) //非9341,尝试是不是6804
{
LCD_WR_REG(0xBF);
lcddev.id = LCD_RD_DATA(); //dummy read
lcddev.id = LCD_RD_DATA(); //读到0x01
lcddev.id = LCD_RD_DATA(); //读到0xD0
lcddev.id = LCD_RD_DATA(); //读到0x68
lcddev.id <<= 8;
lcddev.id |= LCD_RD_DATA(); //读取0x04
if(lcddev.id != 0x6804) //也不是6804,尝试NT35310
{
LCD_WR_REG(0xd4);
lcddev.id = LCD_RD_DATA(); //dummy read
lcddev.id = LCD_RD_DATA(); //读到0x01
lcddev.id = LCD_RD_DATA(); //读到0x53
lcddev.id <<= 8;
lcddev.id |= LCD_RD_DATA(); //读取0x10
if(lcddev.id != 0x5310) //也不是NT35310,尝试NT35110
{
LCD_WR_REG(0xda00);
lcddev.id = LCD_RD_DATA(); //读回0x00
LCD_WR_REG(0xdb00);
lcddev.id = LCD_RD_DATA(); //读回0x80
lcddev.id <<= 8;
LCD_WR_REG(0xdc00);
lcddev.id |= LCD_RD_DATA(); //读回0x00
if(lcddev.id == 0x8000)
lcddev.id == 0x5510; //NT35510读回的ID是8000H,为方便区分,我们强制设置为5510
if(lcddev.id != 0x5510) //也不是5510,尝试SSD1963
{
LCD_WR_REG(0xa1);
lcddev.id = LCD_RD_DATA();
lcddev.id = LCD_RD_DATA(); //读回0x57
lcddev.id <<= 8;
lcddev.id |= LCD_RD_DATA(); //读回0x61
if(lcddev.id == 0x5761)
lcddev.id == 0x1963; //SSD1963读回的ID是5761H,为方便区分,我们强制设置为1963
}
}
}
}
}
printf(" LCD ID:%x\r\n",lcddev.id); //打印 LCD ID
if(lcddev.id==0X9341) //9341 初始化
{
……//9341 初始化代码
}
else if(lcddev.id==0xXXXX) //其他 LCD 初始化代码
{
……//其他 LCD 驱动 IC,初始化代码
}
LCD_Display_Dir(0); //默认为竖屏显示
LCD_LED=1; //点亮背光
LCD_Clear(WHITE);
}
int main(void)
{
u8 x = 0;
u8 lcd_id[12]; //存放LCD ID字符串
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2
uart_init(115200); //串口初始化波特率115200
LED_Init(); //LED初始化
LCD_Init();
POINT_COLOR = RED;
sprintf((char *)lcd_id, "LCD ID:%04X", lcddev.id); //将LCD ID打印到lcd_id数组
while(1)
{
case 0:LCD_Clear(WHITE); break;
case 1:LCD_Clear(BLACK); break;
case 2:LCD_Clear(BLUE); break;
case 3:LCD_Clear(RED); break;
case 4:LCD_Clear(MAGENTA); break;
case 5:LCD_Clear(GREEN); break;
case 6:LCD_Clear(CYAN); break;
case 7:LCD_Clear(YELLOW); break;
case 8:LCD_Clear(BRRED); break;
case 9:LCD_Clear(GRAY); break;
case 10:LCD_Clear(LGRAY); break;
case 11:LCD_Clear(BROWN); break;
}
POINT_COLOR=RED;
LCD_ShowString(30,40,210,24,24,"WarShip STM32 ^_^");
LCD_ShowString(30,70,200,16,16,"TFTLCD TEST");
LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,110,200,16,16,lcd_id); //显示 LCD ID
LCD_ShowString(30,130,200,12,12,"2014/5/4");
x++;
if(x == 12)
x = 0;
LED0 = !LED0
delay_ms(1000);
}