FSMC驱动LCD显示屏学习2

目录

1.LCD

1.1基本概念

1.1.1LCD的简介

1.1.2ILI9341液晶控制器简介

1.1.3LCD的时序图

1.1.48080时序的模拟

1.2代码讲解(正点原子和LCD9341芯片)

1.2.1读和写操作代码

1.2.2LCD的开启显示代码

1.2.3LCD的扫描代码

1.2.4LCD的像素的显示

1.2.5LCD的初始化代码

1.2.6其他

正点原子探索者开发板上使用4.3寸NT35510控制的。其他的芯片驱动也是差不多,不同的芯片驱动的程序不一样,填充函数等是数学算法,写法并没有固定的公式

1.3FSMC的配置显示

1.3.1FSMC的配置

1.3.2实验效果


1.LCD

1.1基本概念

1.1.1LCD的简介
  • 液晶显示器,简称 LCD(Liquid Crystal Display)相对于上一代 CRT 显示器 (阴极射线管显示器),LCD显示器具有功耗低、体积小、承载的信息量大及不伤眼的优点,因而它成为了现在的主流电子显示设备
  • 液晶是一种介于固体和液体之间的特殊物质,它是一种有机化合物,常态下呈液态,但是它的分 子排列却和固体晶体一样非常规则,因此取名液晶。如果给液晶施加电场,会改变它的分子排列,从而改变光线的传播方向,配合偏振光片,它就具有控制光线透过率的作用,再配合彩色滤光片,改变加给液晶电压大小,就能改变某一颜色透光量的多少

  • 注意液晶本身是不发光的,所以需要有一个背光灯提供光源 ,光线经过一系列处理过程才到输
    出,所以输出的光线强度是要比光源的强度低很多的
  • 显示器的基本参数

(1)像素

        像素是组成图像的最基本单元要素,显示器的像素指它成像最小的点,把三种显示结构组成一个显示单位,通过控制红绿蓝的强度,可以使该单位混合输出不同的色彩,这样的一个显示单位被称为像素

(2)分辨率

        一些嵌入式设备的显示器常常以“行像素值x列像素值”表示屏幕的分辨率。如分辨率800x480 表示该显示器的每一行有800个像素点,每一列有 480 个像素点,也可理解为有800 列,480行。

(3)显示器尺寸

        显示器的大小一般以英寸表示,如5英寸、21 英寸、24 英寸等,这个长度是指屏幕对角线的长度,通过显示器的对角线长度及长宽比可确定显示器的实际长宽尺寸。

(4)点距
        
        点距指两个相邻像素点之间的距离,它会影响画质的细腻度及观看距离,相同尺寸的屏幕,若分辨率越高,则点距越小,画质越细腻。如现在有些手机的屏幕分辨率比电脑显示器的还大,这是手机屏幕点距小的原因;LED点阵显示屏的点距一般都比较大,所以适合远距离观看
  • 基本色原理:无法通过其他颜色混合得到的颜色,称之为基本色;通过三基色混合,可以得到自然界中绝大部分颜色
  • 色彩深度:色彩深度指显示器的每个像素点能表示多少种颜色,一般用“位”(bit) 来表示。如单色屏的每个像素点能表示亮或灭两种状态 (即实际上能显示2种颜色),用1个数据位就可以表示像素点的所有状态,所以它的色彩深度为1bit,其它常见的显示屏色深为16bit、24bit

  • 这样MCU的16位数据,最低5位代表蓝色,中间6位为绿色,最高5位为红色。数值越大,表示该颜色越深。ILI9341在16位模式下面,数据线有用的是:D17~D13和D11~D1,D0和D12没有用到。

1.1.2ILI9341液晶控制器简介

  • 通讯引脚

  • RGB信号线
