⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lcd.c

📁 基于EK—STM32开发板的LCD驱动编程实现
💻 C
字号:
/******************************************************************
   本程序只供学习使用,未经作者许可,不得用于其它任何用途

        欢迎访问我的USB专区:http://group.ednchina.com/93/
        欢迎访问我的blog:   http://www.ednchina.com/blog/computer00
                             http://computer00.21ic.org

LCD.c  file

作者:Computer-lov
建立日期: 2008.07.30
修改日期: 2008.07.31
版本:V1.2
版权所有,盗版必究。
Copyright(C) Computer-lov 2008-2018
All rights reserved            
*******************************************************************/

#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;
 
 //一个完整的驱动周期,需要在COM和SEG之间正负
 //电压交替一次。我们把COM输出低时定义为前半
 //个周期,COM输出为高时定义为后半个周期。
 //为了能够调节显示的对比度,需要在每个半周期
 //中控制显示时间的长短。这里为了程序简单,
 //使用了50%的占空比,即在每个半周期的前半段
 //正常显示,后半段不显示,将COM和SEG都设置为
 //低电平。该过程由Off标志来决定,当Off标志
 //为1时,则是后半段的关闭过程,将COM和SEG置0
 //后,就返回。当Off标志为0时,则处于前半段,
 //就选中某个COM显示。这样,对于一个COM,完整
 //的扫描周期有4个阶段:COM负亮,关,COM正亮,关。
 //由于有4个COM,因此整个扫描周期就有16个阶段。
 
 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++;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -