论坛风格切换切换到宽版
  • 5293阅读
  • 26回复

初学单片机DIY了个温度计 [复制链接]

上一主题 下一主题
离线yyh
发帖
1403
只看该作者 20楼 发表于: 2011-09-19
昨晚下班后研究1602液晶,整了一晚上也没有搞明白,后来想了想,就当它是led好了,直接一个字符一个字符的送进去显示,居然给误打误撞弄出来了,原来驱动液晶真的很简单,哈哈。上午没什么别的事情,抓紧时间写了一个1602的电子钟,带utc同步显示。
//头文件:
#include "reg51.h"


/********io引脚定义***********************************************************/
sbit lcd_rs=p1^0;//定义引脚
sbit lcd_rw=p1^1;
sbit lcd_e=p1^2;

/********宏定义***********************************************************/
#define lcd_data p0
#define busy   0x80 //用于检测lcd状态字中的busy标识

/********数据定义*************************************************************/

unsigned char wdlcd,x,y,ddata,a1;
/********函数声明*************************************************************/
void writedatalcd(unsigned char wdlcd);                              //写数据
void writecommandlcd(unsigned char wclcd,buysc);            //写命令
unsigned char readdatalcd(void);                                    //读数据
unsigned char readstatuslcd(void);                                    //读状态
void lcdinit(void);                                                            //初始化
void displayonechar(unsigned char x, unsigned char y, unsigned char ddata);                  //相应坐标显示字节内容
void delay5ms(void);                                                      //延时
void delay400ms(void);                                                      //延时

//变量定义:
                             
unsigned char tt;      
unsigned char ss;
unsigned char mm;
unsigned char hh;//作为计数时间量
char hh_utc;      //协调时

//引脚定义:            


sbit key_h=p3^3;//设定小时
sbit key_m=p3^2;//设定分钟

//函数声明:
void display(void);//定义显示函数,参数为显示内容,只显示两位数
void delay(void);
void init();                              //初如化函数
void delay_ms (unsigned int a);

//主函数,c语言的入口函数:      
void main()
{
     init();                              //初始化中断控制寄存器
  delay400ms();      //启动等待,等lcd讲入工作状态
     lcdinit();            //初始化
     delay5ms();      //延时片刻(可不要)
     while(1){
if(key_m==0){ delay_ms(10);if(key_m==0){mm++;if(mm==60) mm=0;} delay_ms(300);}
if(key_h==0){ delay_ms(10);if(key_h==0){hh++;if(hh==24) hh=0;} delay_ms(300);} //设置              
if(ss==60){ss=0;mm=mm++;}//60秒计数进位
if(mm==60){mm=0;hh=hh++;}//60分钟计数进位
if(hh==24){hh=0;}//24小时计数      

hh_utc=hh-8;
if(hh_utc<0) hh_utc=24+hh_utc;//utc协调时换算

display();            //显示变量内容
     }
}

//初始化函数
void init()
{
     tt=0;
     tmod=0x01;            //设置定时器1为模式一,即16位计算模式
     th0=(65536-10000)/256;      //给计数寄存器赋值,10毫秒时间
     tl0=(65536-10000)%256;
     ea=1;            //开启总中断
     et0=1;            //开启定时器0中断
     tr0=1;            //启定定时器0
}

//中断函数,关键字"interrupt" , 这是c语言的中断函数表示法,1表时定地器0
void timer() interrupt 1
{
     th0=(65536-10000)/256;      //重新赋值
     tl0=(65536-10000)%256;
     tt++;                              //10毫秒加1,加100次为一秒
  if(tt==100) {tt=0;ss++;}      //100*10ms定时时间为1秒 计数变量加1            
}

