Acaicjhacai 发表于 2012-3-24 09:46:14

调试AT89S52 ——MLX90614 失败,求助

这几天调试AT89S52 ——MLX90614 ,一直无应答。是移植IIC过来的,不知道为啥老是无应答。
参考了http://www.ourdev.cn/forum.php?mod=viewthread&tid=3990328这个帖子 还是失败。
一直找不到原因,电路上我是用10K电阻上拉的。

代码如下:
#include "reg52.h"
#include <intrins.h>
#include   <stdio.h>

#define uchar unsigned char
#define uintunsigned int
//************函数声明*****************************************************
void start();//MLX90614发起始位子程序
void stop();//MLX90614发结束位子程序
uchar ReadByte(void);//MLX90614接收字节子程序
//void send_bit(void);//MLX90614发送位子程序
void SendByte(uchar number);//MLX90614接收字节子程序
void read_bit(void);//MLX90614接收位子程序
void delay(uint N);//延时程序
uint readtemp(void);//读温度数据
void init1602(void);//LCD初始化子程序
void busy(void);//LCD判断忙子程序
void delayscan(i);

//************数据定义****************************************************
bdata uchar flag1; //可位寻址数据
sbit bit_out=flag1^7;
sbit bit_in=flag1^0;

sbit SCK=P1^7;
sbit SDA=P1^6;
//i2c总线
//sbit scl = P2^2;
//sbit sda = P2^3;
sbit SCL=P1^7;

uchar tempH,tempL,err;
//**************************mlx90614***********************************
//command mode命令模式
#define RamAccess 0x00 //对RAM操作
#define EepomAccess 0x20 //对EEPRAM操作
#define Mode 0x60 //进入命令模式
#define ExitMode 0x61 //退出命令模式
#define ReadFlag 0xf0 //读标志
#define EnterSleep 0xff //进入睡眠模式
//ram address read only RAM地址(只读)
#define AbmientTempAddr 0x03 //周围温度
#define IR1Addr 0x04
#define IR2Addr 0x05
#define LineAbmientTempAddr 0x06   //环境温度
/*0x0000 0x4074165000.01/单元
   -40    125*/
#define LineObj1TempAddr 0x07 //目标温度,红外温度
/*0x27ad-0x7fff0x3559 22610 0.02/单元
-70.01-382.190.01   452.2*/
#define LineObj2TempAddr 0x08
//eepom addressEEPROM地址
#define TObjMaxAddr 0x00 //测量范围上限设定
#define TObjMinAddr 0x01 //测量范围下限设定
#define PWMCtrlAddr 0x02 //PWM设定
#define TaRangeAddr 0x03 //环境温度设定
#define KeAddr 0x04 //频率修正系数
#define ConfigAddr 0x05 //配置寄存器
#define SMbusAddr 0x0e //器件地址设定
#define Reserverd1Addr 0x0f //保留
#define Reserverd2Addr 0x19 //保留
#define ID1Addr 0x1c //ID地址1
#define ID2Addr 0x1d //ID地址2
#define ID3Addr 0x1e //ID地址3
#define ID4Addr 0x1f //ID地址4


#define _Nop()   _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_()
#define delayNOP();{ _nop_();_nop_();_nop_();_nop_();_nop_();};// _nop()_=1 CPU cycle

typedef bit BOOL;
uchar CHACK;
uchar aa;
#define Nack_number 10

bit ack;
sbit rs = P2^6 ;
sbit rw = P3^6 ;
sbit ep = P2^7 ;



void delayms(uchar) ;
void lcd_wcmd(uchar) ;
BOOL lcd_bz() ;
void lcd_pos(uchar) ;
void lcd_wdat(uchar) ;
void display(uchar,uchar *) ;
union
{       
uchar c;        //c为X的高位,c为X的底位,
           int x;
}Temp;

uchardis1;
uchardis2 ;

/*void delay2ms()
{
        byte i;
        for(i=0xff;i!=0;i--)
                {Wdt();} //4*1.085*256
}

void delay2(void)
{
        byte i;
        for(i=2;i!=0;i--);
}
          */


void longdelay(uchar s)//长延时
{
       while(s--)
       {
                  delayms(60) ;
       }
}

