打印
[STM32F1]

STM32液晶显示HT1621驱动原理及程序代码

[复制链接]
3030|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
1、HT1621电路分析
      HT1621为32×4即128点内存映像LCD驱动器,包含内嵌的32×4位显示RAM内存和时基发生器以及WDT看门狗定时器.
      HT1621驱动电路如下图所示:
图1
          与单片机相连接控制的有9脚CS,3脚WR,12脚DATA,其功能描述如下表。
图2

沙发
734774645|  楼主 | 2018-12-5 22:30 | 只看该作者
2、字符显示原理
         液晶管点亮和熄灭原理分别为在对应的RAM地址中写1和写0.首先需要清楚所驱动控制的液晶的COM-SEG对应关系,然后需要了解HT1621的32×4RAM地址映射。
         例如要控制的液晶的装脚成品图部分如下:
图3
        着重看一个液晶数码管,我们了解原理就行。可以看到图3中是第2个液晶数码管,有7段,分别为A,B,C,D,E,F,G。也就分别为下面COM\SEG地址对应关系图中的2A,2B,2C,2D,2E,2F,2G。
        液晶的显示字符的部分COM公共端输出口和SEG段输出口的分布如下表所示,同理我们可以看到例如:2D对应(SEG5,COM0),2E对应(SEG5,COM1),2F对应(SEG5,COM2),2A对应(SEG5,COM3),2C对应(SEG4,COM1),2G对应(SEG4,COM2),2B对应(SEG4,COM3)。
图4
         搞清楚我们要控制的对象之后那,  HT1621的RAM 地址映射如下图所示:
图5
        可以清楚的看到要控制液晶段对应SEG号作为6位地址,COM号对应作为4位数据写入,此时注意4位数据的高低位。写数据到RAM命令格式为:101+6位RAM地址+4位数据,其中RAM地址为SEG序号.
        例如我们在图3的第二个液晶数码管上显示数字,首先我们根据图3得到地址映射关系,先写入地址SEG4中的四位数据(COM3,COM2,COM1,COM0),再写如地址SEG5中的四位数据(COM3,COM2,COM1,COM0),对应关系如下:
SEG4
SEG5
COM3
COM2
COM1
COM0
COM3
COM2
COM1
COM0
2B
2G
2C
T10
2A
2F
2E
2D
        所以如果在图3中显示“5”,则在显示的液晶段对应地址上写1,不显示写0,如下图所示。所以SEG4地址应写入的数据为0110 ,SEG5地址应写入数据1101。
图6

使用特权

评论回复
板凳
734774645|  楼主 | 2018-12-5 22:31 | 只看该作者
3、显示的保持       
     写数据过程需要保证写前无关位数据的保持,因此在单片机程序中开辟32×4数组作为虚拟ARM,存储写前LCD显示数据.通过与清零,或置位操作实现,例如6位地址Address当前显示的数据为Data_last .若Xi(i=0,1,2,3) 位需要保持,则Xi为1,否则Xi为0.写入的数据为Data_now,变换公式为:

使用特权

评论回复
地板
734774645|  楼主 | 2018-12-5 22:31 | 只看该作者
4、程序
      主要的程序编写流程如下:
图7
            程序的参考步骤:
①Display_Wendu_1
②write_addr_dat_n_wendu
③write_mode
④write_address
⑤write_data_4bit,
其中Lcdram数组为建立的虚拟数组。

使用特权

评论回复
5
734774645|  楼主 | 2018-12-5 22:32 | 只看该作者
unsigned char Lcdram[32]=
    {
                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    };

const unsigned char Wendu[] = //温度0-9
    {   
    0X5F, 0X50, 0X3D, 0X79, 0X72, 0X6B, 0X6F, 0X51, 0X7F, 0X7B
    };
