液晶显示温度单片机

2010-12-18 22:09:00 NUPTboyZHB 阅读数 8219

#include<reg51.h>
#include<stdlib.h>
#include<stdio.h>//头文件
#define uchar unsigned char
#define uint unsigned int
sbit DQ=P2^6;//ds18b20与单片机连接口
sbit PWM=P2^5;//控制信号的输出
unsigned char code str[]={"my name is zhb "};
unsigned char code str_[]={"MADE IN NUPT... "};
unsigned char code str1[]={"temper:"};
unsigned char code str2[]={"         "};
unsigned char code nul[]={"        "};
unsigned char code str3[]={"target:  "};
unsigned char  str4[6];//设定温度的存储
uchar data disdata[5];

uchar a[4]={0,0,0,0},j,i,k,num=0;      //定义变量
sbit js=P3^2;   //红外接收端
uchar zhb_flag=0;//保证一次解码,只执行一次代码

uint tvalue;//温度值
uchar tflag;//温度正负标志
uint  count=0;//按键次数初始化为0
uint  number=4;//暂时规定输入的温度为xx.x的形式
uchar j,key;
uint time_flag=0;
bit enterflag=0;     // 确认键按下与否标志
uint new_t;    //转化后的十进制实时温度
uint target=0;  //转化后的十进制的目标温度---有键盘输入

//------------定义接口-------------//
sbit RS=P2^2 ;
sbit RW=P2^3 ;
sbit E=P2^4;
sbit PSB= P2^5;   //H=并口; L="串口";
#define Lcd_Bus P0
// P0 接 LCM
#define uchar unsigned char
#define FIRST_ADDR 0
//定义字符/汉字显示起始位置
/*------------------检查忙位-----------------------------*/
void chk_busy()
{
    RS=0 ;
    RW=1 ;
    E=1 ;
    Lcd_Bus=0xff ;
    while((Lcd_Bus&0x80)==0x80);
    E=0 ;
}
/*------------------延时子程序-----------------------------*/
void lcd_delay(unsigned int t)
{
    unsigned int i,j ;
    for(i=0;i<t;i++)
    for(j=0;j<10;j++);
}

/*------------------写命令到LCD------------------------------*/
void write_com(unsigned char cmdcode)
{
    chk_busy();
    RS=0 ;
    RW=0 ;
    E=1 ;
    Lcd_Bus=cmdcode ;
    lcd_delay(5);
    //------------------在数据写入的时候加入适当的延时
    E=0 ;
    lcd_delay(5);
}

/*-------------------写数据到LCD----------------------------*/
void write_data(unsigned char Dispdata)
{
    chk_busy();
    RS=1 ;
    RW=0 ;
    E=1 ;
    Lcd_Bus=Dispdata ;
    lcd_delay(5);
    //------------------在数据写入的时候加入适当的延时
    E=0 ;
    lcd_delay(5);
}
/*------------------初始化LCD屏--------------------------*/
void lcdreset()
{
    PSB = 1;
    lcd_delay(2000);
    write_com(0x30);
    lcd_delay(10);
    //选择基本指令集
    write_com(0x30);
    //选择8bit数据流
    lcd_delay(5);
    write_com(0x0c);
    //开显示(无游标、不反白)
    lcd_delay(10);
    write_com(0x01);
    //清除显示,并且设定地址指针为00H
    lcd_delay(500);
    write_com(0x06);
    //指定在资料的读取及写入时,设定游标的移动方向及指定显示的移位
    lcd_delay(0);
}
/*------------------显示字符串--------------------------*/
void hzkdis(unsigned char code*s)
{
    while(*s>0)
    {
        write_data(*s);
        s++;
        lcd_delay(50);
    }
}
/*------------------首屏显示--------------------------*/
void ceshi()
{
    write_com(0x01);
    //清除显示,并且设定地址指针为00H
    lcd_delay(5);
   
    write_com(0x80);
    //第一行(如果是地址是:80H,即LCD的第一行的第一个位置显示)
    hzkdis("南京邮电大学");
   
    write_com(0x90);
    //第二行(如果是地址是:90H,即LCD的第二行的第一个位置显示)
    hzkdis(str);
   
    write_com(0x88);
    //第三行(如果是地址是:88H,即LCD的第二行的第一个位置显示)
    hzkdis("电子信息工程");
   
    write_com(0x98);
    //第四行(如果是地址是:98H,即LCD的第二行的第一个位置显示)
    hzkdis("郑海波测试程序");
}
//------------------清整个GDRAM空间----------------------------
void clrgdram()
{
    unsigned char x,y ;
    for(y=0;y<64;y++)
    for(x=0;x<16;x++)
    {
        write_com(0x34);
        write_com(y+0x80);
        //行地址
        write_com(x+0x80);
        //列地址
        write_com(0x30);
        write_data(0x00);
        write_data(0x00);
    }
}
//------------------------------------------------------------
void clrscreen()
{
    write_com(0x01);
    lcd_delay(10);
}
unsigned char ReadByte(void)
{
    unsigned char byReturnValue ;
    chk_busy();
    Lcd_Bus=0xff ;
    RS=1 ;
    RW=1 ;
    E=0 ;
    E=1 ;
    byReturnValue=Lcd_Bus ;
    E=0 ;
   
    return byReturnValue ;
}

