段码液晶屏点亮思路--以华大单片机为例

本文详细介绍了段码液晶的工作原理,以及使用华大单片机HC32L176进行驱动的具体步骤。内容包括液晶分子的排列与电场作用、LCD控制器介绍、LCDram配置、代码实现和效果展示。重点讨论了如何通过配置LCD寄存器和编写底层驱动函数来点亮特定段码,实现任意位置字符显示。



前言

提示:点亮断码液晶其实是难而不会,会者不难的体力活.时间紧迫可直接跳过前面的废话去看小结以后的内容.


提示:下面案例可供参考

一、什么是段码液晶?

示例:段码液晶,或段式液晶屏,是液晶产品中的一种,但在液晶行业内,一般称为图案型液晶屏,笔段式液晶屏,单色液晶屏等等(百度百科)。其实就下面这东西,见多了,额温枪,电瓶车表盘…一堆
常见的断码液晶屏

二、段码点亮基本原理

1.液晶发光的基本原理

"具有偶极矩的液晶棒状分子外加电场的作用下其排列状态发生变化,使得通过液晶显示器件的光被调制,从而呈现明与暗或秀光与不透光的显示效果。液晶显示器件中的每个显示像素都单独被电场控制,不同的显示像素按照控制信号的“指挥”便可以在显示屏上组成不同的字符,数字及图形。因此建立显示所需的电场以及控制显示像素的组合不成为液晶显示驱动器和液晶显示控制器的功能。"
————————————————
版权声明:优快云博主「晶拓」的原创文章
原文链接:https://blog.youkuaiyun.com/qq_43188920/article/details/84567722)

简单来说意思就是每一段都是由一个电场控制的,也就是两端的电压,两端就是seg和com口.

" 要使得晶体发生扭转,必须使得电极两端的电压差大于一定的阈值,才可以显示内容。通常LCD段码屏有三个参数:工作电压、Duty(对应COM数)和BIAS(偏压,对应阈值),比如,3.3V、1/4 Duty、1/3 BIAS表示LCD的工作电压为3.3V,有4个COM,阈值大约是1.1V(3.3/3=1.1)。实际使用中,为保证显示效果良好,通常给电极两端加的电压差接近LCD的工作电压;若要不显示,通常给电极两端加的电压差接近0V。需要特别注意的是,液晶分子是需要用交流信号来驱动的,万万不可将直流电压长时间的加在电极两端,否则,会影响液晶分子的电气化学特性,引起显示效果模糊,使用寿命减少的后果,其破坏性不可恢复。
了解了以上原理后,我们要点亮某个段时,只需要保证给其电极两端加的电压差为3.3V(如COM1=3.3V,SEG1=0V),并且间隔合适的时间,将这两极的电压反转输出(如COM1=0V,SEG1=3.3V);不点亮某个段时,只需要保证给其电极两端加的电压差为0V(如COM1=3.3V,SEG1=3.3V),并且间隔合适的时间,将这两极的电压反转输出(如COM1=0V,SEG1=0V)。"
————————————————
版权声明:本文为优快云博主「大表哥姓王」的原创文章
原文链接:https://blog.youkuaiyun.com/weixin_34634720/article/details/111953664

看到这里大家只需要了解段码液晶的基本原理,至于生产工艺的细节不必多做考虑(百度的这些玩意儿根本不用多看)甚至有些单片机自带LCD液晶驱动,都不需要去手动去产生驱动波形,只需要按照硬件的方式去配置代码就可以了产生驱动波形了.我以华大单片机HC32L176为例,记录下最近的一个工程分享给大家

2.LCD控制器简介

LCD 控制器是一款适用于单色无源液晶显示器(LCD)的数字控制器/驱动器,最多具有
8 个公用端子(COM)和 48 个区段端子(SEG),用以驱动 208 (4x52)或 384 (8x48)
个 LCD 图像元素。端子的确切数量取决于数据手册中所述的器件引脚。
LCD 由若干区段(像素或完整符号)组成,这些区段均可点亮或熄灭。每个区段都包
含一层在两根电极之间对齐的液晶分子。当向液晶施加高于阈值电压的电压时,相应
的区段可见。区段电压必须为交流,以避免液晶中出现电泳效应(这将影响显示效果)。
之后,必须在区段两端生成波形以避免出现直流。
液晶(LCD):无源显示面板,带有直接引向区段的端子。
公用(COM):连接到多个区段的电气连接端子。
偏置(BIAS):驱动 LCD 时使用的电压等级,定义为 1/(驱动 LCD 显示的电压等级数
–1)。
区段(SEG):最小可视单元(LCD 显示器上的最小组成元素,线条或点)。
占空比(DUTY):定义为 1/(LCD 显示器上的公用端子数)的数字。
帧:写入区段的波形的一个周期。
帧速率:每秒帧数,即每秒激励 LCD 区段的次数。

