这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » 51单片机的测温+按键+LCD显示的一个软硬件范例

共12条 1/2 1 2 跳转至

51单片机的测温+按键+LCD显示的一个软硬件范例

工程师
2021-06-15 21:57:25     打赏

51单片机的测温+按键+LCD显示的一个软硬件范例, 电路图和源码可参考如下:

1623765409946926.png

//包含的头文件
#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显示段码115段码表
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();       
 } 
}



关键词: 测温     显示     LCD     DS18B20    

院士
2021-06-16 21:25:52     打赏
2楼

谢谢分享,收藏了。


工程师
2021-06-16 22:27:18     打赏
3楼

项目挺完整的嘛!用来学习不错!


工程师
2021-06-16 22:34:04     打赏
4楼

原理图画得挺beatiful的,楼主啥软件画的啊?


高工
2021-06-17 23:48:45     打赏
5楼

代码写的非常好


工程师
2021-06-18 17:39:41     打赏
6楼

感谢分享


工程师
2021-06-19 13:46:16     打赏
7楼

代码写的非常不错


工程师
2021-06-19 16:16:41     打赏
8楼

学习到了


工程师
2021-06-19 16:20:23     打赏
9楼

学习一下


工程师
2021-06-19 19:20:26     打赏
10楼

学习到了


共12条 1/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]