Acelerômetro MMA84X no PIC18F4550


#1

Olá tudo bem?

Eu comprei um acelerômetro que é comumente utilizado pra arduíno pra tentar usar no PIC e tenho algumas dúvidas!

Eu não encontrei em lugar algum alguém usando ele pra PIC, isso não quer dizer que não seja possível certo?

Pelo que eu entendi para utilizar esse acelerômetro é necessário os pinos SDA e SCL?
Como fazer para usar eles e como funcionam?
Alguém pode dar um help?

Att


#2

Ola! Geralmente o arduino tem bibliotecas prontas, já no PIC você mesmo vai ter que cria a sua, e exige muita experiencia de programação e conhecimentos de hardware do dispositivo que se vai controlar. Se você tem experiencia suficiente de programação de PIC comece lendo o datasheet do componente.


#3

Olá @al777 , as conexões SDA e SCL são portas usadas em conexões com barramento I2C (Inter-Integrated Circuit) e, com certeza, há uma implementação para PIC. Aqui há um tutorial de como trabalhar com I2C utilizando o MPLab.

Basicamente, pelo que me lembro, o dispositivo I2C tem um endereço único (que deve constar no datasheet do acelerômetro em questão) e ele é usado para fazer a conexão. Aqui há um documento em duas partes ensinando a utilizar dispositivos I2C com Arduino, apesar de se referir ao Arduino, o conceito de conexão, envio e recebimento, clock e etc. deve servir para você trabalhar no PIC e sua biblioteca I2C.

Qualquer dúvida, estamos a disposição.


#4

Olá, eu to lendo há alguns dias já hahaha
Obrigado por me responder!

Estou usando um PIC18F4550
http://ww1.microchip.com/downloads/en/DeviceDoc/39632e.pdf
e o acelerômetro MM845X: http://chiselapp.com/user/jschimpf/repository/MM8451/doc/tip/Docs/MMA8451Q.pdf

Já configurei as saídas direitinho (acredito eu) e to vendo no osciloscópio a comunicação.
Porém ao tentar escrever o valor no LCD, não aparece nada, isso implica que o PIC não tá lendo a informação ou que o acelerômetro não está enviando.

Eu acredito que não configurei o acel apropriadamente e por isso estou lendo mais.

No datasheet fala isso:

Single Byte Read
The MMA8451Q has an internal ADC that can sample, convert and return sensor data on request. The transmission of an
8-bit command begins on the falling edge of SCL. After the eight clock cycles are used to send the command, note that the data
returned is sent with the MSB first once the data is received. Figure 11 shows the timing diagram for the accelerometer 8-bit I2C
read operation. The Master (or MCU) transmits a start condition (ST) to the MMA8451Q, slave address ($1D), with the R/W bit
set to “0” for a write, and the MMA8451Q sends an acknowledgement. Then the Master (or MCU) transmits the address of the
register to read and the MMA8451Q sends an acknowledgement. The Master (or MCU) transmits a repeated start condition (SR)
and then addresses the MMA8451Q ($1D) with the R/W bit set to “1” for a read from the previously selected register. The Slave
then acknowledges and transmits the data from the requested register. The Master does not acknowledge (NAK) the transmitted
data, but transmits a stop condition to end the data transfer.

E foi o que eu tentei fazer:

I2C_Master_Start(); //Start condition
I2C_Master_Write(0b38); //7 bit address + Read
I2C_Master_Write(0b01); //7 bit address + Read
I2C_Master_RepeatedStart();
I2C_Master_Write(0b39); //7 bit address + Read
val = I2C_Master_Read(0); //Read + Acknowledge
I2C_Master_Stop(); //Stop condition

Mas não está rolando infelizmente.
Alguma dica?


#include <p18f4550.h>
#include “lcd.c”
#include <delay.h>
#include <stdio.h>

unsigned int val=0;
unsigned int vez=0;

#define _XTAL_FREQ 20000000

void I2C_Master_Init(const unsigned long c)
{
SSPCON1 = 0b00101000;
SSPCON2 = 0;
SSPADD = (_XTAL_FREQ/(4*c))-1;
SSPSTAT = 0;
TRISB0 = 1; //Setting as input as given in datasheet
TRISB1 = 1; //Setting as input as given in datasheet
}