(1)RGB信号线各有8根,分别用于表示液晶屏一个像素点的红、绿、蓝颜色分量。使用红绿蓝颜色分量来表示颜色是一种通用的做法,打开Windows系统自带的画板调色工具,可看到颜色的红绿蓝分量值,见图颜色表示法。常见的颜色表示会在“RGB” 后面附带各个颜色分量值的数据位数,如RGB565表示红绿蓝的数据线数分别为 5、 6、5 根,一共为16个数据位,可表示2^{16}种颜色;而这个液晶屏的种颜色分量的数据线都有8根,所以它支持RGB888格式,一共24位数据线,可表示的颜色为2^{24}种。
  • 同步时钟信号CLK
(1)液晶屏与外部使用同步通讯方式,以CLK信号作为同步时钟,在同步时钟的驱动下, 每个时钟传输一个像素点数据
  • 水平同步信号HSYNC
(1)水平同步信号HSYNC(Horizontal Sync) 用于表示液晶屏一行像素数据的传输结束,每传输完成液晶屏的一行像素数据时,HSYNC会发生电平跳变,如分辨率为800x480的显示屏 (800列,480行),传输一帧的图像HSYNC的电平会跳变480次。
  • 垂直同步信号VSYNC
1)垂直同步信号VSYNC(Vertical Sync) 用于表示液晶屏一帧像素数据的传输结束,每传输完成一帧像素数据时,VSYNC会发生电平跳变。其中“帧”是图像的单位,一幅图像称为一帧,在液晶屏中,一帧指一个完整屏液晶像素点。人们常常用“帧/秒”来表示液晶屏的刷新特性,即液晶屏每秒可以显示多少帧图像,如液晶屏以60帧/秒的速率运行时 VSYNC每秒钟电平会跳变60次
  • 数据使能信号 DE
(1)数据使能信号 DE(Data Enable) 用于表示数据的有效性,当DE信号线为高电平时, RGB 信号线表示的数据有效
  • 显存 

(1)液晶屏中的每个像素点都是数据,在实际应用中需要把每个像素点的数据缓存起来,再传输给液晶屏,一般会使用SRAM或SDRAM性质的存储器,而这些专门用于存储显示数据的存储器,则被称为显存。显存一般至少要能存储液晶屏的一帧显示数据,如分辨率为 800x480 的液晶屏,使用RGB888格式显示,它的一帧显示数据大小为:3x800x480=1152000 字节;若使用 RGB565格式显示,一帧显示数据大小为:2x800x480=768000 字节。

  • LED控制

(1) 在GRAM的左侧还有一个 LED控制器 (LED Controller)。LCD为非发光性的显示装置,它需要借助背光源才能达到显示功能,LED 控制器就是用来控制液晶屏中的LED背光源

1.1.3LCD的时序图

  • 液晶屏有一个显示指针, 它指向将要显示的像素。显示指针的扫描方向方向从左到右、从上到下,一个像素点一个像素点地描绘图形。这些像素点的数据通过RGB数据线传输至液晶屏,它们在同步时钟CLK 的驱动下一个一个地传输到液晶屏中,交给显示指针,传输完成一行时,水平同步信号 HSYNC电平跳变一次,而传输完一帧时VSYNC电平跳变一次
