Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[PIC] Help reading data from MCP9808 with pic12f683 through I2C bus

Status
Not open for further replies.

bgdev

Newbie level 1
Joined
Feb 2, 2015
Messages
1
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
9
Hi I'm trying to read the temperature data from a sensor MCP9808 with a PIC12F683 through the i2c bus and then store it into the pic internal eeprom, working with mplab and XC8 C compiler.
From the MCP9808 datasheet, these are the steps:

Code:
i2c_start(); // send START command
i2c_write (AddressByte & 0xFE); //WRITE Command (see Section 4.1.4 “Address Byte”) also, make sure bit 0 is cleared ‘0’
i2c_write(0x05); // Write TA Register Address
i2c_start(); //Repeat START
i2c_write(AddressByte | 0x01); // READ Command (see Section 4.1.4 “Address Byte”) also, make sure bit 0 is Set ‘1’
UpperByte = i2c_read(ACK); // READ 8 bits and Send ACK bit
LowerByte = i2c_read(NAK); // READ 8 bits and Send NAK bit
i2c_stop(); // send STOP command

I have found a PIC12F675 bit banging library that should be fine for my purpose.

This is my code:
Code:
[B]Includes.h[/B]
#ifndef __INCLUDES_H
#define __INCLUDES_H

// Define CPU Frequency
// This must be defined, if __delay_ms()
// or __delay_us() functions are used in the code
#define _XTAL_FREQ 4000000     // Hz

// Include files
#include <xc.h>         /* XC8 General Include File */
#include <stdint.h>        /* For uint8_t definition */
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>       /* For true/false definition */
#include <htc.h>
#include "I2C.h"

#endif

[B]I2C.h[/B]
#ifndef __I2C_H
#define __I2C_H

// Define i2c pins
#define SDA			GP4				// Data pin for i2c
#define SCK			GP5				// Clock pin for i2c
#define SDA_DIR		TRISIO4			// Data pin direction
#define SCK_DIR		TRISIO5			// Clock pin direction

#define DataPinADCMask		ANS3	// It is attached on GP4(AN3) pin
#define ClockPinADCMask		ANS3	// It is not attached on any ADC pin

// Define i2c speed
#define I2C_SPEED	1				// kbps
#define HalfBitDelay 500/I2C_SPEED	// usec

// Define macros
#define Set_SDA_Low		SDA_DIR = 0
#define Set_SDA_High	SDA_DIR = 1
#define Set_SCK_Low		SCK_DIR = 0
#define Set_SCK_High	SCK_DIR = 1

//Function Declarations
void InitI2C(void);
void I2C_Start(void);
void I2C_ReStart(void);
void I2C_Stop(void);
void I2C_Send_ACK(void);
void I2C_Send_NACK(void);
bit  I2C_Write_Byte(unsigned char);
unsigned char I2C_Read_Byte(void);

#endif

[B]I2C.c[/B]
#include "Includes.h"



// Function Purpose: Set initial values of SCK and SDA pins
void InitI2C(void)
{
	DataPinADCMask  = 1;	// Make analog output
	ClockPinADCMask = 1;	// Make analog output

	// Make SDA and SCK pins input initially
	SDA_DIR = 1;
	SCK_DIR = 1;

	// Write zero in output register of SDA and SCK pin
	SDA = 0;
	SCK = 0;
}


// Function Purpose: I2C_Start sends start bit sequence
void I2C_Start(void)
{
	SDA = 0;	// Write zero in output register
	SCK = 0;	// of SDA and SCK pin

	Set_SCK_High;				// Make SCK pin high
	Set_SDA_High;				// Make SDA pin High
	__delay_us(HalfBitDelay);	// Half bit delay
	Set_SDA_Low;				// Make SDA Low
	__delay_us(HalfBitDelay);	// Half bit delay
}


// Function Purpose: I2C_ReStart sends start bit sequence
void I2C_ReStart(void)
{
	Set_SCK_Low;				// Make SCK pin low

	__delay_us(HalfBitDelay/2);	// Data pin should change it's value,
								// when it is confirm that SCK is low
	Set_SDA_High;				// Make SDA pin High

	__delay_us(HalfBitDelay/2);	// 1/4 bit delay
	Set_SCK_High;				// Make SCK pin high
	__delay_us(HalfBitDelay/2);	// 1/4 bit delay
	Set_SDA_Low;				// Make SDA Low
	__delay_us(HalfBitDelay/2);	// 1/4 bit delay
}


//Function : I2C_Stop sends stop bit sequence
void I2C_Stop(void)
{
	Set_SCK_Low;				// Make SCK pin low

	__delay_us(HalfBitDelay/2);	// Data pin should change it's value,
								// when it is confirm that SCK is low
	Set_SDA_Low;				// Make SDA pin low

	__delay_us(HalfBitDelay/2);	// 1/4 bit delay
	Set_SCK_High;				// Make SCK pin high
	__delay_us(HalfBitDelay/2);	// 1/4 bit delay
	Set_SDA_High;				// Make SDA high
	__delay_us(HalfBitDelay/2);	// 1/4 bit delay
}