//显示函数,参数为显示内容,只显示两位数
void display(void)
{
//第一行
  lcd_data=85;      
  displayonechar(0, 0, lcd_data);
  lcd_data=84;      
  displayonechar(1, 0, lcd_data);
     lcd_data=67;      
  displayonechar(2, 0, lcd_data);//显示utc

     lcd_data=hh_utc /10+0x30;      
  displayonechar(5, 0, lcd_data);
     lcd_data=hh_utc%10+0x30;      
     displayonechar(6, 0, lcd_data);//显示协调时小时

  lcd_data=0x3a;
  displayonechar(7, 0, lcd_data);//显示":"
     lcd_data=mm/10+0x30;      
  displayonechar(8, 0, lcd_data);      
  lcd_data=mm%10+0x30;      
  displayonechar(9, 0, lcd_data);//显示协调时分钟

     lcd_data=0x3a;
  displayonechar(10, 0, lcd_data);//显示":"
     lcd_data=ss/10+0x30;      
  displayonechar(11, 0, lcd_data);      
  lcd_data=ss%10+0x30;      
  displayonechar(12, 0, lcd_data);//显示协调时秒钟

//第二行
  lcd_data=66;      
  displayonechar(0, 1, lcd_data);
  lcd_data=84;      
  displayonechar(2, 1, lcd_data);//显示bt


     lcd_data=hh/10+0x30;      
  displayonechar(5, 1, lcd_data);
     lcd_data=hh%10+0x30;      
      displayonechar(6, 1, lcd_data)      ;//显示北京时间小时

     lcd_data=0x3a;
  displayonechar(7, 1, lcd_data);//显示":"
     lcd_data=mm/10+0x30;      
  displayonechar(8, 1, lcd_data);      
  lcd_data=mm%10+0x30;      
  displayonechar(9, 1, lcd_data);//显示北京时间分钟

     lcd_data=0x3a;
  displayonechar(10, 1, lcd_data);//显示":"
     lcd_data=ss/10+0x30;      
  displayonechar(11, 1, lcd_data);      
  lcd_data=ss%10+0x30;      
  displayonechar(12, 1, lcd_data);//显示北京时间秒钟
     
}

//延时子函数,短暂延时'
void delay(void){            
     unsigned char i=10;
     while(i--);
}

void delay_ms (unsigned int a){
     unsigned int i;
     while( a-- != 0){
           for(i = 0; i < 100; i++);
     }
}







/***********写数据********************************************************/      
void writedatalcd(unsigned char wdlcd)
{
     readstatuslcd(); //检测忙
     lcd_data = wdlcd;
     lcd_rs = 1;
     lcd_rw = 0;
     lcd_e = 0;            //若晶振速度太高可以在这后加小的延时
     lcd_e = 0;            //延时
     lcd_e = 1;
}

/***********写指令********************************************************/      
void writecommandlcd(unsigned char wclcd,buysc) //buysc为0时忽略忙检测
{
     if (buysc) readstatuslcd(); //根据需要检测忙
     lcd_data = wclcd;
     lcd_rs = 0;
     lcd_rw = 0;
     lcd_e = 0;
     lcd_e = 0;
     lcd_e = 1;
}

/***********读数据********************************************************/      
unsigned char readdatalcd(void)
{
     lcd_rs = 1;
     lcd_rw = 1;
     lcd_e = 0;
     lcd_e = 0;
     lcd_e = 1;
     return(lcd_data);
}

/***********读状态*******************************************************/      
unsigned char readstatuslcd(void)
{
     lcd_data = 0xff;
     lcd_rs = 0;
     lcd_rw = 1;
     lcd_e = 0;
     lcd_e = 0;
     lcd_e = 1;
     while (lcd_data & busy); //检测忙信号
     return(lcd_data);
}

/***********初始化********************************************************/      
void lcdinit(void)
{
     lcd_data = 0;
     writecommandlcd(0x38,0);      //三次模式设置,不检测忙信号
     delay5ms();
     writecommandlcd(0x38,0);
     delay5ms();
     writecommandlcd(0x38,0);
     delay5ms();

     writecommandlcd(0x38,1);      //显示模式设置,开始要求每次检测忙信号
     writecommandlcd(0x08,1);      //关闭显示
     writecommandlcd(0x01,1);      //显示清屏
     writecommandlcd(0x06,1);      //显示光标移动设置
     writecommandlcd(0x0c,1);      //显示开及光标设置
}