///////////////////////////////////////////////////驱动函数
/*
*    LCD 模式写入
*    入口:MODE :COM(命令模式) DAT(数据模式)
*    出口:void
*/
void write_mode(unsigned char MODE)    //写入模式,数据or命令
{
    GPIO_ResetBits(GPIOB, HT1621_WR);                                //    RW = 0;
    delay_us(10);
    GPIO_SetBits(GPIOB, HT1621_DATA);                                    //    DA = 1;
    GPIO_SetBits(GPIOB, HT1621_WR);                                    //    RW = 1;
    delay_us(10);

    GPIO_ResetBits(GPIOB, HT1621_WR);                                //    RW = 0;
    delay_us(10);
    GPIO_ResetBits(GPIOB, HT1621_DATA);                                //    DA = 0;
    GPIO_SetBits(GPIOB, HT1621_WR);                                    //    RW = 1;
    delay_us(10);

    GPIO_ResetBits(GPIOB, HT1621_WR);                                //    RW = 0;
    delay_us(10);

    if (0 == MODE)
    {
        GPIO_ResetBits(GPIOB, HT1621_DATA);                            //    DA = 0;
    }
    else
    {
        GPIO_SetBits(GPIOB, HT1621_DATA);                                //    DA = 1;
    }
    delay_us(10);
    GPIO_SetBits(GPIOB, HT1621_WR);                                    //    RW = 1;
    delay_us(10);
}

/*
*    LCD 命令写入函数
*    入口:cbyte ,控制命令字
*    出口:void
*/
void write_command(unsigned char Cbyte)
{
    unsigned char i = 0;

    for (i = 0; i < 8; i++)
    {
        GPIO_ResetBits(GPIOB, HT1621_WR);
        if ((Cbyte >> (7 - i)) & 0x01)
        {
            GPIO_SetBits(GPIOB, HT1621_DATA);
        }
        else
        {
            GPIO_ResetBits(GPIOB, HT1621_DATA);
        }
        delay_us(10);
        GPIO_SetBits(GPIOB, HT1621_WR);
        delay_us(10);
    }
    GPIO_ResetBits(GPIOB, HT1621_WR);
    delay_us(10);
    GPIO_ResetBits(GPIOB, HT1621_DATA);
    GPIO_SetBits(GPIOB, HT1621_WR);
    delay_us(10);
}

/*
*    LCD 地址写入函数
*    入口:cbyte,地址
*    出口:void
*/
void write_address(unsigned char Abyte)
{
    unsigned char i = 0;
    Abyte = Abyte << 2;

    for (i = 0; i < 6; i++)
    {
        GPIO_ResetBits(GPIOB, HT1621_WR);
        //delay_us(10);
        if ((Abyte >> (7 - i)) & 0x01)
        {
            GPIO_SetBits(GPIOB, HT1621_DATA);
        }
        else
        {
            GPIO_ResetBits(GPIOB, HT1621_DATA);
        }
        delay_us(10);
        GPIO_SetBits(GPIOB, HT1621_WR);
        delay_us(10);
    }
   
}

/*
*    LCD 数据写入函数
*    入口:Dbyte,数据
*    出口:void
*/
void write_data_8bit(unsigned char Dbyte)
{
    int i = 0;

    for (i = 0; i < 8; i++)
    {
        GPIO_ResetBits(GPIOB, HT1621_WR);
        delay_us(10);
        if ((Dbyte >> (7 - i)) & 0x01)
        {
            GPIO_SetBits(GPIOB, HT1621_DATA);
        }
        else
        {
            GPIO_ResetBits(GPIOB, HT1621_DATA);
        }
        delay_us(10);
        GPIO_SetBits(GPIOB, HT1621_WR);
        delay_us(10);
    }
}

void write_data_4bit(unsigned char Dbyte)
{
    int i = 0;

    for (i = 0; i < 4; i++)
    {
        GPIO_ResetBits(GPIOB, HT1621_WR);
        //delay_us(10);
        if ((Dbyte >> (3 - i)) & 0x01)
        {
            GPIO_SetBits(GPIOB, HT1621_DATA);
        }
        else
        {
            GPIO_ResetBits(GPIOB, HT1621_DATA);
        }
        delay_us(10);
        GPIO_SetBits(GPIOB, HT1621_WR);
        delay_us(10);
    }
}



