Ir ao conteúdo
  • Cadastre-se

PIC Programação I2C para PIC18f4685


Posts recomendados

Sou iniciante no fórum, caso haja algum erro, me perdoem, irei arrumar.

 

Pessoal, me deparei com a seguinte questão, necessito usar um sensor de temperatura infravermelho junto de um PIC18F4685. Através do arduino (com bibliotecas) encontrei diversos exemplos, tanto com I2C ou usando a biblioteca do sensor. O problema é que preciso "passar" esse código do arduino para o PIC18F4586, porém ainda sou iniciante e estou com alguns problemas para entender como funciona etc.

O código usado em I2C no arduino foi o seguinte:

 

/**
 * Infrared Thermometer MLX90614
 * by Jaime Patarroyo
 * based on 'Is it hot? Arduino + MLX90614 IR Thermometer' by bildr.blog
 * 
 * Returns the temperature in Celcius and Fahrenheit from a MLX90614 
 * Infrared Thermometer, connected to the TWI/I²C pins (on the Wiring v1 
 * board 0 (SCL) and 1 (SDA) and on Wiring S board 8 (SCL) and 9 (SDA)).
 */

#include <i2cmaster.h>


int deviceAddress = 0x5A<<1;    // From MLX906114 datasheet's, 0x5A is 
                                // the default address for I²C communication.
                                // Shift the address 1 bit right, the 
                                // I²Cmaster library only needs the 7 most 
                                // significant bits for the address.

float celcius = 0;              // Variable to hold temperature in Celcius.
float fahrenheit = 0;           // Variable to hold temperature in Fahrenheit.

void setup() {
  Serial.begin(9600);           // Start serial communication at 9600bps.

  i2c_init();                               // Initialise the i2c bus.
  PORTC = (1 << PORTC4) | (1 << PORTC5);    // Enable pullups.
}

void loop() {
  celcius = temperatureCelcius(deviceAddress);  // Read's data from MLX90614
                                                // with the given address,
                                                // transform's it into
                                                // temperature in Celcius and
                                                // store's it in the Celcius
                                                // variable.
  
  fahrenheit = (celcius*1.8) + 32;     // Converts celcius into Fahrenheit 
                                       // and stores in Fahrenheit variable.

  Serial.print("Celcius: ");           // Prints both readings in the Serial 
  Serial.println(celcius);             // port.
  Serial.print("Fahrenheit: ");
  Serial.println(fahrenheit);

  delay(1000);                         // Wait a second before printing again.
}

float temperatureCelcius(int address) {
  int dev = address;
  int data_low = 0;
  int data_high = 0;
  int pec = 0;

  // Write
  i2c_start_wait(dev+I2C_WRITE);
  i2c_write(0x07);

  // Read
  i2c_rep_start(dev+I2C_READ);
  data_low = i2c_readAck();       // Read 1 byte and then send ack.
  data_high = i2c_readAck();      // Read 1 byte and then send ack.
  pec = i2c_readNak();
  i2c_stop();

  // This converts high and low bytes together and processes temperature, 
  // MSB is a error bit and is ignored for temps.
  double tempFactor = 0.02;       // 0.02 degrees per LSB (measurement 
                                  // resolution of the MLX90614).
  double tempData = 0x0000;       // Zero out the data
  int frac;                       // Data past the decimal point

  // This masks off the error bit of the high byte, then moves it left 
  // 8 bits and adds the low byte.
  tempData = (double)(((data_high & 0x007F) << 8) + data_low);
  tempData = (tempData * tempFactor)-0.01;
  float celcius = tempData - 273.15;
  
  // Returns temperature un Celcius.
  return celcius;
}

Acredito que a partir dessa base consigo com alguma ajuda a programar para o PIC. Agradeço se alguém puder me dar umas dicas e quais o detalhes preciso me atentar.

O sensor utilizado é o MLX90614 (Datasheet em PDF). No datasheet tem alguns detalhes para a comunicação como endereçamento e tal, mas como usar com o I2C? Acabei não compreendendo da melhor forma o datasheet.

 

Agradeço desde já quem puder me dar uma luz, e em caso de alguma infração, assim que avisado eu arrumo (li as regras, mas mesmo assim pode acontecer).

MLX90614_rev001.pdf

Link para o comentário
Compartilhar em outros sites

  • Membro VIP

Amigo você primeiro deve saber como seu pic trata e conversa via I2c. Basicamente é só setar e ler registros. Depois disso, tudo que você precisa está aqui:

2 horas atrás, antonioosergio disse:

