• 【屏幕模块 - 笔记】深圳市晶联讯电子 液晶模块 JLX19296G-915-BN


    最近工作在用这款屏幕,折腾两星期后差不多摸透了,写下笔记给日后的自己,和有需要的人.

    一、屏幕介绍

    • 型号 : JLX19296G-915-BN , 这个型号属于裸屏,焊接式 FPC,没有自带字库.尺寸为192*96 .
    • 特点 : 能串行也能并行通讯, 多种显示扫描方向,有单色和灰度,能亮和不亮背光.对比度设置.
    • 实现 : 我实现的是硬件串行; 扫描方向是自上到下,从左到右,低位在上; 单色;亮不亮背光取决于有没有给背光供电,有就亮,没有就不亮.
    • 相关 : 官网链接 http://www.jlxlcd.cn/html/zh-detail-877.html ; pdf 说明文档也在里面下载.
    • 注意 : 不同型号的引脚不太一样,初始化的部分参数不一样,其它差不多(虽然我没用过多款,但是对比pdf手册感觉是一样的 )

    二、代码解析

    不说废话,直接按着代码一步步解说 .

    1. 单片机通讯引脚 的 初始化

    • 这部分主要是gpio的初始化,不同单片机平台的api接口不一样,自行测试更换.建议一开始拿着裸机的spi例程修改,事半功倍.
    • 只有两点需要 注意 的:
    1. 模块正常工作时,复位引脚接高电平,需要复位就拉低,保持,再拉高.如果悬空或没有接高电平,就不能使用,惨痛的教训!!!
    2. 串行通讯使用spi协议,感觉pdf的时序图,是在时钟线scl从低电平跳变高电平时读取sda的数据,从pdf自带例程的模拟通讯实现也能看出来.时钟线先保持低电平,改变数据线,时钟线跳变拉高读取数据; 在硬件spi设置中就是模式0 (CPOL=0; CPHA=0).波特率的设置根据单片机不同,可以自己算也可以自己试,我是从快到慢一个个试.

    推荐笔记 : SPI总线传输的4种模式 https://www.cnblogs.com/gmpy/p/12461461.html
    在这里插入图片描述

    
    /*******************************************************************************
     * 局部宏定义
     ******************************************************************************/
    #if 1   // 外部实现
    #define lcd_cs1(x)     Spi_SetCS(M0P_SPI1, x);Gpio_WriteOutputIO(PORT_S3_SSEL, PIN_S3_SSEL, x) //CS 
    #define lcd_reset(x)   ;//RST   lcd_reset(0)    lcd_reset(1) // 使用时不需要复位,就不接
    #define lcd_sclk(x)    Gpio_WriteOutputIO(PORT_S3_SCLK, PIN_S3_SCLK, x) //串行时钟  lcd_sclk(0) lcd_sclk(1)
    #define lcd_rs(x)      Gpio_WriteOutputIO(PORT_S3_MISO, PIN_S3_MISO, x) //RS        lcd_rs(0)   lcd_rs(1) 
    #define lcd_sid(x)     Gpio_WriteOutputIO(PORT_S3_MOSI, PIN_S3_MOSI, x) //串行数据  lcd_sid(0)  lcd_sid(1)
    #endif
    
    /*******************************************************************************
     * 函数实现-全局(“外部”)和局部(“静态”)
     ******************************************************************************/
    
    /**     // 外部实现
     *******************************************************************************
     ** \brief  板级引脚初始化
     ** \retval None
     ******************************************************************************/
    static void gpio_bsp_init(void)
    {
    	// 具体实现略,不同单片机平台不一样,不赘述.
    	
    	// 初始化 gpio 引脚
    	// 初始化 spi 外设 模式0,波特率自行测试
    	
    	// 注意 该屏幕的spi通讯并不需要输入, 
    	// MISO 引脚被用作输出,输出高电平代表MOSI输出数据,输出低电平代表MOSI输出指令
    	
    	// 如果控模块电源引脚,别忘记打开;
    	// 复位引脚必须接高电平
    }
    
    /**     // 外部实现
     *******************************************************************************
     ** \brief  板级延时
     ** \param  i           延时毫秒
     ** \retval None
     ******************************************************************************/
    static void lcd_jlx19296_delay_ms(int i)
    {
        delay10us(i*10);
    }
    
    /**     // 外部实现
     *******************************************************************************
     ** \brief  板级模块复位
     ** \param  i           延时毫秒
     ** \retval None
     ******************************************************************************/
    static void lcd_jlx19296_reset(void)
    {
    	// 如果没有复位操作就将复位引脚接高电平,才能正常工作!!!!!
        lcd_reset(0);
        lcd_jlx19296_delay_ms(100);
        lcd_reset(1);
        lcd_jlx19296_delay_ms(100);
    }
    
    /**     // 外部实现
     *******************************************************************************
     ** \brief  发送指令
     ** \param  data1       8位/1字节的指令
     ** \retval None
     ******************************************************************************/
    static void lcd_jlx19296_cmd(uint32_t data1)
    {
    	lcd_cs1(0);
    	lcd_rs(0);
    	// 模拟spi的方法
    	/*for(int i=0; i<8; i++) 
    	{
    		lcd_sclk(0); // 时钟线先保持低电平
    		if(data1&0x80) lcd_sid(1); // 改变数据线
    		else lcd_sid(0);
    		lcd_sclk(1); // 时钟线跳变拉高,读取数据线
    		data1<<=1;
    	}*/
    	// 硬件spi的方法
        while(Spi_GetStatus(M0P_SPI1, SpiTxe) == FALSE);    //发送缓冲器器空标志
        Spi_SendData(M0P_SPI1, data1);
        
    	lcd_cs1(1);
    }
    
    /**     // 外部实现
     *******************************************************************************
     ** \brief  发送数据
     ** \param  data1       8位/1字节的数据
     ** \retval None
     ******************************************************************************/
    static void lcd_jlx19296_data(uint32_t data1)
    {
    	lcd_cs1(0);
    	lcd_rs(1) ;
    	// 模拟spi的方法
    	/*for(int i=0; i<8; i++)
    	{
    		lcd_sclk(0); // 时钟线先保持低电平
    		if(data1&0x80) lcd_sid(1); // 改变数据线
    		else lcd_sid(0);
    		lcd_sclk(1); // 时钟线跳变拉高,读取数据线
    		data1<<=1;
    	}*/
    	// 硬件spi的方法
        while(Spi_GetStatus(M0P_SPI1, SpiTxe) == FALSE);    //发送缓冲器器空标志
        Spi_SendData(M0P_SPI1, data1);
        
    	lcd_cs1(1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112

    2. 屏幕模块 的 初始化

    • 这部分就是拷贝pdf例程的内容的了,我对比多个型号的pdf例程,和指令表内容, 发现模块初始化这部分内容,不同型号的例程存在坑爹的赋值粘贴嫌疑 ,也就是有部分注释没改或没有用的多余内容,但不影响使用.

    • 可以屏幕说明pdf有附带中文指令表说明,网上也有 ST75256 (屏幕内嵌的主控芯片) 说明手册的中文版,可以对照查看.

    • 这部分我无聊的将每个指令都化作宏定义,查看手册表明注释和分类.如下.最后总结需要重点关注的内容:

    1. 数据扫描方向 Data_Scan_Direction_0 : 决定了扫描方向 自上到下,从左到右.
    2. 数据格式选择 Data_Format_Select : 决定了 低位在上.
    3. 显示模式 Display_Mode_0 : 决定了单色模式.
    4. 设置对比度 Set_Vop_0 : 决定屏幕整体显示偏黑还是偏透明.
    5. 显示控制 Display_Control_0 : (重点) 我起初将这个误以为是对比度,修改后导致显示坐标发生整体偏移,所以这部分内容不要修改,直接拷贝例程最好.
    • 如果你初始化成功会看到屏幕是"雪花屏"的效果,之后调用清屏即可.如果你初始化后屏幕没有任何显示,代表初始化失败了,可能没成功通讯,检查通讯引脚,模块电源,还有复位引脚有没有接高电平.
    /*******************************************************************************
     * 全局宏定义    // https://max.book118.com/html/2017/1025/137875607.shtm
     ******************************************************************************/
    // 1. 设置扩展指令
    #define Extension_Command(EXT1, EXT0)   ((0x30)|(((EXT1)&0x1)<<3)|(((EXT0)&0x1)<<0)) 	
    // ======================= 指令 1 =======================
    // 2. 显示开/关 设置LCD显示器 DSP=0;显示关闭 DSP=1;显示打开
    #define Display_ON_OFF(DSP)  	    ((0xAE)|(((DSP)&0x1)<<0))	
    // 3. 反转显示 设置反向显示 INV=0;正常显示 INV=1;反向显示
    #define Inverse_Display(INV)  	    ((0xA6)|(((INV)&0x1)<<0))	
    // 4. 所有像素开/关 设置所有像素模式 AP=0;全像素关闭模式 AP=1;全像素开启模式
    #define All_Pixel_ON_OFF(AP)  	    ((0x22)|(((AP)&0x1)<<0))	
    // 5. 显示控制  CLD;设置CL驱动频率 DT;点空比 LF/FI;帧周期
    #define Display_Control_0()  	    (0xCA)
    #define Display_Control_1(CLD)		((0x00)|(((CLD)&0x1)<<2))
    #define Display_Control_2(DT)		((0x00)|(((DT)&0xFF)<<0))
    #define Display_Control_3(LF, FI)	((0x00)|(((LF)&0xF)<<0)|(((FI)&0x1)<<4)|(((LF)&0x10)<<1))
    // 6. 省电 设置省电模式 SLP=0;退出休眠模式 SLP=1;进入休眠模式
    #define Power_Save(SLP)  		    ((0x94)|(((SLP)&0x1)<<0))
    // 7. 设置页面地址 起始页面地址;00H<=YS<=28H 结束页面地址;YS<=YE<=28H
    #define Set_Page_Address_0()  	    (0x75)
    #define Set_Page_Address_1(YS)  	((0x00)|(((YS)&0xFF)<<0))
    #define Set_Page_Address_2(YE)  	((0x00)|(((YE)&0xFF)<<0))
    // 8. 设置列地址 起始列地址;00H<=XS<=FFH 结束列地址;XS<=XE<=FFH
    #define Set_Column_Address_0()	    (0x15)
    #define Set_Column_Address_1(XS)	((0x00)|(((XS)&0xFF)<<0))
    #define Set_Column_Address_2(XE)	((0x00)|(((XE)&0xFF)<<0))
    // 9. 数据扫描方向 设置正/反显示地址 和 地址扫描方向
    #define Data_Scan_Direction_0()		(0xBC)
    #define Data_Scan_Direction_1(MV, MX, MY) 	((0x00)|(((MV)&0x1)<<2)|(((MX)&0x1)<<1)|(((MY)&0x1)<<0))
    // 10. 写数据 循环写数据
    #define Write_Data_0()				(0x5C)
    #define Write_Data_1(DATA)			((0x00)|(((DATA)&0xFF)<<0))
    // 20. 电源控制 功率电路操作 =0;OFF =1;ON
    #define Power_Control_0()			(0x20)
    #define Power_Control_1(VB,VF,VR) 	((0x00)|(((VB)&0x1)<<3)|(((VF)&0x1)<<1)|(((VR)&0x1)<<0))
    // 21. 设置VOP 设置对比度 微调对比度,可调范围0x00~0x3f,共64级 粗调对比度,可调范围0x00~0x07,共8级
    #define Set_Vop_0()					(0x81)
    #define Set_Vop_1(VOP)				((0x00)|(((VOP)&0x3F)<<0))
    #define Set_Vop_2(VOP)				((0x00)|(((VOP)&0x7)<<0))
    // 27. 数据格式选择 DO=0;高位在前 DO=1;低位在前
    #define Data_Format_Select(DO)      ((0X8)|(((DO)&0x1)<<2))
    // 28. 显示模式 设置显示模式 DM=0;单色(默认) DM=1;4级灰度模式
    #define Display_Mode_0()			(0xF0)
    #define Display_Mode_1(DM)			((0x10)|(((DM)&0x1)<<0))
    // ======================= 指令 2 =======================
    // 31.设定灰度 GL;设置轻灰色级别 GD;设定暗灰色等级
    #define Set_Gray_Level_0()			(0x20)
    #define Set_Gray_Level_1(HD)	    ((0x00)|(((HD)&0x1F)<<0))
    #define Set_Gray_Level_2(HD)	    ((0x00)|(((HD)&0x1F)<<0))
    #define Set_Gray_Level_3(HD)		((0x00)|(((HD)&0x1F)<<0))
    #define Set_Gray_Level_4(GL)		((0x00)|(((GL)&0x1F)<<0))
    #define Set_Gray_Level_5(GL)		((0x00)|(((GL)&0x1F)<<0))
    #define Set_Gray_Level_6(GL)		((0x00)|(((GL)&0x1F)<<0))
    #define Set_Gray_Level_7(HD)	    ((0x00)|(((HD)&0x1F)<<0))
    #define Set_Gray_Level_8(HD)		((0x00)|(((HD)&0x1F)<<0))
    #define Set_Gray_Level_9(GD)		((0x00)|(((GD)&0x1F)<<0))
    #define Set_Gray_Level_10(HD)		((0x00)|(((HD)&0x1F)<<0))
    #define Set_Gray_Level_11(HD)		((0x00)|(((HD)&0x1F)<<0))
    #define Set_Gray_Level_12(GD)		((0x00)|(((GD)&0x1F)<<0))
    #define Set_Gray_Level_13(GD)		((0x00)|(((GD)&0x1F)<<0))
    #define Set_Gray_Level_14(GD)		((0x00)|(((GD)&0x1F)<<0))
    #define Set_Gray_Level_15(HD)		((0x00)|(((HD)&0x1F)<<0))
    #define Set_Gray_Level_16(HD)		((0x00)|(((HD)&0x1F)<<0))
    // 32. LCD偏压比设置 BE;升压电容频率 BS;偏压比,
    #define Analog_Circuit_Set_0()		(0x32)
    #define Analog_Circuit_Set_1()		(0x00)
    #define Analog_Circuit_Set_2(BE)	((0x00)|(((BE)&0x3)<<0))
    #define Analog_Circuit_Set_3(BS)	((0x00)|(((BS)&0x7)<<0))
    // 35. 自动读取控制 设置自动读取指令 XARD=0;启用自动读取 XARD=1;禁用自动读取
    #define Auto_Read_Control_0()	    (0xD7)
    #define Auto_Read_Control_1(XARD)	((0x8F)|(((XARD)&0x1)<<4))
    // 42. 帧速率 此指令比较重要,不加此指令升压会慢 0.5s  帧速率设置在不同的温度范围
    #define Set_Frame_Rate_0()          (0xF0)
    #define Set_Frame_Rate_1(FRA)       ((0x00)|(((FRA)&0x1F)<<0))
    #define Set_Frame_Rate_2(FRB)       ((0x00)|(((FRB)&0x1F)<<0))
    #define Set_Frame_Rate_3(FRC)       ((0x00)|(((FRC)&0x1F)<<0))
    #define Set_Frame_Rate_4(FRD)       ((0x00)|(((FRD)&0x1F)<<0))
    // ======================= 指令 3 =======================
    // 用不到
    // ======================= 指令 4 =======================
    // 用不到
    
    /**
     *******************************************************************************
     ** \brief  模块初始化
     ** \retval None
     ******************************************************************************/
    void lcd_jlx19296_init(void)
    {
        gpio_bsp_init();
        lcd_jlx19296_delay_ms(100);
        
        lcd_jlx19296_reset();    // 奇葩的屏幕,复位引脚要一直处于高电平
    
        lcd_jlx19296_cmd(Extension_Command(0,0));           // EXT1=0,EXT0=0,表示选择了“扩展指令表 1” 
        lcd_jlx19296_cmd(Power_Save(0));                    // 退出睡眠 
        
        lcd_jlx19296_cmd(Extension_Command(0,1));           // EXT1=0,EXT0=1,表示选择了“扩展指令表 2” 
        lcd_jlx19296_cmd(Auto_Read_Control_0());            // 自动读取设置 指令
        lcd_jlx19296_data(Auto_Read_Control_1(1));          // 自动读取禁用
        
        lcd_jlx19296_cmd(Analog_Circuit_Set_0());           // LCD 偏压比设置 指令
        lcd_jlx19296_data(Analog_Circuit_Set_1());          // 振荡频率的调整 
        lcd_jlx19296_data(Analog_Circuit_Set_2(1));         // 升压电容器的频率->6KHz 
        lcd_jlx19296_data(Analog_Circuit_Set_3(3));         // Bias=1/11 
    
        lcd_jlx19296_cmd(Set_Frame_Rate_0());               // 帧速率 帧速率设置在不同的温度范围
        lcd_jlx19296_data(Set_Frame_Rate_1(0xF));           // 此指令比较重要,不加此指令升压会慢 0.5s
        lcd_jlx19296_data(Set_Frame_Rate_2(0xF));   
        lcd_jlx19296_data(Set_Frame_Rate_3(0xF)); 
        lcd_jlx19296_data(Set_Frame_Rate_4(0xF)); 
        
        /*lcd_jlx19296_cmd(Set_Gray_Level_0());             // 灰度设置 
        lcd_jlx19296_data(Set_Gray_Level_1(0x01));          // 没有用到灰度,也是摆设
        lcd_jlx19296_data(Set_Gray_Level_2(0x03)); 
        lcd_jlx19296_data(Set_Gray_Level_3(0x05));
        lcd_jlx19296_data(Set_Gray_Level_4(0x07)); 
        lcd_jlx19296_data(Set_Gray_Level_5(0x09)); 
        lcd_jlx19296_data(Set_Gray_Level_6(0x0b)); 
        lcd_jlx19296_data(Set_Gray_Level_7(0x0d)); 
        lcd_jlx19296_data(Set_Gray_Level_8(0x10)); 
        lcd_jlx19296_data(Set_Gray_Level_9(0x11)); 
        lcd_jlx19296_data(Set_Gray_Level_10(0x13)); 
        lcd_jlx19296_data(Set_Gray_Level_11(0x15)); 
        lcd_jlx19296_data(Set_Gray_Level_12(0x17)); 
        lcd_jlx19296_data(Set_Gray_Level_13(0x19)); 
        lcd_jlx19296_data(Set_Gray_Level_14(0x1b)); 
        lcd_jlx19296_data(Set_Gray_Level_15(0x1d)); 
        lcd_jlx19296_data(Set_Gray_Level_16(0x1f));*/
        
        lcd_jlx19296_cmd(Extension_Command(0,0));           // EXT1=0,EXT0=0,表示选择了“扩展指令表 1” 
    	/*lcd_jlx19296_cmd(Set_Column_Address_0());         // 设置列地址
    	lcd_jlx19296_data(Set_Column_Address_1(0x00));      // 在这里设置行列坐标貌似是摆设,没有用
    	lcd_jlx19296_data(Set_Column_Address_1(0xC0));
    	lcd_jlx19296_cmd(Set_Page_Address_0());             // 设置页面地址
    	lcd_jlx19296_data(Set_Page_Address_1(0x00));        
    	lcd_jlx19296_data(Set_Page_Address_2(0x60));*/
        
        lcd_jlx19296_cmd(Data_Scan_Direction_0());          // 数据扫描方向 
        lcd_jlx19296_data(Data_Scan_Direction_1(1, 0, 0));  // DATA 0x04h (MV =1, MX=0, MY=0)
    
        lcd_jlx19296_cmd(Data_Format_Select(1));            // 数据格式选择, 1 是低位在前 D0-D7, 0 是高位在前 D7-D0 
        
        lcd_jlx19296_cmd(Display_Mode_0());                 // 显示模式 
        lcd_jlx19296_data(Display_Mode_1(0));               // 如果设为 1:表示选择 4 灰度级模式,如果设为 0:表示选择黑白模式 
        
        lcd_jlx19296_cmd(Display_Control_0());              // 显示控制 
        lcd_jlx19296_data(Display_Control_1(0));            // 设置 CL 驱动频率:CLD=0 
        lcd_jlx19296_data(Display_Control_2(0X5F));         // 0X5F // 占空比:Duty=128 
        lcd_jlx19296_data(Display_Control_3(0x10, 0));      // N 行反显:Nline=off 
        
        lcd_jlx19296_cmd(Set_Vop_0());                      // 设置对比度,“0x81”不可改动,紧跟着的 2 个数据是可改的,但“先微调后粗调”这个顺序别乱了 
        lcd_jlx19296_data(Set_Vop_1(0x14));                 // 0x7 // 0x14 // 0x22 // 对比度微调,可调范围 0x00~0x3f,共 64 级 
        lcd_jlx19296_data(Set_Vop_2(0x03));                 // 0x03 // 对比度粗调,可调范围 0x00~0x07,共 8 级 
        
        lcd_jlx19296_cmd(Power_Control_0());                // 电源控制
        lcd_jlx19296_data(Power_Control_1(1,1,1));          // D0=regulator ; D1=follower ; D3=booste, on:1 off:0 
        
        lcd_jlx19296_delay_ms(100); 
        lcd_jlx19296_cmd(Display_ON_OFF(1));                // 打开显示
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162

    3. 屏幕显示

    • 首先就是设置显示区域,也就是行列坐标的起始和结束点.然后输入写数据.这部分操作和大部分屏幕操作类似.清屏函数就是设置全屏区域,然后输入空数据.

    • 值得 注意 的是显示区域的设置, 屏幕内嵌的主控芯片ST75256 规定,纵向坐标是 8个像素点1组 .也就说192*96的屏幕,横向x坐标输入范围是0~191,而纵向y坐标输入范围则是 0~11 (96/8=12组). 这意味着刷新时是8行1组像素点一起刷新的,如果想交叉组显示内容就颇为麻烦.

    这款除了单色外,还支持四级灰度显示,貌似设置显示区域的部分不变.输入数据的部分需要加倍输入.

    如果你在初始化时,修改了 显示控制 Display_Control_0的参数,那设置坐标就会发生偏移,而且刷新速度大大减低.如果你发现刷新速度肉眼可见的慢,纵向y坐标范围不是0~11,而是8~19.那你可以怀疑是不是这里个参数初始化错了.

    • 然后就是控制单个点显示内容了.如果一时不理解显示方向,就用修改清屏函数然后单步调试,再用纸笔笔画一下就理解了.
    /**
     *******************************************************************************
     ** \brief  设置显示的区域 设置行列地址
     ** \param  xs          开始列地址 0~191
     ** \param  xe          结束列地址
     ** \param  ys          开始行地址 0~11
     ** \param  ye          结束行地址
     ** \retval None
     ******************************************************************************/
    static void lcd_jlx19296_address(uint32_t xs,uint32_t xe,uint32_t ys,uint32_t ye)
    {    
        xs = xs-0;
        xe = xe-0;
        ys = ys+0;
        ye = ye+0; 
        
    // ======================= 特别说明 =======================
    // 根据实测,
    // y的取值范围是 0~11,共12行,
    // x的取值范围是 0~191,共192列,     
    // 如果发生偏移,是 Display_Control_0 指令参数有误,要按照例程来,调整对比度不是调整这个
    // ======================= 特别说明 =======================
        
    	lcd_jlx19296_cmd(Set_Column_Address_0());          // 设置列地址
    	lcd_jlx19296_data(Set_Column_Address_1(xs));
    	lcd_jlx19296_data(Set_Column_Address_1(xe));
    	lcd_jlx19296_cmd(Set_Page_Address_0());            // 设置页面地址
    	lcd_jlx19296_data(Set_Page_Address_1(ys));         // 注意,页地址是以4为单位
    	lcd_jlx19296_data(Set_Page_Address_2(ye));
    	lcd_jlx19296_cmd(Write_Data_0());                  // 写数据 循环写数据
    }
    
    /**
     *******************************************************************************
     ** \brief  清屏
     ** \retval None
     ******************************************************************************/
    void lcd_jlx19296_clear_screen(void)
    {
        // 设置显示区域
    	lcd_jlx19296_address(0,191,0,11);  
        // 输入显示数据
    	for(int i=0; i<192; i++)
    	{
    		for(int j=0; j<12; j++)
    		{
    			lcd_jlx19296_data(Write_Data_1(0x00));
    		}
    	}
    }
    
    /**
     *******************************************************************************
     ** \brief  显示一个字符
     ** \param  x           x坐标 (0~191)
     ** \param  y           y坐标 (0~95)
     ** \param  x_size      x尺寸 (5/8/16/32)
     ** \param  y_size      y尺寸 (8/16/32)
     ** \param  data        数组数据
     ** \retval None
     ******************************************************************************/
    void lcd_jlx19296_char(uint32_t x, uint32_t y, uint32_t x_size, uint32_t y_size, const uint8_t *data)
    {
        uint32_t index = 0;
        // 计算正确的xy坐标
        x = (x > 191) ? (191) : (x);
        y = (y > 95) ? (95/8) : (y/8);
        x_size = (x_size == 5 || x_size == 8 || x_size == 16 || x_size == 32) ? (x_size) : (5);
        y_size = (y_size == 8 || y_size == 16 || y_size == 32) ? (y_size/8-1) : (8/8-1);
        // 设置显示区域
    	lcd_jlx19296_address(x, x+x_size, y, y+y_size);  
        // 输入显示数据
        for (int i=0; i<x_size; i++)
            for (int j=0; j<=y_size; j++)
    			lcd_jlx19296_data(Write_Data_1(data[index++]));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    4. 字符取模

    • 最后推荐一下字符取模, 使用 PCtoLCD2002 即可,功能多操作易.就是小尺寸的取模会不正常,比如5*8.推测作者是直接将字符图片像素化输出,并没有专门的优化.

    看了一下介绍才发现,这工具是一个学生的毕设作品,真棒,感谢这位大神的无私奉献.

    • 可以选择不同字体来优化显示效果.(忘记我选的那种了,各位自己根据喜欢到字库里挑吧 ).

    • 最后的最后说明一下中文字符串在单片机里的编码,我才知道,原来ide能编译中文字符串,如果输入中文字符串,在单片机程序中是以三字节为单位的,不同于ascii的一字节.

    1. 这时有个方向问题,众所周知,字符串是倒序的,即 高位在右边,低位在左边 . 比如字符串 uint8_t str[2] = "12" , str[0] = '1' (0x31) , str[1] = '2' (0x32). 如果用16位类型读取就是 0x3231 ,而不是 0x3132.之前使用都没感觉什么问题.
    2. 如果是中文字符串,占三个字节, 就会有个奇葩现象, 比如 uint8_t str[] = "我", 假设 str[0] = 0xFE , str[1] = 0xFB ,str[2] = 0x23 , 用32位类型读取就是 0x0023FBFE. 直接这样判断用好像没问题.但是!!!
    3. 中文如果不是按字符串,而是按字符赋值, 比如 uint32_t str = '我' ,那str的值就是0x00FEEB23. 结果会反过来,这样判断就不成立了!!! 特别有趣 ,一定要注意.
    4. 我使用时统一按字符串赋值,单个字符也是字符串形式,这样就不用担心了.
    • 推荐一下我使用的字库形式,使用结构体嵌套共用体+数组的形式.
    • 从取模软件导出数据,使用python脚本处理数据格式,得到想要的格式.一键搞定字库问题.

    吐槽一下,python中处理中文字符串是占2个字节的.不知道这个怎么设置,单片机也占2个比较好,使用的中文不多,2个字节完全够用.

    /**
     *******************************************************************************
     ** \brief 点阵字符数据 5*8 结构体定义
     ******************************************************************************/
    typedef struct st_lattice_data_5x8
    {
        union
        {
            uint8_t bit_8[4];           // 如果是 ascii 占用1个字节, 否者占用3个字节
            uint32_t bit_32;    
        }encoding;                      // 当前字符编码
        uint8_t lattice_data[5*8/8];   // 当前字符大小 5x8 所需的字节数量
    } st_lattice_data_5x8_t;
    
    static const st_lattice_data_5x8_t     lf_ascii_5x8[]      = {
         
    {" ",{0x00,0x00,0x00,0x00,0x00}}, /* " ",0x20 */ 
    {"!",{0x00,0x00,0xBE,0x00,0x00}}, /* "!",0x21 */
    ... /* 略 */ ...
    };
    
    // 注意上赋值字符串,不能赋值字符,不然中文字符判断不对.其它尺寸的结构体依次定义即可.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    单链表(详解)
    k8s-service详解
    Spring Data JPA - Web 支持、排序和分页
    浅谈USB的枚举过程
    Chapter8 : Predicting Residence Time of GPCR Ligands with Machine Learning
    数据结构之空间复杂度、顺序表
    WPF|快速添加新手引导功能(支持MVVM)
    抖音矩阵系统,抖音矩阵系统源码定制 tell me
    云安全态势
    18. `bs对象.节点名.next_sibling` previous_sibling 获取兄弟节点
  • 原文地址:https://blog.csdn.net/Lovely_him/article/details/126284516