十字路口交通信号灯的控制系统设计
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
单片机原理与应用课程设计报告
实验名称:十字路口交通信号灯的控制系统设计学生姓名: xxx
班级:电信1101
学号: 07031101xx
成绩:
指导教师:
二○一四年六月九日
目录
一、绪论 (3)
1.1 交通灯研究的背景和意义 (3)
1.2 交通灯国内外发展概况 (3)
1.3 本课程设计的要求 (4)
二、硬件电路 (5)
2.1 硬件电路框图 (5)
2.2 电路原理图 (5)
2.3 芯片介绍 (6)
2.3.1 MCS-51单片机 (6)
2.3.2 MAX232芯片 (7)
2.3.3 PCF8563芯片 (8)
2.3.4 24C04芯片 (10)
2.3.5 7407芯片 (11)
三、程序系统 (12)
3.1 程序框图 (12)
3.2 程序 (12)
四、心得体会 (26)
一、绪论
1.1 交通灯研究的背景和意义
交通是城市经济活动的命脉,对城市经济发展、人民生活水平的提高起着十分重要的作用。
城市交通问题是困扰城市发展、制约城市经济建设的重要因素。
城市道路增长的有限与车辆增加的无限这一对矛盾是导致城市交通拥挤的根本原因。
城市街道网络上的交通容量的不断增加,表明车辆对道路容量的要求仍然很高,短期内还不可能改变。
自从开始使用计算机控制系统后,不管在控制硬件里取得什么样的实际进展,交通控制领域的控制逻辑方面始终没能取得重大突破。
因此,研究基于智能集成的城市交通信号控制系统具有相当的学术价值和实用价值。
把智能控制引入到城市交通控制系统中,未来的城市交通控制系统才能适应城市交通的发展。
从长远来看该研究具有巨大的现实意义。
1.2 交通灯国内外发展概况
随着经济的发展,城市现代化程度不断提高,交通需求和交通量迅速增长,城市交通网络中交通拥挤日益严重,道路运输所带来的交通拥堵、交通事故和环境污染等负面效应也日益突出,逐步成为经济和社会发展中的全球性共同问题。
交通问题已经日益成为世界性的难题,城市交通事故、交通阻塞和交通污染问题愈加突出。
交通系统正是解决这一问题的途径之一。
智能交通系统是将先进的信息技术、数据通讯传输技术、电子传感技术、电子控制技术及计算机处理技术等有效的集成运用于整个地面交通管理系统而建立的一种在大范围内、全方位发挥作用的实时、准确、高效的综合交通运输管理系统。
对城市交通流进行智能控制,可以使道路畅通,提高交通效率。
合理进行交通控制可以对交通流进行有效的引导和调度,使交通保持在一个平稳的运行状态,从而避免或缓和交通拥挤状况,大大提高交通运输的运行效率,还可以减少交通事故,增加交通安全,降低污染程度,节省能源消耗,本文就是通过对交叉路口交通信号的智能控制,达到优化路口交通流的目的
进入20世纪70年代,随着计算机技术和自动控制技术的发展,以及交通流理论的不断完善,交通运输组织与优化理论和技术水平不断提高,控制手段越来越先进,形成了一批商水平有实效的城市道路交通控制系统。
早在1977年,Pappis等人就将模糊控制运用到交通控制上,通过建立规则库或是专家系统对各种交通状况进行模糊控制,并取得了很好的效果。
近年来,欧美日本等相继建立了智能交通控制系统。
在这些系统中,大部分都在路口附近安装磁性环路检测器,还使用了新型检测器等技术和设备。
这些现代化设备技术加上控制理论和现代化科学管理技术,使得交通控制系统日益完善。
随着一些研究控制理论的学者投身到交通控制的研究中,在交通信号控制领域提出了一些新方法、新思路。
如静态多段配时控制、
准动态多段配时控制、最优控制、大系统递阶控制、模糊控制、神经网络控制,网络路由控制等。
模糊交通控制已经成为了交通信号控制的主流方向之一。
国内外很多学者都进行了此类研究。
交通系统作为一个时变的、具有随机性的复杂系统,传统的人为设定多种方案或是建立各种预测模型均比较困难。
城市交通控制研究的起源比较早。
1868年,英国伦敦燃汽信号灯的问世,标志着城市交通控制的开始。
1913年,在美国俄亥俄州的Cleveland市出现了世界上最早的交通信号控制。
1926年美国的芝加哥市采用了交通灯控制方案,每个交叉口设有唯一的交通灯,适用于单一的交通流。
从此,交通控制技术和相关的控制算法得到了发展和改善,提高了交通控制的安全性、有效性,并减少了对环境的影响。
虽然模糊控制能有效处理模糊信息,但是产生的规则比较粗糙,利用规则表查表进行控制,运算速度虽然比较快,但没有自学习功能。
而且这些研究有些以相序固定为前提。
不能保证相序与实际交通流状况的一致性,影响了绿灯时间的利用率。
有些研究则提出了可变相序的模糊控制方法,提高了绿灯时间的利用率,弥补了相序固定的缺点,但同时也存在一些不足。
例如目前应用比较好的交通系统:SCOOT(经典交通系统),他们都是主要采用统计模型和经典算法。
但城市交通系统是一个复杂的、随机性很强的巨型系统,要想建立实用性较强的数学模型是十分困难。
利用模糊控制智能控制技术进行交叉口信号灯控制能取得比定时控制与感应控制更好的效果,是今后单交叉路口信号灯控制的主要研究方向。
1.3 本课程设计的要求
(1)可按不同的时间段采用不同的控制方案,方案如下:
①0~5点,东西南北黄灯闪(红绿不亮),1次1秒
②5~7点,东西南北绿灯各亮30s
③7~12点,东西方向绿灯各亮30s,南北方向绿灯亮60s
④12~18点,东西方向绿灯亮60s,南北方向绿灯亮30s
⑤18~24点,东西南北方向红灯同时亮30s
(2)当上电开始时,东西方向的红灯同时亮3秒
(3)东西南北方向有倒计时提示
(4)控制方案在停电后不丢失
(5)系统时钟在停电后仍然正常计时
(6)控制方案可通过232串口下载
(7)画出交通信号灯控制系统的电路原理图
(8)编制交通信号灯控制系统软件
二、硬件电路
2.1 硬件电路框图
根据课程设计设计要求,完成了十字路口交通信号灯控制系统的硬件框图,见图2-1 单片机MCS5124C04
PCF 85637407LED
MAX 232单片机最小系统 图2-1 十字路口交通信号灯控制系统的硬件框图 2.2 电路原理图 根据上述的硬件框图,设计十字路口交通信号灯控制系统的原理图,见图2-2
图2-2 十字路口交通信号灯控制系统
2.3 芯片介绍
2.3.1 MCS-51单片机
MCS-51单片机是美国INTE公司于1980年推出的产品,与MCS-48单片机相比,它的结构更先进,功能更强,在原来的基础上增加了更多的电路单元和指令,指令数达111条。
MCS-51具有比较大的寻址空间,地址线宽达16条,即外部数据存储器和程序存储器的寻址范围达216=64kB。
它集成了几乎完善的8位中央处理单元,处理功能强,中央处理单元中集成了方便灵活的专用寄存器,硬件的加、减、乘、除法器和布尔处理机及各种逻辑运算和转移指令,这给应用提供了极大的便利。
另外,MCS-51的指令系统近乎完善,指令系统中包含了全面的数据传送指令、完善的算术和逻辑运算指令、方便的逻辑操作和控制指令、对于编程来说,是相当灵活和方便的。
MCS-51把微型计算机的主要部件都集成在一块心片上,使得数据传送距离大大缩短,可靠性更高,运行速度更块。
由于属于芯片化的微型计算机,各功能部件在芯片中的布局和结构达最优化,抗干扰能力加强,工作亦相对稳定。
因此,在工业测控系统中,使用单片机是最理想的选择。
单片机属于典型的嵌入式系统,所以它是低端控制系统最佳器件。
单片机引脚排列及功能以及引脚见图2-3
图2-3 MCS-51单片机引脚图
2.3.2 MAX232芯片
MAX232芯片是美信(MAXIM)公司专为RS-232标准串口设计的单电源电平转换芯片,使用+5v单电源供电。
MAX220–MAX249系列线驱动器/接收器,专为EIA/TIA-232E 以及V.28/V.24通信接口设计,尤其是无法提供±12V电源的应用。
MAX232芯片的作用是将单片机输出的TTL电平转换成PC机能接收的232电平或将PC机输出的232电平转换成单片机能接收的TTL电平。
的作用是将单片机输出的TTL电平转换成PC机能接收的232电平或将PC机输出的232电平转换成单片机能接收的TTL电平。
主要特点:
1、符合所有的RS-232C技术标准
2、只需要单一5V电源供电
3、片载电荷泵具有升压、电压极性反转能力,能够产生+10V和-10V电压
4、功耗低,典型供电电流5mA
5、内部集成2个RS-232C驱动器
6、高集成度,片外最低只需4个电容即可工作。
MAX232芯片引脚排列及功能以及引脚见图2-4和表2-1
图2-4 MAX232芯片引脚
表2-1 MAX232芯片引脚功能
引脚名称功能说明
引脚
号
1 DCD 载波检测
2 RXD 接收数据
3 TXD 发送数据
4 DTR 数据终端准备好
5 SG 信号地
6 DSR 数据准备好
7 RTS 请求发送
8 CTS 清除发送
9 RI 振铃提示
2.3.3 PCF8563芯片
PCF8563时钟芯片是一款工业级低功耗的CMOS实时时钟/日历芯片。
它提供一个可编程时钟输出,一个中断输出和掉电检测器,所有的地址和数据通过IC总线接口串行传递。
最大总线速度为400Kb/s,每次读写数据后,内嵌的字地址寄存器会自动产生增量。
主要的性能指标:
1、PCF8583是P H IL IPS公司制造的带有256×8bit RAM的8引脚日历/时钟芯片。
2、两线串行I2C总线接口,内含完整的振荡,分频,上电复位电路,并具备计时,日历,定时,闹钟
和中断输出功能。
3、带256字节静态RAM
4 、可以做到1/100秒采集,报警控制输出. 。
5、具有定时和时钟两种模式进行控制操作。
6、结构简单,占用单片机端口少,功耗极低。
PCF8563芯片引脚排列及功能以及引脚见表2-2
表2-2 PCF8563芯片引脚功能
符号管
脚号
描述
OS
CI
1振荡器输入
OS
CO
2振荡器输出
/INT
3
中断输出(开漏:低电平有效)
VSS4地
SDA5串行数据I/O
SCL6串行时钟输入
CLK
OUT
7时钟输出(开漏)VDD8正电源
2.3.4 24C04芯片
24c04是采用铁电技术生产的EEPROM ,掉电后数据不丢失。
相比传统的EEPROM 具有寿命长,读写速度快的优点,采用I2C 总线与外界通讯,容量应该是512字节。
主要用于存储掉电后需要保存的数据。
24C04芯片引脚排列及功能以及引脚见图2-5和表2-3
图2-5 24C04芯片引脚排列
表2-3 24C04芯片引脚功能 引脚
号
引脚名称 功能说明 1
A0 地址输入。
A2,A1,和A0是器件地址输入引脚。
24C04使用A2和A1输入引脚作为硬件地址,总线上课同时级联4个24C04器件,A0为空脚,可接地。
2
A1 3
A2 4
GND 地 5 SDA 串行地址和数值输入\输出。
SDA 是双向串行数据传输引脚,
漏极开路,需外接上拉电阻到VCC 。
6 SCL 串行时钟输入。
SCL 同步数据传输,,上升沿数据写入,下降
沿数据读出。
7 WP 写保护。
WP 引脚提供硬件数据保护。
当WP 接地时,允许
数据正常读写操作;当WP 接VCC ,写保护,只读。
8
VCC 正电源
2.3.5 7407芯片
7407主要起着缓冲的作用,就是缓冲单片机的承受能力,如果没有7407,那么单片机承受的电流能能力很小,那么的工作电流就受到了限制,亮度不够亮,而加上7407就可以缓冲单片机的灌电流,从而减小限流电阻的值,使流过二极管的电流增强,从而灯变的更亮。
7407芯片引脚排列及功能以及引脚见图2-6和表2-4
图2-6 7407芯片引脚排列
表2-4 7407芯片引脚功能
引脚名称功能说明
1A-6A 输入端
1Y-6Y 输出端
三、程序系统
3.1 程序框图
为了满足该系统的功能输出,采用了以下程序流程,见程序框图3-1
开始
复位
东西南北方向红灯全部亮5秒
东西方向通行30秒,南北方向亮红灯
黄灯闪烁3秒
南北方向通行25秒,东西方向亮红灯
黄灯闪烁3秒
结束
图3-1 系统程序框图
3.2 程序
程序:#include<reg52.h>
#include<intrins.h>
#define _Nop() _nop_() //定义空指令
#define DataPort P0 //定义数据端口
#define RST_CLR RST=0//电平置低
#define RST_SET RST=1//电平置高
#define ds1302_sec_add 0x80 //秒数据地址
#define ds1302_min_add 0x82 //分数据地址
#define ds1302_hr_add 0x84 //时数据地址
#define ds1302_date_add 0x86 //日数据地址
#define ds1302_month_add 0x88 //月数据地址
#define ds1302_day_add 0x8a //星期数据地址
#define ds1302_year_add 0x8c //年数据地址
#define ds1302_control_add 0x8e //控制数据地址
#define ds1302_charger_add 0x90
#define ds1302_clkburst_add 0xbe
//双向数据
#define IO_CLR IO=0//电平置低
#define IO_SET IO=1//电平置高
#define IO_R IO //电平读取
//时钟信号
#define SCK_CLR SCK=0//时钟信号
#define SCK_SET SCK=1//电平置高
extern unsigned char time_buf1[8];//空年月日时分秒周
extern unsigned char time_buf[8] ;//空年月日时分秒周
sbit LATCH1=P2^2;//定义锁存使能端口段锁存
sbit LATCH2=P2^3;// 位锁存
sbit SCK=P2^4;
sbit IO=P2^5;
sbit RST=P2^6;
sbit led1=P1^0; //东西红
sbit led2=P1^1; //东西绿
sbit led3=P1^2; //东西黄
sbit led4=P1^3; //南北红
sbit led5=P1^4; //南北绿
sbit led6=P1^5; //南北黄
sbit SDA=P2^1; //模拟I2C数据传送位
sbit SCL=P2^0; //模拟I2C时钟控制位
bit ack; //应答标志位
unsigned char code dofly_DuanMa[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};// 显示段码值0~9 unsigned char code dofly_WeiMa[]={0xfe,0xfd,0xfb};//分别对应相应的数码管点亮,即位码unsigned char TempData[8]; //存储显示值的全局变量
/*------------------------------------------------
uS延时函数,含有输入参数unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编,大致延时
长度如下T=tx2+5 uS
------------------------------------------------*/
void DelayUs2x(unsigned char t)
{
while(--t);
}
/*------------------------------------------------
mS延时函数,含有输入参数unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编
------------------------------------------------*/
void DelayMs(unsigned char t)
{
while(t--)
{
//大致延时1mS
DelayUs2x(245);
DelayUs2x(245);
}
}
/*------------------------------------------------
显示函数,用于动态扫描数码管
输入参数FirstBit 表示需要显示的第一位,如赋值2表示从第三个数码管开始显示如输入0表示从第一个显示。
Num表示需要显示的位数,如需要显示99两位数值则该值输入2
------------------------------------------------*/
void Display(unsigned char FirstBit,unsigned char Num)
{
static unsigned char i=0;
DataPort=0; //清空数据,防止有交替重影
LATCH1=1; //段锁存
LATCH1=0;
DataPort=dofly_WeiMa[i+FirstBit]; //取位码
LATCH2=1; //位锁存
LATCH2=0;
DataPort=TempData[i]; //取显示数据,段码
LATCH1=1; //段锁存
LATCH1=0;
i++;
if(i==Num)
i=0;
}
unsigned char time_buf1[8] = {20,10,6,5,12,55,00,6};//空年月日时分秒周
unsigned char time_buf[8] ; //空年月日时分秒周/*------------------------------------------------
向DS1302写入一字节数据
------------------------------------------------*/
void Ds1302_Write_Byte(unsigned char addr, unsigned char d)
{
unsigned char i;
RST_SET; //写入目标地址:addr
addr = addr & 0xFE; //最低位置零
for (i = 0; i < 8; i ++)
{
if (addr & 0x01)
{
IO_SET;
}
else
{
IO_CLR;
}
SCK_SET;
SCK_CLR;
addr = addr >> 1;
} //写入数据:d
for (i = 0; i < 8; i ++)
{
if (d & 0x01)
{
IO_SET;
}
else
{
IO_CLR;
}
SCK_SET;
SCK_CLR;
d = d >> 1;
}
RST_CLR; //停止DS1302总线
}
/*------------------------------------------------
从DS1302读出一字节数据
------------------------------------------------*/
unsigned char Ds1302_Read_Byte(unsigned char addr)
{
unsigned char i;
unsigned char temp;
RST_SET;
//写入目标地址:addr
addr = addr | 0x01;//最低位置高
for (i = 0; i < 8; i ++)
{
if (addr & 0x01)
{
IO_SET;
}
else
{
IO_CLR;
}
SCK_SET;
SCK_CLR;
addr = addr >> 1;
}
//输出数据:temp
for (i = 0; i < 8; i ++)
{
temp = temp >> 1;
if (IO_R)
{
temp |= 0x80;
}
else
{
temp &= 0x7F;
}
SCK_SET;
SCK_CLR;
}
RST_CLR; //停止DS1302总线
return temp;
}
/*------------------------------------------------
向DS1302写入时钟数据------------------------------------------------*/ void Ds1302_Write_Time(void)
{
unsigned char i,tmp;
for(i=0;i<8;i++)
{ //BCD处理
tmp=time_buf1[i]/10;
time_buf[i]=time_buf1[i]%10;
time_buf[i]=time_buf[i]+tmp*16;
}
Ds1302_Write_Byte(ds1302_control_add,0x00); //关闭写保护Ds1302_Write_Byte(ds1302_sec_add,0x80); //暂停
//Ds1302_Write_Byte(ds1302_charger_add,0xa9); //涓流充电Ds1302_Write_Byte(ds1302_year_add,time_buf[1]); //年
Ds1302_Write_Byte(ds1302_month_add,time_buf[2]); //月
Ds1302_Write_Byte(ds1302_date_add,time_buf[3]); //日
Ds1302_Write_Byte(ds1302_day_add,time_buf[7]); //周
Ds1302_Write_Byte(ds1302_hr_add,time_buf[4]); //时
Ds1302_Write_Byte(ds1302_min_add,time_buf[5]); //分
Ds1302_Write_Byte(ds1302_sec_add,time_buf[6]); //秒
Ds1302_Write_Byte(ds1302_day_add,time_buf[7]); //周
Ds1302_Write_Byte(ds1302_control_add,0x80); //打开写保护}
/*------------------------------------------------
从DS1302读出时钟数据
------------------------------------------------*/
void Ds1302_Read_Time(void)
{
unsigned char i,tmp;
time_buf[1]=Ds1302_Read_Byte(ds1302_year_add); //年
time_buf[2]=Ds1302_Read_Byte(ds1302_month_add); //月
time_buf[3]=Ds1302_Read_Byte(ds1302_date_add); //日
time_buf[4]=Ds1302_Read_Byte(ds1302_hr_add); //时
time_buf[5]=Ds1302_Read_Byte(ds1302_min_add); //分
time_buf[6]=(Ds1302_Read_Byte(ds1302_sec_add))&0x7F;//秒
time_buf[7]=Ds1302_Read_Byte(ds1302_day_add); //周
for(i=0;i<8;i++)
{ //BCD处理
tmp=time_buf[i]/16;
time_buf1[i]=time_buf[i]%16;
time_buf1[i]=time_buf1[i]+tmp*10;
}
}
/*------------------------------------------------
DS1302初始化
------------------------------------------------*/
void Ds1302_Init(void)
{
RST_CLR; //RST脚置低
SCK_CLR; //SCK脚置低
Ds1302_Write_Byte(ds1302_sec_add,0x00);
}
/*------------------------------------------------
启动总线
------------------------------------------------*/
void Start_I2c()
{
SDA=1; //发送起始条件的数据信号
_Nop();
SCL=1;
_Nop(); //起始条件建立时间大于4.7us,延时
_Nop();
_Nop();
_Nop();
_Nop();
SDA=0; //发送起始信号
_Nop(); //起始条件锁定时间大于4μ
_Nop();
_Nop();
_Nop();
_Nop();
SCL=0; //钳住I2C总线,准备发送或接收数据_Nop();
_Nop();
}
/*------------------------------------------------
结束总线
------------------------------------------------*/
void Stop_I2c()
{
SDA=0; //发送结束条件的数据信号
_Nop(); //发送结束条件的时钟信号
SCL=1; //结束条件建立时间大于4μ
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SDA=1; //发送I2C总线结束信号
_Nop();
_Nop();
_Nop();
_Nop();
}
/*----------------------------------------------------------------
字节数据传送函数
函数原型: void SendByte(unsigned char c);
功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对此状态位进行操作.(不应答或非应答都使ack=0 假)
发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
------------------------------------------------------------------*/
void SendByte(unsigned char c)
{
unsigned char BitCnt;
for(BitCnt=0;BitCnt<8;BitCnt++) //要传送的数据长度为8位{
if((c<<BitCnt)&0x80)SDA=1; //判断发送位
else SDA=0;
_Nop();
SCL=1; //置时钟线为高,通知被控器开始接收数据位_Nop();
_Nop(); //保证时钟高电平周期大于4μ
_Nop();
_Nop();
_Nop();
SCL=0;
}
_Nop();
_Nop();
SDA=1; //8位发送完后释放数据线,准备接收应答位_Nop();
_Nop();
SCL=1;
_Nop();
_Nop();
_Nop();
if(SDA==1)ack=0;
else ack=1; //判断是否接收到应答信号
SCL=0;
_Nop();
_Nop();
}
/*----------------------------------------------------------------
字节数据传送函数
函数原型: unsigned char RcvByte();
功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),发完后请用应答函数。
------------------------------------------------------------------*/ unsigned char RcvByte()
{
unsigned char retc;
unsigned char BitCnt;
retc=0;
SDA=1; //置数据线为输入方式
for(BitCnt=0;BitCnt<8;BitCnt++)
{
_Nop();
SCL=0; //置时钟线为低,准备接收数据位
_Nop();
_Nop(); //时钟低电平周期大于4.7us
_Nop();
_Nop();
_Nop();
SCL=1; //置时钟线为高使数据线上数据有效
_Nop();
_Nop();
retc=retc<<1;
if(SDA==1)retc=retc+1; //读数据位,接收的数据位放入retc中
_Nop();
_Nop();
}
SCL=0;
_Nop();
_Nop();
return(retc);
}
/*------------- 应答子函数
原型: void Ack_I2c(void); ----------------------------------------------------------------*/
void Ack_I2c(void)
{
SDA=0;
_Nop();
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop(); //时钟低电平周期大于4μ
_Nop();
_Nop();
_Nop();
SCL=0; //清时钟线,钳住I2C总线以便继续接收
_Nop();
_Nop();
}
/*----非应答子函数
原型: void NoAck_I2c(void); ----------------------------------------------------------------*/
void NoAck_I2c(void)
{
SDA=1;
_Nop();
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop(); //时钟低电平周期大于4μ
_Nop();
_Nop();
_Nop();
SCL=0; //清时钟线,钳住I2C总线以便继续接收
_Nop();
_Nop();
}
/*--------------------------------------------向有子地址器件发送多字节数据函数
函数原型: bit ISendStr(unsigned char sla,unsigned char suba,ucahr *s,unsigned char no);
功能: 从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件
地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。
如果返回1表示操作成功,否则操作有误。
注意:使用前必须已结束总线。
----------------------------------------------------------------*/ bit ISendStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no)
{
unsigned char i;
Start_I2c(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(0);
SendByte(suba); //发送器件子地址
if(ack==0)return(0);
for(i=0;i<no;i++)
{
SendByte(*s); //发送数据
DelayMs(1);
if(ack==0)return(0);
s++;
}
Stop_I2c(); //结束总线
return(1);
}
bit IRcvStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no) {
unsigned char i;
Start_I2c(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(0);
SendByte(suba); //发送器件子地址
if(ack==0)return(0);
Start_I2c();
SendByte(sla+1);
if(ack==0)return(0);
for(i=0;i<no-1;i++)
{
*s=RcvByte(); //发送数据
Ack_I2c(); //发送就答位
s++;
}
*s=RcvByte();
NoAck_I2c(); //发送非应位
Stop_I2c(); //结束总线
return(1);
}
void main()
{
unsigned char dofly[6]={0,0,0,0,0,0}; // 定义临时变量,赋初值0
unsigned i;
dofly[0]=led1;
dofly[1]=led2;
dofly[2]=led3;
dofly[3]=led4;
dofly[4]=led5;
dofly[5]=led6;
led1=1;
led4=1;
DelayMs(180); //上电红灯同时亮三秒
led1=0;
led4=0;
while(1)
{
Ds1302_Init(); //初始化时钟芯片
Ds1302_Read_Time(); //读出时钟芯片数据
if(0<=time_buf[4]<5) //0~5点黄灯亮闪
{
IRcvStr(0xae,4,&dofly,6); //调用存储数据
led3=1;
led6=1;
DelayMs(30);
led3=0;
led6=0;
ISendStr(0xae,4,&dofly,6); //写入24c02
}
else if(5<=time_buf[4]<7) //5~7点东西南北绿灯各亮30s
{
IRcvStr(0xae,4,&dofly,6); //调用存储数据
for(i=0;i<30;i++)
{
led2=1;
led4=1;
DelayMs(60);
led2=0;
led4=0;
TempData[0]=dofly_DuanMa[i/10];//倒计时分解显示信息,如要显示23,则23/10=2 23%10=3
TempData[1]=dofly_DuanMa[i%10];
Display(0,2); //从第一个数码管开始显示
ISendStr(0xae,4,&dofly,6); //写入24c02
}
for(i=0;i<30;i++)
{
led5=1;
led1=1;
DelayMs(60);
led5=0;
led1=0;
TempData[0]=dofly_DuanMa[i/10];//倒计时分解显示信息,如要显示23,则23/10=2 23%10=3
TempData[1]=dofly_DuanMa[i%10];
Display(2,2); //从第三个数码管开始显示
ISendStr(0xae,4,&dofly,6); //写入24c02
}
}
else if(7<=time_buf[4]<12) // 7~12点东西绿灯亮30s,南北绿灯亮60s {
IRcvStr(0xae,4,&dofly,6); //调用存储数据
for(i=0;i<30;i++)
{
led2=1;
led4=1;
DelayMs(60);
led2=0;
led4=0;
TempData[0]=dofly_DuanMa[i/10];//倒计时分解显示信息,如要显示23,则23/10=2 23%10=3
TempData[1]=dofly_DuanMa[i%10];
Display(0,2); //从第一个数码管开始显示
ISendStr(0xae,4,&dofly,6); //写入24c02
}
for(i=0;i<60;i++)
{
led5=1;
led1=1;
DelayMs(60);
led5=0;
led1=0;
TempData[0]=dofly_DuanMa[i/10];//倒计时分解显示信息,如要显示23,则23/10=2 23%10=3
TempData[1]=dofly_DuanMa[i%10];
Display(2,2); //从第三个数码管开始显示
ISendStr(0xae,4,&dofly,6); //写入24c02
}
}
else if(12<=time_buf[4]<18) //12~18点东西绿灯亮60s,南北绿灯亮30s {
IRcvStr(0xae,4,&dofly,6); //调用存储数据
for(i=0;i<60;i++)
{
led2=1;
led4=1;
DelayMs(60);
led2=0;
led4=0;
TempData[0]=dofly_DuanMa[i/10];//倒计时分解显示信息,如要显示23,则23/10=2 23%10=3
TempData[1]=dofly_DuanMa[i%10];
Display(0,2); //从第一个数码管开始显示
ISendStr(0xae,4,&dofly,6); //写入24c02
}
for(i=0;i<30;i++)
{
led5=1;
led1=1;
DelayMs(60);
led5=0;
led1=0;
TempData[0]=dofly_DuanMa[i/10];//倒计时分解显示信息,如要显示23,则23/10=2 23%10=3
TempData[1]=dofly_DuanMa[i%10];
Display(2,2); //从第三个数码管开始显示
ISendStr(0xae,4,&dofly,6); //写入24c02
}
}
else if(18<=time_buf[4]<24) //18~24点东西南北方向各亮30s
{
IRcvStr(0xae,4,&dofly,6); //调用存储数据
for(i=0;i<30;i++)
{
led2=1;
led4=1;
DelayMs(60);
led2=0;
led4=0;
TempData[0]=dofly_DuanMa[i/10];//倒计时分解显示信息,如要显示23,则23/10=2 23%10=3
TempData[1]=dofly_DuanMa[i%10];
Display(0,2); //从第一个数码管开始显示
ISendStr(0xae,4,&dofly,6); //写入24c02
}
for(i=0;i<30;i++)
{
led5=1;
led1=1;
DelayMs(60);
led5=0;
led1=0;
TempData[0]=dofly_DuanMa[i/10];//倒计时分解显示信息,如要显示23,则23/10=2 23%10=3
TempData[1]=dofly_DuanMa[i%10];
Display(2,2); //从第三个数码管开始显示
ISendStr(0xae,4,&dofly,6); //写入24c02
}
}
}
}
四、心得体会
通过这次交通灯的课程设计,使我得到了一次用专业知识、专业技能分析和解决现实问题的能力。
使我在单片机的基本原理、单片机应用学习过程中,以及在常用编程设计思路技巧的掌握方面都能向前迈了一大步,为日后成为一名合格的应用型人才打下良好的基础。
综合课程设计让我把以前学习到的知识得到巩固和进一步的提高认识,对已有知识有了更深层次的理解和认识。
在此,由于自身能力有限,在课程设计中碰到了很多的问题,我通过查阅相关书籍、资料以及和周围同学交流得到解决。
单片机的课程设计也让我更加充分地认识自身的一些不好毛病。
一,前期准备工作做的不够好,想的还算蛮多,可就是没落实。
先说开始做单片机这个大作业,就表现自己有畏难情绪,其实当时找到好几个论文和项目报告,但是交通灯的设计复杂而且得充分考虑到实用性,所以实践的过程是相当困难的。
这次的交通灯设计,做的不是很理想,还有好些人性化的智能功能可以加上去,像通过测流量来自动调整通行时间,加个监控电路,看门狗电路等。
二,行动起来不是很卖力,虽说动手还算早,但是每天的进展却不大,特别是程序那部分这是非常考验学习能力和编程能力,可以说做与玩相伴而行。
本次的课程设计,充分意识到自己所学的东西还是非常有限的,不过通过设计,还是学到了一些书本上没有学到的东西,为自己以后的学习起了很大的帮助。
就我个人而言,很深刻地体会到一点,那就是我们在设计过程中一定要有一个整体的清晰的思路,知道自己的设计的对象的基本功能和核心器件的适用及其作用,只要把握住这些主要方面,一些小问题都将围绕着这些主要问题而逐步得到解决。
同时我也懂得,在整个设计过程中,生活中也一样,一定要意志坚定,克服自己的畏难情绪,这样才能将事情做好,才能干出一番成就。
我觉得这种课程设计的实践真的不错,通过这些项目练习,我自学能力,解决实际问题的能力得到提高,可以说是对综合素质全面提升,我想这也是我们上大学应真正学到的。