// Write

i2c_start_wait(dev+I2C_WRITE);

i2c_write(0x07);

// Read

i2c_rep_start(dev+I2C_READ);

data_low = i2c_readAck();

// Read 1 byte and then send ack.

data_high = i2c_readAck();

// Read 1 byte and then send ack.

pec = i2c_readNak();

i2c_stop();

 

Link para o comentário
Compartilhar em outros sites

  • 2 semanas depois...

Sobre isso, a comunicação entre I2C do PIC18f4685, é dessa maneira?

 I2C_Init(100000);         // frequencia de clock do barramento I2C (CONSULTAR DATASHEET DO CHIP PARA SABER SUA FREQUENCIA MÁXIMA)
                           //esta função só precisa ser inicializada somente 1 unica vez no programa

 I2C_Start();              // start no barramento i2c
 I2C_Wr(0xA0);             // endereço da memória no barramento + comando de escrita(0)
 I2C_Wr(0x00);             // endereço da eerprom onde será salvo o dado
 I2C_Wr(variavel_A);       // grava a variável A no endereço 00 da memória serial
 I2C_Wr(variavel_B);       // grava a variável B no endereço 01 da memória serial
 I2C_Wr(variavel_C);       // grava a variável C no endereço 02 da memória serial
 I2C_Wr(variavel_D);       // grava a variável D no endereço 03 da memória serial
 I2C_Stop();               // condição de stop na comunicação i2c

 

Link para o comentário
Compartilhar em outros sites

  • Membro VIP

Estás no caminho certo amigo. O que te falta agora é dar uma olhadela no d.s. da sua eeprom pra ver como e se é feita a gravação em sequência. Me lembro de ter visto que em alguma é possível gravar/ler blocos sequenciais de 64 bytes.

E sim, pode ser exatamente como descreveste acima. Confirme com algum simulador p.ex. proteus.

abç

Link para o comentário
Compartilhar em outros sites

Em 07/02/2019 às 07:52, Isadora Ferraz disse:

Estás no caminho certo amigo. O que te falta agora é dar uma olhadela no d.s. da sua eeprom pra ver como e se é feita a gravação em sequência. Me lembro de ter visto que em alguma é possível gravar/ler blocos sequenciais de 64 bytes.

E sim, pode ser exatamente como descreveste acima. Confirme com algum simulador p.ex. proteus.

abç

Isadora, andei dando uma pesquisada, e encontrei alguns programas que poderiam me servi como base. Partindo do príncipio deles, queria saber qual o problema do mesmo, pois não consigo simular no proteus (não tem o sensor no proteus), e utilizando direto no pic ainda não está funcionando.

const  _IR_THERMO_ADDR = 0x5A;
const  _AMB_TEMP = 0x06;
const  _OBJ_TEMP = 0x07;

char Temp;

char ReadSensor(char Temp_Source){
unsigned int Temp_var;
  I2C1_Start();
  I2C1_Wr(_IR_THERMO_ADDR << 1);
  I2C1_Wr(Temp_Source);
  I2C1_Repeated_Start();
  I2C1_Wr(_IR_THERMO_ADDR << 1);
  Temp_var = I2C1_Rd(0);
  Temp_var = (I2C1_Rd(0) << 8) + Temp_var;
  I2C1_Stop();
   return Temp_var;
}

  void main(){
  ADCON1 |= 0x0F;
  CMCON |= 0x07;
  TRISB    = 0xFC;                          //Configura o RB0 como saída
  PORTB    = 0xFC;                          //Inicializa o PORTB (RB0 em LOW)

  I2C1_Init(50000);
  Delay_ms(1000);

   while(1){
   Temp = ReadSensor(_AMB_TEMP);
    Temp = (Temp * 0.02) - 273.15;
    if( Temp>25)
    {
        LATB0_bit = 0x01; //RB0 em High
    }
    else  {
        LATB0_bit = 0x00; //RB0 em low
           }

    Temp = ReadSensor(_OBJ_TEMP); //hata veriyor
    Temp = (Temp * 0.02) - 273.15;
    if ( Temp>40)
    {
         LATB1_bit = 0x01; //RB1 em High
    }
    
    else    {
        LATB1_bit = 0x00; //RB1 em low
}   
}
}

O que estou fazendo de errado?

Na parte do I2C eu não entendi exatamente o que ocorre, usei do código de exemplo.

 

O código exemplo utilizado foi este:

 


