8H4K64TLCD驱动段码LCD的寄存器咨询
1. 下载了官网提供的 断码LCD程序,发现里面对显示寄存器操作有点复杂。/****************** 对第1~5数字装载显示函数 ***************************/
u8 code t_display[]={ //标准字库
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black - H J K L N o P U t G Q r M y
0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e};
u8 code T_LCD_mask= {0x00,0x0C,0x30,0xC0,0x03,0x0C};
u8 code T_LCD_mask7 = {0x00,0x04,0x10,0x40,0x01,0x04};
u8 code T_SEG_ABC = {0x00,0x08,0x20,0x80,0x02,0x08};
u8 code T_SEG_DEFG= {0x00,0x04,0x10,0x40,0x01,0x04};
/********************** 装载显示5个8字 *****************************/
void LCD_load(u8 n, u8 dat) //n为第几个数字,为1~5,dat为要显示的数字
{
u8 i,k;
if((n == 0) || (n >= 6)) return; //合法值 1~5
dat =t_display; //3F
k = ~T_LCD_mask; //FF
if(n <= 3) //1~3
{
LCD_buff &= ~T_LCD_mask7; //FF
LCD_buff &= k; //NC
LCD_buff &= k; //NC
LCD_buff &= k; //NC
i = T_SEG_ABC;//00
k = T_SEG_DEFG;//00
if(dat & 0x01) LCD_buff |= i; //T_SEG_ABC; //A
if(dat & 0x02) LCD_buff |= i; //T_SEG_ABC; //B
if(dat & 0x04) LCD_buff |= i; //T_SEG_ABC; //C
if(dat & 0x08) LCD_buff |= k; //T_SEG_DEFG; //D
if(dat & 0x10) LCD_buff |= k; //T_SEG_DEFG; //E
if(dat & 0x20) LCD_buff |= k; //T_SEG_DEFG; //F
if(dat & 0x40) LCD_buff |= k; //T_SEG_DEFG; //G
}
else // n=4 or 5
{
LCD_buff &= ~T_LCD_mask7;
LCD_buff &= k;
LCD_buff &= k;
LCD_buff &= k;
i = T_SEG_ABC;
k = T_SEG_DEFG;
if(dat & 0x01) LCD_buff |= i; //T_SEG_ABC; //A
if(dat & 0x02) LCD_buff |= i; //T_SEG_ABC; //B
if(dat & 0x04) LCD_buff |= i; //T_SEG_ABC; //C
if(dat & 0x08) LCD_buff |= k; //T_SEG_DEFG; //D
if(dat & 0x10) LCD_buff |= k; //T_SEG_DEFG; //E
if(dat & 0x20) LCD_buff |= k; //T_SEG_DEFG; //F
if(dat & 0x40) LCD_buff |= k; //T_SEG_DEFG; //G
}
}
/********************** 将显示内容导入显存 *****************************/
void LoadToLcd(void)
{
C0SEGV1 = LCD_buff; // C0SEG 15~8数据寄存器
C0SEGV2 = LCD_buff; // C0SEG 23~16数据寄存器
C1SEGV1 = LCD_buff; // C1SEG 15~8数据寄存器
C1SEGV2 = LCD_buff; // C1SEG 23~16数据寄存器
C2SEGV1 = LCD_buff; // C2SEG 15~8数据寄存器
C2SEGV2 = LCD_buff; // C2SEG 23~16数据寄存器
C3SEGV1 = LCD_buff; // C3SEG 15~8数据寄存器
C3SEGV2 = LCD_buff; // C3SEG 23~16数据寄存器
}
前面对buf的数据处理逻辑比较复杂,最后将数据传入到 CxSEGVx寄存器中。 这段过程一直没有理解;
2. 之前用过TM1621这类的驱动,不知道咱们的这个驱动方式是否和这类芯片类似?如果不相同,应该怎么理解 这些寄存器的作用? 尤其是CxSEGVx寄存器。
区别于数码管,段码的连接一般不是整组接在位或者段上的。
数码管可能八个段码刚好占用一个P1端口,但是LCD你仔细看提供的段码表,你可以推理下如果要点亮一个数字2需要哪几个位输出,算出来了这个数值,在来看这个程序你就懂了 电子DIY小家 发表于 2023-5-18 14:11
区别于数码管,段码的连接一般不是整组接在位或者段上的。
数码管可能八个段码刚好占用一个P1端口,但是LCD ...
数码管是了解的;TM1621这类专用LCD断码驱动屏,是每次发4个bit数据,发两次正好可以对应一个显示数字;但是STC的驱动方式好像不一样。感觉驱动起来就比TM1621要麻烦点
。
本帖最后由 xuzeabc 于 2023-5-18 19:39 编辑
zl_diy 发表于 2023-5-18 16:24
数码管是了解的;TM1621这类专用LCD断码驱动屏,是每次发4个bit数据,发两次正好可以对应一个显示数字; ...
刚使用TLCD给一朋友开发的段码液晶摩托车仪表。用惯了1621驱动,刚开始感觉有点不适应,诚如楼主所言。慢慢的使用过程中,感觉操作起来比1621便宜不少。使用1621为了驱动不同种类的8,用了很多数组,使用单片机,一个数组完成工作。
把段码的数据定义在了bdata处,用联合体和结构体,可以进行位操作,也可以进行字节操作,方便多多。希望对楼主有参考。
zl_diy 发表于 2023-5-18 16:24
数码管是了解的;TM1621这类专用LCD断码驱动屏,是每次发4个bit数据,发两次正好可以对应一个显示数字; ...
一样的,其实我们的比HT1621要方便得多,传送速度快得多。
例子为什么看起来复杂?其实是因为例子用的屏是网上买来的,并且是在通用测试板上测试的,所以每一段对应显存有点乱,实际工程会自己设计LCD,排列有规律,连到MCU的LCD驱动脚也按屏设计,就会有规律。
下面是我某个测试用的HT1621,2个数码管,也一样的复杂:
/****************** 对第1 2数字装载显示函数 ***************************/
u8 code t_display[]={ //标准字库
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black - H J K L N o P U t G Q r M y
0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e,
0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46}; //0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1
void LCD_load(u8 n, u8 dat) //n为第几个数字,为1~2,dat为要显示的数字
{
u8 i;
if(n == 1)
{
LCD_buff &= 0x0f; LCD_buff &= 0xf8;
i = t_display;
if(i & 0x01) LCD_buff |= 0x10; //A
if(i & 0x02) LCD_buff |= 0x01; //B
if(i & 0x04) LCD_buff |= 0x04; //C
if(i & 0x08) LCD_buff |= 0x80; //D
if(i & 0x10) LCD_buff |= 0x40; //E
if(i & 0x20) LCD_buff |= 0x20; //F
if(i & 0x40) LCD_buff |= 0x02; //G
HT1621_write_byte(2,LCD_buff);
HT1621_write_byte(4,LCD_buff);
}
else if(n == 2)
{
LCD_buff &= 0x0f; LCD_buff &= 0xf8;
i = t_display;
if(i & 0x01) LCD_buff |= 0x10; //A
if(i & 0x02) LCD_buff |= 0x01; //B
if(i & 0x04) LCD_buff |= 0x04; //C
if(i & 0x08) LCD_buff |= 0x80; //D
if(i & 0x10) LCD_buff |= 0x40; //E
if(i & 0x20) LCD_buff |= 0x20; //F
if(i & 0x40) LCD_buff |= 0x02; //G
HT1621_write_byte(4,LCD_buff);
HT1621_write_byte(6,LCD_buff);
}
}
为什么会这样?因为LCD的段码排列和HT1621的引线是工程师乱连的结果。
如果是下面的内存映射表,则不管是HT1621还是STC8H4K64TLCD,只要规划好COM线和SEG线,则会很简单的,所以最关键的是映射表是否有规律,没有规律,用哪个IC都恼火。
RAM地址B7 B6 B5 B4 B3 B2 B1 B0
LCD_buff: 19,18 3D 3E 3G 3F 3H 3C 3B 3A
LCD_buff: 21,20 -- -- -- -- 61 - LB Kg 61为右上角到E显示1
LCD_buff: 23,22 5D 5E 5G 5F -- 5C 5B 5A 5为右下角小8
LCD_buff: 25,24 4D 4E 4G 4F 三 4C 4B 4A
LCD_buff: 29,28 2D 2E 2G 2F 2H 2C 2B 2A
LCD_buff: 31,30 1D 1E 1G 1F -- 1C 1B 1A
如上图中的寄存器,我一开始是没有理解这个表格中CxSEGVx寄存器的作用,后来反复琢磨,猜想到他的对饮关系 是不是:例如C0SEGV0 寄存器对用的 COM0 线上的SEG0~SEG7 的这7个段,哪一个位为1,对应的LCD哪一段就亮起来。不知道是不是这样理解的?
xuzeabc 发表于 2023-5-18 19:35
刚使用TLCD给一朋友开发的段码液晶摩托车仪表。用惯了1621驱动,刚开始感觉有点不适应,诚如楼主所言。慢 ...
非常感谢,您的思路,我试试是否可以做到。
这就有点麻烦了;LCD屏也是按照HT1621这类驱动来做的引脚。
zl_diy 发表于 2023-5-19 14:43
这就有点麻烦了;LCD屏也是按照HT1621这类驱动来做的引脚。
所以说,屏的真值表很关键,基本都是确定了驱动IC,再画图设计段码,排列有规律,如果买个乱排的,用HT1621也一样要按我那样复杂处理。