/***********按指定位置显示一个字符*******************************************/      
void displayonechar(unsigned char x, unsigned char y, unsigned char ddata)
{
     y &= 0x1;
     x &= 0xf;                        //限制x不能大于15,y不能大于1
     if (y) x |= 0x40;            //当要显示第二行时地址码+0x40;
     x |= 0x80;                  //算出指令码
     writecommandlcd(x, 0); //这里不检测忙信号,发送地址码
     writedatalcd(ddata);
}
     

/***********短延时********************************************************/      
void delay5ms(void)
{
     unsigned int tempcyc = 5552;
     while(tempcyc--);
}

/***********长延时********************************************************/      
void delay400ms(void)
{
     unsigned char tempcyca = 5;
     unsigned int tempcycb;
     while(tempcyca--){
           tempcycb=7269;
           while(tempcycb--);
     }
}
本主题包含附件,请 登录 后查看, 或者 注册 成为会员
离线BD4UAC
发帖
128
只看该作者 21楼 发表于: 2011-09-19
楼主神人也,鉴定完毕,
离线老干部
发帖
7646
只看该作者 22楼 发表于: 2011-09-19
做成有串口nmea格式输出的,肯定有人要!!!!!
离线yyh
发帖
1403
只看该作者 23楼 发表于: 2011-09-19
再来一张,改了下加入了温度显示
//头文件:
#include "reg51.h"
#include "ds18b20.h"      //引入ds18b20头文件

/********io引脚定义***********************************************************/
sbit lcd_rs=p1^0;//定义引脚
sbit lcd_rw=p1^1;
sbit lcd_e=p1^2;

/********宏定义***********************************************************/
#define lcd_data p0
#define busy   0x80 //用于检测lcd状态字中的busy标识

/********函数声明*************************************************************/
void writedatalcd(unsigned char wdlcd);                              //写数据
void writecommandlcd(unsigned char wclcd,buysc);            //写命令
unsigned char readdatalcd(void);                                    //读数据
unsigned char readstatuslcd(void);                                    //读状态
void lcdinit(void);                                                            //初始化
void displayonechar(unsigned char x, unsigned char y, unsigned char ddata);                  //相应坐标显示字节内容
void delay5ms(void);                                                      //延时
void delay400ms(void);                                                      //延时
void display(void);//定义显示函数,参数为显示内容,只显示两位数
void delay(void);
void init();                              //初如化函数
void delay_ms (unsigned int a);

//变量定义:
char ltemp;            //定义温度                  
unsigned char tt;      //定义毫秒
unsigned char ss;
unsigned char mm;
unsigned char hh;//定义计数时间量
char hh_utc;      //定义协调时

//引脚定义:            


sbit key_h=p3^3;//设定小时
sbit key_m=p3^2;//设定分钟


//主函数,c语言的入口函数:      
void main()
{unsigned int i=0;      
     init();                              //初始化中断控制寄存器
  delay400ms();      //启动等待,等lcd讲入工作状态
     lcdinit();            //初始化
     delay5ms();      //延时片刻(可不要)
     while(1){
/*以下时间转换部分*/
if(key_m==0){ delay_ms(10);if(key_m==0){mm++;if(mm==60) mm=0;} delay_ms(300);}
if(key_h==0){ delay_ms(10);if(key_h==0){hh++;if(hh==24) hh=0;} delay_ms(300);} //设置时间              
if(ss==60){ss=0;mm=mm++;}//60秒计数进位
if(mm==60){mm=0;hh=hh++;}//60分钟计数进位
if(hh==24){hh=0;}//24小时计数      

hh_utc=hh-8;
if(hh_utc<0) hh_utc=24+hh_utc;//utc协调时换算

/*以下温度转换部分*/
           if(i==0)                        //先发转换命令,再读数值,以减少速度慢带来的显示抖动
                 tmpchange();          //温度转换
           if(i==100)
                 ltemp=tmp()/16;            //得到十进制温度值,因为ds18b20可以精确到0.0625度,这里取整数显示            
           if(ltemp<0) ltemp=-ltemp;//处理负数温度
           i++;
           if(i==1000)      i=0;                  //3000一个读取周期

    display();            //显示变量内容
     }
}



