目录

  • 前言
  • 一、什么是段码液晶?
  • 二、段码点亮基本原理
    • 1.液晶发光的基本原理
    • 2.LCD控制器简介
  • 三.华大单片机LCD驱动简介
    • 1.段码液晶seg-com表
    • 2.LCD原理图
    • 3.LCD输出配置寄存器
    • 4.小结
  • 四.代码实现
  • 五.效果
  • 六.后续补充
    • 1.问题一:对配置代码中的问题简单理一下
    • 2.第二个问题:显示思路调整

前言

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


提示:下面案例可供参考

一、什么是段码液晶?

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

二、段码点亮基本原理

1.液晶发光的基本原理

"具有偶极矩的液晶棒状分子在外加电场的作用下其排列状态发生变化,使得通过液晶显示器件的光被调制,从而呈现明与暗或秀光与不透光的显示效果。液晶显示器件中的每个显示像素都单独被电场控制,不同的显示像素按照控制信号的“指挥”便可以在显示屏上组成不同的字符,数字及图形。因此建立显示所需的电场以及控制显示像素的组合不成为液晶显示驱动器和液晶显示控制器的功能。"
————————————————
版权声明:CSDN博主「晶拓」的原创文章
原文链接:https://blog.csdn.net/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)。"
————————————————
版权声明:本文为CSDN博主「大表哥姓王」的原创文章
原文链接:https://blog.csdn.net/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 面板选择合适的显示方式可以简化程序操作。

一个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的数字并不一定一一对应厂家的lcd图纸给的脚位,如原理图com0对应厂家图纸为com1,原理图seg0对应硬件seg1,以此类推,这里需要特别注意一下,刚开始看的时候容易搞混,熟悉之后实际上的com和seg实质上是指原理图的seg,也就是LCDram对应的寄存器的值所谓的com和seg.


所以,硬件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和厂家图纸不一定在数字上一一对应,有时候就会混乱,所以我建议新手做一个表把他们统一一下像下图,花不了多少时间,省去很多麻烦

