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 * 出口: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 }

当轩不是怜苍翠,只要人知耐岁寒。

转载需说明出处,笔者总结之前的知识,与大家分享,有问题的可以留给我哦~

STM32液晶显示HT1621驱动原理及程序代码的更多相关文章

  1. Windows 驱动加载程序代码

    #include <windows.h> #include <winsvc.h> #include <conio.h> #include <stdio.h&g ...

  2. 分享STM32 FLASH 擦除(以及防止误擦除程序代码)、写入

    编译环境:我用的是(Keil)MDK4.7.2   stm32库版本:我用的是3.5.0一.本文不对FLASH的基础知识做详细的介绍,不懂得地方请查阅有关资料. 对STM32 内部FLASH进行编程操 ...

  3. 如何为编程爱好者设计一款好玩的智能硬件(九)——LCD1602点阵字符型液晶显示模块驱动封装(下)

    六.温湿度传感器DHT11驱动封装(下):如何为编程爱好者设计一款好玩的智能硬件(六)——初尝试·把温湿度给收集了(下)! 七.点阵字符型液晶显示模块LCD1602驱动封装(上):如何为编程爱好者设计 ...

  4. 如何为编程爱好者设计一款好玩的智能硬件(八)——LCD1602点阵字符型液晶显示模块驱动封装(中)

    六.温湿度传感器DHT11驱动封装(下):如何为编程爱好者设计一款好玩的智能硬件(六)——初尝试·把温湿度给收集了(下)! 七.点阵字符型液晶显示模块LCD1602驱动封装(上):如何为编程爱好者设计 ...

  5. C++学习笔记1(Windows程序运行原理及程序编写流程)

    窗口产生过程,句柄原理,消息队列,回调函数,窗口关闭与应用程序退出的工作关系,使用VC++的若干小技巧,stdcall与Lessonecl调用规范的比较,初学者常犯错误及注意事项.以下是应用程序与操作 ...

  6. 编译原理-词法分析04-NFA & 代码实现

    编译原理-词法分析04-NFA & 代码实现 0.术语 NFA 非确定性有穷自动机nondeterministic finite automation. ε-转换ε-transition 是无 ...

  7. Bullet核心类介绍(Bullet 2.82 HelloWorld程序及其详解,附程序代码)

    实验平台:win7,VS2010 先上结果截图: 文章最后附有生成该图的程序. 1. 刚体模拟原理 Bullet作为一个物理引擎,其任务就是刚体模拟(还有可变形体模拟).刚体模拟,就是要计算预测物体的 ...

  8. ANTLR4权威指南 - 第7章 通过特定应用程序代码解耦语法

    第7章 通过特定应用程序代码解耦语法 到目前为止,我们已经知道了怎么用ANTLR的语法来定义语言了,接下来我们要给我们的语法注入一些新的元素了.就语法本身而言,其用处并不大,因为它只能告诉我们一个用户 ...

  9. [转帖]Docker五种存储驱动原理及应用场景和性能测试对比

    Docker五种存储驱动原理及应用场景和性能测试对比 来源:http://dockone.io/article/1513 作者: 陈爱珍 布道师@七牛云   Docker最开始采用AUFS作为文件系统 ...

随机推荐

  1. linux创建磁盘阵例10

    Linux创建RAID10 生产环境中用到的服务器一般都配备RAID阵列卡,尽管服务器的价格越来越便宜,但是我们没有必要为了做一个实验而去单独购买一台服务器,而是可以学会使用mdadm命令在Linux ...

  2. Java 18 新特性:使用Java代码启动jwebserver

    前几天分享了Java 18 新特性:简单Web服务器的jwebserver命令行功能. 今天换一种方式,使用Java代码来实现一个静态资源服务器. 详细步骤我录了个视频放到B站了,感兴趣的小伙伴可以点 ...

  3. Django学习——分组查询、图书管理系统项目、wsgi, uwsgi, cgi, fastcgi

    1 分组查询 # 分组查询 # 查询每一个出版社id,以及图书平均价格(单表) # 原生sql # select publish_id,avg(price) from app01_book group ...

  4. hashib加密模块、logging模块

    hashib加密模块 # 加密模块 1.什么是加密 将明文的数据通过一些手段变成能密文数据 密文数据的表现形式一般都是一串没有规则的字符串 2.加密算法 加密算法有很多>>>(讲文明 ...

  5. 程序包 applets.user.service.UserService 不存在-2022新项目

    一.问题由来 接上一篇文章使用maven进行打包时报中文乱码错误,经过多次尝试后最终解决问题,显示出真正的错误信息如下: 程序包 applets.user.service.UserService 不存 ...

  6. scanf("%d",a[i]+j)为什么不加取地址符号

    为什么我画的地方不加取地址符号? 不要在意标题为什么不加分号,因为长度太长了! 二维数组a[3][5]中,a[3]储存的是下一维的地址,a[1]等同于&a[1][0] 同理,a[1]+1等于& ...

  7. Git技法:.gitignore、移除暂存与撤销修改

    1. .gitignore常见项目添加 1.1 .gitignore模板 .gitignore针对每个语言都有对应的模板,在GitHub创建项目时就可以选择(你可以在GitHub提供的.gitigno ...

  8. 【摸鱼神器】一次搞定 vue3的 路由 + 菜单 + tabs

    做一个管理后台,首先要设置路由,然后配置菜单(有时候还需要导航),再来一个动态tabs,最后加上权限判断. 这个是不是有点繁琐?尤其是路由的设置和菜单的配置,是不是很雷同?那么能不能简单一点呢?如果可 ...

  9. 第06组 Beta冲刺 (5/5)

    目录 1.1 基本情况 1.2 冲刺概况汇报 1.郝雷明 2. 方梓涵 3.曾丽莉 4.黄少丹 5. 董翔云 6.鲍凌函 7.杜筱 8.詹鑫冰 9.曹兰英 10.吴沅静 1.3 冲刺成果展示 1.1 ...

  10. [USACO2021DEC] HILO 踩标做法

    [USACO2021DEC] HILO Solution 参考自 官方题解 里提到的一篇 Obliteration.pdf,但是里面作者写出了极多错误...然后式子还错错得对了. 令 \(y=n-x\ ...