//显示函数,参数为显示内容,只显示两位数
void display(void)
{
//第一行
  lcd_data=84;
  displayonechar(0, 0, lcd_data);
  lcd_data=77;      
  displayonechar(1, 0, lcd_data);
     lcd_data=80;      
  displayonechar(2, 0, lcd_data);//显示tmp

  lcd_data=66;      
  displayonechar(4, 0, lcd_data);
  lcd_data=74;      
  displayonechar(5, 0, lcd_data);
  lcd_data=84;      
  displayonechar(6, 0, lcd_data);//显示bjt

  lcd_data=126;      
  displayonechar(7, 0, lcd_data);//显示箭头

     lcd_data=hh/10+0x30;      
  displayonechar(8, 0, lcd_data);
     lcd_data=hh%10+0x30;      
      displayonechar(9, 0, lcd_data)      ;//显示北京时间小时

     lcd_data=0x3a;
  displayonechar(10, 0, lcd_data);//显示":"
     
     lcd_data=mm/10+0x30;      
  displayonechar(11, 0, lcd_data);      
  lcd_data=mm%10+0x30;      
  displayonechar(12, 0, lcd_data);//显示北京时间分钟

     lcd_data=0x3a;
  displayonechar(13, 0, lcd_data);//显示":"
     
     lcd_data=ss/10+0x30;      
  displayonechar(14, 0, lcd_data);      
  lcd_data=ss%10+0x30;      
  displayonechar(15, 0, lcd_data);//显示北京时间秒钟




//第二行


     lcd_data=ltemp/10+0x30;      
     if(tmp()<0) lcd_data=45;//判断如果温度是负数,就在十位显示负号
  displayonechar(0, 1, lcd_data);
     lcd_data=ltemp%10+0x30;      
  displayonechar(1, 1, lcd_data)      ;//显示温度

     lcd_data=67;      
  displayonechar(2, 1, lcd_data)      ;//显示c字母

  lcd_data=85;      
  displayonechar(4, 1, lcd_data);
  lcd_data=84;      
  displayonechar(5, 1, lcd_data);
     lcd_data=67;      
  displayonechar(6, 1, lcd_data);//显示utc

  lcd_data=126;      
  displayonechar(7, 1, lcd_data);//显示箭头

     lcd_data=hh_utc /10+0x30;      
  displayonechar(8, 1, lcd_data);
     lcd_data=hh_utc%10+0x30;      
     displayonechar(9, 1, lcd_data);//显示协调时小时

  lcd_data=0x3a;
  displayonechar(10, 1, lcd_data);//显示":"
     lcd_data=mm/10+0x30;      
  displayonechar(11, 1, lcd_data);      
  lcd_data=mm%10+0x30;      
  displayonechar(12, 1, lcd_data);//显示协调时分钟

     lcd_data=0x3a;
  displayonechar(13, 1, lcd_data);//显示":"
     lcd_data=ss/10+0x30;      
  displayonechar(14, 1, lcd_data);      
  lcd_data=ss%10+0x30;      
  displayonechar(15, 1, lcd_data);//显示协调时秒钟
     
}

//初始化函数
void init()
{
     tt=0;
     tmod=0x01;            //设置定时器1为模式一,即16位计算模式
     th0=(65536-9986)/256;      //给计数寄存器赋值,10毫秒时间(修整了计数)
     tl0=(65536-9986)%256;
     ea=1;            //开启总中断
     et0=1;            //开启定时器0中断
     tr0=1;            //启定定时器0
}