这样就一目了然,单片机哪几个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);  //COM0Gpio_SetAnalogMode(GpioPortA, GpioPin10); //COM1Gpio_SetAnalogMode(GpioPortA, GpioPin11); //COM2Gpio_SetAnalogMode(GpioPortA, GpioPin12); //COM3   Gpio_SetAnalogMode(GpioPortA, GpioPin8);  //SEG0Gpio_SetAnalogMode(GpioPortC, GpioPin9);  //SEG1Gpio_SetAnalogMode(GpioPortC, GpioPin8);  //SEG2Gpio_SetAnalogMode(GpioPortC, GpioPin7);  //SEG3Gpio_SetAnalogMode(GpioPortC, GpioPin6);  //SEG4Gpio_SetAnalogMode(GpioPortB, GpioPin15); //SEG5Gpio_SetAnalogMode(GpioPortB, GpioPin14); //SEG6Gpio_SetAnalogMode(GpioPortB, GpioPin13); //SEG7Gpio_SetAnalogMode(GpioPortB, GpioPin12); //SEG8Gpio_SetAnalogMode(GpioPortB, GpioPin11); //SEG9Gpio_SetAnalogMode(GpioPortB, GpioPin10); //SEG10Gpio_SetAnalogMode(GpioPortB, GpioPin2);  //SEG11Gpio_SetAnalogMode(GpioPortB, GpioPin1);  //SEG12Gpio_SetAnalogMode(GpioPortB, GpioPin0);  //SEG13Gpio_SetAnalogMode(GpioPortC, GpioPin5);  //SEG14Gpio_SetAnalogMode(GpioPortC, GpioPin4);  //SEG15Gpio_SetAnalogMode(GpioPortA, GpioPin7);  //SEG16Gpio_SetAnalogMode(GpioPortA, GpioPin6);  //SEG17Gpio_SetAnalogMode(GpioPortA, GpioPin5);  //SEG18Gpio_SetAnalogMode(GpioPortA, GpioPin4);  //SEG19Gpio_SetAnalogMode(GpioPortA, GpioPin3);  //SEG20Gpio_SetAnalogMode(GpioPortA, GpioPin2);  //SEG21Gpio_SetAnalogMode(GpioPortA, GpioPin1);  //SEG22Gpio_SetAnalogMode(GpioPortA, GpioPin0);  //SEG23Gpio_SetAnalogMode(GpioPortC, GpioPin3);  //SEG24Gpio_SetAnalogMode(GpioPortC, GpioPin2);  //SEG25Gpio_SetAnalogMode(GpioPortC, GpioPin1);  //SEG26Gpio_SetAnalogMode(GpioPortC, GpioPin0);  //SEG27Gpio_SetAnalogMode(GpioPortB, GpioPin9);  //SEG28Gpio_SetAnalogMode(GpioPortB, GpioPin8);  //SEG29//Gpio_SetAnalogMode(GpioPortA, GpioPin8);  //SEG30Gpio_SetAnalogMode(GpioPortB, GpioPin7);  //SEG31Gpio_SetAnalogMode(GpioPortB, GpioPin6);  //SEG32Gpio_SetAnalogMode(GpioPortB, GpioPin5);  //SEG33Gpio_SetAnalogMode(GpioPortB, GpioPin4);  //SEG34Gpio_SetAnalogMode(GpioPortB, GpioPin3);  //SEG35Gpio_SetAnalogMode(GpioPortD, GpioPin2);  //SEG36}/********************************************************************************** \brief  配置LCD**** \return 无******************************************************************************/
void LCD_LcdCfg(void)
{stc_lcd_cfg_t LcdInitStruct;stc_lcd_segcom_t LcdSegCom;LcdSegCom.u32Seg0_31 = 0x40000000;                              ///< 配置LCD_POEN0寄存器 开启SEG0~SEG31除30之外全部打开LcdSegCom.stc_seg32_51_com0_8_t.seg32_51_com0_8 = 0xfe1fffe0;   ///< 初始化LCD_POEN1寄存器 打开seg32-36 其余位置1关闭LcdSegCom.stc_seg32_51_com0_8_t.segcom_bit.Com0_3 = 0;          ///< 使能COM0~COM3LcdSegCom.stc_seg32_51_com0_8_t.segcom_bit.Mux = 0;             ///< Mux=0内部电阻工作模式MUX置0,Seg32_35=0为xxxxLcdSegCom.stc_seg32_51_com0_8_t.segcom_bit.Seg32_35 = 0;Lcd_SetSegCom(&LcdSegCom);                                      ///< LCD COMSEG端口配置LcdInitStruct.LcdBiasSrc = LcdInResHighPower;                  ///< 内部电阻分压 大功耗模式CRO.BSEL分压选择LcdInitStruct.LcdDuty = LcdDuty4;                              ///< 1/4dutyLcdInitStruct.LcdBias = LcdBias3;                              ///< 1/3 BIASLcdInitStruct.LcdCpClk = LcdClk2k;                             ///< 电压泵时钟频率选择2kHzLcdInitStruct.LcdScanClk = LcdClk128hz;                        ///< LCD扫描频率选择128HzLcdInitStruct.LcdMode = LcdMode0;                              ///< 选择模式0LcdInitStruct.LcdClkSrc = LcdRCL;                              ///< LCD时钟选择RCLLcdInitStruct.LcdEn   = LcdEnable;                             ///< 使能LCD模块Lcd_Init(&LcdInitStruct);
}/********************************************************************************** \brief  配置背光端口PD11**** \return 无******************************************************************************/
void Backlight_Init()
{stc_gpio_cfg_t pstcGpioCfg;Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE); ///< GPIO外设时钟使能pstcGpioCfg.enDir = GpioDirOut;///< 端口方向输出  pstcGpioCfg.enDrv = GpioDrvH; ///< 端口驱动能力配置 高驱动能力  pstcGpioCfg.enPu = GpioPuEnable; ///<端口上下拉配置 无上下拉pstcGpioCfg.enOD = GpioOdDisable;  ///< 端口开漏输出配置 开漏输出关闭 pstcGpioCfg.enCtrlMode = GpioAHB; ///<端口输出输出值寄存器总线控制模式配置 AHBGpio_Init(Backlight_Port, Backlight_Pin, &pstcGpioCfg);  ///< GPIO IO PD11初始化Gpio_SetIO(Backlight_Port,Backlight_Pin);///背光关闭}//字符0-9
uint16_t lcd_Num[10]=
{Char_0,Char_1,Char_2,Char_3,Char_4,Char_5,Char_6,Char_7,Char_8,Char_9};
//这里用二维数组 正好可以将两个相邻RAM的高低位组合起来分别单独读写
uint32_t lcd_Char[10][2]=
{{Char_0_Ram1,Char_0_Ram2},{Char_1_Ram1,Char_1_Ram2},{Char_2_Ram1,Char_2_Ram2},{Char_3_Ram1,Char_3_Ram2},{Char_4_Ram1,Char_4_Ram2},{Char_5_Ram1,Char_5_Ram2},{Char_6_Ram1,Char_6_Ram2},{Char_7_Ram1,Char_7_Ram2},{Char_8_Ram1,Char_8_Ram2},{Char_9_Ram1,Char_9_Ram2},};uint32_t lcd_Ch[10][2]=
{{Ch_0_Ram1,Ch_0_Ram2},{Ch_1_Ram1,Ch_1_Ram2},{Ch_2_Ram1,Ch_2_Ram2},{Ch_3_Ram1,Ch_3_Ram2},{Ch_4_Ram1,Ch_4_Ram2},{Ch_5_Ram1,Ch_5_Ram2},{Ch_6_Ram1,Ch_6_Ram2},{Ch_7_Ram1,Ch_7_Ram2},{Ch_8_Ram1,Ch_8_Ram2},{Ch_9_Ram1,Ch_9_Ram2},
};//单个数字num 678位置 显示
void Write_SNum_pox678(uint8_t num,uint8_t pox)
{uint8_t nram;uint32_t  lcdram;lcdram0 = M0P_LCD->RAM0; lcdram1 = M0P_LCD->RAM1;switch(pox){case 8:nram = 0;    lcdram0 &= 0xffff0100;lcdram = lcdram0|lcd_Num[num];if(bai==0){lcdram = lcdram0&0xffff0100;//0xffff0000}//lcdram0 = lcdram;break;case 7:nram =0;//lcdram0 = M0P_LCD->RAM0;lcdram0 &= 0x0100ffff; //p5和低16位保留lcdram = lcdram0|lcd_Num[num]<<16;if(bai==0&&shi==0){lcdram = lcdram0&0x0100ffff;;}// lcdram0 = lcdram;break;case 6:nram =1;      lcdram1 &= 0xffff0000;lcdram = lcdram1|lcd_Num[num];// lcdram1 = lcdram;break;}Lcd_WriteRam(nram,lcdram);}
//在678区域写一个0-999的数字显示,大于999显示0
void Write_MNum_pox678(uint16_t num)
{uint8_t i,temp[3];if(num>999)num=0;for(i = 0;i <3;i++){temp[2-i] = num%10;num /= 10;}  ge = temp[2];shi = temp[1];bai =  temp[0];Write_SNum_pox678(temp[0],8);Write_SNum_pox678(temp[1],7);Write_SNum_pox678(temp[2],6);}
/********************************************************************************** \brief  小数点P显示函数**pos 显示位置**state 显示状态 0不显示,非0显示** \return 无******************************************************************************/
void Display_P(uint8_t pos,uint8_t state )
{   lcdram0 = M0P_LCD->RAM0;lcdram2 = M0P_LCD->RAM2;lcdram3 = M0P_LCD->RAM3;lcdram4 = M0P_LCD->RAM4;lcdram5 = M0P_LCD->RAM5;    lcdram7 = M0P_LCD->RAM7;lcdram9 = M0P_LCD->RAM9;lcdramB = M0P_LCD->RAMB;switch(pos){case 1: if(state==0){Lcd_WriteRam(5, lcdram5&0x0f0f0e0f);}else{Lcd_WriteRam(5, lcdram5|0x00000100);}break;case 2: if(state==0){Lcd_WriteRam(4, lcdram4&0x0f0f0e0f);}else{Lcd_WriteRam(4, lcdram4|0x00000100);}break;    case 3: if(state==0){Lcd_WriteRam(3, lcdram3&0x0f0f0e0f);}else{Lcd_WriteRam(3, lcdram3|0x00000100);}break;    case 4: if(state==0){Lcd_WriteRam(2, lcdram2&0x0f0f0e0f);}else{Lcd_WriteRam(2, lcdram2|0x00000100);}break;    case 6: if(state==0){Lcd_WriteRam(0, lcdram0&0x0f0f0e0f);}else{Lcd_WriteRam(0, lcdram0|0x00000100);}break;        case 5: if(state==0){Lcd_WriteRam(0, lcdram0&0x0e0f0f0f);}else{Lcd_WriteRam(0, lcdram0|0x01000000);}break;    case 7: if(state==0){Lcd_WriteRam(11,lcdramB&0x00000007);}else{Lcd_WriteRam(11,lcdramB|0x00000008);}break;case 8: if(state==0){Lcd_WriteRam(9, lcdram9&0x00000007);}else{Lcd_WriteRam(9, lcdram9|0x00000008);}break;            case 9: if(state==0){Lcd_WriteRam(7, lcdram7&0x070f0f0f);}else{Lcd_WriteRam(7, lcdram7|0x08000000);}break;case 10:if(state==0){Lcd_WriteRam(7, lcdram7&0x0f0f0f07);}else{Lcd_WriteRam(7, lcdram7|0x00000008);}break;}
}
/********************************************************************************** \brief  字符mA %显示函数**pos 显示位置 1--S1--mA  2--S2--%**state 显示状态 0不显示,非0显示** \return 无******************************************************************************/
void Display_S(uint8_t pos,uint8_t state )
{   lcdram6 = M0P_LCD->RAM6;switch(pos){case 1: if(state==0){Lcd_WriteRam(6, lcdram6&0x0f070f0f);}else{Lcd_WriteRam(6, lcdram6|0x00080000);}break;case 2: if(state==0){Lcd_WriteRam(6, lcdram6&0x0f0f0e0f);}else{Lcd_WriteRam(6, lcdram6|0x00000100);}break;    }
}
/********************************************************************************** \brief  单个字符在9 10 11 12 13位置显示**num 显示的字符 **pox 显示的位置** \return 无******************************************************************************/
void Write_Schar9_13(uint8_t ch,uint8_t pox)
{uint8_t nram1, nram2;uint32_t  lm1;uint32_t    lm2;lcdramB = M0P_LCD->RAMB;    lcdramC = M0P_LCD->RAMC;lcdram9 = M0P_LCD->RAM9;    lcdramA = M0P_LCD->RAMA;lcdram7 = M0P_LCD->RAM7;    lcdram8 = M0P_LCD->RAM8;lcdram6 = M0P_LCD->RAM6;switch(pox){case 9:nram1 = 11;nram2 = 12;      lcdramB &= 0;lcdramC &= 0;       lm1 = lcdramB|lcd_Char[ch][0];lm2 = lcdramC|lcd_Char[ch][1];break;case 10:nram1 = 9;nram2 = 10; lcdram9 &= 0;lcdramA &= 0;    lm1 = lcdram9|lcd_Char[ch][0];lm2 = lcdramA|lcd_Char[ch][1];break;case 11:nram1 = 7;nram2 = 8;       lcdram7 &= 0xf0ffffff;lcdram8 &= 0;  lm1 = lcdram7|lcd_Char[ch][0]<<24;lm2 = lcdram8|lcd_Char[ch][1];break;case 12:nram1 = 7;nram2 = 7;         lcdram7 &= 0xffff0000;lm1 = lcdram7|lcd_Char[ch][0];lm2 = lcdram7|lcd_Char[ch][1]<<8|lm1;//写两次相同RAM的会覆盖前一次导致前一次刷新不显示出问题break;case 13:nram1 = 6;nram2 = 6;        lcdram6 &= 0x0000ffff;lm1 = lcdram6|lcd_Char[ch][0]<<16;lm2 = lcdram6|lcd_Char[ch][1]<<24|lm1;break;        default :break;}Lcd_WriteRam(nram1,lm1);Lcd_WriteRam(nram2,lm2);
}/********************************************************************************** \brief  单个字符在1 2 3 4 5位置显示**num 显示的字符 **pox 显示的位置** \return 无******************************************************************************/
void Write_Schar1_5(uint8_t ch,uint8_t pox)
{uint8_t nram1, nram2;uint32_t  lm1;uint32_t    lm2;lcdram1 = M0P_LCD->RAM1;    lcdram2 = M0P_LCD->RAM2;lcdram3 = M0P_LCD->RAM3;    lcdram4 = M0P_LCD->RAM4;lcdram5 = M0P_LCD->RAM5;         lcdram6 = M0P_LCD->RAM6;switch(pox){case 1:nram1 = 5;nram2 = 6; lcdram5 &= 0x0000ffff;lcdram6 &= 0xffff0000;lm1 = lcdram5|lcd_Ch[ch][0];lm2 = lcdram6|lcd_Ch[ch][1];         break;case 2:nram1 = 4;nram2 = 5;lcdram4 &= 0x0000ffff;lcdram5 &= 0xffff0000;lm1 = lcdram4|lcd_Ch[ch][0];lm2 = lcdram5|lcd_Ch[ch][1];         break;case 3:nram1 = 3;nram2 = 4;lcdram3 &= 0x0000ffff;lcdram4 &= 0xffff0000;lm1 = lcdram3|lcd_Ch[ch][0];lm2 = lcdram4|lcd_Ch[ch][1];         break;case 4:nram1 = 2;nram2 = 3;lcdram2 &= 0x0000ffff;lcdram3 &= 0xffff0000;lm1 = lcdram2|lcd_Ch[ch][0];lm2 = lcdram3|lcd_Ch[ch][1];         break;case 5:nram1 = 1;nram2 = 2; lcdram1 &= 0x0000ffff;lcdram2 &= 0xffff0000;lm1 = lcdram1|lcd_Ch[ch][0];lm2 = lcdram2|lcd_Ch[ch][1];                break;}Lcd_WriteRam(nram1,lm1);Lcd_WriteRam(nram2,lm2);
}

代码自己看看吧,思路有了代码很简单的,如果有错希望指正,大家有更好的写法多提提建议,谢谢谢谢

五.效果


视频链接审核太慢,然后用PR将视频转成gif大小不能超过五兆,压缩了下就变成这b样了

六.后续补充

最近新发现有一个问题,然后再抽空补充一下代码的配置.

1.问题一:对配置代码中的问题简单理一下

/********************************************************************************** \brief  配置LCD**** \return 无******************************************************************************/
void LCD_LcdCfg(void)
{stc_lcd_cfg_t LcdInitStruct;stc_lcd_segcom_t LcdSegCom;LcdSegCom.u32Seg0_31 = 0x40000000;                              ///< 配置LCD_POEN0寄存器 开启SEG0~SEG31除30之外全部打开LcdSegCom.stc_seg32_51_com0_8_t.seg32_51_com0_8 = 0xfe1fffe0;   ///< 初始化LCD_POEN1寄存器 打开seg32-36 其余位置1关闭LcdSegCom.stc_seg32_51_com0_8_t.segcom_bit.Com0_3 = 0;          ///< 使能COM0~COM3LcdSegCom.stc_seg32_51_com0_8_t.segcom_bit.Mux = 0;             ///< Mux=0内部电阻工作模式MUX置0,Seg32_35=0为xxxxLcdSegCom.stc_seg32_51_com0_8_t.segcom_bit.Seg32_35 = 0;Lcd_SetSegCom(&LcdSegCom);                                      ///< LCD COMSEG端口配置LcdInitStruct.LcdBiasSrc = LcdInResHighPower;                  ///< 内部电阻分压 大功耗模式CRO.BSEL分压选择LcdInitStruct.LcdDuty = LcdDuty4;                              ///< 1/4dutyLcdInitStruct.LcdBias = LcdBias3;                              ///< 1/3 BIASLcdInitStruct.LcdCpClk = LcdClk2k;                             ///< 电压泵时钟频率选择2kHzLcdInitStruct.LcdScanClk = LcdClk128hz;                        ///< LCD扫描频率选择128HzLcdInitStruct.LcdMode = LcdMode0;                              ///< 选择模式0LcdInitStruct.LcdClkSrc = LcdRCL;                              ///< LCD时钟选择RCLLcdInitStruct.LcdEn   = LcdEnable;                             ///< 使能LCD模块Lcd_Init(&LcdInitStruct);
}

LCD配置主要就是配置几个寄存器,显示配置寄存器有两个输出配置寄存器 0(LCD_POEN0)和输出配置寄存器 1(LCD_POEN1)

可以看到这个配置函数最终就是写这俩寄存器.
LcdSegCom.u32Seg0_31 = 0x40000000;除了seg30为boot之外 其余的seg都用了 所以这个寄存器配置为0x40000000


由于使用的是内部电阻,所以MUX位=0,所以配置应该是)0Xfe1fefe0;但是细心的人可以发现我代码配置的是)0xfe1fffe0,区别就在于MUX位这里是1,别急,其实后面这三句分别对mux位 COM0-3 seg32-35 进行了配置.可以看这个结构体
LcdSegCom.stc_seg32_51_com0_8_t.segcom_bit.Com0_3 = 0; ///< 使能COM0~COM3
LcdSegCom.stc_seg32_51_com0_8_t.segcom_bit.Mux = 0; ///< Mux=0内部电阻工作模式MUX置0,Seg32_35=0为xxxx
LcdSegCom.stc_seg32_51_com0_8_t.segcom_bit.Seg32_35 = 0;


观察这个函数只对结构体中的第一个成员 u32Seg0-31,和 seg32-51-com0-8进行了操作,并没有对下面的segcom-bit进行操作,那问题来了怎么会在函数中赋值呢.原因是union,联合体和结构体的不同之处就是联合体各成员公用同一内存地址,所以实际上联合体的第一个成员 seg32-51-com0-8和第二个成员结构体是一个存储空间,巧妙之处就在于位域操作可以单独对这个寄存器的位进行01操作.所以修改segcom-bit.成员的值,相当于修改了 seg32-51-com0-8相应的位,所以寄存器赋值函数中只用这个变量赋值.

2.第二个问题:显示思路调整

之前讲的那种方法我认为在实际使用中完全可以使用,如果非要找点瑕疵的话,应该可以更简便一点.
之前的显示一个多位数的思路是将这个数字先分解到每一位(个十百千…)然后将对应的位依次写入对应的ram,注意是依次,也就是一个位置一个位置的显出来,这样会存在一个什么问题呢.这样的,比如说我写11 12 位置写个1和2,按照之前的思路是写ram7 和ram8 11的位置的1先显示出来,然后在写ran7把12的位置的2再显示出来,发现没? ram7写了两次,代码有重复冗余的地方,因为液晶小,刷新快所以看不出来区别,但是理想的方法是,**将显示这俩数字对应的ram都算出来,一次写好,只需写一次就可以显示,速度大大提高,**而且段数多的话也不会闪,这应该才是断码液晶驱动的正确显示方法.代码如下:

void Write_Schar9_13_NUM(uint32_t NUM)
{uint8_t P=0,Q=1;uint32_t NUMT = NUM;Lcd_ClearDisp();lcdramB = M0P_LCD->RAMB;    lcdramC = M0P_LCD->RAMC;lcdram9 = M0P_LCD->RAM9;    lcdramA = M0P_LCD->RAMA;lcdram7 = M0P_LCD->RAM7;    lcdram8 = M0P_LCD->RAM8;lcdram6 = M0P_LCD->RAM6;while(NUMT/10){Q++;NUMT/=10;}while(P<Q){P++;if(P==1){lcdram6 |= lcd_Char[NUM%10][0]<<16|lcd_Char[NUM%10][1]<<24;}else if(P==2){lcdram7 |= lcd_Char[NUM%10][0]|lcd_Char[NUM%10][1]<<8;}else if(P==3){lcdram7 |= lcd_Char[NUM%10][0]<<24; lcdram8 |=lcd_Char[NUM%10][1];}else if(P==4){lcdram9 |= lcd_Char[NUM%10][0];lcdramA |= lcd_Char[NUM%10][1];}else if(P==5){lcdramB |= lcd_Char[NUM%10][0];lcdramC |= lcd_Char[NUM%10][1];}NUM /=10;}Lcd_WriteRam(6,lcdram6);Lcd_WriteRam(7,lcdram7);Lcd_WriteRam(8,lcdram8);Lcd_WriteRam(9,lcdram9);Lcd_WriteRam(10,lcdramA);Lcd_WriteRam(11,lcdramB);Lcd_WriteRam(12,lcdramC);
}

算法思路就是先数这个数字是几位的,然后把每个 个位取出来 依次算出对应的ram,最后一次将ram写入.

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

  1. 怎么点亮段码屏_段码液晶屏实现原理及应用

    什么是段码液晶屏 段码液晶或段码液晶屏,只是液晶屏的用户对于某一类液晶显示屏的一种叫法,但是在液晶行业之内,一般都称之为图案型的液晶屏,从而来区别于点阵型的液晶屏,故段码液晶屏并不是一个很严格的表述或 ...

  2. 怎么点亮段码屏_灰阶显示段码液晶屏及其灰阶显示方法与流程

    本发明涉及一种段码液晶屏,具体涉及一种灰阶显示段码液晶屏及其灰阶显示方法,属于光电显示技术领域. 背景技术: 生活中小电器见到最多的液晶显示屏模组就是段码液晶显示屏,段码液晶显示屏有普通的数码管的特征 ...

  3. 段码液晶屏学习应用笔谈

    液晶显示屏,英文简称LCD,全称为Liquid Crystal Display. LCD从类型上分:有TN型LCD,STN型LCD和TFT型LCD等. 不同类型LCD差别: TN型 STN型 TFT型 ...

  4. 段码液晶屏实现原理及注意事项

    **段码液晶屏由于能提供简单快捷的显示效果,被广泛应用于电子领域.我们生活中常见的空调遥控器.电子血压计以及电子计算器等等,使用的都是段码液晶屏.** 图1:几种常见的段码屏 <p> Si ...

  5. 定制段码液晶屏,不的不了解的知识!

    段码液晶屏和点阵式液晶屏不同的是,段码液晶屏显示內容是固定不动的,仅仅根据手机软件操纵什么段亮,什么段没亮,需要出模定制,定制后如需更改显示屏的内容,则需再次出模:而点阵式液晶屏显示內容是由手机软件自 ...

  6. 如何判断段码液晶屏是没有问题的?

    在了解段码液晶屏检测时是否存在问题之前,先来说说如何定制液晶屏? 定制液晶屏时需要提供几个参数:尺寸.电压.液晶屏的类型.颜色.COM数.偏压比.工作温度.视角方向.是否需要背光.背光尺寸.颜色.亮度 ...

  7. 室外用LCD段码液晶屏如何选择?

    很多时候遇到客户需要定制的LCD段码液晶屏都是需要在室外用的,客户便会让我们推荐选择什么样的LCD段码液晶屏.那么我们要怎么给客户推荐呢?客户要如何选择室外用的LCD段码液晶屏呢?以下我们从4个方面来 ...

  8. 段码液晶屏怎么焊接?

    这一期是焊接段码液晶屏的干货,各位小主还请注意查收! 说起焊接段码液晶屏,之前小编给大家避雷过一个焊接方法,叫波峰焊焊接,这个焊接方法非常的不适用于咱们的段码液晶屏,很容易造成屏的损坏,那么正确的焊接 ...

  9. LCD段码液晶屏开模过程参数

    许多客户在问液晶的打样时间是总觉得时间太长,无法接受,但一般厂商不会告诉他立即可以出来,这是有原因的,下面我们来做个简单流程介绍: 一:开模的基本流程: 基础资料核实 : 尺寸.逻辑表.显示模式.显示 ...

最新文章

  1. 文件处理命令:sed
  2. php where 优先,php – 使用WHERE选择所有内容
  3. 一直被喷不实用的超算 在深度学习时代会改变吗?
  4. jquery-$()函数的用法及一些常用的选择器
  5. bzoj1669 [Usaco2006 Oct]Hungry Cows饥饿的奶牛
  6. 用立异,声东击西——贵阳Flex创客团队航行器吸引世界眼光
  7. 九章算法班L5 Linked List
  8. SAP Fiori UI上的三个catelog对应后台的JSON返回
  9. NFS服务的配置过程
  10. 基本linux命令vi,基本linux和vi命令.pdf
  11. 基于JAVA+SpringBoot+Mybatis+MYSQL的电影院管理系统
  12. 从AI打王者荣耀到自动驾驶,高通一口气公布了5G+AI未来的无数种可能
  13. 改善C#程序的建议8:避免锁定不恰当的同步对象
  14. puppeteer实现网页截图
  15. SIMULINK模型自动生成Verilog代码
  16. Vue Typescript @Prop
  17. raid功能中spanning和striping模式有什么区别?
  18. 面向对象设计原则实践:之四.里氏代换原则
  19. MATLAB中图像的读取与显示及灰度
  20. Android各厂商Rom包解压方式

热门文章

  1. vue中前端实现图片压缩 file文件
  2. [从头学数学] 第188节 千军阅尽还复来(全)
  3. SEM优化教程第5讲-百度竞价账户计划、单元搭建原则。
  4. 2021美亚杯资格赛
  5. 测试轮播banner
  6. Open3d学习计划——6(RGBD图像)
  7. 基于matlab的Lorenz系统仿真可视化
  8. 电子信息工程与计算机网络技术,电子信息工程与计算机网络技术探析
  9. 第十五届全国青少年信息学奥林匹克联赛初赛试题
  10. springboot全局异常拦截