/*增加画点子程序
函数功能:在坐标为(x,y)点画一个点
参数意义
X:12864屏幕的横坐标,范围是0到128(从左到右)
Y:12864的纵坐标,范围是0到64(从上到下)
Color:为1的时候表示为黑点
*/
void DrawPoint(unsigned char X,unsigned char Y,unsigned char Color)
{
    unsigned char Row,Tier,Tier_bit ;
    unsigned char ReadOldH,ReadOldL ;
    write_com(0x34);
    write_com(0x36);
    Tier=X>>4 ;
    Tier_bit=X&0x0f ;
    if(Y<32)
    {
        Row=Y ;
    }
    else
    {
        Row=Y-32 ;
        Tier+=8 ;
    }
    write_com(Row+0x80);
    write_com(Tier+0x80);
    ReadByte();
    ReadOldH=ReadByte();
    ReadOldL=ReadByte();
    write_com(Row+0x80);
    write_com(Tier+0x80);
    if(Tier_bit<8)
    {
        switch(Color)
        {
            case 0 :
            ReadOldH&=(~(0x01<<(7-Tier_bit)));
            break ;
            case 1 :
            ReadOldH|=(0x01<<(7-Tier_bit));
            break ;
            case 2 :
            ReadOldH^=(0x01<<(7-Tier_bit));
            break ;
            default :
            break ;
        }
        write_data(ReadOldH);
        write_data(ReadOldL);
    }
    else
    {
        switch(Color)
        {
            case 0 :
            ReadOldL&=(~(0x01<<(15-Tier_bit)));
            break ;
            case 1 :
            ReadOldL|=(0x01<<(15-Tier_bit));
            break ;
            case 2 :
            ReadOldL^=(0x01<<(15-Tier_bit));
            break ;
            default :
            break ;
        }
        write_data(ReadOldH);
        write_data(ReadOldL);
    }
    write_com(0x30);
}


void send_to_pc(void)
{
 uint pc_flag=0;
 SCON=0x50;//串口方式1,允许接收
 TMOD=0x20;//定时器1,定时方式2
 TCON=0x40;//设定时器1开始计数
 TH1=0xE8;//11.0592MHz, 1200波特率
 TL1=0xE8;
 TI=1;
 TR1=1;
 while(1)
 {
  if(pc_flag==1)
  {
   TMOD=1;
  }
  else
  {
   printf("Now temperture is ");
   printf(disdata);
   printf("*0.1 C");
   pc_flag++;
  }
 }
}

 


void delay_18B20(unsigned int i)//延时1微秒
{
 while(i--);
}

 

void ds1820rst()/*ds1820复位*/
{
 unsigned char x=0;
 DQ = 1;          //DQ复位
 delay_18B20(4); //延时
 DQ = 0;          //DQ拉低
 delay_18B20(100); //精确延时大于480us
 DQ = 1;          //拉高
 delay_18B20(40);
}

 

uchar ds1820rd()/*读数据*/
{
 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_18B20(10);
 }
 return(dat);
}

 

 

void ds1820wr(uchar wdata)/*写数据*/
{
    unsigned char i=0;
    for (i=8; i>0; i--)
 {
  DQ = 0;
        DQ = wdata&0x01;
        delay_18B20(10);
        DQ = 1;
        wdata>>=1;
 }
}


read_temp1()/*读取温度值并转换*/
{
    ds1820rst();   
    ds1820wr(0xcc);//*跳过读序列号*/
    ds1820wr(0x44);//*启动温度转换*/
    ds1820rst();   
}
read_temp2()
{
    uchar a,b;
    ds1820wr(0xcc);//*跳过读序列号*/
    ds1820wr(0xbe);//*读取温度*/
    a=ds1820rd();
    b=ds1820rd();
    tvalue=b;
    tvalue<<=8;
    tvalue=tvalue|a;
    if(tvalue<0x0fff)
  tflag=0;
    else
 {
  tvalue=~tvalue+1;
        tflag=1;
 }
    tvalue=tvalue*(0.625);//温度值扩大10倍,精确到1位小数
    return(tvalue);
}

 

/*******************************************************************/


void ds1820disp1()//温度值显示

    uchar flagdat;
    disdata[0]=tvalue/1000+0x30;//百位数
    disdata[1]=tvalue%1000/100+0x30;//十位数
    disdata[2]=tvalue%100/10+0x30;//个位数
    disdata[3]=tvalue%10+0x30;//小数位
    if(tflag==0)
  flagdat=0x20;//正温度不显示符号
    else
  flagdat=0x2d;//负温度显示负号:-
    if(disdata[0]==0x30)
    {
  disdata[0]=0x20;//如果百位为0,不显示
  if(disdata[1]==0x30)
  {
   disdata[1]=0x20;//如果百位为0,十位为0也不显示
  }
 }
}

 

void ds1820disp2()
{
    lcd_delay(5);
 write_com(0x80);
    hzkdis("温度为:");
 lcd_delay(50);
 write_com(0x84);
 write_data(disdata[1]);
 write_com(0x85);
 write_data(disdata[2]);
 write_com(0x86);
 write_data(0x2e);
 write_com(0x87);
 write_data(disdata[3]);
 lcd_delay(50);
    new_t=disdata[1]*10+disdata[2];
}

