|
|
View previous topic :: View next topic |
Author |
Message |
ep.hobbyiest
Joined: 08 Oct 2014 Posts: 20
|
PIC16F886 and MLX90614 |
Posted: Wed Oct 25, 2017 12:39 pm |
|
|
Hi,
I am using MLX90614 Temp. Sensor and PIC16F886. Following is my code
I am facing problem as i am not able to make it wok. I spend few days in the same. I got following code from forum only.
Power supply is of 3.3V to sensor and PIC.
I am using PC3 to SCL and PC4 to SDA.
External XTAL is of 8MHz.
main.c
Code: |
#include "main.h"
#include <stdint.h>
//SMBUS Device Address
#define Device_Address 0x50
//RAM Addresses for Temperatures
#define AT_Address 0x06 // Ambient Temperature - The Sensor's internal temperature
#define OT_Address 0x07 // Object Temperature - Whats in the Sensor's FOV
//EEPROM Addresses for Configuration/Writing
#define TO_Max 0x20
#define TO_Min 0x21
#define PWM_Control 0x22
#define TA_Range 0x23
#define Emissivity_Address 0x24
#define Config_Address 0x25
#define SMBUS_Address 0x2E
//Other Stuff for code Readability
#define Write_Bit 0x00
#define Read_Bit 0x01
#define ACK 0x00
#define NACK 0x01
//Function Declarations
int16 MLX_Read_Transaction(int); // Needs Address to read from
void MLX_Write_Transaction(int,int,int);// Needs Address to write to, lo and hi bytes.
int Create_CRC(int,int,int); // Needs Address to write to, lo and hi bytes.
int Check_CRC(int,int,int,int); // Needs Read address,hi, lo and CRC Bytes
int CRC8_CCITT(int, int); // Starting CRC and Byte to encode/decode
//**********************************************************************************
// EXAMPLE FUNCTIONS
//**********************************************************************************
// These are not really part of the driver, just examples of how to call things from
// your program:
//
// void main()
// {
// Read_Object(); //Gets you Temp of objects in FOV
// Read_Ambient(); //Gets you Ambient Temp
//
// //LETS EDIT SOME EEPROM VALUES!!!
// Read_TOMAX(); //Will read default value - probably 9993
// MLX_Write_Transaction(TO_Max,0x00,0x00);//Need to erase EEPROM first with 0x0000
// Read_TOMAX(); //Will now read 0x0000
// MLX_Write_Transaction(TO_Max,0xFF,0xFF);//Write desired values
// Read_TOMAX(); //Will now read 0xFFFF
// }
void sendBT(char *str)
{
while(*str!='\0')
{
putchar(*str++);
delay_ms(10);
}
}
void Read_Object()
{
printf("Object Temp:%3.2f\r\n",((MLX_Read_Transaction(OT_Address)*0.02)-273.15));
// *dat = ((float)raw *0.02 -0.01 ) - 273.15; // convert Absolute temperature to Degrees Celsius of temperature
delay_ms(1000);
}
void Read_Ambient()
{
printf("Ambient Temp:%3.2f\r\n",((MLX_Read_Transaction(AT_Address)*0.02)-273));
delay_ms(1000);
}
void Read_Config()
{
// fprintf(lcd_putc,"MLX Configuration:%LX\r\n",MLX_Read_Transaction(Config_Address));
delay_ms(500);
}
void Read_Emissivity()
{
// fprintf(lcd_putc,"Emissivity Value:%LX\r\n",MLX_Read_Transaction(Emissivity_Address));
delay_ms(500);
}
void Read_TOMAX()
{
// fprintf(lcd_putc,"TO_MAX:%LX\r\n",MLX_Read_Transaction(TO_Max));
delay_ms(500);
}
//**********************************************************************************
// READ MLX DATA
//**********************************************************************************
// This functions works for both EEPROM and RAM Data from the MLX Sensor.
// A Checksum check is included to confirm Data integrity
int16 MLX_Read_Transaction(uint8_t Read_Address)
{
int16 MLX_Response; // Stores the 16 bit responses from the MLX
int Command=0; // stores the Address+write/read bit
int Lo_Byte=0;
int Hi_Byte=0;
int CRC=0;
Command=Device_Address<<1; // Prepare Command: shift address 1 bit
Command|=Write_Bit; // Shifted Address with W/R Bit set or cleared
i2c_start(); // Send Start Bit
if (i2c_write(0xB4)==ACK) // Send "Write" Command to the Device Address
{
i2c_write(Read_Address); // Write Address to be read
Command=Device_Address<<1; // Prepare Command: byte shift address 1 bit
Command|=Read_Bit; // Shifted Address with W/R Bit set or cleared
i2c_start(); // Send Re-Start Bit
i2c_write(0xB5); // Send "Read" Command to the Device Address
Lo_Byte = i2c_read(1); // Get Low Byte and ACK the read
Hi_Byte = i2c_read(1); // Get High Byte and ACK the read
CRC = i2c_read(0); // Get CRC and ACK the Read
}
i2c_stop(); // Hammer Time
// if(Check_CRC(Read_Address,Lo_Byte,Hi_Byte,CRC)==0)
{
MLX_Response= make16(Hi_Byte,Lo_Byte);
return(MLX_Response);
}
}
//**********************************************************************************
// WRITE DATA TO MLX
//**********************************************************************************
// This function writes to the EEPROM of the MLX. It calculates the CRC automatically.
// There is a small delay at the end as "settling time" after the write.
// During testing this delay was required if reading the data Immediatly after the write
void MLX_Write_Transaction(int Write_Address,int Lo_Byte,int Hi_Byte)
{
int CRC=0; // Holds the CRC of data to be sent
int Command=0; //
CRC=Create_CRC(Write_Address,Lo_Byte,Hi_Byte);
Command=Device_Address<<1; // Prepare Command: shift address 1 bit
Command|=Write_Bit; // Shifted Address with W/R Bit set or cleared
i2c_start(); // Send Start Bit
if (i2c_write(Command)==ACK) // Send Device Address
{
i2c_write(Write_Address); // Write Address to be Written onto
i2c_write(Lo_Byte); // Send Low Byte
i2c_write(Hi_Byte); // Send Hi Byte
i2c_write(CRC); // Send CRC/PEC
}
i2c_stop(); // Hammer Time
delay_ms(10); // Allow time after write
}
//**********************************************************************************
// CREATE A CRC
//**********************************************************************************
// Calculates the CRC of the DATA to be sent to EEPROM
int Create_CRC(int Write_Address,int Lo_Byte,int Hi_Byte)
{
int Temp_CRC=0; // Holds the intermediate CRC Calculations
int Command=0; //
Command=Device_Address<<1; // Prepare Command: shift address 1 bit
Command|=Write_Bit; // Shifted Address with W/R Bit set or cleared
Temp_CRC=CRC8_CCITT(0x00,Command); // Device Address
Temp_CRC=CRC8_CCITT(Temp_CRC,Write_Address);// Memory Address
Temp_CRC=CRC8_CCITT(Temp_CRC,Lo_Byte); // LSB Byte
Temp_CRC=CRC8_CCITT(Temp_CRC,Hi_Byte); // MSB Byte
//fprintf(lcd_putc,"New CRC:%X\r\n",Temp_CRC); //DEBUG
return (Temp_CRC);
}
//**********************************************************************************
// CHECK INCOMMING DATA'S CRC
//**********************************************************************************
// Takes the data read from the sensor and checks if the Checksum is Right
int Check_CRC(int Read_Address,int Lo_Byte,int Hi_Byte,int CRC)
{
int Temp_CRC=0;
int Command=0;
Command=Device_Address<<1; // Prepare Command: shift address 1 bit
Command|=Write_Bit; // Shifted Address with W/R Bit set or cleared
Temp_CRC=CRC8_CCITT(0x00,Command); // Device Address
Temp_CRC=CRC8_CCITT(Temp_CRC,Read_Address); // Memory Address
Command=Device_Address<<1; // Prepare Command: shift address 1 bit
Command|=Read_Bit; // Shifted Address with W/R Bit set or cleared
Temp_CRC=CRC8_CCITT(Temp_CRC,Command); // Device Address with Read Bit Set
Temp_CRC=CRC8_CCITT(Temp_CRC,Lo_Byte); // LSB Byte
Temp_CRC=CRC8_CCITT(Temp_CRC,Hi_Byte); // MSB Byte
Temp_CRC=CRC8_CCITT(Temp_CRC,CRC); // Received CRC Value
//fprintf(lcd_putc,"CRC Check:%X\r\n",Temp_CRC); //DEBUG
return (Temp_CRC);
}
//**********************************************************************************
// CRC8-CCITT CALCULATION
//**********************************************************************************
// This function was taken from "AVR Libc Reference Manual" and some names changed.
// Full credit to those involved in its creation.
int CRC8_CCITT(int inCrc, int inData)
{
int i;
int data;
data = inCrc ^ inData;
for ( i = 0; i < 8; i++ )
{
if (( data & 0x80 ) != 0 )
{
data <<= 1;
data ^= 0x07;
}
else
{
data <<= 1;
}
}
return data;
}
void main()
{
while(1)
{
output_low(LED);
Read_Object(); //Gets you Temp of objects in FOV
output_high(LED);
Read_Ambient(); //Gets you Ambient Temp
}
//LETS EDIT SOME EEPROM VALUES!!!
// Read_TOMAX(); //Will read default value - probably 9993
// MLX_Write_Transaction(TO_Max,0x00,0x00);//Need to erase EEPROM first with 0x0000
// Read_TOMAX(); //Will now read 0x0000
// MLX_Write_Transaction(TO_Max,0xFF,0xFF);//Write desired values
// Read_TOMAX(); //Will now read 0xFFFF
}
|
Main.h file.
Code: |
#include <16F886.h>
#device ADC=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#use delay(crystal=8MHz)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=PORT1)
#use i2c(Master,slow,sda=PIN_C3,scl=PIN_C4,FORCE_SW)
#define LED PIN_A0
#define DELAY 1000
|
I think i2c_read is not working properly. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Wed Oct 25, 2017 1:36 pm |
|
|
1st place to start...
Download and compile the I2C Scanner program that PCM P put in the 'code library'.
Run it and CONFIRM the PIC does see the device.
Be sure to use appropriate I2C bus pullup resistors. Maybe 1k5 ??
Once that confirms the PIC does see the device, then you know the hardware is Ok.
2nd chunk of code.
Create a simple 'write a register then read a register' program. Be sure you can alter the contents of any register of that device that you're supposed to be able to.
once this works
THEN
try your 'real' program.
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19497
|
|
Posted: Wed Oct 25, 2017 1:39 pm |
|
|
The default address of this chip is 0x5A, not 0x50.
Always with I2C, the first thing to do is to run the I2C address scanner program from PCM_Programmer (in the code forum). This will tell you if your hardware is working, and what address the device is on. |
|
|
ep.hobbyiest
Joined: 08 Oct 2014 Posts: 20
|
|
Posted: Wed Oct 25, 2017 8:19 pm |
|
|
Yes. It was 0x5A only. But i was checking how it working with wrong address.
I was using 0x5A only and not working with that also.
I ran i2c scanner for this device, but got more than 50 address (invalid).
i2c scanner gives correct address for oled, but not working properly with MLX90614. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19497
|
|
Posted: Thu Oct 26, 2017 1:57 am |
|
|
You have got the 'B' device. MLX90614xxx-Bxxxx
It must be a B device to run at 3v (or a D device). Unlike a lot of devices where the higher voltage version will run at lower voltages these don't
If the hardware is working, PCM's scanner will find it. That it is reporting phantom devices, says the pull ups are not doing what they should. What resistors are you using?. |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Thu Oct 26, 2017 6:00 am |
|
|
As i mentioned on your post on the library..... the serial streams dont match.
G. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
ep.hobbyiest
Joined: 08 Oct 2014 Posts: 20
|
|
Posted: Thu Oct 26, 2017 9:40 am |
|
|
I am using Pull up of 1K8 ohm.
Quote: | As i mentioned on your post on the library..... the serial streams dont match. |
are you talking about uart communication? If yes, then Yes it is working properly.
For I2C communication i am using 1 i2c bus only. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Oct 26, 2017 9:41 am |
|
|
I wonder if your #use i2c statement is correct, because you have sda
and scl reversed. Normally, you would specify SCL on PIN_C3, and
SDA on PIN_C4. They are reversed in your #use i2c statement below:
Quote: | #use i2c(Master, slow, sda=PIN_C3, scl=PIN_C4, FORCE_SW) |
Check your wiring. If it's wired for scl to PIN_C3, and sda to PIN_C4
then you need to fix the statement above to match the wiring. |
|
|
ep.hobbyiest
Joined: 08 Oct 2014 Posts: 20
|
|
Posted: Thu Oct 26, 2017 9:53 am |
|
|
Yes my definition is correct only. After connection i checked in code then i was corrected it in code and made it as FORCE_SW.
Result of i2c_scanner:
Code: | Start:
ACK addr: 10
ACK addr: 12
ACK addr: 18
ACK addr: 1A
ACK addr: 1C
ACK addr: 1E
.
.
.
.
ACK addr: DE
ACK addr: E4
ACK addr: E6
ACK addr: E8
ACK addr: EC
ACK addr: EE
Number of i2c chips found: 79
|
Again i changed the wiring and connected same as hardware i2c.
When i used as FORCE_HW then got stuck after first read.
Code: | #use i2c(Master,fast,sda=PIN_C4,scl=PIN_C3, FORCE_HW) |
But after removing of FORCE_HW then it didn't stuck.
Code: | #use i2c(Master,fast,sda=PIN_C4,scl=PIN_C3) |
Quote: | You have got the 'B' device. MLX90614xxx-Bxxxx |
I tried with giving 5 volt as well. but same result.
is that means problem in i2c hardware? |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Fri Oct 27, 2017 6:06 am |
|
|
I think you need to post a complete compilable program for others to test, short and simple, that shows the error.
Your serial might be working, but your streams do not match.
My code's print statements use "lcd_putc" as a stream, yours use "PORT1"....also some mis-matches on the use of "printf" vs "fprintf".
Might not be the cause of the problem, but it should be taken care of. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Oct 27, 2017 11:04 am |
|
|
Also post a link to the schematic for your board.
Also post a link to a photo of your test setup, so we can see the connections. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|