打印

请各位高手帮忙看下这程序啊....

[复制链接]
1398|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
abm983|  楼主 | 2007-10-9 18:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
怎么在KEIL51中编译通不过啊,一直有两处警告啊.......
以下是程序
  //多功能时钟, 精确到小数0.01秒, 即10ms
  //功能: 时钟, 秒表, 温度计
  
  /**//*
  S5键为功能选择键, 上电默认使用时钟功能
  功能顺序为: 时钟, 温度计, 秒表
  
  mode = 1. 时钟(每次掉电后都要重新设置时间)
  1)当选中时钟功能时, 具体按键功能如下:
 
 2)可设置时分秒, 时利用发光二极管显示, 分秒用数码管显示
 
 3)时钟: 采用定时器0计时, 工作方式1
 
 mode = 2. 时钟设置模式
 当选中时钟设置模式
 S2为位选, S3为增加选中位的值
 S4确定更改, S5放弃更改, 进入秒表模式
 
 mode = 3. 秒表
 1)当选中秒表功能时, 具体按键功能如下:
S2为开始/暂停, S3为清零
 
2)采用定时器1计时, 工作方式1
 
 mode = 4. 温度计
 1)利用DS18B20检测环境温度;
 2)最小温度值为0.01℃, 可表示温度范围: -55℃~+125℃
 
 */
 
 #include <reg52.H>
 #include <intrins.H>
 #include <math.h>
 
 //0-F数码管的编码(共阴极)
 unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,
     0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
 //0-9数码管的编码(共阴极), 带小数点
 unsigned char code tableWidthDot[]={0xbf, 0x86, 0xdb, 0xcf, 0xe6, 0xed, 0xfd, 
     0x87, 0xff, 0xef};
 
 sbit wela = P2^7;  //数码管位选
 sbit dula = P2^6;  //数码管段选
 sbit ds = P2^2;
 10:21 2007-10-7unsigned char th, tl, mode = 1; //mode存放功能模式, 默认在模式1 时钟
 10:21 2007-10-7unsigned char clockPosition = 0;  //时钟设置模式下, 光标所在的位置; 默认在0
 10:21 2007-10-7unsigned char clockTmp = 0; //用于时钟模式下临时计数
 bit clockTmpBit = 0; //用于时钟模式下临时标志位
 
 //秒4字节, 分2字节, 时1字节
 unsigned char datas[] = {0, 0, 0, 0, 0, 0, 0};//保存计时器数据
 unsigned char clockDatas[] = {0, 0, 0, 0, 0, 0, 0};//保存时钟数据
 unsigned char * values = clockDatas;  //根据mode选择适当的数据数组指针
 int tempValue; //存放温度值
 unsigned char tempCount = 0; //用于记录显示了多少次温度值, 用于定时
 
 sbit S2 = P3^4;  //键S2, 作开始/暂停 
 sbit S3 = P3^5;     //键S3, 清零
 sbit S4 = P3^6;     //键S4
 sbit S5 = P3^7;     //键S5
 unsigned char tmpDatas[] = {0, 0, 0, 0, 0, 0, 0};  //存放临时设置值
 unsigned char icount;
 
 //延时函数, 对于11.0592MHz时钟, 例i=5,则大概延时5ms.
 void delay(unsigned int i)
 {
    unsigned int j;
     while(i--)
     {
         for(j = 0; j < 125; j++);
     }
 }
 
 /**//***********************温度计模式******************************/
 
 //初始化DS18B20
 //让DS18B20一段相对长时间低电平, 然后一段相对非常短时间高电平, 即可启动
 void dsInit()
 {
     //对于11.0592MHz时钟, unsigned int型的i, 作一个i++操作的时间大于为8us
     unsigned int i;  
     ds = 0;
     i = 100;   //拉低约800us, 符合协议要求的480us以上
     while(i>0) i--;
    ds = 1;    //产生一个上升沿, 进入等待应答状态
     i = 4;
     while(i>0) i--;
 }
 
 void dsWait()
 {
      unsigned int i;
      while(ds);  
      while(~ds);  //检测到应答脉冲
      i = 4;
      while(i > 0) i--;
 }
 