void delay(uint us)   //delay time
{
 while(us--);
}
void HW_key(void)
{
 if(zhb_flag==1)
 {
  if((a[2]+a[3])==0xff)  //判断接收到数据是否正确
  {
   switch(a[2])   //将接受到的数据与所建表一一对应
   { 
            case 0x00:
    {
     num=0;
     if (count<number)
     {
      str4[count]='0';
      count++;
     }break;//数字键0
    }
            case 0x01:
    {
     num=1;
     if (count<number)
     {
      str4[count]='1';
      count++;
     }break;//数字键1
    }
            case 0x02:
    {
     num=2;
     if (count<number)
     {
      str4[count]='2';
      count++;
     }break;//数字键2
    }
            case 0x03:
    {
     num=3;
     if (count<number)
     {
      str4[count]='3';
      count++;
     }break;//数字键3
    }
            case 0x04:
    {
     num=4;
     if (count<number)
     {
      str4[count]='4';
      count++;
     }break;//数字键4
    }
            case 0x05:
    {
     num=5;
     if (count<number)
     {
      str4[count]='5';
      count++;
     }break;//数字键5
    }
   case 0x06:
    {
     num=6;
     if (count<number)
     {
      str4[count]='6';
      count++;
     }break;//数字键6
    }
   case 0x07:
    {
     num=7;
     if (count<number)
     {
      str4[count]='7';
      count++;
     }break;//数字键7
    }
   case 0x08:
    {
     num=8;
     if (count<number)
     {
      str4[count]='8';
      count++;
     }break;//数字键8
    }
   case 0x09:
    {
     num=9;
     if (count<number)
     {
      str4[count]='9';
      count++;
     }break;//数字键9
    }
   case 0x0a:
    {
     num=10;
     if (count<number)
     {
      str4[count]='.';
      count++;
     }break;//键"--/-"
    }
   case 0x0b:
    {
     num=11;
     break;//键LG
    }
   case 0x0f:
    {
     num=12; break;//AV键
    }
   case 0x10:
    {
     num=13;
     send_to_pc();break;//静音键
    }
   case 0x15:
    {
     num=14;
     break;//开关键
    }
   case 0x16:
    {
     num=15;break;//选台键
    }
   case 0x17:
    {
    /* num=16; count = 0;//清零
     for (j=0;j<number;j++)
     {
      str4[j]=' ';
     }
                    str4[j]='/0';
     PWM=1;
     time_flag=0;
     wr_com(0xcd);
     display(nul);
     target=0;
     enterflag = 0;break;//睡眠键*/
    }
   case 0x1a:
    {
     num=17;break;//音量+
    }
   case 0x1b:
    {
     num=18;break;//频道+
    }
   case 0x1c:
    {
     num=19;break;//屏显
    }
   case 0x1e:
    {
     num=20;break;//音量-
    }
   case 0x1f:
    {
     num=21;break;//频道-
    }
   case 0x30:
    {
     num=22;break;//小键'-'
    }
   case 0x4e:
    {
     num=23;break;//小键'+'
    }
   case 0x51:
    {
     num=24;break;//画中画
    }
   case 0x56:
    {
     num=25;break;//图像,菜单
    }
   case 0x57:
    {
     num=26;break;//声音
    }
   case 0x5a:
    {
     num=27;break;//方向上
    }
   case 0x5b:
    {
     num=28;break;//方向右
    }
   case 0x5c:
    {
     num=29;
     enterflag = 1;    // 确认键按下   
     str4[count]='/0';break;//完成
    }
   case 0x5e:
    {
     
     num=30;break;//方向下
    }
   case 0x5f:
    {  
     num=31;break;//方向左
    }
            default:break;
  }
  if (enterflag==1)     // 如果按下确认键
  {
   //   enterflag = 0;      // 标志位置回0
/*   wr_com(0xcd);
            wr_dat(0xdf);
            wr_dat(0x43);
   target=str4[0]*10+str4[1];
   time_flag=1;*/
  }
/*  wr_com(0xc0);
        display(str3);
        wr_com(0xc8);
        display(str4);
  zhb_flag=0;*/
  }
       }
}
/*void pitu_wave(void)
{
   uchar i,a;
   uchar colour=1;
   for(i=0;i<128;i+=2)
    {
         a=64-new_t;
         DrawPoint(i,a,colour);
    }
}*/
/********************主程序***********************************/
void main()
{
    uchar wave=0;
  uchar i=0,a;
   uchar colour=1;
    RW=0 ;
    lcdreset();
    ceshi();
    clrgdram();
    delay(2000);
    clrscreen();
    EA=1;    //初始化
 ET0=1;  //开计数中断0
 EX0=1;   //开外部中断0
 TMOD=1; //设置工作方式
 IT0=1;    //启动计时器
    while(1)
    { 
  read_temp1();//读取温度
  read_temp2();//读取温度
  ds1820disp1();//显示
  ds1820disp2();//显示
  wave++;
  if(wave>=10)
  {
        a=64-new_t;
     if(i>=128)
     {
       i=0;
    clrgdram();
             delay(2000);
             clrscreen();
     }
           DrawPoint(i++,a,colour);
     wave=0;
  }
  HW_key();
    }
}
void zhb(void) interrupt 0 // 外部中断子程序(译码过程)
{
    zhb_flag=1;
 TH0=0;   //计数器清零
 TL0=0;
 TR0=1;   //启动计数器
 while(!js)   //等待低电平结束
 {
  delay(5);
  if(TH0>45)  //判断低电平是否高于11.52ms如果高于则跳出等待和中断
   return;
 }
 TR0=0;
 if(TH0<30)  //判断低电平是否低于7.68ms如果低于跳出中断
  return;
 TH0=0;
 TR0=1;
 while(js)   //等待高电平结束
 {
  delay(5);
  if(TH0>28)  //判断高电平是否高于7.168ms如果高于则跳出等待和中断
   return;
 }
 
 //至此为起始信号检测
 
 TR0=0;
 TH0=0;
 for(i=0;i<4;i++)  //一次锁存红外接收的四个十六进制数到a[4]中
 {
  for(j=0;j<8;j++)
  {
   TR0=1;
   while(!js)  //判断低电平宽度是否大于3..40ms
   {
    delay(5);
    if(TH0>15)
     return;
   }
   TH0=0;
   while(js) //判断高电平是否大于1.012ms如果高于则为接受到1,否则为0
   {
    delay(5);
    if(TH0>15)
     return;
   }
   TR0=0;
   CY=0;
   k=(k>>1);
   if(TH0>4)
    k=k+0x80;
   TH0=0;
  }
  a[i]=k;
 }
}

2014-05-11 19:30:35 yangguangmeng 阅读数 1572

