1.Introdução
Neste tutorial é demonstrado a leitura dos dados gerados pelo acelerômetro MMA8451Q com foco na comunicação I2C. Primeiramente é usada a comunicação I2C com pooling e após com interrupção, em seguida, é adiciona a porta USB para transmissão dos dados para um PC.
O acelerômetro MMA8451Q é um acelerômetro capacitivo, de 3 eixos, com resolução de até 14 bits e medindo até 8g. Ele possui uma porta I2C para comunicação com MCUs e duas saídas para sinalizar interrupções internas. Para controle do dispositivo no barramento I2C há um pino SA0 para que o projetista configure o endereço do mesmo no barramento. Como mostrado na Fig. 1, o pino SA0 está conectado ao nível lógico "1", sendo assim, o endereço do dispositivo no barramento é 1Dh. A Fig. 1 também mostra a tabela de conexão dos pinos do acelerômetro no MCU.
Figura 1. Circuito com o acelerômetro MMA8451Q.
Fonte: (NXP, 2016)
2. Criação do projeto
Com o projeto criado, é necessário configurar o clock do MCU para 96 MHz, já pensando no uso da porta USB. A configuração do clock já foi abordada no tutorial Programa 3 - Comunicação USB.
Feitas as configurações para o clock, o passo seguinte é adicionar o componente responsável pelo controle do módulo I2C presente no MCU. No Components Library digite I2C e selecione o componente I2C_LDD. Na aba Interrupt service, deve-se deixar a opção interrupt service desmarcada, na aba settings as configurações devem ficar como na fig. 2.
Figura 2. Configurações para a I2C.
Fonte: Elaborado pelo autor.
Este MCU possui duas portas I2C, neste exemplo é utilizada a I2C0 e o modo de seleção deve ser MASTER, dizendo ao MCU que ele controla o barramento I2C (MASTER). De acordo com o valor selecionado no combo internal frequency o usuário deverá selecionar, nos dois combos seguintes, os divisores necessários para configurar o clock de SCL em até 100 KHz. Na caixa de texto Target slave address init é configurado o endereço do escravo, que neste exemplo é 1Dh=29d. Na Pins, é possível selecionar os pinos da porta.
Com estas configurações feitas pode-se passar para a escrita do código do programa.
3. Código do programa
Neste exemplo é implementado a comunicação I2C com o acelerômetro MMA8451Q. O dispositivo possui uma tabela de 49 registradores, cada um apresenta funções diferentes possibilitando o uso intenso do dispositivo. Para uma aplicação simples, é necessário configurar apenas o registrador 2Ah=42d. Na Fig. 3, temos em detalhes os bits do registrador CTRL_REG1. O bit0 controla o modo de funcionamento, em "0" o dispositivo fica em standby, sem fazer conversões, em "1" o dispositivo inicia as conversões. O bit1 controla o modo de conversões, em "0" as conversões são feitas no modo normal, em "1" no modo fast (contínuas). Passando este bits para "1", o dispositivo já começa a operar.
Figura 3. Detalhes do registrador de controle.
Fonte: Elaborado pelo autor.
No arquivo main.c, o código abaixo executa a leitura dos 3 registradores de aceleração, X, Y e Z, no modo pooling
CÓDIGO
/* ###################################################################
** Filename : main.c
** Project : kl25z acelerometro
** Processor : MKL25Z128VLK4
** Version : Driver 01.01
** Compiler : GNU C Compiler
** Date/Time : 2016-08-08, 19:51, # CodeGen: 0
** Abstract :
** Main module.
** This module contains user's application code.
** Settings :
** Contents :
** No public methods
**
** ###################################################################*/
/*!
** @file main.c
** @version 01.01
** @brief
** Main module.
** This module contains user's application code.
*/
/*!
** @addtogroup main_module main module documentation
** @{
*/
/* MODULE main */
/* Including needed modules to compile this module/procedure */
#include "Cpu.h"
#include "Events.h"
#include "I2C.h"
#include "WAIT1.h"
#include "KSDK1.h"
#include "LED1.h"
#include "LEDpin1.h"
#include "BitIoLdd1.h"
#include "LED2.h"
#include "LEDpin2.h"
#include "BitIoLdd2.h"
#include "LED3.h"
#include "LEDpin3.h"
#include "BitIoLdd3.h"
/* Including shared modules, which are used for whole project */
#include "PE_Types.h"
#include "PE_Error.h"
#include "PE_Const.h"
#include "IO_Map.h"
/* External 3-axis accelerometer control register addresses */
#define MMA8451_CTRL_REG_1 0x2A
/* MMA8451 3-axis accelerometer control register bit masks */
#define MMA8451_ACTIVE_BIT_MASK 0x01
#define MMA8451_F_READ_BIT_MASK 0x02
/* External 3-axis accelerometer data register addresses */
#define MMA8451_OUT_X_MSB 0x01
#define MMA8451_OUT_X_LSB 0x02
#define MMA8451_OUT_Y_MSB 0x03
#define MMA8451_OUT_Y_LSB 0x04
#define MMA8451_OUT_Z_MSB 0x05
#define MMA8451_OUT_Z_LSB 0x06
/* User includes (#include below this line is not maintained by Processor Expert) */
LDD_TDeviceData *Myi2c;
LDD_TError Error;
bool gb_transmitiu = FALSE;
bool gb_dado_recebido = FALSE;
/*lint -save -e970 Disable MISRA rule (6.3) checking. */
int main(void)
/*lint -restore Enable MISRA rule (6.3) checking. */
{
/* Write your local variable definition here */
uint8_t c_cmd[4];
/*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
PE_low_level_init();
/*** End of Processor Expert internal initialization. ***/
for (;;) {
Myi2c = I2C_Init(NULL);
c_cmd[0] = MMA8451_CTRL_REG_1;
c_cmd[1] = MMA8451_F_READ_BIT_MASK|MMA8451_ACTIVE_BIT_MASK;
gb_transmitiu = FALSE;
Error = I2C_MasterSendBlock(Myi2c, c_cmd, 2, LDD_I2C_SEND_STOP);
if (Error == ERR_OK) {
while (gb_transmitiu == FALSE) {
I2C_Main(Myi2c);
}
}
//agora pergunta o valor do eixo X
WAIT1_Waitus(10);
c_cmd[0] = MMA8451_OUT_X_MSB;
gb_transmitiu = FALSE;
Error = I2C_MasterSendBlock(Myi2c, c_cmd, 1, LDD_I2C_NO_SEND_STOP);
if (Error == ERR_OK) {
while (gb_transmitiu == FALSE) {
I2C_Main(Myi2c);
}
gb_transmitiu = FALSE;
gb_dado_recebido = FALSE;
Error = I2C_MasterReceiveBlock(Myi2c, c_cmd, 3U, LDD_I2C_SEND_STOP);
if (Error == ERR_OK) {
while (!gb_dado_recebido) {
I2C_Main(Myi2c);
}
gb_dado_recebido = FALSE;
if(c_cmd[0]!=255 && c_cmd[0]>50)
LED1_On();
else
LED1_Off();
if(c_cmd[1]!=255 && c_cmd[1]>50)
LED2_On();
else
LED2_Off();
if(c_cmd[2]!=255 && c_cmd[2]>50)
LED3_On();
else
LED3_Off();
}
}
I2C_Deinit(Myi2c);
}
/* Write your code here */
/* For example: for(;;) { } */
/*** Don't write any code pass this line, or it will be deleted during code generation. ***/
/*** RTOS startup code. Macro PEX_RTOS_START is defined by the RTOS component. DON'T MODIFY THIS CODE!!! ***/
#ifdef PEX_RTOS_START
PEX_RTOS_START(); /* Startup of the selected RTOS. Macro is defined by the RTOS component. */
#endif
/*** End of RTOS startup code. ***/
/*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/
for(;;){}
/*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/
} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/
/* END main */
/*!
** @}
*/
/*
** ###################################################################
**
** This file was created by Processor Expert 10.5 [05.21]
** for the Freescale Kinetis series of microcontrollers.
**
** ###################################################################
*/
Além dos código acima, é necessário adicionar o código abaixo para os dois eventos que são gerados ao final da transmissão dos dados e após a recepção também. As duas variáveis bool, declaradas no arquivo main.c são atualizadas quando estes eventos ocorrem, alterando o valor delas para TRUE. Antes de executar uma troca de dados com a I2C o usuário deve alterar os valores destas para FALSE.
CÓDIGO
extern bool gb_transmitiu,gb_dado_recebido;
void I2C_OnMasterBlockSent(LDD_TUserData *UserDataPtr)
{
/* Write your code here ... */
gb_transmitiu=TRUE;
}
/*
** ===================================================================
** Event : I2C_OnMasterBlockReceived (module Events)
**
** Component : I2C [I2C_LDD]
*/
/*!
** @brief
** This event is called when I2C is in master mode and finishes
** the reception of the data successfully. This event is not
** available for the SLAVE mode and if MasterReceiveBlock is
** disabled.
** @param
** UserDataPtr - Pointer to the user or
** RTOS specific data. This pointer is passed
** as the parameter of Init method.
*/
/* ===================================================================*/
void I2C_OnMasterBlockReceived(LDD_TUserData *UserDataPtr)
{
/* Write your code here ... */
gb_dado_recebido=TRUE;
}
Referências:
NXP, NXP Products. Disponível em <FRDM-KL25Z: Freedom Development Platform for Kinetis® KL14, KL15, KL24, KL25 MCUs>. Acessado em Maio de 2016.