void I2C_Master_Wait()
{
while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
}

void I2C_Master_Start()
{
I2C_Master_Wait();
SEN = 1;
}

void I2C_Master_RepeatedStart()
{
I2C_Master_Wait();
RSEN = 1;
}

void I2C_Master_Stop()
{
I2C_Master_Wait();
PEN = 1;
}

void I2C_Master_Write(unsigned d)
{
I2C_Master_Wait();
SSPBUF = d;
}

unsigned short I2C_Master_Read(unsigned short a)
{
unsigned short temp;
I2C_Master_Wait();
RCEN = 1;
I2C_Master_Wait();
temp = SSPBUF;
I2C_Master_Wait();
ACKDT = (a); //0:1;
ACKEN = 1;
return temp;
}

void main()
{

I2C_Master_Init(100000); //Initialize I2C Master with 100KHz clock

TRISD=0; // Configura como saída
TRISC=0; // Configura como saída
TRISE=0; // Configura como saída

LATC=0; // Seta pra zero
LATD=0; // Seta pra zero
LATE=0; // Seta pra zero

lcd_init();
lcd_clear();

lcd_goto(0,0);
lcd_puts(" TESTE: ");

while(1)
{

PORTDbits.RD2 = 1; // Liga pra ver se o código travou (cria PWM)

I2C_Master_Start(); //Start condition
I2C_Master_Write(0b38); //7 bit address + Read
I2C_Master_Write(0b01); //7 bit address + Read
I2C_Master_RepeatedStart();
I2C_Master_Write(0b39); //7 bit address + Read
val = I2C_Master_Read(0); //Read + Acknowledge
I2C_Master_Stop(); //Stop condition

lcd_goto(2,5);

printf ("%u", val);
delay_ms(1000);

PORTDbits.RD2 = 0; // Desliga pra ver se o código travou (cria PWM)
delay_ms(1000);

}
}


#5

Olá, estou com pressa no momento e não li o código inteiro mas, do que eu vi, de cara essa notação está incorreta: “0b38”.

“0b” indica que você está trabalhando com dados binários, logo não pode existir 0b38, mas sim algo do tipo 0b11001010, só para exemplificar. Pode ser que este não seja o único erro do teu programa, mas isto me saltou imediatamente aos olhos.


#6

Ops, peço desculpas.

Eu realmente estava usando em bits anteriormente, mas me confundi ao modificar pra hexa pra “poupar” 10 segundos seus porque sabia que você ia olhar o datasheet e os registradores.

O código “correto” é esse:

I2C_Master_Start(); //Start condition
I2C_Master_Write(0x38); //7 bit address + Read
I2C_Master_Write(0x01); //7 bit address + Read
I2C_Master_RepeatedStart();
I2C_Master_Write(0x39); //7 bit address + Read
val = I2C_Master_Read(0); //Read + Acknowledge
I2C_Master_Stop(); //Stop condition

Falta agora o resto haha

Abraços


#7

Então @al777, bom, nesse caso, conforme o tutorial que passei no tronixstuff, a relação entre o MCU e o dispositivo é de Master/Slave, você está usando apenas funções de Master, verifique a parte de Slave no documento, já que você precisa delas para ler do Slave, que seria o dispositivo.

Outra coisa é também referente ao endereçamento (o dispositivo tem 2 endereços, SA0 = 0 ou 1), verifico na Tabela 11 do datasheet o endereçamento completo em 8-bit do dispositivo e, se você está utiliza SA0 = 0, o endereçamento para o comando Read(leitura) é 0x39 e não 0x38, como você tenta escrever, mas isso, só no modo de múltiplos bytes, se você deseja ler só um byte, o comando de operação pode ser omitido, conforme a tabela 10, mas creio que o registrador não incrementa no modo single byte.

Por fim, é bom também verificar o projeto e a pinagem do MCU, você deve se certificar que está utilizando os pinos corretos das portas que sejam referentes a SDA/SCL.


#8

