单片机课设(三篇课设均带带仿真图和源程序代码)

更新时间:2024-07-08 10:40:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

12232 LCD PROTEUS仿真(51C)

12232在proteus 里模型用关键字P ,“12232” 查不出LCD的,要用1232 查找 。

好不容易得到模型,编写程序,一直不能成功。第一个字符正常,后面的就乱了。最后才明白:12232的模型和实物不一样,共4页(这和实物一样),每页只能从地址0开始,水平方向从左往右显示。另外,按实物的程序,仿真中显示是相反的,所以初始化时应改为反向显示,仿真显示才正常。

//12232LCD proteus仿真

//2012 01 20 E:\\DPJ_C\\12232\\12232UV4\\12232_2C.C #include #include #include\#define uchar unsigned char #define uint unsigned int #define LCD_DB P0 sbit E2=P3^5; sbit E1=P3^6; sbit A0=P3^7;

void WR_Mcom(uchar i) { E1=1; _nop_(); _nop_();

1 / 53

A0=0; _nop_(); _nop_(); LCD_DB=i; _nop_(); _nop_(); E1=0; _nop_(); _nop_(); }

void WR_Mdat(uchar i) { E1=1; _nop_(); _nop_(); A0=1; _nop_(); _nop_(); LCD_DB=i; _nop_(); _nop_(); E1=0; _nop_(); _nop_(); }

void WR_Scom(uchar i) { A0=0; _nop_(); _nop_(); E2=1; _nop_(); _nop_(); LCD_DB=i; _nop_(); _nop_(); E2=0; _nop_(); _nop_();

2 / 53

}

void WR_Sdat(uchar i) { A0=1; _nop_(); _nop_(); E2=1; _nop_(); _nop_(); LCD_DB=i; _nop_(); _nop_(); E2=0; _nop_(); _nop_(); }