//Function : I2C_Send_ACK sends ACK bit sequence
void I2C_Send_ACK(void)
{
	Set_SCK_Low;				// Make SCK pin low
	__delay_us(HalfBitDelay/2);	// Data pin should change it's value,
								// when it is confirm that SCK is low
	Set_SDA_Low;				// Make SDA Low
	__delay_us(HalfBitDelay/2);	// 1/4 bit delay
	Set_SCK_High;				// Make SCK pin high
	__delay_us(HalfBitDelay);	// Half bit delay
}


//Function : I2C_Send_NACK sends NACK bit sequence
void I2C_Send_NACK(void)
{
	Set_SCK_Low;				// Make SCK pin low
	__delay_us(HalfBitDelay/2);	// Data pin should change it's value,
								// when it is confirm that SCK is low
	Set_SDA_High;				// Make SDA high
	__delay_us(HalfBitDelay/2);	// 1/4 bit delay
	Set_SCK_High;				// Make SCK pin high
	__delay_us(HalfBitDelay);	// Half bit delay
}


// Function Purpose: I2C_Write_Byte transfers one byte
bit I2C_Write_Byte(unsigned char Byte)
{
	static bit ACK = 0;

	unsigned char i;		// Variable to be used in for loop

	for(i=0;i<8;i++)		// Repeat for every bit
	{
		Set_SCK_Low;		// Make SCK pin low

		__delay_us(HalfBitDelay/2);	// Data pin should change it's value,
									// when it is confirm that SCK is low

		if((Byte<<i)&0x80)  // Place data bit value on SDA pin
			Set_SDA_High;	// If bit is high, make SDA high
		else				// Data is transferred MSB first
			Set_SDA_Low;	// If bit is low, make SDA low

		__delay_us(HalfBitDelay/2);	// Toggle SCK pin
		Set_SCK_High;				// So that slave can
		__delay_us(HalfBitDelay);	// latch data bit
    }

	// Get ACK from slave
	Set_SCK_Low;
    Set_SDA_High;
    __delay_us(HalfBitDelay);
    Set_SCK_High;
    __delay_us(HalfBitDelay);

	DataPinADCMask = 0;		// Make digital input
	ACK = SDA;				// Read data pin status
	DataPinADCMask = 1;		// Make analog output

	return ACK;
}


// Function Purpose: I2C_Read_Byte reads one byte
unsigned char I2C_Read_Byte(void)
{
	unsigned char i, RxData = 0;

	for(i=0;i<8;i++)
	{
		Set_SCK_Low;					// Make SCK pin low
		Set_SDA_High;					// Don't drive SDA
		__delay_us(HalfBitDelay);		// Half bit delay
		Set_SCK_High;					// Make SCK pin high
		__delay_us(HalfBitDelay/2);		// 1/4 bit delay
		DataPinADCMask = 0;				// Make digital input
		RxData = RxData|(SDA<<(7-i));	// Captured received bit
		DataPinADCMask = 1;				// Make analog output
		__delay_us(HalfBitDelay/2);		// 1/4 bit delay
	}

    return RxData;						// Return received byte
}

[B]main.c[/B]
#include "Includes.h"


// CONFIG
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown Out Detect (BOR enabled)
#pragma config IESO = ON        // Internal External Switchover bit (Internal External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)

void InitCCT(void)
{
	ANSEL  = 0x00;       // Set ports as digital I/O, not analog input
	ADCON0 = 0x00;		 // Shut off the A/D Converter
	CMCON0 = 0x07;		 // Shut off the Comparator
	VRCON  = 0x00;	     // Shut off the Voltage Reference
        TRISIO = 0x00;       // GP3 input, rest all output
	GPIO   = 0x00;       // Make all pins 0
}

int main(int argc, char** argv) {
        unsigned char msb;
        unsigned char lsb;

	InitCCT();	// Turn off ADC and comparator to make pins digital IOs
	InitI2C();	// Initialize i2c pins

        __delay_ms(100);
						// Send stop bit on i2c
        I2C_Start();				// Send start bit on i2c
        I2C_Write_Byte((unsigned char)0x18 & 0xFE);
        I2C_Write_Byte((unsigned char)0x05);
        I2C_Start();
        I2C_Write_Byte((unsigned char)0x18 | 0x01);		// Send 0xA0 on i2c
        msb = I2C_Read_Byte();	// Read value from i2c
        I2C_Send_ACK();  // Send ACK bit on i2c
        lsb = I2C_Read_Byte();	// Read value from i2c
        I2C_Send_NACK();  // Send ACK bit on i2c
        I2C_Stop();
        eeprom_write(0x00, msb);
        eeprom_write(0x01, lsb);
        while(1){
        }
}

msb and lsb are always 0x00, I really can not find the problem, hope someone can help.
thanks
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top