sbit LCD_RS at RD4_bit;
sbit LCD_EN at RD5_bit;
sbit LCD_D4 at RD0_bit;
sbit LCD_D5 at RD1_bit;
sbit LCD_D6 at RD2_bit;
sbit LCD_D7 at RD3_bit;

sbit LCD_RS_Direction at TRISD4_bit;
sbit LCD_EN_Direction at TRISD5_bit;
sbit LCD_D4_Direction at TRISD0_bit;
sbit LCD_D5_Direction at TRISD1_bit;
sbit LCD_D6_Direction at TRISD2_bit;
sbit LCD_D7_Direction at TRISD3_bit;




const  _IR_THERMO_ADDR = 0x5A;
const  _AMB_TEMP = 0x06;
const  _OBJ_TEMP = 0x07;

char Temp;

char ReadSensor(char Temp_Source){
unsigned int Temp_var;
  I2C1_Start();
  I2C1_Wr(_IR_THERMO_ADDR << 1);
  I2C1_Wr(Temp_Source);
  I2C1_Repeated_Start();
  I2C1_Wr(_IR_THERMO_ADDR << 1);
  Temp_var = I2C1_Rd(0);
  Temp_var = (I2C1_Rd(0) << 8) + Temp_var;
  I2C1_Stop();
   return Temp_var;
}
void Display_Temperature(char Temp_Source, float temperature){
char text[15];
FloatToStr(temperature, text);
  if (text[1] == '.')
  text[4] = 0;
    if (text[2] == '.')
    text[5] = 0;
  if (text[3] == '.')
    text[6] = 0;
strcat(text, "°C");
if (Temp_Source == _AMB_TEMP)
Lcd_Out(2, 1, text);
  if (Temp_Source == _OBJ_TEMP)
    Lcd_Out(2, 10, text);

     }



  void main(){
    ADCON1 |= 0x0F;
  CMCON |= 0x07;

  Lcd_Init();
  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Cmd(_LCD_CURSOR_OFF);
  Lcd_Out(1,1,"Initialising I2C");

  I2C1_Init(50000);
  Delay_ms(1000);
  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,"Init OK");
  Delay_ms(1000);

  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,"Amb. t: ");
  Lcd_Out(1,9," Obj. t:");

   while(1){
   Temp = ReadSensor(_AMB_TEMP); /* kod bu satira kadar derleniyor ama bu satira gelince hata veriyor bu kismi fonksiyon alarak yazdim ama degisen bir sey olmadi arkadasimin bilgisayarinda derleyince kodu demo hatasi verdi microc'nin demo sürümünden kaynakli oldugunu düsünüyorum bi türlü main fonkiyonun içide bu kismi çalistiramiyorum   */
    Temp = (Temp * 0.02) - 273.15;
    Display_Temperature(_AMB_TEMP, Temp); //hata veriyor bu satirlari silince sorun olmuyor


    Temp = ReadSensor(_OBJ_TEMP); //hata veriyor
    Temp = (Temp * 0.02) - 273.15;
    Display_Temperature(_OBJ_TEMP, Temp); //hata veriyor

    Delay_ms(500);
   }

  }

 

Link para o comentário
Compartilhar em outros sites

  • Membro VIP

Perdão amigo, não havia percebido que era sensor. Achei que era eeprom. Faz assim... no proteus tem eeprom 24c02 p.ex. Tenta conversar com ela pra ver se a linha i2c do mc está operando a contento. Depois uma lidinha no datasheet do MLX90614 deve te elucidar muito. E complemente com google MLX90614 c code example pra arrematar a questão... bem... provavelmente já fez isso.

 

Não vi o d.s. do sensor mas verifique se ele tem algum pino de endereço físico (a exemplo da eeprom) e se este está correto, alimentação,pullup e etc. Ou seja... verifique algo no seu hw pois penso que o sw não foge muito daquele que você achou...

Link para o comentário
Compartilhar em outros sites

Em 08/02/2019 às 19:59, Isadora Ferraz disse:

Perdão amigo, não havia percebido que era sensor. Achei que era eeprom. Faz assim... no proteus tem eeprom 24c02 p.ex. Tenta conversar com ela pra ver se a linha i2c do mc está operando a contento. Depois uma lidinha no datasheet do MLX90614 deve te elucidar muito. E complemente com google MLX90614 c code example pra arrematar a questão... bem... provavelmente já fez isso.

 

Não vi o d.s. do sensor mas verifique se ele tem algum pino de endereço físico (a exemplo da eeprom) e se este está correto, alimentação,pullup e etc. Ou seja... verifique algo no seu hw pois penso que o sw não foge muito daquele que você achou...

 