void lcdini() {

WR_Mcom(0XE2); WR_Scom(0XE2);// WR_Mcom(0XAE);

WR_Scom(0XAE);//显示开关:关 WR_Mcom(0XA4);//动态显示 WR_Scom(0XA4);//

WR_Scom(0XA9);//1/32 占空比 WR_Mcom(0XA1); WR_Scom(0XA1); WR_Mcom(0XEE); WR_Scom(0XEE);//写模式 WR_Mcom(0X00);//起始列0 WR_Mcom(0XC0);//起始行0 WR_Scom(0X00); WR_Scom(0XC0); WR_Mcom(0XAF);

WR_Scom(0XAF);//显示开关:开 }

void SetPage(uchar page0,uchar page1) {

WR_Mcom(0xB8|page1);

3 / 53

WR_Scom(0xB8|page0); }

void SetAddress(uchar address0,uchar address1) {

WR_Mcom(address1&0x7F); WR_Scom(address0&0x7F); }

void clrscr( ) { uchar i; uchar page;

for (page=0;page<4;page++) {

SetPage(page,page); SetAddress(0,0); for (i=0;i<61;i++) {

WR_Mdat(0); WR_Sdat(0); } } }

void display() {

uchar i,j,page;

for(page=0;page<4;page++) {

SetPage(page,page); SetAddress(0,0); for(i=0;i<4;i++) {

for(j=0;j<15;j++) { if(page<2) {

WR_Mdat(chr16[2*i][j+page*15]); WR_Sdat(chr16[2*i+8][j+page*15]); } else

4 / 53

{

WR_Mdat(chr16[2*i+16][j+(page-2)*15]); WR_Sdat(chr16[2*i+24][j+(page-2)*15]); } } } } }

void main() { lcdini(); clrscr(); while(1) { display(); } }

/****************************************************************************************/

CHR16.H //

unsigned char code chr16[32][15]={

{0x00,0x40,0x40,0xDA,0xFE,0x24,0x20,0xF8,0xDE,0xD6,0xD8,0xC8,0x48,0x00,0x00,}, {0x08,0x0C,0x07,0x3F,0x3F,0x03,0x0F,0x1F,0x17,0xD5,0xFF,0x3F,0x11,0x11,0x01,},/*\梅\{0x00,0x00,0x10,0x10,0x9C,0x9C,0x10,0x98,0x9E,0x0E,0x88,0x88,0x08,0x00,0x00,}, {0x10,0x18,0x0C,0x7F,0x7F,0x08,0x08,0x3F,0x7F,0x43,0x41,0x40,0x78,0x38,0x00,},/*\花\{0x00,0x00,0x20,0x20,0xE0,0xE0,0x60,0xFA,0xFE,0x24,0x60,0x60,0x20,0x00,0x00,}, {0x00,0x10,0x19,0x0F,0x07,0x24,0x38,0x1F,0x07,0x0C,0x38,0x30,0x20,0x20,0x00,},/*\欢\{0x00,0x00,0x00,0x08,0xA8,0xA8,0xFE,0x7E,0xEC,0xC4,0x44,0x00,0x00,0x00,0x00,},

{0x08,0x08,0x08,0x08,0x6A,0xEF,0xAD,0xBD,0xD7,0x77,0x34,0x04,0x04,0x04,0x00,},/*\喜\{0x00,0x40,0x40,0x18,0x98,0x84,0xFC,0xFC,0xEC,0xFE,0xDE,0xC4,0x40,0x00,0x00,}, {0x00,0x10,0x3C,0x3E,0x42,0x45,0x6D,0x3D,0x1F,0x3F,0x63,0x60,0x40,0x40,0x40},/*\漫\{0x00,0x00,0x80,0x88,0x88,0x88,0xF8,0x7C,0x44,0x44,0x40,0x40,0x00,0x00,0x00,},

{0x00,0x20,0x20,0x30,0x1C,0x0F,0x03,0x07,0x0E,0x18,0x30,0x30,0x20,0x20,0x00,},/*\天\{0x00,0x80,0xF0,0x70,0x64,0x64,0xFC,0xFC,0xD6,0xD2,0x10,0x30,0x30,0x00,0x00,}, {0x00,0x00,0x00,0x44,0x55,0x55,0x55,0x5F,0x6A,0x3E,0x1E,0x00,0x00,0x00,0x00,},/*\雪\{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}, {0x00,0x00,0x68,0x78,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*\,\{0x00,0x00,0x10,0xB0,0xB0,0x00,0xE0,0xF8,0xDE,0xD6,0x10,0x10,0x00,0x00,0x00,}, {0x00,0x08,0x0C,0x0F,0x23,0x3B,0x1B,0x42,0x7F,0x7F,0x09,0x39,0x31,0x00,0x00,},/*\冻\

5 / 53

{0x00,0x00,0x00,0xC8,0xE8,0xA8,0x88,0xFC,0xF4,0x84,0xC4,0x40,0x00,0x00,0x00,}, {0x00,0x20,0x31,0x1B,0x0E,0x07,0x01,0x1F,0x3F,0x31,0x20,0x30,0x3C,0x1C,0x00,},/*\死\{0x00,0x00,0x08,0x08,0x0E,0xCE,0xE8,0x68,0xCE,0x8E,0x0E,0x04,0x00,0x00,0x00,}, {0x08,0x08,0x0C,0x06,0x3F,0x7F,0x42,0x5E,0x5E,0x43,0x73,0x73,0x02,0x02,0x02,},/*\苍\{0x00,0xC0,0xC0,0xFC,0xFC,0xE0,0xF8,0xB8,0xE8,0xF8,0xDC,0xCC,0x80,0x00,0x00,}, {0x00,0x10,0x19,0x0F,0x07,0x07,0x07,0x0F,0x1F,0x3F,0x27,0x27,0x30,0x30,0x00,},/*\蝇\{0x00,0x00,0x00,0x00,0x80,0x90,0xFE,0xFE,0x90,0xD0,0x40,0x00,0x00,0x00,0x00,},

{0x00,0x20,0x31,0x19,0x0D,0x07,0xFF,0xFF,0x06,0x0C,0x18,0x10,0x30,0x20,0x00,},/*\未\{0x00,0x00,0x00,0x80,0xB8,0x78,0xE8,0xEC,0x3C,0x3C,0x00,0x00,0x00,0x00,0x00,}, {0x20,0x30,0x1C,0x0F,0x07,0x04,0x0F,0x0F,0x19,0x31,0x30,0x20,0x20,0x20,0x20,},/*\足\{0x00,0x80,0x80,0x80,0xC8,0xE8,0xB8,0x9E,0xFE,0xEC,0xC4,0x40,0x40,0x40,0x00,}, {0x00,0x00,0x00,0x00,0x0E,0x0E,0x0E,0x06,0xC2,0xFF,0x3F,0x00,0x00,0x00,0x00,},/*\奇\{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,},

{0x00,0x00,0x30,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,},/*\。\};

2012 01 24 更新 原来的程序虽然正常运行,但总觉得数组部分有点问题。更改 display()子函数如下,总算可以了。 void display() {

uchar i,j,page;

for(page=0;page<4;page++) {

SetPage(page,page); SetAddress(0,0); for(i=0;i<4;i++) {

for(j=0;j<15;j++) { if(page<2) {

WR_Mdat(chr16[2*i+page][j]); WR_Sdat(chr16[2*i+8+page][j]); } else {

WR_Mdat(chr16[2*i+14+page][j]); WR_Sdat(chr16[2*i+22+page][j]); } }

6 / 53

} } }

2013.05.25 更新 取模

7 / 53

要注意,你说的通用型其实并不通用,LCD模块中使用不同的控制器,其控制方法都不同!所有的LCD模块都在Optoelectronics大类下。 1602是LM016L; 12232有好几种:

AGM1232G DISPLAY 122x32 Graphical LCD with SED1520 controllers EW12A03GLY DISPLAY 122x32 Graphical LCD with SED1520 controllers

HDM32GS12-B DISPLAY 122x32 Graphical LCD with SED1520 controllers, LED Backlight HDM32GS12Y-3 DISPLAY 122x32 Graphical LCD with SED1520 controllers, Selectable Interface, VAC LED Backlight 12864也有好几种:

AMPIRE128X64 DISPLAY 128x64 Graphical LCD with KS0108 controllers

HDG12864F-1 DISPLAY 128x64 Graphical LCD with SED1565 controller, Serial data input

HDG12864F-3 DISPLAY 128x64 Graphical LCD with SED1565 controller, Parallel data input

HDG12864L-4 DISPLAY 128x64 Graphical LCD with SED1565 controller, Parallel data input, LED Backlight

HDG12864L-6 DISPLAY 128x64 Graphical LCD with SED1565 controller, Selectable Interface, LED Backlight

LGM12641BS1R DISPLAY 128x64 Graphical LCD with KS0108 controllers LM3228 DISPLAY 128x64 Graphical LCD LM4228 DISPLAY 128x64 Graphical LCD LM4265 DISPLAY 128x128 Graphical LCD PG128128A DISPLAY 128x128 Graphical LCD Display PG12864F DISPLAY 128x64 Graphical LCD Display

TG126410GFSB DISPLAY 128x66 Graphical LCD with SED1565 controllers, Bottom View

8 / 53

单片机与接口技术课程设计总结报告

设计题目: 电子万年历学生姓名: 系 别: 专 业: 班 级: 学 号: 指导教师:

2011年12月16日

9 / 53

设计题目:

电子万年历

设计任务与要求:

1、显示年月日时分秒及星期信息 2、具有可调整日期和时间功能 3、增加闰年计算功能

方案比较:

方案一:系统分为主控制器模块、显示模块、按键开关模块,主控制模块采用AT89C52单片机为控制中心,显示模块采用普通的共阴LED数码管,键输入采用中断实现功能调整,计时使用AT89C52单片机自带的定时器功能,实现对时间、日期的操作,通过按键盘开关实现对时间、日期的调整。

方案二:系统分为主控模块、时钟电路模块、按键扫描模块,LCD显示模块,电源电路、复位电路、晶振电路等模块。主控模块采用AT89C52单片机,按键模块用四个按键,用于调整时间,显示模块采用LCD1602,时钟电路模块采用DS1302时钟芯片实现对时间、日期的操作。

两个方案工作原理大致相同,只有显示模块和时钟电路不同。LED数码管价格适中,对于数字显示效果较好,而且使用单片机的端口也较少; LCD1602液晶显示屏,显示功能强大,可以显示大量文字、图形,显示多样性,清晰可见,价格相对LED数码管来说要昂贵些,但是基于本设计显示的东西较多,若采用LED数码管的话,所需数码管较多,而且不利于控制,因此选择LCD1602作为显示模块。DS1302是一款高性能的实时时钟芯片,以计时准确、接口简单、使用方便、工作电压范围宽和低功耗等优点,得到广泛的应用,实时时钟有秒、分、时、星期、日、月和年,月小于31天时可以自动调整,并具有闰年补偿功能,而且在掉电时能够在外部纽扣电池的供电下继续工作。单片机有定时器的功能,但时间误差较大,且需要编写时钟程序,因此采用DS1302作为时钟电路。

对比以上方案,结合设计技术指标与要求我们选择了方案二进行设计。

10 / 53

逻辑总框图:

该电子万年历的总体设计框图如图(1)所示。

设计所需的元件:

元件名称 型号 数量/个 单片机

AT89C52 1

时钟芯片 DS1302 1 晶振 12MHz 1 晶振 32.768kHz

1

电容 30pF 2 电容 22uF 1 按键开关

4

电阻 10K 9 滑动变阻器 1K 1 电池 1.5V 4 LCD LCD1602 1 电源Vcc +5V 1 导线

若干

单元电路设计:

11 / 53

1、主控制系统

单片机中央处理系统的方案设计,选用AT89C52单片机作为中央处理器,如图(2)所示。该单片机除了拥有MCS-51系列单片机的所有优点外,内部还具有8K的在系统可编程FLASH存储器,低功耗的空闲和掉电模式,极大的降低了电路的功耗,还包含了定时器、程序存储器、数据存储器等硬件,其硬件能符合整个控制系统的要求,不需要外接其他存储器芯片和定时器件,方便地构成一个最小系统。整个系统结构紧凑,抗干扰能力强,性价比高。

2、时钟振荡电路

时钟振荡电路图(3)所示,时钟振荡电路用于产生单片机正常工作时所需要的时钟信号,电路由两个30pF的瓷片电容和一个12MHz的晶振组成,并接入到单片机的XTAL1和XTAL2引脚处,使单片机工作于内部振荡模式。此电路在加电后延迟大约10ms振荡器起振,在XTAL2引脚产生幅度为3V左右的正弦波时钟信号,其振荡频率主要由石英晶振的频率决定。电路中两个电容C1、C2的作用使电路快速起振,提高电路的运行速度。

12 / 53

图(3) 时钟振荡电路图 图(4) 复位电路

3、复位电路

复位电路由电阻和极性电容组成,如图(4)所示,通过高电平使单片机复位,在时钟电路开始工作后,当高电平的时间超过大约2us时,即可实现复位。此复位电路为上电复位,较为简单。若改进可以添加手动复位的功能,上电复位发生在开机加电时,由系统自动完成,手动复位通过一个按键来实现,在程序运行时,若遇到死机,死循环或程序“跑飞”等情况,通过手动复位就可以实现重新启动的操作。手动按钮复位需要人为在复位输入端RST上加入高电平。一般采用的办法是在RST端和正电源Vcc之间接一个按钮和一个电阻。

4、DS1302时钟电路

时钟电路主要由时钟芯片DS1302、备用电池、晶振等几部分组成,如图(6)所示。DS1302采用3线串行接口,占用引脚少,内部集成了可编程日历时钟,用户可以根据需要通过单片机的控制来自行设置,支持双电源供电,可以使用外部主电源和备用电源,备份电源能够使时钟芯片继续工作。

图(5) DS1302管脚图 图(6) DS1302时钟电路 DS1302各引脚的功能为:

13 / 53

8: Vcc1:备用电池端;

1: Vcc2:5V电源。当Vcc2>Vcc1+0.2V时,由Vcc2向DS1302供电,当Vcc2< Vcc1时,由Vcc1向DS1302供电;

7: SCLK:串行时钟,输入; 6: I/O:数据输入输出口; 5: CE/RST:复位脚;

2、3: X1、X2 是外接晶振脚 (32.768KHZ的晶振); 4: 地(GND)。

DS1302有关日历、时间的寄存器:

图(7)DS1302有关日历、时间的寄存器

1、秒寄存器(81h、80h)的位7定义为时钟暂停标志(CH)。当初始上电时该位置为1,时钟振荡器停止,DS1302处于低功耗状态;只有将秒寄器的该位置改写为0时,时钟才能开始运行。

2、小时寄存器(85h、84h)的位7用于定义DS1302是运行于12小时模式还是24小时模式。当为高时,选择12小时模式。在12小时模式时,位5是 ,当为1时,表示PM。在24小时模式时,位5是第二个10小时位

3、控制寄存器(8Fh、8Eh)的位7是写保护位(WP),其它7位均置为0。在对任何的时钟和RAM的写操作之前,WP位必须为0。当WP位为1时,写保护位防止对任一寄存器的写操作。也就是说在电路上电的初始态WP是1,这时是不能改写上面任何一个时间寄存器的,只有首先将WP改写为0,才能进行其它寄存器的写操作。

14 / 53

DS1302读写时序

DS1302是SPI总线驱动方式。它不仅要向寄存器写入控制字,还需要读取相应寄存器的数据。DS1302的控制字如图(8):

图(8)DS1302的控制字图

控制字的最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入到DS1302中。

位6:如果为0,则表示存取日历时钟数据,为1表示存取RAM数据; 位5至位1(A4~A0):指示操作单元的地址;

位0(最低有效位):如为0,表示要进行写操作,为1表示进行读操作。 读数据:

读数据时在紧跟8位的控制字指令后的下一个SCLK脉冲的下降沿,读出DS1302的数据,读出的数据是从最低位到最高位。 写数据:

控制字总是从最低位开始输出。在控制字指令输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入也是从最低位(0位)开始。 5、按键电路

按键电路由四个轻触开关组成,如图(9)所示。按键用来调整时间,其一端直接接到单片机的端口,另一端接地,当按下按键时,相应的端口变为低电平,通过一个与门只要这四个按键有一个按下就会在P3.2检测到一低电平就触发外部中断0进入按键调节程序中,通过与个各键相连的端口P3.4_P3.7可以判断是哪个键按下,从而作相应的操作。

15 / 53

图(9) 按键电路

6、显示电路

1602液晶也叫1602字符型液晶 它是一种专门用来显示字母、数字、符号等的点阵型液晶模块 它有若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符。显示电路采用LCD1602液晶显示,如图(10)所示,图中只画出了其相应的接口,3脚用于调节LCD1602的背光,4、5、6为LCD1602的控制口,用于控制其写入或是读出指令,7至14脚为LCD1602的数据口,将数传送到LCD1602中。

图(10) LCD1602显示电路

LCD1602的特性

+5V电压,对比度可调; 内含复位电路;

16 / 53

提供各种控制命令,如:清屏、字符闪烁、光标闪烁、显示移位等多种功能; 有80字节显示数据存储器DDRAM;

内建有160个5X7点阵的字型的字符发生器CGROM,8个可由用户自定义的5X7的字符发生器CGRAM;

基本操作时序:

读状态:输入:RS=L,RW=H,E=H;输出:DB0~DB7=状态字 ;

写指令:输入:RS=L,RW=L,E=下降沿脉冲,DB0~DB7=指令码 ;输出:无。 读数据:输入:RS=H,RW=H,E=H;输出:DB0~DB7=数据 ;

写数据:输入:RS=H,RW=L,E=下降沿脉冲,DB0~DB7=数据 ;输出:无。 LCD1602的各种指令不再一一说明。

流程图与软件设计:

1、程序流程图

主程序首先初始化定时器、LCD1602及DS1302,然后就开始查询按键,有键按下则开始调整时间和日期,若没有按下,则执行下面的时间、日期的显示,最后依次循环这些相同的操作,相应流程图如图(11)所示:

17 / 53

图(12)程序流程图

按键的检测是通过中断的办法来实现,利用按键进行间调整。 K1按下则开始设置时间及日期,同时在第一行最右端显示被选择的对象,第一次按下K1时,设置年份,若按下K3,则是减1操作,按下K2是加1操作,设置好年后,第二次按下K1时,则是设置月份,按K3减,按K2则加1,依次循环下去,则可以将时间和日期设置完毕,K4是确定键,设置好按下即可保存设置了。 2、软件设计

软件总设计:主程序首先对系统环境初始化,设置定时器T0工作模式为16位定时/计数器模式,置位总中断允许位EA,并对键盘端口置位,再对LCD1602初始化,DS1302初始化。接着扫描键盘,在键盘程序里面是对时间、日期及闹钟的调整,最下面是时间的显示。

软件程序编写:软件程序编写的好坏直接影响着系统运行情况的良好。因本程序涉及的模块较多,所以程序编写也采用模块化设计,C语言具有编写灵活、移植方便、便于模块化设计的特点,所以本系统的软件采用C51编写。

具体程序见附件一:程序 3、软件调试

在软件调试过程中,当调节时间和日期后,单片机上电后更新的是PC的时间,后来查找资料发现,是设置ds1302的问题,

对于开发板上的液晶一般RW都接的地,故不需要读液晶状态,也不需要读忙,但在仿真中还是加上了这一部分。

还有一个问题,在按键操作时有时会出现功能不稳定,这是由于按键存在抖动,所以后来加个去抖动的延时后在判断,基本就可以解决问题,

整体电路与仿真结果分析:

电子万年历硬件电路图及仿真如图(13)所示,系统由AT89C52单片机,按键扫描电

18 / 53

路、显示电路、时钟电路、晶振电路、复位电路及电源指示电路。

仿真正确显示了时间,在LCD1602中正确显示了当前日期、时间,通过按按键K1,就可以开始设置时间,依次按K1依次在年、月、日、时、分之间切换,,按K2键用于加1操作,K3键用于减1操作,K4是确定按钮。仿真正确显示了时间和日期,符合设计的要求。

图(13) 电子万年历硬件电路图

结论与心得:

在这学期的课程序设计中,收获知识的同时,还收获了阅历,收获了成熟,通过查找大量资料,请教老师,以及不懈的努力,不仅培养了独立思考、 动手制作的能力,在各种其它能力上也都有了提高。更重要的是,在课程序设计里,我们学会了很多学习的方法,知道了理论和实践的巨大差别。而这是以后最实用的,真的是受益匪浅。要面 对社会的挑战,只有不断的学习、实践,再学习、再实践。同时在与老师和同学的交流过程中,互

19 / 53

动学习,将知识融会贯通。通过自己的努力,做出了一个万年历,对以后的学习是一个莫大的鼓舞,激起了我的学习兴趣和开发创新思维。

参考文献

图书类:[1] 张毅坤 陈善久, 单片微型计算机原理及应用 西安电子科技大学出版社

[2] 张毅刚,,彭喜元,单片机原理与应用设计 电子工业出版社 [3] 赵建领 薛园园 ,零基础学单片机C语言程序设计 机械工业出版社 [4] 周向红 51单片机课程设计 华中科技大学出版社,

[5] 郭天祥 51单片机C语言教程-入门,提高,开发,拓展全攻略, 电子工业出版社 [6] 赵亮 侯国锐. 单片机C语言编程与实例 人民邮电出版社

附实验源程序: #include #include #include #define uint unsigned int #define uchar unsigned char

sbit IO= P1^0; //DS1302数据线 sbit SCLK = P1^1; //DS130时钟线 sbit RST = P1^2; //DS1302复位线

sbit RS = P2^0; sbit RW = P2^1; sbit EN = P2^2; sbit K1=P3^4;

//LCD数据/命令选择端 //LCD读/写控制 //LCD使能端 //选择

20 / 53

sbit K2=P3^5; sbit K3=P3^6;

//加 //减

sbit K4=P3^7; //确定

uchar tCount=0;

uchar MonthsDays[]={0,31,0,31,30,31,30,31,31,30,31,30,31}; uchar *WEEK[]={%uchar LCD_DSY_BUFFER1[]={\显示格式 uchar LCD_DSY_BUFFER2[]={%uchar DateTime[7]; //所读取的日期时间

char Adjust_Index=-1; //当前调节的时间对象:,,分,是,日,月,年

(1,2,3,4,6)

uchar Change_Flag[]= \ //(分,时,日,月,年)(不调节秒与

周)

/*---------延时程序------------------*/ void DelayMS(uint ms) {

uchar i;

while(ms--){for(i=0;i<120;i++);} }

//-----------向DS1302写入一字节------------------// void Write_A_Byte_TO_DS1302(uchar x) { uchar i;

for(i=0;i<8;i++){

IO=x&0x01; //每一位与1与存入IO中

SCLK=1;SCLK=0; //一个高脉冲将数据送入液晶控制器

21 / 53

} }

x>>=1; // 右移

//-----------从DS1302读取一字节------------------// uchar Get_A_Byte_FROM_DS1302() { uchar i,b=0x00; for(i=0;i<8;i++){

b |= _crol_((uchar)IO,i); }

