Skocz do zawartości

STM32F103 - I2C (akcelerometr MMA8452Q)


DonPablo

Pomocna odpowiedź

Cześć,

akcelerometr wyświetla cały czas te same wartości.

Próbuję obsłużyć wspomniany w temacie akcelerometr komunikujący się po I²C.

Korzystałem przy pisaniu programu z kursu Forbot, który też jest o obsłudze akcelerometru po I²C, ale innego modelu. Główne różnice między nimi są takie, że mój wysyła dane w postaci 8/12-bitowej (str. 13, 45), w przeciwieństwie do postaci 16-bitowej ze znakiem dla akcelerometru opisanego w kursie.

Przesiedziałem nad tym całą dobę, ale wciąż nie udaje mi się uzyskać jakiegokolwiek sensownego odczytu. Ciągle dostaję coś podobnego do:

1Y4pG0a.png

Zasadniczo, za każdym razem wygląda to tak samo, nieważne jak mocno będę trząść płytką, ani to w jakiej pozycji będzie akcelerometr przy wgrywaniu programu. Czasem po odłączeniu i ponownym podłączeniu mikrokontrolera wartość X zmienia się na 33, ale na ruch reakcji brak.

Nie mam pojęcia co może być przyczyną, dlatego proszę o pomoc. I o wyrozumiałość, bo dopiero zaczynam zgłębiać dziedzinę mikrokontrolerów 🙂

Poniżej mój kod:

main.c:

#include "stm32f10x.h"
#include "lcd.h"
#include "mma8452q.h"
#include <stdio.h>

volatile uint32_t timer_ms = 0;

void SysTick_Handler();
void delay_ms(int);

void RCC_Config_HSE_PLL_Max(void);
void USART2_Init(USART_InitTypeDef, uint32_t);
void I2C2_Init(void);

void send_char(char c);
int __io_putchar(int c);

int main(void)
{
   lcd_init();
RCC_Config_HSE_PLL_Max(); // set HCLK to 72 MHz

USART_InitTypeDef uart_structure;

USART2_Init(uart_structure, 9600); // configure and initialize USART2 transmission, default baud rate = 9600
I2C2_Init();
////////////////////////////////////////////////////////////////////////////////////////////////////////////

printf("Searching for accelerometer...\n");

uint8_t who_am_i = mma_read(MMA8452Q_ADDR, MMA8452Q_WHO_AM_I);

if(who_am_i == 0x2a)
{
	printf("MMA8452Q accelerometer was found\n");
	printf("Who am i value is: (0x%X)\n", who_am_i);
}
else
{
	printf("Invalid device response (0x%X)\n", who_am_i);
}

uint8_t ctrl_reg1 = mma_read(MMA8452Q_ADDR, MMA8452Q_CTRL_REG1);

mma_write(MMA8452Q_ADDR, MMA8452Q_CTRL_REG1, 0x38|0x02); // DR (0x20 = 25 Hz, 0x28 = 12,5 Hz, 0x38 = 1,56 Hz) | fast-read mode

printf("Control_register 1 value is: (0x%X)\n", ctrl_reg1);

   while(1)
   	{
   	uint8_t a_x = mma_read(MMA8452Q_ADDR, MMA8452Q_OUT_X_MSB);
   	uint8_t a_y = mma_read(MMA8452Q_ADDR, MMA8452Q_OUT_Y_MSB);
   	uint8_t a_z = mma_read(MMA8452Q_ADDR, MMA8452Q_OUT_Z_MSB);
   	printf("X = %d Y = %d Z = %d\n", a_x, a_y, a_z);
   	};
}

void RCC_Config_HSE_PLL_Max(void) // 72 MHz
{
RCC_DeInit();
ErrorStatus HSEStartUpStatus;

RCC_HSEConfig(RCC_HSE_ON); // enable HSE clock 12 MHz
HSEStartUpStatus = RCC_WaitForHSEStartUp();

if(HSEStartUpStatus == SUCCESS)
{
	FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
	FLASH_SetLatency(FLASH_Latency_2); // set wait state
	RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_6);
	RCC_PLLCmd(ENABLE);
	while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); // wait till HSE PLL is ready
	RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // select HSE PLL as system clock source
	while(RCC_GetSYSCLKSource() != 0x08); // wait till HSE PLL is used as system clock source
	RCC_HCLKConfig(RCC_SYSCLK_Div1); // 72 MHz
	RCC_PCLK1Config(RCC_HCLK_Div2); // 36 MHz
	RCC_PCLK2Config(RCC_HCLK_Div1); // 72 MHz
}
}

void USART2_Init(USART_InitTypeDef uart, uint32_t rate)
{
GPIO_InitTypeDef gpio;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

/* GPIOA configuration for USART */
GPIO_StructInit(&gpio);
gpio.GPIO_Pin = GPIO_Pin_2;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &gpio);

gpio.GPIO_Pin = GPIO_Pin_3;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &gpio);

   /* USART configuration */
USART_StructInit(&uart);
uart.USART_BaudRate = rate;
uart.USART_WordLength = USART_WordLength_8b;
uart.USART_StopBits = USART_Parity_No;
uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
   //uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART2, &uart);

   USART_Cmd(USART2, ENABLE);

   USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);

   NVIC_EnableIRQ(USART2_IRQn);
}

void I2C2_Init(void)
{
GPIO_InitTypeDef gpio;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

/* GPIOB configuration for I2C */
GPIO_StructInit(&gpio);
gpio.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; // SCL, SDA, SA0
gpio.GPIO_Mode = GPIO_Mode_AF_OD;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio);

/* I2C configuration */
I2C_InitTypeDef i2c;

