51下外部总线结构的小计算器(C和一部分汇编参考)

来源:互联网 发布:政府数据共享开放目录 编辑:程序博客网 时间:2024/06/06 08:27

 好久好久没有写博客了~唉~最近弄得东西都是实物没什么研究可写,全部就是调试啊调试啊~还是写一点东西吧。

最近做了一个基于51外部扩展RAM的小计算器。

 

 这是仿真SAMPLE的图

用的是标准的总线结构,锁存器用的74L373,RAM用的是6264,液晶是1602,使能用74LS00来选择。最后用7407作为了

驱动。

本来他们公司给的代码说的是C51,实际上核心的确是C,不过LCD和键盘用的都是汇编。由于正在略微研究下外部扩展就拿来做出来顺便把代码都改成C的。LCD的驱动完全是总线结构,根据硬件连接来写代码。下面把LCD的代码汇编和C都放上来

我把前面汇编的注释掉了~

[cpp] view plaincopy
  1.          /****************************************************************************** 
  2. ************                LABCENTER ELECTRONICS                   ************                               
  3. ************             Proteus VSM Sample Design Code             ************             
  4. ************            Integer Calculator ( 2K Code Limit)         ************ 
  5. ********************************************************************************/  
  6. /*汇编 
  7. NAME    LCD 
  8.  
  9. ;Set up Code Segment and exports: 
  10.  
  11. LCD              SEGMENT CODE 
  12. RSEG             LCD 
  13.  
  14.                  PUBLIC  _output 
  15.                  PUBLIC  initialise 
  16.                  PUBLIC  clearscreen 
  17.  
  18.  
  19. ;LCD Register Addresses. 
  20. LCD_CMD_WR  equ     00h 
  21. LCD_DATA_WR equ 01h 
  22. LCD_BUSY_RD equ 02h 
  23. LCD_DATA_RD equ 03h 
  24. LCD_PAGE    equ 80h 
  25.  
  26. ;LCD Commands 
  27. LCD_CLS     equ 1 
  28. LCD_HOME    equ 2 
  29. LCD_SETMODE equ 4 
  30. LCD_SETVISIBLE  equ 8 
  31. LCD_SHIFT   equ 16 
  32. LCD_SETFUNCTION equ 32 
  33. LCD_SETCGADDR   equ 64 
  34. LCD_SETDDADDR   equ 128 
  35.  
  36.  
  37.  
  38.  
  39. ; Initialisation Routine for the LCD display. 
  40. initialise:     mov A,#030h         ;1 line, 8 bits 
  41.         call wrcmd 
  42.         mov A,#LCD_SETVISIBLE + 4 
  43.         call wrcmd 
  44.         mov A,#LCD_SETDDADDR+15     ; Start at right hand side of the display 
  45.         call wrcmd 
  46.         mov A,#LCD_SETMODE + 3      ; Automatic Increment - Display shift left.   
  47.         call wrcmd 
  48.                 ret 
  49.  
  50. ; We move the parameter (held in R7) into the Accumulator prior to writing it. 
  51. _output:    mov A,R7     
  52.         call wrdata 
  53.         ret 
  54.  
  55.  
  56. ;Clears the LCD display and sets the initialisation conditions. 
  57. clearscreen:    mov A,#LCD_CLS 
  58.         call wrcmd 
  59.         mov A,#LCD_SETDDADDR + 15 
  60.         call wrcmd 
  61.         ret 
  62.  
  63.          
  64.          
  65. ;***************************** 
  66. ;******** SUBROUTINES ******** 
  67. ;***************************** 
  68.  
  69. ;Sub routine to write command: 
  70. wrcmd:      mov P2,#LCD_PAGE 
  71.         mov R0,#LCD_CMD_WR 
  72.         movx @R0,A 
  73.         jmp wtbusy 
  74.  
  75. ; Subroutine to Write a Character to the LCD Display. 
  76. wrdata:     MOV P2,#LCD_PAGE                 
  77.         MOV R0,#LCD_DATA_WR 
  78.         MOV A,R7 
  79.         MOVX @R0,A 
  80.  
  81.  
  82. ; Subroutine to wait for a busy clear.   
  83. wtbusy:     MOV R1,#LCD_BUSY_RD 
  84.         MOVX A,@R1 
  85.         JB ACC.7,wtbusy 
  86.                 ret 
  87.  
  88.                 END 
  89.         */  
  90.   
  91. #ifndef _LCD1602_H_  
  92. #define _LCD1602_H_  
  93. #include <reg52.h>  
  94. #include <intrins.h>  
  95. #include <absacc.h>  
  96. #define clear 0x01  
  97. #define ret 0x02  
  98. #define fuction_set_usual 0x38    
  99. /********************************显示数据表*********************************/  
  100. enum Mode{in_shift,in_nshift,de_shift,de_nshift};  
  101. unsigned char Entry_Mode[]={0x07,0x06,0x05,0x04};   
  102. // Display_Control 其中几位靠位来吧,比较多,这个命令控制了是否显示,光标是否显示和闪烁功能  
  103. // 通用函数  
  104. /*********************************端口定义**********************************/  
  105. #define LCMDW       XBYTE[0x8001]       // 数据口  
  106. #define LCMCW       XBYTE[0x8000]       // 命令  
  107. #define LCMBY       XBYTE[0x8002]  
  108. //sbit ep = P2^2;  
  109. /********************************显示数据表*********************************/  
  110. //00-0h乃是GGRAM自定义库的自建位  
  111. unsigned char  CGCODE[]={0x08,0x0F,0x12,0x0F,0x0A,0x1F,0x02,0x02,//"年"代码 0x00  
  112.    0x0F,0x09,0x0F,0x09,0x0F,0x09,0x13,0x00,//"月"代码 0x01  
  113.    0x0F,0x09,0x09,0x0F,0x09,0x09,0x0F,0x00,//"日"代码  0x02  
  114.    0x07,0x04,0x07,0x04,0x07,0x00,0x04,0x07,//"星"左上半部分代码 0x03  
  115.    0x1F,0x01,0x1F,0x01,0x1F,0x08,0x08,0x1F,//"星"右上半部分代码 0x04  
  116.    0x08,0x17,0x00,0x1F,0x00,0x00,0x00,0x00,//"星"左下半部分代码 0x05  
  117.    0x08,0x1F,0x08,0x1F,0x00,0x00,0x00,0x00//"星"右下半部分代码 0x06    
  118.    };  
  119. unsigned char  tab[]={'1','0',0x00,'0','3',0x01,'0','9',0x02};//显示"08年03月09日"     
  120. /***************************************************************************** 
  121. 函数功能:LCD延时子程序 
  122.  
  123. 入口参数:ms 
  124.  
  125. 出口参数: 
  126.  
  127. *****************************************************************************/  
  128.   
  129. void delay(unsigned char ms)  
  130. {  
  131. unsigned char i;  
  132.   
  133. while(ms--)  
  134.   
  135. {  
  136.   
  137. for(i = 0; i< 250; i++)  
  138.   
  139. {  
  140.   
  141. _nop_();  
  142.   
  143. _nop_();  
  144.   
  145. _nop_();  
  146.   
  147. _nop_();  
  148.   
  149. }  
  150.   
  151. }  
  152.   
  153. }  
  154.   
  155. /***************************************************************************** 
  156.  
  157. 函数功能:测试LCD忙碌状态 
  158.  
  159. 入口参数: 
  160.  
  161. 出口参数:result 
  162.  
  163. *****************************************************************************/  
  164. bit lcd_bz()  
  165. {  
  166. bit result;  
  167. //ep = 1;  
  168.   
  169. //_nop_();  
  170.   
  171. //_nop_();  
  172.   
  173. //_nop_();  
  174.   
  175. //_nop_();  
  176. result = (bit)(LCMBY&0x80);//高1就是D7  
  177. //ep=0;  
  178. return result;  
  179. }  
  180. /***************************************************************************** 
  181.  
  182. 函数功能:写指令数据到LCD子程序 
  183.  
  184. 入口参数:cmd 
  185.  
  186. 出口参数: 
  187.  
  188. *****************************************************************************/  
  189.   
  190. void lcd_wcmd(unsigned char cmd)  
  191. {  
  192.   
  193. while(lcd_bz());//判断LCD是否忙碌  
  194.   
  195.   
  196. //ep = 0;  
  197.   
  198. //_nop_();  
  199.   
  200. //_nop_();  
  201.   
  202. LCMCW = cmd;  
  203.   
  204. //_nop_();  
  205.   
  206. //_nop_();  
  207.   
  208. //_nop_();  
  209.   
  210. //_nop_();  
  211.   
  212. //ep = 1;  
  213.   
  214. //_nop_();  
  215.   
  216. //_nop_();  
  217.   
  218. //_nop_();  
  219.   
  220. //_nop_();  
  221.   
  222. //ep = 0;  
  223.   
  224. }  
  225.   
  226. /***************************************************************************** 
  227.  
  228. 函数功能:设定显示位置子程序 
  229.  
  230. 入口参数:pos 
  231.  
  232. 出口参数: 
  233.  
  234. *****************************************************************************/  
  235.   
  236. void lcd_pos(unsigned char pos)  
  237.   
  238. {  
  239.   
  240. lcd_wcmd(pos | 0x80);  
  241.   
  242. }  
  243.   
  244. /***************************************************************************** 
  245.  
  246. 函数功能:写入显示数据到LCD子程序 
  247.  
  248. 入口参数:dat 
  249.  
  250. 出口参数: 
  251.  
  252. *****************************************************************************/  
  253.   
  254. void lcd_wdat(unsigned char dat)  
  255.   
  256. {  
  257.   
  258. while(lcd_bz());//判断LCD是否忙碌  
  259.   
  260.   
  261. //ep = 0;  
  262.  LCMDW = dat;  
  263.   
  264. //_nop_();  
  265.   
  266. //_nop_();  
  267.   
  268. //_nop_();  
  269.   
  270. //_nop_();  
  271.   
  272. //ep = 1;  
  273.   
  274. //_nop_();  
  275.   
  276. //_nop_();  
  277.   
  278. //_nop_();  
  279.   
  280. //_nop_();  
  281.   
  282. //ep = 0;  
  283.   
  284. }  
  285.   
  286. /***************************************************************************** 
  287.  
  288. 函数功能:LCD初始化子程序 
  289.  
  290. 写指令38H:显示模式设置 
  291.  
  292. 写指令08H:显示关闭 
  293.  
  294. 写指令01H:显示清屏 
  295.  
  296. 写指令06H:显示光标移动设置 
  297.  
  298. 写指令0CH:显示开及光标设置 
  299.  
  300. 入口参数: 
  301.  
  302. 出口参数: 
  303.  
  304. *****************************************************************************/  
  305.   
  306. void lcd_init()  
  307.   
  308. {  
  309.   
  310. lcd_wcmd(0x38);  
  311.   
  312. delay(1);  
  313.   
  314. lcd_wcmd(0x0c);  
  315.   
  316. delay(1);  
  317.   
  318. lcd_wcmd(0x06);  
  319.   
  320. delay(1);  
  321.   
  322. lcd_wcmd(0x01);  
  323.   
  324. delay(1);  
  325.   
  326. }  
  327.   
  328.   
  329. /***************************************************************************** 
  330.  
  331. 函数功能:画图 
  332.  
  333. 入口参数: 
  334.  
  335. 出口参数: 
  336.  
  337. *****************************************************************************/  
  338.   
  339. void draw()  
  340. {  
  341.  int i;  
  342.  lcd_init();  
  343.  delay(10)   ;  
  344.  lcd_wcmd(0x40);//将自定义字符写入CGRAM   
  345.  for(i=0;i<56;i++)//循环56次写入  
  346.  {  
  347.  lcd_wdat(CGCODE[i]);     
  348.  }  
  349.  lcd_wcmd(0x80);//写入初始地址  
  350.  for(i=0;i<9;i++)  
  351.  {  
  352.   lcd_wdat(tab[i]);  
  353.  }   
  354.  }  
  355. #endif   