return b/16*10+b; //返回BCD码 }

//-----------从DS1302指定位置读数据------------------// uchar Read_Data(uchar addr) {

uchar dat;

RST = 0;SCLK=0;RST=1;

//RST高电平时读/写

SCLK=1;SCLK=0;

//每一个高脉冲读取一位数据

Write_A_Byte_TO_DS1302(addr); //先写入地址 dat = Get_A_Byte_FROM_DS1302(); SCLK=1;RST=0; return dat; }

//---------向DS1302某地址写入数据--------------------// void Write_DS1302(uchar addr,uchar dat) { SCLK=0;RST=1;

Write_A_Byte_TO_DS1302(addr);

22 / 53

Write_A_Byte_TO_DS1302(dat); SCLK=0;RST=0; }

//--------------设置时间----------------// void SET_DS1302() { uchar i;

//写控制字,取消写保护 Write_DS1302(0x8E,0x00); //分时日月年依次写入 for(i=1;i<7;i++)

{ //分的起始地址10000010(0x82),后面依次是时,日,月,周,年,写入

地址每次递增2

Write_DS1302(0x80+2*i,(DateTime[i]/10<<4)|(DateTime[i]));

//高脉冲写入数据

}

Write_DS1302(0x8E,0x80); //加保护 }

//----------读取当前日期时间------------// void GetTime() {uchar i;