void delayms(uchar ms)
{       // 延时子程序
       uchar i ;
       while(ms--)
       {
                  for(i = 0 ; i<250;i++) ;
       }
}

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

BOOL lcd_bz()
{       // 测试LCD忙碌状态
       BOOL result ;
       rs = 0 ;
       rw = 1 ;
       ep = 1 ;
       result = (BOOL)(P0 & 0x80) ;
       ep = 0 ;
       return result ;
}

void lcd_wcmd(uchar cmd)
{       // 写入指令数据到LCD
        while(lcd_bz()) ;
        rs = 0 ;
        rw = 0 ;
        ep = 0 ;
        P0 = cmd ;
        ep = 1 ;
        ep = 0 ;
}

void lcd_pos(uchar pos)
{       //设定显示位置
        lcd_wcmd(pos | 0x80) ;
}

void lcd_wdat(uchar dat)
{       //写入字符显示数据到LCD
        while(lcd_bz()) ;
        rs = 1 ;
        rw = 0 ;
        ep = 0 ;
        P0 = dat ;
        ep = 1 ;
        ep = 0 ;
}

void lcd_init()
{       //LCD初始化设定
       lcd_wcmd(0x38) ;   //function set
       delayms(1) ;
       lcd_wcmd(0x38) ;   //function set
       delayms(1) ;
       lcd_wcmd(0x08) ;   //display on/off
       delayms(1) ;
       lcd_wcmd(0x01) ;   //清除LCD的显示内容
       delayms(1) ;
       lcd_wcmd(0x06) ;   //entry mode set
       delayms(1) ;
       lcd_wcmd(0x0F) ;   //entry mode set
       delayms(1) ;
}

/*---------------
函数名称:display()
功能 :在LCD上显示数组的数据
说明 :先写显示地址,后写显示数据
调用 :lcd_wcmd(), lcd_pos()
入口参数:pos 写入的位置,q指向要写入的数据所在的数组
返回值 :无
----------------*/
void display(uchar pos, uchar *q)
{
       uchar i ;
       //lcd_wcmd(0x01) ; //clear
       delayms(10) ;
       lcd_pos(pos) ;
       for(i=0 ;i<16;i++)
       {
                  lcd_wdat(*q) ;
                  q++ ;
                //longdelay(2) ;
       }
}

void init_serial(void)
                  
