查看: 729|回复: 0
打印 上一主题 下一主题

DS18B20,ATmega8+DS18B20,希望对像我这样的新手有点用

[复制链接]
跳转到指定楼层
沙发
发表于 2016-6-4 00:59:53 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
今天早上终于把DS18B20给调试出来了,程序比较简单,因为我还是新手,刚学AVR不久。希望这个程序对像我这样的新手有点帮助。
我用的是ATmega8,时钟是1M的。内部时钟振荡。
MCU:ATmega8
CLK:1M

PC1:RS
PC2:R/W
PC3:E
PD0--PD7:液晶1602数据双向口
PB0;ds18b20数据I/O口

#include<iom8v.h>
#include<macros.h>

#define uchar unsigned char
#define uint unsigned int

#define rs_h PORTC |= BIT(1)
#define rs_l PORTC &= ~BIT(1)
#define rw_h PORTC |= BIT(2)
#define rw_l PORTC &= ~BIT(2)
#define e_h  PORTC |= BIT(3)
#define e_l  PORTC &= ~BIT(3)

#define DQ_H PORTB |= BIT(0)
#define DQ_L PORTB &= ~BIT(0)

uchar temp,temp_dec,nub;
//温度的整数,温度的小数变量
uchar lcd[11]={"0123456789."};
uchar b_d[7]={0};
/****************************/
void delay_ms(uint x)
{
    uchar i;
        while(x--)
        {
            for(i=0;i<100;i++);
        }
}

/**************************/
void delay_us(uint x)
{
    while(x--);
}

/***************************/
void port_init(void)
{
    DDRC |= BIT(1)|BIT(2)|BIT(3);
        PORTC &= ~(BIT(1)|BIT(2)|BIT(3));
        DDRD=0XFF;
        PORTD=0X00;
        
        DDRB |= BIT(0);
        PORTB |= BIT(0);
        
        DDRB |= BIT(1);
        PORTB |= BIT(1);   
}

/********18b20*****************/
void reset(void)  //复位函数
{
    DQ_H;             //数据线高
        DQ_L;             //把数据线拉低
        delay_us(80);     //延时480us
        DQ_H;             //释放总线。        
        DDRB &= ~BIT(0);  //改变PB0口的方向
        delay_us(10);     //延时60us
        while( PINB&BIT(0) );        //复位成功
        delay_us(40);       //延时240us
        //PORTB &= ~BIT(1); //检测一下是不是在死循环里了.
        DDRB |= BIT(0);
        DQ_H;              //再次释放总线
}

/***************************/
void write_byte(uchar x)
{
    uchar i;
        for(i=0;i<8;i++)
        {            
                DQ_L;   //拉低数据线,空闲时是为高电平
                delay_us(1); //15us
                if( ( x&0x01 )==0x01 ) DQ_H;
                else DQ_L;
                delay_us(5); //45us
                DQ_H;  //释放总线,以便于下次进for语句时,DQ_H;是为高电平.
                x>>=1;  
        }        
}

/********************************/
uchar read_byte(void)   //ds18b20读一字节
{
   uchar i,z;
   z=0;
   for(i=0;i<8;i++)
   {
       z>>=1;                 
           DQ_L;           //拉低数据线,空闲时是为高电平
           DQ_H;           //释放总线
           delay_us(1);    //延时15us
           DDRB &= ~BIT(0);
           if( ( PINB&BIT(0) )==0X01 ) z|=0x80;
           else z&=0x7f;
           delay_us(10);    //延时60us
           DDRB |= BIT(0);
           DQ_H;            //再次释放总线
   }   
   return(z);   
}

/*******************************/
void get_time(void)
{
    uchar temp_l,temp_h,i;
               
        
        reset();           //复位.
        write_byte(0xcc);  //跳过ROM.
        write_byte(0x44);  //温度转换.
        delay_ms(2000);    //延时2秒.
        reset();           //复位.
        write_byte(0xcc);  //跳过ROM.
        write_byte(0xbe);  //读暂存存储器.
        temp_l=read_byte();    //温度存储器中的温度低8位.
        temp_h=read_byte();    //温度存储器中的高8位.
        reset();             //再来个复位,终止读暂存存储器.
                        
        i=temp_l;
        i &= 0x0f;      //温度的低四位.
        temp_dec=i/16;      //温度的小数.
        temp_dec=temp_dec*1000; //放大1000倍,用于显示小数点后的小数.
        
        temp_l>>=4;  //把小数点移掉,得到温度整数的个位,既低四位。            
        temp_h<<=4;   //把前面4个符号位移掉,只保留一位符号位和温度的高三位。
        temp = temp_l|temp_h;        //温度的整数.
        
}

/*******************************/
void b_d_data(void)   //数据处理
{
    b_d[0]=temp/100;   //温度的百位.
        b_d[1]=temp%100/10;//温度的十位.
        b_d[2]=temp%100%10;//温度的个位.
        
        b_d[3]=temp_dec/1000;//小数的第一位
        b_d[4]=temp_dec%1000/100;//小数的第二位
        b_d[5]=temp_dec%1000%100/10;//小数的第三位
        b_d[6]=temp_dec%1000%100%10;//小数的第四位
        
        
        //b_d[3]=temp_dec%10;//温度的一位小数.
}



/********1602液晶***************/
void busy(void)   //1602判断忙函数
{
    DDRD=0X00;
        rs_l;
        rw_h;
        e_h;
        while( ( PIND&0x80 )==0x80 );        
        e_l;
        DDRD=0xff;
}
/******************************/
void write_com(uchar com)  //1602液晶写命令
{
    busy();
    PORTD=0x00;
    rs_l;
        rw_l;
        PORTD=com;
        e_h;
        e_l;
        PORTD=0x00;   
}

/*****************************/
void write_data(uchar data)  //1602写数据
{
    busy();
    PORTD=0x00;
    rs_h;
        rw_l;
        e_h;
        PORTD=data;        
        e_l;
        PORTD=0x00;
}

/*****************************/
void init_1602(void)
{
    write_com(0x38);    //1602显示模式设置
        write_com(0x01);    //清显示
        delay_ms(2);
        write_com(0x0c);    //开显示,不显示光标,光标不闪烁。
        write_com(0x06);    //当写一字符时,地址加一,而且光标加一.
}

void disp_lcd(void)  //显示刷新
{
    write_com(0x80+0x04);  //显示地址
        write_data(lcd[b_d[0]]);
        write_data(lcd[b_d[1]]);
        write_data(lcd[b_d[2]]);
        write_data(lcd[10]);
        write_data(lcd[b_d[3]]);
        write_data(lcd[b_d[4]]);
        write_data(lcd[b_d[5]]);
        write_data(lcd[b_d[6]]);
}

/**************************/
void main(void)
{
    port_init();        
        init_1602();               
        while(1)
        {
            get_time();
            b_d_data();               
                disp_lcd();
        }
}
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入因仑

本版积分规则

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