找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 12602|回复: 27
收起左侧

数码管显示温度

  [复制链接]
ID:83083 发表于 2015-6-15 18:31 | 显示全部楼层 |阅读模式
问题:用这个程序烧写到单片机里面结果发现。三位数码管中总有两位显示的时候闪个不停,并且亮度较正常显示的时候暗。求大神教
数码管显示温度程序如下:
#include<reg52.h>    //包含单片机寄存器的头文件
#include<intrins.h>  //包含_nop_()函数定义的头文件
unsigned char flag,tltemp;      //负温度标志 和临时暂存变量
unsigned char code s8[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//数码管数字0-9
void delay1ms()
{
   unsigned char i,j;
  for(i=0;i<4;i++)
   for(j=0;j<33;j++)
    ;   
}
void delaynms(unsigned char n)
{
   unsigned char i;
for(i=0;i<n;i++)
    delay1ms();
}
/************************************************************************
以下是DS18B20的操作程序
************************************************************************/
sbit DQ=P3^3;
unsigned char time;   //设置全局变量,专门用于严格延时
/*****************************************************
函数功能:将DS18B20传感器初始化,读取应答信号
出口参数:flag
***************************************************/
bit Init_DS18B20(void)
{
bit flag;         //储存DS18B20是否存在的标志,flag=0,表示存在;flag=1,表示不存在
DQ = 1;           //先将数据线拉高
for(time=0;time<2;time++) //略微延时约6微秒
     ;
DQ = 0;           //再将数据线从高拉低,要求保持480~960us
for(time=0;time<200;time++)  //略微延时约600微秒
     ;         //以向DS18B20发出一持续480~960us的低电平复位脉冲
DQ = 1;           //释放数据线(将数据线拉高)
  for(time=0;time<10;time++)
     ;  //延时约30us(释放总线后需等待15~60us让DS18B20输出存在脉冲)
flag=DQ;          //让单片机检测是否输出了存在脉冲(DQ=0表示存在)      
for(time=0;time<200;time++)  //延时足够长时间,等待存在脉冲输出完毕
      ;
return (flag);    //返回检测成功标志
}
/*****************************************************
函数功能:从DS18B20读取一个字节数据
出口参数:dat
***************************************************/
unsigned char ReadOneChar(void)
{
  unsigned char i=0;
  unsigned char dat;  //储存读出的一个字节数据
  for (i=0;i<8;i++)
   {
     
     DQ =1;       // 先将数据线拉高
     _nop_();     //等待一个机器周期  
     DQ = 0;      //单片机从DS18B20读书据时,将数据线从高拉低即启动读时序
     _nop_();     //等待一个机器周期     
     DQ = 1;     //将数据线"人为"拉高,为单片机检测DS18B20的输出电平作准备
     for(time=0;time<2;time++)
             ;      //延时约6us,使主机在15us内采样
     dat>>=1;
     if(DQ==1)
        dat|=0x80;  //如果读到的数据是1,则将1存入dat
   else
    dat|=0x00;//如果读到的数据是0,则将0存入dat
       //将单片机检测到的电平信号DQ存入r
     for(time=0;time<8;time++)
         ;              //延时3us,两个读时序之间必须有大于1us的恢复期
     }                     
  return(dat);    //返回读出的十六进制数据
}
/*****************************************************
函数功能:向DS18B20写入一个字节数据
入口参数:dat
***************************************************/  
WriteOneChar(unsigned char dat)
{
unsigned char i=0;
for (i=0; i<8; i++)
   {
    DQ =1;         // 先将数据线拉高
    _nop_();      //等待一个机器周期  
    DQ=0;          //将数据线从高拉低时即启动写时序      
    DQ=dat&0x01;   //利用与运算取出要写的某位二进制数据,
                       //并将其送到数据线上等待DS18B20采样
   for(time=0;time<10;time++)
       ;//延时约30us,DS18B20在拉低后的约15~60us期间从数据线上采样
    DQ=1;          //释放数据线      
    for(time=0;time<1;time++)
     ;//延时3us,两个写时序间至少需要1us的恢复期
    dat>>=1;       //将dat中的各二进制位数据右移1位
   }
   for(time=0;time<4;time++)
               ; //稍作延时,给硬件一点反应时间
}
/*****************************************************
函数功能:做好读温度的准备
***************************************************/
void ReadyReadTemp(void)
{
      Init_DS18B20();     //将DS18B20初始化
  WriteOneChar(0xCC); // 跳过读序号列号的操作
  WriteOneChar(0x44); // 启动温度转换   
       delaynms(200); //转换一次需要延时一段时间

  Init_DS18B20();     //将DS18B20初始化
  WriteOneChar(0xCC); //跳过读序号列号的操作
  WriteOneChar(0xBE); //读取温度寄存器,前两个分别是温度的低位和高位
}

/*****************************************************
函数功能:显示温度的整数部分
入口参数:x
***************************************************/
void display_temp1(unsigned char x)
{
unsigned char k,l;     //j,k,l分别储存温度的百位、十位和个位
k=(x%100)/10;    //取十位
l=x%10;             //取个位
P0=0x00;
P0=s8[l];    //将个位数字的字符常量写入LCD
P2=0xfd;    //将十位数字的字符常量写入LCD
delaynms(20);         //延时1ms给硬件一点反应时间      
P0=0x00;
P0=s8[k];
    P2=0xfe;
delaynms(1);

}
/*****************************************************
函数功能:显示温度的小数数部分
入口参数:x
***************************************************/
void display_temp2(unsigned char x)
{
P0=0x00;
P0=s8[x];
    P2=0xfb;
delaynms(20);
}

/*****************************************************
函数功能:主函数
***************************************************/
void main(void)
{   
   
   unsigned char TL;     //储存暂存器的温度低位
     unsigned char TH;    //储存暂存器的温度高位
     unsigned char TN;      //储存温度的整数部分
   unsigned char TD;       //储存温度的小数部分
    delaynms(5);        //延时5ms给硬件一点反应时间     
   while(1)                //不断检测并显示温度
  {  
   flag=0;
  ReadyReadTemp();     //读温度准备
     TL=ReadOneChar();    //先读的是温度值低位
  TH=ReadOneChar();    //接着读的是温度值高位  
  TN=TH*16+TL/16;      //实际温度值=(TH*256+TL)/16,即:TH*16+TL/16
                      //这样得出的是温度的整数部分,小数部分被丢弃了
    TD=(TL%16)*10/16;    //计算温度的小数部分,将余数乘以10再除以16取整,
                     //这样得到的是温度小数部分的第一位数字(保留1位小数)
   display_temp2(TD);
     display_temp1(TN);    //显示温度的整数部
       delaynms(1);                          
    }
     
}

回复

使用道具 举报

ID:83193 发表于 2015-6-16 21:37 | 显示全部楼层
顶一下
回复

使用道具 举报

ID:83246 发表于 2015-6-17 12:21 | 显示全部楼层
不知道你用的是LCD屏还是数码管在显示,LCD屏显示,如果出现闪动,或者比较暗的话,多半就是单片机一直重复在向LCD那一位写数据,导致LCD一直在更新那一个字符,  
如果是数码管显示,就看看WHILE循环中是不是周期长了点,我以前也遇到过类似的,LCD也遇到过,就是一直重复在写数据,导致LCD一直在刷新屏幕

评分

参与人数 1黑币 +35 收起 理由
admin + 35 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:61876 发表于 2015-6-17 12:33 | 显示全部楼层
这个程序用数码管显示还缺位码及很多的定义;用1602显示也缺少有关的定义。

评分

参与人数 1黑币 +35 收起 理由
admin + 35 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:83083 发表于 2015-6-17 13:04 | 显示全部楼层
z1061828841 发表于 2015-6-17 12:21
不知道你用的是LCD屏还是数码管在显示,LCD屏显示,如果出现闪动,或者比较暗的话,多半就是单片机一直重复 ...

我用的是数码管显示。那这个程序要怎么修改才能使他正常显示呢,求教
回复

使用道具 举报

ID:83083 发表于 2015-6-17 13:04 | 显示全部楼层
gaozhaohong 发表于 2015-6-17 12:33
这个程序用数码管显示还缺位码及很多的定义;用1602显示也缺少有关的定义。

那这个该怎么修改呢
回复

使用道具 举报

ID:83083 发表于 2015-6-17 14:48 | 显示全部楼层
gaozhaohong 发表于 2015-6-17 12:33
这个程序用数码管显示还缺位码及很多的定义;用1602显示也缺少有关的定义。

请问具体可以怎么修改呢
回复

使用道具 举报

ID:61876 发表于 2015-6-22 20:59 | 显示全部楼层
邱育 发表于 2015-6-17 14:48
请问具体可以怎么修改呢

不知道是想用LED还是想用LCD?
回复

使用道具 举报

ID:81118 发表于 2015-6-22 22:21 | 显示全部楼层
你这个程序 小数部分显示的应该比较暗          写个 计数中断  把显示 放到中断服务函数去

评分

参与人数 1黑币 +35 收起 理由
admin + 35 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:83349 发表于 2015-6-27 13:35 | 显示全部楼层
顶顶更好

评分

参与人数 1黑币 +35 收起 理由
admin + 35 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:82588 发表于 2015-6-29 19:15 | 显示全部楼层
本帖最后由 dely2009 于 2015-6-29 19:18 编辑

修改你的延时   如果不行的话   改用频率较高的晶振设置,,,  动态扫描显示数码管   延时过长 会闪烁  还会偏暗

评分

参与人数 1黑币 +35 收起 理由
admin + 35 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:84419 发表于 2015-6-30 23:37 | 显示全部楼层
这个我也需要一份,
回复

使用道具 举报

ID:18297 发表于 2015-7-1 20:47 | 显示全部楼层
1)你的显示为动态扫描,必须在DS18S20的温度采集的延时等待时间中插入显示输出,否则你的显示会变暗或黑屏。
2)你的显示程序,小数点和个位显示重合。位选都是P2=0xfd;
3)这种DS18S20的读取温度需要有一定的延时,加上动态扫描显示,必须要在时间上安排好。