1602具有8根数据线和三根控制线(E使能线   R/W读写线   RS表示数据还是指令

一般是先写地址再写数据即可



DS18b20为单线器件,数据在该线上一位一位传输的,向DS18b20写入命令之后,就可以一位一位读取温度数值了


DS1302主要是数据引脚和时钟引脚匹配使用的,写操作时候是先写入地址再写入数据 ,读操作时候是先写入地址再读数据,比如写时候给I/O引脚一位数据,CLK来个下降沿该数据就写成功了。


2012-12-13 14:33:55 ap105638 阅读数 854
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit lcdrs=P1^7;
sbit lcdrw=P1^6;
sbit le=P2^4;
sbit DQ=P3^5;
uchar num = 0;

uchar i;

uchar code tabel[]="0123456789.";
uchar tabel0[]="TEMPERATURE:";
uchar tabel1[]="THE TIME IS:";

 void delay8(uint ms)
{
 while(ms--);
}
void delay(uint s)
{
 uint x,y;
 for(x=s;x>0;x--)
   for(y=110;y>0;y--);
}
void init_1820()  //1820的复位
{
 uchar x;
 DQ=1;
 delay8(8);
 DQ=0;
 delay8(140);
 DQ=1;
 delay8(15);
 x=DQ;
 delay8(5);
}
void write_byte(uchar dat)   //写指令
{
 uchar i;
 for(i=0;i<8;i++)
 {
  DQ=0;     //这里是单片机
  DQ=dat&0x01;   //这还是单片机发的  所以不用释放
  delay8(4);
  DQ=1;
  dat>>=1;
 }
 delay(5);
}

  uchar read_byte()   //读数据
 {
 uchar i,value;
 for(i=0;i<8;i++)
 {
  DQ=0;
  value>>=1;
  DQ=1;   //一定要释放 因为DQ即将要被1820用到而不是单片机
  if(DQ) 
   value|=0x80;
  delay8(4);  
 }
 return value;
}
uint temper()       //就是由于把uint写成uchar导致无法显示小数点,浪费8个小时啊.....
{
 uchar a,b;
 uint temp;
   
 init_1820();
 write_byte(0xcc);   //跳过ROM
 write_byte(0x44);  //启动转换温度
 delay8(300);
  
    init_1820();   //每次操作都要init初始化才行
 write_byte(0xcc);
 write_byte(0xbe); //读取温度
 a=read_byte();
 b=read_byte();
 temp=(a+b*256)*(0.0625*10);  //保留一位小数,即百位实际是十位,十位是个位,个位是小数点后一位
 return temp;
}
void write_com(uchar com)
{
 lcdrs=0;
 //le=0;
 delay(5);
 P0=com;
 delay(5); 
 le=1;
 delay(5);
 le=0;
}

void write_data(uchar dete)
{
 lcdrs=1;
 //le=0;
 delay(5);
 P0=dete;
 delay(5); 
 le=1;
 delay(5);
 le=0;
}
void init()
{
 le=0;
 lcdrw=0;    //时序图是低电平  而文档文字是高电平  
 write_com(0x01);  //清屏等操作
 write_com(0x38);
 write_com(0x0f);

 /////////////////////外部中断0
 EA = 1;
 EX0 = 1;
 IT0 = 1;

  
}

void main()
{
    uchar shi,ge,dot1;
    uint tt;
 init();
    while(1){
 write_com(0x80+0x40);
 for(i=0;i<12;i++)
 {
  write_data(tabel0[i]);
  delay(30);
 }

 write_com(0x80);
 for(i=0;i<12;i++)
 {
  write_data(tabel1[i]);
  delay(30);
 }
 write_com(0x80+0x4c);
  tt=temper();
 
  shi=tt/100;
  ge=tt%100/10;
  dot1=tt%10;
  
  
 write_data(tabel[shi]);
 
  delay(200);

 write_data(tabel[ge]&0x7f);  //突出小数点
 
  delay(200); 
   write_data(tabel[10]);
   delay(200); 
 
   
 write_data(tabel[dot1]);
 
  delay(200);



  
 } 
 
}

void int0() interrupt 0
{
 num++;
}

#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit lcdrs=P2^2;
sbit lcdrw=P2^3;
sbit le=P2^4;
sbit peng=P2^1;

uchar min1=1;
uchar min2=0;
uchar sex1=0;
uchar sex2=0;
int fage=1;
uchar i;

uchar code tabel[]="0123456789.";
uchar tabel0[]=":";
uchar tabel1[]="THE TIME IS:";

 void delay8(uint us)
{
	 while(us--);
}
void delay(uint ms)
{
 	 uint x,y;
	 for(x=ms;x>0;x--)
  	 for(y=110;y>0;y--);
}


void write_com(uchar com)
{
 	lcdrs=0;
 	//le=0;
 	delay(5);
 	P0=com;
 	delay(5); 
 	le=1;
 	delay(5);
 	le=0;
}

void write_data(uchar dete)
{
 	lcdrs=1;
 	//le=0;
 	delay(5);
 	P0=dete;
 	delay(5); 
 	le=1;
	delay(5);
 	le=0;
}
void init()
{
 	le=0;
 	lcdrw=0;    //时序图是低电平  而文档文字是高电平  
 	write_com(0x01);  //清屏等操作
 	write_com(0x38);
 	write_com(0x0f);

 	/////////////////////外部中断0
	EA = 1;
 	EX0 = 1;

 	EX1=1;    //开外部中断1 
	IT1=0;  //外部中断边沿触发,下降沿触发  
	IT0=0;  //外部中断0边沿触发,下降沿触发
	
	
 

  
}
void int0() interrupt 0
{
 	

	fage=0;

}
 void int1() interrupt 2
{ 
 
	
	fage=1;


}


void main()
{
 	init();
	peng=0;
    while(1)
	{
	
		if(fage==1)
		{
		 	
			
		
	 		write_com(0x80);
 			for(i=0;i<12;i++)
 			{
 				write_data(tabel1[i]);
  			 	delay(30);
		
 			}
		
			write_com(0x80+0x49);
			write_data(tabel[min1])	;
			delay(30);
			write_data(tabel[min2])	;
			delay(30);
			write_data(tabel0[0])	;
			delay(30);
			write_data(tabel[sex1]);
			delay(30);
			write_data(tabel[sex2]);
			delay(30) ;
			
				
			if((sex1==0)&&(sex2==1)&&(min2==0)&&(min1==0))
			{
			 	fage=0;
				peng=1;
			}
			if((sex1==0)&&(sex2==0)&&(min2==0)&&(min1==1))
			{
			  min1--;
			  min2=9;
			  sex1=5;
			  sex2=10;
			}
			if((sex1==0)&&(sex2==0)&&(min2!=0))
			{
			  min2--;
			  sex1=5;
			  sex2=10;
			}
			if(sex2==0&&(sex1!=0))
			{
			  sex1--;
			  sex2=10;
			}
			 delay(700) ;
			 sex2--;
			
		
		}
		else
		{
		
		 
			write_com(0x80);
 			for(i=0;i<12;i++)
 			{
 				write_data(tabel1[i]);
  			 	delay(30);
		
 			}
		
			write_com(0x80+0x49);
			write_data(tabel[min1])	;
			delay(30);
			write_data(tabel[min2])	;
			delay(30);
			write_data(tabel0[0])	;
			delay(30);
			write_data(tabel[sex1]);
			delay(30);
			write_data(tabel[sex2]);
			delay(30) ;
			delay(700) ;
			
		
		}

	} 
 
}


2019-02-12 21:41:30 weixin_43394725 阅读数 2601

外接晶振为12MHz时,51单片机相关周期的具体值为:

振荡周期=1/12us;
状态周期=1/6us;
机器周期=1us;
指令周期=1~4us;

51单片机定时/计数器的工作由两个特殊功能寄存器控制。TMOD用于设置其工作方式;TCON用于控制其启动和中断申请。
1、工作方式寄存器TMOD
工作方式寄存器TMOD用于设置定时/计数器的工作方式,低四位用于T0,高四位用于T1。其格式如下:
在这里插入图片描述
GATE是门控位, GATE=0时,用于控制定时器的启动是否受外部中断源信号的影响。只要用软件使TCON中的TR0或TR1为1,就可以启动定时/计数器工作;GATA=1时,要用软件使TR0或TR1为1,同时外部中断引脚INT0/1也为高电平时,才能启动定时/计数器工作。即此时定时器的启动条件,加上了INT0/1引脚为高电平这一条件。
C/T :定时/计数模式选择位。C/T =0为定时模式;C/T =1为计数模式。
M1M0:工作方式设置位。定时/计数器有四种工作方式。
在这里插入图片描述
控制寄存器TCON
TCON的高4位用于控
制定时/计数器的启动和中断申请。其格式如下:
在这里插入图片描述
TF1(TCON.7):T1溢出中断请求标志位。T1计数溢出时由硬件自动置TF1为1。CPU响应中断后TF1由硬件自动清0。T1工作时,CPU可随时查询TF1的状态。所以,TF1可用作查询测试的标志。TF1也可以用软件置1或清0,同硬件置1或清0的效果一样。
TR1(TCON.6):T1运行控制位。TR1置1时,T1开始工作;TR1置0时,T1停止工作。TR1由软件置1或清0。所以,用软件可控制定时/计数器的启动与停止。
TF0(TCON.5):T0溢出中断请求标志位,其功能与TF1类同。
TR0(TCON.4):T0运行控制位,其功能与TR1类同。

定时/计数器的工作方式

1、方式1
方式1的计数位数是16位,由TL0作为低8位,TH0
作为高8位,组成了16位加1计数器 。计数个数与计数初值的关系为:X=2(16次方)-N

2、方式2
为自动重装初值的8位计数方式。 计数个数与计数初值的关系为:X=28-N
工作方式2特别适合于用作较精确的脉冲信号发生器。所以串口通信处用此方式。

计数器初值的计算
机器周期也就是CPU完成一个基本操作所需要的时间。
机器周期=1/单片机的时钟频率。
51单片机内部时钟频率是外部时钟的12分频。也就是说当外部晶振的频率输入到单片机里面的时候要进行12分频。比如说你用的是12MHZ的晶振,那么单片机内部的时钟频率就是12/12MHZ,当你使用12MHZ的外部晶振的时候。机器周期=1/1M=1us。
而我们定时1ms的初值是多少呢,1ms/1us=1000。也就是要计数1000个数,初值=65535-1000+1(因为实际上计数器计数到66636才溢出)=64536=FC18H

串口通信
比特率是每秒钟传输二进制代码的位数,单位是:位/秒(bps)。如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位、1个停止位、8个数据位),这时的比特率为:
10位×240个/秒 = 2400 bps

