学习单片机已经有一段时间了,但是很多程序都缺少模块化的思想,之前以为只要把单个的功能封装在一个函数里面就是模块化,经过了十多天实习,才真正开始有了模块化的编程思想,这里将我编写的STC12C5A60S2单片机控制2004A液晶屏的程序共享一下,一是希望没有模块化编程思想的后来者看看,二是希望前辈们给予斧正。
(补充:以下代码只需要修改.h文件中含有 “选择” 字样的部分,就可以达到复用的效果,只需要注意中文注释部分)
(提示:因为其中的宏较多,建议source insight查看代码)
(图片有点大,在网页可能无法全部显示,可以右键选择在新标签页中查看,就可以在新网页看到全部图片)
/*################lcd2004.h start################*/
#ifndef __LCD2004_H__ #define __LCD2004_H__ #include <reg52.h> #include "common.h" sbit lcd2004_rs_bit = P2^6;/*根据硬件连接选择*/ sbit lcd2004_rw_bit = P2^5;/*根据硬件连接选择*/ sbit lcd2004_en_bit = P2^7;/*根据硬件连接选择*/ #define LCD2004_DATA_PORT P0/*根据硬件连接选择*/ /*default type: px^0---DB0(LSB) px^1---DB1 px^2---DB2 px^3---DB3 px^4---DB4 px^5---DB5 px^6---DB6 px^7---DB7(MSB) */ /* RS Rw 0 0 ---->write command to lcd2004 0 1 ---->read lcd2004‘s status 1 0 ---->write data to lcd2004 1 1 ---->read lcd2004‘s data */ //lcd2004_rw_bit select #define LCD2004_READ_OPERATION HIGH_LEVEL #define LCD2004_WRITE_OPERATION LOW_LEVEL //lcd2004_rs_bit select #define LCD2004_DATA_OPERATION HIGH_LEVEL #define LCD2004_COMMAND_OPERATION LOW_LEVEL //lcd2004_en_bit select #define LCD2004_ENABLE HIGH_LEVEL #define LCD2004_DISABLE LOW_LEVEL /*display:16(column)x2(row),5x7 lattice,8bit data interface*/ #define LCD2004_DEFAULT_DISPALY_MODE 0x38 /* ==================================================== lcd diaplay on/off and cursor display on/off configure ==================================================== /* 0 0 0 0 1 D C B | | |------cursor blink : 1-->enable ; 0-->disalbe | |----------cursor display: 1-->enable ; 0-->disable |-------------lcd2004 dispaly: 1-->enable ; 0-->disalbe */ #define LCD2004_DISPLAY_ENABLE 0X04 #define LCD2004_CURSOR_DISPLAY_ENABLE 0X02 #define LCD2004_CURSOR_BLINK_ENABLE 0X01 #define LCD2004_DISPLAY_DISABLE (0X04 & (~(0x01<<2))) #define LCD2004_CURSOR_DISPLAY_DISABLE (0X02 & (~(0x01<<1))) #define LCD2004_CURSOR_BLINK_DISABLE (0X01 & (~(0x01<<0))) /*默认:lcd显示,光标显示,光标闪烁*/ /*根据实际需要选择*/ #define LCD2004_DEFAULT_DISPLAY_AND_CURSOR_MODE 0x08 | LCD2004_DISPLAY_ENABLE | LCD2004_CURSOR_DISPLAY_ENABLE| LCD2004_CURSOR_BLINK_ENABLE /* ==================================================== point and cursor address configure ==================================================== 0 0 0 0 0 1 N S | |----- screen move:1-->enable ; 0-->disable |--------- N=1:读或者写一个字符后地址指针加1,且光标加1 N=0:度或者写一个字符后地址指针减1,且光标减1 当S=1时 : 若N=1,整屏幕左移 N=0,整屏幕右移 以达到光标不移动,而整个屏幕移动的效果 */ #define LCD2004_POINT_AND_CURSOR_PLUS 0X02 #define LCD2004_SCREEN_MOVE_ENABLE 0x01 #define LCD2004_POINT_AND_CURSOR_MINUS (0X02 & (~(0X01<<1))) #define LCD2004_SCREEN_MOVE_DISABLE (0x01 & (~(0X01<<0))) /*默认:光标和指针加一,屏幕不移动*/ /*根据实际需要选择*/ #define LCD2004_DEFAULT_POINT_AND_POINT_ADDRESS_MODE 0X04 | LCD2004_POINT_AND_CURSOR_PLUS| LCD2004_SCREEN_MOVE_DISABLE #define LCD2004_ROW0 0 #define LCD2004_ROW1 1 #define LCD2004_ROW2 2 #define LCD2004_ROW3 3 #define LCD2004_MIN_ROW LCD2004_ROW0 #define LCD2440_MAX_ROW LCD2004_ROW3 #define LCD2004_ROW_LENGHT 0X14 //20 #define LCD2004_ROW0_ADDRESS_START (0X80) #define LCD2004_ROW1_ADDRESS_START (0X80+0X40) #define LCD2004_ROW2_ADDRESS_START (LCD2004_ROW0_ADDRESS_START+LCD2004_ROW_LENGHT) #define LCD2004_ROW3_ADDRESS_START (LCD2004_ROW1_ADDRESS_START+LCD2004_ROW_LENGHT) //instruction: #define LCD2004_CLEAN_ALL_DISPALY 0x01/*清屏*/ #define LCD2004_CURSOR_RETURN_TO_ORIGIN 0x02/*光标归位*/ //写命令 extern void lcd2004WriteCommand(UB8 commandCode); //写数据 extern void lcd2004WriteData(UB8 dataCode); //lcd20041清屏 extern void lcd2004CleanAll(void) ; //光标归位 extern void lcd2004CursorHoming(void); //lcd2004初始化 extern void lcd2004Init(void) ; //lcd2004地址写字节 extern void lcd2004AddressWriteByte(UB8 row,UB8 column,UB8 dataCode) ; //lcd2004地址写字符串 extern void lcd2004AddressWriteString(UB8 row,UB8 column,UB8 *stringCode); #endif /*__LCD2004_H__*/
/*################lcd2004.h end################*/
/*################lcd2004.c start################*/
/*************************************************************************** 申明 经过测试J204A(也称2004A,每行20字符,显示4行)液晶屏和1602液晶屏的 使用方法几乎是一样的,不过也是有区别的,在1602液晶屏中,用来寄存待显 示字符代码的DDRAM共有80个字节,而J204A能够一次性显示的字符是80字 节,这里不是巧合,即J204A只是将LCD1602的DDRAM的80个自己全部显示出 来而已。 第一行首地址 :0x80 第二行首地址 :0x80+0x40 第三行首地址 :0x80+20 第四行首地址 :0x80+0x40+20 可以注意到,第一行和第三行、第二行和第四行的地址是分别连续的。 经过 实验验证,可以得出这样的结论:J204A是将LCD1602的DDRAM的0x00~0x13地址 的数据映射显示在J204A的第一行,LCD1602的DDRAM的0x14~0x27地址的数据映 射显示在第三行 ; LCD1602的DDRAM的0x40~0x53地址的数据映射显示在J204A 的第二行,将LCD1602的DDRAM的0x54~0x67地址的数据映射显示在J204A的第四行。 ---------------------------------------------------------------------------- J204A的程序和LCD1602的程序很相似,这里的程序是由LCD1602程序修改而来。 ---------------------------------------------------------------------------- ***************************************************************************/ /*************************************************************************** Module :lcd2004.c Purpose :Implementation of lcd2004 module. Version :0.01 2014/02/13 12:00(OK) Complier:Keil 8051 C complier V9.01 MCU :STC12C5A60S2 Author :yangrui Email :yangrui90s@163.com Modification: ================= 2014/02/24 23:44 Reson: 1.Add function lcd2004AddressWriteString(...) ================= ================= 2014/02/24 15:00 Reason: 1.Add Function delay1msForLcd2004() STC12C5A60S2单片机操作速度快比传统8051快,某些操作延时必须足够。 ================= ***************************************************************************/ #include <reg52.h> #include <intrins.h> #include <string.h> #include "lcd2004.h" /****************************************************** Function :delay1msForLcd2004 Input :N/A Output :N/A Return :N/A Description :N/A Note :crystal frequency is 12MHZ ******************************************************/ static void delay1msForLcd2004(void) { unsigned char i, j; _nop_(); _nop_(); i = 12; j = 168; do { while (--j); } while (--i); } /****************************************************** Function :lcd2004ReadStatus Input :N/A Output :N/A Return :lcd2004 status value Description :N/A Note :N/A ******************************************************/ static UB8 lcd2004ReadStatus(void) { UB8 statusCode ; lcd2004_en_bit = LCD2004_DISABLE ; lcd2004_rs_bit = LCD2004_COMMAND_OPERATION ; lcd2004_rw_bit = LCD2004_READ_OPERATION ; LCD2004_DATA_PORT = 0xff ; delay1msForLcd2004() ; lcd2004_en_bit = LCD2004_ENABLE ; delay1msForLcd2004() ; statusCode = LCD2004_DATA_PORT ; lcd2004_en_bit = LCD2004_DISABLE ; return statusCode ; } /****************************************************** Function :lcd2004CheckBusy Input :N/A Output :N/A Return :N/A Description :check lcd2004 busy or free,if busy,wait ! Note :when LCD2004_DATA_PORT[7]==1,lcd2004 is busy, LCD2004_DATA_PORT[7]==0,lcd2004 is free. ******************************************************/ static void lcd2004CheckBusy(void) { do{ ; }while((lcd2004ReadStatus()) & 0x80); } /****************************************************** Function :lcd2004WriteCommand Input :command code Output :N/A Return :N/A Description :write command to lcd2004 Note :N/A ******************************************************/ void lcd2004WriteCommand(UB8 commandCode) { lcd2004CheckBusy(); lcd2004_en_bit = LCD2004_DISABLE ; lcd2004_rs_bit = LCD2004_COMMAND_OPERATION ;/*command*/ lcd2004_rw_bit = LCD2004_WRITE_OPERATION ; /*write*/ LCD2004_DATA_PORT = commandCode ; delay1msForLcd2004(); lcd2004_en_bit = LCD2004_ENABLE ; delay1msForLcd2004(); lcd2004_en_bit = LCD2004_DISABLE ; } /****************************************************** Function :lcd2004WriteData Input :data code Output :N/A Return :void Description :write data to lcd2004 Note :N/A ******************************************************/ void lcd2004WriteData(UB8 dataCode) { lcd2004CheckBusy() ; lcd2004_en_bit = LCD2004_DISABLE ; lcd2004_rs_bit = LCD2004_DATA_OPERATION ; /*data*/ lcd2004_rw_bit = LCD2004_WRITE_OPERATION ; /*write*/ LCD2004_DATA_PORT = dataCode; delay1msForLcd2004(); lcd2004_en_bit = LCD2004_ENABLE ; delay1msForLcd2004(); lcd2004_en_bit = LCD2004_DISABLE ; } /****************************************************** Function :lcd2004CleanAll Input :N/A Output :N/A Return :N/A Description :clean lcd2004 display Note :清除屏幕显示,光标归位(左上角),地址计数器AC设为0 ******************************************************/ void lcd2004CleanAll(void) { lcd2004WriteCommand(LCD2004_CLEAN_ALL_DISPALY); } /****************************************************** Function :lcd2004CursorHoming Input :N/A Output :N/A Return :N/A Description :curosr homing to the 0x80 Note :光标归位,当屏幕移动显示时,lcd2004显示所有数据后, 调用此函数,屏幕显示的所有东西都会归位。光标在第一 个位置(0x80)。 ******************************************************/ void lcd2004CursorHoming(void) { lcd2004WriteCommand(LCD2004_CURSOR_RETURN_TO_ORIGIN); } /****************************************************** Function :lcd2004Init Input :N/A Output :N/A Return :N/A Description :N/A Note :N/A ******************************************************/ void lcd2004Init(void) { lcd2004_en_bit = LCD2004_DISABLE ; lcd2004CleanAll(); lcd2004WriteCommand(LCD2004_DEFAULT_DISPALY_MODE); lcd2004WriteCommand(LCD2004_DEFAULT_DISPLAY_AND_CURSOR_MODE); lcd2004WriteCommand(LCD2004_DEFAULT_POINT_AND_POINT_ADDRESS_MODE); /*可忽略,在lcd2004CleanAll()中隐含了该功能*/ lcd2004WriteCommand(LCD2004_ROW0_ADDRESS_START); lcd2004_en_bit = LCD2004_DISABLE ; } /****************************************************** Function :lcd2004AddressWriteByte Input :行位置 列位置 数据 Output :N/A Return :N/A Description :N/A Note :N/A ******************************************************/ void lcd2004AddressWriteByte(UB8 row,UB8 column,UB8 dataCode) { if(row == LCD2004_ROW0) { lcd2004WriteCommand(LCD2004_ROW0_ADDRESS_START+column) ; } else if(row == LCD2004_ROW1) { lcd2004WriteCommand(LCD2004_ROW1_ADDRESS_START+column) ; } else if(row == LCD2004_ROW2) { lcd2004WriteCommand(LCD2004_ROW2_ADDRESS_START+column) ; } else if(row == LCD2004_ROW3) { lcd2004WriteCommand(LCD2004_ROW3_ADDRESS_START+column) ; } lcd2004WriteData(dataCode); } /****************************************************** Function :lcd2004AddressWriteString Input :首个字符显示的行,列地址,字符串 Output :N/A Return :N/A Description :N/A Note :这里使用的是strlen,而不是sizeof ******************************************************/ void lcd2004AddressWriteString(UB8 row,UB8 column,UB8 *stringCode) { UB8 length = strlen(stringCode) ; if(row == LCD2004_ROW0) { lcd2004WriteCommand(LCD2004_ROW0_ADDRESS_START+column) ; } else if(row == LCD2004_ROW1) { lcd2004WriteCommand(LCD2004_ROW1_ADDRESS_START+column) ; } if(row == LCD2004_ROW2) { lcd2004WriteCommand(LCD2004_ROW2_ADDRESS_START+column) ; } else if(row == LCD2004_ROW3) { lcd2004WriteCommand(LCD2004_ROW3_ADDRESS_START+column) ; } while(length--) { lcd2004WriteData(*stringCode); stringCode++; } }
/*################lcd2004.c end################*/
测试程序:
/*################main.c start################*/
#include <reg52.h> #include <string.h> #include "common.h" #include "lcd2004.h" void main(void) { UB8 i ; UB8 author[] = "Author:YangRui" ; lcd2004Init(); for(i=0 ; i<sizeof(author)-1 ; i++) { lcd2004AddressWriteByte(LCD2004_ROW0,i,author[i]) ; } lcd2004AddressWriteString(LCD2004_ROW1,0,"QQ:279729207"); lcd2004AddressWriteString(LCD2004_ROW2,0,"yangrui90s@163.com"); lcd2004AddressWriteString(LCD2004_ROW3,0,"Data:2014/02/26"); while(1); }
/*################main.c end################*/
补充:common.h
#ifndef __COMMON_H__ #define __COMMON_H__ typedef unsigned char UB8 ; typedef unsigned short int UW16 ; typedef unsigned long UL32 ; typedef char SB8; typedef short int SW16 ; typedef long SL32 ; #define HIGH_LEVEL 1 #define LOW_LEVEL 0 #endif /*__COMMON_H__*/
单片机控制2004A液晶屏之模块化编程,布布扣,bubuko.com
原文:http://blog.csdn.net/yagnruinihao/article/details/19999551