红外温度传感器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();
}
} mark,虽然没有用到,但是也非常感谢楼主的开源 想看看 红外测温 我试过的的就是这个程序,但是我在读的时候,并没有将addr+1,很奇怪的读出来了!!!!
然后我今天看说明书,发现第二次发的时候,addr要+1,刚刚改了程序,但是还没硬件测试。 谢谢你的源代码, 给我启发很大. mark 温度读出来误差很大,不知道是怎么回事。很奇怪,一直都跟实际温度大概差8℃左右,调发射率也没有什么作用,我把发射率调成0.3,竟然温度还变成了负数!!!
不是发射率调低了,温度应该变大吗??
我测试的是手掌的温度,用我从市场上买回来的红外测温仪测试,是34.5℃,用mlx90615测试的是28~29℃之间。
有没有谁指教下????
多谢了! {:smile:}刚开始接触!!!学习。 也不知道楼主调试出来没有啊!求帮助啊 yufengzheyang 发表于 2013-4-30 11:38 static/image/common/back.gif
也不知道楼主调试出来没有啊!求帮助啊
同求啊 不管写0X00还是0XB4 从机根本就没应答让我怀疑器件坏了两个 啊几百块大洋啊 有没有调出来的
页:
[1]