SCON 是一个特殊功能寄存器,用以设定串行口的工作方式、接收/发送控制以及设置状态标志:在这里插入图片描述
SM0和SM1为工作方式选择位,可选择四种工作方式:
在这里插入图片描述
SM2,多机通信控制位,主要用于方式2和方式3。当接收机的SM2=1时可以利用收到的RB8来控制是否激活RI(RB8=0时不激活RI,收到的信息丢弃;RB8=1时收到的数据进入SBUF,并激活RI,进而在中断服务中将数据从SBUF读走)。当SM2=0时,不论收到的RB8为0和1,均可以使收到的数据进入SBUF,并激活RI(即此时RB8不具有控制RI激活的功能)。通过控制SM2,可以实现多机通信。
在方式0时,SM2必须是0。在方式1时,如果SM2=1,则只有接收到有效停止位时,RI才置1。
REN,允许串行接收位。由软件置REN=1,则启动串行口接收数据;若软件置REN=0,则禁止接收

TI,发送中断标志位。在方式0时,当串行发送第8位数据结束时,或在其它方式,串行发送停止位的开始时,由内部硬件使TI置1,向CPU发中断申请。在中断服务程序中,必须用软件将其清0,取消此中断申请。

RI,接收中断标志位。在方式0时,当串行接收第8位数据结束时,或在其它方式,串行接收停止位的中间时,由内部硬件使RI置1,向CPU发中断申请。也必须在中断服务程序中,用软件将其清0,取消此中断申请。

