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

[复制链接]
 楼主| 734774645 发表于 2018-12-5 22:30 | 显示全部楼层 |阅读模式
1、HT1621电路分析
      HT1621为32×4即128点内存映像LCD驱动器,包含内嵌的32×4位显示RAM内存和时基发生器以及WDT看门狗定时器.
      HT1621驱动电路如下图所示:
1070495-20180627225051691-2038770537.jpg
图1
1070495-20180627225150876-1500656912.jpg
          与单片机相连接控制的有9脚CS,3脚WR,12脚DATA,其功能描述如下表。
1070495-20180627225513986-195694438.jpg
图2

 楼主| 734774645 发表于 2018-12-5 22:30 | 显示全部楼层
2、字符显示原理
         液晶管点亮和熄灭原理分别为在对应的RAM地址中写1和写0.首先需要清楚所驱动控制的液晶的COM-SEG对应关系,然后需要了解HT1621的32×4RAM地址映射。
         例如要控制的液晶的装脚成品图部分如下:
1070495-20180628101719637-1218396171.jpg
图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.jpg
图4
         搞清楚我们要控制的对象之后那,  HT1621的RAM 地址映射如下图所示:
1070495-20180628103613524-643933794.jpg
图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.jpg
图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、程序
      主要的程序编写流程如下:
1070495-20180628152647965-1330687251.jpg
图7
            程序的参考步骤:
①Display_Wendu_1
②write_addr_dat_n_wendu
③write_mode
④write_address
⑤write_data_4bit,
其中Lcdram数组为建立的虚拟数组。

 楼主| 734774645 发表于 2018-12-5 22:32 | 显示全部楼层
  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. const unsigned char Wendu[] = //温度0-9
  9.     {   
  10.     0X5F, 0X50, 0X3D, 0X79, 0X72, 0X6B, 0X6F, 0X51, 0X7F, 0X7B
  11.     };
  12. ///////////////////////////////////////////////////驱动函数
  13. /*
  14. *    LCD 模式写入
  15. *    入口:MODE :COM(命令模式) DAT(数据模式)
  16. *    出口:void
  17. */
  18. void write_mode(unsigned char MODE)    //写入模式,数据or命令
  19. {
  20.     GPIO_ResetBits(GPIOB, HT1621_WR);                                //    RW = 0;
  21.     delay_us(10);
  22.     GPIO_SetBits(GPIOB, HT1621_DATA);                                    //    DA = 1;
  23.     GPIO_SetBits(GPIOB, HT1621_WR);                                    //    RW = 1;
  24.     delay_us(10);

  25.     GPIO_ResetBits(GPIOB, HT1621_WR);                                //    RW = 0;
  26.     delay_us(10);
  27.     GPIO_ResetBits(GPIOB, HT1621_DATA);                                //    DA = 0;
  28.     GPIO_SetBits(GPIOB, HT1621_WR);                                    //    RW = 1;
  29.     delay_us(10);

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

  32.     if (0 == MODE)
  33.     {
  34.         GPIO_ResetBits(GPIOB, HT1621_DATA);                            //    DA = 0;
  35.     }
  36.     else
  37.     {
  38.         GPIO_SetBits(GPIOB, HT1621_DATA);                                //    DA = 1;
  39.     }
  40.     delay_us(10);
  41.     GPIO_SetBits(GPIOB, HT1621_WR);                                    //    RW = 1;
  42.     delay_us(10);
  43. }

  44. /*
  45. *    LCD 命令写入函数
  46. *    入口:cbyte ,控制命令字
  47. *    出口:void
  48. */
  49. void write_command(unsigned char Cbyte)
  50. {
  51.     unsigned char i = 0;

  52.     for (i = 0; i < 8; i++)
  53.     {
  54.         GPIO_ResetBits(GPIOB, HT1621_WR);
  55.         if ((Cbyte >> (7 - i)) & 0x01)
  56.         {
  57.             GPIO_SetBits(GPIOB, HT1621_DATA);
  58.         }
  59.         else
  60.         {
  61.             GPIO_ResetBits(GPIOB, HT1621_DATA);
  62.         }
  63.         delay_us(10);
  64.         GPIO_SetBits(GPIOB, HT1621_WR);
  65.         delay_us(10);
  66.     }
  67.     GPIO_ResetBits(GPIOB, HT1621_WR);
  68.     delay_us(10);
  69.     GPIO_ResetBits(GPIOB, HT1621_DATA);
  70.     GPIO_SetBits(GPIOB, HT1621_WR);
  71.     delay_us(10);
  72. }

  73. /*
  74. *    LCD 地址写入函数
  75. *    入口:cbyte,地址
  76. *    出口:void
  77. */
  78. void write_address(unsigned char Abyte)
  79. {
  80.     unsigned char i = 0;
  81.     Abyte = Abyte << 2;

  82.     for (i = 0; i < 6; i++)
  83.     {
  84.         GPIO_ResetBits(GPIOB, HT1621_WR);
  85.         //delay_us(10);
  86.         if ((Abyte >> (7 - i)) & 0x01)
  87.         {
  88.             GPIO_SetBits(GPIOB, HT1621_DATA);
  89.         }
  90.         else
  91.         {
  92.             GPIO_ResetBits(GPIOB, HT1621_DATA);
  93.         }
  94.         delay_us(10);
  95.         GPIO_SetBits(GPIOB, HT1621_WR);
  96.         delay_us(10);
  97.     }
  98.    
  99. }

  100. /*
  101. *    LCD 数据写入函数
  102. *    入口:Dbyte,数据
  103. *    出口:void
  104. */
  105. void write_data_8bit(unsigned char Dbyte)
  106. {
  107.     int i = 0;

  108.     for (i = 0; i < 8; i++)
  109.     {
  110.         GPIO_ResetBits(GPIOB, HT1621_WR);
  111.         delay_us(10);
  112.         if ((Dbyte >> (7 - i)) & 0x01)
  113.         {
  114.             GPIO_SetBits(GPIOB, HT1621_DATA);
  115.         }
  116.         else
  117.         {
  118.             GPIO_ResetBits(GPIOB, HT1621_DATA);
  119.         }
  120.         delay_us(10);
  121.         GPIO_SetBits(GPIOB, HT1621_WR);
  122.         delay_us(10);
  123.     }
  124. }

  125. void write_data_4bit(unsigned char Dbyte)
  126. {
  127.     int i = 0;

  128.     for (i = 0; i < 4; i++)
  129.     {
  130.         GPIO_ResetBits(GPIOB, HT1621_WR);
  131.         //delay_us(10);
  132.         if ((Dbyte >> (3 - i)) & 0x01)
  133.         {
  134.             GPIO_SetBits(GPIOB, HT1621_DATA);
  135.         }
  136.         else
  137.         {
  138.             GPIO_ResetBits(GPIOB, HT1621_DATA);
  139.         }
  140.         delay_us(10);
  141.         GPIO_SetBits(GPIOB, HT1621_WR);
  142.         delay_us(10);
  143.     }
  144. }



  145. //1621初始化
  146. void ht1621_init(void)
  147. {
  148.         GPIO_InitTypeDef GPIO_InitStructure;// declare the structure
  149.         GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

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

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

  161. }

  162. /*
  163. *    LCD 初始化,对lcd自身做初始化设置
  164. *    入口:void
  165. *    出口:void
  166. */
  167. void lcd_init(void)
  168. {
  169.     //////////////////////////////////////////////////////
  170.     GPIO_SetBits(GPIOA, HT1621_CS);
  171.     GPIO_SetBits(GPIOB, HT1621_WR);
  172.     GPIO_SetBits(GPIOB, HT1621_DATA);
  173.     for (ii=0;ii<10000;ii++)
  174.     {for(j=10;j>0;j--);}
  175.     //////////////////////////////////////////////////////        
  176.     GPIO_ResetBits(GPIOA, HT1621_CS);        //CS = 0;
  177.     //delay_us(10);
  178.     for (ii=0;ii<10000;ii++)
  179.     {for(j=10;j>0;j--);}
  180.     write_mode(COMMAND);    //命令模式
  181.     write_command(0x01);    //Enable System
  182.     write_command(0x03);    //Enable Bias
  183.     write_command(0x04);    //Disable Timer
  184.     write_command(0x05);    //Disable WDT
  185.     write_command(0x08);    //Tone OFF
  186.     write_command(0x18);    //on-chip RC震荡
  187.     write_command(0x29);    //1/4Duty 1/3Bias
  188.     write_command(0x80);    //Disable IRQ
  189.     write_command(0x40);    //Tone Frequency 4kHZ
  190.     write_command(0xE3);    //Normal Mode

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

  193. /*
  194. *    LCD 清屏函数
  195. *    入口:void
  196. *    出口:void
  197. */
  198. void lcd_clr(void)
  199. {
  200.     write_addr_dat_n(0x0, 0x00, 32);//15
  201. }
  202. //用于温度区域写数据
  203. void write_addr_dat_n_wendu(unsigned char _addr, unsigned char _dat, unsigned char n)
  204. {
  205.    
  206.     unsigned char i = 0;
  207.     unsigned char _dat_temp1,_dat_temp2;
  208.    
  209.     //WriteLcdram(_addr, _dat);
  210.         
  211.    

  212.     GPIO_ResetBits(GPIOA, HT1621_CS);                                // CS = 0;
  213.     write_mode(DAT);
  214.    
  215.     if(Lcdram[_addr]==0x00)
  216.     {
  217.         WriteLcdram(_addr, _dat);
  218.     }
  219.         if((_addr%2)==0)
  220.         {
  221.             _dat_temp1=Lcdram[_addr];
  222.             _dat_temp2=(_dat_temp1&0x08)|_dat;
  223.             
  224.             write_address(_addr);
  225.             for (i = 0; i < n; i++)
  226.         {
  227.             write_data_4bit(_dat_temp2);
  228.         }
  229.         GPIO_SetBits(GPIOA, HT1621_CS);                                    //CS = 1;
  230.             
  231.         }
  232.         else if((_addr%2)!=0)
  233.         {
  234.             write_address(_addr);
  235.             for (i = 0; i < n; i++)
  236.         {
  237.             write_data_4bit(_dat);
  238.         }
  239.         GPIO_SetBits(GPIOA, HT1621_CS);
  240.         }
  241.         
  242.         WriteLcdram(_addr, _dat_temp2);
  243. }

  244. //用于湿度区域写数据
  245. void write_addr_dat_n_shidu(unsigned char _addr, unsigned char _dat, unsigned char n)
  246. {
  247.    
  248.     unsigned char i = 0;
  249.     unsigned char _dat_temp1,_dat_temp2;
  250.    
  251.     //WriteLcdram(_addr, _dat);
  252.         
  253.    

  254.     GPIO_ResetBits(GPIOA, HT1621_CS);                                // CS = 0;
  255.     write_mode(DAT);
  256.    
  257.     if(Lcdram[_addr]==0x00)
  258.     {
  259.         WriteLcdram(_addr, _dat);
  260.     }
  261.         if((_addr%2)==0)
  262.         {
  263.             _dat_temp1=Lcdram[_addr];
  264.             _dat_temp2=(_dat_temp1&0x01)|_dat;
  265.             
  266.             write_address(_addr);
  267.             for (i = 0; i < n; i++)
  268.         {
  269.             write_data_4bit(_dat_temp2);
  270.         }
  271.         GPIO_SetBits(GPIOA, HT1621_CS);                                    //CS = 1;
  272.             
  273.         }
  274.         else if((_addr%2)!=0)
  275.         {
  276.             write_address(_addr);
  277.             for (i = 0; i < n; i++)
  278.         {
  279.             write_data_4bit(_dat);
  280.         }
  281.         GPIO_SetBits(GPIOA, HT1621_CS);
  282.         }
  283.         
  284.         WriteLcdram(_addr, _dat_temp2);
  285. }


  286. //用于底部数字写数据
  287. void write_addr_dat_n_others(unsigned char _addr, unsigned char _dat, unsigned char n)
  288. {
  289.    
  290.     unsigned char i = 0;
  291.     unsigned char _dat_temp1,_dat_temp2;
  292.     GPIO_ResetBits(GPIOA, HT1621_CS);                                // CS = 0;
  293.     write_mode(DAT);
  294.    
  295.     if(Lcdram[_addr]==0x00)
  296.     {
  297.         WriteLcdram(_addr, _dat);
  298.         
  299.     }
  300.         if((_addr%2)==0)
  301.         {
  302.             _dat_temp1=Lcdram[_addr];
  303.             _dat_temp2=(_dat_temp1&0x01)|_dat;
  304.             
  305.             write_address(_addr);
  306.             for (i = 0; i < n; i++)
  307.         {
  308.             write_data_4bit(_dat_temp2);
  309.         }
  310.         GPIO_SetBits(GPIOA, HT1621_CS);                                    //CS = 1;
  311.             
  312.         }
  313.         else if((_addr%2)!=0)
  314.         {
  315.             write_address(_addr);
  316.             for (i = 0; i < n; i++)
  317.         {
  318.             write_data_4bit(_dat);
  319.         }
  320.         GPIO_SetBits(GPIOA, HT1621_CS);
  321.         }
  322.         
  323.         //WriteLcdram(_addr, _dat);
  324.         WriteLcdram(_addr, _dat_temp2);
  325. }

  326. //用于字符写数据
  327. void write_addr_dat_n_char(unsigned char _addr, unsigned char _dat, unsigned char state)
  328. {
  329.    
  330.     unsigned char i = 0;
  331.     unsigned char _dat_temp1,_dat_temp2;
  332.    

  333.         GPIO_ResetBits(GPIOA, HT1621_CS);                                // CS = 0;
  334.          write_mode(DAT);
  335.             
  336.                 _dat_temp1=Lcdram[_addr];
  337.             if(state==1)
  338.             {
  339.                
  340.                 _dat_temp2=(_dat_temp1|_dat);
  341.             }
  342.             else if(state==0)
  343.             {
  344.                 _dat_temp2=(_dat_temp1&(~_dat));
  345.             }
  346.                  write_address(_addr);
  347.             
  348.                 for (i = 0; i < 1; i++)
  349.             {
  350.                 write_data_4bit(_dat_temp2);
  351.             }
  352.             GPIO_SetBits(GPIOA, HT1621_CS);                                    //CS = 1;
  353.             WriteLcdram(_addr, _dat_temp2);
  354.         
  355.         
  356.         
  357.    
  358. }
  359. //显示温度
  360. //入口:pos,显示位置,地址0、2、4分别为从右到左的三个数字
  361. //            num:要显示的一位数
  362. void Display_Wendu_1(unsigned char add, unsigned char num )
  363. {
  364.     unsigned char n,i,j;
  365.     n=getChr_Wendu(num);
  366.     i=(n&0xF0)>>4;
  367.     j=n&0x0F;
  368.     write_addr_dat_n_wendu(add,i,1);
  369.     write_addr_dat_n_wendu(add+1,j,1);
  370.    
  371. }


  372. //温度数据转换,lcd.c内部使用
  373. unsigned char getChr_Wendu(unsigned char c)
  374. {
  375.      unsigned char i;
  376.         for ( i = 0; i < 10; ++i)
  377.         {
  378.             if (c == i)
  379.             {
  380.                 return Wendu[i];
  381.             }
  382.         }
  383.     }

  384. //更新lcdram数组
  385. void WriteLcdram(unsigned char add, unsigned char data)
  386. {
  387.    
  388.     Lcdram[add]=data;
  389.    
  390. }
磨砂 发表于 2018-12-7 13:55 | 显示全部楼层
非常感谢楼主分享啊
晓伍 发表于 2018-12-7 13:59 | 显示全部楼层
分析的好详细啊
八层楼 发表于 2018-12-7 14:03 | 显示全部楼层
源码写的很清晰
haihua151 发表于 2019-3-27 10:46 | 显示全部楼层
gdgn_0526345 发表于 2019-6-3 16:29 | 显示全部楼层
本帖最后由 gdgn_0526345 于 2019-6-3 16:32 编辑

HT1621_WR     HT1621_DATA   COMMAND 之类的宏定义应用  如果贴出来就好了
joyshen102 发表于 2019-10-17 11:53 | 显示全部楼层
原帖写的新详细啊
您需要登录后才可以回帖 登录 | 注册

本版积分规则

210

主题

3585

帖子

15

粉丝
快速回复 在线客服 返回列表 返回顶部

210

主题

3585

帖子

15

粉丝
快速回复 在线客服 返回列表 返回顶部