for(i=0;i<7;i++){ DateTime[i]=Read_Data(0X81+2*i);} }

//-----------读LCD状态------------------// uchar Read_LCD_State() { uchar state;

RS=0;RW=1;EN=1; //输出:D0~D7=状态字 DelayMS(1);

23 / 53

state=P0; //从P0口读LCD状态

EN = 0;DelayMS(1); return state; }

//-----------忙等待------------------// void LCD_Busy_Wait() {

while((Read_LCD_State()&0x80)==0x80); DelayMS(5); }

//-----------向LCD写数据------------------// void Write_LCD_Data(uchar dat) {

LCD_Busy_Wait(); RS=1;EN=0;RW=0;

//写数据,EN为高脉冲,

P0=dat;EN=1;DelayMS(1);EN=0; }

//-------------写LCD指令-------------------// void Write_LCD_Command(uchar cmd) {

LCD_Busy_Wait();

RS=0;EN=0; RW=0; //写指令,EN高脉冲,输出:D0~D7=数据 P0=cmd;EN=1;DelayMS(1);EN=0; }

//-------------LCD初始化-------------------//

24 / 53

void Init_LCD() {

Write_LCD_Command(0x38); //设置16*2显示,5*7点阵,8位数据接口 DelayMS(1);

Write_LCD_Command(0x01); //显示清零,数据指针清零 DelayMS(1);

Write_LCD_Command(0x06); //写一个字符后地址指针自动加1 DelayMS(1);

Write_LCD_Command(0x0c); //设置开显示,不显示光标 DelayMS(1); }

//------------------------------------------ //设置液晶显示位置

//------------------------------------------ void Set_LCD_POS(uchar p){

Write_LCD_Command(p|0x80);//相当于在0x80基础上加入位置量 }

//----在LCD上显示字符串---------// void Display_LCD_String(uchar p,uchar *s) {

uchar i;

Set_LCD_POS(p); for(i=0;i<16;i++) { }

25 / 53

Write_LCD_Data(s[i]); //在固定位置显示时间日期 DelayMS(1);

}

