本帖最后由 SnailWillow 于 2021-3-15 17:12 编辑

1、HT1621电路分析

      HT1621为32×4即128点内存映像LCD驱动器,包含内嵌的32×4位显示RAM内存和时基发生器以及WDT看门狗定时器.

      HT1621驱动电路如下图所示:

1070495-20180627225051691-2038770537.png

图1

1070495-20180627225150876-1500656912.png

          与单片机相连接控制的有9脚CS,3脚WR,12脚DATA,其功能描述如下表。

1070495-20180627225513986-195694438.png

图2

2、字符显示原理

         液晶管点亮和熄灭原理分别为在对应的RAM地址中写1和写0.首先需要清楚所驱动控制的液晶的COM-SEG对应关系,然后需要了解HT1621的32×4RAM地址映射。

         例如要控制的液晶的装脚成品图部分如下:

1070495-20180628101719637-1218396171.png

图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)。

1070495-20180628102414101-683330418.png

图4

         搞清楚我们要控制的对象之后那,  HT1621的RAM 地址映射如下图所示:

1070495-20180628103613524-643933794.png

图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。

1070495-20180628111442268-864304970.png

图6

3、显示的保持      

     写数据过程需要保证写前无关位数据的保持,因此在单片机程序中开辟32×4数组作为虚拟ARM,存储写前LCD显示数据.通过与清零,或置位操作实现,例如6位地址Address当前显示的数据为Data_last .若Xi(i=0,1,2,3) 位需要保持,则Xi为1,否则Xi为0.写入的数据为Data_now,变换公式为:

1070495-20180628151228131-2538792.png

4、程序

      主要的程序编写流程如下:

1070495-20180628152647965-1330687251.png

图7

            程序的参考步骤:①Display_Wendu_1②write_addr_dat_n_wendu③write_mode④write_address⑤write_data_4bit,其中Lcdram数组为建立的虚拟数组。

