MELEXIS/MLX90614ESF-DCI 传感器 2440 IIC通讯



//---------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------------------------//
//函数名: 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

就是目标温度值了(摄氏度)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值