完整单片机程序源码和proteus仿真文件在本文尾部附件中
C语言部分代码:
- #include<reg51.h> //预处理命令,定义SFR的头
- #include <math.h>
- #define uchar unsigned char //定义缩写字符uchar
- #define uint unsigned int //定义缩写字符uint
- #define lcd_data P0 //定义LCD1602接口 P0
- sbit DQ =P1^7; //将DQ位定义为P1.7引脚
- sbit lcd_RS=P2^0; //将RS位定义为P2.0引脚
- sbit lcd_RW=P2^1; //将RW位定义为P2.1引脚
- sbit lcd_EN=P2^2; //将EN位定义为P2.2引脚
- sbit PWM=P3^7; //将PWM定义为P3.7引脚
- sbit D=P3^6; //将d定义为P3.6引脚,转向选择位
- uchar t[2],speed,temperature; //用来存放温度值,测温程序就是通过这个数组与主函数通信的
- uchar DS18B20_is_ok;
- uchar TempBuffer1[12]={0x20,0x20,0x20,0x20,0xdf,0x43,'\0'};
- uchar tab[16]={0x20,0x20,0x20,0x54,0x20,0x4d,0x6f,0x6e,0x69,0x74,0x6f,0x72,'\0'};
- //显示"T Monitor"
- /**********lcd显示子程序************/
- void delay_20ms(void) /*延时20ms函数*/
- {
- uchar i,temp; //声明变量i,temp
- for(i = 20;i > 0;i--) //循环
- {
- temp = 248; //给temp赋值248
- while(--temp); //temp减1是否等于0,否则继续执行该行
- temp = 248; //给temp赋值248
- while(--temp); //temp减1是否等于0,否则继续执行该行
- }
- }
- void delay_38us(void) /*延时38us函数*/
- { uchar temp; //声明变量temp
- temp = 18; //给temp赋值
- while(--temp); //temp减1是否等于0,否则继续执行该行
- }
- void delay_1520us(void) /*延时1520us函数*/
- { uchar i,temp; //声明变量i,temp
- for(i = 3;i > 0;i--) //循环
- {
- temp = 252; //给temp赋值
- while(--temp); //temp减1是否等于0,否则继续执行该行
- }
- }
- uchar lcd_rd_status( ) /*读取lcd1602的状态,主要用于判断忙*/
- {
- uchar tmp_sts; //声明变量tmp_sts
- lcd_data = 0xff; //初始化P3口
- lcd_RW = 1; //RW =1 读
- lcd_RS = 0; //RS =0 命令,合起来表示读命令(状态)
- lcd_EN = 1; //EN=1,打开EN,LCD1602开始输出命令数据,100nS之后命令数据有效
- tmp_sts = lcd_data; //读取命令到tmp_sts
- lcd_EN = 0; //关掉LCD1602
- lcd_RW = 0; //把LCD1602设置成写
- return tmp_sts; //函数返回值tmp_sts
- }
- void lcd_wr_com(uchar command ) /*写一个命令到LCD1602*/
- {
- while(0x80&lcd_rd_status()); //写之前先判断LCD1602是否忙,看读出的命令的最高位是否为1,为1表示忙,继续读,直到不忙
- lcd_RW = 0;
- lcd_RS = 0; //RW=0,RS=0 写命令
- lcd_data = command; //把需要写的命令写到数据线上
- lcd_EN = 1;
- lcd_EN = 0; //EN输出高电平脉冲,命令写入
- }
- void lcd_wr_data(uchar sjdata ) /*写一个显示数据到lcd1602*/
- {
- while(0x80&lcd_rd_status()); //写之前先判断lcd1602是否忙,看读出的命令的最高位是否为1,为1表示忙,继续读,直到不忙
- lcd_RW = 0;
- lcd_RS = 1; //RW=0,RS=1 写显示数据
- lcd_data = sjdata ; //把需要写的显示数据写到数据线上
- lcd_EN = 1;
- lcd_EN = 0; //EN输出高电平脉冲,命令写入
- lcd_RS = 0;
- }
- void Init_lcd(void) /*初始化lcd1602*/
- {
- delay_20ms(); //调用延时
- lcd_wr_com(0x38); //设置16*2格式,5*8点阵,8位数据接口
- delay_38us(); //调用延时
- lcd_wr_com(0x0c); //开显示,不显示光标
- delay_38us(); //调用延时
- lcd_wr_com(0x01); //清屏
- delay_1520us(); //调用延时
- lcd_wr_com(0x06); //显示一个数据后光标自动+1
- }
- void GotoXY(uchar x, uchar y) //设定位置,x为行,y为列
- {
- if(y==0) //如果y=0,则显示位置为第一行
- lcd_wr_com(0x80|x);
- if(y==1)
- lcd_wr_com(0xc0|x); //如果y=1,则显示位置为第二行
- }
- void Print(uchar *str) //显示字符串函数
- {
- while(*str!='\0') //判断字符串是否显示完
- {
- lcd_wr_data(*str); //写数据
- str++;
- }
- }
- void LCD_Print(uchar x, uchar y, uchar *str)//x为行值,y为列值,str是要显示的字符串
- {
- GotoXY(x,y); //设定显示位置
- Print(str); //显示字符串
- }
-
- /*****************系统显示子函数*****************/
- void covert1() //温度转化程序
- {
- uchar x=0x00; //变量初始化
- if(t[1]>0x07) //判断正负温度
- {
- TempBuffer1[0]=0x2d; //0x2d为"-"的ASCII码
- t[1]=~t[1]; //负数的补码
- t[0]=~t[0]; //换算成绝对值
- x=t[0]+1; //加1
- t[0]=x; //把x的值送入t[0]
- if(x>255) //如果x大于255
- t[1]++; //t[1]加1
- }
- else
- TempBuffer1[0]=0x2b; //0xfe为变"+"的ASCII码
- t[1]<<=4; //将高字节左移4位
- t[1]=t[1]&0x70; //取出高字节的3个有效数字位
- x=t[0]; //将t[0]暂存到X,因为取小数部分还要用到它
- x>>=4; //右移4位
- x=x&0x0f; //和前面两句就是取出t[0]的高四位
- t[1]=t[1]|x; //将高低字节的有效值的整数部分拼成一个字节
- temperature=t[1];
- TempBuffer1[1]=t[1]/100+0x30;//加0x30 为变 0~9 ASCII码
- if(TempBuffer1[1]==0x30) //如果百位为0
- TempBuffer1[1]=0xfe; //百位数消隐
- TempBuffer1[2]=(t[1]%100)/10+0x30;//分离出十位
- TempBuffer1[3]=(t[1]%100)%10+0x30;//分离出个位
- }
- /*******************DS18B20函数**********************/
- void delay_18B20(uint i) //延时程序
- {
- while(i--);
- }
- void Init_DS18B20(void) //ds18b20初始化函数
- {
- uchar x=0;
- DQ = 1; //DQ复位
- delay_18B20(8); //稍做延时
- DQ = 0; //单片机将DQ拉低
- delay_18B20(80); //精确延时大于480us
- DQ = 1; //拉高总线
- delay_18B20(14);
- x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
- delay_18B20(20);
- }
- uchar ReadOneChar(void) //ds18b20读一个字节函数
- {
- unsigned char i=0;
- unsigned char dat0 = 0;
- for (i=8;i>0;i--)
- {
- DQ = 0; //读前总线保持为低
- dat0>>=1;
- DQ = 1; //开始读总线释放
- if(DQ) //从DS18B20总线读得一位
- dat0|=0x80;
- delay_18B20(4); //延时一段时间
- }
- return(dat0); //返回数据
- }
- void WriteOneChar(uchar dat1) //ds18b20写一个字节函数
- {
- uchar i=0;
- for (i=8; i>0; i--)
- {
- DQ = 0; //开始写入DS18B20总线要处于复位(低)状态
- DQ = dat1&0x01; //写入下一位
- delay_18B20(5);
- DQ = 1; //重新释放总线
- dat1>>=1; //把一个字节分成8个BIT环移给DQ
- }
- }
- void ReadTemperature() //读取ds18b20当前温度
- {
- delay_18B20(80); //延时一段时间
- Init_DS18B20();
- WriteOneChar(0xCC); // 跳过读序号列号的操作
- WriteOneChar(0x44); // 启动温度转换
- delay_18B20(80); // 延时一段时间
- Init_DS18B20(); //DS18B20初始化
- WriteOneChar(0xCC); //跳过读序号列号的操作
- WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
- delay_18B20(80); //延时一段时间
- t[0]=ReadOneChar(); //读取温度值低位
- t[1]=ReadOneChar(); //读取温度值高位
- }
- void delay_motor(uchar i) //延时函数
- {
- uchar j,k; //变量i、k为无符号字符数据类型
- for(j=i;j>0;j--) //循环延时
- for(k=200;k>0;k--); //循环延时
- }
- /*******************电机转动程序*******************/
- void motor(uchar tmp)
- {
- uchar x;
- if(TempBuffer1[0]==0x2b) //温度为正数
- {
- if(tmp<25) //温度小于25度
- {
- D=0; //电机停止转动
- PWM=0;
- }
- else if(tmp>50) //温度大于50度,全速转动
- {
- D=0; //D置0
- PWM=1; //正转,PWM=1
- x=250; //时间常数为x
- delay_motor(x); //调延时函数
- PWM=0; // PWM=0
- x=5; //时间常数为x
- delay_motor(x); //调延时函数
- }
- else
- {
- D=0; //D置0
- PWM=1; //正转,PWM=1
- x=5*tmp; //时间常数为x
- delay_motor(x); //调延时函数
- PWM=0; // PWM=0
- x=255-5*tmp; //时间常数为255-x
- delay_motor(x); //调延时函数
- }
- }
- else if (TempBuffer1[0]==0x2d) //温度小于0,反转
- {
- D=1;
- PWM=0; // PWM=0
- x=5*tmp; //时间常数为tmp
- delay_motor(x); //调延时函数
- PWM=1; // PWM=1
- x=255-5*tmp; //时间常数为255- tmp
- delay_motor(x); //调延时函数
- }
- }
-
- void delay(unsigned int x) //延时函数名
- {
- unsigned char i; //定义变量i的类型
- while(x--) //x自减1
- {
- for(i=0;i<123;i++){;} //控制延时的循环
- }
- }
- /*************************main主程序*********************/
- void main(void)
- {
- delay_20ms(); //系统延时20ms启动
- ReadTemperature(); //启动DS18B20
- Init_lcd(); //调用LCD初始化函数
- LCD_Print(0,0,tab); //液晶初始显示
- delay(1000); //延时一段时间
- while(1)
- {
- ReadTemperature(); //读取温度,温度值存放在一个两个字节的数组中,
- delay_18B20(100);
- covert1(); //数据转化
- LCD_Print(4,1,TempBuffer1); //显示温度
- motor(temperature); //电机转动
- }
- }
复制代码 ASM汇编语言部分代码
- TEMPER_L EQU 31H ;用于保存读出温度的低字节
- TEMPER_H EQU 30H ;用于保存读出温度的高字节
- T_INTEGER EQU 32H ;温度的整数部分(integer)
- T_IN_BAI EQU 35H ;温度的百位
- T_IN_SHI EQU 36H ;温度的十位
- T_IN_GE EQU 37H ;温度的个位
- FLAG BIT 33H ;标志位
- TEMPHC EQU 34H ;正、负温度值标记
- SPEED EQU 45H ;电机的速度调节位
- RW BIT P2.1 ;LCD1602R/W引脚由P2.1引脚控制
- RS BIT P2.0 ;LCD1602RS引脚由P2.0引脚控制
- E BIT P2.2 ;LCD1602E引脚由P2.2引脚控制
- DQ BIT P1.7 ;DS18B20数据线
- PWM BIT P3.6 ;定义速度控制位PWMP3.7
- D BIT P3.7 ;定义方向控制位P3.2
- ORG 0000H ;在0000H单元存放转移指令
- SJMP MAIN ;转移到主程序
- ORG 0060H ;主程序从0060H开始
- MAIN: LCALL DELAY20ms ;系统延时20ms启动
- LCALL INIT ;调用LCD初始化函数
- LCALL MENU ;调用液晶初始界面
- LCALL READ_TEM ;开启DS18B20
- LCALL DELAY1S ;调用1s延时,使DS18B20能完全启动
- LOOP: LCALL READ_TEM ;读取温度,温度值存放
- LCALL CONVTEMP ;调用温度转化程序
- LCALL DISPLAY ;调用显示程序
- LCALL MOTOR ;调用电机转动程序
- LJMP LOOP ;循环调用
- DELAY1S:MOV R5,#10 ;1S延时程序,给R5赋值,外循环控制
- DEL1: MOV R6,#200 ;中循环控制
- DEL2: MOV R7,#250 ;内循环控制
- DEL3: DJNZ R7,DEL3 ;内循环体
- DJNZ R6,DEL2 ;中循环体
- DJNZ R5,DEL1 ;外循环体
- RET ;子程序返回
- ;------------------------电机转动程序----------------------
- MOTOR: MOV A,T_INTEGER ;温度转化的整数暂存于A中
- MOV B,#5 ;给寄存器赋值立即数5
- MUL AB ;整数*5,提高转速的占空比
- MOV SPEED,A
- MOV A,TEMPHC ;把正、负温度值标记暂存于A中
- CJNE A,#0AH,NEG ;判断温度值标记是正还是负,如果是正,就顺序执行;否则,跳转到NEG
- CLR C ;把进位清零
- WIN: MOV A,T_INTEGER ;温度转化的整数暂存于A中
- SUBB A,#25 ;判断温度是否超过25度
- JNC POS ;温度大于25度,跳转到POS
- SETB D ;方向控制端置1
- SETB PWM ;PWM端置1,电机停止转动
- JMP REND ;子程序返回
- POS: MOV A,T_INTEGER ;温度转化的整数暂存于A中
- SUBB A,#50 ;判断温度是否大于50度
- JNC POS2 ;温度大于50度,跳转到POS2
- POS1: SETB D ;方向控制端置1
- CLR PWM ;正转,PWM=0
- MOV A, SPEED ;时间常数为SPEED
- LCALL DELAY_MOTOR ;调用电机转动延时子程序
- SETB PWM ;电机停止转动,PWM=1
- MOV A, #255 ;时间常数为255-TMP
- SUBB A, SPEED
- LCALL DELAY_MOTOR ;调用电机延时子程序
- JMP REND ;子程序返回
- POS2: MOV SPEED,#250 ;SPEED赋值为250
- JMP POS1 ;跳转到POS1
- NEG: CLR D ;方向控制端置0
- SETB PWM ;反转,PWM=1
- MOV A, SPEED ;时间常数为SPEED
- LCALL DELAY_MOTOR ;调用电机延时子程序
- CLR PWM ;PWM=0
- MOV A, #255 ;时间常数为255-TMP
- SUBB A, SPEED
- LCALL DELAY_MOTOR ;调用延时子程序
- REND: RET ;子程序返回
- ;---------------------电机转动延时子程序--------------------------
- DELAY_MOTOR:MOV R6, #5 ;设循环次数
- D1: DJNZ R6, D1 ;循环等待
- DJNZ ACC,D1 ;循环等待
- RET ;子程序返回
- ;---------------------温度转化程序------------------------------
- CONVTEMP: MOV A,TEMPER_H ;判温度是否零下
- ANL A,#08H
- JZ TEMPC1 ;温度没有零下,跳转到TEMPC1
- CLR C ;进位清零
- MOV A,TEMPER_L ;温度的低字节二进制数求补
- CPL A ;取反
- ADD A,#01H ;加1
- MOV TEMPER_L,A
- MOV A,TEMPER_H ;温度的高字节二进制数求补(双字节)
- CPL A ;取反
- ADDC A,#00H
- MOV TEMPER_H,A
- MOV TEMPHC,#0BH ;负温度标志
- LJMP TEMPC11 ;跳转到TEMPC11
- TEMPC1: MOV TEMPHC,#0AH ;正温度标志
- TEMPC11: MOV A,TEMPER_L
- ANL A,#0F0H ;取出高四位
- SWAP A
- MOV TEMPER_L,A
- MOV A,TEMPER_H ;取出低四位
- ANL A,#0FH
- SWAP A
- ORL A,TEMPER_L ;把温度的高字节和低字节重新组合为一个字节
- MOV T_INTEGER,A ;把组合成字节存于T_INTEGER
- MOV B,#100 ;把温度整数部分化为BCD码
- DIV AB
- MOV T_IN_BAI,A
- MOV A,B
- MOV B ,#10
- DIV AB
- MOV T_IN_SHI,A
- MOV T_IN_GE,B
- RET
- ;----------------------读温度程序---------------------------------
- READ_TEM: LCALL Set_18B20 ;DS18B20初始化
- MOV A,#0CCH ;跳过ROM匹配
- LCALL WRITE_1820 ;写DS18B20的子程序
- MOV A,#44H ;发出温度转换命令
- LCALL WRITE_1820 ;写DS18B20的子程序
- LCALL Set_18B20 ;准备读温度前先初始化
- MOV A,#0CCH ;跳过ROM匹配
- LCALL WRITE_1820 ;写DS18B20的子程序
- MOV A,#0BEH ;发出读温度命令
- LCALL WRITE_1820 ;写DS18B20的子程序
- LCALL READ_1820 ;读DS18B20的程序
- RET ;子程序返回
- ;--------------------------DS18B20初始化程序--------------------------
- Set_18B20:SETB DQ ;数据线拉高
- NOP
- CLR DQ ;赋值数据线低电平
- MOV R2,#255 ;主机发出延时500微秒的复位低脉冲
- DJNZ R2,$
- SETB DQ ;拉高数据线
- MOV R2,#30
- DJNZ R2,[ DISCUZ_CODE_3 ]nbsp; ;延时60us等待DS18B20回应
- JNB DQ,INIT1
- JMP Set_18B20 ;超时而没有响应,重新初始化
- INIT1: MOV R2,#120
- DJNZ R2,[ DISCUZ_CODE_3 ]nbsp; ;延时240us
- JB DQ,INIT2 ;数据变高,初始化成功
- JMP Set_18B20 ;初始化失败,重新初始化
- INIT2: MOV R2,#240
- DJNZ R2,$
- RET
- ;-----------------写DS18B20的子程序(有具体的时序要求)-----------------
- WRITE_1820:
- MOV R2,#8 ;一共8位数据
- WR0: CLR DQ ;开始写入DS18B20总线要处于复位
- MOV R3,#6 ;总线复位保持14微妙以上
- DJNZ R3,$
- RRC A ;把一个字节分成8个BIT环移给C
- MOV DQ,C
- MOV R3,#20 ;等待40微妙
- DJNZ R3,$
- SETB DQ ;重新释放总线
- NOP
- NOP
- DJNZ R2,WR0 ;写入下一位
- SETB DQ
- RET
- ;------ 从DS18B20中读出两个字节的温度数据--------
- READ_1820:
- MOV R4,#2 ;将温度高位和低位从DS18B20中读出
- MOV R1,#TEMPER_L ;低位存入31H(TEMPER_L)
- RE0: MOV R2,#8
- RE1: SETB DQ ;数据总线拉高
- NOP
- NOP
- CLR DQ ;读前总线保持为低
- NOP
- NOP
- SETB DQ ;开始读总线释放
- MOV R3,#4 ;延时一段时间
- DJNZ R3,$
- MOV C,DQ ;从DS18B20总线读得一位
- RRC A ;把读得的位值环移给A
- MOV R3,#30 ;延时一段时间
- DJNZ R3,$
- DJNZ R2,RE1 ;读下一位
- MOV @R1,A
- DEC R1 ;高位存入30H(TEMPER_H)
- DJNZ R4,RE0
- RET
- ;------------------------------显示程序----------------------
- DISPLAY: MOV A,#0C4H ;设定显示位置
- LCALL WRC ;调用写入命令程序
- MOV A, TEMPHC ;判断温度是正还是负
- CJNE A,#0BH,FZ ;如果温度是负,顺序执行;是正,跳转到FZ
- MOV A,#2DH ;"-"号显示
- AJMP WDA ;跳转到WDA
- FZ: MOV A,#2BH ;"+"号不显示
- WDA: LCALL WRD ;写数据
- MOV R0,#35H ;显示温度的百位、十位、个位
- WDA1: MOV A,@R0
- ADD A,#30H
- LCALL WRD ;写数据
- INC R0
- CJNE R0,#38H,WDA1 ;判断温度是否显示完
- MOV A,#0C9H ;设定显示位置
- LCALL WRC ;写入命令
- MOV A,#0DFH ;"。"的ASCII码
- LCALL WRD ;写数据
- MOV A,#043H ;"C"的ASCII码
- LCALL WRD ;写数据
- RET ;子程序返回
- ;******** 显示正确信息子程序 ***************
- MENU: MOV DPTR,#M_1 ;指针指到显示消息
- LINE1: MOV A,#80H ;设置 LCD 的第一行地址
- LCALL WRC ;写入命令
- FILL: CLR A ;填入字符
- MOVC A,@A+DPTR ;由消息区取出字符
- CJNE A,#0,LC1 ;判断是否为结束码
- JMP RET_END ;子程序返回
- LC1: LCALL WRD ;写入数据
- INC DPTR ;指针加1
- JMP FILL ;继续填入字符
- RET_END: RET
- M_1: DB " T Monitor ",0
- ;---------------液晶初始化程序-----------------
- INIT: MOV A,#01H ;清屏
- LCALL WRC ;调用写命令子程序
- MOV A,#38H ;8位数据,2行,5×8点阵
- LCALL WRC ;调用写命令子程序
- MOV A,#0cH ;开显示和光标,字符不闪烁
- LCALL WRC ;调用写命令子程序
- MOV A,#06H ;字符不动,光标自动右移1格
- LCALL WRC ;调用写命令子程序
- RET ;子程序返回
- ;---------------忙检查子程序-------------
- CBUSY: PUSH ACC ;将A的值暂存于堆栈
- PUSH DPH ;将DPH的值暂存于堆栈
- PUSH DPL ;将DPL的值暂存于堆栈
- PUSH PSW ;将PSW的值暂存于堆栈
- WEIT: CLR RS ;RS=0,选择指令寄存器
- SETB RW ;RW=1,选择读模式
- CLR E ;E=0,禁止读/写LCD
- SETB E ;E=1,允许读/写LCD
- NOP
- MOV A,P0 ;读操作
- CLR E ;E=0,禁止读/写LCD
- JB ACC.7,WEIT ;忙碌循环等待
- POP PSW ;从堆栈取回PSW的值
- POP DPL ;从堆栈取回DPL的值
- POP DPH ;从堆栈取回DPH的值
- POP ACC ;从堆栈取回A的值
- LCALL DELAY ;延时
- RET ;子程序返回
- ;---------------写子程序-------------
- ……………………
- …………限于本文篇幅 余下代码请下载附件…………
复制代码
温度监控系统.zip
(115.41 KB, 售价: 3 E币)
【必读】版权免责声明
1、本主题所有言论和内容纯属会员个人意见,与本论坛立场无关。2、本站对所发内容真实性、客观性、可用性不做任何保证也不负任何责任,网友之间仅出于学习目的进行交流。3、对提供的数字内容不拥有任何权利,其版权归原著者拥有。请勿将该数字内容进行商业交易、转载等行为,该内容只为学习所提供,使用后发生的一切问题与本站无关。 4、本网站不保证本站提供的下载资源的准确性、安全性和完整性;同时本网站也不承担用户因使用这些下载资源对自己和他人造成任何形式的损失或伤害。 5、本网站所有软件和资料均为网友推荐收集整理而来,仅供学习用途使用,请务必下载后两小时内删除,禁止商用。6、如有侵犯你版权的,请及时联系我们(电子邮箱1370723259@qq.com)指出,本站将立即改正。
|
|