//---------日期与时间值转换为数字字符----------------// void Format_DateTime(uchar d,uchar *a) {

a[0]=d/10+'0'; a[1]=d+'0'; }

//判断是否为闰年

uchar isLeapYear(uint y)

{ return (y%4==0&&y0!=0)||(y@0==0);} //求自2000.1.1开始的任何一天是星期几 //函数没有通过,求出总天数后再求星期几 //因为求总天数可能会超出uint的范围 void RefreshWeekDay()

{ uint i,d,w=5; //已知1999.12.31是周五 for(i=2000;i<2000+DateTime[6];i++) { } d=0;

for(i=1;i

//保存星期,0~6表示星期日,星期一,二,...,六,为了与DS1302的星期

格式匹配,返回值需要加1

26 / 53

d=isLeapYear(i)?366:365; w=(w+d)%7;

DateTime[5]=(w+d)%7+1; }

//*****年月日时分++/--********// void DateTime_Adjust(char x) { {

中断二月 天数

27 / 53

switch(Adjust_Index)

case 6:

//年00-99

if(x==1&&DateTime[6]<99) DateTime[6]++; if(x==-1&&DateTime[6]>0) DateTime[6]--; //获取2月天数

MonthsDays[2]=isLeapYear(2000+DateTime[6])?29:28; //如果年份变化后当前月份的天数大于上限则设为上限 if(DateTime[3]>MonthsDays[DateTime[4]]) { DateTime[3]=MonthsDays[DateTime[4]];} RefreshWeekDay(); //刷新星期 break;

//月01-12

case 4:

if(x==1&&DateTime[4]<12) DateTime[4]++; if(x==-1&&DateTime[4]>1) DateTime[4]--;

MonthsDays[2]=isLeapYear(2000+DateTime[6])?29:28; if(DateTime[3]>MonthsDays[DateTime[4]]) { DateTime[3]=MonthsDays[DateTime[4]];} RefreshWeekDay(); break;

//日00-28、29、30、31,调节之前首先根据年份得出该年

case 3:

} }