1 unsigned char Lcdram[32]=
  •   2     {
  •   3                 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  •   4                 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  •   5                 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  •   6                 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  •   7     };
  •   8
  •   9 const unsigned char Wendu[] = //温度0-9
  • 10     {   
  • 11     0X5F, 0X50, 0X3D, 0X79, 0X72, 0X6B, 0X6F, 0X51, 0X7F, 0X7B
  • 12     };
  • 13 ///驱动函数
  • 14 /*
  • 15 *    LCD 模式写入
  • 16 *    入口:MODE :COM(命令模式) DAT(数据模式)
  • 17 *    出口:void
  • 18 */
  • 19 void write_mode(unsigned char MODE)    //写入模式,数据or命令
  • 20 {
  • 21     GPIO_ResetBits(GPIOB, HT1621_WR);                                //    RW = 0;
  • 22     delay_us(10);
  • 23     GPIO_SetBits(GPIOB, HT1621_DATA);                                    //    DA = 1;
  • 24     GPIO_SetBits(GPIOB, HT1621_WR);                                    //    RW = 1;
  • 25     delay_us(10);
  • 26
  • 27     GPIO_ResetBits(GPIOB, HT1621_WR);                                //    RW = 0;
  • 28     delay_us(10);
  • 29     GPIO_ResetBits(GPIOB, HT1621_DATA);                                //    DA = 0;
  • 30     GPIO_SetBits(GPIOB, HT1621_WR);                                    //    RW = 1;
  • 31     delay_us(10);
  • 32
  • 33     GPIO_ResetBits(GPIOB, HT1621_WR);                                //    RW = 0;
  • 34     delay_us(10);
  • 35
  • 36     if (0 == MODE)
  • 37     {
  • 38         GPIO_ResetBits(GPIOB, HT1621_DATA);                            //    DA = 0;
  • 39     }
  • 40     else
  • 41     {
  • 42         GPIO_SetBits(GPIOB, HT1621_DATA);                                //    DA = 1;
  • 43     }
  • 44     delay_us(10);
  • 45     GPIO_SetBits(GPIOB, HT1621_WR);                                    //    RW = 1;
  • 46     delay_us(10);
  • 47 }
  • 48
  • 49 /*
  • 50 *    LCD 命令写入函数
  • 51 *    入口:cbyte ,控制命令字
  • 52 *    出口:void
  • 53 */
  • 54 void write_command(unsigned char Cbyte)
  • 55 {
  • 56     unsigned char i = 0;
  • 57
  • 58     for (i = 0; i < 8; i++)
  • 59     {
  • 60         GPIO_ResetBits(GPIOB, HT1621_WR);
  • 61         if ((Cbyte >> (7 - i)) & 0x01)
  • 62         {
  • 63             GPIO_SetBits(GPIOB, HT1621_DATA);
  • 64         }
  • 65         else
  • 66         {
  • 67             GPIO_ResetBits(GPIOB, HT1621_DATA);
  • 68         }
  • 69         delay_us(10);
  • 70         GPIO_SetBits(GPIOB, HT1621_WR);
  • 71         delay_us(10);
  • 72     }
  • 73     GPIO_ResetBits(GPIOB, HT1621_WR);
  • 74     delay_us(10);
  • 75     GPIO_ResetBits(GPIOB, HT1621_DATA);
  • 76     GPIO_SetBits(GPIOB, HT1621_WR);
  • 77     delay_us(10);
  • 78 }
  • 79
  • 80 /*
  • 81 *    LCD 地址写入函数
  • 82 *    入口:cbyte,地址
  • 83 *    出口:void
  • 84 */
  • 85 void write_address(unsigned char Abyte)
  • 86 {
  • 87     unsigned char i = 0;
  • 88     Abyte = Abyte << 2;
  • 89
  • 90     for (i = 0; i < 6; i++)
  • 91     {
  • 92         GPIO_ResetBits(GPIOB, HT1621_WR);
  • 93         //delay_us(10);
  • 94         if ((Abyte >> (7 - i)) & 0x01)
  • 95         {
  • 96             GPIO_SetBits(GPIOB, HT1621_DATA);
  • 97         }
  • 98         else
  • 99         {
  • 100             GPIO_ResetBits(GPIOB, HT1621_DATA);
  • 101         }
  • 102         delay_us(10);
  • 103         GPIO_SetBits(GPIOB, HT1621_WR);
  • 104         delay_us(10);
  • 105     }
  • 106     
  • 107 }
  • 108
  • 109 /*
  • 110 *    LCD 数据写入函数
  • 111 *    入口:Dbyte,数据
  • 112 *    出口:void
  • 113 */
  • 114 void write_data_8bit(unsigned char Dbyte)
  • 115 {
  • 116     int i = 0;
  • 117
  • 118     for (i = 0; i < 8; i++)
  • 119     {
  • 120         GPIO_ResetBits(GPIOB, HT1621_WR);
  • 121         delay_us(10);
  • 122         if ((Dbyte >> (7 - i)) & 0x01)
  • 123         {
  • 124             GPIO_SetBits(GPIOB, HT1621_DATA);
  • 125         }
  • 126         else
  • 127         {
  • 128             GPIO_ResetBits(GPIOB, HT1621_DATA);
  • 129         }
  • 130         delay_us(10);
  • 131         GPIO_SetBits(GPIOB, HT1621_WR);
  • 132         delay_us(10);
  • 133     }
  • 134 }
  • 135
  • 136 void write_data_4bit(unsigned char Dbyte)
  • 137 {
  • 138     int i = 0;
  • 139
  • 140     for (i = 0; i < 4; i++)
  • 141     {
  • 142         GPIO_ResetBits(GPIOB, HT1621_WR);
  • 143         //delay_us(10);
  • 144         if ((Dbyte >> (3 - i)) & 0x01)
  • 145         {
  • 146             GPIO_SetBits(GPIOB, HT1621_DATA);
  • 147         }
  • 148         else
  • 149         {
  • 150             GPIO_ResetBits(GPIOB, HT1621_DATA);
  • 151         }
  • 152         delay_us(10);
  • 153         GPIO_SetBits(GPIOB, HT1621_WR);
  • 154         delay_us(10);
  • 155     }
  • 156 }
  • 157
  • 158
  • 159
  • 160 //1621初始化
  • 161 void ht1621_init(void)
  • 162 {
  • 163         GPIO_InitTypeDef GPIO_InitStructure;// declare the structure
  • 164         GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
  • 165
  • 166         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);
  • 167         memset(&GPIO_InitStructure, 0, sizeof(GPIO_InitTypeDef));
  • 168         GPIO_InitStructure.GPIO_Pin =  HT1621_WR | HT1621_DATA ;//| HT1621_IRQ
  • 169         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  • 170         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  • 171         GPIO_Init(GPIOB, &GPIO_InitStructure);
  • 172
  • 173         memset(&GPIO_InitStructure, 0, sizeof(GPIO_InitTypeDef));
  • 174         GPIO_InitStructure.GPIO_Pin = HT1621_CS ;//| HT1621_IRQ
  • 175         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  • 176         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  • 177         GPIO_Init(GPIOA, &GPIO_InitStructure);
  • 178
  • 179 }
  • 180
  • 181 /*
  • 182 *    LCD 初始化,对lcd自身做初始化设置
  • 183 *    入口:void
  • 184 *    出口:void
  • 185 */
  • 186 void lcd_init(void)
  • 187 {
  • 188     //
  • 189     GPIO_SetBits(GPIOA, HT1621_CS);
  • 190     GPIO_SetBits(GPIOB, HT1621_WR);
  • 191     GPIO_SetBits(GPIOB, HT1621_DATA);
  • 192     for (ii=0;ii<10000;ii++)
  • 193     {for(j=10;j>0;j--);}
  • 194     //        
  • 195     GPIO_ResetBits(GPIOA, HT1621_CS);        //CS = 0;
  • 196     //delay_us(10);
  • 197     for (ii=0;ii<10000;ii++)
  • 198     {for(j=10;j>0;j--);}
  • 199     write_mode(COMMAND);    //命令模式
  • 200     write_command(0x01);    //Enable System
  • 201     write_command(0x03);    //Enable Bias
  • 202     write_command(0x04);    //Disable Timer
  • 203     write_command(0x05);    //Disable WDT
  • 204     write_command(0x08);    //Tone OFF
  • 205     write_command(0x18);    //on-chip RC震荡
  • 206     write_command(0x29);    //1/4Duty 1/3Bias
  • 207     write_command(0x80);    //Disable IRQ
  • 208     write_command(0x40);    //Tone Frequency 4kHZ
  • 209     write_command(0xE3);    //Normal Mode
  • 210
  • 211     GPIO_SetBits(GPIOA, HT1621_CS);  //CS = 1;
  • 212 }
  • 213
  • 214 /*
  • 215 *    LCD 清屏函数
  • 216 *    入口:void
  • 217 *    出口:void
  • 218 */
  • 219 void lcd_clr(void)
  • 220 {
  • 221     write_addr_dat_n(0x0, 0x00, 32);//15
  • 222 }
  • 223 //用于温度区域写数据
  • 224 void write_addr_dat_n_wendu(unsigned char _addr, unsigned char _dat, unsigned char n)
  • 225 {
  • 226     
  • 227     unsigned char i = 0;
  • 228     unsigned char _dat_temp1,_dat_temp2;
  • 229     
  • 230     //WriteLcdram(_addr, _dat);
  • 231         
  • 232     
  • 233
  • 234     GPIO_ResetBits(GPIOA, HT1621_CS);                                // CS = 0;
  • 235     write_mode(DAT);
  • 236     
  • 237     if(Lcdram[_addr]==0x00)
  • 238     {
  • 239         WriteLcdram(_addr, _dat);
  • 240     }
  • 241         if((_addr%2)==0)
  • 242         {
  • 243             _dat_temp1=Lcdram[_addr];
  • 244             _dat_temp2=(_dat_temp1&0x08)|_dat;
  • 245            
  • 246             write_address(_addr);
  • 247             for (i = 0; i < n; i++)
  • 248         {
  • 249             write_data_4bit(_dat_temp2);
  • 250         }
  • 251         GPIO_SetBits(GPIOA, HT1621_CS);                                    //CS = 1;
  • 252            
  • 253         }
  • 254         else if((_addr%2)!=0)
  • 255         {
  • 256             write_address(_addr);
  • 257             for (i = 0; i < n; i++)
  • 258         {
  • 259             write_data_4bit(_dat);
  • 260         }
  • 261         GPIO_SetBits(GPIOA, HT1621_CS);
  • 262         }
  • 263         
  • 264         WriteLcdram(_addr, _dat_temp2);
  • 265 }
  • 266
  • 267 //用于湿度区域写数据
  • 268 void write_addr_dat_n_shidu(unsigned char _addr, unsigned char _dat, unsigned char n)
  • 269 {
  • 270     
  • 271     unsigned char i = 0;
  • 272     unsigned char _dat_temp1,_dat_temp2;
  • 273     
  • 274     //WriteLcdram(_addr, _dat);
  • 275         
  • 276     
  • 277
  • 278     GPIO_ResetBits(GPIOA, HT1621_CS);                                // CS = 0;
  • 279     write_mode(DAT);
  • 280     
  • 281     if(Lcdram[_addr]==0x00)
  • 282     {
  • 283         WriteLcdram(_addr, _dat);
  • 284     }
  • 285         if((_addr%2)==0)
  • 286         {
  • 287             _dat_temp1=Lcdram[_addr];
  • 288             _dat_temp2=(_dat_temp1&0x01)|_dat;
  • 289            
  • 290             write_address(_addr);
  • 291             for (i = 0; i < n; i++)
  • 292         {
  • 293             write_data_4bit(_dat_temp2);
  • 294         }
  • 295         GPIO_SetBits(GPIOA, HT1621_CS);                                    //CS = 1;
  • 296            
  • 297         }
  • 298         else if((_addr%2)!=0)
  • 299         {
  • 300             write_address(_addr);
  • 301             for (i = 0; i < n; i++)
  • 302         {
  • 303             write_data_4bit(_dat);
  • 304         }
  • 305         GPIO_SetBits(GPIOA, HT1621_CS);
  • 306         }
  • 307         
  • 308         WriteLcdram(_addr, _dat_temp2);
  • 309 }
  • 310
  • 311
  • 312 //用于底部数字写数据
  • 313 void write_addr_dat_n_others(unsigned char _addr, unsigned char _dat, unsigned char n)
  • 314 {
  • 315     
  • 316     unsigned char i = 0;
  • 317     unsigned char _dat_temp1,_dat_temp2;
  • 318     GPIO_ResetBits(GPIOA, HT1621_CS);                                // CS = 0;
  • 319     write_mode(DAT);
  • 320     
  • 321     if(Lcdram[_addr]==0x00)
  • 322     {
  • 323         WriteLcdram(_addr, _dat);
  • 324         
  • 325     }
  • 326         if((_addr%2)==0)
  • 327         {
  • 328             _dat_temp1=Lcdram[_addr];
  • 329             _dat_temp2=(_dat_temp1&0x01)|_dat;
  • 330            
  • 331             write_address(_addr);
  • 332             for (i = 0; i < n; i++)
  • 333         {
  • 334             write_data_4bit(_dat_temp2);
  • 335         }
  • 336         GPIO_SetBits(GPIOA, HT1621_CS);                                    //CS = 1;
  • 337            
  • 338         }
  • 339         else if((_addr%2)!=0)
  • 340         {
  • 341             write_address(_addr);
  • 342             for (i = 0; i < n; i++)
  • 343         {
  • 344             write_data_4bit(_dat);
  • 345         }
  • 346         GPIO_SetBits(GPIOA, HT1621_CS);
  • 347         }
  • 348         
  • 349         //WriteLcdram(_addr, _dat);
  • 350         WriteLcdram(_addr, _dat_temp2);
  • 351 }
  • 352
  • 353 //用于字符写数据
  • 354 void write_addr_dat_n_char(unsigned char _addr, unsigned char _dat, unsigned char state)
  • 355 {
  • 356     
  • 357     unsigned char i = 0;
  • 358     unsigned char _dat_temp1,_dat_temp2;
  • 359     
  • 360
  • 361         GPIO_ResetBits(GPIOA, HT1621_CS);                                // CS = 0;
  • 362          write_mode(DAT);
  • 363            
  • 364                 _dat_temp1=Lcdram[_addr];
  • 365             if(state==1)
  • 366             {
  • 367                 
  • 368                 _dat_temp2=(_dat_temp1|_dat);
  • 369             }
  • 370             else if(state==0)
  • 371             {
  • 372                 _dat_temp2=(_dat_temp1&(~_dat));
  • 373             }
  • 374                  write_address(_addr);
  • 375            
  • 376                 for (i = 0; i < 1; i++)
  • 377             {
  • 378                 write_data_4bit(_dat_temp2);
  • 379             }
  • 380             GPIO_SetBits(GPIOA, HT1621_CS);                                    //CS = 1;
  • 381             WriteLcdram(_addr, _dat_temp2);
  • 382         
  • 383         
  • 384         
  • 385     
  • 386 }
  • 387 //显示温度
  • 388 //入口:pos,显示位置,地址0、2、4分别为从右到左的三个数字
  • 389 //            num:要显示的一位数
  • 390 void Display_Wendu_1(unsigned char add, unsigned char num )
  • 391 {
  • 392     unsigned char n,i,j;
  • 393     n=getChr_Wendu(num);
  • 394     i=(n&0xF0)>>4;
  • 395     j=n&0x0F;
  • 396     write_addr_dat_n_wendu(add,i,1);
  • 397     write_addr_dat_n_wendu(add+1,j,1);
  • 398     
  • 399 }
  • 400
  • 401
  • 402 //温度数据转换,lcd.c内部使用
  • 403  unsigned char getChr_Wendu(unsigned char c)
  • 404  {
  • 405      unsigned char i;
  • 406         for ( i = 0; i < 10; ++i)
  • 407         {
  • 408             if (c == i)
  • 409             {
  • 410                 return Wendu[i];
  • 411             }
  • 412         }
  • 413     }
  • 414
  • 415 //更新lcdram数组
  • 416 void WriteLcdram(unsigned char add, unsigned char data)
  • 417 {
  • 418     
  • 419     Lcdram[add]=data;
  • 420     
  • 421 }
  • 复制代码