调试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);
} */
} 自己顶顶。代码比较乱,不好意思,LCD部分的 可以忽略不看 看不是太懂! MLX90614 是即插即用的,你那边有做过设置? 我也遇到了同样的问题{:funk:}
页:
[1]