有关ATMEGA128和DS18B20的问题

2019-03-24 20:18发布

最近在做一个DS18B20测室温的程序,单片机是AVR的,也在网上查了很多资料,自己写了很多程序,然而一个也没调出来,感觉挺受挫的 ,又不想搁置,特来此寻找大神帮我看看我的程序,找到错误之处。新人没有多少芯币,还望不要嫌弃。下面是我的程序:/*******************************头文件**************************************/
#include<iom128v.h>
#include<macros.h>

/*******************************宏定义*************************************/
#define TEM_PORT PORTG
#define TEM_DDR DDRG
#define TEM_PIN PING

#define TEM_SDT 3

#define SET_TEM_SDT (TEM_PORT|=(1<<TEM_SDT))
#define CLR_TEM_SDT (TEM_PORT&=~(1<<TEM_SDT))

#define SET_TEM_DDR (TEM_DDR|=(1<<TEM_SDT))
#define CLR_TEM_DDR (TEM_DDR&=~(1<<TEM_SDT))

#define CHECK_TEM_SDT (TEM_PIN&(1<<TEM_SDT))

/*************************************************************
**
**
**串口和液晶屏
**
**
*************************************************************/
/******************************uart0初始化*********************************/
void uart0_init(void)
{
        UCSR0B=0x00;                        //关闭UART00
        UCSR0A=0x00;                       //不使用倍速发送(异步)
        UCSR0C=0x06;    //数据位为8位
        UBRR0L=103;    //波特率9600
        UBRR0H=0x00;  //误差率0.156%
        UCSR0B=0x98; //发送接收使能,接收结束使能
}


/***************************uart0发送单字节数据****************************/
void putchar0(unsigned char c)
{
        while (!(UCSR0A&(1<<UDRE0)));//表明发送器已经准备就绪
        UDR0=c; //将要发送的数据装入UDR0寄存器
}

/*****************************LCD显示函数***********************************/
void LCD_display(unsigned char i,unsigned char j)
{
    putchar0(0x5A);
        putchar0(0xA5);
        putchar0(0x05);
        putchar0(0x82);
        putchar0(0x00);    //地址高位
        putchar0(i);       //地址低位
        putchar0(0x00);    //数据高位
        putchar0(j);       //数据低位
        WDR();
}

/*************************************************************
**
**
**延时函数
**
**
**************************************************************/
void delay2_1us(void)//延时1us
{
     NOP();
         NOP();
         NOP();
         NOP();
}

void delay1_1us(void)    //940ns
{
         NOP();
}

void delay1_nus(unsigned int n)       //N us延时函数
{   
   unsigned int i=0;   
   for(i=0;i<n;i++)   
   {
   delay1_1us();
   }   
}   

void delay10us(unsigned int n)       //n=10 ,10us延时函数
{   
   unsigned int i=0;   
   for(i=0;i<n;i++)   
   {
       NOP();
           NOP();
           NOP();
           NOP();
           NOP();
           NOP();
           NOP();
   }   
}   
void delay(unsigned int k)
{
        unsigned int n;
        n = 0;
        while(n<k)
        {
                n++;
        }
        return;
}

void delay6(unsigned char x,unsigned char y)
{
    unsigned char z;
        do{
             z = y;
                 do
                 {
                     ;
                 }
                 while(--z);
          }
          while(--x);
}


void delay5(unsigned int count) //count=13,1ms延时子函数
{
unsigned int i;
while(count)
{
i=200;
while(i>0)
i--;
count--;
}
}

void delay1(void)    //延时大约1秒(较精确)
{       
        unsigned int x;
        unsigned int y;
        for(x=0;x<1000;x++)
        {
                for(y=0;y<2286;y++)
                {
                        WDR();
                }
                WDR();
        }
}

