精华内容
下载资源
问答
  • LCD显示

    2015-05-26 01:01:04
    今天在写LCD显示,用的是51单片机和Proteus仿真,但是Proteus中没有以前写的LCD5110所以只能用库中的HDG12864F-1,后来才发现这个好像是写LCM的,搞了一晚上总算是弄出来了一下贴出代码每一个LCD驱动都要有命令和...

    今天在写LCD的显示,用的是51单片机和Proteus仿真,但是Proteus中没有以前写的LCD5110所以只能用库中的HDG12864F-1,后来才发现这个好像是写LCM的,搞了一晚上总算是弄出来了一下贴出代码

    每一个LCD驱动都要有命令和数据的写入首先是这两个代码

    //CE 片选信号
    //LCD_CE_OL     置低,表示选中芯片   
    //LCD_CE_OH     置高,表示未选中芯片
    //DC 数据命令选择
    //LCD_DC_OL     置低:数据   
    //LCD_DC_OH     置高:数据 
    //SCLK 时钟 每个时钟的上升沿写入数据
    void LCD_WrDat(uint8_t dat)
    {
        uint8_t i = 8;
        LCD_CE_OL;//片选信号置低,表示选中芯片   
        LCD_DC_OH;//数据命令 置高:数据  
        LCD_SCLK_OL;
        while (i --)
        {
            if (dat & 0x80)
            {
                LCD_SDIN_OH;
            }
            else
            {
                LCD_SDIN_OL;
            }
            LCD_SCLK_OH; 
            LCD_SCLK_OL;    
            dat <<= 1;    
        }
        LCD_CE_OH;
    }
    
    void LCD_WrCmd(uint8_t cmd)
    {
        uint8_t i = 8;
        LCD_CE_OL;
        LCD_DC_OL;
        LCD_SCLK_OL;
        while (i --)
        {
            if (cmd & 0x80)
            {
                LCD_SDIN_OH;
            }
            else
            {
                LCD_SDIN_OL;
            }
            LCD_SCLK_OH; 
            LCD_SCLK_OL;    
            cmd <<= 1;    
        }
        LCD_CE_OH;  
    }       

    其次,设定要写的位置,位置要根据芯片手册确定LCD5110和HDG12864F-1的是不一样的,一开始怎么都不对,后来看了芯片手册才发现原来就不一样

    void LCD_Set_XY(uint8_t X, uint8_t Y)
    {
         LCD_WrCmd(Y | 0xB0);
         LCD_WrCmd(0x10|((0xf0 & X) >> 4));//设定列地址高4位为0
         LCD_WrCmd(0x00|(0x0f & X));    //设定列地址低4位为0
    
    }

    然后是清屏函数,这个没什么大问题,只要把所有的格格写入0就可以了

    void LCD_Clear(void)
    {
         uint8_t t,k;
         LCD_Set_XY(0,0);
         for(t = 0; t < (HEIGHT >> 3); t++)
         {
                for(k = 0;k < WIDTH; k++)
                {
                        LCD_WrDat(0x00);
                }
         }
    }

    初始化函数,这个问题就大了,不同的芯片初始化是不一样的,开始怎么都出来,后来看了一下手册,duangduang的。

    void LCD_Init(void)
    {
        LCD_RST_OL;  //LCD(低电平)复位
        LCD_WrCmd(0xae);
        LCD_RST_OH;     // RES置高
        LCD_WrCmd(0xa2);    // LCD偏压设置:1/9 BIAS
        LCD_WrCmd(0xa1);    //列地址选择为从右到左对应0~127;0xa1:列地址从左到右;0xa0:列地址从右到左
        LCD_WrCmd(0xc0);    // 行地址从上到下为0~63;0xc0:行地址从上到下;0xc8:行地址从下到上
        LCD_WrCmd(0x26);    // V5电压内部电阻调整设置
        LCD_WrCmd(0x81);    //亮度调整命令0~63(暗到亮)
        LCD_WrCmd(0x10);    //亮度调节为双字节命令,前一个参数控制字的深浅
        LCD_WrCmd(0x2f);    //上电控制,打开调压器、稳压器和电压跟随
        LCD_WrCmd(0xaf);    //0xae:set display off。0xaf:set display on
        //LCD_WrCmd(0x60);  //其实行设置
    
    }

    接着是写入字符,我这里用的是小字符,宽度占6个点

    void LCD_Write_Char(uint8_t x, uint8_t y, uint8_t c) 
    {
        uint8_t i = 0;
        if ((c >= 'A') && (c <= 'Z'))
        {
            c = c - 'A' + 10;
        }
        else if ((c >= 'a') && (c <= 'z')) 
        {
            c = c - 'a' + 44;
        }
        else if (c == ' ')
        {
            c = 36;
        }
        else if (c == ':')
        {
            c = 37;
        }
        else if (c == '-')
        {
            c = 38;
        }
        else if (c == '/')
        {
            c = 39;
        }
        else if(c == '.')
        {
            c = 40;
        }
        else if (c == ',')
        {
            c = 41;
        }
        else if (c == '^')
        {
            c = 42;
        }
    
        if (x > 126)
        {
            x = 0;
            y ++;
        }
    
        LCD_Set_XY(x * 6, y);
        for (i = 0; i < 6; i++) 
        {
            LCD_WrDat(SmallChars[c * 6 + i]); 
        }
    
    }
    void LCD_Write_Num5(uint8_t x, uint8_t y, int num)
    {
        LCD_Write_Char(x,     y, num / 10000);
        LCD_Write_Char(x + 1, y, num % 10000 / 1000);
        LCD_Write_Char(x + 2, y, num % 1000 / 100);
        LCD_Write_Char(x + 3, y, num % 100/10);
        LCD_Write_Char(x + 4, y, num % 10);
    }
    void LCD_Write_String(uint8_t x, uint8_t y, uint8_t *s)
    {
        uint8_t i;
    
        for (i=0; s[i]!='\0'; i++)
        {
            LCD_Write_Char(x + i, y, s[i]);
        }
    }
    //这里的字符是16*16大小的
    void LCD_Write_Chinese(uint8_t x,uint8_t y,uint8_t *China)
    {
        uint8_t ii = 0;
    
            LCD_Set_XY(x, y);
            for(ii = 0; ii < 16; ii++)
            {           
                LCD_WrDat(China[ii]);           
            }
            LCD_Set_XY(x, y + 1);
            for(ii = 0; ii < 16; ii++)
            {           
                LCD_WrDat(China[16 + ii]);          
            }
    
    }

    接着是防止闪屏写的“双缓冲”.其实这段代码在51上没有试过,32上的内存空间很大,51上定义了一个字符数组就没有空间了,也懒的删再去试。原理是吧所有的点写到一个数组里面,然后全部写出来,这样清屏的时候只要把数组清一下就可以了,不需要刷屏,就可以防止屏闪

    uint8_t data buff[HEIGHT][WIDTH]={0};
    void LCD_Write_Point(uint8_t hang,uint8_t lie)
    {
        buff[hang][lie] = 1;
    }
    void LCD_Draw(void)
    {
            uint8_t dat = 0;
            uint8_t i,j,k;
            unsigned short t = 0;
            for(j = 0; j < (HEIGHT >> 3); j++)//hang
            {
                for(i = 0; i < WIDTH; i++)//lie
                {
                        for(k = 0; k < 7; k++)
                        {
                            if(buff[(j << 3) + k][i])
                                dat |= (1 << k);
                        }
                        LCD_WrDat(dat);
                        dat = 0;
                }       
            }   
    }
    void LCD_ClearBuff(void)
    {
            uint8_t i = 0, j = 0;
            for(i = 0; i < WIDTH; i++)
                for(j = 0; j < HEIGHT; j++)
                    buff[j][i] = 0;
    }
    //TFT上画出的线很漂亮,但是这个上面。。。。。不知道为什么
    void LCD_DrawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
    {
        char t; 
        char xerr = 0,yerr = 0,delta_x,delta_y,distance; 
        char incx,incy,uRow,uCol; 
        delta_x = x2 - x1; 
        delta_y = y2 - y1; 
        uRow = x1; 
        uCol = y1; 
        if(delta_x > 0)
            incx = 1; 
        else if(delta_x == 0)
            incx=0;
        else 
        {
            incx = -1;
            delta_x = -delta_x;
        } 
    
        if(delta_y > 0)
            incy = 1; 
        else if(delta_y == 0)
            incy = 0;
        else
        {
            incy = -1;
            delta_y = -delta_y;
        } 
        if(delta_x > delta_y)
            distance = delta_x;
        else 
            distance = delta_y; 
        for(t = 0;t <= distance + 1; t++ )
        {  
            LCD_Write_Point(uRow,uCol);
            xerr += delta_x ; 
            yerr += delta_y ; 
            if(xerr > distance) 
            { 
                xerr -= distance; 
                uRow += incx; 
            } 
            if(yerr > distance) 
            { 
                yerr -= distance; 
                uCol += incy; 
            } 
        }  
    }

    这个东西真的很有收获,一个收获就是知道数据手册的重要性,另一个数关于双缓冲的,下一步想要来重定向

    展开全文
  • LCD显示方向

    2019-10-28 19:25:46
    LCD显示方向 一、ILI9341内存到显示地址的映射  本文只讨论“正常显示”,不讨论“垂直滚动显示”模式。 可以看到物理内存被两个指针访问,行指针和列指针,行指针范围从000h到013Fh,列指针范围为0000h到00EF...

    LCD显示方向

    一、ILI9341内存到显示地址的映射

      本文只讨论“正常显示”,不讨论“垂直滚动显示”模式。

    可以看到物理内存被两个指针访问,行指针和列指针,行指针范围从000h到013Fh,列指针范围为0000h到00EFh。也就是说,物理内存和LCD显示屏的对应关系是一种竖屏(240*320)的对应的关系。至于如何让GRAM数据显示到LCD屏上,不需要我们去考虑,只要知道这种对应关系就可以了。

      那么ILI9341有8种显示方式:左上角->右下角(竖屏)、左下角->右上角(竖屏)、右上角->左下角(竖屏)、右下角->左上角(竖屏)、左上角->右下角(横屏)、左下角->右上角(横屏)、右上角->左下角(横屏)、右下角->

    左上角(横屏),又是怎么实现的呢?

    二、MCU读写GRAM的方向

    1、来自MCU读写数据流

    2、ILI9341读写GRAM的控制

    1) ILI9341读写GRAM的控制器的结构图

    2) 虚拟地址到物理地址的转换关系

    由此可见,正是通过虚拟地址到物理地址的转换,使得写入到GRAM中图片的映射方向发生了改变。也就是说,通过改变写入GRAM的位置,改变了LCD的显示方向

    3、8中显示方向描述

    看图说明:

    1. MV、MX、MY的控制位在命令0x36对应的寄存器中
    2. Image in the Memory(MPU)中描述的是在MCU的240(宽)*320(高)*16bit(假设565显示方式)中显示了一个图像“F”。
    3. Image In the Driver(Frame Memory)描述的是经过虚拟地址到物理地址转换器后,实际传输到GRAM中的数据显示阵列。
    4. B、E分别描述了MCU传输的数据流的起始位置和终止位置。

    注:(x,y)代表(列地址,行地址)

    example 1: Y-Mirror

       MCU向(0,0)写入数据,经过虚拟地址到物理地址的转换,实际写入到GRAM的地址是(0,319),对应LCD的左下角。MCU向(239,319)写入数据,经过虚拟地址到物理地址的转换,实际写入到GRAM的地址是(239,0),对应LCD的右上角。最终的效果就是LCD的显示实现了Y方向上的翻转。

    example 1: X-Y Exchange

       MCU向(0,0)写入数据,经过虚拟地址到物理地址的转换,实际写入到GRAM的地址是(0,0),对应LCD的左上角。MCU向(239,319)写入数据,经过虚拟地址到物理地址的转换,实际写入到GRAM的地址是(319,239),对应LCD的右下角。

      经过这样的变换,LCD变成了横屏显示。最终的效果就是LCD的显示实现了行列的交换

    4、8种显示方向探秘

      不论哪种显示方向,其实并没有改变GRAM物理内存与LCD显示屏的对应关系,也即是说GRAM物理内存与显示屏之间的对应关系、内存到LCD的扫描方式,是固定不变的。

      那么这种显示方向是怎么说起的?

      实际上,显示方向说的是MCU的显示缓存MPU(或者MCU读写GRAM的数据流)与LCD显示屏的对应关系。由于GRAM物理内存与LCD显示屏的对应关系是不会改变的,所以就是MPU与GRAM的对应关系,也即是虚拟地址与物理地址的转换关系。

      用户在写程序的过程中,LCD显示操作是更改MPU的内容,至于MPU到GRAM的传输是驱动程序完成的。也就是说,用户控制显示的内容,接触的是MPU,而更改显示方向需要配置ILI9341的寄存器。

      其实,ILI9341的扫描方向的功能也可以没有,这个时候需要用户自己软件进行转换,实际上就是那么转换关系表。

    三、测试

    1、左上角->右下角(竖屏)

    2、左下角->右上角(竖屏)

    3、右上角->左下角(竖屏)

    4、右下角->左上角(竖屏)

    5、左上角->右下角(横屏)

    6、左下角->右上角(横屏)

    7、右上角->左下角(横屏)

    8、右下角->左上角(横屏)

     

    参考资料:《ILI9341芯片手册》

    附STM32测试代码:GramScan_Test.zip

    展开全文
  • LCD显示屏显问题

    2020-08-20 15:44:00
    LCD显示屏显问题 lcd显示屏显示时,产生显示错位,错位等问题时有可能是以下两个原因: 第一个是 程序中并未对lcd显示屏进行清屏,lcd显示屏不对某个字显示进行操作的话,会保持原来的状态。 第二个 显示延迟。...

    LCD显示屏显问题

    lcd显示屏显示时,产生显示错位,错位等问题时有可能是以下两个原因:
    		第一个是 程序中并未对lcd显示屏进行清屏,lcd显示屏不对某个字显示进行操作的话,会保持原来的状态。
    		第二个  显示延迟。每个显示函数需要有200us的延迟,可以多个显示语句后统一延迟,如十个显示语句后延迟2000us
    
    展开全文
  • 51单片机LED LCD 显示

    2010-08-15 22:33:44
    51单片机LED LCD 显示LED LCD 显示 51单片机LED LCD 显示LED LCD 显示 51单片机LED LCD 显示LED LCD 显示 51单片机LED LCD 显示LED LCD 显示
  • STM32学习笔记一一TFTLCD 显示

    万次阅读 多人点赞 2017-07-29 14:27:12
    TFT-LCD与无源 TN-LCD、 STN-LCD 的简单矩阵不同,它在液晶显示屏的每一个象素上都设置有一个薄膜晶体管( TFT),可有效地克服非选通时的串扰,使显示液晶屏的静态特性与扫描线数无关,因此大大提高了图像质量。...

    前言:

    为了方便查看博客,特意申请了一个公众号,附上二维码,有兴趣的朋友可以关注,和我一起讨论学习,一起享受技术,一起成长。

    在这里插入图片描述


    1.TFTLCD 简介

    TFT-LCD 即薄膜晶体管液晶显示器。TFT-LCD与无源 TN-LCD、 STN-LCD 的简单矩阵不同,它在液晶显示屏的每一个象素上都设置有一个薄膜晶体管( TFT),可有效地克服非选通时的串扰,使显示液晶屏的静态特性与扫描线数无关,因此大大提高了图像质量。 TFT-LCD 也被叫做真彩液晶显示器。ALIENTEK TFTLCD 模块采用 16 位的并方式与外部连接。

    2.80 并口有如下一些信号线:

    信号线 作用
    CS TFTLCD 片选信号
    WR 向 TFTLCD 写入数据
    RD 从 TFTLCD 读取数据
    D[15: 0] 16 位双向数据线
    RST 硬复位 TFTLCD
    RS 命令/数据标志( 0,读写命令; 1,读写数据)

    注:TFTLCD 模块的 RST 信号线是直接接到 STM32 的复位脚上,并不由软件控制,这样可以省下来一个 IO口。另外我们还需要一个背光控制线来控制 TFTLCD 的背光。所以,我们总共需要的 IO 口数目为 21 个。

    3.ILI9341 控制器介绍

    ILI9341 液晶控制器自带显存,其显存总大小为 172800( 24032018/8),即 18 位模式( 26万色)下的显存量。在 16 位模式下, ILI9341 采用 RGB565 格式存储颜色数据,此时 ILI9341的 18 位数据线与 MCU 的 16 位数据线以及 LCD GRAM 的对应关系如图:

    这里写图片描述

    ILI9341 在 16 位模式下面,数据线有用的是: D17~D13 和 D11~D1, D0和 D12 没有用到,实际上在我们 LCD 模块里面, ILI9341 的 D0 和 D12 压根就没有引出来,这样, ILI9341 的 D17~D13 和 D11~D1 对应 MCU 的 D15~D0。

    MCU 的 16 位数据, 最低 5 位代表蓝色,中间 6 位为绿色,最高 5 位为红色。数值越大,表示该颜色越深。 另外,特别注意 ILI9341 所有的指令都是 8 位的(高 8 位无效),且参数除了读写 GRAM 的时候是 16 位,其他操作参数,都是 8 位的

    4.ILI9341 的重要命令

    (1)0XD3

    这个是读 ID4 指令,用于读取 LCD 控制器的 ID

    这里写图片描述

    可以看出, 0XD3 指令后面跟了 4 个参数,最后 2 个参数,读出来是 0X93 和 0X41,刚好是控制器 ILI9341 的数字部分,从而,通过该指令,即可判别所用的 LCD 驱动器是什么型号,这样,我们的代码,就可以根据控制器的型号去执行对应驱动 IC 的初始化代码,从而兼容不同驱动 IC 的屏,使得一个代码支持多款 LCD。

    (2)0X36

    这是存储访问控制指令,可以控制 ILI9341 存储器的读写方向,简单的说,就是在连续写 GRAM 的时候,可以控制 GRAM 指针的增长方向,从而控制显示方式。(读 GRAM 也是一样)。该指令如表:

    这里写图片描述

    0X36 指令后面,紧跟一个参数,主要关注: MY、 MX、 MV 这三个位,通过这三个位的设置,可以控制整个 ILI9341 的全部扫描方向。

    这里写图片描述

    在利用 ILI9341 显示内容的时候,就有很大灵活性了,比如显示 BMP 图片,BMP 解码数据,就是从图片的左下角开始,慢慢显示到右上角,如果设置 LCD 扫描方向为从左到右,从下到上,那么我们只需要设置一次坐标,然后就不停的往 LCD 填充颜色数据即可,这样可以大大提高显示速度。

    (3)0X2A

    这是列地址设置指令, 在从左到右,从上到下的扫描方式(默认)下面,该指令用于设置横坐标( x 坐标),该指令如表 :

    这里写图片描述

    在默认扫描方式时,该指令用于设置 x 坐标,该指令带有 4 个参数,实际上是 2 个坐标值:SC 和 EC,即列地址的起始值和结束值, SC 必须小于等于 EC,且 0≤SC/EC≤239。一般在设置 x 坐标的时候,我们只需要带 2 个参数即可,也就是设置 SC 即可,因为如果 EC 没有变化,我们只需要设置一次即可(在初始化 ILI9341 的时候设置),从而提高速度。

    (4)0X2B

    是页地址设置指令, 在从左到右,从上到下的扫描方(默认)下面,该指令用于设置纵坐标( y 坐标)。该指令如表:

    这里写图片描述

    在默认扫描方式时,该指令用于设置 y 坐标,该指令带有 4 个参数,实际上是 2 个坐标值:SP 和 EP,即页地址的起始值和结束值, SP 必须小于等于 EP,且 0≤SP/EP≤319。一般在设置y 坐标的时候,我们只需要带 2 个参数即可,也就是设置 SP 即可,因为如果 EP 没有变化,我们只需要设置一次即可(在初始化 ILI9341 的时候设置),从而提高速度。

    (5)0X2C

    该指令是写 GRAM 指令,在发送该指令之后,我们便可以往 LCD的 GRAM 里面写入颜色数据了,该指令支持连续写,指令描述如表:

    这里写图片描述

    在收到指令 0X2C 之后,数据有效位宽变为 16 位,我们可以连续写入 LCD GRAM 值, 而 GRAM 的地址将根据 MY/MX/MV 设置的扫描方向进行自增。

    (6)0X2E

    该指令是读 GRAM 指令,用于读取 ILI9341 的显存( GRAM),输出情况如表:

    这里写图片描述

    该指令用于读取 GRAM,如表 所示,ILI9341在收到该指令后,第一次输出的是 dummy数据,也就是无效的数据,第二次开始,读取到的才是有效的 GRAM 数据(从坐标: SC, SP开始),输出规律为:每个颜色分量占 8 个位,一次输出 2 个颜色分量。

    比如:

    第一次输出是R1G1,随后的规律为:B1R2G2B2R3G3B3R4G4B4R5G5… 以此类推。如果我们只需要读取一个点的颜色值,那么只需要接收到参数 3 即可,如果要连续读取(利用 GRAM 地址自增),那么就按照上述规律去接收颜色数据。

    5.TFTLCD 模块的使用流程

    这里写图片描述

    任何 LCD,使用流程都可以简单的用以上流程图表示。其中硬复位和初始化序列,只需要执行一次即可。而画点流程就是:设置坐标 -> 写 GRAM 指令 -> 写入颜色数据,然后在 LCD 上面,我们就可以看到对应的点显示我们写入的颜色了。读点流程为:设置坐标 -> 读 GRAM 指令 -> 读取颜色数据,这样就可以获取到对应点的颜色数据了。

    1) 设置 STM32 与 TFTLCD 模块相连接的 IO。

    先将我们与 TFTLCD 模块相连的 IO 口进行初始化,以便驱动 LCD。 这里需要根据连接电路以及 TFTLCD 模块的设置来确定。

    2) 初始化 TFTLCD 模块。

    即上图的初始化序列,这里我们没有硬复位 LCD,因为 MiniSTM32 开发板的 LCD 接口,将 TFTLCD 的 RST 同 STM32 的 RESET 连接在一起了,只要按下开发板的 RESET 键,就会对 LCD 进行硬复位。

    初始化序列,就是向 LCD 控制器写入一系列的设置值(比如伽马校准),这些初始化序列一般 LCD 供应商会提供给客户,我们直接使用这些序列即可,不需要深入研究。在初始化之后, LCD 才可以正常使用。

    3) 通过函数将字符和数字显示到 TFTLCD 模块上。

    这一步则通过上图 左侧的流程,即:设置坐标->写 GRAM 指令->写 GRAM 来实现,但是这个步骤,只是一个点的处理,我们要显示字符/数字,就必须要多次使用这个步骤,从而达到显示字符/数字的目标,所以需要设计一个函数来实现数字/字符的显示,之后调用该函数,就可以实现数字/字符的显示了。

    6.实例学习

    (1)在硬件上, TFTLCD 模块与 MiniSTM32 开发板的 IO口对应关系如下:

    功能 IO
    LCD_LED PC10
    LCD_CS PC9
    LCD _RS PC8
    LCD _WR PC7
    LCD _RD PC6
    LCD _D[17:1] PB[15:0]

    (2)时序

    模块的8080并口读/写的过程为:

    先根据要写入/读取的数据的类型,设置RS为高(数据)/低(命令),然后拉低片选,选中ILI9341,接着我们根据是读数据,还是要写数据置RD/WR为低。

    1.读数据:在RD的上升沿, 读取数据线上的数据(D[15:0]);

    这里写图片描述

    2.写数据:在WR的上升沿,使数据写入到ILI9341里面

    这里写图片描述

    3.例程分析

    //LCD重要参数集
    typedef struct  
    {										    
    	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; 
    

    /*写数据函数:通过 80 并口向 LCD 模块写入一个 16 位的数据,宏定义的方式,以提高速度。*/
     #define LCD_WR_DATA(data){\
    	LCD_RS_SET;\
    	LCD_CS_CLR;\
    	DATAOUT(data);\
    	LCD_WR_CLR;\
    	LCD_WR_SET;\
    	LCD_CS_SET;\
    } 	
    
    void LCD_WR_DATAX(u16 data)
    {
    	LCD_RS_SET;
    	LCD_CS_CLR;
    	DATAOUT(data);
    	LCD_WR_CLR;
    	LCD_WR_SET;
    	LCD_CS_SET;
    } 
    

    /*通过 8080 并口向 LCD 模块写入寄存器命令*/
    //写寄存器函数
    //data:寄存器值
    void LCD_WR_REG(u16 data)
    {
    	LCD_RS_CLR;//写地址
    	LCD_CS_CLR;
    	DATAOUT(data);
    	LCD_WR_CLR;
    	LCD_WR_SET;
    	LCD_CS_SET;
    }
    
    /*读取 LCD 控制器的寄存器数据(非 GRAM 数据)*/
    //读 LCD 寄存器数据
    //返回值:读到的值
    u16 LCD_RD_DATA(void)
    {
    	u16 t;
    	GPIOB->CRL=0X88888888; //PB0-7 上拉输入
    	GPIOB->CRH=0X88888888; //PB8-15 上拉输入
    	GPIOB->ODR=0X0000; //全部输出 0
    	LCD_RS_SET;
    	LCD_CS_CLR;
    	LCD_RD_CLR; //读取数据(读寄存器时,并不需要读 2 次)
    	if(lcddev.id==0X8989)delay_us(2);//FOR 8989,延时 2us
    	t=DATAIN;
    	LCD_RD_SET;
    	LCD_CS_SET;
    	GPIOB->CRL=0X33333333; //PB0-7 上拉输出
    	GPIOB->CRH=0X33333333; //PB8-15 上拉输出
    	GPIOB->ODR=0XFFFF; //全部输出高
    	return t;
    }
    

    /*LCD 寄存器操作*/
    //写寄存器:用于向 LCD 指定寄存器写入指定数据
    //LCD_Reg:寄存器编号
    //LCD_RegValue:要写入的值
    void LCD_WriteReg(u16 LCD_Reg,u16 LCD_RegValue)
    {
    	LCD_WR_REG(LCD_Reg);
    	LCD_WR_DATA(LCD_RegValue);
    }
    
    //读寄存器:用于读取指定寄存器的数据
    //LCD_Reg:寄存器编号
    //返回值:读到的值
    u16 LCD_ReadReg(u16 LCD_Reg)
    {
    	LCD_WR_REG(LCD_Reg); //写入要读的寄存器号
    	return LCD_RD_DATA();
    }
    

    /*坐标设置*/
    //设置光标位置:将 LCD 的当前操作点设置到指定坐标(x,y)
    //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);
    	}else if(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);
    	}else if(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_WR_DATA(POINT_COLOR);
    }
    

    //读取个某点的颜色值
    //x,y:坐标
    //返回值:此点的颜色
    u16 LCD_ReadPoint(u16 x,u16 y)
    {
    	u16 r,g,b;
    	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 指令
    	GPIOB->CRL=0X88888888; //PB0-7 上拉输入
    	GPIOB->CRH=0X88888888; //PB8-15 上拉输入
    	GPIOB->ODR=0XFFFF; //全部输出高
    	LCD_RS_SET;
    	LCD_CS_CLR;
    	LCD_RD_CLR; //读取数据(读 GRAM 时,第一次为假读)
    	opt_delay(2); //延时
    	r=DATAIN; //实际坐标颜色
    	LCD_RD_SET;
    	if(lcddev.id==0X1963)
    	{
    	LCD_CS_SET;
    	GPIOB->CRL=0X33333333; //PB0-7 上拉输出
    	GPIOB->CRH=0X33333333; //PB8-15 上拉输出
    	GPIOB->ODR=0XFFFF; //全部输出高
    	return r; //1963 直接读就可以
    	}
    	LCD_RD_CLR; //dummy READ
    	opt_delay(2); //延时
    	r=DATAIN; //实际坐标颜色
    	LCD_RD_SET;
    	if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X5510)//这几个 IC 要分 2 次读出
    	{
    	LCD_RD_CLR;
    	opt_delay(2);//延时
    	b=DATAIN;//读取蓝色值
    	LCD_RD_SET;
    	g=r&0XFF;//对于 9341,第一次读取的是 RG 的值,R 在前,G 在后,各占 8 位
    	g<<=8;
    	}else if(lcddev.id==0X6804)
    	{
    	LCD_RD_CLR;
    	LCD_RD_SET;
    	r=DATAIN;//6804 第二次读取的才是真实值
    	}
    	LCD_CS_SET;
    	GPIOB->CRL=0X33333333; //PB0-7 上拉输出
    	GPIOB->CRH=0X33333333; //PB8-15 上拉输出
    	GPIOB->ODR=0XFFFF; //全部输出高
    	if(lcddev.id==0X9325||lcddev.id==0X4535||lcddev.id==0X4531||lcddev.id==0X8989||
    	lcddev.id==0XB505)return r; //这几种 IC 直接返回颜色值
    	else if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X5510)
    	return (((r>>11)<<11)|((g>>10)<<5)|(b>>11));//这几个 IC 需要公式转换一下
    	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-' ';//得到偏移后的值
    	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(x>=lcddev.width)return; //超区域了
    	if((y-y0)==size)
    	{
    	y=y0; x++;
    	if(x>=lcddev.width)return; //超区域了
    	break;
    			}
    		}
    	}
    }
    

    //该初始化函数可以初始化各种 ALIENTEK 出品的 LCD 液晶屏
    void LCD_Init(void)
    { 
     	GPIO_InitTypeDef GPIO_InitStructure;
     	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE); //使能PORTB,C时钟和AFIO时钟
    	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);//开启SWD,失能JTAG
    	
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_9|GPIO_Pin_8|GPIO_Pin_7|GPIO_Pin_6;	   ///PORTC6~10复用推挽输出
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOC, &GPIO_InitStructure); //GPIOC	
    
    	GPIO_SetBits(GPIOC,GPIO_Pin_10|GPIO_Pin_9|GPIO_Pin_8|GPIO_Pin_7|GPIO_Pin_6);
    
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;	//  PORTB推挽输出
    	GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
     
    	GPIO_SetBits(GPIOB,GPIO_Pin_All);
    
    	delay_ms(50); // delay 50 ms 
    	LCD_WriteReg(0x0000,0x0001);
    	delay_ms(50); // delay 50 ms 
      	lcddev.id = LCD_ReadReg(0x0000);   
    	if(lcddev.id<0XFF||lcddev.id==0XFFFF||lcddev.id==0X9300)//读到ID不正确,新增lcddev.id==0X9300判断,因为9341在未被复位的情况下会被读成9300
    	{	
     		//尝试9341 ID的读取		
    		LCD_WR_REG(0XD3);				   
    		LCD_RD_DATA(); 				//dummy read 	
     		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);				   
    			LCD_RD_DATA(); 			//dummy read 	 
    	 		LCD_RD_DATA();   	    //读回0X01			   
    	 		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);				   
    				LCD_RD_DATA(); 				//dummy read  
    				LCD_RD_DATA();   			//读回0X01	 
    				lcddev.id=LCD_RD_DATA();	//读回0X53	
    				lcddev.id<<=8;	 
    				lcddev.id|=LCD_RD_DATA();	//这里读回0X10	 
    				if(lcddev.id!=0X5310)		//也不是NT35310,尝试看看是不是NT35510
    				{
    					LCD_WR_REG(0XDA00);	
    					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)			//也不是NT5510,尝试看看是不是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初始化
    	{	 
    		LCD_WR_REG(0xCF);  
    		LCD_WR_DATAX(0x00); 
    		LCD_WR_DATAX(0xC1); 
    		LCD_WR_DATAX(0X30); 
    		LCD_WR_REG(0xED);  
    		LCD_WR_DATAX(0x64); 
    		LCD_WR_DATAX(0x03); 
    		LCD_WR_DATAX(0X12); 
    		LCD_WR_DATAX(0X81); 
    		LCD_WR_REG(0xE8);  
    		LCD_WR_DATAX(0x85); 
    		LCD_WR_DATAX(0x10); 
    		LCD_WR_DATAX(0x7A); 
    		LCD_WR_REG(0xCB);  
    		LCD_WR_DATAX(0x39); 
    		LCD_WR_DATAX(0x2C); 
    		LCD_WR_DATAX(0x00); 
    		LCD_WR_DATAX(0x34); 
    		LCD_WR_DATAX(0x02); 
    		LCD_WR_REG(0xF7);  
    		LCD_WR_DATAX(0x20); 
    		LCD_WR_REG(0xEA);  
    		LCD_WR_DATAX(0x00); 
    		LCD_WR_DATAX(0x00); 
    		LCD_WR_REG(0xC0);    //Power control 
    		LCD_WR_DATAX(0x1B);   //VRH[5:0] 
    		LCD_WR_REG(0xC1);    //Power control 
    		LCD_WR_DATAX(0x01);   //SAP[2:0];BT[3:0] 
    		LCD_WR_REG(0xC5);    //VCM control 
    		LCD_WR_DATAX(0x30); 	 //3F
    		LCD_WR_DATAX(0x30); 	 //3C
    		LCD_WR_REG(0xC7);    //VCM control2 
    		LCD_WR_DATAX(0XB7); 
    		LCD_WR_REG(0x36);    // Memory Access Control 
    		LCD_WR_DATAX(0x48); 
    		LCD_WR_REG(0x3A);   
    		LCD_WR_DATAX(0x55); 
    		LCD_WR_REG(0xB1);   
    		LCD_WR_DATAX(0x00);   
    		LCD_WR_DATAX(0x1A); 
    		LCD_WR_REG(0xB6);    // Display Function Control 
    		LCD_WR_DATAX(0x0A); 
    		LCD_WR_DATAX(0xA2); 
    		LCD_WR_REG(0xF2);    // 3Gamma Function Disable 
    		LCD_WR_DATAX(0x00); 
    		LCD_WR_REG(0x26);    //Gamma curve selected 
    		LCD_WR_DATAX(0x01); 
    		LCD_WR_REG(0xE0);    //Set Gamma 
    		LCD_WR_DATAX(0x0F); 
    		LCD_WR_DATAX(0x2A); 
    		LCD_WR_DATAX(0x28); 
    		LCD_WR_DATAX(0x08); 
    		LCD_WR_DATAX(0x0E); 
    		LCD_WR_DATAX(0x08); 
    		LCD_WR_DATAX(0x54); 
    		LCD_WR_DATAX(0XA9); 
    		LCD_WR_DATAX(0x43); 
    		LCD_WR_DATAX(0x0A); 
    		LCD_WR_DATAX(0x0F); 
    		LCD_WR_DATAX(0x00); 
    		LCD_WR_DATAX(0x00); 
    		LCD_WR_DATAX(0x00); 
    		LCD_WR_DATAX(0x00); 		 
    		LCD_WR_REG(0XE1);    //Set Gamma 
    		LCD_WR_DATAX(0x00); 
    		LCD_WR_DATAX(0x15); 
    		LCD_WR_DATAX(0x17); 
    		LCD_WR_DATAX(0x07); 
    		LCD_WR_DATAX(0x11); 
    		LCD_WR_DATAX(0x06); 
    		LCD_WR_DATAX(0x2B); 
    		LCD_WR_DATAX(0x56); 
    		LCD_WR_DATAX(0x3C); 
    		LCD_WR_DATAX(0x05); 
    		LCD_WR_DATAX(0x10); 
    		LCD_WR_DATAX(0x0F); 
    		LCD_WR_DATAX(0x3F); 
    		LCD_WR_DATAX(0x3F); 
    		LCD_WR_DATAX(0x0F); 
    		LCD_WR_REG(0x2B); 
    		LCD_WR_DATAX(0x00);
    		LCD_WR_DATAX(0x00);
    		LCD_WR_DATAX(0x01);
    		LCD_WR_DATAX(0x3f);
    		LCD_WR_REG(0x2A); 
    		LCD_WR_DATAX(0x00);
    		LCD_WR_DATAX(0x00);
    		LCD_WR_DATAX(0x00);
    		LCD_WR_DATAX(0xef);	 
    		LCD_WR_REG(0x11); //Exit Sleep
    		delay_ms(120);
    		LCD_WR_REG(0x29); //display on	
    	}	
    	LCD_Display_Dir(0);		 	//默认为竖屏
    	LCD_LED=1;					//点亮背光
    	LCD_Clear(WHITE);
    }  		
    

    注:此处仅为9341 的初始化


    参考:

    原子开发手册-----库函数版

    展开全文
  • 想知道emmc换成flash会影响lcd显示屏吗? 或者说eeprom会影响到lcd显示屏吗? 若没有关系话,就不用动uboot了。 按常理说lcd显示屏只是板子上的输入输出的接口,当给bbb上电后会到处理器的 rom运行再到flash的...
  • Arduino——LCD显示实验

    千次阅读 2020-03-05 15:45:39
    用Arduino Nano连接IIC LCD显示器模块上...学会使用LCD显示屏,静态显示或则滚动显示,并可以调整速度 原理图: 流程图: 代码加粗样式 #include <Wire.h> // Arduino IDE 內建 #include <LiquidCrystal_I...
  • 使用Arduino连接一个LCD显示

    万次阅读 多人点赞 2019-06-19 22:10:00
    使用Arduino连接一个LCD显示屏,为您的项目提供显示。 将字符LCD显示屏连接到Arduino开发板,为您的项目添加了一个很好的可读性元素。世界上许多最好的Arduino项目都有液晶显示器。这些L...
  • LCD显示摄像头图像

    2020-06-29 11:56:00
    我们将从摄像头读到数据在LCD上显示,首先将摄像头数据读出到一块内存上,然后设置好LCD控制器从这块内存读取数据到LCD显示屏上,对于摄像头数据格式来说有YUV,MJPEG,RGB,而我们的LCD只支持RGB格式的数据格式,所以这...
  • 嵌入式LCD显示业务优化笔记 在嵌入式电子产品的设计中,不可避免的要涉及到LCD的显示,显示设计没有多难,每一屏的内容设计出来开个定时器延时刷屏就好,难的是在未来业务变化时如何很便捷的添加一屏内容上去。 有人...
  • STM32单片机TFTLCD显示实验:TFTLCD简介

    千次阅读 2020-02-13 21:55:02
    STM32单片机TFTLCD显示实验学习笔记 1、TFTLCD模块接口图 以2.8寸的TFTLCD为例,采用16位的并方式与外界进行连接,模块接口图如下所示: 具有如下一些信号线: CS:TFTLCD片选信号 WR:向TFTLCD写入数据 RD:从TFT...
  • 6410LCD显示配置

    千次阅读 2014-12-28 14:33:01
    6410LCD显示寄存器配置
  • 文章目录一、TFTLCD显示白屏1.1修改读写寄存器1.2修改字体导出变量二、TFTLCD出现镜像显示解决方法 一、TFTLCD显示白屏 可以先看看这篇博客,看能不能解决你的问题 显示屏已亮,那电源接线是肯定没有问题的,硬件...
  • stm32专题二十一:LCD显示原理

    千次阅读 2019-09-09 23:30:15
    LCD显示原理
  • STM32CubeMX系列|TFTLCD显示

    千次阅读 2020-10-09 21:40:55
    TFTLCD显示 1. TFTLCD显示简介 2. 硬件设计 3. 软件设计 3.1 STM32CubeMX设置 3.2 MDK-ARM编程 4. 下载验证
  • 调试lcd显示

    2012-11-23 13:31:22
    今天又一次调试lcd显示了。是在原来显示的基础上增加了显示分辨率。 1 首先要高清楚的分辨率所对应的pclk是多少??  1280x720p的一般是74.25Mx2 2 接着设置lcd屏的timing;  hfrontporch 对应的是left...
  • STM32控制TFTLCD显示

    万次阅读 多人点赞 2018-02-26 22:30:43
    一、用STM32控制TFTLCD显示的编程方法,在编程驱动TFTLCD液晶显示器之前,我们先熟悉以下概念:1、色彩深度,这是一个与TFTLCD显存对应的概念;所谓色彩深度就是每个像素点需要多少位的RGB 数据表示该点的颜色信息...
  • TFT_LCD显示图片总结

    千次阅读 2019-04-16 16:27:26
    1.给出实现显示picture的main函数代码,包括初始化,和调用显示图片代码;...然后就是LCD_DisplayString等LCD显示调用函数,这些可以理解为LCD配套编写的显示函数,这里也是用的示例; 2.然后就是图片该怎么去在...
  • 优秀的LCD显示效果

    2017-10-09 20:33:26
    优秀的LCD显示效果 效果图: 程序和源代码链接:
  • 本篇记录LCD显示屏加入百叶窗特效显示BMP图片,通过双线程并行显示,实现百叶窗特效。在显示函数中,已对BMP图片显示位置进行了居中设置,而缩小倍数只需通过在调用函数时进行传参即可。具体代码如下: myhead.h部分...
  • LCD显示屏UI界面

    千次阅读 2017-08-03 12:19:56
    LCD显示屏UI界面硬件:德飞莱STM32开发板M3S(STM32F103ZE) LCD控制器 ILI9325 LCD屏幕大小320×240 软件:keil uVision4 固件库:STM32F10x_StdPeriph_Lib_V3.5.0 uCOSIII版本:Release V3.02.00 (2011/08/01)该...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 18,714
精华内容 7,485
关键字:

lcd显示