{
                                //定时器1的工作方式2
        TMOD=0x20;        //装载计数初值
        TL1=0xfd;
        TH1=0xfd;        //采用串口工作方式1,无奇偶校验
        SCON=0x50;        //串口波特率不加倍
        PCON=0x00;         //开总中断,开串口中断
        IE=0x90;         //启动定时器1
        TR1=1;
}

   void comsend(uchar ch)           //串口发送数据发送一个数据
{
//        TB8=0;
        SBUF = ch;
    while(!TI);                       
    TI=0;               
}
/*--------------------------------------------------------------------------
函数名: start_bit
功能: 在SMBus总线上产生起始状态
注解: 参考"系统管理总线说明书-版本2.0"
--------------------------------------------------------------------------*/
void start_bit()
{
//   _SDA_OUTPUT;                                    //设置SDA为输出
   SDA=1;                                                //设置SDA线为高电平
    //_nop_(); _nop_();                        
   SCL=1;                                                //设置SCL线为高电平
   delayNOP();                                        //在终止和起始状态之间产生总线空闲时间(Tbuf=4.7us最小值)
   SDA=0;                                                //设置SDA线为低电平
   delayNOP();
   //(重复)开始状态后的保持时间,在该时间后,产生第一个时钟信号    //Thd:sta=4us最小值                                                   
   SCL=0;                                                //设置SCL线为低电平
    //_nop_(); _nop_();
}
/*------------------------------------------------------------------------
函数名: stop_bit
功能: 在SMBus总线上产生终止状态
注解: 参考"系统管理总线说明书-版本2.0"
------------------------------------------------------------------------*/
void stop_bit()
{
// _SDA_OUTPUT;                                       //设置SDA为输出

SDA=0;
        SCL=1;
        delayNOP();                       //延时5us
        SDA=1;
        delayNOP();
        SCL=0;                                    //终止状态建立时间(Tsu:sto=4.0us最小值)
                                          //设置SDA线为高电平
}
/*-------------------------------------------------------------
函数名: send_bit
功能:在SMBus总线上发送一位数据
//-------------------------------------------------------------*/
void send_bit(unsigned char bit_out)
{
   
//_SDA_OUTPUT;                        //设置SDA为开漏输出以在总线上传送数据
if(bit_out==1)                  //核对字节的位
          SDA=1;                      //如果bit_out=1,设置SDA线为高电平
else                                                         
    SDA=0;                //如果bit_out=0,设置SDA线为低电平
//delayNOP();                                    //
SCL=1;                      //设置SCL线为高电平
delayNOP();                        //时钟脉冲高电平脉宽(10.6us)
SCL=0;                      //设置SCL线为低电平
delayNOP();      //时钟脉冲低电平脉宽
}
/*------------------------------------------------------------
函数名: receive_bit
功能:在SMBus总线上接收一位数据
//---------------------------------------------------------*/
unsigned char receive_bit()
{
unsigned char bit_in;
SDA=1;                                    //设置SDA为高阻输入
SCL=1;                              //设置SCL线为高电平
delay_nus(1);
if(SDA==1)                            //从总线上读取一位,赋给bit_in      
       bit_in=1;
else
       bit_in=0;
delay_nus(1);
SCL=0;                                  //设置SCL线为低电平                                          
delay_nus(2);
return bit_in;               //返回bit_in值
}
/*-----------------------------------------------------------
函数名: slave_ack
功能: 由受控器件MLX90614中读取确认位
返回值:unsigned char ack
1 - ACK
0 - NACK
//-----------------------------------------------------------*/
unsigned char slave_ack()
{
   unsigned char ack;
   ack=0;
   SDA=1;                                    //设置SDA为高阻输入
   SCL=1;                  //设置SCL线为高电平
   delayNOP();
   if(SDA==1)                                    //从总线上读取一位,赋给ack
         ack=0;
   else
         ack=1;
   //delay_nus(1);
   SCL=0;                   //设置SCL线为低电平
// delay_nus(2);
   return ack;
}
/*--------------------------------------------------------
发送一个字节
函数名: TX_byte
功能: 在SMBus总线上发送一个字节
参数: unsigned char TX_buffer (将要在总线上发送的字节)
注解: 先发送字节的高位

//--------------------------------------------------------*/
void TX_byte(unsigned char TX_buffer)
{
unsigned char idata n = 8;
        while(n--)
        {
                if(0x80==(TX_buffer&0x80))
                {
                        SDA = 1 ;           //传送 1
                        SCL = 1 ;
                        delayNOP();
                        SCL = 0 ;
                        SDA = 0 ;
                       
                }
                else
                {
                        SDA = 0;               //传送 0
                        SCL = 1;
                        delayNOP();
                        SCL = 0;
                }
                TX_buffer = TX_buffer<<1; //左移一位
                delayNOP();
        }
        delayNOP();
        //check_ACK(); //
        //return (CHACK);                      
                                                                        
}
/*------------------------------------------------------
接收一个字节
函数名: RX_byte
功能: 在SMBus总线上接收一个字节
参数: unsigned char ack_nack (确认位)
0 - 主控器件发送 ACK
1 - 主控器件发送 NACK
返回值:unsigned char RX_buffer (总线接收的字节)
注解: 先接收字节的高位
//-------------------------------------------------------*/
unsigned char RX_byte(unsigned char ack_nack)
{
    unsigned char RX_buffer;
    unsigned char Bit_counter;
    for(Bit_counter=8;Bit_counter;Bit_counter--)
    {
                if(receive_bit()==1)                        //由SDA线读取一位
                   {
                        RX_buffer<<=1;                   //如果位为"1",赋"1"给RX_buffer
                        RX_buffer|=0x01;
                   }
                else                                 //如果位为"0",赋"0"给RX_buffer
                   {
                        RX_buffer<<=1;
                        RX_buffer&=0xfe;
                   }               
      }
         send_bit(ack_nack);                           //发送确认位
         return RX_buffer;
}
//-------------------------------------------------------------//


