Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F103 и компас HMC6352
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
D1mcon
Всем привет! Работаю с МК STM32F103 и компасом HMC6352 по I2C. Но ни как не могу прочитать данные о курсе, всегда компас возвращает значение 0х42. В чем причина, понять не могу. Если кто работал с этим компасом, прошу помочь в решении проблемы.
Код программы
Код
#include "stm32f10x.h"
#include "stm32f10x_i2c.h"


GPIO_InitTypeDef         GPIO_InitStructure;
USART_InitTypeDef         USART_InitStructure;
I2C_InitTypeDef            I2C_InitStructure;
FlagStatus Status = SET;    

#define I2C1_SLAVE_ADDRESS7   0x42
#define HMC6352GetData          0x41
#define BufferSize             4
#define ClockSpeed             100000
typedef enum { FAILED = 0, PASSED = !FAILED} TestStatus;

int angle = 0;
void Delay(unsigned long ms)// delay 1 ms per count @ Crystal 8.0 MHz and PLL9x or SYSCLK = 72 MHz
{
    volatile unsigned long i,j;
    for (i = 0; i < ms; i++ )
    for (j = 0; j < 5525; j++ );
}

int HMC6352GetHeading( void)
{
   unsigned char data_l = 0, data_m = 0;
  

       /* Send I2C1 START condition */
      I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(I2C1, 0x42, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ));

   I2C_SendData(I2C1,0x41);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED ));

   Delay(60);

   I2C_GenerateSTART(I2C1, ENABLE);
   while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

   I2C_Send7bitAddress(I2C1, 0x43, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ));

   data_l = I2C_ReceiveData(I2C1);         // read LSB data byte
   data_m = I2C_ReceiveData(I2C1);         // read MSB data byte
   I2C_AcknowledgeConfig(I2C1, DISABLE);
                    
   I2C_GenerateSTOP(I2C1, ENABLE);      // send STOP condition
   return ( (data_m << 8) + data_l);   // return 16 bits data
}

void main()
{    

    SystemInit();
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA  | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
      /* I2C1 Periph clock enable */
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    /* Configure I2C1 pins: SCL and SDA ----------------------------------------*/
      GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
      GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* I2C1 configuration ------------------------------------------------------*/
      I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
      I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
      I2C_InitStructure.I2C_OwnAddress1 = I2C1_SLAVE_ADDRESS7;
      I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
      I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
      I2C_InitStructure.I2C_ClockSpeed = ClockSpeed;
      I2C_Init(I2C1, &I2C_InitStructure);

    /* Enable I2C1 */
      I2C_Cmd(I2C1, ENABLE);

    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_9 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
      GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_9;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
      GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_10;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
      GPIO_Init(GPIOA, &GPIO_InitStructure);


    
    USART_InitStructure.USART_BaudRate = 9600;
      USART_InitStructure.USART_WordLength = USART_WordLength_8b;
      USART_InitStructure.USART_StopBits = USART_StopBits_1;
      USART_InitStructure.USART_Parity = USART_Parity_No;
      USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
      USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    
    /* USART configuration */
      USART_Init(USART1, &USART_InitStructure);
    
      /* Enable USART */
      USART_Cmd(USART1, ENABLE);
    angle = HMC6352GetHeading();
    
    while(1)
    {
        
            angle = HMC6352GetHeading();
        USART_SendData(USART1, (uint8_t) angle);
    

    }
Serj78
Компас возвращает число от 0 до 3600 ( курс в десятых долях градуса.)

Вы выводите одно число (младшие 8 бит? ) что не совсем корректно. выводите два байта или курс, деленный на 20, так понятнее будет.
Библиотеки I2c стандартные? Советую ими не пользоваться- в стандартных очень много фирменных индийских глюков.

Судя по коду, вы работаете в запросном режиме. Прочитайте для начала не курс, а хотя бы режим работы, смените его и снова прочитайте (через снятие питания) убедитесь что ваш ввод/ вывод правильно работает.

Посмотрите также (прочитайте данные из регистра), установлен ли periodic set/reset., иначе пластины сенсора не перемагничиваются и результат будет не верным (максимальным).

Надо обязательно выдавать подтверждение чтения первого байта (ASK), иначе второй не выведется (там будет FF, линия SDA отпустится)
Также возьмите осциллограф и внимательно посмотрите на поведение линий после запроса байта 0х43..
D1mcon
Спасибо, буду разбираться.
KKV2003
Вчера бился с другим девайсом через I2C ( почти, называется по другому ). В качестве контроллера взял Мегу8 ( что под рукой оказалось ). Подпрограммы взял в Инете, немного переделал. Не работало нормально. Достаточно долго бился и вот что понял.

В первоисточнике кода было написано, что после выдачи цикла записи адреса регистра для чтения ( 2-хфазный цикл записи ) достаточно выдать новый сигнал "Старт" на шину и дальше уже выдать 2-хфазный цикл чтения ( с единичным битом чтения/записи в идентификаторе ).

Так вот мой девайс такого делать не захотел - реагировал на новый идентификатор как на байт данных для записи. Пришлось вставлять "Стоп" перед "Стартом" - тогда все поехало.

То есть чтение происходило так:
1) Старт шины
2) Идентификатор четный ( на запись )
3) Адрес регистра для чтения
4) Стоп шины
5) Старт шины
6) Идентификатор нечетный ( на чтение )
7) Циклы чтения ( последний без квитанции от Мастера, остальные - без квитанции )
8) Стоп шины