详细看代码就可以了,其中汇编的关键在MOVX的使用上,时序图可以查的到,可以研究一下~其中把LCD的地址当做寄存器来看待

每次先选好使用再给数据,就可行了~

主要说C

首先说明~C语言是我从以前的非总线式结构里面改写的。因此有些函数没有用到。

C语言的关键在这里就是

#define LCMDW  XBYTE[0x8001]  // 数据口
#define LCMCW  XBYTE[0x8000]  // 命令
#define LCMBY       XBYTE[0x8002] //忙检测

XBYTE是在absacc.h库里的一个定义地址的工具

其中有~#define XBYTE ((unsigned char volatile xdata *) 0)

其中根据硬件连接高2位的使能打开正是80H的地址,低2位的地址根据功能(A0,A1)定义不同的地址

然后在输出的时候协商

LCMDW=*****;就可以实现MOVX的功能了,产生外部存储的时序来啦~

液晶怎么使用就看数据手册吧,1602的手册可是很全很很全,网上的例子更是很多很多(把上面代码稍微改动就可以直接使用lcd了哈)

接下来给出SAMPLE里我一点没动的核心,计算器的算法实现

 

[c-sharp] view plaincopy
  1.          /****************************************************************************** 
  2. ************                LABCENTER ELECTRONICS                   ************                               
  3. ************             Proteus VSM Sample Design Code             ************             
  4. ************            Integer Calculator ( 2K Code Limit)         ************ 
  5. ********************************************************************************/  
  6. /*汇编 
  7. NAME    LCD 
  8.  
  9. ;Set up Code Segment and exports: 
  10.  
  11. LCD              SEGMENT CODE 
  12. RSEG             LCD 
  13.  
  14.                  PUBLIC  _output 
  15.                  PUBLIC  initialise 
  16.                  PUBLIC  clearscreen 
  17.  
  18.  
  19. ;LCD Register Addresses. 
  20. LCD_CMD_WR  equ     00h 
  21. LCD_DATA_WR equ 01h 
  22. LCD_BUSY_RD equ 02h 
  23. LCD_DATA_RD equ 03h 
  24. LCD_PAGE    equ 80h 
  25.  
  26. ;LCD Commands 
  27. LCD_CLS     equ 1 
  28. LCD_HOME    equ 2 
  29. LCD_SETMODE equ 4 
  30. LCD_SETVISIBLE  equ 8 
  31. LCD_SHIFT   equ 16 
  32. LCD_SETFUNCTION equ 32 
  33. LCD_SETCGADDR   equ 64 
  34. LCD_SETDDADDR   equ 128 
  35.  
  36.  
  37.  
  38.  
  39. ; Initialisation Routine for the LCD display. 
  40. initialise:     mov A,#030h         ;1 line, 8 bits 
  41.         call wrcmd 
  42.         mov A,#LCD_SETVISIBLE + 4 
  43.         call wrcmd 
  44.         mov A,#LCD_SETDDADDR+15     ; Start at right hand side of the display 
  45.         call wrcmd 
  46.         mov A,#LCD_SETMODE + 3      ; Automatic Increment - Display shift left.   
  47.         call wrcmd 
  48.                 ret 
  49.  
  50. ; We move the parameter (held in R7) into the Accumulator prior to writing it. 
  51. _output:    mov A,R7     
  52.         call wrdata 
  53.         ret 
  54.  
  55.  
  56. ;Clears the LCD display and sets the initialisation conditions. 
  57. clearscreen:    mov A,#LCD_CLS 
  58.         call wrcmd 
  59.         mov A,#LCD_SETDDADDR + 15 
  60.         call wrcmd 
  61.         ret 
  62.  
  63.          
  64.          
  65. ;***************************** 
  66. ;******** SUBROUTINES ******** 
  67. ;***************************** 
  68.  
  69. ;Sub routine to write command: 
  70. wrcmd:      mov P2,#LCD_PAGE 
  71.         mov R0,#LCD_CMD_WR 
  72.         movx @R0,A 
  73.         jmp wtbusy 
  74.  
  75. ; Subroutine to Write a Character to the LCD Display. 
  76. wrdata:     MOV P2,#LCD_PAGE                 
  77.         MOV R0,#LCD_DATA_WR 
  78.         MOV A,R7 
  79.         MOVX @R0,A 
  80.  
  81.  
  82. ; Subroutine to wait for a busy clear.   
  83. wtbusy:     MOV R1,#LCD_BUSY_RD 
  84.         MOVX A,@R1 
  85.         JB ACC.7,wtbusy 
  86.                 ret 
  87.  
  88.                 END 
  89.         */  
  90.  
  91. #ifndef _LCD1602_H_  
  92. #define _LCD1602_H_  
  93. #include <reg52.h>  
  94. #include <intrins.h>  
  95. #include <absacc.h>  
  96. #define clear 0x01  
  97. #define ret 0x02  
  98. #define fuction_set_usual 0x38    
  99. /********************************显示数据表*********************************/  
  100. enum Mode{in_shift,in_nshift,de_shift,de_nshift};  
  101. unsigned char Entry_Mode[]={0x07,0x06,0x05,0x04};   
  102. // Display_Control 其中几位靠位来吧,比较多,这个命令控制了是否显示,光标是否显示和闪烁功能  
  103. // 通用函数  
  104. /*********************************端口定义**********************************/  
  105. #define LCMDW       XBYTE[0x8001]       // 数据口  
  106. #define LCMCW       XBYTE[0x8000]       // 命令  
  107. #define LCMBY       XBYTE[0x8002]  
  108. //sbit ep = P2^2;  
  109. /********************************显示数据表*********************************/  
  110. //00-0h乃是GGRAM自定义库的自建位  
  111. unsigned char  CGCODE[]={0x08,0x0F,0x12,0x0F,0x0A,0x1F,0x02,0x02,//"年"代码 0x00  
  112.    0x0F,0x09,0x0F,0x09,0x0F,0x09,0x13,0x00,//"月"代码 0x01  
  113.    0x0F,0x09,0x09,0x0F,0x09,0x09,0x0F,0x00,//"日"代码  0x02  
  114.    0x07,0x04,0x07,0x04,0x07,0x00,0x04,0x07,//"星"左上半部分代码 0x03  
  115.    0x1F,0x01,0x1F,0x01,0x1F,0x08,0x08,0x1F,//"星"右上半部分代码 0x04  
  116.    0x08,0x17,0x00,0x1F,0x00,0x00,0x00,0x00,//"星"左下半部分代码 0x05  
  117.    0x08,0x1F,0x08,0x1F,0x00,0x00,0x00,0x00//"星"右下半部分代码 0x06    
  118.    };  
  119. unsigned char  tab[]={'1','0',0x00,'0','3',0x01,'0','9',0x02};//显示"08年03月09日"     
  120. /***************************************************************************** 
  121. 函数功能:LCD延时子程序 
  122.  
  123. 入口参数:ms 
  124.  
  125. 出口参数: 
  126.  
  127. *****************************************************************************/  
  128.   
  129. void delay(unsigned char ms)  
  130. {  
  131. unsigned char i;  
  132.   
  133. while(ms--)  
  134.   
  135. {  
  136.   
  137. for(i = 0; i< 250; i++)  
  138.   
  139. {  
  140.   
  141. _nop_();  
  142.   
  143. _nop_();  
  144.   
  145. _nop_();  
  146.   
  147. _nop_();  
  148.   
  149. }  
  150.   
  151. }  
  152.   
  153. }  
  154.   
  155. /***************************************************************************** 
  156.  
  157. 函数功能:测试LCD忙碌状态 
  158.  
  159. 入口参数: 
  160.  
  161. 出口参数:result 
  162.  
  163. *****************************************************************************/  
  164. bit lcd_bz()  
  165. {  
  166. bit result;  
  167. //ep = 1;  
  168.   
  169. //_nop_();  
  170.   
  171. //_nop_();  
  172.   
  173. //_nop_();  
  174.   
  175. //_nop_();  
  176. result = (bit)(LCMBY&0x80);//高1就是D7  
  177. //ep=0;  
  178. return result;  
  179. }  
  180. /***************************************************************************** 
  181.  
  182. 函数功能:写指令数据到LCD子程序 
  183.  
  184. 入口参数:cmd 
  185.  
  186. 出口参数: 
  187.  
  188. *****************************************************************************/  
  189.   
  190. void lcd_wcmd(unsigned char cmd)  
  191. {  
  192.   
  193. while(lcd_bz());//判断LCD是否忙碌  
  194.   
  195.   
  196. //ep = 0;  
  197.   
  198. //_nop_();  
  199.   
  200. //_nop_();  
  201.   
  202. LCMCW = cmd;  
  203.   
  204. //_nop_();  
  205.   
  206. //_nop_();  
  207.   
  208. //_nop_();  
  209.   
  210. //_nop_();  
  211.   
  212. //ep = 1;  
  213.   
  214. //_nop_();  
  215.   
  216. //_nop_();  
  217.   
  218. //_nop_();  
  219.   
  220. //_nop_();  
  221.   
  222. //ep = 0;  
  223.   
  224. }  
  225.   
  226. /***************************************************************************** 
  227.  
  228. 函数功能:设定显示位置子程序 
  229.  
  230. 入口参数:pos 
  231.  
  232. 出口参数: 
  233.  
  234. *****************************************************************************/  
  235.   
  236. void lcd_pos(unsigned char pos)  
  237.   
  238. {  
  239.   
  240. lcd_wcmd(pos | 0x80);  
  241.   
  242. }  
  243.   
  244. /***************************************************************************** 
  245.  
  246. 函数功能:写入显示数据到LCD子程序 
  247.  
  248. 入口参数:dat 
  249.  
  250. 出口参数: 
  251.  
  252. *****************************************************************************/  
  253.   
  254. void lcd_wdat(unsigned char dat)  
  255.   
  256. {  
  257.   
  258. while(lcd_bz());//判断LCD是否忙碌  
  259.   
  260.   
  261. //ep = 0;  
  262.  LCMDW = dat;  
  263.   
  264. //_nop_();  
  265.   
  266. //_nop_();  
  267.   
  268. //_nop_();  
  269.   
  270. //_nop_();  
  271.   
  272. //ep = 1;  
  273.   
  274. //_nop_();  
  275.   
  276. //_nop_();  
  277.   
  278. //_nop_();  
  279.   
  280. //_nop_();  
  281.   
  282. //ep = 0;  
  283.   
  284. }  
  285.   
  286. /***************************************************************************** 
  287.  
  288. 函数功能:LCD初始化子程序 
  289.  
  290. 写指令38H:显示模式设置 
  291.  
  292. 写指令08H:显示关闭 
  293.  
  294. 写指令01H:显示清屏 
  295.  
  296. 写指令06H:显示光标移动设置 
  297.  
  298. 写指令0CH:显示开及光标设置 
  299.  
  300. 入口参数: 
  301.  
  302. 出口参数: 
  303.  
  304. *****************************************************************************/  
  305.   
  306. void lcd_init()  
  307.   
  308. {  
  309.   
  310. lcd_wcmd(0x30);  
  311.   
  312. delay(1);  
  313.   
  314. lcd_wcmd(0x0c);  
  315. delay(1);  
  316. lcd_wcmd(0x06);//此处最好用07调节成右侧显示模式。仿真时用07不出现。故用06  
  317. delay(1);  
  318. lcd_wcmd(0x01);    
  319. delay(1);  
  320. lcd_wcmd(0x8f);  //设置位置,上面汇编转过来的  
  321.   
  322. delay(1);  
  323.   
  324. }  
  325.   
  326.   
  327. /***************************************************************************** 
  328.  
  329. 函数功能:画图 
  330.  
  331. 入口参数: 
  332.  
  333. 出口参数: 
  334.  
  335. *****************************************************************************/  
  336.   
  337. void draw()  
  338. {  
  339.  int i;  
  340.  lcd_init();  
  341.  delay(10)   ;  
  342.  lcd_wcmd(0x40);//将自定义字符写入CGRAM     
  343.  for(i=0;i<56;i++)//循环56次写入  
  344.  {  
  345.  lcd_wdat(CGCODE[i]);     
  346.  }  
  347.  lcd_wcmd(0x80);//写入初始地址  
  348.  for(i=0;i<9;i++)  
  349.  {  
  350.   lcd_wdat(tab[i]);  
  351.  }   
  352.  }  
  353. #endif   

