求解答:我用ATMEGA16模拟SMBus同MLX90314通信,编写代码,但是没有得到数据。一下是我的代码,请求高人指点!!!
/********Done. Mon Dec 21 11:40:37 2015***********/
/*
MLX90614BAA
非接触温度传感器
额定电压+3V,最大耐压值+3.6V
*/
#include <iom16v.h> //包含型号头文件
#include <macros.h> //包含"位"操作头文件
#include <stdio.h> //标准输入输出头文件
#define uchar unsigned char
#define uint unsigned int
//#define RAM 0x00 //单个MLX时,可以使用0x00进行访问
//#define EEPROM 0x01
#define SEGLK PD2 //数码管段选锁存器控制端
#define BITLK PD3 //数码管位选锁存器控制端
//#define ack 0
//#define nack 1
#define SCL 0
#define SDA 1
uchar temp=333;
const SEGMENT[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d, 0x07,0x7f,0x6f,0x77,
0x7c,0x39,0x5e,0x79,0x71};
/************************
函数名称:PORT_Init()
函数功能:初始化端口
函数说明:对于不使用的IO引脚,设置为上拉输入
**********************/
void PORT_Init(void)
{
DDRA=0X00; //A端口暂时不涉及
PORTA=0XFF;
DDRB=0XFF; //B端口数码管
PORTB=0XFF;
DDRC=0X03; //C端口设计为模拟SMBus
PORTC=0XFF;
DDRD=0X0C; //D端口涉及位选、段选、蜂鸣器(蜂鸣器位设置为上拉输入,禁用蜂鸣器)
PORTD=0XFF;
}
/**************************
函数名称:Delay_us(uchar N)
函数功能:延时微秒
**************************/
void Delay_us(uint N)
{
uint i;
N=N*5/4;
for(i=0;i<N;i++);
}
/*******************************************
函数名称: Delay_ms
功 能: 延时指定毫秒(8M晶振)
参 数: MS--延时的毫秒数
/********************************************/
void Delay_ms(uint MS)
{
uint i,j;
for( i=0;i<MS;i++)
for(j=0;j<1141;j++); //1141是在8MHz晶振下,通过软件仿真反复实验得到的数值
}
/*******************************************
函数名称: One_smg_display
功 能: 指定的数码管显示指定的内容
参 数: data--显示的内容(0-15),number--指定的数码管(1-3)
/********************************************/
void One_smg_display(uchar data,uchar number)
{
PORTB=0X00;
PORTD|=BIT(SEGLK); //更新段选
PORTB|=SEGMENT[data]; //输出段选
PORTD&=~BIT(SEGLK); //锁存段选
PORTB=0XFF;
PORTD|=BIT(BITLK); //更新位选
switch(number)
{
case 1:PORTB&=~0X84;break;
case 2:PORTB&=~0X82;break;
case 3:PORTB&=~0X81;break;
}
PORTD&=~BIT(BITLK); //锁存位选
Delay_ms(1); //900时间有些长,造成闪屏Dec 22 08:09:58 2015
}
/***********************************************
函数名称:smbus_start()
功能:smbus总线开始信号
******************************************/
void smbus_start(void)
{
PORTC|=BIT(SCL);
PORTC|=BIT(SDA);
Delay_us(5);
PORTC&=~BIT(SDA);
Delay_us(6);
PORTC&=~BIT(SCL);
Delay_us(3);
}
/*****************************************
函数名称:smbus_stop()
函数功能:smbus总线停止
****************************************/
void smbus_stop(void)
{
PORTC&=~BIT(SCL);
PORTC&=~BIT(SDA);
Delay_us(5);
PORTC|=BIT(SCL);
Delay_us(6);
PORTC|=BIT(SDA);
}
/******************************
函数名称:read_slave_ack()
函数功能:接收一个回应位
*************************/
uchar read_slave_ack(void)
{
uchar ack_nack;
DDRC&=~BIT(SDA);
PORTC|=BIT(SCL);
Delay_us(4);
if(PIND&(1<<1))
ack_nack=1; //1高电平表示非应答信号
else
ack_nack=0; //0低电平表示应答信号
PORTC&=~BIT(SCL);
DDRC|=BIT(SDA);
Delay_us(4);
return ack_nack;
}
/*******************************
函数名称:smbus_read_bit()
函数功能:读取一位
****************************/
uchar smbus_read_bit(void)
{
uchar in_bit;
DDRC&=~BIT(SDA); //在引脚设置完成和读取引脚电平值之间,要添加一个系统时钟周期
PORTC|=BIT(SCL);
Delay_us(4);
if(PIND&(1<<1))
in_bit=1;
else
in_bit=0;
PORTC&=~BIT(SCL);
DDRC|=BIT(SDA);
Delay_us(4);
return in_bit;
}
/****************************
函数名称:smbus_send_bit()
函数功能:发送一位
*****************************/
void smbus_send_bit(uchar out_bit)
{
uchar t=5;
if(out_bit==1)
PORTC|=BIT(SDA);
else
PORTC&=~BIT(SDA);
while(t--); //约250ns Dec 22 14:59:59 2015
PORTC|=BIT(SCL);
Delay_us(15);
PORTC&=~BIT(SCL);
Delay_us(5);
}
/*****************************************
函数名称:smbus_readbyte()
函数功能:读一个字节
参数: 读命令
返回值: 读的值
****************************************/
uint smbus_readbyte(uint ack_nack)
{
uint i=0;
uint data=0;
for(i=8;i>0;i--) //接收8位数据
{
if(smbus_read_bit()==1) //判断SDA是否是高位
{
data<<=1;
data=data|0x01;
}
else
{
data=data<<1;
data&=~0xfe;
}
}
smbus_send_bit(ack_nack);
return data;
}
/*****************************************
函数名称:smbus_writebyte()
函数功能:写一个字节
参数: data
返回值:返回1成功,返回0失败
****************************************/
uchar smbus_writebyte(uint data)
{
uchar i=0;
uchar bit;
uchar ack_nack;
for(i=8;i>0;i--)
{
if((data&0x80)==0x80)
bit=1;
else
bit=0;
smbus_send_bit(bit);
data<<=1;
}
ack_nack=read_slave_ack(); //Dec 22 15:34:30 2015
return ack_nack;
}
/*************************
函数名称:pec_cal()
函数功能:计算PEC值,使用定义好的CRC校验和计算方式
参数:被计算数组,数组长度
返回值:计算结果
**************************/
uint pec_cal(uchar pec[])
{
uchar crc[6]; //存储初始校验值
uchar bitposition=47;
uchar shift;
uchar i;
uchar j;
uchar temp;
do
{
crc[5]=0; //载入CRC数值0x000000000107
crc[4]=0;
crc[3]=0;
crc[2]=0;
crc[1]=0x01;
crc[0]=0x07;
bitposition=47; //设置bitposition的最大值为47
shift=0; //在传送的字节中找出第一个1
i=5; //设置最高标志位(包裹字节标志)
j=0; //字节位标志,从最低位开始
while((pec[i]&(0x80>>j))==0&&(i>0))
{
bitposition--;
if(j<7)
j++;
else
{
j=0x00;
i--;
}
} //while语句结束,并找出bitposition中为1的最高位位置
shift=bitposition-8; //得到CRC数值将要左移/右移的数值shift
while(shift) //对CRC数据左移shift位
{
for(i=5;i<0xff;i--)
{
if((crc[i-1]&0x80)&&(i>0)) //核对字节的最高位的下一位是否为1
temp=1; //是,当前字节+1
else
temp=0; //否,当前字节+0
crc[i]<<=1;
crc[i]+=temp;
}
shift--;
}
for(i=0;i<=5;i++) //pec和crc之间进行异或计算
{
pec[i]^=crc[i];
}
}
while(bitposition>8);
return pec[0]; //返回计算所得的crc数值
}
/*****************************************
函数名称:smbus_readram()
函数功能:读RAM中的值
参数:地址addr,命令cmd
返回值:数值
****************************************/
uint smbus_readram(uchar addr,uchar cmd)
{
unsigned long int data; //存储处理后的温度值
uchar datal,datah; //存储读数据的低8位和高8位
uchar pec; //packet errer count
uchar buf[6]; //计算校验和的临时缓存数组
uchar ack_nack; //接收回应值
uchar pecreg;
uchar slave_addr;
slave_addr=addr<<1;
do
{
Begin:
smbus_start(); //发送开始信号
smbus_writebyte(slave_addr); //写地址,接收回应值
//Dec 23 08:49:32 2015
//ack 表示应答 SDA低电平
//nack 表示非应答 SDA高电平
//如果使用if(read_slave_ack()==0),0==0使得if()成立,表明接收到应答
//如果使用if(read_slave_ack()==1),1==1使得if()成立,表明接收到非应答
if(read_slave_ack()) //从设备接收失败
{
smbus_stop();
goto Begin; //写命令,接收回应值
}
smbus_writebyte(cmd);
if(read_slave_ack()) //从设备接收成功,否则重新开始循环
{
smbus_stop();
goto Begin;
}
smbus_start(); //重新发送开始信号
smbus_writebyte(slave_addr|0x01); //写地址,接收回应值
if(read_slave_ack())
{
smbus_stop();
goto Begin;
}
datah=smbus_readbyte(0); //读高8位值
datal=smbus_readbyte(0); //读低8 位值
pec=smbus_readbyte(1); //接收校验值
smbus_stop();
buf[5]=slave_addr;
buf[4]=cmd;
buf[3]=slave_addr|0x01;
buf[2]=datal;
buf[1]=datah;
buf[0]=0;
pecreg=pec_cal(buf); //计算校验值
}while(pecreg!=pec); //if received and calculated CRC are equal go out from da-while
data=(datah<<8+datal)*0.02-273.15;
return data;
}
/*******************************************
函数名称: main
功 能: 独立按键驱动主函数
参 数: 无
返回值 : 无
/********************************************/
void main(void)
{
uchar i=0;
//uchar slave_addr;
PORT_Init(); //端口初始化
/*PORTC&=~BIT(SCL);
Delay_ms(3);
PORTC|=BIT(SCL);*/
while(1)
{
i++;
if(i>2)
{
//slave_addr=smbus_readram(0x00,0x2e);
temp=smbus_readram(0x5a,0x07);
Delay_ms(15);
i=0;
}
temp=temp/1;
One_smg_display(temp/100,1);
One_smg_display(temp%100/10,2);
One_smg_display(temp%10,3);
}
}
|