您好,欢迎来到欧得旅游网。
搜索
您的当前位置:首页PIC课程设计报告

PIC课程设计报告

来源:欧得旅游网


电子装置与系统设计

课程设计

学院: 班级: 学号: 姓名: 指导老师: 日期:

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;ireturn SEGCODE[KeyTemp]; } //while(0x0F!=(PORTC & 0x0F)); } } }

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 #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;iwrite_com(0x80+i); write_data(table[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

本站由北京市万商天勤律师事务所王兴未律师提供法律服务