评分

参与人数 1黑币 +35 收起 理由
admin + 35 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:84532 发表于 2015-7-2 09:30 | 显示全部楼层
没有看懂。。。。
回复

使用道具 举报

ID:19715 发表于 2015-7-3 18:55 | 显示全部楼层
只能是改善一点
/*****************************************************
函数功能:显示温度的整数部分
入口参数:x
***************************************************/
void display_temp1(unsigned char x)
{
unsigned char k,l;     //j,k,l分别储存温度的百位、十位和个位
k=(x%100)/10;    //取十位
l=x%10;             //取个位
P0=0xff;
P2=0xfd;    //将十位数字的字符常量写入LCD
P0=s8[l];    //将个位数字的字符常量写入LCD
delaynms(4);         //延时1ms给硬件一点反应时间      
P0=0xff;
P2=0xfe;
P0=s8[k];
delaynms(4);
}
/*****************************************************
函数功能:显示温度的小数数部分
入口参数:x
***************************************************/
void display_temp2(unsigned char x)
{
P0=0xff;
P2=0xfb;
P0=s8[x];
delaynms(4);
}

评分

参与人数 1黑币 +35 收起 理由
admin + 35 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:19715 发表于 2015-7-3 18:58 | 显示全部楼层
温度采集太过频繁,每一秒采集最多2-3次,一般应用0.5次就够了

