
第一章绪论
课题背景
当今时候是一个信息化的时代,信息的重要性不言而喻的,获取手段显得尤其重要。人们所接受的信息有70%来自于人的视觉,无论用何种方式获取的信息最终需要有某种显示方式来表示。在当代显示技术中,主流的有LED显示屏和LCD液晶显示,而在这些显示技术中,尤其以液晶显示器LCD(Liquid crystal display)为代表的平板显示器发展最快,应用最广。LCD是典型的发光器件,它一材料科学为基础,综合利用了精密机械,光电及计算机技术,并正在微机械,微光学,纤维光学等前沿领域研究基础上,向高集成化,智能化方向发展。
液晶显示技术发展迅猛,市场预测表明,液晶显示平均年销售呈增长10%~13%,不久的将来有可能取代CRT,成为电子信息产品的主要显示器件,另外,液晶显示器对空间电磁辐射的干扰不敏感,且在紧凑的仪器空间不需要专门的屏蔽保护,因而课大大简化仪器的结构和制造成本,在各种便携式仪器,仪表将会越来越广泛的应用。特别是在电池供电的单片机产品中,液晶显示更是必选的显示器件。
}
课题设计目标
本设计是基于ATC51芯片单片机为主控芯片,结合1602液晶显示模板等外围电路,通过软件程序,来实现液晶显示英文字母。本次设计的目的在于利用单片机和IIC技术来显示英文字母。
课程设计的主要工作
(1)对系统的各个模块的各个功能进行深入分析和研究,在对课题所采用的方案进行可行详细的研究后设计具体功能电路。
、
(2)熟悉所选芯片的功能并完成具体电路设计。
(3)对系统的最终指标进行测试,针对系统的不足,进行分析并提出一些改正方法。
设计要求
(1)运行IIC总线技术。
(2)循环显示字母。
第二章 硬件设计
:
LCD1602 简介
2.1.1 LCD1602 引脚功能
LCD1602引脚如图所示
图 LCD1602引脚图
引脚图的功能如表2—1所示
表2—1引脚功能图
}
2.1.2 LCD1602显示模指令集
(1)清屏
功能:清DDROM值和AC值
(2)归位
功能:光标复位,光标返回到地址00H
{
(3)输入方式设置
功能:设置光标,画面移动方式。
其中:I/D=1:数据读写操作后,AC 自加一;
I/D=0:数据读写操作后,AC 自减一;
S=1:数据读写操作,画面平移;
S=0:数据读写操作,画面不动;
(4)显示开关控制
·
功能:设置显示、光标和闪烁开关。
其中:D 表示显示开关,D=1 为开,D=0 为关;
C 表示光标开关,C=1 为开,C=0 为关;
B 表示闪烁开关,B=1 为开,B=0 为关。
(5)光标、画面位移
功能:光标、画面移动。
)
其中:S/C=1 画面移动一个字符位;
S/C=0 光标移动一个字符位;
R/L=1:右移;R/L=0 左移。
(6)功能设置
功能:工作方式设置(初始化指令)。
其中:DL=1,8 位数据接口;
$
DL=0,4 位数据接口;
N=1,两行显示;N=0,一行显示;
F=1,5*10 点阵显示;F=0,5*7 点阵显示。
(7)CGRAM 地址设置
功能:设置CGRAM 地址,A5~A0=0~3FH。
(8)DDRAM 地址设置
、
功能:设置DDRAM 地址。
其中:N=0,一行显示A6~A0=0~4FH;
N=1 两行显示,首行A6~A0=0~2FH,次行A6~A0=40~67H。
(9)读BF 及AC 值
功能:读忙BF 和地址计数器AC 的值。
其中:BF=1:忙,BF=0:准备好。此时AC 值意义为最近一次地址设置(CGRAM 或DDRAM)定义。
(10)写数据
【
功能:根据最近设置的地址性质,数据写入CGRAM 或DDRAM 中。
(11)读数据
功能:根据最近设置的地址性质,从CGRAM 或DDRAM 数据读出。
IIC 总线
IIC 总线是PHILIPS 公司推出的两线式串行总线。用于连接微控制器及其外围设备。IIC 总线产生于在80 年代,最初为音频和视频设备开发,如今主要在服务器管理中使用,其中包括单个组件状态的通信。例如管理员可对各个组件进行查询,以管理系统的配置或掌握组件的功能状态,如电源和系统风扇。可随时监控内存、硬盘、网络、系统温度等多个参数,增加了系统的安全性,方便了管理。
}
2.2.1 IIC 总线的特点
(1) 只要求两条总线线路 一条串行数据线 SDA 一条串行时钟线SCL。
(2) 每个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机从机关系软件设定地址;主机可以作为主发送器或主机接收器。
(3) 它是一个真正的多主机总线,如果两个或更多主机同时初始化数据
传输可以通过冲突检测和仲裁防止数据被破坏。
(4) 串行的 8 位双向数据传输位速率在标准模式下可达 100kbit/s 快速模式下可达 400kbit/s 高速模式下可达4Mbit/s 。
(
(5) 片上的滤波器可以滤去总线数据线上的毛刺波保证数据完整。
(6) 连接到相同总线的IC 数量只受到总线的最大电容400pF 。
2.2.2 IIC 协议总线信号时序
(1)数据的有效性
SDA 线上的数据必须在时钟的高电平周期保持稳定数据线的高或低电平状态只有在 SCL 线的时钟信号是低电平时才能改变。如图 IIC 总线的位传输所示。
图 IIC总线的为传输
?
(2)起始和停止条件
在 IIC 总线中 唯一出现的是被定义为起始(S)和停止(P )条件(见图)的情况。其中一种情况是在 SCL 线是高电平时,SDA 线从高电平向低电平切换,这个情况表示起始条件。当 SCL 是高电平时 SDA 线由低电平向高电平切换表示停止条件。
起始和停止条件一般由主机产生,总线在起始条件后被认为处于忙的状态。在停止条件的某段时间后,总线被认为再次处于空闲状态。如果产生重复起始(Sr)条件而不产生停止条件,总线会一直处于忙的状态,此时的起始条件(S)和重复起始(Sr)条件在功能上是一样的。因此在本文档的剩余部分,符号(S)将作为一个通用的术语既表示起始条件又表示重复起始条件,除非有特别声明的(Sr)。
如果连接到总线的器件合并了必要的接口硬件,那么用它们检测起始和停止条件十分简便。但是,没有这种接口的微控制器在每个时钟周期至少要采样 SDA 线两次来判别有没有发生电平切换。
图起始和停止条件
(3)总线空闲状态
SDA 和SCL 两条信号线都处于高电平,即总线上所有的器件都释放总线,两条信号线各自的上拉电阻把电平拉高。
;
(4)数据传输与应答信号ACK
发送到SDA 线上的数据必须是8 位的。每次传输可以发送的数据不受。每个字节后必须在时钟的第9 个脉冲期间释放数据总线(SDA 为高),由接收器发送一个ACK(把数据总线的电平拉低)来表示数据成功接收。如图 IIC 总线响应。
图总线响应
首先传输的是数据的最高位(MSB)。如果从机要完成一些其他功能后(例如一个内部中断服务程序)才能接收或发送下一个完整的数据字节,可以使时钟SCL 保持低电平迫使主机进入等待状态。当从机准备好接收下一个数据字节并释放时钟线SCL 后,数据传输继续。如图 IIC 总线数据传输所示。
图总线数据传输
2.2.3 IIC 总线器件寻址方式
、
IIC 总线上的器件是共用总线的,因此,主器件在进行数据传输前要选择通信的从器件,即进行总线寻址。总线上的所有器件都有唯一的地址,由器件地址和引脚地址两部分构成,共7 位。引脚地址由IIC 总线外围器件的地址引脚(A2、A1、A0)决定的。
数据的传输遵循如图 完整的数据传送所示,在起始条件之后,发送一个7 位的从机地址,紧接着第8 位是数据方向(R/ W),0-表示发送数据(写),1-表示接收数据(读)。数据传输一般由主机产生的停止位(P)终止。但是如果主机仍希望在总线上通讯,它可以产生重复起始条件(Sr),和寻址另一个从机,而不是首先产生一个停止条件。在这种传输中,可能有不同的读/写格式结合。如图 IIC 总线完整的数据传输。
图 IIC总线的数据传输
系统电路图
系统的电路图如 所示:
图 系统电路图
,
运行状况如图:
图 运行状态
。
第三章 软件设计
[
系统框图
本课题的程序设计是在C 语言的基础之上的,可分为两大模块,分别是:(1)IIC 协议;(2)LCD 显示。
程序总体框图如图 所示:
图 总程序框图
·
LCD 显示程序框图如图 所示:
·
图显示程序框图
程序清单
(一)
#include<>
#include<>
#define uint unsigned int
#define uchar unsigned char
uchar code display_1[]={"good morning"};
《
uchar code display_2[]={"miss you"};
sbit lcden=P3^4;
sbit lcdrs=P3^5;
//sbit lcdrw=P3^6;
uchar num;
uint i=0;
void delayms(uint z)
{
…
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void write_com(uchar com)
{
lcdrs=0;
lcden=0;
(
P0=com;
delayms(5);
lcden=0;
lcden=1;
delayms(5);
lcden=0;
}
void write_data(uchar date)
:
{
lcdrs=1;
P0=date;
delayms(5);
lcden=0;
lcden=1;
delayms(5);
lcden=0;
,
}
void init()
{
lcden=0;
write_com(0x38);
write_com(0x0f);
write_com(0x06);
write_com(0x01);
`
}
void main()
{
init();
//lcdrw=0;
write_com(0x80+0x1a);
while(display_1[i]!='\\0')
{
:
write_data(display_1[i]);
i++;
delayms(5);
}
write_com(0x80+0x5f);
for(num=0;num<10;num++)
{
write_data(display_2[num]);
}
delayms(5);
}
for(num=0;num<16;num++)
{
write_com(0x18);
delayms(100);
}
while(1);
|
}
(二)
/****************************************************************************
* File:
* 功能:向LCD输出HelloWorld
****************************************************************************/
#include ""
】
#define rs (1<<8)
#define rw (1<<9)
#define en (1<<10)
#define busy (1<<7)
uint8 txt[]={"HelloWorld"};
/****************************************************************************
* 名称:ChkBusy()
<
* 功能:检查总线是否忙
****************************************************************************/
void ChkBusy()
{
IODIR=0x700;
while(1)
{
IOCLR=rs;
{
IOSET=rw;
IOSET=en;
if(!(IOPIN & busy))break;
IOCLR=en;
}
IODIR=0x7ff;
}
/****************************************************************************
`
* 名称:WrOp()
* 功能:写函数
****************************************************************************/
void WrOp(uint8 dat)
{
ChkBusy();
IOCLR=rs; //全部清零
IOCLR=rw;
【
IOCLR=0xff; //先清零
IOSET=dat; //再送数
IOSET=en;
IOCLR=en;
}
/****************************************************************************
* 名称:WrDat()
* 功能:写数据函数
{
****************************************************************************/
void WrDat(uint8 dat)
{
ChkBusy();
IOSET=rs;
IOCLR=rw;
IOCLR=0xff; //先清零
IOSET=dat; //再送数
:
IOSET=en;
IOCLR=en;
}
/****************************************************************************
* 名称:lcd_init()
* 功能:lcd初始化函数
****************************************************************************/
void lcd_init(void)
}
{
WrOp(0x38);
WrOp(0x06); //光标加1
WrOp(0x0c); //开显示
}
/****************************************************************************
* 名称:DisText()
* 功能:显示文本函数
?
****************************************************************************/
void DisText(uint8 addr,uint8 *p)
{
WrOp(addr);
while(*p !='\\0')WrDat(*(p++));
}
/****************************************************************************
~
* 名称:main()
* 功能:显示文本
****************************************************************************/
int main(void)
{
lcd_init();
IODIR=0x7ff; //设置为输出
·
IOCLR=0x7ff;
DisText(0x86,txt);
while(1);
}
/**--------------文件信息--------------------------------------------------------------------------------
**文 件 名:
**描 述: lpc210x(飞利浦的ARM)目标板特殊的代码,包括异常处理程序和目标板初始化程序
,
** 每个工程应当具有这个文件的拷贝,用户根据程序的需要修改本文件。
**注 意:本文件必须以ARM(32位代码)方式编译,否则,必须更改和文件
** 别的C代码不必使用ARM(32位代码)方式编译
********************************************************************************************************/
#define IN_TARGET
#include ""
…
/*********************************************************************************************************
** 函数名称: IRQ_Exception
** 功能描述: 中断异常处理程序,用户根据需要自己改变程序
**
********************************************************************************************************/
void __irq IRQ_Exception(void)
{
while(1); // 这一句替换为自己的代码
'
}
/*********************************************************************************************************
** 函数名称: FIQ_Exception
** 功能描述: 快速中断异常处理程序,用户根据需要自己改变程序
**
********************************************************************************************************/
void FIQ_Exception(void)
\
{
while(1); // 这一句替换为自己的代码
}
/*********************************************************************************************************
** 函数名称: TargetInit
** 功能描述: 目标板初始化代码,在需要的地方调用,根据需要改变
¥
********************************************************************************************************/
void TargetInit(void)
{
/* 添加自己的代码 */
}
/*********************************************************************************************************
** 函数名称: TargetResetInit
:
** 功能描述: 调用main函数前目标板初始化代码,根据需要改变,不能删除
********************************************************************************************************/
void TargetResetInit(void)
{
/* 设置系统各部分时钟 */
/* PLLCON = 1;
@
#if ((Fcclk / 4) / Fpclk) == 1
VPBDIV = 0;
#endif
#if ((Fcclk / 4) / Fpclk) == 2
VPBDIV = 2;
#endif
]
#if ((Fcclk / 4) / Fpclk) == 4
VPBDIV = 1;
#endif
#if (Fcco / Fcclk) == 2
PLLCFG = ((Fcclk / Fosc) - 1) | (0 << 5);
#endif
#if (Fcco / Fcclk) == 4
】
PLLCFG = ((Fcclk / Fosc) - 1) | (1 << 5);
#endif
#if (Fcco / Fcclk) == 8
PLLCFG = ((Fcclk / Fosc) - 1) | (2 << 5);
#endif
#if (Fcco / Fcclk) == 16
PLLCFG = ((Fcclk / Fosc) - 1) | (3 << 5);
#endif
,
PLLFEED = 0xaa;
PLLFEED = 0x55;
while((PLLSTAT & (1 << 10)) == 0);
PLLCON = 3;
PLLFEED = 0xaa;
PLLFEED = 0x55;
*/
^
/* 设置存储器加速模块 */
MAMCR = 2; //MAMCR 8u2 00-MAM 功能被禁止、01-MAM功能部分使能、10-MAM功能完全使能
/* MAMTIM 8u3
000=0-保留
001=1-一段时间内只有 1 个处理器时钟(cclk)用于 MAM 取指。
010=2-一段时间内只有2个处理器时钟(cclk)用于MAM取指。
011=3-一段时间内只有 3 个处理器时钟(cclk)用于 MAM 取指。
100=4-一段时间内只有4个处理器时钟(cclk)用于 MAM 取指。
{
101=5-一段时间内只有5 个处理器时钟(cclk)用于 MAM 取指。
110=6-一段时间内只有 6 个处理器时钟(cclk)用于 MAM 取指。
111=7-一段时间内只有7个处理器时钟(cclk)用于 MAM 取指。
*/
#if Fcclk <
MAMTIM = 1;
#else
#if Fcclk <
:
MAMTIM = 2;
#else
MAMTIM = 3;
#endif
#endif
/* 初始化VIC */
VICIntEnClr = 0xffffffff;//清所有中断使能,即关中断
,
VICVectAddr = 0;//默认向量地址寄存器
VICIntSelect = 0;//1:对应的中断请求分配为FIQ。0:对应的中断请求分配为IRQ。
/* 添加自己的代码 */
}
#include ""
#include ""
&
#pragma import(__use_no_semihosting_swi)
#pragma import(__use_two_region_memory)
int __rt_div0(int a)
{
a = a;
return 0;
,
}
int fputc(int ch,FILE *f)
{
ch = ch;
f = f;
return 0;
}
~
int fgetc(FILE *f)
{
f = f;
return 0;
}
`
int _sys_close(FILEHANDLE fh)
{
fh = fh;
return 0;
}
int _sys_write(FILEHANDLE fh, const unsigned char * buf,
unsigned len, int mode)
\
{
fh = fh;
buf = buf;
len =len;
mode = mode;
return 0;
}
int _sys_read(FILEHANDLE fh, unsigned char * buf,
…
unsigned len, int mode)
{
fh = fh;
buf = buf;
len =len;
mode = mode;
return 0;
)
}
void _ttywrch(int ch)
{
ch = ch;
}
int _sys_istty(FILEHANDLE fh)
、
{
fh = fh;
return 0;
}
int _sys_seek(FILEHANDLE fh, long pos)
{
fh = fh;
return 0;
}
int _sys_ensure(FILEHANDLE fh)
{
fh = fh;
return 0;
}
long _sys_flen(FILEHANDLE fh)
{
fh = fh;
return 0;
}
int _sys_tmpnam(char * name, int sig, unsigned maxlen)
{
name = name;
sig = sig;
maxlen = maxlen;
return 0;
}
void _sys_exit(int returncode)
{
returncode = returncode;
}
char *_sys_command_string(char * cmd, int len)
{
cmd = cmd;
len = len;
return 0;
}
/*********************************************************************************************************
** End Of File
********************************************************************************************************/
第四章 调 试
程序的调试是用Keil 软件和Proteus 联调的,LCD 两行滚动显示的字符,第一行为“hello everyone ”第二行为"miss you ",两行同时向右平移。调试后的效果图如 所示:
图 调试后的效果图
第五章 总 结
通过本次课程设计,我熟悉和掌握了IIC 的原理及其应用,能够初步使用LCD1602 显示字符等。本课题的程序设计是基于C语言的,C 语言具有方便,快速,高效。当然本设计也存在不足之处,由于LCD1602 只能显示字符,而不能显示汉字和图片,如果想要显示汉字和图片的话,需要用到12832 等的LCD 模块,这是本设计的一大缺陷。另外,这次课题中的程序设计中,对时序要求很严格,尤其是IIC。
通过本次课程设计,我有熟悉和掌握了单片机开发软件Keil和仿真软件Proteus。
参考文献:
[1] 楼然苗.单片机课程设计指导[M].北京:北京航空航天大学出版社,2007
[2] 何立民.单片机实验与实践教程[M].北京:北京航空航天大学出版社,2004
致 谢
在这次课程设计的撰写过程中,我得到了许多人的帮助。
首先我要感谢我的老师在课程设计上给予我的指导、提供给我的支持和帮助,这是我能顺利完成这次报告的主要原因,更重要的是老师帮我解决了许多技术上的难题,让我能把系统做得更加完善。在此期间,我不仅学到了许多新的知识,而且也开阔了视野,提高了自己的设计能力。
其次,我要感谢帮助过我的同学,他们也为我解决了不少我不太明白的设计的难题。
最后再一次感谢所有在设计中曾经帮助过我的良师益友和同学。
