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

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、程序

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

程序的参考步骤:①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 }

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

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

原文地址:https://www.cnblogs.com/lemonzhang/p/9239172.html

时间: 2024-08-23 23:17:28

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

二级域名原理以及程序代码

二级域名原理以及程序代码 TYPE:经典代码片段 TIME:2002-7-30 AUTHOR:扬子 URL:N/A HIT:51  DAYHIT:1  WEEKHIT:1 要达到二级名的效果,必须一下条件以及流程: 1.必须有一个顶级域名,而且此域名必须做好泛解析并做好指向. 2.必须有一台独立的服务器.泛解析的域名指向该服务器. 3.在服务器上的IIS建一个空的主机头名的web站点. 4.将默认的页面设置为你的二机解析程序(比如:freedns.asp) 5.二级域名系列程序(包括申请页:sh

驱动原理(应用程序访问驱动程序)

以read为例: read是一个系统调用,系统调用之前在应用程序当中(或者叫用户空间当中),read的实现代码在内核中,read是如何找到内核的实现代码呢? /********************************************* *filename:read_mem.c ********************************************/ #include <stdio.h> #include <sys/types.h> #include

[转载]步进电机原理介绍与基于STM32的SPWM驱动步进电机,使用软件实现电机细分

文章摘自: http://bbs.eeworld.com.cn/thread-370591-1-1.html 一.混合式步进电机的结构和驱动原理 电机原理这部分不想讲的太复杂了,拆开一台电机看看就明白了.      电机的转子是一个永磁体, 它的上面有若干个磁极SN组成,这些磁极固定的摆放成一定角度.电机的定子是几个串联的线圈构成的磁体. 出线一般是四条线标记为A+,A-,B+,B-.A相与B相是不通的,用万用表很容易区分出来,至于各相的+-出线实际是不用考虑的,任意一相正负对调电机将反转.另外

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

六.温湿度传感器DHT11驱动封装(下):如何为编程爱好者设计一款好玩的智能硬件(六)——初尝试·把温湿度给收集了(下)! 七.点阵字符型液晶显示模块LCD1602驱动封装(上):如何为编程爱好者设计一款好玩的智能硬件(七)——LCD1602点阵字符型液晶显示模块驱动封装(上) 八.LCD1602点阵字符型液晶显示模块驱动封装(中) 已经有好一阵子没写了,一方面是因为最近闲杂的事特多,另一方面(主要方面)是因为我卡在了LCD1602驱动的权衡上面——总共3个控制线和一个8位并行的数据线,放在51

STM32 USB转串口驱动移植到SylixOS中遇到的问题总结

1. 简介         由于客户项目需求,需要在STM32的硬件平台上实现USB转串口的功能,由于ST公司基于STM32硬件平台实现了相应的USB库以方便开发者进行开发,因此,在SylixOS下实现USB转串口功能时对该USB库进行了移植.由于该USB库的实现是基于STM32的裸机代码实现,因此在移植的过程中,不需要做过多的修改.         下面章节主要介绍在移植STM32的USB转串口驱动到SylixOS下遇到的问题以及对应的解决方法.对于其中的有些解决方法在移植STM32其他外设驱

驱动相关的内核代码分析

arch\arm\include\asm\Io.h #define __raw_readl(a) (__chk_io_ptr(a), *(volatile unsigned int __force   *)(a)) #define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force   *)(a) = (v)) 注:(volatile unsigned int __force   *)指针强制转换为unsigne

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

实验平台:win7,VS2010 先上结果截图: 文章最后附有生成该图的程序. 1. 刚体模拟原理 Bullet作为一个物理引擎,其任务就是刚体模拟(还有可变形体模拟).刚体模拟,就是要计算预测物体的运动,举个例子,我抛一块砖头,砖头砸在地上翻了几圈最后停下来,刚体模拟就是要用计算机把这一切虚拟化(给定砖头形状质量等属性及砖头初始运动状态,还要给定地面的信息,预测砖头未来任意时刻状态). 刚体模拟的主要理论基础是牛顿力学(高中物理水平).可以想见,如果刚体之间没有碰撞,刚体模拟很简单,就是自由落

编写高质量JAVA程序代码的建议

--------------------------------------------------------------------------------------------------- 前言:原著<改善JAVA程序的151个建议>有151个建议,我在拜读的过程根据自己的理解合并了其中的几个,并将每个建议的核心要义进行了一次纯手工提炼,以方便想阅读这本书的同行能够更快的掌握这本书的所有核心内容. -------------------------------------------

程序代码阅读技巧

一.代码阅读的必要性 阅读别人的代码作为研发人员是一件经常要做的事情.一个是学习新的编程语言的时候通过阅读别人的代码是个最佳的学习方法,另外是积累编程经验.如果你有机 会阅读一些操作系统的代码会帮助你理解一些基本的原理.更有就是在你作为一个质量确保人员或一个小领导的时候如果你要做白盒测试的时候没有阅读代码的能力 是不能完成相应的任务.最后一个就是如果你中途接手一个项目的时候或给一个项目做售后服务的时候是要有阅读代码的能力的. 二.收集所有可能收集的材料 阅读代码要做的第一件事情是收集所有和项目相