MonthsDays[2]=isLeapYear(2000+DateTime[6])?29:28; //根据当前月份决定调节日期的上限

if(x==1&&DateTime[3]0) DateTime[3]--; RefreshWeekDay(); break;

//时

case 2:

if(x==1&&DateTime[2]<23) DateTime[2]++; if(x==-1&&DateTime[2]>0) DateTime[2]--; break;

//分

case 1:

if(x==1&&DateTime[1]<59) DateTime[1]++; if(x==-1&&DateTime[1]>0) DateTime[1]--; break;

//---定时器0每秒刷新LCD显示----// void T0_INT() interrupt 1 {

TH0=-50000/256; TL0=-50000%6;

if(++tCount !=2) return; tCount=0;

//按指定格式生成待显示的日期时间串

Format_DateTime(DateTime[6],LCD_DSY_BUFFER1+5); Format_DateTime(DateTime[4],LCD_DSY_BUFFER1+8);

28 / 53

Format_DateTime(DateTime[3],LCD_DSY_BUFFER1+11); //星期

strcpy(LCD_DSY_BUFFER1+13,WEEK[DateTime[5]-1]); //时分秒

Format_DateTime(DateTime[2],LCD_DSY_BUFFER2+5); Format_DateTime(DateTime[1],LCD_DSY_BUFFER2+8); Format_DateTime(DateTime[0],LCD_DSY_BUFFER2+11); //显示年月日,星期,时分秒

Display_LCD_String(0x00,LCD_DSY_BUFFER1); Display_LCD_String(0x40,LCD_DSY_BUFFER2); }

//----------键盘中断(INT0)-------------// void EX_INT0() interrupt 0 {

if(K1==0) //选择调整对象(Y M D H M) {

DelayMS(10); if(K1==0){

//while(K1==0);

if(Adjust_Index==-1||Adjust_Index==1) { }

Adjust_Index--;

if(Adjust_Index==5) Adjust_Index=4; LCD_DSY_BUFFER2[13]='[';

29 / 53

Adjust_Index=7;

LCD_DSY_BUFFER2[14]=Change_Flag[Adjust_Index]; //显示调节对象 }

else if(K2==0)

//加

LCD_DSY_BUFFER2[15]=']'; }