I2C_StructInit(&i2c);
i2c.I2C_Mode = I2C_Mode_I2C;
i2c.I2C_ClockSpeed = 400000;
i2c.I2C_DutyCycle = I2C_DutyCycle_2;
i2c.I2C_OwnAddress1 = 0x00;
i2c.I2C_Ack = I2C_Ack_Enable;
i2c.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C2, &i2c);
I2C_Cmd(I2C2, ENABLE);
}

void SysTick_Handler()
{
if(timer_ms) {
   timer_ms--;
}
}

void delay_ms(int time)
{
timer_ms = time;
while (timer_ms) {};
}

void send_char(char c)
{
while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
USART_SendData(USART2, c);
}

int __io_putchar(int c)
{
if (c=='\n')
send_char('\r');
send_char(c);
return c;
}

mma8452q.c:

#include "stm32f10x.h"
#include "mma8452q.h"

void mma_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t reg_data)
{
while(!I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY)); // while the bus is busy

//I2C_AcknowledgeConfig(I2C2, ENABLE);

I2C_GenerateSTART(I2C2, ENABLE); // send I2C start condition
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));

I2C_Send7bitAddress(I2C2, dev_addr, I2C_Direction_Transmitter); // send device slave address for write
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

I2C_SendData(I2C2, reg_addr); // send the device internal register address
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

I2C_SendData(I2C2, reg_data); // send data to register
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

I2C_GenerateSTOP(I2C2, ENABLE);
}

uint8_t mma_read(uint8_t dev_addr, uint8_t reg_addr)
{
I2C_AcknowledgeConfig(I2C2, DISABLE);
while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY)); // while the bus is busy

I2C_GenerateSTART(I2C2, ENABLE); // send I2C start condition
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));

I2C_Send7bitAddress(I2C2, dev_addr, I2C_Direction_Transmitter); // send device slave address for write
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

I2C_SendData(I2C2, reg_addr); //0x80 | reg_addr); // send the device internal register address
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

/////////////////////////////////////////////////////////////

I2C_GenerateSTART(I2C2, ENABLE); // repeated start
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));

I2C_Send7bitAddress(I2C2, dev_addr, I2C_Direction_Receiver); // send device slave address for read
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED));

uint8_t read_reg = I2C_ReceiveData(I2C2);

I2C_GenerateSTOP(I2C2, ENABLE);
I2C_AcknowledgeConfig(I2C2, DISABLE);

return read_reg;
}

mma8452q.h:

#ifndef MMA8452Q_H_
#define MMA8452Q_H_

#include <stdint.h>

#define MMA8452Q_ADDR		0x3a
#define MMA8452Q_STATUS		0x00
#define MMA8452Q_OUT_X_MSB	0x01
#define MMA8452Q_OUT_X_LSB	0x02
#define MMA8452Q_OUT_Y_MSB	0x03
#define MMA8452Q_OUT_Y_LSB	0x04
#define MMA8452Q_OUT_Z_MSB	0x05
#define MMA8452Q_OUT_Z_LSB	0x06
#define MMA8452Q_WHO_AM_I	0x0d
#define MMA8452Q_CTRL_REG1	0x2a
#define MMA8452Q_CTRL_REG2	0x2b
#define MMA8452Q_CTRL_REG3	0x2c
#define MMA8452Q_CTRL_REG4	0x2d
#define MMA8452Q_CTRL_REG5	0x2e

extern void mma_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t reg_data);
extern uint8_t mma_read(uint8_t dev_addr, uint8_t reg_addr);

extern void delay_ms(int time);

#endif /* MMA8452Q_H_ */

__________

Komentarz dodany przez: Sabre

Link do komentarza
Share on other sites

Jak komunikacja działa dobrze to po odczytaniu MSB odczytaj LSB. Akcelerometr przed odnowieniem danych czeka na odczytanie LSB. W ten sposób nie ma możliwości, że odczytany MSB należy do jednej próbki, a odczytany LSB do innej co mogłoby dać czasami losowe "skoki" wyników.

PS. SPojrzałem, że używasz fast read mode, więc może to nie jest to... drugie co bym spróbował to zmienić status flagi ACTIVE na 1 w reg1.

PPS. Ja używam takich ustawień dla 8451 i działa:

//ustaw MMA8451
 temp[0]=0x10;//High res oversampling
 I2C_BufferWrite(MMA8451_SLAVE_ADDRESS,&temp[0],0x2B,1);
 temp[0]=0x11;//ACTIVE mode 200Hz etc.
 I2C_BufferWrite(MMA8451_SLAVE_ADDRESS,&temp[0],0x2A,1);

//odczytanie wyniku po bajcie
       I2C_BufferRead(MMA8451_SLAVE_ADDRESS,&tekst[3],0x01,1);
   	I2C_BufferRead(MMA8451_SLAVE_ADDRESS,&tekst[4],0x02,1);

   	I2C_BufferRead(MMA8451_SLAVE_ADDRESS,&tekst[5],0x03,1);
   	I2C_BufferRead(MMA8451_SLAVE_ADDRESS,&tekst[6],0x04,1);

   	I2C_BufferRead(MMA8451_SLAVE_ADDRESS,&tekst[7],0x05,1);
   	I2C_BufferRead(MMA8451_SLAVE_ADDRESS,&tekst[8],0x06,1);

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Nie mam pojęcia dlaczego myślałem, że domyślnym ustawieniem jest ACTIVE = 1... cały dzień zmarnowany przez jedną jedynkę.

Kliknąłem "pomógł" 😉

P.S. Proszę o usunięcie tego wątku, bo aż mi wstyd 😃

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...