//1621初始化
void ht1621_init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;// declare the structure
        GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);
        memset(&GPIO_InitStructure, 0, sizeof(GPIO_InitTypeDef));
        GPIO_InitStructure.GPIO_Pin =  HT1621_WR | HT1621_DATA ;//| HT1621_IRQ
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);

        memset(&GPIO_InitStructure, 0, sizeof(GPIO_InitTypeDef));
        GPIO_InitStructure.GPIO_Pin = HT1621_CS ;//| HT1621_IRQ
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

}

/*
*    LCD 初始化,对lcd自身做初始化设置
*    入口:void
*    出口:void
*/
void lcd_init(void)
{
    //////////////////////////////////////////////////////
    GPIO_SetBits(GPIOA, HT1621_CS);
    GPIO_SetBits(GPIOB, HT1621_WR);
    GPIO_SetBits(GPIOB, HT1621_DATA);
    for (ii=0;ii<10000;ii++)
    {for(j=10;j>0;j--);}
    //////////////////////////////////////////////////////        
    GPIO_ResetBits(GPIOA, HT1621_CS);        //CS = 0;
    //delay_us(10);
    for (ii=0;ii<10000;ii++)
    {for(j=10;j>0;j--);}
    write_mode(COMMAND);    //命令模式
    write_command(0x01);    //Enable System
    write_command(0x03);    //Enable Bias
    write_command(0x04);    //Disable Timer
    write_command(0x05);    //Disable WDT
    write_command(0x08);    //Tone OFF
    write_command(0x18);    //on-chip RC震荡
    write_command(0x29);    //1/4Duty 1/3Bias
    write_command(0x80);    //Disable IRQ
    write_command(0x40);    //Tone Frequency 4kHZ
    write_command(0xE3);    //Normal Mode

    GPIO_SetBits(GPIOA, HT1621_CS);  //CS = 1;
}

/*
*    LCD 清屏函数
*    入口:void
*    出口:void
*/
void lcd_clr(void)
{
    write_addr_dat_n(0x0, 0x00, 32);//15
}
//用于温度区域写数据
void write_addr_dat_n_wendu(unsigned char _addr, unsigned char _dat, unsigned char n)
{
   
    unsigned char i = 0;
    unsigned char _dat_temp1,_dat_temp2;
   
    //WriteLcdram(_addr, _dat);
        
   

    GPIO_ResetBits(GPIOA, HT1621_CS);                                // CS = 0;
    write_mode(DAT);
   
    if(Lcdram[_addr]==0x00)
    {
        WriteLcdram(_addr, _dat);
    }
        if((_addr%2)==0)
        {
            _dat_temp1=Lcdram[_addr];
            _dat_temp2=(_dat_temp1&0x08)|_dat;
            
            write_address(_addr);
            for (i = 0; i < n; i++)
        {
            write_data_4bit(_dat_temp2);
        }
        GPIO_SetBits(GPIOA, HT1621_CS);                                    //CS = 1;
            
        }
        else if((_addr%2)!=0)
        {
            write_address(_addr);
            for (i = 0; i < n; i++)
        {
            write_data_4bit(_dat);
        }
        GPIO_SetBits(GPIOA, HT1621_CS);
        }
        
        WriteLcdram(_addr, _dat_temp2);
}

//用于湿度区域写数据
void write_addr_dat_n_shidu(unsigned char _addr, unsigned char _dat, unsigned char n)
{
   
    unsigned char i = 0;
    unsigned char _dat_temp1,_dat_temp2;
   
    //WriteLcdram(_addr, _dat);
        
   

    GPIO_ResetBits(GPIOA, HT1621_CS);                                // CS = 0;
    write_mode(DAT);
   
    if(Lcdram[_addr]==0x00)
    {
        WriteLcdram(_addr, _dat);
    }
        if((_addr%2)==0)
        {
            _dat_temp1=Lcdram[_addr];
            _dat_temp2=(_dat_temp1&0x01)|_dat;
            
            write_address(_addr);
            for (i = 0; i < n; i++)
        {
            write_data_4bit(_dat_temp2);
        }
        GPIO_SetBits(GPIOA, HT1621_CS);                                    //CS = 1;
            
        }
        else if((_addr%2)!=0)
        {
            write_address(_addr);
            for (i = 0; i < n; i++)
        {
            write_data_4bit(_dat);
        }
        GPIO_SetBits(GPIOA, HT1621_CS);
        }
        
        WriteLcdram(_addr, _dat_temp2);
}