PCON中只有一位SMOD与串行口工作有关 :SMOD(PCON.7) 波特率倍增位。在串行口方式1、方式2、方式3时,波特率与SMOD有关,当SMOD=1时,波特率提高一倍。复位时,SMOD=0。

80C51串行口的工作方式
这里只介绍方式1:
方式1是10位数据的异步通信口。TXD为数据发送引脚,RXD为数据接收引脚,传送一帧数据的格式如图所示。其中1位起始位,8位数据位,1位停止位。
在这里插入图片描述
在这里插入图片描述
用软件置REN为1时,接收器以所选择波特率的16倍速率采样RXD引脚电平,检测到RXD引脚输入电平发生负跳变时,则说明起始位有效,将其移入输入移位寄存器,并开始接收这一帧信息的其余位。接收过程中,数据从输入移位寄存器右边移入,起始位移至输入移位寄存器最左边时,控制电路进行最后一次移位。当RI=0,且SM2=0(或接收到的停止位为1)时,将接收到的9位数据的前8位数据装入接收SBUF,第9位(停止位)进入RB8,并置RI=1,向CPU请求中断。

方式1的波特率 =(2SMOD/32)·(T1溢出率)
T1 溢出率 = fosc /{12×[256 -(TH1)]}

在这里插入图片描述

DS18B20温度传感器原理
DS18B20温度转换规则
DS18B20的核心功能是它可以直接读出数字的温度数值。温度传感器的精度为用户可编程的9,10,11或12位,分别以0.5℃,0.25℃,0.125℃和0.0625℃增量递增。在上电状态下默认的精度为12位。

在这里插入图片描述
这是12位转化后得到的12位数据,存储在DS18B20的两个8位的RAM中,高字节的前5位是符号位,如果测得的温度大于0,这5位为‘0’,只要将测到的数值乘以0.0625即可得到实际温度;如果温度小于0,这5位为‘1’,测到的数值需要先减1再取反再乘以0.0625即可得到实际温度。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
(1).数据线拉到低电平“0”。
(2).延时480微妙(该时间的时间范围可以从480到960微妙)。
(3).数据线拉到高电平“1”。
(4).延时等待80微妙。如果初始化成功则在15到60微妙时间内产生一个由DS18B20所返回的低电平“0”.根据该状态可以来确定它的存在,但是应注意不能无限的进行等待,不然会使程序进入死循环,所以要进行超时判断。
(5).若CPU读到了数据线上的低电平“0”后,还要做延时,其延时的时间从发出的高电平算起(第(3)步的时间算起)最少要480微妙。

读时序
在这里插入图片描述
(1).将数据线拉低“0”。
(2).延时1微妙。
(3).将数据线拉高“1”,释放总线准备读数据。
(4).延时10微妙。
(5).读数据线的状态得到1个状态位,并进行数据处理。
(6).延时45微妙。
(7).重复1~7步骤,直到读完一个字节。

写时序
在这里插入图片描述
(1).数据线先置低电平“0”
(2).延时15微妙。
(3).按从低位到高位的顺序发送数据(一次只发送一位)。
(4).延时60微妙。
(5).将数据线拉到高电平。
(6).重复1~5步骤,直到发送完整的字节。
(7).最后将数据线拉高。

#include<reg51.h>	
#define LCD1602_DATAPINS P0

typedef	 unsigned int	  uint;
typedef unsigned char	 uchar;

sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^5;
sbit LCD1602_RS=P2^6;
sbit DSPORT=P3^7;

uchar CNCHAR[6] = "摄氏度";

void LcdInit();
void LcdWriteData(uchar dat);
void LcdWriteCom(uchar com);
void LcdDisplay(int);
void UsartConfiguration();
uchar init();
void writebyte(uchar datas);
void change_temper();
void read_tempercom();
uint read_temper();
uchar readbyte();
void DelayMs(unsigned int x);

void main(void)	
{
	UsartConfiguration();
	LcdInit();			 //初始化LCD1602
	LcdWriteCom(0x88);	//写地址 80表示初始地址
	LcdWriteData('C'); 
	while(1)
	{
		LcdDisplay(read_temper());
//		Delay1ms(1000);//1s钟刷一次
	}				
}

void DelayMs(unsigned int x)   //0.14ms误差 0us
{
 unsigned char i;
  while(x--)
 {
  for (i = 0; i<13; i++)
 {}
 }
}

