本帖最后由 SnailWillow 于 2021-3-15 17:12 编辑
1、HT1621电路分析
HT1621为32×4即128点内存映像LCD驱动器,包含内嵌的32×4位显示RAM内存和时基发生器以及WDT看门狗定时器.
HT1621驱动电路如下图所示:
图1
与单片机相连接控制的有9脚CS,3脚WR,12脚DATA,其功能描述如下表。
图2
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
3、显示的保持
写数据过程需要保证写前无关位数据的保持,因此在单片机程序中开辟32×4数组作为虚拟ARM,存储写前LCD显示数据.通过与清零,或置位操作实现,例如6位地址Address当前显示的数据为Data_last .若Xi(i=0,1,2,3) 位需要保持,则Xi为1,否则Xi为0.写入的数据为Data_now,变换公式为:
4、程序
主要的程序编写流程如下:
图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 * 出口:void113 */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 else127 {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 else149 {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_IRQ169 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_IRQ175 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 * 入口:void184 * 出口:void185 */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 System201 write_command(0x03); //Enable Bias202 write_command(0x04); //Disable Timer203 write_command(0x05); //Disable WDT204 write_command(0x08); //Tone OFF205 write_command(0x18); //on-chip RC震荡206 write_command(0x29); //1/4Duty 1/3Bias207 write_command(0x80); //Disable IRQ208 write_command(0x40); //Tone Frequency 4kHZ209 write_command(0xE3); //Normal Mode210 211 GPIO_SetBits(GPIOA, HT1621_CS); //CS = 1;212 }213 214 /*215 * LCD 清屏函数216 * 入口:void217 * 出口:void218 */219 void lcd_clr(void)220 {221 write_addr_dat_n(0x0, 0x00, 32);//15222 }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 }复制代码