这个由于里面的注释很详细,我也稍微加了一两句,就不做解释了,懒人~不过其中有个设定从右侧开始的。。我设定竟然不好用

当然了,从右侧自然好看~从左侧是可以用的呵呵(我已经写在注释里面啦~)。很怀疑软件有点不太支持哈~

最后是键盘的扫描,对于这个东西,用汇编实在是蛮痛苦的。呵呵~不过就像学长说过,用习惯了都是一样的!

同样前面的汇编注释掉了

[cpp] view plaincopy
  1.          /****************************************************************************** 
  2. ************                LABCENTER ELECTRONICS                   ************                               
  3. ************             Proteus VSM Sample Design Code             ************             
  4. ************            Integer Calculator ( 2K Code Limit)         ************ 
  5. ********************************************************************************/  
  6. /*汇编 
  7. NAME    LCD 
  8.  
  9. ;Set up Code Segment and exports: 
  10.  
  11. LCD              SEGMENT CODE 
  12. RSEG             LCD 
  13.  
  14.                  PUBLIC  _output 
  15.                  PUBLIC  initialise 
  16.                  PUBLIC  clearscreen 
  17.  
  18.  
  19. ;LCD Register Addresses. 
  20. LCD_CMD_WR  equ     00h 
  21. LCD_DATA_WR equ 01h 
  22. LCD_BUSY_RD equ 02h 
  23. LCD_DATA_RD equ 03h 
  24. LCD_PAGE    equ 80h 
  25.  
  26. ;LCD Commands 
  27. LCD_CLS     equ 1 
  28. LCD_HOME    equ 2 
  29. LCD_SETMODE equ 4 
  30. LCD_SETVISIBLE  equ 8 
  31. LCD_SHIFT   equ 16 
  32. LCD_SETFUNCTION equ 32 
  33. LCD_SETCGADDR   equ 64 
  34. LCD_SETDDADDR   equ 128 
  35.  
  36.  
  37.  
  38.  
  39. ; Initialisation Routine for the LCD display. 
  40. initialise:     mov A,#030h         ;1 line, 8 bits 
  41.         call wrcmd 
  42.         mov A,#LCD_SETVISIBLE + 4 
  43.         call wrcmd 
  44.         mov A,#LCD_SETDDADDR+15     ; Start at right hand side of the display 
  45.         call wrcmd 
  46.         mov A,#LCD_SETMODE + 3      ; Automatic Increment - Display shift left.   
  47.         call wrcmd 
  48.                 ret 
  49.  
  50. ; We move the parameter (held in R7) into the Accumulator prior to writing it. 
  51. _output:    mov A,R7     
  52.         call wrdata 
  53.         ret 
  54.  
  55.  
  56. ;Clears the LCD display and sets the initialisation conditions. 
  57. clearscreen:    mov A,#LCD_CLS 
  58.         call wrcmd 
  59.         mov A,#LCD_SETDDADDR + 15 
  60.         call wrcmd 
  61.         ret 
  62.  
  63.          
  64.          
  65. ;***************************** 
  66. ;******** SUBROUTINES ******** 
  67. ;***************************** 
  68.  
  69. ;Sub routine to write command: 
  70. wrcmd:      mov P2,#LCD_PAGE 
  71.         mov R0,#LCD_CMD_WR 
  72.         movx @R0,A 
  73.         jmp wtbusy 
  74.  
  75. ; Subroutine to Write a Character to the LCD Display. 
  76. wrdata:     MOV P2,#LCD_PAGE                 
  77.         MOV R0,#LCD_DATA_WR 
  78.         MOV A,R7 
  79.         MOVX @R0,A 
  80.  
  81.  
  82. ; Subroutine to wait for a busy clear.   
  83. wtbusy:     MOV R1,#LCD_BUSY_RD 
  84.         MOVX A,@R1 
  85.         JB ACC.7,wtbusy 
  86.                 ret 
  87.  
  88.                 END 
  89.         */  
  90.   
  91. #ifndef _LCD1602_H_  
  92. #define _LCD1602_H_  
  93. #include <reg52.h>  
  94. #include <intrins.h>  
  95. #include <absacc.h>  
  96. #define clear 0x01  
  97. #define ret 0x02  
  98. #define fuction_set_usual 0x38    
  99. /********************************显示数据表*********************************/  
  100. enum Mode{in_shift,in_nshift,de_shift,de_nshift};  
  101. unsigned char Entry_Mode[]={0x07,0x06,0x05,0x04};   
  102. // Display_Control 其中几位靠位来吧,比较多,这个命令控制了是否显示,光标是否显示和闪烁功能  
  103. // 通用函数  
  104. /*********************************端口定义**********************************/  
  105. #define LCMDW       XBYTE[0x8001]       // 数据口  
  106. #define LCMCW       XBYTE[0x8000]       // 命令  
  107. #define LCMBY       XBYTE[0x8002]  
  108. //sbit ep = P2^2;  
  109. /********************************显示数据表*********************************/  
  110. //00-0h乃是GGRAM自定义库的自建位  
  111. unsigned char  CGCODE[]={0x08,0x0F,0x12,0x0F,0x0A,0x1F,0x02,0x02,//"年"代码 0x00  
  112.    0x0F,0x09,0x0F,0x09,0x0F,0x09,0x13,0x00,//"月"代码 0x01  
  113.    0x0F,0x09,0x09,0x0F,0x09,0x09,0x0F,0x00,//"日"代码  0x02  
  114.    0x07,0x04,0x07,0x04,0x07,0x00,0x04,0x07,//"星"左上半部分代码 0x03  
  115.    0x1F,0x01,0x1F,0x01,0x1F,0x08,0x08,0x1F,//"星"右上半部分代码 0x04  
  116.    0x08,0x17,0x00,0x1F,0x00,0x00,0x00,0x00,//"星"左下半部分代码 0x05  
  117.    0x08,0x1F,0x08,0x1F,0x00,0x00,0x00,0x00//"星"右下半部分代码 0x06    
  118.    };  
  119. unsigned char  tab[]={'1','0',0x00,'0','3',0x01,'0','9',0x02};//显示"08年03月09日"     
  120. /***************************************************************************** 
  121. 函数功能:LCD延时子程序 
  122.  
  123. 入口参数:ms 
  124.  
  125. 出口参数: 
  126.  
  127. *****************************************************************************/  
  128.   
  129. void delay(unsigned char ms)  
  130. {  
  131. unsigned char i;  
  132.   
  133. while(ms--)  
  134.   
  135. {  
  136.   
  137. for(i = 0; i< 250; i++)  
  138.   
  139. {  
  140.   
  141. _nop_();  
  142.   
  143. _nop_();  
  144.   
  145. _nop_();  
  146.   
  147. _nop_();  
  148.   
  149. }  
  150.   
  151. }  
  152.   
  153. }  
  154.   
  155. /***************************************************************************** 
  156.  
  157. 函数功能:测试LCD忙碌状态 
  158.  
  159. 入口参数: 
  160.  
  161. 出口参数:result 
  162.  
  163. *****************************************************************************/  
  164. bit lcd_bz()  
  165. {  
  166. bit result;  
  167. //ep = 1;  
  168.   
  169. //_nop_();  
  170.   
  171. //_nop_();  
  172.   
  173. //_nop_();  
  174.   
  175. //_nop_();  
  176. result = (bit)(LCMBY&0x80);//高1就是D7  
  177. //ep=0;  
  178. return result;  
  179. }  
  180. /***************************************************************************** 
  181.  
  182. 函数功能:写指令数据到LCD子程序 
  183.  
  184. 入口参数:cmd 
  185.  
  186. 出口参数: 
  187.  
  188. *****************************************************************************/  
  189.   
  190. void lcd_wcmd(unsigned char cmd)  
  191. {  
  192.   
  193. while(lcd_bz());//判断LCD是否忙碌  
  194.   
  195.   
  196. //ep = 0;  
  197.   
  198. //_nop_();  
  199.   
  200. //_nop_();  
  201.   
  202. LCMCW = cmd;  
  203.   
  204. //_nop_();  
  205.   
  206. //_nop_();  
  207.   
  208. //_nop_();  
  209.   
  210. //_nop_();  
  211.   
  212. //ep = 1;  
  213.   
  214. //_nop_();  
  215.   
  216. //_nop_();  
  217.   
  218. //_nop_();  
  219.   
  220. //_nop_();  
  221.   
  222. //ep = 0;  
  223.   
  224. }  
  225.   
  226. /***************************************************************************** 
  227.  
  228. 函数功能:设定显示位置子程序 
  229.  
  230. 入口参数:pos 
  231.  
  232. 出口参数: 
  233.  
  234. *****************************************************************************/  
  235.   
  236. void lcd_pos(unsigned char pos)  
  237.   
  238. {  
  239.   
  240. lcd_wcmd(pos | 0x80);  
  241.   
  242. }  
  243.   
  244. /***************************************************************************** 
  245.  
  246. 函数功能:写入显示数据到LCD子程序 
  247.  
  248. 入口参数:dat 
  249.  
  250. 出口参数: 
  251.  
  252. *****************************************************************************/  
  253.   
  254. void lcd_wdat(unsigned char dat)  
  255.   
  256. {  
  257.   
  258. while(lcd_bz());//判断LCD是否忙碌  
  259.   
  260.   
  261. //ep = 0;  
  262.  LCMDW = dat;  
  263.   
  264. //_nop_();  
  265.   
  266. //_nop_();  
  267.   
  268. //_nop_();  
  269.   
  270. //_nop_();  
  271.   
  272. //ep = 1;  
  273.   
  274. //_nop_();  
  275.   
  276. //_nop_();  
  277.   
  278. //_nop_();  
  279.   
  280. //_nop_();  
  281.   
  282. //ep = 0;  
  283.   
  284. }  
  285.   
  286. /***************************************************************************** 
  287.  
  288. 函数功能:LCD初始化子程序 
  289.  
  290. 写指令38H:显示模式设置 
  291.  
  292. 写指令08H:显示关闭 
  293.  
  294. 写指令01H:显示清屏 
  295.  
  296. 写指令06H:显示光标移动设置 
  297.  
  298. 写指令0CH:显示开及光标设置 
  299.  
  300. 入口参数: 
  301.  
  302. 出口参数: 
  303.  
  304. *****************************************************************************/  
  305.   
  306. void lcd_init()  
  307.   
  308. {  
  309.   
  310. lcd_wcmd(0x30);  
  311.   
  312. delay(1);  
  313.   
  314. lcd_wcmd(0x0c);  
  315. delay(1);  
  316. lcd_wcmd(0x06);//此处最好用07调节成右侧显示模式。仿真时用07不出现。故用06  
  317. delay(1);  
  318. lcd_wcmd(0x01);    
  319. delay(1);  
  320. lcd_wcmd(0x8f);  //设置位置,上面汇编转过来的  
  321.   
  322. delay(1);  
  323.   
  324. }  
  325.   
  326.   
  327. /***************************************************************************** 
  328.  
  329. 函数功能:画图 
  330.  
  331. 入口参数: 
  332.  
  333. 出口参数: 
  334.  
  335. *****************************************************************************/  
  336.   
  337. void draw()  
  338. {  
  339.  int i;  
  340.  lcd_init();  
  341.  delay(10)   ;  
  342.  lcd_wcmd(0x40);//将自定义字符写入CGRAM  for(i=0;i<56;i++)//循环56次写入  
  343.  {  
  344.  lcd_wdat(CGCODE[i]);     
  345.  }  
  346.  lcd_wcmd(0x80);//写入初始地址  
  347.  for(i=0;i<9;i++)  
  348.  {  
  349.   lcd_wdat(tab[i]);  
  350.  }   
  351.  }  
  352. #endif   

键盘的扫描实现~没有用上拉下拉电阻~建议使用上拉下拉的电阻。做实物时总是不一样的,比如P0口总线可以不上拉

不过事实说,自己做的时候不上拉是很不好用的~没办法,自己做的工艺太差啦。

好了~大概就是这么多。计划下一个是以前的一个小超声波东东。串口只能再等等啦,虽然很是重要的东西。

(*^__^*) 嘻嘻……