|
|
View previous topic :: View next topic |
Author |
Message |
jleblanc
Joined: 17 May 2006 Posts: 9
|
LM75 Addressing Problem |
Posted: Tue Aug 01, 2006 12:48 pm |
|
|
Hello,
I'm trying to develop some code that will allow me to talk to multiple LM75 temperature sensors on an I2C bus. The problem I'm having though is my code will only communicate with an LM75 at it's base address (A0-A2 pins on the LM75 all grounded). When I try to communicate with a chip on base address+1 (A0 high, A1-A2 ground) my code doesn't work. I've posted my code below, any ideas?
When I'm conducting my tests I only have the one LM75 on the I2C bus.
Thanks!
Code: | double LM75_ReadTemperatureRegister(unsigned int pAddress)
{
unsigned long Data=0;
unsigned int Address=0;
unsigned int HiByte=0;
unsigned int LoByte=0;
double Temperature=0;
Address=LM75_BASE_ADDRESS | pAddress;
Address<<=1;
i2c_start();
i2c_write(Address);
i2c_write(LM75_TEMP_REG);
i2c_start();
i2c_write(Address | 1);
HiByte=i2c_read();
LoByte=i2c_read();
i2c_stop();
Data=make16(HiByte,LoByte);
Data>>=5; //lower 5 bits aren't used
//test the sign bit
if (Data & 1024!=1) //temperature is positive
{
Temperature=Data*0.125;
}
else //temperature is negative
{
Temperature=(0-Data)*0.125;
}
return(Temperature);
} |
Here's how I2C is setup in my program:
Code: | #use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3) |
So calling
Code: | LM75_ReadTemperatureRegister(0); |
Will work with an LM75 on that address but calling
Code: | LM75_ReadTemperatureRegister(1); |
Does not. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Aug 01, 2006 1:03 pm |
|
|
Please edit your post, and fix the garbled lines of code, and
then submit the post with the checkbox for "Disable HTML in this post"
selected. If you use Less Than or Greater Than symbols with HTML
enabled, your code will get scrambled. The checkbox is directly
below the posting composition window. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Aug 01, 2006 1:42 pm |
|
|
OK, that's better.
I see one immediate problem. The last i2c_read() needs to do a "NAK".
In CCS, this is done by giving the function a 0 parameter. Change
your code so it does this. See the line shown in bold below.
Quote: | i2c_start();
i2c_write(Address);
i2c_write(LM75_TEMP_REG);
i2c_start();
i2c_write(Address | 1);
HiByte=i2c_read();
LoByte=i2c_read(0);
i2c_stop(); |
I didn't really look closely at the rest of your code. If that doesn't
fix the problem, then post the #define statements for your constants,
such as LM75_BASE_ADDRESS. Currently we don't know what those
are. |
|
|
jleblanc
Joined: 17 May 2006 Posts: 9
|
|
Posted: Tue Aug 01, 2006 1:59 pm |
|
|
That change didn't fix my problem.
Here are my constants:
Code: | #define LM75_BASE_ADDRESS 72
#define LM75_TEMP_REG 0
#define LM75_CONFIG_REG 1
#define LM75_HYSTERESIS_REG 2
#define LM75_OVERTEMP_REG 3
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Aug 01, 2006 2:24 pm |
|
|
I think you need to show a small test program that shows how
you are calling the LM75 function with different addresses.
There's another bug in your program. This line right here
is not doing what you think it's doing.
Quote: | if (Data & 1024!=1) //temperature is positive |
The '!=' operator has high precedence than the '&' operator.
But even if you fix that, there's a still a problem. You're assuming
that the expression of (Data & 1024) is automatically converted
to a boolean (0 or 1), and it's not. You need to spend some
more time on your if() statement, and run some test programs
so you understand it.
One more thing. You're using decimal numbers throughout your code.
Decimal is not the best radix to use for register operations. The
registers are usually best thought of in terms of bitmasks or bitfields,
and for me, hex is the best. Other people might use binary notation.
Using decimal just doesn't give the best 'feel' for this type of coding. |
|
|
jleblanc
Joined: 17 May 2006 Posts: 9
|
|
Posted: Tue Aug 01, 2006 2:30 pm |
|
|
Quote: | You're assuming
that the expression of (Data & 1024) is automatically converted
to a boolean (0 or 1), and it's not |
I thought in C 0 is false and anything >0 is true?
Edit: Oops - I see the mistake in my if statement now.
I'll post a test program shortly. |
|
|
jleblanc
Joined: 17 May 2006 Posts: 9
|
|
Posted: Tue Aug 01, 2006 2:45 pm |
|
|
Here's a sample program:
Code: | #include <16F877A.h>
#device ICD=TRUE
#device adc=8
#fuses HS,WDT,NOPROTECT,NOLVP,PUT //No Watch Dog Timer
#FUSES
#use delay(clock=20000000)
#use i2c(Master,Fast,sda=PIN_B0,scl=PIN_B1)
#use rs232(DEBUGGER)
#define LM75_BASE_ADDRESS 72
#define LM75_TEMP_REG 0
#define LM75_CONFIG_REG 1
#define LM75_HYSTERESIS_REG 2
#define LM75_OVERTEMP_REG 3
double LM75_ReadTemperatureRegister(unsigned int pAddress)
{
unsigned long Data=0;
unsigned int Address=0;
unsigned int HiByte=0;
unsigned int LoByte=0;
double Temperature=0;
Address=LM75_BASE_ADDRESS | pAddress;
Address<<=1;
i2c_start();
i2c_write(Address);
i2c_write(LM75_TEMP_REG);
i2c_start();
i2c_write(Address | 1);
HiByte=i2c_read();
LoByte=i2c_read(0);
i2c_stop();
Data=make16(HiByte,LoByte);
Data>>=5; //lower 5 bits aren't used
//test the sign bit
if ((Data & 1024)==0) //temperature is positive, sign bit not set
{
Temperature=Data*0.125;
}
else //temperature is negative
{
Temperature=(0-Data)*0.125;
}
return(Temperature);
}
void main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(VREF_LOW|-2);
printf("Temp is %f(C)\r\n",LM75_ReadTemperatureRegister(0));
printf("Temp is %f(C)\r\n",LM75_ReadTemperatureRegister(1));
}
|
Note my #use i2c() statement is slightly different as this program I have been running on my breadboard/test platform. Although my project uses a different PIC microcontroller it experiences the same results.
All I change when running this program is the A0 pin on the LM75. If I ground it the first printf() prints a valid temperature while the second doesn't (expected, only one LM75 on the bus). If I make A0 high neither statement prints out a valid temperature (expected for the first printf(), not the second). |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Aug 01, 2006 3:07 pm |
|
|
The "%f" format specifier doesn't really work by itself, in many versions
of the compiler. You need to give it a width and a precision value.
Use something like "%3.2f" instead.
Also, you need a while(1); statement right before the closing brace of
main(). If you don't have it, the PIC will execute a hidden SLEEP
instruction and cut off the last two characters that are sent to the
hardware UART.
Also, the setup_vref() statement is wrong. There is no "-2" parameter.
The PCWH wizard has a bug. I would just delete that whole statement.
The Vref generator is disabled upon reset, anyway. |
|
|
jleblanc
Joined: 17 May 2006 Posts: 9
|
|
Posted: Tue Aug 01, 2006 3:20 pm |
|
|
Made those changes; same results.
Thanks a lot for the help/pointers by the way. It is much appreciated. |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Tue Aug 01, 2006 3:22 pm |
|
|
From looking at the spec. sheet it seems as though the base address(lowest) would be 0x90. You have assigned the variable, LM75_BASE_ADDRESS to a value of 72 which is HEX 0x48. The possible addresses are 0x90(A0,A1,A2=low), 0x92, 0x94, 0x96 and so on up to 0x9E. I have no idea what address you are sending to the routine as pADDRESS but make sure it ends up to be one of 0x90 to 0x9E.
Also, when declaring a double does that make it signed or unsigned. If you want to be returning a negative number you will want to make sure that it is signed.
Ronald |
|
|
jleblanc
Joined: 17 May 2006 Posts: 9
|
|
Posted: Tue Aug 01, 2006 3:29 pm |
|
|
Quote: | From looking at the spec. sheet it seems as though the base address(lowest) would be 0x90. You have assigned the variable, LM75_BASE_ADDRESS to a value of 72 which is HEX 0x48. The possible addresses are 0x90(A0,A1,A2=low), 0x92, 0x94, 0x96 and so on up to 0x9E. I have no idea what address you are sending to the routine as pADDRESS but make sure it ends up to be one of 0x90 to 0x9E. |
The base address actually is 72 decimal; however because the address is only 7 bits the last bit in the address transmission (LSB) is the write flag. You'll notice in my code that I shift my address variable left one bit to take this into account. So the actual addresses being transmitted are correct. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Aug 01, 2006 3:41 pm |
|
|
1. Remove the first LM75 chip from the bus, physically, so that only
the 2nd chip is present.
2. Hardcode your program to talk to the 2nd LM75 only.
Hardcode the addresses.
See if that works. |
|
|
jleblanc
Joined: 17 May 2006 Posts: 9
|
|
Posted: Tue Aug 01, 2006 4:06 pm |
|
|
Quote: | 1. Remove the first LM75 chip from the bus, physically, so that only
the 2nd chip is present. |
All of my tests have been conducted with a single LM75 which I just change pin A0 on. There have not been two LM75's on my test board simultaneously for any of my tests.
Quote: | 2. Hardcode your program to talk to the 2nd LM75 only.
Hardcode the addresses.
|
This fixed the problem but not directly. It still didn't work with hard coded addresses so I thought I'd better inspect my hardware again and make sure I didn't overlook something. Turns out I had. Pin placement created an island in my ground plane which was supposed to ground the A1 & A2 address pins leaving them floating. Added a jumper wire to actually ground them and now my code works fine.
So thanks for the help and for pointing out other mistakes in my code. |
|
|
claude Guest
|
building a project for loggin temperature |
Posted: Sun Nov 19, 2006 11:20 am |
|
|
How much distance can i get bi using a lm75 , i mean how far from the pic can i put it. I'm pplanning of making a 24 lm75 sensor logging pic program, that will outpus the temperatures over 232, and add the them into nice draw....is it possible to put them as far as 5 meters ? i have made this program , and it work, i managed to get the data on a lcd whit 1*16 characters.
My question is what must i change to be able to use more lm 75's by them adresses ? A0A1A2
#include <16F870.h>
#use delay(clock=4000000)
#fuses XT,NOWDT,PUT,NOPROTECT,BROWNOUT,NOLVP,NOCPD,NOWRT,NODEBUG
#define SDA_PIN PIN_C2 // i2c serial data in/out
#define SCL_PIN PIN_C3 // i2c serial clock
// Variabile pentru citire LM75
int8 dataH,dataL,current_temp, max_temp, min_temp;
int1 flgSign;
char txt;
#define p1 PIN_A3 //push button for temperature reset
#define p4 PIN_A0
#define buz PIN_A4 //buzzer
#define fan PIN_A5
#use i2c(master,sda=SDA_PIN, scl=SCL_PIN)
void i2c_init(void)
{
output_high( SCL_PIN );
output_high( SDA_PIN );
}
void lm75_start(void)
{
i2c_start();
i2c_write(0x90);
i2c_write(0x01); // Pointer Byte
i2c_write(0x00); // Configuration Byte (operating)
i2c_stop();
}
void lm75_setandread(void)
{
i2c_start();
i2c_write(0x90);
i2c_write(0x00); // Pointer Byte
i2c_start();
i2c_write(0x91);
dataH = i2c_read(); // with ACK
dataL = i2c_read(0); // with NOACK
// dataL &= 0x80; // // D6-D0 sunt undefined
i2c_stop();
}
#include <lcdme.c>
void sounds() {
output_low(buz);delay_ms(20);
output_high(buz);delay_ms(20);
output_low(buz);delay_ms(30);
output_high(buz);delay_ms(30);
output_low(buz);delay_ms(40);
output_high(buz);delay_ms(40);
output_low(buz);delay_ms(50);
output_high(buz);delay_ms(50);
output_low(fan);
}
void reset_temp() {
current_temp = dataH;
min_temp=current_temp;
max_temp=current_temp;
}
main() {
i2c_init();
delay_ms( 10 );
lcd_init();
reset_temp();
txt=223;
while(1)
{
lm75_start();
delay_ms( 30 );
// lm75_read();
lm75_setandread();
// lm75_shutdown();
delay_ms( 100 );
// Stabileste valoarea/semnul temperaturii (in 0,5 grade Celsius)
flgSign = 0;
if( bit_test( dataH, 7 ) ){ // semn negativ (bit-ul 7 setat)
flgSign = 1;
dataH = ( 0xFF - dataH + 1 );
}
dataH = ( dataH <<1>max_temp) max_temp=current_temp;
else if(current_temp<min_temp>=27) sounds();
else {output_high(buz);output_high(fan);}
lcd_gotoxy(1,1);
printf(lcd_putc,"%u %cC" ,min_temp,txt);
lcd_gotoxy(6,1);
printf(lcd_putc,">%u" ,dataH);
lcd_gotoxy(1,2);
printf(lcd_putc,"< %u %cC" ,max_temp,txt);
if (!input(p4)) {lcd_gotoxy(1,1);printf(lcd_putc, "Claudiu ");
lcd_gotoxy(1,2);printf(lcd_putc, "Godinel ");
output_high(buz);}
delay_ms(250);
}} |
|
|
godinel claudiu Guest
|
a program to talk to several lm 75's |
Posted: Wed Mar 21, 2007 1:17 am |
|
|
#include <16F870.h>
#use delay(clock=4000000)
#fuses XT,NOWDT,PUT,NOPROTECT,BROWNOUT,NOLVP,NOCPD,NOWRT,NODEBUG
#define SDA_PIN PIN_C2 // i2c serial data in/out
#define SCL_PIN PIN_C3 // i2c serial clock
#define p1 PIN_A3
#define LM75_WRITE1 0x90 // 1001 0000
#define LM75_READ1 0x91 // 1001 0001
#define LM75_WRITE2 0x9e // 1001 1110
#define LM75_READ2 0x9f // 1001 1111
#use i2c(master,sda=SDA_PIN, scl=SCL_PIN)
int8 dataH,dataL,temp,senz,x;
int1 flgSign;
char grad;
void i2c_init(void)
{
output_high( SCL_PIN );
output_high( SDA_PIN );
}
void lm75_start(int8 x)
{
i2c_start();
if (x==1) i2c_write(LM75_WRITE1);
else i2c_write(LM75_WRITE2);
i2c_write(0x01); // Pointer Byte
i2c_write(0x00); // Configuration Byte (operating)
i2c_stop();
}
void lm75_setandread(int8 x)
{
i2c_start();
if (x==1) i2c_write(LM75_WRITE1);
else i2c_write(LM75_WRITE2);
i2c_write(0x00); // Pointer Byte
i2c_start();
if (x==1) i2c_write(LM75_READ1);
else i2c_write(LM75_READ2);
dataH = i2c_read(); // with ACK
dataL = i2c_read(0); // with NOACK
i2c_stop();
}
#include <lcdme.c>
main() {
i2c_init();
delay_ms( 10 );
lcd_init();
senz=1;
grad=223;
while(1)
{
lcd_gotoxy(1,1);
printf(lcd_putc,"Senz");
lcd_gotoxy(6,1);
printf(lcd_putc,"%u =",senz);
lm75_start(senz);
delay_ms( 30 );
lm75_setandread(senz);
//lm75_shutdown();
delay_ms( 100 );
// Stabileste valoarea/semnul temperaturii (in 0,5 grade Celsius)
flgSign = 0;
if( bit_test( dataH, 7 ) ){ // semn negativ (bit-ul 7 setat)
flgSign = 1;
dataH = ( 0xFF - dataH + 1 );
}
dataH = ( dataH << 1 );
if( bit_test( dataL, 7 ) ) // 0,5 grade (bit-ul 7 setat)
dataH |= 0x01;
//facut de Godinel claudiu
// Ajusteaza valoarea temperaturii (cu +2 grade) (4 unitati de 0,5 grade)
if (senz==1) dataH -= 25 ;
if (senz==2) dataH -= 33 ;
dataL += 128 ;
temp=dataH;
lcd_gotoxy(1,2);
printf(lcd_putc,"Tmp");
lcd_gotoxy(5,2);
printf(lcd_putc,"%u" ,dataH);
lcd_gotoxy(7,2);
printf(lcd_putc,"%cC",grad);
if (!input(p1)) {senz=senz+1; if(senz==3) senz=1;}
delay_ms(100);
//if (!input(p4)) {lcd_gotoxy(1,1);printf(lcd_putc, "Claudiu ");
//lcd_gotoxy(1,2);printf(lcd_putc, "Godinel ");
//output_high(buz);}
}} |
|
|
|
|
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
|