在实际项目中,我们通常会遇到许多需要驱动LCD段码屏的情形。
如下图:
假如是LED灯,我们都知道只需加载在一端接高另一端接低的直流电,就可以点亮。但是对于液晶屏来说,长时间的加直流电压会损坏液晶屏的内部,并且不可逆。所以需要用模拟的交流电来驱动,正常厂商会给你一份规格书,base偏压达到多少以上对应的字段就会点亮,我的这个是2.5V,也就是说一个段的两端压差超过2.5V,对应的段就会点亮。
有需求就会有市场,于是带LCD工作模式的芯片就问世了,它的IO口有一个专门的寄存器来控制它输出多大的电压,区别于正常的只能是高或低的芯片,确实很方便。
很幸运,老板的预算不足以我来用这样的芯片,考验哥们的时候来了。话不多说,直接展示结果:
所有的COM口和Seg口都接IO口,直接控制。
使用这样的电路:我们只需要改变IO口的工作模式就可以达到改变COM端电压的大小,浮空输入模式下,IO口电压完全取决于外部电压,我的原理图5V和GND对半分刚好是2.5V,等于我的LCD段码屏base电压,所以我只需要让5个COM循环扫描,仅仅在对应的时间段内拉高或者拉低Seg口即可,COM口扫描波形如下
这个是四扫的示意图,简单说就是在一个时间片内只有一个COM口是工作在有效电压内,其余都不是,四个口来回换着工作,由于它换的太快了,人眼识别不了这么快的亮灭,就觉得它是一直亮的,这和呼吸灯是一个道理
驱动部分代码如下:
void LedDisplayProcess()
{
unsigned char i;
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 |GPIO_Pin_6 |GPIO_Pin_7 |GPIO_Pin_8|GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//2.5V
if(LedReadyFlag)
{
LedReadyFlag=0; //显示数据更新标志位
for(i=0;i<5;i++)
{
S_LEDDSP1[i]=LEDDSP1[i];
}
}
if(++SEGNumber>=10) //0~9 对应5个COM口的10个时间片(单个COM口有高和低2种,base不算是一种)
SEGNumber=0;
LCD_Scan_Deal();//COM、Seg扫描函数 此处只做COM的展示,Seg结合自己的应用,对应拉低或拉高即可
}
void LCD_Scan_Deal()
{
//com----------------------------------------------------------------------------------
if(SEGNumber==0)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits( GPIOA, GPIO_Pin_5);//5V
}
if(SEGNumber==1)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits( GPIOA, GPIO_Pin_5);//0V
}
if(SEGNumber==2)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits( GPIOA, GPIO_Pin_6);//5V
}
if(SEGNumber==3)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits( GPIOA, GPIO_Pin_6);//0V
}
if(SEGNumber==4)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_7);//5V
}
if(SEGNumber==5)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA, GPIO_Pin_7);//0V
}
if(SEGNumber==6)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits( GPIOA, GPIO_Pin_8);//5V
}
if(SEGNumber==7)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA, GPIO_Pin_8);//0V
}
if(SEGNumber==8)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits( GPIOA, GPIO_Pin_13);//5V
}
if(SEGNumber==9)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA, GPIO_Pin_13);//0V
}
}
这样就完美实现了不用专门的驱动芯片仅靠MCU的IO口来实现LCD屏的显示。
这里再给大家补充一个小技巧,当IO口不够用时,我们是可以将输入和输出分时复用的,比如我的这个项目中Seg和按键检测就是部分复用
只需要在按键扫描前改为输入模式,扫描函数结束改为输出模式,并不会对效果产生很大的影响。