zhang2274 发表于 2011-8-9 09:53:50

红外温度传感器MLX90614T调试不成功,单片机用的是C8051f320

红外温度传感器MLX90614T调试不成功,单片机用的是C8051f320。
程序是参照MLX官网上 < MLX90614 和单片机STC12C5604AD 的SMBus,PWM通信> 上的C代码, 显示部分是74HC164和74HC138 四位数码管组成。晶振用的内部12M .可是温度不显示。有人知道原因吗,以下是用keil51写的代码。本人刚接触51单片机,请高手指教


#include "C8051f320.h"
#include "stdio.h"
#include "intrins.h"
#include "string.h"


#define uchar unsigned char      //定义无符号字符为 uchar
#define uintunsigned int       //定义无符号整型



sbit SDA = P1^1;                     // SMBus on P0.0
sbit SCL = P1^2;                     // and P0.1
//sbit A_138 = P1^3;
//sbit B_138 = P1^4;
//sbit C_138 = P1^5;
//sbit AB_164 = P1^6;
//sbit CLK_164 = P1^7;
//sbit CLR_164 = P2^0;




#define HC164_B_H( )    { P1 |= ( 1<<6 ); P1MDOUT |= ( 1<<6 ); }
#define HC164_B_L( )    { P1 &= ~( 1<<6 ); P1MDOUT |= ( 1<<6 ); }

#define HC164_CLK_H( ){ P1 |= ( 1<<7 ); P1MDOUT |= ( 1<<7 ); }
#define HC164_CLK_L( ){ P1 &= ~( 1<<7 ); P1MDOUT |= ( 1<<7 ); }
#define HC164_CLR_H( ){ P2 |= ( 1<<0 ); P2MDOUT |= ( 1<<0 ); }
#define HC164_CLR_L( ){ P2 &= ~( 1<<0 ); P2MDOUT |= ( 1<<0 ); }




#define _SDA_OUTPUT P1MDOUT |= ( 1<<1 );            //设置SDA为开漏输出   SCL为开漏输出
#define _SDA_INPUTP1MDIN|= ( 1<<1 );                         //设置SDA为高阻输入   SCL为开漏输出
#define _SCL_IO                P1MDOUT |= ( 1<<2 );



