极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 35112|回复: 16

Arduino+LCD1602自定义新字体

[复制链接]
发表于 2012-8-24 14:23:17 | 显示全部楼层 |阅读模式
本帖最后由 freevector 于 2012-8-24 14:23 编辑

阿古坊所做的TCA1602S液晶屏时钟+串口校时(http://aguegu.net/?p=1009)中使用了其自己定义的一种大字体很是漂亮,但其在github上的源代码很高深,我尝试在Arduino上运行,可惜没能成功,同时阿古的内功异常高深,我功底低微,几次想看懂其代码都差点受内伤,最后我毅然放弃了,尝试自己写一个较为简单的库,先看效果:

其实现的基本思想就是利用LCD1602的CGRAM自定义几个基本模块,然后在显示具体字符时再将其具体的字符划分为若干模块,依次显示即可。例如在style 4中就定义了如下几个基本模块:

每个字符设置为横向15个像素,纵向为16个像素。从左到右从上到下进行组合,那么数字5一共由6个模块组成。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2012-8-24 14:47:41 | 显示全部楼层
想法不错,顶起!
回复 支持 反对

使用道具 举报

发表于 2012-8-24 17:43:36 | 显示全部楼层
求github上的源代码,想学习一下,效果很炫的说!赞一个!!!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-24 21:05:17 | 显示全部楼层
但丁 发表于 2012-8-24 17:43
求github上的源代码,想学习一下,效果很炫的说!赞一个!!!

https://github.com/aguegu/dot-matrix此代码我认为很高深,我基本看不下去,几次想在Arduino上跑,可跑不起来,好像RAM区不够,所以我干脆还是自己写了自己的代码,估计原理应该一样...........
回复 支持 反对

使用道具 举报

发表于 2012-8-24 21:10:03 | 显示全部楼层
freevector 发表于 2012-8-24 21:05
https://github.com/aguegu/dot-matrix此代码我认为很高深,我基本看不下去,几次想在Arduino上跑,可跑不 ...

嗯,你是用lcd库写的代码吗?之前折腾了一下,发现用库写这个效果还是可以的
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-24 21:12:20 | 显示全部楼层
我的Arduino核心部分的代码如下,这是我这个暑假在DFRobot实习期间最后一周所写的库,是基于LCD1602_4Bit.h改写的,大家可以根据自己的taste改写不同的字体,但有点遗憾的是LCD1602的CGRAM只能写8个字节,所以不够我发挥啊!
  1. /*
  2. This code is based on LCD4Bit v0.1   16/oct/2006 neilzero
  3. IDE  Arduino 1.0 or 1.01
  4. Usage:
  5. we have write a new font for LCD1602(HD44780) in this code.
  6. see the examples folder of this library distribution.
  7. */
  8. #include "FONT.h"
  9. #include "LCD4Bit_mod.h"
  10. #include  <Arduino.h>

  11. //command bytes for LCD
  12. #define CMD_CLR 0x01
  13. #define CMD_RIGHT 0x1C
  14. #define CMD_LEFT 0x18
  15. #define CMD_HOME 0x02

  16. // --------- PINS -------------------------------------
  17. //is the RW pin of the LCD under our control?  If we're only ever going to write to the LCD, we can use one less microcontroller pin, and just tie the LCD pin to the necessary signal, high or low.
  18. //this stops us sending signals to the RW pin if it isn't being used.
  19. int USING_RW = false;

  20. //RS, RW and Enable can be set to whatever you like
  21. int RS = 8;
  22. int RW = 11;
  23. int Enable = 9;
  24. //DB should be an unseparated group of pins  - because of lazy coding in pushNibble()
  25. int DB[] = {4, 5, 6, 7};  //wire these to DB4~7 on LCD.

  26. //--------------------------------------------------------

  27. //how many lines has the LCD? (don't change here - specify on calling constructor)
  28. int g_num_lines = 2;
  29. //pulse the Enable pin high (for a microsecond).
  30. //This clocks whatever command or data is in DB4~7 into the LCD controller.
  31. void LCD4Bit_mod::pulseEnablePin()
  32. {
  33.   digitalWrite(Enable,LOW);
  34.   delayMicroseconds(1);
  35.   // send a pulse to enable
  36.   digitalWrite(Enable,HIGH);
  37.   delayMicroseconds(1);
  38.   digitalWrite(Enable,LOW);
  39.   delay(1);  // pause 1 ms.  TODO: what delay, if any, is necessary here?
  40. }

  41. //push a nibble of data through the the LCD's DB4~7 pins, clocking with the Enable pin.
  42. //We don't care what RS and RW are, here.
  43. void LCD4Bit_mod::pushNibble(int value)
  44. {
  45.   int val_nibble= value & 0x0F;  //clean the value.  (unnecessary)

  46.   for (int i=DB[0]; i <= DB[3]; i++) {
  47.     digitalWrite(i,val_nibble & 01);
  48.     val_nibble >>= 1;
  49.   }
  50.   pulseEnablePin();
  51. }

  52. //push a byte of data through the LCD's DB4~7 pins, in two steps, clocking each with the enable pin.
  53. void LCD4Bit_mod::pushByte(int value)
  54. {
  55.   int val_lower = value & 0x0F;
  56.   int val_upper = value >> 4;
  57.   pushNibble(val_upper);
  58.   pushNibble(val_lower);
  59. }

  60. LCD4Bit_mod::LCD4Bit_mod (int num_lines)
  61. {
  62.   g_num_lines = num_lines;
  63.   if (g_num_lines < 1 || g_num_lines > 2)
  64.   {
  65.     g_num_lines = 1;
  66.   }
  67. }

  68. void LCD4Bit_mod::commandWriteNibble(int nibble)
  69. {
  70.   digitalWrite(RS, LOW);
  71.   if (USING_RW) { digitalWrite(RW, LOW); }
  72.   pushNibble(nibble);
  73. }


  74. void LCD4Bit_mod::commandWrite(int value)
  75. {
  76.   digitalWrite(RS, LOW);
  77.   if (USING_RW) { digitalWrite(RW, LOW); }
  78.   pushByte(value);
  79.   //TODO: perhaps better to add a delay after EVERY command, here.  many need a delay, apparently.
  80. }


  81. //print the given character at the current cursor position. overwrites, doesn't insert.
  82. void LCD4Bit_mod::print(int value)
  83. {
  84.   //set the RS and RW pins to show we're writing data
  85.   digitalWrite(RS, HIGH);
  86.   if (USING_RW) { digitalWrite(RW, LOW); }

  87.   //let pushByte worry about the intricacies of Enable, nibble order.
  88.   pushByte(value);
  89. }


  90. //print the given string to the LCD at the current cursor position.  overwrites, doesn't insert.
  91. //While I don't understand why this was named printIn (PRINT IN?) in the original LiquidCrystal library, I've preserved it here to maintain the interchangeability of the two libraries.
  92. void LCD4Bit_mod::printIn(char msg[])
  93. {
  94.   uint8_t i;  //fancy int.  avoids compiler warning when comparing i with strlen()'s uint8_t
  95.   for (i=0;i < strlen(msg);i++){
  96.     print(msg[i]);
  97.   }
  98. }


  99. //send the clear screen command to the LCD
  100. void LCD4Bit_mod::clear()
  101. {
  102.   commandWrite(CMD_CLR);
  103.   delay(1);
  104. }


  105. // initiatize lcd after a short pause
  106. //while there are hard-coded details here of lines, cursor and blink settings, you can override these original settings after calling .init()
  107. void LCD4Bit_mod::init ()
  108. {
  109.   pinMode(Enable,OUTPUT);
  110.   pinMode(RS,OUTPUT);
  111.   if (USING_RW) { pinMode(RW,OUTPUT); }
  112.   pinMode(DB[0],OUTPUT);
  113.   pinMode(DB[1],OUTPUT);
  114.   pinMode(DB[2],OUTPUT);
  115.   pinMode(DB[3],OUTPUT);
  116.   delay(50);
  117.   //The first 4 nibbles and timings are not in my DEM16217 SYH datasheet, but apparently are HD44780 standard...
  118.   commandWriteNibble(0x03);
  119.   delay(5);
  120.   commandWriteNibble(0x03);
  121.   delayMicroseconds(100);
  122.   commandWriteNibble(0x03);
  123.   delay(5);
  124.   // needed by the LCDs controller
  125.   //this being 2 sets up 4-bit mode.
  126.   commandWriteNibble(0x02);
  127.   commandWriteNibble(0x02);
  128.   //todo: make configurable by the user of this library.
  129.   //NFXX where
  130.   //N = num lines (0=1 line or 1=2 lines).
  131.   //F= format (number of dots (0=5x7 or 1=5x10)).
  132.   //X=don't care

  133.   int num_lines_ptn = g_num_lines - 1 << 3;
  134.   int dot_format_ptn = 0x00;      //5x7 dots.  0x04 is 5x10

  135.   commandWriteNibble(num_lines_ptn | dot_format_ptn);
  136.   delayMicroseconds(60);
  137.   commandWrite(0x0C);
  138.   delayMicroseconds(60);
  139.   commandWrite(0x01);//clear display
  140.   delay(3);
  141.   commandWrite(0x06);
  142. //write basic segments to CGRAM
  143.    for(int i=0x40;i<0x80;i++)
  144.   {
  145.     commandWrite(i);
  146.     print(FONT_SEGMENT[i-0x40]);
  147.     delay(5);  
  148.   }
  149.     delay(1);//TODO: remove unnecessary delays
  150. }

  151. void LCD4Bit_mod::LCD_SET_XY( int x, int y )  //the command of setting Cursor
  152. {
  153.   int address;
  154.   if (y ==0) address = 0x80 + x;             //01 000 000    D5D4D3 is the character's place; D2D1D0
  155.   else address = 0xc0 + x;
  156.   commandWrite(address);
  157. }  

  158. //scroll whole display to left
  159. void LCD4Bit_mod::leftScroll(int num_chars, int delay_time)
  160. {
  161.   for (int i=0; i<num_chars; i++) {
  162.     commandWrite(CMD_LEFT);
  163.     delay(delay_time);
  164.   }
  165. }
  166. void LCD4Bit_mod::PrintSelfDefine(int x,int num)// the program of displaying self-define char
  167. {
  168.         if(num!=12)
  169.         {
  170.                 for(int j=0;j<3;j++)    // 3 is the width of char, if you wanna use font1 in the directory, you can change it to 1
  171.                 {
  172.                         int index0=num*3;
  173.                         int temp=FONT_CODE[index0+j];
  174.                         LCD_SET_XY(x+j,0);
  175.                         print((temp&0xf0)>>4);
  176.                         LCD_SET_XY(x+j,1);
  177.                         print(temp&0x0f);
  178.                 }
  179.         }
  180.   /*        if(num==12)     // using this part to display a LOGO designed by me ,just for fun.
  181.         {
  182.                 for(int j=0;j<6;j++)
  183.                 {
  184.                         int index0=num*3;
  185.                         int temp=FONT_CODE[index0+j];
  186.                         LCD_SET_XY(x+j,0);
  187.                         print((temp&0xf0)>>4);
  188.                         LCD_SET_XY(x+j,1);
  189.                         print(temp&0x0f);
  190.                 }
  191.         }
  192.         */
  193. }
  194. //print sel-design string.
  195. void LCD4Bit_mod::printString(int x,char msg[])
  196. {
  197.         uint8_t i;
  198.         for (i=0;i < strlen(msg);i++)
  199.         {
  200.                 PrintSelfDefine(x+3*i,msg[i]-'0');
  201.         }
  202. }
复制代码
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-24 21:13:11 | 显示全部楼层
FONT部分的代码如下:
  1. int FONT_SEGMENT[]=
  2. {  //you can change the segments according your taste,here we have given 3 styles for example.  
  3.   // 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//segment 0
  4.   // 0x15,0x15,0x00,0x00,0x00,0x00,0x00,0x00,//segment 1
  5.    //0x00,0x00,0x00,0x15,0x15,0x00,0x00,0x00,//segment 2
  6.   // 0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x15,//segment 3
  7. //  0x15,0x15,0x00,0x00,0x00,0x00,0x15,0x15,//segment 4
  8. //  0x15,0x15,0x00,0x15,0x15,0x00,0x15,0x15,//segment 5

  9.    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//segment 0
  10.    0x1B,0x1B,0x00,0x00,0x00,0x00,0x00,0x00,//segment 1
  11.    0x00,0x00,0x00,0x1B,0x1B,0x00,0x00,0x00,//segment 2
  12.    0x00,0x00,0x00,0x00,0x00,0x00,0x1b,0x1b,//segment 3
  13.    0x1b,0x1b,0x00,0x00,0x00,0x00,0x1b,0x1b,//segment 4
  14.    0x1b,0x1b,0x00,0x1b,0x1b,0x00,0x1b,0x1b,//segment 5

  15. //  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//segment 0
  16. //  0x1f,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,//segment 1
  17. //  0x00,0x00,0x00,0x1f,0x1f,0x00,0x00,0x00,//segment 2
  18. //  0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x1f,//segment 3
  19. //  0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,//segment 4
  20. //  0xff,0xff,0x00,0xff,0xff,0x00,0xff,0xff,//segment 5
  21.    0x1b,0x1,0x1b,0x1b,0x00,0x00,0x00,0x00,//segment 6
  22.    0x00,0x00,0x00,0x00,0x1b,0x1b,0x1b,0x1b //segment 7
  23. };
  24. int FONT_CODE[]=
  25. {
  26.   0x55,0x13,0x55,//0
  27.   0x00,0x55,0x00,//1
  28.   0x45,0x43,0x53,//2
  29.   0x43,0x43,0x55,//3
  30.   0x51,0x01,0x55,//4
  31.   0x54,0x14,0x15,//5
  32.   0x55,0x14,0x15,//6
  33.   0x10,0x10,0x55,//7
  34.   0x55,0x43,0x55,//8
  35.   0x53,0x43,0x55,//9
  36.   0x00,0x22,0x00,//:
  37.   0x00,0x00,0x00, //space

  38.   0x71,0x56,0x75,0x56,0x71//LOGO
  39. };

复制代码
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-24 21:15:37 | 显示全部楼层
本帖最后由 freevector 于 2012-8-24 21:21 编辑

另外为了大家更好的了解如何根据该库自定义自己的字符,可以根据下面我写的Instruction来定义自己的字符或字体:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-24 21:26:19 | 显示全部楼层
再来一个example:
  1. #include <LCD4Bit_mod.h>
  2. LCD4Bit_mod lcd = LCD4Bit_mod(2); // 2 is the number of rows, the value could be 1 or 2
  3. void setup()
  4. {
  5.   lcd.init();
  6.   delay(450);
  7.   lcd.clear();
  8. }
  9. int count=0;
  10. void loop()
  11. {
  12.    // lcd.printString(0,"15:49");
  13.    int temp0=(count/100);
  14.    int temp1=(count%100)/10;
  15.    int temp2=(count%100)%10;
  16.    lcd.PrintSelfDefine(0,temp0);// 0 is the loca1tion of temp0 in screen
  17.    lcd.PrintSelfDefine(4,temp1);// PrintSelfDefine is the function of printing the number in self-designed font
  18.    lcd.PrintSelfDefine(8,temp2);
  19.    delay(1000);
  20.    count++;
  21. }
复制代码
回复 支持 反对

使用道具 举报

发表于 2012-8-24 22:24:47 | 显示全部楼层
谢谢楼主指点!!
偶用lcd库尝试了一下,效果如下:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

发表于 2012-8-24 22:50:30 | 显示全部楼层
木有,那个真心难,偶还是个Arduino入门者,这两天正好一直在捣鼓1602,所以看到你的帖子就直接试了....偶用的方法比较弱,你可以看看官网的这个链接就明白了http://arduino.cc/en/Reference/LiquidCrystalCreateChar
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-24 22:53:23 | 显示全部楼层
但丁 发表于 2012-8-24 22:50
木有,那个真心难,偶还是个Arduino入门者,这两天正好一直在捣鼓1602,所以看到你的帖子就直接试了....偶用 ...

额,我要被鄙视了......我居然没发现这个函数..........................
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-26 11:02:37 | 显示全部楼层
大家还可以尝试为12564写一个这样的库。
回复 支持 反对

使用道具 举报

发表于 2012-11-2 11:06:03 | 显示全部楼层
我前段时间也用1602自己写了几个日语平假名字符,使用的是5*8的,定义字模的数组长度如果为8,即使最后一位为0x00,最下面那一行也会显示一点东西,,如果字模的长度定义为9个的话,最后一个为0x00,则可以正常显示,求解释。
回复 支持 反对

使用道具 举报

发表于 2013-3-8 12:54:23 来自手机 | 显示全部楼层
新手想驱动LCD1602如何办?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-5-18 14:43 , Processed in 0.042223 second(s), 22 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表