NORTH CHINA UNIVERSITY OF SCIENCE AND TECHNOLOGY
单片机课程设计报告
学生姓名: 王文帅
学 号: 201214570405 学 院: 信息工程学院 专业班级: 12级电信四班 指导教师: 崔博
2015年 06 月 21 日
一、课程设计目的
PIC单片机课程设计报告
本课程设计是在《PIC单片机原理及应用》及《单片机C语言编程》课程的基础上,通过硬件设计、软件编程及仿真调试的实践,进一步掌握PIC单片机的应用方法,熟练掌握PICC C语言程序的编写与调试,是毕业设计前的一次重要实践,为今后走上工作岗位打下坚实的单片机应用基础。
二、设计题目及要求
2.1 设计题目:
基于PIC16F877单片机的多功能电子时钟 2.2 功能实现:
实时时钟显示,时间可调;实时温度显示,并具有超限报警功能。输出显示采用LCD1602或LED七段数码显示器。 2.3 设计要求:
自己设计硬件和程序编程,画出完整的电路原理图,用Multisim或Proteus仿真,最终可实现脱机运行。
三、设计原理说明
3.1 时钟模块
DS1307是美国DALLAS公司推出的I2C总线接口实时时钟芯片,它可于CPU 工作,不受CPU主晶振及其电容的影响,且计时准确,月累积误差一般小于10秒。芯片还具有主电源掉电情况下的时钟保护电路,DS1307的时钟靠后备电池维持工作,拒绝CPU对其读出和写入访问。同时还具有备用电源自动切换控制电路,因而可在主电源掉电和其它一些恶劣环境场合中保证系统时钟的定时准确性。
DS1307具有产生秒、分、时、日、月、年等功能,且具有闰年自动调整功能。同时,DS1307芯片内部还集成有一定容量、具有掉电保护特性的静态RAM,可用于保存一些关键数据。 3.2 显示模块
如用LCD1602作为显示设备,要求显示屏分两行显示,第一行显示日期(年-月-日)和星期,第二行显示时间(时:分:秒)和温度。显示秒由00一直加到59,分钟数也由00加到59,小时采用24小时制,由00加到23,如此循环显示。
- 1 -
3.3 按键模块
PIC单片机课程设计报告
按键用来作为时间调整。要求至少设计4个按键,按键1作为设置键;按键2、按键3分别为增加、减少键,在设置键按下时,此两个按键方有效;按键4是确定键,在设置键按下时方才有效。 3.4 温度采集模块
DS18B20是美国DALLAS公司推出的单总线数字温度传感器。DS18B20内部集成了温敏元件、数据转换芯片、存储器芯片和计算机接口芯片等多功能模块。其主要技术特点有:具有独特的单线接口方式;可以通过数据线供电,具有超低功耗工作方式;测温范围为-55℃~125℃,测温精度为0.5℃;温度转换精度9~12位可编程,直接将温度转换值以二进制数码的方式串行输出。
四、硬件原理图
(含原理图、电路仿真图)
时间显示:
按下温度键temp后显示温度:
- 2 -
PIC单片机课程设计报告
- 3 -
PIC单片机课程设计报告
五、软件设计
(含流程图、带注释的程序清单)
#include #define _XTAL_FREQ 1000000UL #define speak RC3 #define ON 0 #define OFF 1 #define DQ RB5 //设置数据方向 #define DQ_IN() TRISB5 = 1 //输入 #define DQ_OUT() TRISB5 =0 //输出 //DS1302引脚定义 #define IO RA1 #define SCLK RA0 #define RST RA2 - 4 - //DS1302端口数据读写方向 #define SET_IO_RD() TRISA1 = 1 #define SET_IO_WR() TRISA1 = 0 #define LCD_CLS 0x01 #define LCD_HOME 0x02 #define LCD_SETMODE 0x04 #define LCD_SETVISIBLE 0x08 #define LCD_SHIFT 0x10 #define LCD_SETFUNCTION 0x20 #define LCD_SETCGADDR 0x40 #define LCD_SETDDADDR 0x80 #define PORT_LCD_DAT PORTD #define PORT_LCD_CTL PORTC #define TRIS_LCD_DAT TRISD #define TRIS_LCD_CTL TRISC #define RS RC5 #define RW RC6 #define E RC7 extern unsigned char DateTime[]; PIC单片机课程设计报告 extern char WEEK[][4]= {\"SUN\//0,1,2,3,4,5,6分别对应周日,周一至周六 //所读取的日期时间(秒,分,时,日,月,星期,年) unsigned int temper; unsigned int settempe = 570 ; unsigned char DateTime [7]; unsigned char tmp[]=\"0000\"; //向DS1302写入一个字节 unsigned char RB1_FLAG = 0; const unsigned char tone[]={108,102,91,86,77,68,61,57};//发声的频率常数 - 5 - PIC单片机课程设计报告 void delay18us(unsigned char x) //18us,每次加1,增加9us { unsigned char i; for(;x>0;x--) { for(i=0;i<1;i++); } } void delay1ms(unsigned int x) { } void write_byte_to_DS1302(unsigned char x) { unsigned char i; SET_IO_WR(); for(i=0x01; i !=0x00; i <<= 1) } //从DS1302读取1字节 unsigned char get_byte_form_DS1302() { unsigned char i,dat =0x00; SET_IO_RD(); for(i = 0; i < 8; i++) { - 6 - unsigned char i; for(;x>0;x--) for(i=0;i<165;i++); { } if (x & i) IO = 1; else IO =0; SCLK = 0; SCLK =1; __delay_us(10); SCLK = 1; SCLK=0; PIC单片机课程设计报告 if(IO) dat |= (0x01<} return (dat>>4)*10 + (dat&0x0F); } //从DS1302指定位置读数据 unsigned char read_data(unsigned char addr) { unsigned char dat; RST = 1; write_byte_to_DS1302(addr); dat = get_byte_form_DS1302(); RST = 0; return dat; } //向DS1302指定地址写数据 void Write_DS1302(unsigned char addr,unsigned char dat) { RST = 1; write_byte_to_DS1302(addr); write_byte_to_DS1302(dat); RST = 0; } void port_init() { ADCON1 = 0X06; //RA设置为普通IO口 TRISA = 0X00; //端口A设置为输出 OPTION = 0X00; //端口B弱上拉使能 TRISB = 0xFF; - 7 - PORTC = 0X00; TRISC = 0X00; //端口C设置为输出 PORTD = 0X00; TRISD = 0X00; //端口D设置为输出 PIC单片机课程设计报告 speak=0; } void song(unsigned char x) { unsigned char i,j; for(i=0;i<60;i++) { for(j=0;j<3;j++) { speak = 1; delay18us(tone[x]); speak = 0; //翻转发声 delay18us(tone[x]); } } } void keyscan() { unsigned char a ,b ; DateTime[0]=0; Write_DS1302(0x8E,0x00); // Write_DS1302(0x80,0x80); // if(RB2==0) //小时+1 { - 8 - PIC单片机课程设计报告 DateTime[2] = DateTime[2]+1; //第三个元素小时+1 if(DateTime[2] == 24) DateTime[2]= 0;//当变为24H时,小时位归零 a = DateTime[2]/10*16+DateTime[2]%10; //变成16进制数据 Write_DS1302(0x84,a); } if(RB3==0) { } if(RB4==0) { } } //DS1302初始化 void init_DS1302() - 9 - DateTime[1] = DateTime[1]+1; //第二个元素分钟+1 if(DateTime[1] == 60) DateTime[1]= 0;//当变为60min时,小时位归零 b = DateTime[1]/10*16+DateTime[1]%10; //变成16进制数据 Write_DS1302(0x82,b); song(3); while(RB4 == ON); Write_DS1302(0x80,0x00); // 调整完毕后启动时钟运行 Write_DS1302(0x8E,0x00); // 禁止写 RB1_FLAG = 0; // 将RB1按下后产生的标志清除 { unsigned char second_REG; PIC单片机课程设计报告 second_REG = read_data(0x81); //读取秒寄存器当前值 //如果高位CH为1,则表示当前DS1302振荡器出于待机状态 //这时需要将CH(clock halt flag)位设为0,打开振荡器使时钟运行 if ((second_REG & 0x80) == 0x80) { Write_DS1302(0x8E,0x00) ; //写控制字节,取消写保护 Write_DS1302(0x80,second_REG & 0x7F) ; //0x80地址不变,设高位CH=0 Write_DS1302(0x8E,0x80) ; //加保护 } } //读取当前日期 void getDateTime() { //Write_DS1302(0x8E,0x00); //允许写操作 unsigned char i, addr = 0x81; for (i=0; i<7; i++) { } //********LCD显示子函数***********************// //**********结束LCD子函数********************// void LCD_BUSY_WAIT() //忙等待 { unsigned char status; TRIS_LCD_DAT = 0xFF; - 10 - DateTime[i] = read_data(addr); } addr +=2; RS = 0; RW = 1; do { E =1; NOP(); status = PORT_LCD_DAT; E = 0; } while (status & 0x80); } void Write_LCD_Command(unsigned char cmd) //{ TRIS_LCD_DAT = 0x00; PORT_LCD_DAT = cmd; PORT_LCD_CTL = TRIS_LCD_CTL = 0x00; RS = 0; RW = 0; E = 1 ; NOP(); E = 0 ; LCD_BUSY_WAIT(); } void Write_LCD_Data(unsigned char dat) //{ TRIS_LCD_DAT = 0x00; PORT_LCD_DAT = dat; RS = 1; RW = 0; E = 1 ; NOP(); E = 0; - 11 - PIC单片机课程设计报告 写LCD命令 写LCD寄存器数据 LCD_BUSY_WAIT(); } void LCD_Initialize() { Write_LCD_Command(0x38); __delay_ms(2); Write_LCD_Command(0x01); __delay_ms(2); Write_LCD_Command(0x06); __delay_ms(2); Write_LCD_Command(0x0C); __delay_ms(2); } PIC单片机课程设计报告 void LCD_ShowString(unsigned char r, unsigned char c, char *str) { unsigned char i = 0; if(r == 0) Write_LCD_Command(0x80 | c); else if(r == 1) Write_LCD_Command(0xC0 | c); for (i = 0; i < 16 && str[i]!= '\\0'; i++) Write_LCD_Data(str[i]); } void display_str(unsigned char line,unsigned char location,unsigned char str)//line行,location列,str字符 { RS=0; RW=0; E=1; delay1ms(1); if (line==0) //line=0,第一行 - 12 - } PORT_LCD_DAT=0x80+location; PIC单片机课程设计报告 if (line==1) //line=1,第二行 PORT_LCD_DAT=0xC0+location; E=0; LCD_BUSY_WAIT() ; Write_LCD_Data(str); void Set_LCD_POS(unsigned char r,unsigned char c) //设置显示起始位置 { if(r == 0) Write_LCD_Command(0x80 | c); else if(r == 1) Write_LCD_Command(0xC0 | c); } //********18B20子程序********// //包括函数:void Wait_18B20();// // void delay15us(unsigned int x) { } void reset() { //x必须大于0 do {x--;} while(x); unsigned char state_DQ=1; while(state_DQ) { DQ_OUT(); //延时721us delay15us(); DQ_IN(); delay15us(5); //延时61us - 13 - } if (DQ) state_DQ=1; PIC单片机课程设计报告 //若DS18B20无应答,循环检查 else state_DQ=0; //检测到DS18B20应答低电平信号 //延时490us delay15us(43); } void write_one_byte(unsigned char data) { } - 14 - unsigned char i,tmp; for(i=0;i<8;i++) { } tmp=data&0x01; data>>=1; if (tmp) { } else { } DQ_OUT(); delay15us(5); DQ_IN(); NOP();NOP(); //延时61us DQ_OUT(); NOP();NOP(); DQ_IN(); delay15us(5); //延时61us //tmp=1时 unsigned char read_one_byte() PIC单片机课程设计报告 { unsigned char i,data; for(i=0;i<8;i++) { data>>=1; DQ_OUT(); NOP(); DQ_IN(); NOP();NOP(); if (DQ==1) data=data|0x80; delay15us(5); } return(data); } unsigned int get_temperature() { unsigned char tmpA,tmpB; reset(); write_one_byte(0xcc); write_one_byte(0x44); delay1ms(800); reset(); write_one_byte(0xcc); write_one_byte(0xbe); tmpA=read_one_byte(); tmpB=read_one_byte(); temper=tmpB*256+tmpA; //延时61us //定义读出RAM的高低位变量 //写跳过ROM命令,因为总线上只有一个DS18B20 //启动DS18B20温度转换命令 //如果再写命令必须再次复位 //写跳过ROM命令,因为总线上只有一个DS18B20 //读内部RAM中9字节的内容命令 //读内部RAM 低八位温度 //读内部RAM 高八位温度 - 15 - return(temper); } void temp () { unsigned char tmpB,tmpA; unsigned int results; display_str(1,10,tmp[0]); // display_str(1,11,tmp[1]); // display_str(1,12,tmp[2]); // display_str(1,13,'.'); // display_str(1,14,tmp[3]); // display_str(1,15,0XDF); // display_str(1,16,'C'); // delay1ms(200); results=get_temperature(); if(results>=0x1000) { results=results^0xFFFF; results++; tmpB=results/256; tmpA=(unsigned char)results; results>>=4; tmp[0]=0x2D; } else { tmpB=results/256; tmpA=(unsigned char)results; results>>=4; tmp[0]=results/100+0x30; - 16 - PIC单片机课程设计报告 在指定位置显示百位/负号 在指定位置显示十位 在指定位置显示个位 在指定位置显示小数点位 在指定位置显示十分位位 在指定位置显示° 在指定位置显示C //tmp[21]... 22 23 25 //负号 //高八位 //低八位 //百 } tmp[1]=results/10%10+0x30; tmp[2]=results%10+0x30; PIC单片机课程设计报告 //十 //个 tmpA<<=4; tmpA>>=4; results=625*tmpA; tmp[3]=results/1000+0x30; //if (results>40) //speak = 0; //song(0); } char LCD_disp_buff[17]; void pro_key_scan() { if(RB1 == 1) { getDateTime(); } if(RB1== 0) { song(0); while(RB1 == ON); __delay_ms(10); //if(RB1==0) //{ while(! RB1); RB1_FLAG = 1; //} - 17 - } if (RB1_FLAG == 1) keyscan(); } void Screen() { PIC单片机课程设计报告 sprintf(LCD_disp_buff,\"%02d-%02d-%02d %3s\ DateTime[6],DateTime[4],DateTime[3],WEEK[DateTime[5]-1]); LCD_ShowString(0,0,LCD_disp_buff); sprintf(LCD_disp_buff,\"%02d:%02d:%02d \ DateTime[2], DateTime[1],DateTime[0]); LCD_ShowString(1,0,LCD_disp_buff); __delay_ms(100); } void compare() { if(temper > settempe ) //当温度超过35.7度,蜂鸣器便会报警。 { speak=1; song(1); } else { speak=0; } void main () - 18 - } { //unsigned char i; TRISA0 = TRISA2 = 0; port_init(); LCD_Initialize(); init_DS1302; while(1) { pro_key_scan() ; Screen(); compare(); PIC单片机课程设计报告 temp (); } } 六、设计总结 通过这次课程设计,使我更加扎实的掌握了单片机方面的知识,再设计过程中虽然遇到了一些问题,但经过一次又一次的思考,一遍又一遍的检查终于找出了原因所在,实践出真知,通过亲手制作,使我们掌握的知识不再是纸上谈兵。课程设计是一个重要的教学环节,通过课程设计使我们了解到一些实际与理论之间的差异。通过课程设计不仅可以巩固专业知识,为以后的工作打下了坚实的基础,而其还可以培养和熟练使用资料,运用工具书的能力,把我们所学的课本知识与实践结合起来,起到温故而知新的作用。同时,设计让我感触很深。使我对抽象的理论有了具体的认识。感谢课程设计,他教会了我很多! 设计成绩: 教师签名: 年 月 日 - 19 -
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- fenyunshixun.cn 版权所有 湘ICP备2023022495号-9
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务