1.1.48080时序的模拟

  • 若向0x60000000地址写入数据如0xABCD,FSMC会自动在各信号线上产生相应的电平信号,写入数据。FSMC会控制片选信号NE1选择相应的NOR芯片,然后使用地址线A[25:0]输出0x60000000,在NWE写使能信号线上发出低电平的写使能信号,而要写入的数据信号 0xABCD则从数据线D[15:0] 输出,然后数据就被保存到NOR FLASH中了

  •  由图可知,写命令时序由片选信号CSX拉低开始,对数据/命令选择信号线D/CX也置低电平表示写入的是命令地址 (可理解为命令编码,如软件复位命令:0x01),以写信号WRX为低,读信号RDX为高表示数据传输方向为写入,同时,在数据线D[17:0](或 D[15:0]) 输出命令地址,在第二个传输阶段传送的是命令的参数,所以D/CX要置高电平,表示写入的是命令数据,命令数据是某些指令带有的参数,如复位指令编码为0x01,它后面可以带一个参数,该参数表示多少秒后复位

  • 对于FSMC和8080 接口,前四种信号线都是完全一样的,仅仅是FSMC的地址信号线A[25:0]与8080 的数据/命令选择线 D/CX 有区别。 而对于 D/CX 线,它为高电平的时候表示数值,为低电平的时候表示命令 ,如果能使用 FSMC 的 A 地址线根据不同的情况产生对应的电平,那么就完全可以使用 FSMC 来产生 8080 接口需要的时序了。
  • 为了模拟出8080时序我们可以把FSMC的A0地址线 (也可以使用其它 A1/A2 等地址线) 与ILI9341 芯片 8080 接口的D/CX信号线连接,那么当A0为高电平时 (即 D/CX 为高电平),数据线D[15:0] 的信号会被ILI9341理解为数值,若A0为低电平时 (即 D/CX 为低电平),传输的信号则会被理解为命令
  • 由于FSMC会自动产生地址信号,当使用FSMC向0x6xxx xxx1、0x6xxx xxx3、0x6xxx xxx5…这些奇数地址写入数据时,地址最低位的值均为 1,所以它会控制地址线 A0(D/CX) 输出高电平,那么这时通过数据线传输的信号会被理解为数值;若向 0x6xxx xxx0 、0x6xxx xxx2、0x6xxx xxx4…这些偶数地址写入数据时,地址最低位的值均为 0,所以它会控制地址线 A0(D/CX) 输出低电平, 因此这时通过数据线传输的信号会被理解为命令

1.2代码讲解(正点原子和LCD9341芯片)

1.2.1读和写操作代码

/* FSMC相关参数 定义 
 * 注意: 我们默认是通过FSMC块1来连接LCD, 块1有4个片选: FSMC_NE1~4
 *
 * 修改LCD_FSMC_NEX, 对应的LCD_CS_GPIO相关设置也得改
 * 修改LCD_FSMC_AX , 对应的LCD_RS_GPIO相关设置也得改
 */
#define LCD_FSMC_NEX         4              /* 使用FSMC_NE4接LCD_CS,取值范围只能是: 1~4 */
#define LCD_FSMC_AX          6              /* 使用FSMC_A6接LCD_RS,取值范围是: 0 ~ 25 */

/* LCD_BASE的详细解算方法:
 * 我们一般使用FSMC的块1(BANK1)来驱动TFTLCD液晶屏(MCU屏), 块1地址范围总大小为256MB,均分成4块:
 * 存储块1(FSMC_NE1)地址范围: 0x6000 0000 ~ 0x63FF FFFF
 * 存储块2(FSMC_NE2)地址范围: 0x6400 0000 ~ 0x67FF FFFF
 * 存储块3(FSMC_NE3)地址范围: 0x6800 0000 ~ 0x6BFF FFFF
 * 存储块4(FSMC_NE4)地址范围: 0x6C00 0000 ~ 0x6FFF FFFF
 *
 * 我们需要根据硬件连接方式选择合适的片选(连接LCD_CS)和地址线(连接LCD_RS)
 * 探索者F407开发板使用FSMC_NE4连接LCD_CS, FSMC_A6连接LCD_RS ,16位数据线,计算方法如下:
 * 首先FSMC_NE4的基地址为: 0x6C00 0000;    NEX的基址为(x=1/2/3/4): 0x6000 0000 + (0x400 
 * 0000 * (x - 1))
 * FSMC_A6对应地址值: 2^6 * 2 = 0x80;      FSMC_Ay对应的地址为(y = 0 ~ 25): 2^y * 2
 *
 * LCD->LCD_REG,对应LCD_RS = 0(LCD寄存器); LCD->LCD_RAM,对应LCD_RS = 1(LCD数据)
 * 则 LCD->LCD_RAM的地址为:  0x6C00 0000 + 2^6 * 2 = 0x6C00 0080
 *    LCD->LCD_REG的地址可以为 LCD->LCD_RAM之外的任意地址.
 * 由于我们使用结构体管理LCD_REG 和 LCD_RAM(REG在前,RAM在后,均为16位数据宽度)
 * 因此 结构体的基地址(LCD_BASE) = LCD_RAM - 2 = 0x6C00 0080 -2
 *
 * 更加通用的计算公式为((片选脚FSMC_NEX)X=1/2/3/4, (RS接地址线FSMC_Ay)y=0~25):
 *          LCD_BASE = (0x6000 0000 + (0x400 0000 * (x - 1))) | (2^y * 2 -2)
 *          等效于(使用移位操作)
 *          LCD_BASE = (0x6000 0000 + (0x400 0000 * (x - 1))) | ((1 << y) * 2 -2)
 */

