lcmdrv.c
上传用户:zfj3589
上传日期:2022-07-13
资源大小:635k
文件大小:12k
源码类别:

微处理器开发

开发平台:

C/C++

  1. /****************************************************************************
  2. * 文件名:LCMDRV.C
  3. * 功能:MG12864图形液晶模块驱动程序。使用LPC2131的GPIO口控制操作。
  4. *       用于ZLG/GUI用户图形界面。
  5. * 液晶模块与LPC2131的连接如下所示:
  6. * D0 (7) -- P0.4
  7. * . -- .
  8. * . -- .
  9. * . -- .
  10. * D7 (14) -- P0.11
  11. *
  12. *   CS1 -- P0.12
  13. * CS2 -- P0.13
  14. *
  15. *   RST     --      P0.14
  16. * D/I -- P0.15
  17. * R/W -- GND
  18. * E -- P0.16
  19. *
  20. *  R/W为0进行写操作,为1时进行读操作;
  21. *  D/I为1表示数据传送, 为0表示命令传送;
  22. *  E读写脉冲;
  23. *  CS1和CS2为左右半屏选择,高电平选中;
  24. *  RST为复位控制,低电平复位。
  25. *  
  26. *  作者:黄绍斌
  27. *  日期:2005/3/7
  28. ****************************************************************************/
  29. #include "config.h"
  30. /* 定义显示缓冲区 */
  31. TCOLOR  gui_disp_buf[GUI_LCM_YMAX/8][GUI_LCM_XMAX];
  32. /* 定义总线起始的GPIO,即D0对应的GPIO值(P0.4) */
  33. #define  BUS_NO 4
  34. /* 输出总线数据宏定义 */
  35. #define  OutData(dat) IO0CLR = 0xFF<<BUS_NO; IO0SET = (dat&0xff)<<BUS_NO
  36. /* 定义CS1控制 */
  37. #define  LCM_CS1 12
  38. #define  SCS1() IO0SET = 1<<LCM_CS1
  39. #define  CCS1() IO0CLR = 1<<LCM_CS1
  40. /* 定义CS2控制 */
  41. #define  LCM_CS2 13
  42. #define  SCS2() IO0SET = 1<<LCM_CS2
  43. #define  CCS2() IO0CLR = 1<<LCM_CS2
  44. /* 定义RST控制 */
  45. #define  LCM_RST 14
  46. #define  SRST() IO0SET = 1<<LCM_RST
  47. #define  CRST() IO0CLR = 1<<LCM_RST
  48. /* 定义DI控制 */
  49. #define  LCM_DI 15
  50. #define  SDI() IO0SET = 1<<LCM_DI
  51. #define  CDI() IO0CLR = 1<<LCM_DI
  52. /* 定义E控制 */
  53. #define  LCM_E 16
  54. #define  SE() IO0SET = 1<<LCM_E
  55. #define  CE() IO0CLR = 1<<LCM_E
  56. /* 定义LCM操作的命令字 */
  57. #define LCM_DISPON 0x3f /* 打开LCM显示 */
  58. #define LCM_STARTROW 0xc0 /* 显示起始行0,可以用LCM_STARTROW+x设置起始行。(x<64)  */
  59. #define LCM_ADDRSTRX 0xb8 /* 页起始地址,可以用LCM_ADDRSTRX+x设置当前页(即X)。(x<8) */
  60. #define LCM_ADDRSTRY 0x40 /* 列起始地址,可以用LCM_ADDRSTRY+x设置当前列(即Y)。(x<64) */
  61. /*********************************************************************************
  62. * 名称:DELAY5()
  63. * 功能:软件延时函数。用于LCM显示输出时序控制。
  64. * 入口参数:无
  65. * 出口参数:无
  66. **********************************************************************************/
  67. void DELAY5(void)
  68. { int i;
  69.   for(i=0; i<100; i++);
  70. }
  71. /***********************************************************************
  72. * 名称:LCM_WrCommand()
  73. * 功能:写命令子程序
  74. * 入口参数:command   要写入LCM的命令字
  75. * 注:数据口为P0口(作IO口)
  76. ***********************************************************************/
  77. void LCM_WrCommand(uint8 command) 
  78. { CE(); // 先将E置为低
  79.   CDI(); // DI=0,表示发送命令
  80.           
  81.   OutData(command);           
  82.   DELAY5();     
  83.   SE();
  84.   DELAY5();     
  85.   CE();
  86.   DELAY5();     
  87. }
  88. /***********************************************************************
  89. * 名称:LCM_WrData()
  90. * 功能:写数据子程序
  91. * 入口参数:wrdata   要写入LCM的数据
  92. ***********************************************************************/
  93. void LCM_WrData(uint8 wrdata) 
  94. { CE(); // 先将E置为低
  95.   SDI(); // DI=1,表示发送数据
  96.           
  97.   OutData(wrdata);       
  98.   DELAY5();     
  99.   SE();
  100.   DELAY5();     
  101.   CE();     
  102.   DELAY5();             
  103. }
  104. /***********************************************************************
  105. * 名称:LCM_WriteByte()
  106. * 功能:向指定点写数据(一字节)。
  107. * 入口参数:x  x坐标值(0-127)
  108. *      y       y坐标值(0-63)
  109. *           wrdata 所要写的数据
  110. * 说明:会重新设置CS1/CS2,及其内部指针
  111. ***********************************************************************/
  112. void LCM_WriteByte(uint8 x, uint8 y, uint8 wrdata) 
  113. { x = x&0x7f; // 参数过滤
  114.   y = y&0x3f;
  115.   CCS1();
  116.   CCS2();
  117.   
  118.   //更新显示缓冲区
  119.   y = y>>3;
  120.   gui_disp_buf[y][x] = wrdata;
  121.    
  122.   // 更新LCD显示
  123.   if(x<64) // 选择液晶控制芯片(即CS1--控制前64个点,CS2--控制后64个点)
  124.   { SCS1();  
  125.   }
  126.   else
  127.   { SCS2();
  128.     x = x-64;
  129.   }
  130.   LCM_WrCommand(LCM_ADDRSTRY+x); // 设置当前列地址,即x坐标
  131.   LCM_WrCommand(LCM_ADDRSTRX+y); // 设置当前页地址,即y坐标
  132.   LCM_WrData(wrdata);
  133. }
  134. /***********************************************************************
  135. * 名称:LCM_ReadByte()
  136. * 功能:读取指定点上的数据。
  137. * 入口参数:x    x坐标值(0-127)
  138. *         y     y坐标值(0-63)
  139. * 出口参数:返回该点上的字节数据。
  140. ***********************************************************************/
  141. uint8  LCM_ReadByte(uint8 x, uint8 y)
  142. { x = x&0x7f; // 参数过滤
  143.   y = y&0x3f;
  144.   y = y>>3;
  145.   return(gui_disp_buf[y][x]);
  146. }
  147. /////////////////////////////////////////////////////////////////////////
  148. /***********************************************************************
  149. * 名称:LCM_DispFill()
  150. * 功能:向显示缓冲区填充数据
  151. * 入口参数:filldata   要写入LCM的填充数据
  152. * 注:此函数会设置显示起始行为0,且会自动选中CS1有效
  153. ***********************************************************************/
  154. void LCM_DispFill(uint8 filldata)
  155. { uint8  x,y;
  156.   SCS1(); // 选中两个控制芯片
  157.   SCS2();
  158.   LCM_WrCommand(LCM_STARTROW); // 设置显示起始行为0
  159.   for(x=0; x<8; x++)
  160.   { LCM_WrCommand(LCM_ADDRSTRX+x); // 设置页地址,即X
  161.    LCM_WrCommand(LCM_ADDRSTRY); // 设置列地址,即Y
  162.     for(y=0; y<64; y++)
  163.     { LCM_WrData(filldata);
  164. }
  165.   }
  166.   CCS2();
  167. }
  168.     
  169. /***********************************************************************
  170. * 名称:LCM_DispIni()
  171. * 功能:LCM显示初始化
  172. * 入口参数:无
  173. * 出口参数:无
  174. * 注:初化显示后,清屏并设置显示起始行为0
  175. *     会复位LCM_DISPCX,LCM_DISPCY.(并会只选中CS1)
  176. ***********************************************************************/
  177. void LCM_DispIni(void)
  178. { uint32  i;
  179.     // 设置引脚连接模块
  180. #if LCM_CS1 < 16
  181.     PINSEL0 &= ~(3 << (2 * LCM_CS1));
  182. #else
  183.     PINSEL1 &= ~(3 << (2 * (LCM_CS1 - 16)));
  184. #endif
  185. #if LCM_CS2 < 16
  186.     PINSEL0 &= ~(3 << (2 * LCM_CS2));
  187. #else
  188.     PINSEL1 &= ~(3 << (2 * (LCM_CS2 - 16)));
  189. #endif
  190. #if LCM_DI < 16
  191.     PINSEL0 &= ~(3 << (2 * LCM_DI));
  192. #else
  193.     PINSEL1 &= ~(3 << (2 * (LCM_DI - 16)));
  194. #endif
  195. #if LCM_RST < 16
  196.     PINSEL0 &= ~(3 << (2 * LCM_RST));
  197. #else
  198.     PINSEL1 &= ~(3 << (2 * (LCM_RST - 16)));
  199. #endif
  200. #if LCM_E < 16
  201.     PINSEL0 &= ~(3 << (2 * LCM_E));
  202. #else
  203.     PINSEL1 &= ~(3 << (2 * (LCM_E - 16)));
  204. #endif
  205. #if  BUS_NO<9
  206.     for (i = BUS_NO; i < BUS_NO+8; i++)
  207.     {
  208.         PINSEL0 &= ~(3 << (2 * i));
  209.     }
  210. #else
  211.     for (i = BUS_NO; i < 16; i++)
  212.     {
  213.         PINSEL0 &= ~(3 << (2 * i));
  214.     }
  215.     
  216.     for (; i < (BUS_NO+8); i++)
  217.     {
  218.         PINSEL1 &= ~(3 << (2 * (i-16)));
  219.     }
  220. #endif    
  221.   // 设置I/O为输出方式
  222.   IO0DIR = IO0DIR|(1<<LCM_CS1)|(1<<LCM_CS2)|(1<<LCM_DI)|(1<<LCM_RST)|(1<<LCM_E);
  223.   IO0DIR = IO0DIR|(0xFF<<BUS_NO);
  224.   
  225.   // 复位LCM
  226.   CRST();
  227.   for(i=0; i<5000; i++);
  228.   SRST();   
  229.   for(i=0; i<5000; i++); 
  230.   SCS1(); // 选中两个控制芯片
  231.   SCS2();  
  232.   LCM_WrCommand(LCM_DISPON); // 打开显示
  233.   LCM_WrCommand(LCM_STARTROW); // 设置显示起始行为0
  234.         
  235.   LCM_WrCommand(LCM_ADDRSTRX); // 设置页地址,即X
  236.   LCM_WrCommand(LCM_ADDRSTRY); // 设置列地址,即Y
  237. }
  238. /////////////////////////////////////////////////////////////////////////////
  239. /****************************************************************************
  240. * 名称:GUI_FillSCR()
  241. * 功能:全屏填充。直接使用数据填充显示缓冲区。
  242. * 入口参数:dat 填充的数据
  243. * 出口参数:无
  244. * 说明:用户根据LCM的实际情况编写此函数。
  245. ****************************************************************************/
  246. void  GUI_FillSCR(TCOLOR dat)
  247. {  uint32 i,j;
  248.   
  249.    // 填充缓冲区
  250.    for(i=0; i<(GUI_LCM_YMAX/8); i++)
  251.    {  for(j=0; j<GUI_LCM_XMAX; j++)
  252.       {  gui_disp_buf[i][j] = dat;
  253.       }
  254.    }
  255.    
  256.    // 填充LCM
  257.    LCM_DispFill(dat);
  258. }
  259. /****************************************************************************
  260. * 名称:GUI_Initialize()
  261. * 功能:初始化GUI,包括初始化显示缓冲区,初始化LCM并清屏。
  262. * 入口参数:无
  263. * 出口参数:无
  264. * 说明:用户根据LCM的实际情况编写此函数。
  265. ****************************************************************************/
  266. void  GUI_Initialize(void)
  267. {  LCM_DispIni(); // 初始化LCM模块工作模式,纯图形模式
  268.    GUI_FillSCR(0x00); // 初始化缓冲区为0x00,并输出屏幕(清屏)
  269. }
  270. uint8 const  DEC_HEX_TAB[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
  271. /****************************************************************************
  272. * 名称:GUI_Point()
  273. * 功能:在指定位置上画点。
  274. * 入口参数:x 指定点所在列的位置
  275. *           y 指定点所在行的位置
  276. *           color 显示颜色(对于黑白色LCM,为0时灭,为1时显示)
  277. * 出口参数:返回值为1时表示操作成功,为0时表示操作失败。
  278. * 说明:操作失败原因是指定地址超出缓冲区范围。
  279. ****************************************************************************/
  280. uint8  GUI_Point(uint8 x, uint8 y, TCOLOR color)
  281. {  uint8   bak;
  282.    
  283.    // 参数过滤 
  284.    if(x>=GUI_LCM_XMAX) return(0);
  285.    if(y>=GUI_LCM_YMAX) return(0);
  286.    
  287.    // 设置相应的点为1或0 
  288.    bak = LCM_ReadByte(x,y);
  289.    if(0==color)
  290.    {  bak &= (~DEC_HEX_TAB[y&0x07]);
  291.    }
  292.    else
  293.    {  bak |= DEC_HEX_TAB[y&0x07];
  294.    }
  295.   
  296.    // 刷新显示 
  297.    LCM_WriteByte(x, y, bak);
  298.    return(1);
  299. }
  300. /****************************************************************************
  301. * 名称:GUI_ReadPoint()
  302. * 功能:读取指定点的颜色。
  303. * 入口参数:x 指定点所在列的位置
  304. *           y 指定点所在行的位置
  305. *           ret     保存颜色值的指针
  306. * 出口参数:返回0表示指定地址超出缓冲区范围
  307. * 说明:对于单色,设置ret的d0位为1或0,4级灰度则为d0、d1有效,8位RGB则d0--d7有效,
  308. *      RGB结构则R、G、B变量有效。
  309. ****************************************************************************/
  310. uint8  GUI_ReadPoint(uint8 x, uint8 y, TCOLOR *ret)
  311. {  uint8  bak;
  312.    // 参数过滤
  313.    if(x>=GUI_LCM_XMAX) return(0);
  314.    if(y>=GUI_LCM_YMAX) return(0);
  315.   
  316.    bak = LCM_ReadByte(x,y);
  317.    if( (bak & (DEC_HEX_TAB[y&0x07])) == 0 ) *ret = 0x00;
  318.      else  *ret = 0x01;
  319.    
  320.    return(1);
  321. }
  322. /****************************************************************************
  323. * 名称:GUI_HLine()
  324. * 功能:画水平线。
  325. * 入口参数:x0 水平线起点所在列的位置
  326. *           y0 水平线起点所在行的位置
  327. *           x1      水平线终点所在列的位置
  328. *           color 显示颜色(对于黑白色LCM,为0时灭,为1时显示)
  329. * 出口参数:无
  330. * 说明:操作失败原因是指定地址超出缓冲区范围。
  331. ****************************************************************************/
  332. void  GUI_HLine(uint8 x0, uint8 y0, uint8 x1, TCOLOR color) 
  333. {  uint8  bak;
  334.    if(x0>x1)  // 对x0、x1大小进行排列,以便画图
  335.    {  bak = x1;
  336.       x1 = x0;
  337.       x0 = bak;
  338.    }
  339.    
  340.    do
  341.    {  GUI_Point(x0, y0, color); // 逐点显示,描出垂直线
  342.       x0++;
  343.    }while(x1>=x0);
  344. }
  345. /***********************************************************************
  346. * 名称:GUI_RLine()
  347. * 功能:画竖直线。根据硬件特点,实现加速。
  348. * 入口参数:x0 垂直线起点所在列的位置
  349. *           y0 垂直线起点所在行的位置
  350. *           y1      垂直线终点所在行的位置
  351. *           color 显示颜色(对于黑白色LCM,为0时灭,为1时显示)
  352. * 出口参数: 无
  353. * 说明:操作失败原因是指定地址超出缓冲区范围。
  354. ***********************************************************************/
  355. void  GUI_RLine(uint8 x0, uint8 y0, uint8 y1, TCOLOR color) 
  356. {  uint8  bak;
  357.    uint8  wr_dat;
  358.   
  359.    if(y0>y1)  // 对y0、y1大小进行排列,以便画图
  360.    {  bak = y1;
  361.       y1 = y0;
  362.       y0 = bak;
  363.    }
  364.    
  365.    do
  366.    {  // 先读取当前点的字节数据
  367.       bak = LCM_ReadByte(x0,y0);
  368.       
  369.       // 进行'与'/'或'操作后,将正确的数据写回LCM
  370.       // 若y0和y1不是同一字节,则y0--当前字节结束,即(y0+8)&0x38,全写1,或者0。
  371.       // 若y0和y1是同一字节,则y0--y1,要全写1,或者0。
  372.       // 方法:dat=0xff,然后按y0清零dat低位,按y1清零高位。
  373.       if((y0>>3) != (y1>>3)) // 竖直线是否跨越两个字节(或以上)
  374.       {  wr_dat = 0xFF << (y0&0x07);// 清0低位
  375.       
  376.          if(color)
  377.          {  wr_dat = bak | wr_dat; // 若color不为0,则显示
  378.          }
  379.          else
  380.          {  wr_dat = ~wr_dat; // 若color为0,则清除显示
  381.             wr_dat = bak & wr_dat;
  382.          }
  383.          LCM_WriteByte(x0,y0, wr_dat);
  384.          y0 = (y0+8)&0x38;
  385.       }
  386.       else
  387.       {  wr_dat = 0xFF << (y0&0x07);
  388.          wr_dat = wr_dat &  ( 0xFF >> (7-(y1&0x07)) );
  389.               
  390.          if(color)
  391.          {  wr_dat = bak | wr_dat; // 若color不为0,则显示
  392.          }
  393.          else
  394.          {  wr_dat = ~wr_dat; // 若color为0,则清除显示
  395.             wr_dat = bak & wr_dat;
  396.          }
  397.          LCM_WriteByte(x0,y0, wr_dat);
  398.          return;
  399.       } // end of if((y0>>3) != (y1>>3))... else...
  400.    }while(y1>=y0);
  401. }