Estou meio confuso. Por qual motivo você me mandou ler as funções de slave no documento?
No documento estão usando dois pics, um master e um slave, na minha situação eu tenho que configurar o pic como master e o acelerômetro é passivo e não deveria agir como slave já?

Achei 2 tutoriais muito interessantes e estou seguindo eles, descobri também que o próprio mplab tem a biblioteca pronta do I2C e econtrei um application note:


.

Eu já estou usando o osciloscópio e consigo até ver o bit de ACK, mas infelizmente na hora do pic ler, por algum motivo o acelerômetro não altera os bits, fica tudo nível alto.

Na questão de incrementar ou não, eu estou seguindo a ilustração 11, ele falou pra por o bit e eu estou colocando ahhahaa

Eu vou colocar o programa de novo aqui e vê se estou comendo bola nos endereçamentos:

 OpenI2C( MASTER, SLEW_OFF);  // Master, slew off por causa de 100KHz
 SSPADD = 0x31;       // Configuração para 100KHz

   StartI2C();           // Inicia
   IdleI2C();            // Espera
   WriteI2C(0x38);  //  Endereço do device 0x1C + Write = 0x38 ( 00111000 )    Table 11
   IdleI2C();            // Espera 
   WriteI2C(0x2A);  // Registrador de configuração
   IdleI2C();           // Espera
   WriteI2C(0x01);  // Bit de ativação =1
   IdleI2C();            // Espera
   StopI2C();          // Para
  

  StartI2C();           //Inicia
   IdleI2C();            //Espera
   WriteI2C(0x38);   //  Endereço do device 0x1C + Write (0) = 0x38 ( 00111000 )        Table 11
   IdleI2C();              //Espera
   WriteI2C(0x01);     // Endereço do registrador valor em x - Table 12
   IdleI2C();              //Espera   
   StopI2C();             // Para

   RestartI2C();         // Recomeça
   IdleI2C();                //Espera
   WriteI2C(0x39);        //  Endereço do device 0x1C + Read (1) = 0x38 ( 00111001 )        Table 11                       
   IdleI2C();              //Espera
   val=ReadI2C();
   IdleI2C();                //Espera
   NotAckI2C();
   IdleI2C();               //Espera
   StopI2C();             // Para

Está faltando alguma coisa ainda?

Abraços


#9

@al777,

Não seria o caso de se tentar colocar um resistor de PULL UP nas linhas SCL e SDA?

Tipo isso da figura?

Creio que o acelerômetro pode ter sua interface baseado em “coletor aberto”. Não sei.

Não encontrei referencias sobre este acelerômetro.

No mais se precisar grite.

Abraços,


#10

O acelerômetro é o: http://cache.nxp.com/files/sensors/doc/data_sheet/MMA8451Q.pdf
O aplication note que eu achei: http://www.nxp.com/files/sensors/doc/app_note/AN4076.pdf?fasp=1&WT_TYPE=Application%20Notes&WT_VENDOR=FREESCALE&WT_FILE_FORMAT=pdf&WT_ASSET=Documentation&fileExt=.pdf
A placa onde está colocado o acelerômetro: http://www.robotpark.com/GY-45-MMA8451-3-Axis-Accelerometer-Module

Então, a própria placa tem já tem dois resistores ligando SDA e SCK ao VCC como pull up =/


#11

@al777 vou ter que dar uma olhada com calma nisso, exige um pouco de tempo, mas terei que ler a documentação e verificar o teu código, me parece que essas funções são bem mais claras, se der pra eu me desvencilhar mais rápido o trabalho, verifico no tempo livre, principalmente porque eu não tenho e não uso PIC, já usei e uso i2c com Teensy (AVR) num módulo de expansão de portas I2C (cuja fabricante é a Microchips, por ironia) e tudo que eu fizer é de nível teórico, tentando dar dicas para consertar o problema.


#12

Problema resolvido! O MPLAB já tem uma biblioteca I2C
E nesse site tem um exemplo que me ajudou muito:

http://www.todopic.com.ar/foros/index.php?topic=40764.0

Acho que já dá pra encerrar esse assunto aqui.

Sou muito grato a vocês :smiley:
Abraços