#define LCD_BASE  (uint32_t)((0x60000000+(0x4000000*(LCD_FSMC_NEX-1)))|(((1<< LCD_FSMC_AX)*2)-2))
#define LCD       ((LCD_TypeDef *) LCD_BASE)


/**
 * @brief  写数据的时候由基地址选择Bank1的NE4,由A6选择数据位则向左移动7位,此时为高电平。为传送 
 *         数据位。写数据其实就是传送像素点
 * @param  data: 要写入的数据
 * @retval 无
 */
void lcd_wr_data(volatile uint16_t data)
{
    data = data;            /* 使用-O2优化的时候,必须插入的延时 */
    LCD->LCD_RAM = data;
}

/**
 * @brief  写命令的时候由基地址选择Bank1的NE4,由A6选择数据位则向左移动7位,此时为低电平。 为传 
 *         送命令。
 * @param  regno: 寄存器编号/地址
 * @retval  无
 */
void lcd_wr_regno(volatile uint16_t regno)
{
    regno = regno;          /* 使用-O2优化的时候,必须插入的延时 */
    LCD->LCD_REG = regno;   /* 写入要写的寄存器序号 */
}

/**
 * @brief       LCD延时函数,仅用于部分在mdk -O1时间优化时需要设置的地方
 * @param       t:延时的数值
 * @retval      无
 */
static void lcd_opt_delay(uint32_t i)
{
    while (i--); /* 使用AC6时空循环可能被优化,可使用while(1) __asm volatile(""); */
}


/**
 * @brief   读操作就是将寄存器的值赋值给定义的变量读出来
 * @param   
 * @retval  
 */
static uint16_t lcd_rd_data(void)
{
    volatile uint16_t ram;  /* 防止被优化 */
    lcd_opt_delay(2);
    ram = LCD->LCD_RAM;     /* 数据位寄存器的数据赋值给变量*/
    return ram;             /* 返回变量*/
}














1.2.2LCD的开启显示代码
  • 接下来看指令:0X2C,该指令是写 GRAM 指令,在发送该指令之后,我们便可以往 LCD
    的 GRAM 里面写入颜色数据了,该指令支持连续写

 /**
 * @brief       设置LCD显示方向
 * @retval      无
 */
void lcd_display_dir(uint8_t dir)
{
    lcddev.wramcmd = 0x2C;  //开启内存写操作
    lcddev.setxcmd = 0x2A;  //初始化行命令
    lcddev.setycmd = 0x2B;  //初始化列命令
}


/**
 * @brief       LCD开启显示
 * @param       无
 * @retval      无
 */
void lcd_display_on(void)
{
    lcd_wr_regno(0x29);     /* 开启显示 */
}

/**
 * @brief       LCD关闭显示
 * @param       无
 * @retval      无
 */
void lcd_display_off(void)
{

    lcd_wr_regno(0x28);     /* 关闭显示 */
}


/**
 * @brief       设置光标位置
 * @retval      无
 */