static codeNumber={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
static codeNumber_Dot={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};


static void ClockInit( void )             //设置内部晶振12M
{
       OSCICN    = 0x83;
}


static void GPIOInit( void )            //IO初始化
{
    P0SKIP |= 0xC0;
    P1SKIP |= 0xFE;

        XBR0 |= ( 1<<0 ) | ( 1<<1 ) | ( 1<<2 );
        XBR1 |= ( 1<<6 ) | ( 1<<0 );


}



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


//--------------------------------------------------------------------------//

//--------------------------------------------------------------------------//
//该文档包含了SMBus通信的起始状态,终止状态,发送和接受字节等
//--------------------------------------------------------------------------//

/*--------------------------------------------------------------------------
函数名: start_bit
功能: 在SMBus总线上产生起始状态
注解: 参考"系统管理总线说明书-版本2.0"
--------------------------------------------------------------------------*/
void start_bit()
{
   _SDA_OUTPUT;                                    //设置SDA为输出
   SDA=1;                                              //设置SDA线为高电平
    _nop_(); _nop_();                          
   SCL=1;                                              //设置SCL线为高电平
   delay_nus(5);                                        //在终止和起始状态之间产生总线空闲时间(Tbuf=4.7us最小值)
   SDA=0;                                              //设置SDA线为低电平
   delay_nus(5);
   //(重复)开始状态后的保持时间,在该时间后,产生第一个时钟信号    //Thd:sta=4us最小值                                                    
   SCL=0;                                              //设置SCL线为低电平
    _nop_(); _nop_();
}
/*------------------------------------------------------------------------
函数名: stop_bit
功能: 在SMBus总线上产生终止状态
注解: 参考"系统管理总线说明书-版本2.0"
------------------------------------------------------------------------*/
void stop_bit()
{
_SDA_OUTPUT;                                         //设置SDA为输出
SCL=0;                                           //设置SCL线为低电平
delay_nus(5);
SDA=0;                                           //设置SDA线为低电平
delay_nus(5);
SCL=1;                                              //设置SCL线为高电平
delay_nus(5);                                         //终止状态建立时间(Tsu:sto=4.0us最小值)
SDA=1;                                           //设置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线为低电平
   _nop_();                                   //
   _nop_();                                   //Tsu:dat=250ns 最小值
   _nop_();                                   //
SCL=1;                      //设置SCL线为高电平
delay_nus(4);                          //时钟脉冲高电平脉宽(10.6us)
SCL=0;                      //设置SCL线为低电平
delay_nus(4);         //时钟脉冲低电平脉宽
}
/*------------------------------------------------------------
函数名: receive_bit
功能:在SMBus总线上接收一位数据
//---------------------------------------------------------*/
unsigned char receive_bit()
{
unsigned char bit_in;
_SDA_INPUT;                                  //设置SDA为高阻输入
SCL=1;                              //设置SCL线为高电平
delay_nus(2);
if(SDA==1)                            //从总线上读取一位,赋给bit_in      
       bit_in=1;
else
       bit_in=0;
delay_nus(2);
SCL=0;                                  //设置SCL线为低电平                                          
delay_nus(4);
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_INPUT;                                  //设置SDA为高阻输入
   SCL=1;                  //设置SCL线为高电平
   delay_nus(2);
   if(SDA==1)                                  //从总线上读取一位,赋给ack
         ack=0;
   else
         ack=1;
   delay_nus(2);
   SCL=0;                   //设置SCL线为低电平
   delay_nus(4);
   return ack;
}
/*--------------------------------------------------------
发送一个字节
函数名: TX_byte
功能: 在SMBus总线上发送一个字节
参数: unsigned char TX_buffer (将要在总线上发送的字节)
注解: 先发送字节的高位

//--------------------------------------------------------*/
void TX_byte(unsigned char TX_buffer)
{
   unsigned char Bit_counter;
   unsigned char bit_out;
   
   for(Bit_counter=8;Bit_counter;Bit_counter--)
   {
       if(TX_buffer&0x80)
                     bit_out=1;                       //如果TX_buffer的当前位是1,设置bit_out为1
                else
                     bit_out=0;                           //否则,设置bit_out为0
   send_bit(bit_out);                              //发送SMBus总线上的当前位   
   TX_buffer<<=1;                              //核对下一位                  
        }                                                                
}
/*------------------------------------------------------
接收一个字节
函数名: 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;
}
//-------------------------------------------------------------//





//-------------------------------------------------------------//
//该文档包含了SMBus通信时从MLX90614读取数据,写入数据和PEC校验码计算的程序


/*-------------------------------------------------------------
计算PEC包裹校验码
函数名: PEC_cal
功能: 根据接收的字节计算PEC码
参数: unsigned char pec[], int n
返回值: pec - 该字节包含计算所得crc数值
注解:        参考"系统管理总线说明书-版本2.0"和应用指南"MCU和MLX90614的SMBus通信"
--------------------------------------------------------------*/
unsigned char PEC_cal(unsigned char pec[],int n)
{
   unsigned char crc;
   unsigned char Bitposition=47;
   unsigned char shift;
   unsigned char i;
   unsigned char j;
   unsigned char temp;
       do{
          crc=0;                                         //载入 CRC数值 0x000000000107
          crc=0;
          crc=0;
          crc=0;
          crc=0x01;
          crc=0x07;
          Bitposition=47;                               //设置Bitposition的最大值为47
          shift=0;
          //在传送的字节中找出第一个"1"

          i=5;                                                //设置最高标志位 (包裹字节标志)
          j=0;                                                //字节位标志,从最低位开始
          while((pec&(0x80>>j))==0 && (i>0))          
              {
             Bitposition--;
             if(j<7)
                 {
               j++;
             }
             else
                 {
                   j=0x00;
                   i--;
            }
         }//while语句结束,并找出Bitposition中为"1"的最高位位置
          shift=Bitposition-8;                                 //得到CRC数值将要左移/右移的数值"shift"
                                                                   //对CRC数据左移"shift"位
          while(shift)
              {
            for(i=5;i<0xFF;i--)
                      {
               if((crc&0x80) && (i>0))          //核对字节的最高位的下一位是否为"1"
                         {                                //是 - 当前字节 + 1
                     temp=1;                     //否 - 当前字节 + 0
               }                                     //实现字节之间移动"1"
               else
                   {
                     temp=0;
               }
                     crc<<=1;
                     crc+=temp;
            }

                  shift--;
         }
         //pec和crc之间进行异或计算
         for(i=0;i<=5;i++)
                   {
               pec^=crc;
                   }
      }while(Bitposition>8);
        return pec;                                  //返回计算所得的crc数值
}
/*---------------------------------------------------
由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);                                          //发送受控器件地址,写命令
       if(slave_ack()==0)
       {
             stop_bit();
             goto begin;
   }                                                  //发送命令
   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=1;
       }
       Data=(DataH*256)+DataL;
       return Data;
}
/*-------------------------------------------------------
MLX90614 EEPROM中写入数据
函数名: EEPROM_WRITE
功能: 根据命令写入相关数据到给定受控器件地址的MLX90614
参数: unsigned char slave_addW (受控器件地址)
unsigned char cmdW (命令)
unsigned char DataL
unsigned char DataH
//---------------------------------------------------*/       
/*void EEPROM_WRITE(unsigned char slave_addW,unsigned char cmdW,unsigned char DataL,unsigned char DataH)
{
   unsigned char Pecreg;                                   //存储计算所得PEC字节
   unsigned char SLA;
   unsigned char arr;                                        //存储将要发送字节的缓冲器
   SLA=(slave_addW<<1);
   arr=0;
   arr=SLA;
   arr=cmdW;
   arr=DataL;
   arr=DataH;
   arr=0;
   Pecreg=PEC_cal(arr,6);
   begin:
   start_bit();                                               //发送起始位
   TX_byte(SLA);                                       //发送受控地址,写命令
   if(slave_ack()==0)                                                                  
   {
         stop_bit();
             goto begin;
   }
   TX_byte(cmdW);                                          //发送命令
   if(slave_ack()==0)
   {
         stop_bit();
             goto begin;
   }
   TX_byte(DataL);                                       //发送数据低位字节
   if(slave_ack()==0)
   {
         stop_bit();
             goto begin;
   }
   TX_byte(DataH);                                       //发送数据高位字节
   if(slave_ack()==0)
   {
         stop_bit();
             goto begin;
   }
   TX_byte(Pecreg);                                       //发送PEC码
   if(slave_ack()==0)
   {
         stop_bit();
             goto begin;
   }
   stop_bit();                                    //发送终止位
   delay_nus(200);                                  //等候5ms
   
}*/

unsigned int *CALTEMP(unsigned long int TEMP)
{
      unsigned long int T;
          unsigned int a,b;
      unsigned int A4,A5,A6,A7 ;
          unsigned int mah;
      T=TEMP*2;
   
      if(T>=27315)
            {
               T=T-27315;
               a=T/100;
               b=T-a*100;

               if(a>=100)
                   {
                      A4=a/100;
                      a=a%100;
                      A5=a/10;
                      a=a%10;
                      A6=a;
                  }
               else if(a>=10)
                  {
                      A4=0;
                      A5=a/10;
                      a=a%10;
                      A6=a;
                  }

               else

                  {
                      A4=0;
                      A5=0;
                      A6=a;
                  }
               if(b>=10)
                  {
                      A7=b/10;
                      b=b%10;
                  }
                else
                  {
                      A7=0;
                  }
             }

         else
               {
                  T=27315-T;
                  a=T/100;
                  b=T-a*100;
                  A4=9;

                  if(a>=10)
                      {
                         A5=a/10;
                         a=a%10;
                         A6=a;
                      }
                  else
                      {
                         A5=0;
                         A6=a;
                      }
                  if(b>=10)
                      {
                         A7=b/10;
                         b=b%10;
                      }
                  else
                      {
                         A7=0;
                      }
                }
               
      mah=A4;
                mah=A5;
                mah=A6;
                mah=A7;

return mah;

}



void HC164_Output( char value )                  //74hc164移位
{signed char   i,tem;
       for( i=0;i<8;i++ )
    {
             HC164_CLK_L( );
                tem=(value&0x80);
          if(tem==0)

               { HC164_B_H( );
                  }
                else
      {
            HC164_B_L( );
                        }
                  value=value<<1;
                  HC164_CLK_H( );
                }

}

void HC138_Sel( unsigned char x )                  // 74hc138译码
{
        x &= 0x07;
        P1MDOUT |= ( 1<<3 ) | ( 1<<4 ) | ( 1<<5 );
        P1 |= ( 1<<3 ) | ( 1<<4 ) | ( 1<<5 );
        P1 &= ( ( x<<3 ) | 0xC7 );
}
   


//show(void)
void show(unsigned int mahh[],int number)                  //动态显示部分

{
      //HC138_Sel(0x05);
      HC164_Output(Number);//显示点数位1
                HC164_Output(Number]);//显示点数位1
      HC138_Sel(0x01);
                delay_nus(10);
          
      //HC138_Sel(0x05);
          HC164_Output(Number);
          HC164_Output(Number_Dot]);//显示个位
      HC138_Sel(0x02);
                delay_nus(10);


      //HC138_Sel(0x05);
          HC164_Output(Number);
          HC164_Output(Number]);//显示十位
      HC138_Sel(0x03);
                delay_nus(10);
               
                //HC138_Sel(0x05);
          HC164_Output(Number);
         HC164_Output(Number]);////显示百位
      HC138_Sel(0x04);
                delay_nus(10);

                //HC138_Sel(0x05);

}