//向DS18B20读取一位数据
//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平, 
//之后DS18B20则会输出持续一段时间的一位数据
bit readBit()
{
    unsigned int i;
    bit b;
    ds = 0;
    i++;   //延时约8us, 符合协议要求至少保持1us
    ds = 1; 
    i++; i++;  //延时约16us, 符合协议要求的至少延时15us以上
    b = ds;
    i = 8; 
    while(i>0) i--;  //延时约64us, 符合读时隙不低于60us要求
    return b;
}

//读取一字节数据, 通过调用readBit()来实现
unsigned char readByte()
{
    unsigned int i;
    unsigned char j, dat;
    dat = 0;
    for(i=0; i<8; i++)
    {
        j = readBit();
        //最先读出的是最低位数据
        dat = (j << 7) | (dat >> 1);
    }
    return dat;
}

//向DS18B20写入一字节数据
void writeByte(unsigned char dat)
{
    unsigned int i;
    unsigned char j;
    bit b;
    for(j = 0; j < 8; j++)
    {
        b = dat & 0x01;
        dat >>= 1;
        //写"1", 将DQ拉低15us后, 在15us~60us内将DQ拉高, 即完成写1
        if(b)   
        {
            ds = 0;
            i++; i++;  //拉低约16us, 符号要求15~60us内
            ds = 1;    
            i = 8; while(i>0) i--;  //延时约64us, 符合写时隙不低于60us要求
        }
        else  //写"0", 将DQ拉低60us~120us
        {
           ds = 0;
            i = 8; while(i>0) i--;  //拉低约64us, 符号要求
            ds = 1;
            i++; i++;  //整个写0时隙过程已经超过60us, 这里就不用像写1那样, 再延时64us了
        }
    }
}

//向DS18B20发送温度转换命令
void sendChangeCmd()
{
    dsInit();    //初始化DS18B20, 无论什么命令, 首先都要发起初始化
    dsWait();   //等待DS18B20应答
    delay(1);    //延时1ms, 因为DS18B20会拉低DQ 60~240us作为应答信号
    writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
    writeByte(0x44); //写入温度转换命令字 Convert T
}

//向DS18B20发送读取数据命令
void sendReadCmd()
 {
    dsInit();
    dsWait();
    delay(1);
    writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
    writeByte(0xbe); //写入读取数据令字 Read Scratchpad
}

//获取当前温度值
void getTempValue()
{
    unsigned int tmpvalue;
    float t;
    unsigned char low, high;
    sendReadCmd();
    //连续读取两个字节数据
    low = readByte(); 
    high = readByte();
    //将高低两个字节合成一个整形变量
    //计算机中对于负数是利用补码来表示的
    //若是负值, 读取出来的数值是用补码表示的, 可直接赋值给int型的value
    tmpvalue = high;
    tmpvalue <<= 8;
    tmpvalue |= low;
    tempValue = tmpvalue;
    
    //使用DS18B20的默认分辨率12位, 精确度为0.0625度, 即读回数据的最低位代表0.0625度
   t = tempValue * 0.0625;
    //将它放大100倍, 使显示时可显示小数点后两位, 并对小数点后第三进行4舍5入
    //如t=11.0625, 进行计数后, 得到value = 1106, 即11.06 度
    //如t=-11.0625, 进行计数后, 得到value = -1106, 即-11.06 度
    tempValue = t * 100 + (tempValue > 0 ? 0.5 : -0.5); //大于0加0.5, 小于0减0.5
}