Вот так у меня заработало.
Serj78
Цитата(KKV2003 @ Oct 21 2010, 07:25) *
То есть чтение происходило так:
1) Старт шины
2) Идентификатор четный ( на запись )
3) Адрес регистра для чтения
4) Стоп шины
5) Старт шины
6) Идентификатор нечетный ( на чтение )
7) Циклы чтения ( последний без квитанции от Мастера, остальные - без квитанции )
8) Стоп шины

Вот так у меня заработало.


Такой порядок чтения по запросу прямо указан в даташите на HMC6352 smile.gif

С этим компасом натолкнулся на одну проблему- на нескольких устройствах через 2..3 года слетает регистр режима из eeprom. Почему- не известно. По использованию - есть команды только на чтение, других устройств на шине нет.. Вылечил тем, что по старту устройства сначала записываем нужный режим работы.
KKV2003
Хорошо вам... А в моем даташите такого не было. Так что помучился. laughing.gif
D1mcon
Продолжаем разговор sm.gif . Компас после нескольких месяцев не заработал sad.gif Причина - не получаю ACK после передачи адреса.
Привожу немного измененный код
Код
#include "stm32f10x.h"
#include "stm32f10x_i2c.h"



I2C_InitTypeDef            I2C_InitStructure;
FlagStatus Status = SET;    

#define ReadAddress                0x43
#define WriteAddress            0x42
#define BufferSize              4
#define GetHeading                0x41
#define ClockSpeed              100000

int I2C_address = 0;
bool exit = FALSE;
I2C_TypeDef* HMC6352_I2C;

void HMC6352Init(I2C_TypeDef* HMC6352_I2Cx)
{    
    GPIO_InitTypeDef         GPIO_InitStructure;
    I2C_InitTypeDef            I2C_InitStructure;
    
    HMC6352_I2C = HMC6352_I2Cx;
       I2C_Cmd(HMC6352_I2C, DISABLE);
       I2C_DeInit(HMC6352_I2C);
                                    
                                                      
    /* Configure I2C1 pins: SCL and SDA ----------------------------------------*/    
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);

      GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
      GPIO_Init(GPIOB, &GPIO_InitStructure);
        
    /* I2C1 configuration ------------------------------------------------------*/
      I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
      I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
      I2C_InitStructure.I2C_OwnAddress1 = 0x00;
      I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
      I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
      I2C_InitStructure.I2C_ClockSpeed = ClockSpeed;
      
      I2C_Init(HMC6352_I2C, &I2C_InitStructure);
    I2C_Cmd(HMC6352_I2C, ENABLE);
      
        

}

int HMC6352GetHeading()
{
  
  __IO uint16_t RegValue = 0;
  
  I2C_AcknowledgeConfig(HMC6352_I2C, ENABLE);
  /*--------------------------------- Transmission Phase ------------------*/

  I2C_GenerateSTART(HMC6352_I2C, ENABLE);
  while (!I2C_CheckEvent(HMC6352_I2C, I2C_EVENT_MASTER_MODE_SELECT));  /*!< EV5 */

  I2C_Send7bitAddress(HMC6352_I2C, WriteAddress, I2C_Direction_Transmitter);
  while (!I2C_CheckEvent(HMC6352_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); /*!< EV6 */
  
  I2C_SendData(HMC6352_I2C, GetHeading);
  while (!I2C_CheckEvent(HMC6352_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); /*!< EV8 */


  /*-------------------------------- Reception Phase --------------------------*/
  I2C_GenerateSTART(HMC6352_I2C, ENABLE);
  while (!I2C_CheckEvent(HMC6352_I2C, I2C_EVENT_MASTER_MODE_SELECT));  /*!< EV5 */

  I2C_Send7bitAddress(HMC6352_I2C, ReadAddress, I2C_Direction_Receiver);
  while (!I2C_CheckEvent(HMC6352_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));  /*!< EV6 */
  while (!I2C_CheckEvent(HMC6352_I2C, I2C_EVENT_MASTER_BYTE_RECEIVED));  /*!< EV7 */

  RegValue = I2C_ReceiveData(HMC6352_I2C) << 8;
  I2C_AcknowledgeConfig(HMC6352_I2C, DISABLE);
  I2C_GenerateSTOP(HMC6352_I2C, ENABLE);

  while (I2C_GetFlagStatus(HMC6352_I2C, I2C_FLAG_RXNE) == RESET);
  RegValue |= I2C_ReceiveData(HMC6352_I2C);


  return (RegValue/10);
}


И сигналы SCL и SDA. По сигналам видно что нормально происходит старт I2c, посылка адреса, но на 9 клоке SDA = 1, компас не ответил :cry:
Частота настроена верно. Питание на компасе есть. Подтягивающие резисторы на SCL и SDA по 2КОм, при 10КОм, как в ДШ на компас, сильно заваливались фронты.
Подскажите, в чем может быть причина отсутствия ACK?
D1mcon
Вобщем проблема решена - нашел на демоплате перебитую дорожку на клоки.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.