{ //while(K2==0);

DelayMS(10); if(K2==0)

DateTime_Adjust(1); }

else if(K3==0) { }

else if(K4==0) {

//减

DelayMS(10);//while(K3==0);

if(K3==0)

DateTime_Adjust(-1);

//确定

//while(K4==0); DelayMS(10); if(K4==0){ SET_DS1302();

//将调整后的时间写入DS1302

LCD_DSY_BUFFER2[13]=' '; LCD_DSY_BUFFER2[14]=' '; LCD_DSY_BUFFER2[15]=' '; Adjust_Index=-1;

30 / 53

} }

}

void main() { Init_LCD();

//液晶初始化

IE=0x83; //允许INT0,T0中断,EA=1,,ET0=1,EX0=1 IP=0x01; //设置外部中断0为高级中断

IT0=0x01; //外部中断0为电平触发,低电平有效 TMOD=0x01; //设置定时器T0工作方式为方式1, TH0=-50000/256; TL0=-50000%6; TR0=1; while(1) {

//如果未执行调整操作则正常读取当前时间 } }

if(Adjust_Index==-1) GetTime();

//启动定时器

//装入初始值,定时1秒

31 / 53

毕业论文(设计)

基于单片机的简易十字路口交通灯设计

Sigle—chip Processor––based Design for Traffic Light

姓 名: 张 焰

学 号: 050801245

系 别: 计算机科学与工程系

专 业: 计算机科学与技术

年 级: 05

指导教师: 陈建能

2009年3月20日

摘要

近年来随着科技的飞速发展,单片机的应用正在不断深入,同时带动传统控制检测技术日益更新。在实时检测和自动控制的单片机应用系统中,单片机往往作为一个核心部件来使用,仅单片机方面知识是不够的,还应根据具体硬件结构软硬件结合,加以完善。

十字路口车辆穿梭,行人熙攘,车行车道,人行人道,有条不紊。那么靠什么来实现这井然秩序呢?靠的就是交通信号灯的自动指挥系统。交通信号灯控制方式很多。本系统采用MCS-51系列单片机AT89C52为中心器件来设计交通灯控制器,实现了能根据实际车流量通过8051芯片的P3口设置红、绿灯燃亮时间的功能;红绿灯循环点亮,倒计时剩5秒时黄灯闪烁警示(交通灯信号通过P1口输出,显示时间通过P0口输出至双位数码管)。本系统设计周期短、可靠性高、实用性强、操作简单、维护方便、扩展功能强。

关键词:单片机;交通灯

Abstract

In recent years, with the rapid development of science and technology, the application of SCM is going deep, driving the traditional detection techniques to renew day by day. In the real-time examination and in the automatic control monolithic integrated circuit application system, the monolithic integrated circuit often took a core part uses. The monolithic integrated circuit aspect knowledge is only insufficient, but should also act according to the concrete hardware architecture software and hardware union, to be improved.

The intersection vehicles shuttle, the pedestrian is bustling, car dealership traffic lane, person sidewalk, methodical. Then depending on what to realizes this orderly order? the traffic lights on the automatic control system. There are great number kinds of modes to control the traffic lights. The system uses a series of MCS-51 as the center AT89C52 single-chip device designed to control the traffic lights, so as to realize the function of setting red, green light time by 8051 chip’s P3 port according to the actual traffic flows, lighting the red-light and green-light by turn and lighting the yellow-light to warm while 5 seconds left(outputting the traffic light signal by P1,outpuing the time by P0 and showing the time on double-digits nixie tube). Short of the design cycle, high reliability, practical, simple operation, easy maintenance, the expansion of powerful is this system. Key words: SCM; MCU; traffic light

I

目 录

中英文摘要………………………………………… (Ⅰ) 1 设计要求……………………………………… (1) 2 设计目的………………………………………… (1) 3 方案比较、设计与论证……………………………(1) 4 原理分析……………………………………………(2) 4.1 交通灯显示时序的理论分析…………………………………… (2) 4.2交通灯显示的理论分析……………………………………… (4) 5 程序设计流程图………………………………………(4) 6 总体设计、电路图与程序……………………………(6) 6.1芯片选择………………………………………………… (6) 6.2设计电路图………………………………………………… (7) 6.3 PROTEUS仿真图………………………………………… (8) 6.4交通灯程序……………………………………………… (9) 7 仿真测试、数据及结果分析…………………………(15) 8 总结与展望…………………………………………(15) 致谢…………………………………………………(17) 参考文献……………………………………………(18) 附录…………………………………………………(19)

1 设计要求

1.1 程序开始运行先南北段通行、东西段禁止60s,后东西段通行、南北段禁止60s,依此循环。

1.2 系统分三种工作模式:正常模式、繁忙模式、特殊模式,并且通过三个按钮“正常”、“繁忙”、“特殊”可相互转化。 1.3 正常模式:

直行时间显示数码管显示60。此时南北段直行通行(绿灯)、东西段禁止(红灯)40s,南北段人行道通行(绿灯),东西段人行道禁止(红灯),同时南北段和东西段方向的数码管分别从40s和60s开始倒计时,至最后5s时南北段绿灯变成黄灯闪烁;此后南北段左拐(左拐灯亮)通行、东西段禁止(红灯)20s,南北段、东西段人行道都禁止(红灯),同时南北段和东西段方向的数码管都从20s开始倒计时,至最后5s时南北段左拐灯变成黄灯闪烁;再后东西段直行通行(绿灯)、南北段禁止(红灯)40s,东西段人行道通行(绿灯),南北段人行道禁止(红灯),同时东西段和南北段方向的数码管分别从40s和60s开始倒计时,至最后5s时东西段绿灯变成黄灯闪烁;最后东西段左拐(左拐灯亮)通行、南北段禁止(红灯)20s,东西段、南北段人行道都禁止(红灯),同时东西段和南北段方向的数码管都从20s开始倒计时,至最后5s时东西段左拐灯变成黄灯闪烁。

1.4 繁忙模式:

繁忙指示灯亮,南北段、东西段的通行时间改为45s,其中左拐的时间改为15s,其它与正常模式类似。 1.5 特殊模式:

特殊模式灯亮,南北段、东西段的通行时间改为75s,其中左拐的时间改为20s,其它与正常模式类似。

2 设计目的

2.1 2.2 2.3 2.4 2.5

了解交通灯管理的基本工作原理 熟悉AT89C52的工作原理和应用编程

熟悉AT89C52并行接口的各种工作方式和应用

熟悉AT89C52计数器/定时器的工作方式和应用编程外部中断的方法 掌握多位LED显示问题的解决

3 方案比较、设计与论证

3.1 显示界面方案

3.1.1 倒计时显示

该系统要求完成倒计时的功能。因只需显示数字,基于上述原因,我们考虑完全采用数码管显示,四个路口分别采用一个二位阴极数码管即可。

3.1.2 状态灯显示

该系统要求完成状态灯显示的功能。求于简单,我们把各个路口的红灯和黄灯设成直行和左拐两个通行方式所共有,也就是说,一个路口只需四个状态灯,一个直行通行的绿灯,一个左拐通行的绿灯,一个共有的红灯,一个共有的黄灯。

3.2 输入方案:

该系统要求能手动改变东西与南北的通行时间、紧急情况处理,我们采用扩

展I/O

口方法,在外部中断P32口上扩展三个中断口,分别连接三个按钮。该方案的优点是:使用灵活,并且可提供较多I/O口,节省了AT89C52的中断口资源。

4 原理分析

4.1 交通灯显示时序的理论分析

下图所示为一种红绿灯规则的状态图。

图4.1 状态S1南北图4.2 状态S2南北 直行通行 左拐通行

图4.3 状态S3东图4.4 状态S4东

西直行通行 西左拐通行 共四种状态,分别设定为S1、S2、S3、S4,交通灯以这四种状态为一

个周期,循环执行如下图所示:

图4.5 交通灯状态循环图

依据上述车辆行驶的状态图,可以列出各个路口灯的逻辑表如下表所示(其中逻辑值“1”代表直行通行,逻辑值“0”代表禁止通行,逻辑值“L”代表左拐通行):

S1的状态 逻辑值 显示时间 S2的状态 逻辑值 显示时间 S3的状态 逻辑值 显示时间 S4的状态 E

E 0 S 1 W 0 N 1 正常模式下为40S E 0 S L W 0 N L 正常模式下为20S E 1 S 0 W 1 N 0 正常模式下为40S S W N 逻辑值 显示时间 L 0 L 0 正常模式下为20S 程序就是在上述四种状态下循环转化的。一个周期四个状态,在正常模式下共花费2分钟。

4.2 交通灯显示的理论分析

4.2.1 倒计时显示的理论分析 利用定时器中断,设置 TH0=TH1=(65536-50000)/256,即每0.05秒中断一次。每到第20次中断即过了20*0.05秒=1秒时,使时间的计数值减1,便实现了倒计时的功能。

4.2.2 状态灯显示的理论分析

黄灯闪烁同样可以利用定时器中断。每到第10次中断即过了10*0.05秒=0.5秒时,使黄灯标志位反置,即可让黄灯1秒闪烁一次。

5 程序设计流程图

T0响应 N 0.5s到 Y 南北黄灯标志位为1 N 东西黄灯标志位为1 N N 1s到 Y 倒计时减1,计数值置0 返回 Y 东西黄灯位置反 Y 南北黄灯位置反

图5.1 定时器0中断流程图

开始 AT89C52初始化 南北直行通行东西禁止 N 通行35秒 Y 南北黄灯闪烁 东西直行通行南北禁止 N 闪烁5秒 Y N 通行35秒 Y 东西黄灯闪烁 南北左拐通行东西禁止 N 通行15秒 Y 南北黄灯闪烁 N 闪烁5秒 Y 东西左拐通行南北禁止 N 闪烁5秒 Y N 通行15秒 Y 东西黄灯闪烁 N 闪烁5秒 Y

图5.2 主程序流程图

INT0响应 关中断 Y “正常”键按下 N “繁忙”键按下 N “特殊”键按下 N 开中断 返回 正常模式设置 Y 繁忙模式设置 Y 特殊模式设置 图5.3 外部中断0中断流程图

6 总体设计与电路图

6.1 芯片选择

AT89C52是美国ATMEL公司生产的低电压,高性能CMOS 8位单片机,有40个引脚,32个外部双向输入/输出(I/O)端口,同时内含2个外中断口,3个16位可编程定时计数器,2个全双工串行通信口,2个读写口线,片内含8k bytes的可反复擦写的Flash只读程序存储器和256 bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,与标准MCS-51指令系统及8052产品引脚兼容,片内置通用8位中央处理器(CPU)和Flash存储单元,可以按照常规方法对其进行编程,也可以在线编程。其将通用的微处理器和Flash存储 器结合在一起,特别是可反复擦写的Flash存储器可有效地降低开发成本。

本文来源:https://www.bwwdw.com/article/57h.html

Top