本课程设计旨在驾驭本专业学生理论指导实践能力以及电子产品工程设计与开发能力。本实践课所要达到的主要目的是:
1、通过本次课程设计,是对学生综合能力的检,提高学生综合运用专业知识,强化单片机应用系统设计与防震能力。 2、本次课程设计是在生产实习所完成的“单片机核心板+电子钟模块+MP3模块+RFID模块+无线传输模块+GPS模块+脉搏传感模块”的基础上设计该硬件系统的工作程序。 1.2课程设计的基本内容
1、在生产实习设计单片机硬件系统的基础上,设计相应的应用软件系统。 2、在LCD1602上显示学号程序设计。 3、基于DS1302的实时时钟软件设计。 4、基于DS18B20的温度测量软件设计。
5、基于TL1838A的红外遥控解码软件设计。
6、设计应用软件系统框图和流程图,完成所设计软件的调试。 1.3课程设计的教学要求
1、通过资料查阅及学习了解单片机应用系统的软件设计方法及单片机编程、软硬件联机调试技巧。
2、独立设计并编写下列应用程序: (1)LCD1602学号显示程序; (2)DS1302实时时钟程序; (3)DS18B20温度测量程序;
(4)TL1838A红外遥控解码程序;
3、独立完成所设计程序与硬件系统的联机仿真。 二、整机系统框图(硬件、软件)
该设计方案是以STC12C5A60S2单片机为核心,采用LCD液晶屏幕显示模块、实时时钟模块、温度测量模块、红外遥控解码等模块所构建的系统,能在LCD1602液晶屏上显示当前的日期(年、月、日)、时间(时、分、秒)数据、当前环境温度值和红外遥控解码值。用户可通过遥控器或单片机核心板上的按键来进行日期和时间的设置。本系统设计大部分功能由软件来实现,电路简单明了,系统稳定性也得到大大提高。 1、总体硬件设计框架图:
2、总体软件设计框架图 ///////
三、整机硬件电路原理图(见99SE图) 1、核心板电路原理图 2、蜂鸣器驱动电路 3、按键电路
4、单片机复位电路
5、LCD1602液晶显示电路 6、电子钟模块接口电路 四、软件系统设计思想 ////////////
五、系统软件资源分配表(调试程序、工作程序) //////////////
六、显示学号的调试程序流程图、程序源代码
1、程序流程图 ///////////
2、程序源代码
/*************LCD1602***************************/ #include #define LCD_Data P0 /**************函数声明**********************/ void Lcd_Int(void); void huanying_show(void); void dongtai_show(void); char string1[]=\" LIU JING \";//LIU JING char string2[]=\" 080104020013 \";//080104020013 /***************函数功能:主函数***************************/ void main() {Lcd_Int(); //1602初始化 while(1) {huanying_show(); dongtai_show();} } /********************************************* 函数功能:延时1ms 注:不同单片机不同晶振需要对此函数进行修改 *********************************************/ void Lcd_delay1ms() {unsigned char i,j; for(i=0;i<90;i++) for(j=0;j<33;j++) ;} /********************************************* 函数功能:延时若干毫秒 入口参数:n *********************************************/ void Lcd_delay(unsigned int n) {unsigned int i; for(i=0;i 返回值:result。result=1,忙碌;result=0,不忙 *********************************************/ bit Lcd_BusyTest(void) {bit result; RS=0; //根据规定,RS为低电平,RW为高电平时,可以读状态 RW=1; E=1; //E=1,才允许读写 _nop_(); //空操作 _nop_(); _nop_(); _nop_(); //空操作四个机器周期,给硬件反应时间 result=BF; //将忙碌标志电平赋给result E=0; return result;} /********************************************* 函数功能:将模式设置指令或显示地址写入液晶模块 入口参数:dictate *********************************************/ void Lcd_WriteCom(unsigned char dictate) {while(Lcd_BusyTest()==1); //忙就等待 RS=0; //根据规定,RS和RW同时为低电平时,可以写入指令 RW=0; E=0; //E置低电平(写指令时,就是让E从0到1发生正跳变,所以应先置\"0\" _nop_(); _nop_(); //空操作两个机器周期,给硬件反应时间 LCD_Data=dictate; _nop_(); _nop_(); _nop_(); _nop_(); //空操作四个机器周期,给硬件反应时间 E=1; //E置高电平 _nop_(); _nop_(); _nop_(); _nop_(); //空操作四个机器周期,给硬件反应时间 E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令 } /********************************************* 函数功能:指定字符显示的实际地址 入口参数:x 注:此函数已经加上了0x80,故只需写上实际地址就行 *********************************************/ void Lcd_WriteAddress(unsigned char x) {Lcd_WriteCom(x|0x80); //显示位置的确定方法规定为\"80H+地址码x\" } /********************************************* 函数功能:将数据(字符的标准ASCII码)写入液晶模块 入口参数:y(为字符常量) *********************************************/ void Lcd_WriteData(unsigned char y) {while(Lcd_BusyTest()==1); RS=1; //RS为高电平,RW为低电平时,可以写入数据 RW=0; E=0; //E置低电平(写指令时,就是让E从0到1发生正跳变,所以应先置\"0\" LCD_Data=y; //将数据送入P0口,即将数据写入液晶模块 _nop_(); _nop_(); _nop_(); _nop_(); //空操作四个机器周期,给硬件反应时间 E=1; //E置高电平 _nop_(); _nop_(); _nop_(); _nop_(); //空操作四个机器周期,给硬件反应时间 E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令 } /**********函数功能:对LCD的显示模式进行初始化设置******************/ void Lcd_Int(void) {Lcd_delay(15); //延时15ms,首次写指令时应给LCD一段较长的反应时间 Lcd_WriteCom(0x38);//显示模式设置:16*2显示,5*7点阵,8位数据接口 Lcd_delay(5); //延时5ms Lcd_WriteCom(0x38); Lcd_delay(5); Lcd_WriteCom(0x38); //3次写设置模式 Lcd_delay(5); Lcd_WriteCom(0x0C); //显示模式设置:显示开,有光标,光标不闪烁 Lcd_delay(5); Lcd_WriteCom(0x06); //显示模式设置:光标右移,字符不移 Lcd_delay(5); Lcd_WriteCom(0x01); //清屏幕指令,将以前的显示内容清除 Lcd_delay(5); } /*****************函数功能:LCD的显示********************/ void huanying_show(void) {unsigned int Lcd_i; Lcd_WriteCom(0x01); //清显示:清屏幕指令 Lcd_delay(1); Lcd_WriteAddress(0x00); //设置显示位置为第一行的第1个字 Lcd_delay(1); for(Lcd_i=0;Lcd_i<16;Lcd_i++) //显示字符LIU JING { Lcd_WriteData(string1[Lcd_i]); Lcd_delay(150); } Lcd_WriteAddress(0x40); //设置显示位置为第二行的第1个字 for(Lcd_i=0;Lcd_i<16;Lcd_i++) //显示字符080104020013 { Lcd_WriteData(string2[Lcd_i]); Lcd_delay(150); } Lcd_delay(1000); } //右侧移位进来 void dongtai_show(void) {unsigned int Lcd_i; Lcd_WriteCom(0x01); //清显示:清屏幕指令 Lcd_delay(2); Lcd_WriteAddress(0x10); //设置显示位置为最右侧 Lcd_delay(2); for(Lcd_i=0;Lcd_i<16;Lcd_i++) //显示字符LIU JING { Lcd_WriteData(string1[Lcd_i]); Lcd_delay(2); } Lcd_WriteAddress(0x50); //设置显示位置为最右侧 for(Lcd_i=0;Lcd_i<16;Lcd_i++)//显示字符080104020013 { Lcd_WriteData(string2[Lcd_i]); Lcd_delay(2); } for(Lcd_i=0;Lcd_i<16;Lcd_i++) //开始左移 { Lcd_WriteCom(0x18); //左移指令 Lcd_delay(400); } Lcd_delay(1000); Lcd_WriteCom(0x08); Lcd_delay(400); Lcd_WriteCom(0x0c); Lcd_delay(400); Lcd_WriteCom(0x08); Lcd_delay(400); Lcd_WriteCom(0x0c); Lcd_delay(400); Lcd_WriteCom(0x08); Lcd_delay(400); Lcd_WriteCom(0x0c); Lcd_delay(400); Lcd_WriteCom(0x08); Lcd_delay(400); Lcd_WriteCom(0x0c); Lcd_delay(1); Lcd_WriteCom(0x01); //清显示:清屏幕指令 Lcd_delay(1); } 七、实时时钟、温度测量、红外遥控解码等程序的流程图、程序源代码 (一)流程图 1、实时时钟模块 图7.1.1为电子时钟设计框图,系统由主控制器STC12C5A60S2、时钟电路DS1302、显示电路LCD1602及键扫描电路组成。 电子万年历的程序主要包括3个方面的内容:一是DS1302从单片机中读取数据进行计数,二是利用按键进行时间的调整,三是MAX7219从单片机中读取数 据驱动LED数码管显示时间。 图7.1.1电子时钟设计框图 STC12C5A60S2单片机主要I/O口的分配, P1.4、P1.5、P1.6分别接DS1302的SCLK,MCUIO,RST端,P0口接LCD1602八位数据口,P2.7 、P3.6、P3.7分别接LCD1602的E、RW、RS端,P2.0-P2.3分别接按键K1-K4.下图7.1.2为电子时钟程序设计流程图。 图7.1.2电子时钟程序设计流程图 2、温度测量模块 温度测量程序主要包括主程序,读出温度子程序,温度转换子程序,计算温度子程序,显示 数据子程序等。 主程序的主要功能是负责温度的实时显示、读出并处理DS18B20的测量的当前温度值,温度测量每1s进行一次。这样可以在一秒之内测量一次被测温度,其系统程序流程见图7.2.1所示。 初始发DS18B20复位命令 调用显示 图7.2.1温度测量主程序流程图 3、红外遥控解码模块 (1)遥控器发射端程序流程图: 结束 图7.2.2读温度流程图 发温度转换移入温度暂存器 1S发跳过ROM命令 N 发读取温度命令 Y Y 初次读取操作,CRC校验 Y N 读出温度值温度计算8字节完? N Y CRC校验正?确? N (2)遥控器接收端程序流程图: (二)程序源代码 1、实时时钟模块 /*************DS1302时钟显示程序**********************/ #include sbit SCLK=P1^4; //DS1302时钟控制总线 sbit DATA_IO=P1^5; //DS1302数据传送总线 sbit RESET=P1^6; //DS1302复位总线 sbit ACC0=ACC^0; //移位时的第0位 sbit ACC7=ACC^7; //移位时的第7位 uchar table1[16] ; uchar table2[16] ; uchar second,minute,hour,day,month,year;//定义秒分时日月年变量 /*********DS1302时钟部分子程序****************************/ //向DS1302写入一个字节的函数 void SentByte(uchar byte) {uchar i; ACC=byte; for(i=8;i>0;i--) //相当于汇编中的RRC { DATA_IO=ACC0;//将自己的最低位传到时钟的数据总线上 SCLK=1;//时钟上升沿发送数据有效 SCLK=0;//清时钟总线 ACC=ACC>>1;//将累加器中的数据右移1位 } } //从DS1302读取一个字节函数 uchar ReceiveByte(void) { uchar i; for(i=8;i>0;i--) //相当于汇编中的RRC { ACC=ACC>>1;//将累加器中的数据右移1位 ACC7=DATA_IO;//将数据线上的1位数据存入累加器中 SCLK=1;//时钟上升沿发送数据有效 SCLK=0;//清时钟总线 } return(ACC);//函数最终返回读取的1字节数据 } //向DS1302的某个地址里写入数据函数 void WriteClock(uchar Address,uchar Data)//Address:要写入数据的DS1302地址;Data:要写的数据 {RESET=0;//复位引脚为低电平所有数据传送中止 SCLK=0;//清时钟总线 RESET=1;//复位引脚为高电平逻辑控制有效 delay(10); SentByte(Address);//写入地址命令 SentByte(Data);//写入1字节数据 SCLK=1;//时钟总线置高 RESET=0;//逻辑操作完毕,清复位总线 } //读取DS1302某地址的数据 uchar ReadClock(uchar Address)//Address:要读取数据的DS1302地址 {uchar Data;//定义数据变量 RESET=0;//复位引脚为低电平所有数据传送终止 SCLK=0;//清时钟总线 RESET=1;//复位引脚为高电平逻辑控制有效 delay(1); SentByte(Address|0X01);//写入地址命令,读取地址为写入地址+1H Data=ReceiveByte();//读取1字节数据 SCLK=1;//时钟总线置高 RESET=0;//逻辑操作完毕,清复位总线 return(Data);//返回读取的数据 } //时钟芯片初始化函数 void Init_Clock(void) { uchar Second=ReadClock(0x81);//读取秒数据 if(Second&0x80)//判断时钟芯片是否关闭 { WriteClock(0x8e,0x00);//写入允许 WriteClock(0x8c,0x11);//一下写入初始化时间11年11月25日15:05:00 WriteClock(0x88,0x11); WriteClock(0x86,0x25); WriteClock(0x84,0x15); WriteClock(0x82,0x05); WriteClock(0x80,0x00); WriteClock(0x8e,0x80);//禁止写入 } } void Read_Date(void) { uchar ReadValue;//定义变量 ReadValue=ReadClock(0x81); second=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);//将读取的秒数据的BCD码转换成十进制数据 ReadValue=ReadClock(0x83); if (ReadValue>0x60) ReadValue=ReadClock(0x83); minute=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将读取的分数据的BCD码转换成十进制数据 ReadValue=ReadClock(0x85); if (ReadValue>0x24) ReadValue=ReadClock(0x85); hour=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将读取的时数据的BCD码转换成十进制数据 ReadValue=ReadClock(0x87); day=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将读取的日数据的BCD码转换成十进制数据 ReadValue=ReadClock(0x89); month=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将读取的月数据的BCD码转换成十进制数据 ReadValue=ReadClock(0x8d); year=((ReadValue&0xf0)>>4)*10 + (ReadValue&0x0F); //将读取的年数据的BCD码转换成十进制数据 table1[0]='D'; table1[1]='a'; table1[2]='t'; table1[3]='a'; table1[4]=':'; table1[5]='2'; table1[6]='0'; table1[7]=0x30+year/10; table1[8]=0x30+year%10; table1[9]='-'; table1[10]=0x30+month/10; table1[11]=0x30+month%10; table1[12]='-'; table1[13]=0x30+day/10; table1[14]=0x30+day%10; table1[15]=' '; table2[0]=' '; table2[1]=' '; table2[2]=' '; table2[3]=' '; table2[4]=0x30+hour/10; table2[5]=0x30+hour%10; table2[6]=':'; table2[7]=0x30+minute/10; table2[8]=0x30+minute%10; table2[9]=':'; table2[10]=0x30+second/10; table2[11]=0x30+second%10; table2[12]=' '; table2[13]=' '; table2[14]=' '; table2[15]=' '; } //时钟显示函数 void show_Data() {uint i; Lcd_WriteAddress(0x00); //设置显示位置为第一行的第1个字 for(i=0;i<16;i++) //显示字符 { Lcd_WriteData(table1[i]); delay(10); } Lcd_WriteAddress(0x40); //设置显示位置为第二行的第1个字 for(i=0;i<16;i++)//显示字符 { Lcd_WriteData(table2[i]); delay(10); } } void main() { Lcd_Int(); //1602初始化 huanying_show(); Lcd_WriteCom(0x01); Init_Clock(); //将1302初始化 while(1) { Read_Date(); show_Data();} } 2、温度测量模块 /*********DS18B29温度显示程序**********************/ #include #define uchar unsigned char #define uint unsigned int sbit DQ=P1^7; //DS18B20与单片机连接口 unsigned char a,b; uint tvalue;//温度值 uchar disdata[12]; void delay_18B20(unsigned int i)//延时1微秒 { while(i--); _nop_(); _nop_(); } void delay1ms(uint m)//延时m毫秒 { while(m--) delay_18B20(1000); } void DS18B20rst()/*ds18b20复位*/ { DQ = 1; //DQ复位 delay_18B20(10); //延时 DQ = 0; //DQ拉低 delay_18B20(600); DQ = 1; //拉高 _nop_(); _nop_(); while(DQ); _nop_(); _nop_(); while(~DQ); _nop_(); } uchar DS18B20rd()/*读数据*/ { unsigned char i; unsigned char dat; DQ = 1; for (i=8;i>0;i--) { dat>>=1; DQ = 0; //给脉冲信号 _nop_(); _nop_(); _nop_(); _nop_(); DQ = 1; //给脉冲信号 delay_18B20(5); if(DQ) {dat|=0x80;} delay_18B20(50); } return(dat); } void DS18B20wr(uchar wdata)/*写数据*/ { unsigned char d; int i; DQ = 1; for (i=8; i>0; i--) { d=wdata&0x01; wdata>>=1; if(d) {DQ = 0; delay_18B20(2); DQ=1; delay_18B20(60); } else {DQ=0; delay_18B20(60); DQ=1; _nop_(); _nop_(); } } } read_temp()/*读取温度值并转换*/ { DS18B20rst(); DS18B20wr(0xcc);//*跳过读序列号*/ DS18B20wr(0x44);//*启动温度转换*/ delay1ms(30); DS18B20rst(); DS18B20wr(0xcc);//*跳过读序列号*/ DS18B20wr(0xbe);//*读取温度*/ a=DS18B20rd(); b=DS18B20rd(); tvalue=b; tvalue=tvalue<<8; tvalue=tvalue|a; if(tvalue&0x8000) tvalue=~tvalue+1; tvalue=tvalue*(0.625); return(tvalue); } void DS18B20disp()//温度值显示 { uint i; disdata[0]='T'; disdata[1]='e'; disdata[2]='m'; disdata[3]='p'; disdata[4]='t'; disdata[5]=':'; disdata[6]=(int)tvalue/1000+0x30;//百位数 disdata[7]=(int)(tvalue%1000)/100+0x30;//十位数 disdata[8]=(int)(tvalue%100)/10+0x30;//个位数 disdata[9]='.'; disdata[10]=(int)tvalue%10+0x30;//小数位 disdata[11]='C'; Lcd_WriteAddress(0x40); //设置显示位置为第二行的第1个字 for(i=0;i<12;i++) //显示字符 { Lcd_WriteData(disdata[i]); delay(100); } } void initLCD() { Lcd_Int(); huanying_show();} int main() { a=0x00; b=0x00; initLCD(); Lcd_WriteCom(0x01); //清屏幕指令,将以前的显示内容清除 delay1ms(1000); while(1) { read_temp();//读取温度 DS18B20disp();//显示 } return 0; } 3、红外遥控解码模块 #include #define uchar unsigned char uchar flag; //标志变量,0x01为下降沿进,0x02为引导码,0x03为连发码 unsigned int sys,dat; uchar da[4]; sbit out=P3^3; sbit o1=P3^4; sbit o2=P3^5; /**************************************/ void adjust (void) { if(flag==0x01) { start(); if(flag==0x02) // { getdata(); o1=0; } else if(flag==0x03) // { o2=0; } } } void getdata(void) {int i; int j; for(j=0;j<4;j++) for(i=0;i<8;i++) { da[j]=da[j]>>1; while(~out); TL1=0x00; TH1=0x00; TR1=1; while(out); TR1=0; if(TH1>7) da[j]|=0x80; } } void start (void) { while(~out); TR0=0; if(TH0>60) { EA=0; TR1=1; while(out); TR1=0; if(TH1>30) flag=0x02; else if(TH1>15) flag=0x03; } else { flag=0x00; EA=1; } } void initintterrupt(void) { TL0=0x00; TH0=0x00; TL1=0x00; TH1=0x00; IT1=1; EX1=1; EA=1;} void Int1_Routine(void) interrupt 2 { EA=0; TL0=0x00; TH0=0x00; TL1=0x00; TH1=0x00; TMOD=0x91; TR0=1; ET0=1; flag=0x01; EA=1;} int main(void) {out=1; o1=1; o2=1; initintterrupt(); while(1) {EA=0; adjust(); EA=1; } return 0; } 八、整机硬件、软件联机仿真调试中出现的问题,解决方案、结果 九、设计总结 十、参考文献 因篇幅问题不能全部显示,请点此查看更多更全内容