//---------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------------------------//
//函数名: start_bit
//功能: 在SMBus总线上产生起始状态
//注解: 参考“系统管理总线说明书-版本2.0”
//----------------------------------------------------------------------------------------------------------------------------------------//
void start_bit()
{
int i=0;
GpioInit(GPIO_SPIDATA, "O");
GpioInit(GPIO_SPICLK, "O");
GpioPdo(GPIO_SPIDATA, 1);
for(i=0;i <2; i++);
GpioPdo(GPIO_SPICLK, 1); //设置SCL线为高电平
Delay(5); //在终止和起始状态之间产生总线空闲时间(Tbuf=4.7us最小值)
GpioPdo(GPIO_SPIDATA, 0); //设置SDA线为低电平
Delay(5);
//(重复)开始状态后的保持时间,在该时间后,产生第一个时钟信号
//Thd:sta=4us最小值
GpioPdo(GPIO_SPICLK, 0); //设置SCL线为低电平
for(i=0;i <2; i++);
}
//----------------------------------------------------------------------------------------------------------------------------------------//
//函数名: stop_bit
//功能: 在SMBus总线上产生终止状态
//注解: 参考“系统管理总线说明书-版本2.0”
//----------------------------------------------------------------------------------------------------------------------------------------//
void stop_bit()
{
GpioInit(GPIO_SPIDATA, "O");
GpioInit(GPIO_SPICLK, "O"); //设置SDA为输出
GpioPdo(GPIO_SPICLK, 0); //设置SCL线为低电平
Delay(5);
GpioPdo(GPIO_SPIDATA, 0); //设置SDA线为低电平
Delay(5);
GpioPdo(GPIO_SPICLK, 1); //设置SCL线为高电平
Delay(5); //终止状态建立时间(Tsu:sto=4.0us最小值)
GpioPdo(GPIO_SPIDATA, 1); //设置SDA线为高电平
}
//----------------------------------------------------------------------------------------------------------------------------------------//
//函数名: send_bit
//功能:在SMBus总线上发送一位数据
//----------------------------------------------------------------------------------------------------------------------------------------//
void send_bit(unsigned char bit_out)
{
int i=0;
GpioInit(GPIO_SPIDATA, "O");
GpioInit(GPIO_SPICLK, "O"); //设置SDA为输出
//设置SDA为开漏输出以在总线上传送数据
if(bit_out==0) //核对字节的位
//如果bit_out=1,设置SDA线为高电平
GpioPdo(GPIO_SPIDATA, 0);
else
GpioPdo(GPIO_SPIDATA, 1); //如果bit_out=0,设置SDA线为低电平
for(i=0;i <3; i++);
GpioPdo(GPIO_SPICLK, 1) ; //设置SCL线为高电平
Delay(4); //时钟脉冲高电平脉宽(10.6us)
GpioPdo(GPIO_SPICLK, 0); //设置SCL线为低电平
Delay(4); //时钟脉冲低电平脉宽
}
//----------------------------------------------------------------------------------------------------------------------------------------//
//函数名: receive_bit
//功能:在SMBus总线上接收一位数据
//----------------------------------------------------------------------------------------------------------------------------------------//
unsigned char receive_bit()
{
unsigned char bit_in;
GpioInit(GPIO_SPIDATA, "I");
GpioInit(GPIO_SPICLK, "O"); //设置SDA为高阻输入
GpioPdo(GPIO_SPICLK, 1); //设置SCL线为高电平
Delay(2);
if(GpioPdi(GPIO_SPIDATA)==1) //从总线上读取一位,赋给bit_in
bit_in=1;
else
bit_in=0;
Delay(2);
GpioPdo(GPIO_SPICLK, 0) ; //设置SCL线为低电平
Delay(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;
GpioInit(GPIO_SPIDATA, "I");
GpioInit(GPIO_SPICLK, "O");
//设置SDA为高阻输入
GpioPdo(GPIO_SPICLK, 1) ; //设置SCL线为高电平
Delay(2);
if(GpioPdi(GPIO_SPIDATA)==1)//从总线上读取一位,赋给ack
ack=0;
else
ack=1;
Delay(2);
GpioPdo(GPIO_SPICLK, 0) ; //设置SCL线为低电平
Delay(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;
}
unsigned char PEC_cal(unsigned char pec[],int n)
{
unsigned char crc[6];
unsigned char Bitposition=47;
unsigned char shift;
unsigned char i;
unsigned char j;
unsigned char 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”
//对CRC数据左移“shift”位
while(shift)
{
for(i=5;i<0xFF;i--)
{
if((crc[i-1]&0x80) && (i>0)) //核对字节的最高位的下一位是否为"1"
{ //是 - 当前字节 + 1
temp=1; //否 - 当前字节 + 0
} //实现字节之间移动“1”
else
{
temp=0;
}
crc[i]<<=1;
crc[i]+=temp;
}
shift--;
}
//pec和crc之间进行异或计算
for(i=0;i<=5;i++)
{
pec[i]^=crc[i];
}
}while(Bitposition>8);
return pec[0]; //返回计算所得的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[6]; //存储已发送字节的缓冲器
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[5]=(SLA);
arr[4]=cmdR;
arr[3]=(SLA+1);
arr[2]=DataL;
arr[1]=DataH;
arr[0]=0;
Pecreg=PEC_cal(arr,6); //调用计算 CRC 的函数
if(PEC==Pecreg)
{
ack_nack=0;
}
else
{
ack_nack=1;
}
Data=(DataH*256)+DataL;
return Data;
}
最后
Temp=MEM_READ(0X00,0X07);
OBJTEMP =Temp*0.02-273.15
就是目标温度值了(摄氏度)