• 回复
  • 收藏
  • 点赞
  • 分享
  • 发新帖

从新唐BSP学习段式LCD驱动的模块化编写

首先,看一下LCD液晶屏幕的引脚资料。从图中我们得知这是一个4com,44段的LCD。

以米字型数码管为例。首先创建一个结构体,这个结构体描述每个段所对应的COM,也就是给上图表格建立数据模型。

typedef struct
{
	uint32_t com[14]; //存储每个段对应的哪一位
	uint32_t bit[14];  //14个段
} CHAR_TypeDef;

由上图LCD的表格和数据模型,给这个结构建立数组用于查询。因为每位数码管要14个数据,7位米字形数码共14*7=98个数据。

const CHAR_TypeDef NANO1XXDISPLAY = {
//7个大字符
    { /* 1 */						
		/* A            B               C              D    */
      .com[0] = 3, .com[1] = 2, .com[2] = 1, .com[3] = 0,
      .bit[0] = 0, .bit[1] = 0, .bit[2] = 0, .bit[3] = 0,
		/* E            F               G              H    */
      .com[4] = 1, .com[5] = 2, .com[6] = 2, .com[7] = 3,
      .bit[4] = 38, .bit[5] = 38, .bit[6] = 39, .bit[7] = 39,
		/* J            K               M              N    */
      .com[8] = 3, .com[9] = 2, .com[10] = 1, .com[11] = 0,
      .bit[8] = 1, .bit[9] = 1, .bit[10] = 1, .bit[11] = 1,
		/* P            Q      */
      .com[12] = 0, .com[13] = 1,
      .bit[12] = 39, .bit[13] = 39
    },
    { /* 2 */

      .com[0] = 3, .com[1] = 2, .com[2] = 1, .com[3] = 0,
      .bit[0] = 4, .bit[1] = 4, .bit[2] = 4, .bit[3] = 4,

      .com[4] = 1, .com[5] = 2, .com[6] = 2, .com[7] = 3,
      .bit[4] = 2, .bit[5] = 2, .bit[6] = 3, .bit[7] = 3,

      .com[8] = 3, .com[9] = 2, .com[10] = 1, .com[11] = 0,
      .bit[8] = 5, .bit[9] = 5, .bit[10] = 5, .bit[11] = 5,

      .com[12] = 0, .com[13] = 1,
      .bit[12] = 3, .bit[13] = 3
},

建立完这个核心表格后,查表即可。

查的时候是大循环7个数码,小循环每个数码14位。代码如下所示。

for (index = 0; index < 7;index++)  //大循环,7个米字形数码管
{
        data = (int) *string;
        bitfield = Nuvo_alphabet[data]; //段码
    	for (i = 0; i < 14;i++)  //每个米字形数码管14个段
    	{
      		bit   = NANO1XXDISPLAY.Text[index].bit[i];
      		com   = NANO1XXDISPLAY.Text[index].com[i];
     
      		if (bitfield & (1 << i))  //重要,当前位显示则刷新
      		{
        		LCD_EnableSegment(com, bit);//和CPU有关
      		}
    	}
    	string++;
	}

这样就能完美显示了。和LED数码管不同,为了布线方便,LCD的段码硬件连线不是连续的,只能查出段码后再每一位查询。

对于段码表格Nuvo_alphabet就更简单了,和LED数码管一样。

const uint16_t Nuvo_alphabet[] = {
  0x0000, /* space */
  0x1100, /* ! */
  0x0280, /* " */
  0x0000, /* # */
  0x0000, /* $ */
  0x0000, /* % */
  0x0000, /* & */
  0x0000, /* ? */
  0x0039, /* ( */
  0x000f, /* ) */
  0x3fc0, /* * */
  0x1540, /* + */
  0x0000, /* , */
  0x0440, /* - */
  0x8000, /* . */
  0x2200, /* / */

  0x003f, /* 0 */
  0x0006, /* 1 */

拿数字1来说,只有BC是显示的,所以值是0x0006,既是0b0000 0000 0000 0110。

怎么样,这样的思路很好吧,表格的方式记录LCD特征值可以很方便的移植和提高程序的效率。想当年我是无数的IF实现的,太丢人了。

当然,因为只有段为1时才刷新数据寄存器,所以,数据变化时,老数据1不会消失。我们在每次刷新之前,要清空全部数据寄存器。

void LCD_AlphaNumberOff(void)
{
	LCD->MEM_0 &= ~0x0f0f0f0f;
  	LCD->MEM_1 &= ~0x0f0f0f0f; 
  	LCD->MEM_2 &= ~0x0f0f0f0f; 
  	LCD->MEM_3 &= ~0x0f0f0f0f;
	LCD->MEM_4 &= ~0x0f0f0f0f; 
	LCD->MEM_5 &= ~0x0f070f0f;
	LCD->MEM_6 &= ~0x00000f0f;
	LCD->MEM_9 &= ~0x0f060000;
  	return;
}
全部回复(13)
正序查看
倒序查看
2021-06-09 22:12

编译完的再配个显示图就好了,去年好像新塘搞活动,只不过没抢到带液晶屏显示的开发板

0
回复
k6666
LV.9
3
2021-06-10 12:38

段氏显示的LCD是功耗低吗?

0
回复
2021-06-10 14:49

段码驱动这块原理是啥?

0
回复
飞翔2004
LV.10
5
2021-06-16 14:22
@lihui710884923
段码驱动这块原理是啥?

LCD驱动一般都要采用交流方式驱动,最简单的就是1/2bias,就只有亮与灭。

0
回复
iszjt
LV.5
6
2021-06-18 15:17

实用性比较高~~

请教新唐 的M051 series bsp的实现手法。

0
回复
2021-06-26 09:54

看来还得学习一下

0
回复
鲁珀特
LV.4
8
2021-07-02 16:10

新唐的发展还是很快的,当年刚毕业前才听说过新唐,学长搞一个数显的开关控制用的,主要是新唐的配套的LCD方便。转眼这么多年过去了发展得很快。不过好像这么多年写这个段式LCD驱动的思路还是没变。

0
回复
雅兄
LV.5
9
2021-07-05 19:18
@天府大懒猫
编译完的再配个显示图就好了,去年好像新塘搞活动,只不过没抢到带液晶屏显示的开发板

我是在咸鱼买的,不到50元,还可以!

0
回复
雅兄
LV.5
10
2021-07-05 19:19
@k6666
段氏显示的LCD是功耗低吗?

超级低啊,墨水屏还可以更低!

0
回复
雅兄
LV.5
11
2021-07-05 19:21
@lihui710884923
段码驱动这块原理是啥?

就像百叶窗帘一样,用电压改变液晶的状态,背光就不能透到外面,我们看着就是黑色的了

0
回复
雅兄
LV.5
12
2021-07-05 19:22
@iszjt
实用性比较高~~请教新唐的M051seriesbsp的实现手法。

原理都一样啊,我还没有这块开发板子。

0
回复
雅兄
LV.5
13
2021-07-05 19:22
@鲁珀特
新唐的发展还是很快的,当年刚毕业前才听说过新唐,学长搞一个数显的开关控制用的,主要是新唐的配套的LCD方便。转眼这么多年过去了发展得很快。不过好像这么多年写这个段式LCD驱动的思路还是没变。

底层驱动都是这样子啦

0
回复
iszjt
LV.5
14
2021-07-14 14:27

感谢楼主分享!!!

以前试过用IO口模拟交流信号驱动过,效果不是很理想。后来又用HT1621芯片驱动,可以是可以,不过还是嫌麻烦。买了不少段码液晶屏全部在那吃灰。最近玩新唐,发现新唐N76E616自带段码驱动功能,于是翻出吃灰的液晶屏小试牛刀,效果很好。电路简单,控制逻辑也很清晰。

0
回复