巴拉巴拉一堆,详情在数据手册LCD章,看看就好,了解就行.数据手册华大官网自行下载,方便的一批

三.华大单片机LCD驱动简介

1.段码液晶seg-com表

在这里插入图片描述
液晶厂家会根据客户得需求制作显示的图,客户确认后在生产样品,这个图就是最终液晶显示的seg-com对应的图和表;仔细看你会发现上面表格的每一个com-seg交叉电对应下面数字的每一段.如9位置想显示1,就要点亮9位置的BC段,对应上面的表就是9B9C
这样还远远不够,还需要对应原理图的液晶驱动脚去生成一个新的表格.因为液晶是通用的,而原理图是工程师随机安排的引脚,对应关系可能不同,这对影响写代码时的繁琐与否.

2.LCD原理图

这是HC32L176MATA单片机原理图和LCD的原理图,可以看到这个型号的单片机有很多seg脚,也就是就可以驱动很多段的段码液晶.
因为之前说过,LCD硬件的脚位是由工程师分配的,会影响写程序时的繁杂成度,所以最好的方式就是一一对应,也就是LCD硬件的seg1脚对应单片机的seg1脚,这样就不容易混乱.
一一对应之后发现单片机是从seg0开始的,而LCD硬件是从seg1开始的,所以就成了MCUseg0对应LCDseg1这样一一对应下去,实际上你也可以把LCDseg1改为seg0,无非就是个名字代号而已.只不过一般人数数都是从1开始,而我们数数都习惯是从0开始的罢了.
有些细心的人就发现seg30为什么没有了,的确这是华大单片机以前的一个设计上的缺陷,因为seg30之前136什么型号的对应的脚正好和BOOT脚重叠了,我们知道boot脚上电之后的电位是很重要的,如果服用为LCD之后,很可能出现上电代码跑不下去的情况,一般不建议这样用.所以后面的型号就把这个脚的功能给删了.所以seg30没有了,但并不影响后面的脚位的对应.
对应关系确定好了之后,还需要一个表格,就是单片机LCD驱动的寄存器表格.输出配置寄存器 0(LCD_POEN0)和输出配置寄存器 1(LCD_POEN1)
在这里插入图片描述
在这里插入图片描述

3.LCD输出配置寄存器

在这里插入图片描述在这里插入图片描述

下面这张图一定要看懂,关系到写程序时的思路.HC32L176单片机LCD驱动共有16个LCDram ,这个LCDram是干嘛用的呢?LCDram是长度32位存储这个seg或者com的值.怎么理解这句话呢

LCD 支持两种显示模式。一种以 COM 为显示单元,同一个 SEG 的所有 COM 段在同
一字节中(模式 0)
。另外一种为同一个 COM 的不同 SEG 在同一个字节中(模式 1)
根据 LCD 面板选择合适的显示方式可以简化程序操作。
模式0
模式1

一个LCDram有两个字节,里面包含的要么是同一个com的所有seg段,要么就是同一个seg的所有com段
举例1:假如要显示的字符对应的com为com0,对应的seg为seg0,seg1,然后去在硬件LCD厂家那张表格上找com0-seg0对应的原理图seg和com,找到后假如com0-seg0,com0-seg1对应原理图的seg为seg0和seg1,然后根据显示模式(mode0,mode1),去看相应的LCDram表格就是上面这俩,默认配置为四分之一DUTY;
如果是mode1:看上面的表格seg0 seg1对应bit0,bit1,com0对应LCDram0,所以点亮这两段,置1,LCDram0的值为0b0000 0000 0000 0000 0000 0000 0000 0011(注意高位在前,而表格是低位在前面要反过来) 十六进制为0x000000003,至于seg如何知道是对应哪一段,没懂的看看上面或者接着往下看.
如果是mode0:看上面的表格会发现一个LCDram只控制四个seg,有些只有三个甚至只有两个,也就是说32位的LCDram,其中一个字节控制一个seg的所有com情况.所以要点亮com0-seg0,com0-seg1这两段,先在上面找seg0,seg1在那个ram,然后发现在LCDram0,所以对应的位置1,LCDram0的值为0b0000 0000 0000 0000 0000 0001 0000 0001 十六进制为0x00000101

4.小结

举例:9位置显示数字1,1/4duty,mode0

①:先根据要显示的字符找出相应的段和硬件对应的PIN脚:9B 9C 35脚 com0 com3
在这里插入图片描述
②:对比原理图和LCDram表,找出对应的LCDram和位,置1原理图com-seg定义对应关系
可以发现硬件com和seg的数字并不一定一一对应厂家的lcd图纸给的脚位,如原理图com0对应厂家图纸为com1,原理图seg0对应硬件seg1,以此类推,这里需要特别注意一下,刚开始看的时候容易搞混,熟悉之后实际上的com和seg实质上是指原理图的seg,也就是LCDram对应的寄存器的值所谓的com和seg.

