学习单片机已经有一段时间了,但是很多程序都缺少模块化的思想,之前以为只要把单个的功能封装在一个函数里面就是模块化,经过了十多天实习,才真正开始有了模块化的编程思想,这里将我编写的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