评分

参与人数 1黑币 +35 收起 理由
admin + 35 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:19715 发表于 2015-7-3 19:00 | 显示全部楼层
本帖最后由 明白 于 2015-7-3 19:02 编辑

只能采用定时器中断,才能保证数码管正常显示,
不然的话肯定会被把温度采集调制着

评分

参与人数 1黑币 +35 收起 理由
admin + 35 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:83083 发表于 2015-7-4 13:52 | 显示全部楼层
欢腾智能科技 发表于 2015-6-22 22:21
你这个程序 小数部分显示的应该比较暗          写个 计数中断  把显示 放到中断服务函数去

我试试
回复

使用道具 举报

ID:83083 发表于 2015-7-4 13:53 | 显示全部楼层
gaozhaohong 发表于 2015-6-22 20:59
不知道是想用LED还是想用LCD?

用LED吧,
回复

使用道具 举报

ID:83083 发表于 2015-7-4 13:56 | 显示全部楼层
z1061828841 发表于 2015-6-17 12:21
不知道你用的是LCD屏还是数码管在显示,LCD屏显示,如果出现闪动,或者比较暗的话,多半就是单片机一直重复 ...

我用的是数码管显示
回复

使用道具 举报

ID:83083 发表于 2015-7-4 13:57 | 显示全部楼层
明白 发表于 2015-7-3 19:00
只能采用定时器中断,才能保证数码管正常显示,
不然的话肯定会被把温度采集调制着