//----------------------------------------------------------------------------------------------------------------------------------------//

void main()
{                                               
        unsigned char slaveaddress;                                 
    unsigned long int DATA;
        unsigned int *mahm;
          


      ClockInit();
      GPIOInit();
                HC164_CLR_H( );
      _SCL_IO;
      _SDA_OUTPUT;

       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
          mahm=CALTEMP(DATA);                                            //Calculate the Temperature based on Hex code
      show(mahm,4);                                           //Show the Temperature on Digital LEDs               
          //show();
               
               
                  
       }
}

leifeng 发表于 2011-8-9 10:18:57

mark,虽然没有用到,但是也非常感谢楼主的开源

shenma 发表于 2011-9-14 17:58:17

想看看 红外测温

yanrz 发表于 2011-9-23 15:33:55

我试过的的就是这个程序,但是我在读的时候,并没有将addr+1,很奇怪的读出来了!!!!
然后我今天看说明书,发现第二次发的时候,addr要+1,刚刚改了程序,但是还没硬件测试。

starstar 发表于 2011-9-24 15:11:22

谢谢你的源代码, 给我启发很大.

fanwt 发表于 2011-9-24 19:43:32

mark

yanrz 发表于 2011-10-7 21:50:33

温度读出来误差很大,不知道是怎么回事。很奇怪,一直都跟实际温度大概差8℃左右,调发射率也没有什么作用,我把发射率调成0.3,竟然温度还变成了负数!!!
不是发射率调低了,温度应该变大吗??
我测试的是手掌的温度,用我从市场上买回来的红外测温仪测试,是34.5℃,用mlx90615测试的是28~29℃之间。
有没有谁指教下????
多谢了!

Zdhtdps 发表于 2012-7-9 22:58:42

{:smile:}刚开始接触!!!学习。

692140122 发表于 2013-3-21 16:40:33

yufengzheyang 发表于 2013-4-30 11:38:03

也不知道楼主调试出来没有啊!求帮助啊

Zigbee2012 发表于 2013-5-2 21:32:59

yufengzheyang 发表于 2013-4-30 11:38 static/image/common/back.gif
也不知道楼主调试出来没有啊!求帮助啊

同求啊    不管写0X00还是0XB4   从机根本就没应答让我怀疑器件坏了两个 啊几百块大洋啊    有没有调出来的
页: [1]
查看完整版本: 红外温度传感器MLX90614T调试不成功,单片机用的是C8051f320