//中断函数,关键字"interrupt" , 这是c语言的中断函数表示法,1表时定地器0
void timer() interrupt 1
{
     th0=(65536-9986)/256;      //重新赋值(修整了计数)
     tl0=(65536-9986)%256;
     tt++;                              //10毫秒加1,加100次为一秒
  if(tt==100) {tt=0;ss++;}      //100*10ms定时时间为1秒 计数变量加1            
}


/*1602液晶显示驱动部分*/

/***********写数据********************************************************/      
void writedatalcd(unsigned char wdlcd)
{
     readstatuslcd(); //检测忙
     lcd_data = wdlcd;
     lcd_rs = 1;
     lcd_rw = 0;
     lcd_e = 0;            //若晶振速度太高可以在这后加小的延时
     lcd_e = 0;            //延时
     lcd_e = 1;
}

/***********写指令********************************************************/      
void writecommandlcd(unsigned char wclcd,buysc) //buysc为0时忽略忙检测
{
     if (buysc) readstatuslcd(); //根据需要检测忙
     lcd_data = wclcd;
     lcd_rs = 0;
     lcd_rw = 0;
     lcd_e = 0;
     lcd_e = 0;
     lcd_e = 1;
}

/***********读数据********************************************************/      
unsigned char readdatalcd(void)
{
     lcd_rs = 1;
     lcd_rw = 1;
     lcd_e = 0;
     lcd_e = 0;
     lcd_e = 1;
     return(lcd_data);
}

/***********读状态*******************************************************/      
unsigned char readstatuslcd(void)
{
     lcd_data = 0xff;
     lcd_rs = 0;
     lcd_rw = 1;
     lcd_e = 0;
     lcd_e = 0;
     lcd_e = 1;
     while (lcd_data & busy); //检测忙信号
     return(lcd_data);
}

/***********初始化********************************************************/      
void lcdinit(void)
{
     lcd_data = 0;
     writecommandlcd(0x38,0);      //三次模式设置,不检测忙信号
     delay5ms();
     writecommandlcd(0x38,0);
     delay5ms();
     writecommandlcd(0x38,0);
     delay5ms();

     writecommandlcd(0x38,1);      //显示模式设置,开始要求每次检测忙信号
     writecommandlcd(0x08,1);      //关闭显示
     writecommandlcd(0x01,1);      //显示清屏
     writecommandlcd(0x06,1);      //显示光标移动设置
     writecommandlcd(0x0c,1);      //显示开及光标设置
}

/***********按指定位置显示一个字符*******************************************/      
void displayonechar(unsigned char x, unsigned char y, unsigned char ddata)
{
     y &= 0x1;
     x &= 0xf;                        //限制x不能大于15,y不能大于1
     if (y) x |= 0x40;            //当要显示第二行时地址码+0x40;
     x |= 0x80;                  //算出指令码
     writecommandlcd(x, 0); //这里不检测忙信号,发送地址码
     writedatalcd(ddata);
}
     

/***********短延时********************************************************/      
void delay5ms(void)
{
     unsigned int tempcyc = 5552;
     while(tempcyc--);
}

/***********长延时********************************************************/      
void delay400ms(void)
{
     unsigned char tempcyca = 5;
     unsigned int tempcycb;
     while(tempcyca--){
           tempcycb=7269;
           while(tempcycb--);
     }
}


//延时子函数,短暂延时'
void delay(void){            
     unsigned char i=10;
     while(i--);
}

void delay_ms (unsigned int a){
     unsigned int i;
     while( a-- != 0){
           for(i = 0; i < 100; i++);
     }
}
本主题包含附件,请 登录 后查看, 或者 注册 成为会员
离线BD4UAC
发帖
128
只看该作者 24楼 发表于: 2011-09-19
'
这个东西很实用哈
'
但实际成本并不合算,市场上同样功能的电子钟就一片单片机钱,
离线BG4NWO
发帖
144
只看该作者 25楼 发表于: 2011-09-20
这些程序看着就头疼
离线ihweb
发帖
586
只看该作者 26楼 发表于: 2011-09-20
软硬兼施了。