void lcd_set_cursor(uint16_t x, uint16_t y)
{
     lcd_wr_regno(lcddev.setxcmd); 
     lcd_wr_data(x >> 8);          
     lcd_wr_data(x & 0xFF);        
     lcd_wr_regno(lcddev.setycmd);
     lcd_wr_data(y >> 8);
     lcd_wr_data(y & 0xFF);
}


 
1.2.3LCD的扫描代码

/**
 * @brief       设置LCD的自动扫描方向(对RGB屏无效)
 * @note
 *              9341/5310/5510/1963/7789/7796/9806等IC已经实际测试
 *              注意:其他函数可能会受到此函数设置的影响(尤其是9341),
 *              所以,一般设置为L2R_U2D即可,如果设置为其他扫描方式,可能导致显示不正常.
 *
 * @param       dir:0~7,代表8个方向(具体定义见lcd.h)
 * @retval      无
 */
void lcd_scan_dir(uint8_t dir)
{
    
     /* 根据扫描方式 设置 0x36/0x3600 寄存器 bit 5,6,7 位的值 */
    switch (dir)
    {
        case L2R_U2D:   /* 从左到右,从上到下 */
            regval |= (0 << 7) | (0 << 6) | (0 << 5);
            break;

        case L2R_D2U:   /* 从左到右,从下到上 */
            regval |= (1 << 7) | (0 << 6) | (0 << 5);
            break;

        case R2L_U2D:   /* 从右到左,从上到下 */
            regval |= (0 << 7) | (1 << 6) | (0 << 5);
            break;

        case R2L_D2U:   /* 从右到左,从下到上 */
            regval |= (1 << 7) | (1 << 6) | (0 << 5);
            break;

        case U2D_L2R:   /* 从上到下,从左到右 */
            regval |= (0 << 7) | (0 << 6) | (1 << 5);
            break;

        case U2D_R2L:   /* 从上到下,从右到左 */
            regval |= (0 << 7) | (1 << 6) | (1 << 5);
            break;

        case D2U_L2R:   /* 从下到上,从左到右 */
            regval |= (1 << 7) | (0 << 6) | (1 << 5);
            break;

        case D2U_R2L:   /* 从下到上,从右到左 */
            regval |= (1 << 7) | (1 << 6) | (1 << 5);
            break;
    }
     dirreg = 0x36;  /* 0x36的高三位可以设置GRAM的扫描方向 */
      /* 9341要设置BGR位 */
    if (lcddev.id == 0x9341)
    {
        regval |= 0x08;  //BGR位要设置1
    }
        lcd_wr_regno(lcddev.setxcmd);  //发送2A的行命令 
        lcd_wr_data(0);                //x起始坐标高8位
        lcd_wr_data(0);                //x起始坐标低8位 
        lcd_wr_data((lcddev.width - 1) >> 8); //x结束坐标高8位
        lcd_wr_data((lcddev.width - 1) & 0xFF);//x 结束坐标低8位
        lcd_wr_regno(lcddev.setycmd);  //发送2B列命令
        lcd_wr_data(0);
        lcd_wr_data(0);
        lcd_wr_data((lcddev.height - 1) >> 8);
        lcd_wr_data((lcddev.height - 1) & 0xFF);
    
}    
1.2.4LCD的像素的显示
  • 在16位模式下,ILI9341采用RGB565 格式存储颜色数据,此时 ILI9341 的18位显存与 MCU 的16位数据线以及RGB565的对应关系如图 

  • 从图中可以看出,ILI9341 在16位模式下面,18 位显存的 B0 和 B12 并没有用到,对外的
    数据线使用 DB0-DB15 连接 MCU 的 D0-D15 实现 16 位颜色的传输
  • 这样MCU的6位数据,最低5位代表蓝色,中间6位为绿色,最高5位为红色。数值越大,表示该颜色越深。另外,特别注意 ILI9341 所有的指令都是 8 位的(高 8 位无效),且参数 除了读写 GRAM 的时候是16位,其他操作参数,都是8位的