/*---------------------------------------------------
由MLX90614 RAM/EEPROM 读取的数据
函数名: MEM_READ
功能: 给定受控地址和命令时由MLX90614读取数据
参数: unsigned char slave_addR (受控地址)
         unsigned char cmdR (命令)
返回值: unsigned long int Data
//-------------------------------------------------*/
unsigned long int MEM_READ(unsigned char slave_addR, unsigned char cmdR)
{      
         unsigned char DataL;                         //
         unsigned char DataH;                                 //由MLX90614读取的数据包
         unsigned char PEC;                                    //
         unsigned long int Data;                        //由MLX90614返回的寄存器数值
         unsigned char Pecreg;                              //存储计算所得PEC字节
         unsigned char arr;                                 //存储已发送字节的缓冲器
         unsigned char ack_nack;
         unsigned char SLA;                                                                              
         SLA=(slave_addR<<1);
            begin:                           
         start_bit();                                                      //发送起始位
         TX_byte(SLA);   
               delayNOP();//发送受控器件地址,写命令
         if(slave_ack()==0)
         {
         comsend(0xaa);
             stop_bit();
             goto begin;
   }                                                //发送命令
   comsend(0xBB);
   TX_byte(cmdR);
         if(slave_ack()==0)
         {
             stop_bit();
             goto begin;
   }                                       
         start_bit();                   //发送重复起始位                              
         TX_byte(SLA+1);          //发送受控器件地址,读命令
         if(slave_ack()==0)
         {
             stop_bit();
             goto begin;
         }
         DataL=RX_byte(0);                                                                                 
         DataH=RX_byte(0);                        //读取两个字节数据         
         PEC=RX_byte(ack_nack);            //读取MLX90614的PEC码
         if(ack_nack==1)                  //主控器件发送ack 或是 nack 取决于pec计算,如果PEC是不正确的,发送nack并返回到goto begin
         {
             stop_bit();
             goto begin;
         }                                                
         stop_bit();               //发送终止位
         arr=(SLA);
   arr=cmdR;
   arr=(SLA+1);               
   arr=DataL;
   arr=DataH;
   arr=0;                                                                                                   
      // Pecreg=PEC_cal(arr,6);                            //调用计算 CRC 的函数
         if(PEC==Pecreg)
         {
                ack_nack=0;
         }
         else
         {
                ack_nack=0;
         }
         Data=(DataH*256)+DataL;
         return Data;
}


void main()
{
        uint Tem,yy; //温度变量
        uchar tm1,tm2;
                unsigned char slaveaddress;                                                                   
                unsigned long int DATA;
                        unsigned int *mahm;
       lcd_init();
       init_serial() ;
       SCL=1;        
       delay_nus(1200);       
        SCL=0;                                                                                  //
        delay_nus(1200);                                                               //SMBus request,Switch PWM mode to SMBus mode(at least 2ms)
       SCL=1;                                                                            //
               while(1)
               {
                          slaveaddress=MEM_READ(0x00,0x2E);                                           //Get the slave address which stored in EEPROM "0Eh"
                          DATA=MEM_READ(slaveaddress,0x07);                                                    //Read Object Temperature from MLX90614 RAM 07h
                       
                tm1   =DATA%256;
                tm2=   DATA/256;
                comsend(tm2);
                comsend(tm1);
                        sprintf(dis2,"%d",DATA);
        display(0x00,dis2);       
        delayms(10);                  
                                       
                   }

        /*while(1)
        {
        Tem=readtemp(); //读取温度
              tm1   =Tem%256;
                tm2=   Tem/256;
                comsend(tm2);
                comsend(tm1);
        sprintf(dis2,"%d",Tem);
        display(0x00,dis2);       
        delayms(10);                      
        } */

}

Acaicjhacai 发表于 2012-3-24 09:47:10

自己顶顶。代码比较乱,不好意思,LCD部分的 可以忽略不看

highrock 发表于 2013-4-15 10:01:31

看不是太懂!

highrock 发表于 2013-4-16 16:51:01

MLX90614 是即插即用的,你那边有做过设置?

louguixin 发表于 2014-11-14 11:14:28

我也遇到了同样的问题{:funk:}
页: [1]
查看完整版本: 调试AT89S52 ——MLX90614 失败,求助