I2C read MCP9804

Go To Last Post
16 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

 

i have been trying to come up whit working I2C code for my atmega328 to read a temperature register on a MCP9804 temp sensor. I tried I2C library from Peter Fleury(tried TWITEST and I2CMASTER), but i could not make sense of it or get it to work. So i decided to go whit official at328p datasheet in which there is good explnanation of protocol and code and il ltry to bang together a working code, but i failed miserably couple of times. I read all the literature about TWCR. TWINT, TWDR, slave adresiing, read/write bits,.... but for the love of god, i cannot seem to be able to put it all togehter so it would work. So if some1 has a sample of code that knows it works on AVR for reading register on a I2C slave, please if you can share. Or any guide or tutorial site that i missed, please share.

This topic has a solution.

Last Edited: Fri. Aug 25, 2017 - 10:09 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

when looking for examples to learn from I always start with:  Google arduino MCP9804

it found 1280 results in 0.43 seconds!

 

Peter Fleury's code is pretty easy to use, and has example of talking to an I2C eeprom, post your code and someone will help you with where your stuck.

But an Arduino Uno is about as easy to get going as any....

 

Jim

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Atmel have App Notes on using the TWI ...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I agree setting up the TWI i narduino takes like 1 minute. I went through any app note icould find. Ill post code in couple of hours, for you to see if anyone can find the problem.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The MCP9804 looks very easy to use.   

 

Please post your code.   It is easier to learn from your own code.   (with advice about your errors)

 

You can write your code with proven libraries e.g. Wire.h or Fleury

Then everyone can reproduce your code even if they do not own your specific chip.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry for delayed response, i was swamped whit work.

 

Here is the code, i took from atmega328p datasheet.

#define F_CPU 2000000UL
#include <avr/io.h>
#include <util/delay.h>






int main(void){
	
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);   //Send start condition
while (!(TWCR & (1<<TWINT)));  //Wait for flag

TWDR = 0b0011001+0b00000001; //Temp sensor MCP9804 address, , SLA+R (slave add+read)
TWCR = (1<<TWINT) |(1<<TWEN);//Start transmission of address
while (!(TWCR & (1<<TWINT)));  //Wait for flag

TWDR = 0b00000101; //register on MCP9804 whit temperature
TWCR = (1<<TWINT) |(1<<TWEN);//Start transmission of register
while (!(TWCR & (1<<TWINT)));  //Wait for flag

char DATA = TWSR;		//Received data

//Send data via uart
while(1){
}
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Klemko wrote:
Here is the code

So the standard set of questions:

 

  1. What do you expect it do do?
     

     
  2. What does it actually do?
     

     
  3. Whet testing / debugging / investigation have you done to determine the problem?
    eg: have you stepped it in the debugger? have you looked at the lines on an oscilloscope?

     
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I expect it to read the data from temperature register on the MCP9804 and then transmit it via uart. I already got the uart working. 

 

It hangs when it gets to the part of getting into register on MCP9804.

 

No i have not yet checked whit osciloscope, im not at work, but i will be able to do that at tuesday.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Klemko wrote:

Here is the code,...

 

That's not all your code though is it? Or is it?

'This forum helps those who help themselves.'

 

pragmatic  adjective dealing with things sensibly and realistically in a way that is based on practical rather than theoretical consideration.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes it is, it is just a i2c test code. I removed the rest of it (analog read, timers, uarts,...) to jsut try to get this to work.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why introduce the "unknown" of writing your own code for this? Fleury's I2C code is known to work very well for all so it cuts one variable out of the loop. I would persevere with trying to get that to work. You said:

Klemko wrote:
but i could not make sense of it or get it to work.
Surely now, after trying your own code, the Felury code should be much more obvious to you? It will be doing the same things you have been trying yourself (but the difference is it is known to work!). Maybe show your test code where you tried to use Fleury?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would also advise Fleury.   But most importantly.   Use the return values from i2c_start().

 

Your error is glaringly obvious (to me).

You make no attempt to check error status.

 

This is like driving your car blindfolded.   It is quite possible that you follow the correct route and make a safe journey.    But it is a lot easier when you can see where the road junctions are,  and read the road signs.  

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Klemko wrote:

Yes it is, it is just a i2c test code.

 

But you aren't initialising the TWI module.

'This forum helps those who help themselves.'

 

pragmatic  adjective dealing with things sensibly and realistically in a way that is based on practical rather than theoretical consideration.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Atm i am trying this lib  https://github.com/g4lvanix/I2C-..., if this fails me i will give Fleurs another try.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes,  it looks a perfectly good library.   It supports all the Fleury functions (but only with the TWI hardware).    It has some extra useful functions.

 

The same advice applies:  Use the return value from i2c_start()

 

Post your complete "program" that uses whichever proven library you want.

We can advise on any problems with reference to your code and the chosen library.

 

David.

Last Edited: Fri. Aug 18, 2017 - 03:16 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks a lot to everyone for help. I got it working whit the above mention library. Below is the code to help anyone else, only thing missing is the math to change the binarys to actual temperature value. I did this by hand and it displays correct temperature, i only have to change it into c code to wrok :P

 

#ifndef F_CPU
#define F_CPU 2000000UL
#endif

#include <avr/io.h>
#include <util/delay.h>
#include <math.h>
#include <stdlib.h>

#define BAUD 9600UL



#include "i2c_master.h"

#define tmp_w	0b00110010				//Write
#define tmp_r	0b00110011				//Read

void Print_init(void);
int Print_uart (int pl);


int main(void){
	
	Print_init();
	i2c_init();
	
	
	i2c_start(tmp_w);					//Start write address
	i2c_write(0b00000101);				//Send ambient temperature register address
	i2c_stop();
	
	i2c_start(tmp_r);					//Start read address
	Print_uart(i2c_read_ack());		//Read first 8bits
	Print_uart(i2c_read_nack());	//Reads other 5 bits
	i2c_stop();
	
	while(1){
	}
	
	return 0;
}






void Print_init (void){
	int UBRRn = 12;

	UBRR0H = (UBRRn >> 8);
	UBRR0L = UBRRn;
	UCSR0B = (1 << TXEN0)| (1 << TXCIE0) | (1 << RXEN0) | (1 << RXCIE0);
	UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
	UCSR0A = (0 << U2X0);
}

int Print_uart (int pl){

	while (( UCSR0A & (1<<UDRE0))  == 0){};
	UDR0 = pl;

	return 0;
}