电子装置与系统设计
课程设计
学院: 班级: 学号: 姓名: 指导老师: 日期:
1
电子装置与系统设计课程设计任务书
任务一:以下是PIC评估板上可用的资源列表,请阅读以下芯片的手册资料。 编号 U9 U12 U6 u3 元件 max232 at24C02 ds18b20 pcf8563 1602 K1-K16 功能 RS485 I2C 存储器 数字温度传感器 时钟 液晶模块 4*4键盘 备注 任务二:完成以下单元模块电路 1、双机RS232和RS485通讯,测试10m,50m不同距离时的通讯情况 2、键盘显示功能(计算器) 3、遥控日历查询 4、I2C存储器读写(计数器,并能断点存储) 5、温度测量并带报警(用键盘ps/2设置最高值) 任务三:设计一个简单系统,每10S进行温度采集(结合电路与程序,分析指标),在液晶屏上显示当前温度和前一状态的温度,并将结果存入存储器,具备可将温度的存储结果与PC机通讯和数据发送功能,可以使用键盘设定温度高低值,达到值时报警。
2
任务二选择:键盘显示功能(计算器)
相关资料:
一、 PIC18F452芯片
引脚说明:MCLR/VPP:主清0或编程电压 VDD:接电源
VSS:接地
RA0-RA7:双向I/O口 RB0-RB7:数字I/O口 RC0-RC7:数字I/O口 RD0-RD7:数字I/O口 RE0-RE3:数字I/O口
PIC18F452外设功能:
高灌/拉电流:25mA/25mA;
3个外部中断引脚,定时器0模块:具有8位可编程预分频器的8/16位定时器/计数器;
定时器1模块:16位定时器/计数器;
定时器2模块:具有8位周期寄存器的8位定时器/计数器(时基为脉宽调制);
3
定时器3模块:16位定时器/计数器; 辅助振荡器时钟选项:定时器1/定时器3; 2个捕捉/比较/PWM模块。
CCP引脚,可以配置为:捕捉输入:16位捕捉模块,最大分辨率是6.25ns(TCY/16);
16位比较模块,最大分辨率为100ns(TCY);
PWM输出:最大PWM是1~10位。最大PWM频率:当8位分辨率为156kHz,10位分辨率为39kHz;
主同步串口(MSSP)模块;2种运作模式:3线SPITM(支持所有4线SPI模式);I2CTM主从模式;
模拟功能:兼容的10位模数转换模块带有:快速采样率;可用转换睡眠;线形≤1LSB;可编程低电压检测(PLVD);支持中断低电压检测;可编程欠压复位(BOR);
微控制器的特殊功能:可进行100000次擦写操作的闪存程序存储器(标准值);闪存/数据EEPROM的保存时间:>40年,在软件控制下自行编程; 上电复位(POR),上电延时定时器(PWRT)和振荡器起振定时器(OST);
采用自身片上RC振荡器可靠工作的看门狗定时器(WDT),可编程代码保护;省电的休眠模式;可选振荡器选项包括:碴倍锁相回路(初级振荡器);辅助振荡器(32kHz)时钟输入;
通过2个引脚进行5V单电源供电在线串行编程(ICSPTM);通过2个引脚进行在线调试
二、LCD1602液晶显示屏
字符型液晶显示模块是一种专门用于显示字母、数字、符号等点阵式LCD,目前常用16*1,16*2,20*2和40*2行等的模块。一般1602字符型液晶显示器实物如图
4
1602LCD分为带背光和不带背光两种,基控制器大部分为HD44780,带背光的比不带背光的厚,是否带背光在应用中并无差别,两者尺寸差别如下图
`LCD1602主要技术参数:
显示容量:16×2个字符 芯片工作电压:4.5—5.5V 工作电流:2.0mA(5.0V) 模块最佳工作电压:5.0V 字符尺寸:2.95×4.35(W×H)mm
引脚功能说明:
1602LCD采用标准的14脚(无背光)或16脚(带背光)接口,各引脚接口说明如表 编号 1 2 3 4 5 6
符号 VSS VDD VL RS R/W E 引脚说明 电源地 电源正极 液晶显示偏压 数据/命令选择 读/写选择 使能信号 编号 9 10 11 12 13 14 5
符号 D2 D3 D4 D5 D6 D7 引脚说明 数据 数据 数据 数据 数据 数据
7 8 D0 D1 数据 数据 15 16 BLA BLK 背光源正极 背光源负极 第1脚:VSS为地电源。 第2脚:VDD接5V正电源。
第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比
度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。
第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存
器。
第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS
和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。
第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。 第7~14脚:D0~D7为8位双向数据线。 第15脚:背光源正极。 第16脚:背光源负极。
三、4×4键盘
矩阵键盘又称为行列式键盘,它是用4条I/O线作为行线,4条I/O线作为列线组成的键盘。在行线和列线的每一个交叉点上,设置一个按键。这样键盘中按键的个数是4×4个。这种行列式键盘结构能够有效地提高单片机系统中I/O口的利用率。
6
按键排列
4×4矩阵键盘的编程方法:
1、先读取键盘的状态,得到按键的特征编码。
先从P1口的高四位输出低电平,低四位输出高电平,从P1口的低四位读取键盘状态。再从P1口的低四位输出低电平,高四位输出高电平,从P1口的高四位读取键盘状态。将两次读取结果组合起来就可以得到当前按键的特征编码。使用上述方法我们得到16个键的特征编码。 举例说明如何得到按键的特征编码:
假设“1”键被按下,找其按键的特征编码。
从P1口的高四位输出低电平,即P1.4-P1.7为输出口。低四位输出高电平,即P1.0-P1.3为输入口。读P1口的低四位状态为“ 1101”,其值为“0DH”。
再从P1口的高四位输出高电平,即P1.4-P1.7为输入口。低四位输出低电平,即P10-P13为输出口,读P1口的高四位状态为“1110”,其值为“E0H”。
将两次读出的P0口状态值进行逻辑或运算就得到其按键的特征编码为“EDH”。
用同样的方法可以得到其它15个按键的特征编码。
2、根据按键的特征编码,查表得到按键的顺序编码。
将用上述方法得到的16个按键的特征编码按图2按键排列的顺序排成一张特征编码与顺序编码的对应关系表,然后用当前读得的特征编码来查表,当表中有该特征编码时,它所在的位置就是对应的顺序编码。
7
程序代码:
#include #define uint unsigned int #define uchar unsigned char #define e PORTBbits.RB3 #define rw PORTBbits.RB4 #define rs PORTBbits.RB5 void disp_init(void); //液晶屏初始化 void disp(uint num1,uint i); void dispc(uint num1); void disp1(uint num1,uint num2,uint num3,uint num4,uint num5); void write_com(uchar com); //写指令 void write_data(uchar dat); //写数据 unsigned int anjian(void); unsigned int jisuan(uint a1,uint a2,uint fuhao); void delay(uint z) { uint x,y; for(x=110;x>0;x--) for(y=z;y>0;y--); } rom unsigned char SEGCODE[]= { 0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37, 0x38,0x39,0x2B,0x2D, 0x2A,0x2F,0x3D,0x24, }; rom unsigned char KEYCODE[]= { 0xEE,0xDE,0xBE,0x7E, 0xED,0xDD,0xBD,0x7D, 0xEB,0xDB,0xBB,0x7B, 0xE7,0xD7,0xB7,0x77, }; void main(void) { uint a=0,b=0,c,s=0; uint temp,fuhao; uint i,j,ii=0,temp1=0,temp2=0; disp_init(); loop: while(1) { for(i=0;i<6;i++) { temp=anjian(); if(temp!=0x24) { disp(temp,i);temp1=temp-0x30; if((temp!=0x2B)&(temp!=0x2D)&(temp!=0x2A)&(temp!=0x2F)) { a=a*10+temp1; } else { fuhao=temp; i=6; } ii++; } else { a=(a-temp1)/10; i--; disp(0x20,i); i--; 8 ii--; } } for(j=0;j<6;j++) { temp=anjian(); if(temp!=0x24) { disp(temp,j+ii);temp2=temp-0x30; if(temp!=0x3D) { b=b*10+temp2; } else { j=6; } } else { b=(b-temp2)/10; j--; disp(0x20,j+ii); j--;} } c=jisuan(a,b,fuhao); //c的值 dispc(c); temp=anjian(); //c的显示 if(temp=0x24) { a=0; b=0; ii=0; disp_init(); goto loop; } } } unsigned int jisuan(uint a1,uint a2,uint fuhao) { uint c; switch(fuhao) { case 0x2B:c=a1+a2; break; case 0x2D:c=a1-a2; break; case 0x2A:c=a1*a2; break; case 0x2F:c=a1/a2; break; } return c; } unsigned int anjian(void) //按键扫描 { unsigned char i; unsigned char KeyTemp; TRISC=0xFF; while(1) { TRISC=0xF0; LATC=0xF0; if(0xF0!=(PORTC & 0xF0)) { delay(50); if(0xF0!=(PORTC & 0xF0)) { KeyTemp=PORTC & 0xF0; 9 TRISC=0x0F; LATC=0x0F; KeyTemp|=(PORTC & 0x0F); for(i=0;i void write_com(uchar com) //对液晶屏写指令 { TRISB=0b000000000; //TRISB=0b00010000; TRISD=0; e=0; rw=0; rs=0; //写指令:RS=L,RW=L,D0~D7=指令码,E=高脉冲 PORTD=com; //写指令到液晶 delay(5); e=1; delay(5); e=0; } void write_data(uchar dat) //写数据 { TRISD=0; e=0; rw=0; rs=1; //写数据:RS=H,RW=L,D0~D7=指令码,E=高脉冲 PORTD=dat; //写数据到液晶 delay(5); e=1; delay(5); e=0; } void disp_init() { TRISD=0; //选择D端口为液晶屏数据的输入口 write_com(0x38); //液晶开显示 write_com(0x0c); //显示光标,光标闪烁 write_com(0x06); //读或写一个字符后地址指针加一,光标加一 write_com(0x01); //显示清屏:1、数据指针清零;2、所有显示清零 write_com(0x80); //第一行首位 } void disp(uint num1,uint i) { write_com(0x80+i); //液晶第一行第i位数 write_data(num1); delay(1); } void dispc(uint num1) { uint c1,c2,c3,c4,c5; c1=num1/10000; //ADC结果千位上的数字 c2=num1%10000/1000; //ADC结果百位上的数字 c3=num1%1000/100; //ADC结果十位上的数字 c4=num1%100/10; c5=num1%10; disp1(c1,c2,c3,c4,c5); } void disp1(uint num1,uint num2,uint num3,uint num4,uint num5) { 10 } write_com(0x80+0x40); write_data(num1+0x30); delay(1); write_com(0x80+0x41); write_data(num2+0x30); delay(1); write_com(0x80+0x42); write_data(num3+0x30); delay(1); write_com(0x80+0x43); write_data(num4+0x30); delay(1); write_com(0x80+0x44); write_data(num5+0x30); delay(1); //液晶第二行第一位数 //液晶第二行第二位数 //液晶第二行第三位数 //液晶第二行第四位数 //液晶第二行第五位数 任务三: 相关资料: 一、max232 RS485 MAX232芯片是专门为电脑的RS-232标准串口设计的接口电路,使用+5v单电源供电。 内部结构基本可分三个部分: 第一部分是电荷泵电路。由1、2、3、4、5、6脚和4只电容构成。功能是产生+12v和-12v两个电源,提供给RS-232串口电平的需要。 第二部分是数据转换通道。由7、8、9、10、11、12、13、14脚构成两个数据通道。其中13脚(R1IN)、12脚(R1OUT)、11脚(T1IN)、14脚(T1OUT)为第一数据通道。8脚(R2IN)、9脚(R2OUT)、10脚(T2IN)、7脚(T2OUT)为第二数据通道。TTL/CMOS数据从T1IN、T2IN输入转换成RS-232数据从T1OUT、T2OUT送到电脑DP9插头;DP9插头的RS-232数据从R1IN、R2IN输入转换成TTL/CMOS数据后从R1OUT、R2OUT输出。 第三部分是供电。15脚DNG、16脚VCC(+5v)。 下图为MAX232引脚图和接线图,带有转串口的电路。 11 二、ds18b20 数字温度传感器 1.DS1820的特性 ·单线接口:仅需一根口线与MCU 连接 ·无需外围元件 ·由总线提供电源 ·测温范围为-55℃~75℃,精度为0.5℃ ·九位温度读数 ·A/D 变换时间为200ms ·用户自设定温度报警上下限,其值是非易失性的 ·报警搜索命令可识别哪片DS1820 超温度限 2.DS1820 引脚及功能(见图4) GND:地; DQ:数据输入/输出脚(单线接口,可作寄生供电); VDD:电源电压。 3.DS18B20内部结构 DS1820的内部结构如图5所示。由图5可知,DS1820由三个主要数字器件组成: ① bit闪速ROM; 图4.DS18B20引脚图 ②温度传感器; ③非易失性温度报警触发器TH和TL。 4. 温度寄存器格式 图5.DS18B20内部结构 5.DS18B20的使用方法 由于DS18B20采用的是1-Wire总线协议方式,即在一根数据线实现数据的双向传输,而对ATS51单片机来说,硬件上并不支持单总线协议,因此,我们必须采用软件的方法来模拟单总线的协议时序来完成对DS18B20芯片的访问。 由于DS18B20是在一根I/O线上读写数据,因此,对读写的数据位有着严格的时序要求。DS18B20有严格的通信协议来保证各位数据传输的正确性和完整性。该协议定义了几种信号的时序:初始化时序、读时序、写时序。所有时序 12 都是将主机作为主设备,单总线器件作为从设备。而每一次命令和数据的传输都是从主机主动启动写时序开始,如果要求单总线器件回送数据,在进行写命令后,主机需启动读时序完成数据接收。数据和命令的传输都是低位在先。 DS18B20的复位时序 DS18B20的读时序 对于DS18B20的读时序分为读0时序和读1时序两个过程。 对于DS18B20的读时隙是从主机把单总线拉低之后,在15秒之内就得释放单总线,以让DS18B20把数据传输到单总线上。DS18B20在完成一个读时序过程,至少需要60us才能完成。 DS18B20的写时序 对于DS18B20的写时序仍然分为写0时序和写1时序两个过程。 对于DS18B20写0时序和写1时序的要求不同,当要写0时序时,单总线要被拉低至少60us,保证DS18B20能够在15us到45us之间能够正确地采样IO总线上的“0”电平,当要写1时序时,单总线被拉低之后,在15us之内就得释放单总线。 13 程序代码: //40MHZ,连在RA4脚上 #include //=================================================================== void PIC18F_HIGH_ISR(void); //高优先级中断服务函数 void PIC18F_LOW_ISR(void); //低优先级中断服务函数 #pragma code high_vector_section=0x08 void high_vector (void) { _asm goto PIC18F_HIGH_ISR _endasm } #pragma code low_vector_section=0x18 void low_vector (void) { _asm goto PIC18F_LOW_ISR _endasm } #pragma code //------------------------------------------------宏定义 #define uint unsigned int #define uchar unsigned char #define ds LATAbits.LATA4 #define DQ1_data PORTA&0x10 #define e PORTBbits.RB3 //液晶屏e端接RB5 #define rw PORTBbits.RB4 //液晶屏rw端接RB6 #define rs PORTBbits.RB5 //液晶屏rs端接RB7 #define LEDSEG_C LATC #define Key_Data PORTBbits.RB1 #define Key_CLK PORTBbits.RB0 rom unsigned char LEDSEGCODE[]= //0-9笔段代码 { 0x3f,0x06,0x5b,0x4f,0x66, 0x6d,0x7d,0x07,0x7f,0x6f, }; //-------------------------------------------------------全局变量 uint temp; float f_temp; //温度传感器转换结果保存在lednum uchar a1,a2,a3,a4,num; //a1--a4分别为液晶屏第二行第1、3、4、5位数 unsigned int value=0; unsigned int value2=0; unsigned int value3=0; unsigned char recebuf; uchar IntNum = 0; //中断次数计数 uchar KeyV; //键值 unsigned char BF = 0; unsigned char k; unsigned char flag; unsigned char i=0; unsigned char flagok=0; unsigned char data[2]; unsigned int lednum=0,lednum0=0; unsigned char SndStr[]={\"the tempreture is:\ //---------------------------------------------------------函数声明 void disp(uchar num1,uchar num2,uchar num3); //液晶显示 void disp1(uchar num11,uchar num21); void disp2(uchar num11,uchar num21,uchar num31); void disp3(uchar num11,uchar num21); void delay(unsigned int z); //延时子程序 void delay_us (unsigned int x); 14 void disp_init(void); //液晶屏初始化 void tempwritebyte(unsigned char dat2); //向18B20写一个字节数据 uint tempchange(void); //DS18B20 开始获取温度并转换 void write_com(unsigned char com); //对液晶屏写指令 void write_data(unsigned char dat); //写数据 unsigned dsreset(void) ; //传感器初始化 unsigned char tempread(void); //读1个字节 //unsigned int get_temp() ; //读取寄存器中存储的温度数据 const uchar table[]=\"now last max min\"; //液晶屏第一行显示的字样 void PIC18_PORT_Init(void) { ADCON1=0x0F; //禁止所有模拟端口的输入 TRISC=0x00; //配置RC端口全为输出 TRISBbits.TRISB2=0; LATBbits.LATB2=0; // INTCON2bits.RBPU=0; //启用RB端口的内部弱上拉功能 TRISBbits.TRISB0=1; TRISEbits.TRISE2=1; //RB0为输入引脚 } void pic18_time0_init(void) { T0CONbits.TMR0ON=0; T0CONbits.T08BIT=0; T0CONbits.T0CS=0; TMR0H=(65536-40000)/256; TMR0L=(65536-40000)%256; //定时10ms INTCONbits.TMR0IF=0; T0CONbits.TMR0ON=1; } //=================================================================== // PIC18F45K20单片机的外部中断源初始化 //=================================================================== void PIC18_EINTn_Init(void) { INTCON2bits.INTEDG0=0; //选择下降沿触发方式 INTCONbits.INT0IF=0; //清INT0中断请求标志 INTCONbits.INT0IE=1; //使能INT0中断 } //=================================================================== // PIC18F45K20单片机的中断系统初始化 //=================================================================== void PIC18_INTERRUPT_Init(void) { RCONbits.IPEN=1; //使能中断嵌套 INTCON|=0XC0; //CPU开中断 } //=================================================================== void Decode() //键值处理 { unsigned char TempCyc; unsigned int a1=0,a2=0,a3=0,a4=0; TempCyc=KeyV; if(BF==1) //接收完一个有效数据时 { delay(100); if(BF==1) { BF=0; //准备下一次接收 switch ( TempCyc ) //键值与显示字符的对应关系 { //键值// //对应字符// case 0x70: {k=0; break;} //0 case 0x69: {k=1; break; }//1 case 0x72: {k=2; break;} //2 15 case 0x7A: {k=3; break;} //3 case 0x6B: {k=4; break;} //4 case 0x73: {k=5; break;} //5 case 0x74: {k=6; break;} //6 case 0x6C: {k=7; break;}//7 case 0x6C: k=7; break case 0x75: {k=8; break;} case 0x7D: {k=9; break; }//9 case 0x1c: {k=10; break;} default: break; } value2++; if(k!=10) { if(value2<=2) value=value*10+k; else { value3 = value3*10+k; } } INTCONbits.INT0IE=1; } } } void sci_Init(void) { TXSTAbits.BRGH = 1; // high baud rate SPBRG =103; // 设置波特率9600 TXSTAbits.SYNC = 0; // 1=同步接收方式 0=异步接收方式 RCSTAbits.SPEN = 1; // 串口使能位 RCSTAbits.CREN = 0; // 1=允许连续接收 0=禁止连续接收 RCSTAbits.SREN = 0; // 异步方式:此位未用 PIE1bits.TXIE = 0; // 关闭发送 PIE1bits.RCIE = 0; // 关闭接收中断 TXSTAbits.TX9 = 0; // 1:选择9位接收 0:选择8位接收 // RCSTAbits.RX9 = 0; // 1:选择9位接收 0:选择8位接收 TXSTAbits.TXEN = 1; // 发送允许 TRISCbits.TRISC6=1; // 作为串口使用,RC6必须设置为输入 TRISCbits.TRISC7=1; // 作为串口使用,RC7必须设置为输入 } void send232byte(unsigned char bytebuf) { TXREG=bytebuf; while(TXSTAbits.TRMT==1); } //---------------------------------------------------主函数 void main() { unsigned int a1=0,a2=0,a3=0,a4=0,a5=0,a6=0,a7=0,a8=0,flag = 0,count = 0; unsigned long temp; PIC18_PORT_Init(); PIC18_EINTn_Init(); PIC18_INTERRUPT_Init(); pic18_time0_init(); disp_init(); ADCON1=0X06; //所有IO均为数字口,模拟量输入禁止 sci_Init(); while(1) { Decode(); a1=value/10; //键盘输入显示 a2=value%10; 16 disp1(a1,a2); a1=value3/10; //最小值显示 a2=value3%10; disp3(a1,a2); if(flag==0) {flag=1; a1=lednum/100; //ADC结果千位上的数字 a2=lednum%100/10; //ADC结果百位上的数字 a3=lednum%10; //ADC结果十位上的数字 disp(a1,a2,a3);} //第一次显示零,隔10S之后进行温度采集 if((value>=10)) { if( (value3 >= lednum/10)&&(value3 > 20) ) LATBbits.LATB2=1; else { LATBbits.LATB2=0; if(value <= lednum/10) LATBbits.LATB2=1; else LATBbits.LATB2=0; } } if(1==INTCONbits.TMR0IF) { INTCONbits.TMR0IF=0;TMR0H=(65536-40000)/256;TMR0L=(65536-40000)%256;count++; if(count>=5) { count=0; lednum=tempchange(); a1=lednum/100; //ADC结果千位上的数字 a2=lednum%100/10; //ADC结果百位上的数字 a3=lednum%10; //ADC结果十位上的数字 send232byte(lednum/10); disp(a1,a2,a3); if (lednum0 != lednum) { a5=lednum0/100; //ADC结果千位上的数字 a6=lednum0%100/10; //ADC结果百位上的数字 a7=lednum0%10; //ADC结果十位上的数字 disp2(a5,a6,a7); lednum0 = lednum; } } } } } //////////////////////////////////////////////////LCD驱动程序 void write_com(uchar com) //LCD1602控制字输入 { //TRISB=0b00000000; TRISBbits.TRISB3=0; TRISBbits.TRISB4=0; TRISBbits.TRISB5=0; //TRISB=0b00010000; TRISD=0x00; e=0; rw=0; rs=0; //写指令:RS=L,RW=L,D0~D7=指令码,E=高脉冲 PORTD=com; //写指令到液晶 delay(5); e=1; delay(5); e=0; } void write_data(uchar dat) //LCD1602数据输入 { 17 TRISD=0;e=0; rw=0; rs=1;//写数据:RS=H,RW=L,D0~D7=指令码,E=高脉冲 PORTD=dat; //写数据到液晶 delay(5); e=1; delay(5); e=0; } void disp_init() //LCD初始化 { TRISD=0; //选择D端口为液晶屏数据的输入口 write_com(0x38); //液晶开显示 write_com(0x0c); //显示光标,光标闪烁 write_com(0x06); //读或写一个字符后地址指针加一,光标加一 write_com(0x01); //显示清屏:1、数据指针清零;2、所有显示清零 write_com(0x80); //第一行首位 } void disp(uchar num1,uchar num2,uchar num3) //温度显示 { unsigned char i; for(i=0;i i=0; write_com(0x80+0x40); write_data(num1+0x30); //液晶第二行第一位数 delay(1); write_com(0x80+0x41); write_data(num2+0x30); delay(1); write_com(0x80+0x42);//液晶第二行第三位 write_data('.');//液晶第二行第四位数 delay(1); write_com(0x80+0x43); write_data(num3+0x30); //液晶第二行第五位数 delay(1); } void disp1(uchar num11,uchar num21) //最大值显示 { write_com(0x80+0x4a); write_data(num11+0x30); delay(1); write_com(0x80+0x4b); write_data(num21+0x30); delay(1); } void disp2(uchar num1,uchar num2,uchar num3) //之前的温度显示 { write_com(0x80+0x45); write_data(num1+0x30); delay(1); write_com(0x80+0x46); write_data(num2+0x30); delay(1); write_com(0x80+0x47); write_data('.'); delay(1); write_com(0x80+0x48); write_data(num3+0x30); delay(1); } void disp3(uchar num1,uchar num2) //之前的温度显示 { write_com(0x80+0x4d); 18 write_data(num1+0x30); delay(1); write_com(0x80+0x4e); write_data(num2+0x30); delay(1); } //////////////////////////// 18B20的驱动程序 void delay(uint z) //z毫秒延时子程序 { while(z) {delay_us(300);z--;} } void delay3us(void){Nop();} //3us延时 void delay_us (unsigned int x) //微妙延时函数 {//x/=2; while(x) { delay3us();x--;} } unsigned dsreset(void) //18B20复位,初始化函数 { unsigned char presence; TRISA&=0xEF; ds=0;delay_us(160); ds=1;TRISA|=0x10;delay_us(26); presence=DQ1_data; delay_us(150); return presence; } void tempwritebyte(unsigned char dat2) //向18B20写一个字节数据 { unsigned int i; unsigned char j; unsigned char testb; for(j=1;j<=8;j++) { testb=dat2&0x01; if(testb) //写 1 { TRISA&=0xEF; ds=0; delay3us();delay3us();delay3us(); ds=1; delay_us (16); TRISA|=0x10; } else { TRISA&=0xEF; ds=0; delay_us (20); ds=1; TRISA|=0x10; } dat2>>=1 ; } } unsigned char tempread(void) //读1个字节 { unsigned char i, dat1; dat1=0; for(i=1;i<=8;i++) { dat1>>=1; TRISA&=0xEF; ds=0; delay3us();delay3us(); ds=1; //起延时作用 TRISA|=0x10; delay3us();delay3us();delay3us(); if(DQ1_data) dat1|=0x80; delay_us (13); //加了大括号3 19 } //读出的数据最低位在最前面,这样刚好一个字节在DAT里 return(dat1); } uint tempchange(void) //DS18B20 开始获取温度并转换 {unsigned char a,b; while(dsreset()); tempwritebyte(0xcc); // 写跳过读ROM指令 tempwritebyte(0x44); // 写温度转换指令 delay(20); delay(20); while(dsreset()); tempwritebyte(0xcc); tempwritebyte(0xbe); //temp= tempread()*256+ tempread();//两个字节组合为1个字 a=tempread(); b=tempread(); temp=a+b*256; f_temp=temp*0.0625; //温度在寄存器中为12位 分辨率位0.0625° temp=f_temp*10+0.5; //乘以10表示小数点后面只取1位,加0.5是四舍五入 temp=temp+0.05; return temp; //temp是整型 } ///////////////////////////////////////////////////////////////////// #pragma interrupt PIC18F_HIGH_ISR void PIC18F_HIGH_ISR(void) { if(INTCONbits.INT0IF&&INTCONbits.INT0IE) { if((IntNum>0)&&(IntNum<9)) { KeyV=KeyV>>1; //因键盘数据是低>>高,结合上一句所以右移一位 if(Key_Data) { KeyV=KeyV|0x80; //当键盘数据线为1时为1到最高位 } } IntNum++; while (!Key_CLK){;} //等待PS/2CLK拉高 if (IntNum > 10) { IntNum = 0; //当中断10次后表示一帧数据收完,清变量准备下一次接收 BF = 1; //标识有字符输入完了 INTCONbits.INT0IE= 1; //关中断等显示完后再开中断 } INTCONbits.INT0IF=0; } } // PIC18F45K20单片机的低优先级中断服务程序 //=================================================================== #pragma interruptlow PIC18F_LOW_ISR void PIC18F_LOW_ISR(void) { } 20 心得体会: 本次课程设计历时10天,从查找资料,到写程序,构建电路,调程序,显示结果,这一个个步骤,我们需要亲自去完成,真正实现了理论与实际相结合。 第一天,我们查阅有关max232、at24C02(I2C存储器)、ds18b20(数字温度传感器)、pcf8563(时钟)、1602(液晶模块)、k1-k16(4*4键盘)等芯片的相关内容。这些模块在任务二、三中,都会有一定程度的运用,所以我们对于各个模块都进行了详细的了解,并对于各个模块的示例程序进行了分析理解。 在完成任务二的过程中,我们选了一个平时上课涉及最多的模块,计算器设计,需要实现计算器的一些简单功能,如“+”、“-”“*”“/”等等,并且将计算内容显示在液晶屏上。确定好任务二内容的第一天,基本上没有实质性的进展,我们只是将该程序中可能涉及的程序组合在一起,例如,4*4键盘扫描程序、液晶屏显示程序等等。在第四天,我们终于将程序大体完成,但是内容显示仍存在问题,于是,又是一天纠结在这里。终于,在第二天,我们对程序如何显示两个运算数字的部分进行修改(用*10+按键数方法),并且意识到程序写的显示的是ASCII码,而非实际数字,故会出现乱码。至此,程序基本完成,后又加了清零(用goto语句)和删除的功能,这是本人觉得比较满意的地方,因为这两个功能被赋予在一个按键上。 在完成任务三时,老师给大家两个选择:一是焊电路,而是仿真。两者的区别大家都知道,焊电路充满未知,调试实在不易;仿对简单,但是成绩就不如焊电路。于是,和同学商量后,我们选择了焊电路。 完成任务三,首先要做的就是编写好程序。该程序中涉及到外接键盘、温度传感器、max232串口通信、蜂鸣器报警、液晶屏显示等等,可以说这是我们做过最复杂的程序了。我们需要把任务二中的各个模块整合在一起,于是东拼西凑的,我们将各个功能连接在了一起。由于涉及到得部件多,所以经常出现意外,例如,外接键盘坏了,串口不行等等,所以我们频繁的更换着元件,终于运行成功,加入了焊电路的队伍。 由于我们运行程序所用的是内部链接好的PIC板,所以焊电路的图,必须我们从板子的原理图上,自己整合出来。然后是排版,可是弄了半天,接好后,还是线很多,很乱。怀着忐忑的心情,我们进行了调试,不出意外,不成功。查电路,查到了,线路没连,端口弄反等等问题,但是奇迹并没有出现,我们的PIC板一直就是不运行,检查了两个电源和地的引脚,都没有虚焊的现象。最后,没有办法,求救老师,无奈,老师也找不到。一天的调试,我们还是没有结果,最终我们将板子交给了老师。感觉挺可惜的,熬夜焊好了板子,又花了这么多时间调试,还是没有结果。但是回到寝室,画电路原理图的时候,我终于发现了问题所在,原来是其中一个电源和接地端口弄错了。在今后的学习中,我一定会更加注重理论与实际的结合。 21 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- ovod.cn 版权所有 湘ICP备2023023988号-4
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务