#define WHITE           0xFFFF      /* 白色 */
#define BLACK           0x0000      /* 黑色 */
#define RED             0xF800      /* 红色 */
#define GREEN           0x07E0      /* 绿色 */
#define BLUE            0x001F      /* 蓝色 */ 
#define MAGENTA         0xF81F      /* 品红色/紫红色 = BLUE + RED */
#define YELLOW          0xFFE0      /* 黄色 = GREEN + RED */
#define CYAN            0x07FF      /* 青色 = GREEN + BLUE */ 




/**
 * @brief       设置光标位置(对RGB屏无效)
 * @param       x,y: 坐标
 * @retval      无
 */
void lcd_set_cursor(uint16_t x, uint16_t y)
{
    lcd_wr_regno(lcddev.setxcmd);
    lcd_wr_data(x >> 8);
    lcd_wr_data(x & 0xFF);
    lcd_wr_regno(lcddev.setycmd);
    lcd_wr_data(y >> 8);
    lcd_wr_data(y & 0xFF);
}

void lcd_write_ram_prepare(void)
{
    LCD->LCD_REG = lcddev.wramcmd; //wramcmd=0x2c,准备写像素的命令
}
/**
 * @brief       画点
 * @param       x,y: 坐标
 * @param       color: 点的颜色(32位颜色,方便兼容LTDC)
 * @retval      无
 */