//用于底部数字写数据
void write_addr_dat_n_others(unsigned char _addr, unsigned char _dat, unsigned char n)
{
   
    unsigned char i = 0;
    unsigned char _dat_temp1,_dat_temp2;
    GPIO_ResetBits(GPIOA, HT1621_CS);                                // CS = 0;
    write_mode(DAT);
   
    if(Lcdram[_addr]==0x00)
    {
        WriteLcdram(_addr, _dat);
        
    }
        if((_addr%2)==0)
        {
            _dat_temp1=Lcdram[_addr];
            _dat_temp2=(_dat_temp1&0x01)|_dat;
            
            write_address(_addr);
            for (i = 0; i < n; i++)
        {
            write_data_4bit(_dat_temp2);
        }
        GPIO_SetBits(GPIOA, HT1621_CS);                                    //CS = 1;
            
        }
        else if((_addr%2)!=0)
        {
            write_address(_addr);
            for (i = 0; i < n; i++)
        {
            write_data_4bit(_dat);
        }
        GPIO_SetBits(GPIOA, HT1621_CS);
        }
        
        //WriteLcdram(_addr, _dat);
        WriteLcdram(_addr, _dat_temp2);
}

//用于字符写数据
void write_addr_dat_n_char(unsigned char _addr, unsigned char _dat, unsigned char state)
{
   
    unsigned char i = 0;
    unsigned char _dat_temp1,_dat_temp2;
   

        GPIO_ResetBits(GPIOA, HT1621_CS);                                // CS = 0;
         write_mode(DAT);
            
                _dat_temp1=Lcdram[_addr];
            if(state==1)
            {
               
                _dat_temp2=(_dat_temp1|_dat);
            }
            else if(state==0)
            {
                _dat_temp2=(_dat_temp1&(~_dat));
            }
                 write_address(_addr);
            
                for (i = 0; i < 1; i++)
            {
                write_data_4bit(_dat_temp2);
            }
            GPIO_SetBits(GPIOA, HT1621_CS);                                    //CS = 1;
            WriteLcdram(_addr, _dat_temp2);
        
        
        
   
}
//显示温度
//入口:pos,显示位置,地址0、2、4分别为从右到左的三个数字
//            num:要显示的一位数
void Display_Wendu_1(unsigned char add, unsigned char num )
{
    unsigned char n,i,j;
    n=getChr_Wendu(num);
    i=(n&0xF0)>>4;
    j=n&0x0F;
    write_addr_dat_n_wendu(add,i,1);
    write_addr_dat_n_wendu(add+1,j,1);
   
}


//温度数据转换,lcd.c内部使用
unsigned char getChr_Wendu(unsigned char c)
{
     unsigned char i;
        for ( i = 0; i < 10; ++i)
        {
            if (c == i)
            {
                return Wendu[i];
            }
        }
    }

//更新lcdram数组
void WriteLcdram(unsigned char add, unsigned char data)
{
   
    Lcdram[add]=data;
   
}

使用特权

评论回复
6
磨砂| | 2018-12-7 13:55 | 只看该作者
非常感谢楼主分享啊

使用特权

评论回复
7
晓伍| | 2018-12-7 13:59 | 只看该作者
分析的好详细啊

使用特权

评论回复
8
八层楼| | 2018-12-7 14:03 | 只看该作者
源码写的很清晰

使用特权

评论回复
9
haihua151| | 2019-3-27 10:46 | 只看该作者

使用特权

评论回复
10
gdgn_0526345| | 2019-6-3 16:29 | 只看该作者
本帖最后由 gdgn_0526345 于 2019-6-3 16:32 编辑

HT1621_WR     HT1621_DATA   COMMAND 之类的宏定义应用  如果贴出来就好了

使用特权

评论回复
11
joyshen102| | 2019-10-17 11:53 | 只看该作者
原帖写的新详细啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

197

主题

3451

帖子

14

粉丝