LCDram表
所以,硬件com0对应的原理图com1,硬件com2对应原理图com3,硬件seg35正好对应原理图seg35,然后找seg35所在的LCDram为LCDRAMB.COM0和COM2位为1,其余位为0,所以LCDRAMB的值为0b0000 0000 0000 0000 0000 0000 0000 0101 十六进制为0x00000005
到目前位置应该对段码液晶的点亮有了基本的认识,一些重要的概念duty通俗理解就是几个com就配置为几分之一duty,对比三个图***:①厂家给的液晶硬件接口图,一般来说是有规律的*,(刚开始我以为没规律,写个几把,一段一段点亮暴力输出?仔细琢磨有规律的)下面写代码的时候说,②硬件攻城狮也就是你自己画的原理图,自定义的脚com/seg,一般来说序号一样对应好比较简单不乱,③数据手册的LCDram表去对照哪一段是哪个ram的哪个位,置1就点亮0就不点亮.就这简单,就这??

四.代码实现

通过以上的例子,我们可以轻松点亮任意一段或几段,但是,总不能一段一段一位一位的去点亮吧,所以要有一种函数叫做底层驱动函数去实现一个功能:什么功能呢?
在任意位置写任意字符:void display(u8 char, u8 pos);char为要显示的字符;pos为显示的位置.

所以,通过我的火眼金睛聪明的脑袋发现,原厂给的LCD图纸上面的每个数码管对应的seg和控制它点亮与否的LCDram的位是有一定规律的
之前说过,自己画原理图的com seg和厂家图纸不一定在数字上一一对应,有时候就会混乱,所以我建议新手做一个表把他们统一一下像下图,花不了多少时间,省去很多麻烦
seg-com-LCDRAM放在一个图里
这样就一目了然,单片机哪几个ram控制液晶的哪几段.就这?

然后就发现比如8位置这个8和右下角的小数点p6由LCDRAM0的低16位控制(对照LCDram表);9位置的8和右下角小数点p7由LCDRAMB和LCDRAMC两个寄存器控制,右下角位置1的米8由LCDram5的高位和LCDram6的低位共同控制;可见规律并不是全都统一的,但是对于上面五个8为一组,左下角3个8为一组,右下角五个米8为一组,一共三组三种规律,就需要分别写三种算法.大同小异,因为这个液晶段比较多,算是比较复杂的段码了,一般来说都是一种规律.
核心思路: 写任意LCDram前,将需要改写的位清零重写,不需要变化的位缓存保留,刷新时同时写入整个RAM中.
华大官方由LCD驱动库lcd.c和lcd.h 里面定义了各种数据类型,关于LCD bias源选择,duty选择 ,bias配置位 ,电压泵时钟频率选择,扫描频率选择 ,显示模式以及时钟源等
在这里插入图片描述

这个冒号是位域

理解C语言位域
有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。
关于位域的解释这个老哥说的很清楚
lcd库提供了最基本你的写LCDRAM的函数`/**


** \brief LCD RAM 0-f寄存器设置函数
** \param u8Row RAM地址索引,范围:0-15,u8Data写入寄存器数值
** \retval enRet 成功或失败
******************************************************************************/
en_result_t Lcd_WriteRam(uint8_t u8Row,uint32_t u32Data)
{
en_result_t enRet = Error;
volatile uint32_t ram = NULL;
ram = (volatile uint32_t
)&M0P_LCD->RAM0;

if (u8Row > 15)
{
    enRet = ErrorInvalidParameter;
    return enRet;
}  
ram += u8Row;
*ram = u32Data;
enRet = Ok;
return  enRet; 

}`
我们可以用这个基本函数对任何ram写数据,点亮ram对应的段
比如Lcd_WriteRam(6,0x00000a00); 点亮第一个位置的字符1在这里插入图片描述
我们可以为了方便起见,也是常用手法,每一段段码写出来,然后位或,拼凑,所以我说这是苦力活,妈的根据厂家的液晶图纸推吧 三个位置 写了三段 有精力的看看,没精力的就别看了

//6 7 8位置
#define SegA 0x0008
#define SegB 0x0800
#define SegC 0x0200
#define SegD 0x0001
#define SegE 0x0002
#define SegF 0x0004
#define SegG 0x0400
#define SegP 0x0100

