LCD.C:
#include "gpio.h"
unsigned short int LcdDispBuf[4]; //用来保存显示的段码缓冲
void LcdInit(void)
{
//4个COM口都设置为高阻输入状态
//COM4
//GPIOC_MODE8=0; //输入模式
//GPIOC_CNF8=1; //高阻(浮空输入)输入模式
//COM3
//GPIOC_MODE9=0; //输入模式
//GPIOC_CNF9=1; //高阻(浮空输入)输入模式
//COM2
//GPIOC_MODE10=0; //输入模式
//GPIOC_CNF10=1; //高阻(浮空输入)输入模式
//COM1
//GPIOC_MODE11=0; //输入模式
//GPIOC_CNF11=1; //高阻(浮空输入)输入模式
//PE口设置为50MHz推挽输出
GPIOE_CRL=0x33333333;
GPIOE_CRH=0x33333333;
//先初始化为无显示
LcdDispBuf[0]=0;
LcdDispBuf[1]=0;
LcdDispBuf[2]=0;
LcdDispBuf[3]=0;
}
//像万利的板子上使用的这种LCD,有4个COM,还有有16个SEG。
//要想某一SEG显示时,需要在对应的SEG和COM之间加上足够的电压,
//但是LCD它不像LED那样,有电压就一直亮的,它只能维持一段
//时间,然后内容就消失了。此时需要将电压反转再加到相应的
//SEG和COM之间。在万利的板子上,COM驱动使用了两个电阻分压,
//输出电压为1/2VCC,当不想让某位显示时,就将它的电压设置
//为1/2VCC(通过设置IO口为高阻态来完成),这样加在对应的
//SEG和COM之间的电压只有1/2VCC,不足以点亮对应的SEG。需要显示
//的,就将COM电压设置为0或者1,这样SEG电压跟COM电压相反的
//段就被点亮了(变黑)。通过定期扫描每个COM,即可稳定的在LCD
//上显示需要的图形了。需要显示字符或者数字时,需要自己将
//对应的图案设计好,需要显示时,发送到相应的SEG和COM上即可。
/*the varitronix LCD digit is:
A
-- ----------
X \/ |\ |I /|
F| H | J |B
| \ | / |
--G-- --K--
| /| \ |
E | L | N |C
| / |M \| _
----------- | |DP
D -
PE0 PE1 PE2 PE3 ...................................................... PE15
----------------------------------------------------------------------------------------
| | S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | S8 | S9 | S10| S11| S12| S13| S14| S15|
----------------------------------------------------------------------------------------
| COM1 | 1X | 1I | 1A | 1DP| 2X | 2I | 2A | 2DP| 3X | 3I | 3A | 3DP| 4X | 4I | 4A | 4DP|
----------------------------------------------------------------------------------------
| COM2 | 1F | 1H | 1J | 1B | 2F | 2H | 2J | 2B | 3F | 3H | 3J | 3B | 4F | 4H | 4J | 4B |
----------------------------------------------------------------------------------------
| COM3 | 1E | 1G | 1K | 1C | 2E | 2G | 2K | 2C | 3E | 3G | 3K | 3C | 4E | 4G | 4K | 4C |
----------------------------------------------------------------------------------------
| COM4 | 1L | 1M | 1N | 1D | 2L | 2M | 2N | 2D | 3L | 3M | 3N | 3D | 4L | 4M | 4N | 4D |
----------------------------------------------------------------------------------------
A LCD character coding is based on the following matrix:
{ X , F , E , L }
{ I , H , G , M }
{ A , J , K , N }
{ DP, B , C , D }
The characher A for example is:
{ 0 , 1 , 1 , 0 }
{ 0 , 0 , 1 , 0 }
{ 1 , 0 , 1 , 0 }
{ 0 , 1 , 1 , 0 }
-------------------
= 4 9 F 0 hex
=> 'A' = 0x49F0 */
const unsigned short int Letter[26]={0x49F0,0x01F8,0x4118,0x08F8,0x4178,0x4170,0x41D8,0x09F0,0x600A,
0x0888,0x0534,0x0118,0x0F90,0x0B94,0x4998,0x4970,0x499C,0x4974,
0x41E8,0x6002,0x0998,0x0511,0x299A,0x0605,0x0601,0x4409};
const unsigned short int Number[10]={0x4998,0x0880,0x4878,0x48E8,0x09E0,0x41E8,0x41F8,0x4880,0x49F8,0x49E8};
const unsigned short int Arrow[2]={0x0005,0x0600}; // {Upstair,Downstair}
//根据LCD需要显示的字符设置缓冲区的内容。
//入口参数c为需要显示的字符。
//入口参数p为需要显示的位置,从左往右依次为0,1,2,3。
//入口参数dot为是否需要显示小数点和单引号,1只显示小数点,
//2只显示单引号,3为小数点和单引号同时显示
void LcdSetChar(unsigned char c, unsigned char p, unsigned char dot)
{
//定义一个Temp变量来保存查表的结果
unsigned short int Temp;
if(p>3)return;
if((c>='A')&&(c<='Z')) //A~Z之间的字符
{
Temp=Letter[c-'A'];
}
else if((c>='0')&&(c<='9')) //0~9之间的数
{
Temp=Number[c-'0'];
}
else if(c=='\'') //单引号
{
Temp=0x1000;
}
else if(c=='.') //小数点
{
Temp=0x8000;
}
else //暂时不支持其它字符显示
{
Temp=0;
}
//如果需要显示小数点
if(dot==1)Temp|=0x8000;
if(dot==2)Temp|=0x1000;
if(dot==3)Temp|=0x9000;
//根据不同的位置,设置显示缓冲区中的值
//在这里,并不是每个COM都刚好对应着LCD
//上的一个字符位置,而是每个COM都同时
//控制着4个字符中的4个SEG,因此需要修改
//某个字符位置的显示,就必须将显示缓冲
//区中的每个变量中对应的4位进行修改。
//将COM1选中时显示的SEG中的对应4位先清0
LcdDispBuf[0]&=~((0xF)<<(p*4));
//然后再将需要显示的内容写入
LcdDispBuf[0]|=(((Temp>>12)&0xF)<<(p*4));
//将COM1选中时显示的SEG中的对应4位先清0
LcdDispBuf[1]&=~((0xF)<<(p*4));
//然后再将需要显示的内容写入
LcdDispBuf[1]|=(((Temp>>8)&0xF)<<(p*4));
//将COM1选中时显示的SEG中的对应4位先清0
LcdDispBuf[2]&=~((0xF)<<(p*4));
//然后再将需要显示的内容写入
LcdDispBuf[2]|=(((Temp>>4)&0xF)<<(p*4));
//将COM1选中时显示的SEG中的对应4位先清0
LcdDispBuf[3]&=~((0xF)<<(p*4));
//然后再将需要显示的内容写入
LcdDispBuf[3]|=(((Temp)&0xF)<<(p*4));
}
//每隔一段时间要调用一次该函数,例如2ms
//可以在一个定时器中调用该函数来定期刷新
//这里为了演示程序,使用软件延时的方法
void LcdScan(void)
{
static unsigned int i=1;
static unsigned int Off=0;
if(Off==1)
{
Off=0;
//先将4个COM都设置为高阻状态
GPIOC_MODE8=0; //输入模式
GPIOC_CNF8=1; //高阻输入模式
GPIOC_MODE9=0; //输入模式
GPIOC_CNF9=1; //高阻输入模式
GPIOC_MODE10=0; //输入模式
GPIOC_CNF10=1; //高阻输入模式
GPIOC_MODE11=0; //输入模式
GPIOC_CNF11=1; //高阻输入模式
//然后将所有SEG设置为低电平
GPIOE_ODR=0;
//再将所有COM设置为低电平
GPIOC_CLR=(1<<8)|(1<<9)|(1<<10)|(1<<11);
GPIOC_MODE8=3; //50M输出模式
GPIOC_CNF8=0; //推挽模式
GPIOC_MODE9=3; //50M输出模式
GPIOC_CNF9=0; //推挽模式
GPIOC_MODE10=3; //50M输出模式
GPIOC_CNF10=0; //推挽模式
GPIOC_MODE11=3; //50M输出模式
GPIOC_CNF11=0; //推挽模式
return;
}
else
{
Off=1;
//先将4个COM都设置为高阻状态
GPIOC_MODE8=0; //输入模式
GPIOC_CNF8=1; //高阻输入模式
GPIOC_MODE9=0; //输入模式
GPIOC_CNF9=1; //高阻输入模式
GPIOC_MODE10=0; //输入模式
GPIOC_CNF10=1; //高阻输入模式
GPIOC_MODE11=0; //输入模式
GPIOC_CNF11=1; //高阻输入模式
}
switch(i)
{
case 1:
//COM4的前半个周期
GPIOE_ODR=LcdDispBuf[3]; //将SEG码输出
GPIOC_CLR=1<<8; //COM4输出低电平
GPIOC_CNF8=0; //推挽输出
GPIOC_MODE8=3; //50MHz输出模式
break;
case 2:
//COM4的后半个周期
GPIOE_ODR=~LcdDispBuf[3]; //将SEG码取反
GPIOC_SET=1<<8; //COM4输出高电平
GPIOC_CNF8=0; //推挽输出
GPIOC_MODE8=3; //50MHz输出模式
break;
case 3:
//COM3的前半个周期
GPIOE_ODR=LcdDispBuf[2]; //将SEG码输出
GPIOC_CLR=1<<9; //COM3输出低电平
GPIOC_CNF9=0; //推挽输出
GPIOC_MODE9=3; //50MHz输出模式
break;
case 4:
//COM3的后半个周期
GPIOE_ODR=~LcdDispBuf[2]; //将SEG码取反
GPIOC_SET=1<<9; //COM3输出高电平
GPIOC_CNF9=0; //推挽输出
GPIOC_MODE9=3; //50MHz输出模式
break;
case 5:
//COM2的前半个周期
GPIOE_ODR=LcdDispBuf[1]; //将SEG码输出
GPIOC_CLR=1<<10; //COM2输出低电平
GPIOC_CNF10=0; //推挽输出
GPIOC_MODE10=3; //50MHz输出模式
break;
case 6:
//COM2的后半个周期
GPIOE_ODR=~LcdDispBuf[1]; //将SEG码取反
GPIOC_SET=1<<10; //COM2输出高电平
GPIOC_CNF10=0; //推挽输出
GPIOC_MODE10=3; //50MHz输出模式
break;
case 7:
//COM1的前半个周期
GPIOE_ODR=LcdDispBuf[0]; //将SEG码输出
GPIOC_CLR=1<<11; //COM1输出低电平
GPIOC_CNF11=0; //推挽输出
GPIOC_MODE11=3; //50MHz输出模式
break;
case 8:
//COM1的后半个周期
GPIOE_ODR=~LcdDispBuf[0]; //将SEG码取反
GPIOC_SET=1<<11; //COM1输出高电平
GPIOC_CNF11=0; //推挽输出
GPIOC_MODE11=3; //50MHz输出模式
i=0;
break;
default :
i=0;
}
//切换到下一状态
i++;
}
LCD.h:
#ifndef __LCD_H__
#define __LCD_H__
void LcdScan(void);
void LcdInit(void);
void LcdSetChar(unsigned char c, unsigned char p, unsigned char dot);
extern unsigned short int LcdDispBuf[4]; //用来保存显示的段码缓冲
#endif
|