//显示当前温度值, 精确到小数点后一位
//若先位选再段选, 由于IO口默认输出高电平, 所以当先位选会使数码管出现乱码
void displayTemp() 
{
    unsigned char i;
    unsigned int tmp = abs(tempValue);
    tmpDatas[0] = tmp / 10000;
    tmpDatas[1] = tmp % 10000 / 1000;
    tmpDatas[2] = tmp % 1000 / 100;
    tmpDatas[3] = tmp % 100 / 10;
    tmpDatas[4] = tmp % 10;
    if(tempValue < 0)
    {
        //关位选, 去除对上一位的影响
        P0 = 0xff; 
        wela = 1; //打开锁存, 给它一个下降沿量
        wela = 0;
        //段选
        P0 = 0x40; //显示"-"号
        dula = 1;  //打开锁存, 给它一个下降沿量
        dula = 0;

        //位选
        P0 = 0xfe; 
        wela = 1; //打开锁存, 给它一个下降沿量
        wela = 0;
        delay(1); 
    }
    for(i = 0; i != 5; i++)
    {
        //关位选, 去除对上一位的影响
        P0 = 0xff; 
        wela = 1; //打开锁存, 给它一个下降沿量
        wela = 0;
        //段选
        if(i != 2)
        {
            P0 = table[tmpDatas]];  //显示数字
        }
        else
        {
            P0 = tableWidthDot[tmpDatas]]; //显示带小数点数字
        }
        dula = 1;  //打开锁存, 给它一个下降沿量
        dula = 0;

        //位选 
        P0 = _crol_(0xfd, i); //选择第(i + 1) 个数码管
        wela = 1; //打开锁存, 给它一个下降沿量
        wela = 0;
        delay(1); 
    }
    tempCount++;
    if(tempCount==100)
    {
        tempCount = 0;
        getTempValue();
        sendChangeCmd();
    }
}

//显示时钟和秒表的结果
void display() 
{
    unsigned char i;
    if(mode == 4) //显示温度
    {
        displayTemp();
    }
    else {  //显示时间
        for(i = 0; i < 6; i++)
        {
            //关位选, 去除对上一位的影响
            P0 = 0xff; 
            wela = 1; //打开锁存, 给它一个下降沿量
            wela = 0;
            //段选
            if(i == 2 || i == 4)
            {
                P0 = tableWidthDot[values]; //显示带小数点数字, 作为分秒, 秒与毫秒的分隔
            }
            else
            {
                P0 = table[values];  //显示数字
            }
            if(mode == 2 && i == clockPosition)  //时钟设置模式下, 光标所在位置, 闪烁
            {
                clockTmp++;
                if(clockTmp == 20)
                {
                    clockTmpBit = ~clockTmpBit;
                    clockTmp = 0;
                }
                if(clockTmpBit)
                    P0 = 0x00;
            }
            dula = 1;  //打开锁存, 给它一个下降沿量
            dula = 0;
            
            //位选 
            P0 = _cror_(0xdf, i); //选择第(i + 1) 个数码管
            wela = 1; //打开锁存, 给它一个下降沿量
            wela = 0;
            delay(1);
        }
        if(mode == 2 && 6 == clockPosition)  //时钟设置模式下, 光标所在位置, 闪烁
        {
            clockTmp++;
            if(clockTmp == 20)
            {
                clockTmpBit = ~clockTmpBit;
                clockTmp = 0;
            }
            if(clockTmpBit)
            {
                if(values[6] == 0)
                {
                    P1 = 0x0f;
                }
                else
                {
                    P1 = ~values[6];
                }
            }
            else
            {
                P1 = 0xff;
            }
        }
        else
        {
            P1 = ~values[6];
        }
    }
}

//检测功能模式键是否被按下
void checkModeKey()
{
    if(!S5)
    {
        delay(7);
        if(!S5) 
        {
            mode++;
            switch(mode)
            {
                case 2: //定时器0是不会关闭的, 即使在设置模式下
                    for(icount = 0; icount < 7; icount++)
                    {
                        tmpDatas[icount] = clockDatas[icount]; //将设置之前的值暂存到临时数组
                    }
                    values = tmpDatas;
                    break;
                case 3: //秒表模式
                    values = datas;
                    break;
                case 4: //温度计模式
                    //启动温度转换
                    sendChangeCmd();
                    getTempValue();
                    break;
                default:
                    values = clockDatas;
                    mode = 1;
                    TR0 = 1;
            }
            while(!S5)  //等待释放键
           {
                display();
            }
        }
    }
}

//选中位数值增1, 用于时钟模式的设置状态下
void add()
{
    values[clockPosition]++;
    switch(clockPosition)
    {
        case 3:
        case 5:
            if(values[clockPosition] > 5)
                values[clockPosition] = 0;
            break;
        case 6:
            if(values[clockPosition] > 23)
                values[clockPosition] = 0;
            break;
        default:
            if(values[clockPosition] > 9)
                values[clockPosition] = 0;
    }
}