void LcdDisplay(int temp) 	 //lcd显示
{
    
  	unsigned char i, datas[] = {0, 0, 0, 0, 0}; //定义数组
	float tp;  
	if(temp< 0)				//当温度值为负数
  	{
	  	LcdWriteCom(0x80);		//写地址 80表示初始地址
		SBUF='-';//将接收到的数据放入到发送寄存器
		while(!TI);			         //等待发送数据完成
		TI=0;						 //清除发送完成标志位
	    LcdWriteData('-');  		//显示负
		//因为读取的温度是实际温度的补码,所以减1,再取反求出原码
		temp=temp-1;
		temp=~temp;
		tp=temp;
		temp=tp*0.0625*100+0.5;	
		//留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
		//后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
		//算由?.5,还是在小数点后面。
 
  	}
 	else
  	{			
	  	LcdWriteCom(0x80);		//写地址 80表示初始地址
	    LcdWriteData('+'); 		//显示正
		SBUF='+';//将接收到的数据放入到发送寄存器
		while(!TI);			         //等待发送数据完成
		TI=0;						 //清除发送完成标志位
		tp=temp;//因为数据处理有小数点所以将温度赋给一个浮点型变量
		//如果温度是正的那么,那么正数的原码就是补码它本身
		temp=tp*0.0625*100+0.5;	
		//留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
		//后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
		//算加上0.5,还是在小数点后面。
	}
	datas[0] = temp / 10000;
	datas[1] = temp % 10000 / 1000;
	datas[2] = temp % 1000 / 100;
	datas[3] = temp % 100 / 10;
	datas[4] = temp % 10;

	LcdWriteCom(0x82);		  //写地址 80表示初始地址
	LcdWriteData('0'+datas[0]); //百位 
	SBUF = '0'+datas[0];//将接收到的数据放入到发送寄存器
	while (!TI);			         //等待发送数据完成
	TI = 0;
	
	LcdWriteCom(0x83);		 //写地址 80表示初始地址
	LcdWriteData('0'+datas[1]); //十位
	SBUF = '0'+datas[1];//将接收到的数据放入到发送寄存器
	while (!TI);			         //等待发送数据完成
	TI = 0;

	LcdWriteCom(0x84);		//写地址 80表示初始地址
	LcdWriteData('0'+datas[2]); //个位 
	SBUF = '0'+datas[2];//将接收到的数据放入到发送寄存器
	while (!TI);			         //等待发送数据完成
	TI = 0;

	LcdWriteCom(0x85);		//写地址 80表示初始地址
	LcdWriteData('.'); 		//显示 ‘.’
	SBUF = '.';//将接收到的数据放入到发送寄存器
	while (!TI);			         //等待发送数据完成
	TI = 0;

	LcdWriteCom(0x86);		 //写地址 80表示初始地址
	LcdWriteData('0'+datas[3]); //显示小数点  
	SBUF = '0'+datas[3];//将接收到的数据放入到发送寄存器
	while (!TI);			         //等待发送数据完成
	TI = 0;

	LcdWriteCom(0x87);		 //写地址 80表示初始地址
	LcdWriteData('0'+datas[4]); //显示小数点 
	SBUF = '0'+datas[4];//将接收到的数据放入到发送寄存器
	while (!TI);			         //等待发送数据完成
	TI = 0;
	for(i=0; i<6; i++)
	{
	 	SBUF = CNCHAR[i];//将接收到的数据放入到发送寄存器
		while (!TI);			         //等待发送数据完成
		TI = 0;
	}

	 
}


void UsartConfiguration()
{
	SCON=0X50;			//设置为工作方式1
	TMOD=0X20;			//设置计数器工作方式2
	PCON=0X80;			//波特率加倍
	TH1=0XF3;				//计数器初始值设置,注意波特率是4800的
	TL1=0XF3;
//	ES=1;						//打开接收中断
//	EA=1;						//打开总中断
	TR1=1;					//打开计数器
}


/****************
温度传感器部分
****************/
uchar init()
{
	uchar i=0;
	DSPORT=0;
	i = 70;				   //将总线拉低480us~960us
	while(i--);//延时642us
	DSPORT=1;				 //然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低
	i=0;
	while(DSPORT)		   //等待DS18B20拉低总线
	{
		 DelayMs(1);
		 i++;		  
		 if(i>5)
		 {
		 	return 0;			 //初始化失败
		 }
	}
	return 1;
}

void writebyte(uchar datas)
{
	uchar i,j=1;
	for(i=0;i<8;i++)
	{
		DSPORT=0;		   //每写入一位数据之前先把总线拉低1us
		//j++;		  //此处延时1us,好像又影响不大
		DSPORT=datas&0x01;
		j=6;
		while(j--); //延时68us,持续时间最少60us
		DSPORT=1;		 //然后释放总线,至少1us给总线恢复时间才能接着写入第二个数值
		datas>>=1;
	}
}

