51单片机的测温+按键+LCD显示的一个软硬件范例, 电路图和源码可参考如下:
//包含的头文件 #include<REG51.H> #include<math.h> #include<INTRINS.H> #include<string.h> //定义宏定义 #define CIRCLE 100 #define uchar unsigned char #define uint unsigned int; struct PID { unsigned int SetPoint; // 设定目标 Desired Value unsigned int Proportion; // 比例常数 Proportional Const unsigned int Integral; // 积分常数 Integral Const unsigned int Derivative; // 微分常数 Derivative Const unsigned int LastError; // Error[-1] unsigned int PrevError; // Error[-2] unsigned int SumError; // Sums of Errors }; struct PID spid; // PID Control Structure unsigned int rout; // PID Response (Output) unsigned int rin; // PID Feedback (Input) typedef unsigned char BYTE; typedef unsigned int WORD; typedef bit BOOL ; sbit key1=P3^2; //定义按键位置 sbit key2=P3^3; sbit key3=P3^4; sbit rs = P1^0; sbit rw = P1^1; sbit ep = P1^2; sbit pwm=P1^5; //PWM输出端设置为P1.5输出 sbit DQ=P1^3;//ds18b20 信号引脚即DQ sfr dataled=0x80;//显示数据端口 即P2口为段选码输入口 uchar temp;//温度变量 unsigned char set_temper=30; unsigned char high_time; unsigned int s; uchar flag_get,count,num,counter; //温度读取标志位、中断次数变量t0中断次数以读取温度值, t1中断次数以控制周期和PWM的占空比 char const table[]={100,80,70,60,50,40,30,20,0};//高电平时间查表 uchar code tab[]={0x28,0xEB,0x32,0xA2,0xE1,0xA4,0x24,0xEA,0x20,0xA0,0x60,0x25,0x3C,0x23,0x34, 0x74,0xF7,0xFF};//,0x88,0x83,0xC6,0xA1,0x86,0x8E};//共阳led显示段码115段码表 uchar shi,ge,danwei,dang,dang_dis; // 定义温度十位、个位、摄氏度单位、及档位变量名称,及显示档位的查表变量 void delay1(uchar MS);// 延时函数 unsigned char ReadTemperature(void);//读温度子函数 void Init_DS18B20(void);// DS18B20初始化 unsigned char ReadOneChar(void);//读字节子函数 void WriteOneChar(unsigned char dat);//写字节子函数 void delay(unsigned int i);//延时 //void del(unsigned int); void drive_moto();//由P1低四位输出控制信号 void initial(); unsigned int TempBuffer[5]; BYTE code dis1[] = {"Temperature:"}; BYTE code dis2[] = {"Set_Temper:"}; BYTE code dis3[] = {"0123456789"}; BYTE code dis4[] = 0xdf; BYTE code dis5[] = {"C"}; //定义函数 void delay2(BYTE ms) { BYTE i; while(ms--) { for(i = 0; i< 250; i++) { _nop_(); _nop_(); _nop_(); _nop_(); } } } // 测试LCD忙碌状态 BOOL lcd_bz() { BOOL result; rs = 0; rw = 1; ep = 1; _nop_(); _nop_(); _nop_(); _nop_(); result = (BOOL)(P0 & 0x80); ep = 0; return result; } // 写入指令数据到LCD void lcd_wcmd(BYTE cmd) { while(lcd_bz()); rs = 0; rw = 0; ep = 0; _nop_(); _nop_(); P0 = cmd; _nop_(); _nop_(); _nop_(); _nop_(); ep = 1; _nop_(); _nop_(); _nop_(); _nop_(); ep = 0; } //设定显示位置 void lcd_pos(BYTE pos) { lcd_wcmd(pos | 0x80); } //写入字符显示数据到LCD void lcd_wdat(BYTE dat) { while(lcd_bz()); rs = 1; rw = 0; ep = 0; P0 = dat; _nop_(); _nop_(); _nop_(); _nop_(); ep = 1; _nop_(); _nop_(); _nop_(); _nop_(); ep = 0; } //LCD初始化设定 void lcd_init() { lcd_wcmd(0x38); // delay2(1); lcd_wcmd(0x0c); // delay2(1); lcd_wcmd(0x06); // delay2(1); lcd_wcmd(0x01); //清除LCD的显示内容 delay2(1); } //初始化相应的寄存器 void initial() { EA=1; TMOD=0x11;//定时器设置皆工作在16定时计数器模式 TH0=0xef;//T0赋初值 TL0=0xf0; TH1=(65536-1000)/256;//T1赋初值 TL1=(65536-1000)%256; ET1=1; ET0=1; TR0=1; TR1=1; P2=0xff; count=0; counter=0;//pwm占空比控制变量 //IP=0x08; //T1优先级高于T0 ,后来证明此语句是多余的因为当加入此句后反/////而PWM调速和温度检测都变得有点不稳定 } //延时函数 void delay(unsigned int i) { while(i--); } //18b20初始化函数检测总线上是否有从属器件DS的存在若存在则通讯成功 void Init_DS18B20(void) { unsigned char x=0; DQ = 1; //DQ复位 delay(8); //稍做延时 DQ = 0; //单片机将DQ拉低 delay(80); //延时 大于 480us DQ = 1; //拉高总线 delay(10); x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败因为DQ复位成功的回答信号即存在信号是低电平 delay(5); } //读一个字节ROM unsigned char ReadOneChar(void) { unsigned char i=0; unsigned char dat = 0; for (i=8;i>0;i--) { DQ = 0; // 给脉冲信号 dat>>=1; DQ = 1; // 给脉冲信号 if(DQ) dat|=0x80;// delay(5); } return(dat); } //写一个字节 void WriteOneChar(unsigned char dat) { unsigned char i=0; for (i=8; i>0; i--) { DQ = 0; DQ = dat&0x01; delay(5); DQ = 1; dat>>=1; } delay(5); } //读取温度 unsigned char ReadTemperature(void) { unsigned char a=0; unsigned char b=0; unsigned char t=0; Init_DS18B20();// 复位 WriteOneChar(0xCC); // 跳过读序号列号的操作 WriteOneChar(0x44); // 启动温度转换 delay(100); Init_DS18B20(); //每次操作前都要进行复位 WriteOneChar(0xCC); //跳过读序号列号的操作 WriteOneChar(0xBE); //读取温度寄存器等共可读9个寄存器 前两个就是温度 a=ReadOneChar(); b=ReadOneChar(); s=(unsigned int)(a&0x0f); b<<=4;//取高字节的第四位因为高四位为符号位1111为负0000为正 b+=(a&0xf0)>>4;//忽略小数位取a的高四位与b的相加就是此时所测得到整数温度值 t=b; return(t);//返回温度值给这个函数 } //显示函数 void printf() { BYTE i; delay2(10); lcd_pos(0x00); // 设置显示位置为第一行的第5个字符 i = 0; while(dis1[i] != '\0') { lcd_wdat(dis1[i]); i++; } lcd_pos(0x40); // 设置显示位置为第二行第二个字符 i = 0; while(dis2[i] != '\0') { lcd_wdat(dis2[i]); // 显示字符 i++; } TempBuffer[0]=temp/10; //十位 TempBuffer[1]=temp%10; //个位 lcd_pos(0x0c); lcd_wdat(dis3[TempBuffer[0]]); //测试温度十位 lcd_pos(0x0d); lcd_wdat(dis3[TempBuffer[1]]); //测试温度个位 lcd_pos(0x0e); lcd_wdat(dis4[0]); lcd_pos(0x0f); lcd_wdat(dis5[0]); TempBuffer[2]=set_temper/10; //十位 TempBuffer[3]=set_temper%10; //个位 lcd_pos(0x4c); lcd_wdat(dis3[TempBuffer[2]]); //设置温度十位 lcd_pos(0x4d); lcd_wdat(dis3[TempBuffer[3]]); //设置温度个位 lcd_pos(0x4e); lcd_wdat(dis4[0]); lcd_pos(0x4f); lcd_wdat(dis5[0]); } //键盘输入函数 void keyscan() { if(key1==0) { delay(200); if(key1==0) { set_temper++; } } if(key2==0) { delay(200); if(key2==0) { set_temper--; } } // //开始按键 // if(key3==0) // { // delay(300); // if(key3==0) // { // TR1=1; // } // } } //T1定时中断服务程序 void into(void) interrupt 3 { TH1=(65536-1000)/256;//初值重装 TL1=(65536-1000)%256; counter++; if(counter>CIRCLE) { counter=0;////限定周期为T=100X0.01ms=10ms } if(counter<=high_time)//取得查表参数以调节pwm的占空比 pwm=1;//PWM高电平 else pwm=0; } //设定占空比函数 void compare_temper() { char shi=0,ge=0; if(set_temper>temp) { //当设置温度与实际温度大于10度时 if(set_temper-temp>=10) { //进入死循环 while(1) { TR1=0; //关闭定时器 从而关闭PWM波 pwm=0; //输出低电平 temp=ReadTemperature(); //读取温度传感器的值 shi=temp/10; //分离出十位 ge=temp%10; //分离出个位 lcd_pos(0x0c); //设置显示位置 lcd_wdat(0x30+shi); //在指定位置显示十位 lcd_pos(0x0d); //设置显示位置 lcd_wdat(0x30+ge); //在指定位置显示各位 if(set_temper-temp<10) //如果温度差值低于10度 { TR1=1; //打开定时器 开pwm波 break; //跳出循环 } } } else { //打开定时器 TR1=1; //根据差值调整PWM波 if (set_temper-temp==9) high_time=10; if (set_temper-temp==8) high_time=20; if (set_temper-temp==7) high_time=30; if (set_temper-temp==6) high_time=40; if (set_temper-temp==5) high_time=50; if (set_temper-temp==4) high_time=60; if (set_temper-temp==3) high_time=70; if (set_temper-temp==2) high_time=80; if (set_temper-temp==1) high_time=90; } } else if(set_temper<temp) { //关闭定时器 pwm=1; TR1=0; } } main() { initial();// 初始化个变量及定时器的初值开中断等 lcd_init(); // 初始化LCD while(1) { //比较函数 compare_temper(); //输出函数 printf(); //读取温度函数 temp=ReadTemperature(); //键盘扫描函数 keyscan(); } }