用定时中断程序怎么写可以帮我写一下吗,谢谢
回复

使用道具 举报

ID:58502 发表于 2015-7-4 15:18 | 显示全部楼层
这是由于在读取温度的时候,数码管扫描停下来了,这时候停下来的所显示的那位就比较亮,而由于读取时间太长就导致其他位数在闪

评分

参与人数 1黑币 +35 收起 理由
admin + 35 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:166150 发表于 2017-3-1 15:02 | 显示全部楼层
不知道你用的是LCD屏还是数码管在显示,LCD屏显示,如果出现闪动,或者比较暗的话,多半就是单片机一直重复在向LCD那一位写数据,导致LCD一直在更新那一个字符,  
如果是数码管显示,就看看WHILE循环中是不是周期长了点,我以前也遇到过类似的,LCD也遇到过,就是一直重复在写数据,导致LCD一直在刷新屏幕
回复

使用道具 举报

ID:257097 发表于 2017-12-4 11:49 | 显示全部楼层
好东西值的收藏谢谢分享
回复

使用道具 举报

ID:213173 发表于 2017-12-4 21:38 | 显示全部楼层
给你一个例程参考
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit DS=P2^2;           //单总线端口定义
uchar flag1;            //正或负标记
sbit dula=P2^6;                        //段选
sbit wela=P2^7;                        //位选
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,//0~f数组
           0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
uchar code table1[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,//0~9带小数点数组
                        0x87,0xff,0xef};
/************DS18B20操作程序声明****************/
void dsreset();                              //复位和初始化
bit tmpreadbit();                                        //读1位数据
uchar tmpread();                                   //读取一个字节数据
void tmpwritebyte(uchar dat);        //写一个字节
void tmpchange();                                        //发送操作指令
uint tmp();                             //读取温度值
/************显示程序声明****************/
void display(uint temp);                //数码管显示程序
/************延时程序声明****************/
void delay(uchar k);                                //50us延时程序
void delay1ms(uint k);                                //1ms延时程序