void lcd_draw_point(uint16_t x, uint16_t y, uint32_t color)
{
    lcd_set_cursor(x, y);       /* 设置光标位置 */
    lcd_write_ram_prepare();    /* 开始写入GRAM */
    LCD->LCD_RAM = color;       /* 向一个像素点填充颜色/
}
1.2.5LCD的初始化代码

/**
 * @brief       初始化LCD
 *   @note      该初始化函数可以初始化各种型号的LCD(详见本.c文件最前面的描述)
 *
 * @param       无
 * @retval      无
 */
void lcd_init(void)
{
    
    /* 尝试9341 ID的读取 */
    lcd_wr_regno(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 */


    lcd_ex_ili9341_reginit();   /* 执行ILI9341初始化 */
    
}


/**
 * @brief       ILI9341寄存器初始化代码
 * @param       无
 * @retval      无
 */
void lcd_ex_ili9341_reginit(void)
{
    lcd_wr_regno(0xCF);
    lcd_wr_data(0x00);
    lcd_wr_data(0xC1);
    lcd_wr_data(0x30);
    lcd_wr_regno(0xED);
    lcd_wr_data(0x64);
    lcd_wr_data(0x03);
    lcd_wr_data(0x12);
    lcd_wr_data(0x81);
    lcd_wr_regno(0xE8);
    lcd_wr_data(0x85);
    lcd_wr_data(0x10);
    lcd_wr_data(0x7A);
    lcd_wr_regno(0xCB);
    lcd_wr_data(0x39);
    lcd_wr_data(0x2C);
    lcd_wr_data(0x00);
    lcd_wr_data(0x34);
    lcd_wr_data(0x02);
    lcd_wr_regno(0xF7);
    lcd_wr_data(0x20);
    lcd_wr_regno(0xEA);
    lcd_wr_data(0x00);
    lcd_wr_data(0x00);
    lcd_wr_regno(0xC0); /* Power control */
    lcd_wr_data(0x1B);  /* VRH[5:0] */
    lcd_wr_regno(0xC1); /* Power control */
    lcd_wr_data(0x01);  /* SAP[2:0];BT[3:0] */
    lcd_wr_regno(0xC5); /* VCM control */
    lcd_wr_data(0x30);  /* 3F */
    lcd_wr_data(0x30);  /* 3C */
    lcd_wr_regno(0xC7); /* VCM control2 */
    lcd_wr_data(0xB7);
    lcd_wr_regno(0x36); /* Memory Access Control */
    lcd_wr_data(0x48);
    lcd_wr_regno(0x3A);
    lcd_wr_data(0x55);
    lcd_wr_regno(0xB1);
    lcd_wr_data(0x00);
    lcd_wr_data(0x1A);
    lcd_wr_regno(0xB6); /* Display Function Control */
    lcd_wr_data(0x0A);
    lcd_wr_data(0xA2);
    lcd_wr_regno(0xF2); /* 3Gamma Function Disable */
    lcd_wr_data(0x00);
    lcd_wr_regno(0x26); /* Gamma curve selected */
    lcd_wr_data(0x01);
    lcd_wr_regno(0xE0); /* Set Gamma */
    lcd_wr_data(0x0F);
    lcd_wr_data(0x2A);
    lcd_wr_data(0x28);
    lcd_wr_data(0x08);
    lcd_wr_data(0x0E);
    lcd_wr_data(0x08);
    lcd_wr_data(0x54);
    lcd_wr_data(0xA9);
    lcd_wr_data(0x43);
    lcd_wr_data(0x0A);
    lcd_wr_data(0x0F);
    lcd_wr_data(0x00);
    lcd_wr_data(0x00);
    lcd_wr_data(0x00);
    lcd_wr_data(0x00);
    lcd_wr_regno(0xE1); /* Set Gamma */
    lcd_wr_data(0x00);
    lcd_wr_data(0x15);
    lcd_wr_data(0x17);
    lcd_wr_data(0x07);
    lcd_wr_data(0x11);
    lcd_wr_data(0x06);
    lcd_wr_data(0x2B);
    lcd_wr_data(0x56);
    lcd_wr_data(0x3C);
    lcd_wr_data(0x05);
    lcd_wr_data(0x10);
    lcd_wr_data(0x0F);
    lcd_wr_data(0x3F);
    lcd_wr_data(0x3F);
    lcd_wr_data(0x0F);
    lcd_wr_regno(0x2B);
    lcd_wr_data(0x00);
    lcd_wr_data(0x00);
    lcd_wr_data(0x01);
    lcd_wr_data(0x3f);
    lcd_wr_regno(0x2A);
    lcd_wr_data(0x00);
    lcd_wr_data(0x00);
    lcd_wr_data(0x00);
    lcd_wr_data(0xef);
    lcd_wr_regno(0x11); /* Exit Sleep */
    HAL_Delay(120);
    lcd_wr_regno(0x29); /* display on */
 }
1.2.6其他
正点原子探索者开发板上使用4.3寸NT35510控制的。其他的芯片驱动也是差不多,不同的芯片驱动的程序不一样,填充函数等是数学算法,写法并没有固定的公式

1.3FSMC的配置显示

1.3.1FSMC的配置
  • 在STM32CubeMX中可以设置读写时序的地址建立时间和数据建立时间,单位为一个HCLK时钟周期,当HCLK时钟频率为STM32F407最高频率168MHz时,一个周期大约为6us

  •  地址建立时间,0-0xF个HCLK周期,地址建立时间,0-0xF个HCLK周期,在cubmx中写模式下的数据建立时间不包含后面的加1。读地址建立时间>10ns(2个HCLK时钟周期),写地址建立时间>0us,数据建立/保持时间>15+10ns(5个HCLK时钟周期),读写地址保持时间>2ns,,另外总线翻转时间设置为0,访问模式选择A即可。
  • Extended mode:本成员用于设置是否使用扩展模式 在非扩展模式下,对存储器读写的时序都只使用 FSMC_BCR 寄存器中的配置, 在扩展模式下,对存储器的读写时序可以分开配置 ,读时序使用 FSMC_BCR寄存器,写时序使用FSMC_BWTR寄存器的配置, 
1.3.2实验效果
  lcd_init();
  lcd_show_string(30,40,210,24,24,"2024/9/5",RED);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值