Depois do que você disse, consegui realizar a leitura de um valor pelo lcd, o problema é que o valor está errado, aparece 134,99ºC, (Temperatura ambiente) e o a variação do sensor da temperatura do objeto é de apenas 3ºC (varia de 135°C até 133ºC), sim diminui.

O que pode estar havendo de errado? No arduino o sensor le corretamente.

 

/* Programação PIC18F4685 - TESTE Mack1 I2C
Programção para leitura sensor Temperatura CVT

Sensor: MLX90614
MCU: PIC18F4685

Endereçamento:
Sensor: 0x5A
Temperatura Ambiente: 0x06
Temperatura Objeto: 0x07

ProcoBaja 2019 - Campeonato Nacional
Equipe Eletrônica

*/

#include<stdio.h>
#include<string.h>
#include<math.h>

const sensor = 0x5A;
const ambiente = 0x06;
const sensorbin = 0x5B;
const objeto = 0x07;
char Temp1, Temp2, Temp3, Temp4;

//Função auxiliar conversão binário em hexadecimal

//Protocolo de comunicação I2C (Leitura do sensor)

char leiturasensor(char temp_source){
unsigned int Temp_var, Temp_var1;

I2C1_Start();                   // start no barramento i2c
I2C1_Wr(sensor<<1);                // endereço da memória no barramento + comando de escrita(0)
I2C1_Wr(temp_source);              // endereço da eeprom onde será lido o byte
I2C1_Repeated_Start();          // re-start no barramento
I2C1_Wr(sensor<<1);             // endereço da memória no barramento + comando de leitura(1)
Temp_var = I2C1_Rd(0);          // Leitura do endereço
Temp_var1 = (((I2C1_Rd(0) << 8)));  // Função para conversão de bit para decimal (Função auxiliar)
I2C1_Stop();                    // finaliza a comunicação i2c
return Temp_var1;
}

char leiturasensor2(char temp_source2){
unsigned int Temp_var2, Temp_var3;

I2C1_Start();                   // start no barramento i2c
I2C1_Wr(sensor<<1);                // endereço da memória no barramento + comando de escrita(0)
I2C1_Wr(temp_source2);              // endereço da eeprom onde será lido o byte
I2C1_Repeated_Start();          // re-start no barramento
I2C1_Wr(sensor<<1);             // endereço da memória no barramento + comando de leitura(1)
Temp_var2 = I2C1_Rd(0);          // Leitura do endereço
Temp_var3 = (((I2C1_Rd(0) << 8)));  // Função para conversão de bit para decimal (Função auxiliar)
I2C1_Stop();                    // finaliza a comunicação i2c
return Temp_var3;
}

void main(){

     TRISC    = 0xFE;                          //Configura o RC como saída
     PORTC    = 0xFE;                          //Inicializa o PORTC (RC em LOW)
     TRISC    = 0xFD;                          //Configura o RC como saída
     PORTC    = 0xFD;                          //Inicializa o PORTC (RC em LOW)
     ADCON1 = 0x0F;
     CMCON  = 0x07;
     I2C1_Init(50000);
     Delay_ms(100);

     while(1){
              Temp1 = leiturasensor(objeto);
              Temp2 = (Temp1*0.02)-273.15;
              if (Temp2>134)
              {
                 LATC0_bit=0x01;
              }
              else
              {
                  LATC0_bit=0x00;
              }
              
              }
     while(1){
              Temp3 = leiturasensor2(objeto);
              Temp4 = (Temp1*0.02)-273.15;
              if (Temp4>134)
              {
                 LATC1_bit=0x01;
              }
              else
              {
                  LATC1_bit=0x00;
              }

              }
              
     }



     
     
     
  

Esse foi o último código de teste utilizado.
Nesse trecho que mudei, o que está acontecendo?

 

Temp_var1=(((I2C1_Rd(0) << 8)+Temp_var));

 

Link para o comentário
Compartilhar em outros sites

  • Membro VIP
1 hora atrás, antonioosergio disse:

Nesse trecho que mudei, o que está acontecendo?

este trecho você monta a unsigned int Temp_var1 com o MSB como sendo a leitura i2c

Não vi no seu fonte onde e quando você mostra a temperatura.

 

E...

1 hora atrás, antonioosergio disse:

Temp4 = (Temp1*0.02)-273.15;

temp's sendo char, não dá certo esta conta. Tente temp's com float. Vai desperdiçar recurso, mas fazer o quê... facilita pra mim não ter que te explicar como usar int

Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...