/************主程序****************/
void main()
{
        tmpchange();                //初始化DS18B20
        delay1ms(1000);        //延时1s等待稳定
        while(1)
        {
                tmpchange();                //发送操作指令
                display(tmp());        //数码管显示读到的温度数据
        }
}
//初始化DS18B20
//让DS18B20一段相对长时间低电平, 然后一段相对非常短时间高电平, 即可启动
void dsreset()       //复位和初始化
{
        uint i;                        //用作短延时的计数变量
        DS=0;                        //发送低电平
        i=103;                        //赋值
        while(i>0)i--;        //相对长时间低电平896us
        DS=1;                        //发送高电平
        i=4;                        //赋值
        while(i>0)i--;        //相对非常短时间高电平38us
}
//向DS18B20读取一位数据   
//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平,   
//之后DS18B20则会输出持续一段时间的一位数据
bit tmpreadbit()       //读1位数据
{
   uint i;                        //用作短延时的计数变量
   bit dat;                        //位变量
   DS=0;                                //发送低电平
        i++;                                //少许延时
   DS=1;                                //发送高电平
        i++;i++;                        //执行一个i++;3.25us
   dat=DS;                        //读1位数据
   i=8;
        while(i>0)i--;//短延时
   return (dat);                //返回dat值
}
//读取一个字节数据, 通过调用tmpreadbit()来实现
uchar tmpread()   //读取一个字节数据
{
        uchar i,j,dat;
        dat=0;
        for(i=1;i<=8;i++)
        {
                j=tmpreadbit();//按位分8次读取一个字节数据
        //最先读出的是最低位数据  
                dat=(j<<7)|(dat>>1);   //读出的数据最低位在最前面,这样刚好一个字节在dat里
        }
        return(dat);        //返回dat值
}
//向DS18B20写入一个字节数据
void tmpwritebyte(uchar dat)   //写一个字节
{
        uint i;
        uchar j;
        bit testb;
        for(j=1;j<=8;j++)        //一个字节分8次按位写入
        {
                testb=dat&0x01;//把dat最低位赋值与testb
                dat=dat>>1;                //dat左移一位
//写"1", 让低电平持续2个小延时, 高电平持续8个小延时
                if(testb)     //写 1
                {
                        DS=0;
                        i++;i++;
                        DS=1;
                        i=8;
                        while(i>0)
                                i--;
                }
                else
                {
                        DS=0;       //写 0
                        i=8;
                        while(i>0)
                                i--;
                        DS=1;
                        i++;i++;
                }       
        }
}
//向DS18B20发送温度转换命令
void tmpchange()                        //发送温度转换命令
{
        dsreset();                                //复位和初始化
        delay(1);                            //延时
        tmpwritebyte(0xcc);  //写入跳过序列号命令字
        tmpwritebyte(0x44);  //写入温度转换命令字
}

uint tmp()               //读取温度值
{
        float tt;                                //单精度浮点型数据变量
        uint temp;                                        //变量温度
        uchar a,b;
        dsreset();                        //发送复位和初始化命令
        delay(1);
        tmpwritebyte(0xcc);  //写入跳过序列号命令字
        tmpwritebyte(0xbe);        //写入读取数据令字
//连续读取两个字节数据
        a=tmpread();
        b=tmpread();
        temp=b;
        temp<<=8;          //两个字节组成一个整型变量
        temp=temp|a;
//DS18B20的精确度为0.0625度, 即读回数据的最低位代表0.0625度
        tt=temp*0.0625;
//将它放大10倍, 使显示时可显示小数点后一位, 并对小数点后第二2进行4舍5入
//如t=11.0625, 进行计数后, 得到value = 111, 即11.1 度
        temp=tt*10+0.5;
        return temp;        //返回3位有效数
}
//显示当前温度值, 精确到小数点后一位
void display(uint temp)                        //显示程序
{
        static uchar count=0;
        switch(count)
        {
                case 0:
                        dula=0;
                        P0=table[temp/100];                //显示十位
                        dula=1;
                        dula=0;
                       
                        wela=0;
                        P0=0x7e;
                        wela=1;
                        wela=0;
                        count=1;
                break;

                case 1:
                        dula=0;
                        P0=table1[temp/10%10];                //显示个位
                        dula=1;
                        dula=0;
                       
                        wela=0;
                        P0=0x7d;
                        wela=1;
                        wela=0;
                        count=2;
                break;

                case 2:
                        P0=table[temp%10];                //显示1/10位
                        dula=1;
                        dula=0;
                       
                        P0=0x7b;
                        wela=1;
                        wela=0;
                        count=0;
                break;
        }                               
}

void delay(uchar k)   //11.0592MHz 50us延时
{
    uchar a,b;
    for(b=k;b>0;b--)
        for(a=43;a>0;a--);
}
void delay1ms(uint k)                        //11.0592MHz 1ms延时
{
        uint i,j;
        for(i=k;i>0;i--)
                for(j=114;j>0;j--);       
}
回复

使用道具 举报

ID:245044 发表于 2017-12-4 22:09 | 显示全部楼层
很不错,好东西
回复

使用道具 举报

ID:257582 发表于 2017-12-5 10:38 | 显示全部楼层
谢谢楼主,正是需要的参考,顶!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表