//检测是否有键按下, 并执行相应功能
void checkKey()
{
    checkModeKey();
    switch(mode)
    {
        case 2:
            if(!S2)  //左移光标位
            {
                delay(7);
                if(!S2)
                {
                    clockPosition++;
                    if(clockPosition > 6)
                    {
                        clockPosition = 0;
                    }
                }
            }
            else if(!S3)  //选中位增1
            {
                delay(7);
                if(!S3)
                {
                    add();
                }
            }
            else if(!S4)  //选中确定更改
            {
                delay(7);
                if(!S4)
                {
                    for(icount = 0; icount < 7; icount++)
                    {
                        clockDatas[icount] = tmpDatas[icount]; //将设置的值存到clockDatas[]
                    }
                    values = clockDatas;
                    mode = 1; //将模式变成时钟模式
                }
            }
            break;
        case 3:
            if(!S2)
           {
               delay(7);  //延时大约10ms, 去抖动
                if(!S2)  //开始/暂停键按下
                {
                    TR1 = ~TR1;
                }
            }
        
            else if(!S3)
            {
                delay(7);  //延时大约10ms, 去抖动
                if(!S3)  //清零键按下
                {
                    TR1 = 0;
                    TH1 = th;
                    TL1 = tl;
                    for(icount = 0; icount < 7; icount++)
                    {
                        datas[icount] = 0;
                    }
                }
            }
            break;
    }
    //等待键被释放
    while(!S2 || !S3 || !S4)
    {
        display(); // 等待期间要显示
    }
}

void main()
{
    delay(1);
    th = 0xdb;//(65536 - 10000/1.085) / 256;  //定时10ms
    tl = 0xff;//(65536 - 10000/1.085) - th * 256;
    TH1 = TH0 = th; //初始化定时器1, 0
    TL1 = TL0 = tl;
    EA = 1;  //开中断
    ET1 = ET0 = 1; //允许定时器1, 0 中断请求
    TMOD = 0x11;  //定时器1, 0 都工作方式1
    TR1 = 0;
    TR0 = 1; //开始显示时间
    while(1)
    {
        checkKey();  //检测是否就键按下
        display();  //显示计时值
    }
}

//定时器0中断响应函数, 用于时钟计时
void time0() interrupt 1
{
    TH0 = th;  //重置计数值
    TL0 = tl;

    clockDatas[0]++;  //0.01秒
    if(clockDatas[0] == 10)
    {
        clockDatas[0] = 0;
        clockDatas[1]++;   //0.1秒
        if(clockDatas[1] == 10)
        {
            clockDatas[1] = 0;
            clockDatas[2]++;  //秒
            if(clockDatas[2] == 10)
            {
                clockDatas[2] = 0;
                clockDatas[3]++;   //10秒
                if(clockDatas[3] == 6)
                {
                    clockDatas[3] = 0;
                    clockDatas[4]++;  //分
                    if(clockDatas[4] == 10)
                    {
                        clockDatas[4] = 0;
                        clockDatas[5]++;  //10分
                        if(clockDatas[5] == 6)
                        {
                            clockDatas[5] = 0;
                            clockDatas[6]++;  //时
                            if(clockDatas[6] == 24)
                            {
                                clockDatas[6] = 0;
                            }
                        }
                    }
                }
            }
        }
    }
}

//定时器1中断响应函数, 用于秒表计时
void time1() interrupt 3
{
    TH1 = th;  //重置计数值
    TL1 = tl;

    datas[0]++;  //0.01秒
    if(datas[0] == 10)
    {
        datas[0] = 0;
        datas[1]++;   //0.1秒
        if(datas[1] == 10)
        {
            datas[1] = 0;
            datas[2]++;  //秒
            if(datas[2] == 10)
            {
                datas[2] = 0;
                datas[3]++;   //10秒
                if(datas[3] == 6)
                {
                    datas[3] = 0;
                    datas[4]++;  //分
                    if(datas[4] == 10)
                    {
                        datas[4] = 0;
                        datas[5]++;  //10分
                        if(datas[5] == 6)
                        {
                            datas[5] = 0;
                            datas[6]++;  //时
                            if(datas[6] == 24)
                            {
                                datas[6] = 0;
                            }
                        }
                    }
                }
            }
        }
    }
}


相关帖子

沙发
ayb_ice| | 2007-10-9 19:21 | 只看该作者

太长

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

11

主题

14

帖子

0

粉丝