uchar readbyte()
{
	uchar dat=0,temp;
	uint i ,j;
	for(i=0;i<8;i++)
	{
		DSPORT=0;	 //先将总线拉低1us
		j++;
		DSPORT=1;	//然后释放总线
		j++;	  //此处延时有变化,等待6us
		j++;
		temp=DSPORT;	 //读取数据,从最低位开始读取
		/*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/
		dat=(dat>>1)|(temp<<7);
		j = 4;		//读取完之后等待48us再接着读取下一个数
		while(j--);;			 //好像没影响
	}
	return dat;		//不是temp
}

void change_temper()
{
	init();
	DelayMs(1);			   //无影响
	writebyte(0xcc);		  //跳过ROM操作命令	
	writebyte(0x44);		   //温度转换命令
}

void read_tempercom()
{
   	init();
	//DelayMs(1);
	writebyte(0xcc);
	writebyte(0xbe);		 //发送读取温度命令
}

uint read_temper()
{
	uchar tml,tmh;
	uint t=0;
	change_temper();			//先写入转换命令
	read_tempercom();			//然后等待转换完后发送读取温度命令
	tml=readbyte();				//读取温度值共16位,先读低字节
	tmh=readbyte();				//再读高字节
	t=tmh;
	t<<=8;			//移8位
	t=tml|t;

	return t;
}
/********************
 LCD液晶部分
********************/

void LcdWriteCom(uchar com)	  //写入命令
{
	LCD1602_E = 0;     //使能
	LCD1602_RS = 0;	   //选择发送命令
	LCD1602_RW = 0;	   //选择写入
	
	LCD1602_DATAPINS = com;     //放入命令
	DelayMs(1);		//等待数据稳定

	LCD1602_E = 1;	          //写入时序
	DelayMs(5);	  //保持时间
	LCD1602_E = 0;
}

void LcdWriteData(uchar dat)			//写入数据
{
	LCD1602_E = 0;	//使能清零
	LCD1602_RS = 1;	//选择输入数据
	LCD1602_RW = 0;	//选择写入

	LCD1602_DATAPINS = dat; //写入数据
	DelayMs(1);

	LCD1602_E = 1;   //写入时序
	DelayMs(5);   //保持时间
	LCD1602_E = 0;
}

void LcdInit()						  //LCD初始化子程序
{
 	LcdWriteCom(0x38);  //开显示
	LcdWriteCom(0x0c);  //开显示不显示光标
	LcdWriteCom(0x06);  //写一个指针加1
	LcdWriteCom(0x01);  //清屏
	LcdWriteCom(0x80);  //设置数据指针起点
}

LCD显示部分可以参考我一篇文章
51单片机DS1302时钟LCD1602显示

以上是我在学习过程中的一点总结,用的是普中的51单片机·。

2017-02-20 20:36:09 qq_29233719 阅读数 1123
/*-----------------------------------------------
  名称:DS18b20 温度检测液晶显示
  论坛:www.doflye.net
  编写:shifang
  日期:2009.5
  修改:无
  内容:
------------------------------------------------*/
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include<stdio.h>
#include "18b20.h"
#include "1602.h"
#include "delay.h"


#define KeyPort P3 //定义按键端口


bit ReadTempFlag;//定义读时间标志


void Init_Timer0(void);//定时器初始化
unsigned char KeyScan(void);//键盘扫描
/*------------------------------------------------
              串口通讯初始化
------------------------------------------------*/
void UART_Init(void)
{
    SCON  = 0x50;        // SCON: 模式 1, 8-bit UART, 使能接收  
    TMOD |= 0x20;               // TMOD: timer 1, mode 2, 8-bit 重装
    TH1   = 0xFD;               // TH1:  重装值 9600 波特率 晶振 11.0592MHz  
    TR1   = 1;                  // TR1:  timer 1 打开                         
    //EA    = 1;                  //打开总中断
    //ES    = 1;                  //打开串口中断
TI=1;
}
/*------------------------------------------------
                    主函数
------------------------------------------------*/
void main (void)
{                  
int temp,tempH=50,tempL=1;
float temperature;
unsigned char TempFlag=0;
char displaytemp[16],num;//定义显示区域临时存储数组


LCD_Init();           //初始化液晶
DelayMs(20);          //延时有助于稳定
LCD_Clear();          //清屏
Init_Timer0();
UART_Init();
Lcd_User_Chr();       //写入自定义字符




while (1)         //主循环
  {
 num=KeyScan();
 switch(num)
       {
   case 1:if(tempH<127)tempH++;break;
case 2:if(tempH>-55)tempH--;break;
case 3:if(tempL<127)tempL++;break;
case 4:if(tempL>-55)tempL--;break;
default:break;
  }
 
switch(TempFlag)
       {
   case 0:    //输出温度上限下限
     sprintf(displaytemp,"H.%3d  L.%3d ",tempH,tempL);
              LCD_Write_String(0,1,displaytemp);//显示第二行
 break;
case 1:LCD_Write_String(0,1,"over  tempH    ");break;
case 2:LCD_Write_String(0,1,"under  tempL   ");break;
default:break;
  }
if(ReadTempFlag==1)
 {
  ReadTempFlag=0;
  temp=ReadTemperature();




  temperature=temp*0.0625;


  temp>>=4;
 if(temp>tempH)
    TempFlag=1;  //高于高温标志
 else if(temp<tempL)
    TempFlag=2;  //低于低温标志
 else
   TempFlag=0;   //正常显示标志


    


  sprintf(displaytemp,"Temp  %6.2f ",temperature);//打印温度值
  LCD_Write_String(0,0,displaytemp);//显示第一行
  LCD_Write_Char(13,0,0x01);//写入温度右上角点
  LCD_Write_Char(14,0,'C'); //写入字符C
  } 
 }
}


/*------------------------------------------------
                    定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void)
{
 TMOD |= 0x01;  //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
    
 //TH0=0x00;      //给定初值
 //TL0=0x00;
 EA=1;            //总中断打开
 ET0=1;           //定时器中断打开
 TR0=1;           //定时器开关打开
}
/*------------------------------------------------
                 定时器中断子程序
------------------------------------------------*/
void Timer0_isr(void) interrupt 1 
{
 static unsigned int num;
 TH0=(65536-2000)/256;  //重新赋值 2ms
 TL0=(65536-2000)%256;
 
 num++;
 if(num==400)        //
   {
    num=0;
    ReadTempFlag=1; //读标志位置1
}
}


/*------------------------------------------------
按键扫描函数,返回扫描键值
------------------------------------------------*/
unsigned char KeyScan(void)
{
 unsigned char keyvalue;
 if(KeyPort!=0xff)
   {
    DelayMs(10);
    if(KeyPort!=0xff)
  {
   keyvalue=KeyPort;
   while(KeyPort!=0xff);
switch(keyvalue)
{
case 0xfe:return 1;break;
case 0xfd:return 2;break;
case 0xfb:return 3;break;
case 0xf7:return 4;break;
case 0xef:return 5;break;
case 0xdf:return 6;break;
case 0xbf:return 7;break;
case 0x7f:return 8;break;
default:return 0;break;
}
 }
   }
   return 0;
}