#define Char_0  SegA|SegB|SegC|SegD|SegE|SegF
#define Char_1  SegB|SegC
#define Char_2  SegA|SegB|SegD|SegE|SegG
#define Char_3  SegA|SegB|SegC|SegD|SegG
#define Char_4  SegB|SegC|SegF|SegG
#define Char_5  SegA|SegC|SegD|SegF|SegG
#define Char_6  SegA|SegC|SegD|SegE|SegF|SegG
#define Char_7  SegA|SegB|SegC
#define Char_8  SegA|SegB|SegC|SegD|SegE|SegF|SegG
#define Char_9  SegA|SegB|SegC|SegD|SegF|SegG
#define Char_10  SegA|SegD|SegF|SegE|SegG
#define Char_11  SegG
#define Char_12  SegB|SegC|SegD

//9 10 11 12 13位置

#define Seg_A 1<<0
#define Seg_F 1<<1
#define Seg_E 1<<2
#define Seg_D 1<<3

#define Seg_B 1<<0
#define Seg_G 1<<1
#define Seg_C 1<<2

#define Char_0_Ram1 Seg_B|Seg_C
#define Char_0_Ram2 Seg_A|Seg_F|Seg_E|Seg_D
#define Char_1_Ram1 Seg_B|Seg_C
#define Char_1_Ram2 0
#define Char_2_Ram1 Seg_B|Seg_G
#define Char_2_Ram2 Seg_A|Seg_E|Seg_D
#define Char_3_Ram1 Seg_B|Seg_G|Seg_C
#define Char_3_Ram2 Seg_A|Seg_D
#define Char_4_Ram1 Seg_B|Seg_G|Seg_C
#define Char_4_Ram2 Seg_F
#define Char_5_Ram1 Seg_C|Seg_G
#define Char_5_Ram2 Seg_A|Seg_F|Seg_D
#define Char_6_Ram1 Seg_C|Seg_G
#define Char_6_Ram2 Seg_A|Seg_E|Seg_D|Seg_F
#define Char_7_Ram1 Seg_B|Seg_C
#define Char_7_Ram2 Seg_A
#define Char_8_Ram1 Seg_B|Seg_G|Seg_C
#define Char_8_Ram2 Seg_A|Seg_E|Seg_D|Seg_F
#define Char_9_Ram1 Seg_B|Seg_G|Seg_C
#define Char_9_Ram2 Seg_A|Seg_F|Seg_D

//1 2 3 4 5位置
#define S_E 1<<16
#define S_G 1<<17
#define S_F 1<<18

#define S_L 1<<24
#define S_K 1<<25
#define S_I 1<<26

#define S_D 1<<0
#define S_J 1<<1
#define S_M 1<<2
#define S_A 1<<3

#define S_C 1<<9
#define S_N 1<<10
#define S_B 1<<11

#define Ch_0_Ram1 S_E|S_F
#define Ch_0_Ram2 S_A|S_B|S_C|S_D
#define Ch_1_Ram1 0
#define Ch_1_Ram2 S_B|S_C
#define Ch_2_Ram1 S_E|S_G
#define Ch_2_Ram2 S_A|S_B|S_N|S_D
#define Ch_3_Ram1 S_G
#define Ch_3_Ram2 S_A|S_B|S_C|S_D|S_N
#define Ch_4_Ram1 S_F|S_G
#define Ch_4_Ram2 S_B|S_C|S_N
#define Ch_5_Ram1 S_F|S_G
#define Ch_5_Ram2 S_A|S_C|S_D|S_N
#define Ch_6_Ram1 S_F|S_G|S_E
#define Ch_6_Ram2 S_A|S_C|S_D|S_N
#define Ch_7_Ram1 0
#define Ch_7_Ram2 S_A|S_C|S_B
#define Ch_8_Ram1 S_F|S_G|S_E
#define Ch_8_Ram2 S_A|S_C|S_D|S_N|S_B
#define Ch_9_Ram1 S_F|S_G
#define Ch_9_Ram2 S_A|S_C|S_D|S_N|S_B

#include "mylcd.h"
#include "gpio.h"
#include "lcd.h"

uint32_t lcdram0,lcdram1,lcdram2,lcdram3,lcdram4,lcdram5,lcdram6,lcdram7,lcdram8,lcdram9,lcdramA,lcdramB; lcdramC;
uint8_t bai=1,shi=1,ge=1;
/**
 ******************************************************************************
 ** \brief  初始化外部GPIO引脚 LCD相关引脚
 **
 ** \return 无
 ******************************************************************************/
void LCD_PortCfg(void)
{
   
   
    Gpio_SetAnalogMode(GpioPortA, GpioPin9);  //COM0
    Gpio_SetAnalogMode(GpioPortA, GpioPin10); //COM1
    Gpio_SetAnalogMode(GpioPortA, GpioPin11); //C
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

那头时空

哈哈哈想白嫖就白嫖吧大哥们

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值