/**************************************************************
** 函数名称: void init_1820(void)
** 功能描述: 18b20初始化
** 输 入: 无
** 全局变量: 无
** 调用模块: 无
** 说明:
** 注意:
**************************************************************/
void init_1820(void)  
{  
    TEM_DDR &=~ (1<<TEM_SDT);
        SET_TEM_DDR;      //设置数据端口为输出
    SET_TEM_SDT;
    CLR_TEM_SDT;  
    delay1_nus(600);  //480us以上(530us)
    SET_TEM_SDT;  
    CLR_TEM_DDR;  
    delay10us(10);
        delay10us(10);    //15~60us (20us)
    while(CHECK_TEM_SDT);  
    SET_TEM_DDR;  
    SET_TEM_SDT;  
    delay6(5,50);    //60~240us (97us)
}
/**************************************************************
** 函数名称: void write_1820(unsigned char data)
** 功能描述: 向18b20写入1B的数据
** 输 入: unsigned char data 要写入的数据
** 全局变量: 无
** 调用模块: 无
** 说明:
** 注意:
**************************************************************/
void write_1820(unsigned char data)  
{
    unsigned char i;  
    for(i=0;i<8;i++)  
    {  
       //SET_TEM_SDT;
           CLR_TEM_SDT;  //从高到低,产生写间隙
       if(data&(1<<i))    //写数据,先写低位
                SET_TEM_SDT;  
       else  
         CLR_TEM_SDT;  
       delay6(2,60);     //15~60us (46us)
       SET_TEM_SDT;  
           data>>=1;
    }  
    SET_TEM_SDT;  
}
/**************************************************************
** 函数名称: unsigned char read_1820(void)
** 功能描述: 从18b20读出1B的数据
** 输 入: 无
** 全局变量: 无
** 调用模块: 无
** 说明:
** 注意:
**************************************************************/
unsigned char read_1820(void)  
{      
    unsigned char temp,k,n;  
    temp=0;  
    for(n=0;n<8;n++)  
    {
      //SET_TEM_DDR;           //设为输出
          CLR_TEM_SDT;  
          temp>>=1;
      SET_TEM_SDT;           //从高到低再到高,产生读间隙
      CLR_TEM_DDR;           //设为输入  
      k=CHECK_TEM_SDT;       //读数据,从低位开始  
      if(k)  
        temp|=(1<<n);  
      else  
        temp&=~(1<<n);  
      delay1_nus(100);       //60~120us(82us)      
      SET_TEM_DDR;           //设为输出
    }  
   return (temp);  
}
/**************************************************************
** 函数名称: unsigned char gettemp(void)
** 功能描述: 返回温度值
** 输 入: 无
** 全局变量:
** 调用模块: 无
** 说明:wmh为温度的高位,wml为温度的低位,返回值为温度值,范围0~99摄氏度,字符型
** 注意:
**************************************************************/
unsigned char gettemp(void)         //读取温度值
{  
     unsigned char temh,teml,wm0,wm1,wm2,wm3,wmh,wml,temp;
     init_1820();        //复位18b20  
     write_1820(0xCC);   // 跳过ROM
     write_1820(0x44);  // 温度变换

     init_1820();
     write_1820(0xCC);  // 跳过ROM
     write_1820(0xbe);  // 写暂存存储器
     teml=read_1820();  //读数据  
     temh=read_1820();  
     wm0=teml>>4;       //只要高8位的低四位和低8位的高四位,温度范围0~99
     wm1=temh<<4;
       
     wm2=wm1+wm0;        //16进制转10进制
     wm3=wm2/100;
     wmh=(wm2%100)/10;   //wmh是显示的高位,wml是显示的低位
     wml=(wm2%100)%10;
         temp=wmh*10+wml;
         
         return temp;
}


/**************************************************************
**
**
**主函数
**
**
***************************************************************/
void main(void)
{
unsigned char temp1=0;
init_1820();
while(1)
        {
                 temp1=gettemp();
                 LCD_display(0x0A,temp1);
        }
}



友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
8条回答
dcexpert
1楼-- · 2019-03-25 04:13
问题应该在时序上,特别是使用循环进行延时时,与时钟频率有很大关系,如果不加注意,会出现很多问题。如果使用AVRGCC,有专门的延时函数,如果是ICC或者IAR,需要自己完成了。

建议特别看看下面两篇应用笔记:

AVR318:Dallas 1-Wire master on tinyAVR and megaAVR devices
http://www.atmel.com/images/atmel-2579-dallas-1wire-master-on-tinyavr-and-megaavr_applicationnote_avr318.pdf

MAXIM 126:用软件实现 1-Wire 通信
https://www.maximintegrated.com/cn/app-notes/index.mvp/id/126

在《AVR单片机专题精讲》一书中也专门介绍了单总线的使用技巧,可以参考。
dcexpert
2楼-- · 2019-03-25 08:13
还可以在proteus中去仿真,效果不错。
Doris.Lee
3楼-- · 2019-03-25 13:05
dcexpert 发表于 2016-11-17 20:32
问题应该在时序上,特别是使用循环进行延时时,与时钟频率有很大关系,如果不加注意,会出现很多问题。如果 ...

我写的那些延时都是用示波器勾过得,数据应该是没错,我又分开写了读一位1  读一位0,写一位1,写一位0  的函数,然后读字节写字节时在调用   示波器有显示波形,也能看出两次复位和写命令后 还有一段波形,应该是读温度那部分,但是液晶屏上却没有读数显示
dcexpert
4楼-- · 2019-03-25 18:52
 精彩回答 2  元偷偷看……
dcexpert
5楼-- · 2019-03-25 19:30
下面是我写的程序,可以参考,在实际芯片上运行过。使用AVRGCC,附带proteus仿真程序。

剪贴板02.jpg

1-wire.zip (80.29 KB, 下载次数: 5) 2016-11-18 09:50 上传 点击文件名下载附件
Doris.Lee
6楼-- · 2019-03-25 23:26
dcexpert 发表于 2016-11-18 09:47
如果不是很好的示波器,测这样us级的时间误差是比较大的,需要仔细测试看看。

还有因为时序的要求严格 ...

我的程序其实是有中断的  ,但是我现在只想测试18B20,所以我只写了这一部分,其他部分都去掉了,所以没有中断存在,我用的ICCAVR,延时都是自己写的,也通过高低电平变化测过时间。

一周热门 更多>