Алексей
8 лет назадError: L6218E: Undefined symbol HAL_I2C_Init (referred from main.o).
В этом уроке по STM32 вы научитесь:
/* stm32f1xx_hal_msp.c */
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hi2c->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspInit 0 */
/* USER CODE END I2C1_MspInit 0 */
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral clock enable */
__I2C1_CLK_ENABLE();
/* USER CODE BEGIN I2C1_MspInit 1 */
/* USER CODE END I2C1_MspInit 1 */
}
В файле main.c конфигуриуется сама шина I2C, согласно нашим установкам в CubeMX:
/* main.c */
void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED;
HAL_I2C_Init(&hi2c1);
}
Кстати, иногда CubeMX глючит и не подключает модуль I2C, и это естественно вызывает кучу ошибок при компиляции. Для ручного включения этого модуля придется открыть файл <Project>\Inc\stm32f1xx_hal_conf.h (это для 100 серии микроконтроллера) и в нем раскомментировать строку #define HAL_I2C_MODULE_ENABLED.
Инициализация других объектов нас сейчас мало интересует, поэтому переходим сразу к нашей задаче. В разделе пользовательских переменных инициализируем нужные нам объекты: однобайтный буфер обмена xBuffer, адрес EEPROM микросхемы I2C1_DEVICE_ADDRESS = 0x50 по шине I2C и ячейку памяти MEMORY_ADDRESS с адресом 0x08.
/* main.c */
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
uint8_t xBuffer[1];
#define I2C1_DEVICE_ADDRESS 0x50 /* A0 = A1 = A2 = 0 */
#define MEMORY_ADDRESS 0x08
/* USER CODE END PV */
Важно помнить, что запись своего кода всегда нужно осуществлять в строго отведенных блоках.
/* main.c */
/* USER CODE BEGIN…*/
/* USER CODE END…*/
Тем самым, при следующей генерации кода CubeMX не сотрет эти блоки. Теперь перейдем к записи и чтению одного байта из памяти. В бесконечном цикле main запишем:
/* main.c */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
xBuffer[0] = 'M'; //0x4D
HAL_I2C_Mem_Write(&hi2c1, (uint16_t) I2C1_DEVICE_ADDRESS<<1, MEMORY_ADDRESS, 1, xBuffer, 1, 5); //write to memory address 08
osDelay(10); //memory write delay
xBuffer[0] = 0x00; //clear buffer
osDelay(5000); //system wait
HAL_I2C_Mem_Read(&hi2c1, (uint16_t) I2C1_DEVICE_ADDRESS<<1, MEMORY_ADDRESS, 1, xBuffer, 1, 5); //read memory address 08
if (xBuffer[0] == 0x4D) // if xBuffer[0] = 'M'
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_SET); //BLUE LED ON
}
/* USER CODE BEGIN 3 */
}
Результатом работы будет включение синего светодиода через 5 секунд после запуска. Обнулить ячейку памяти возможно с помощью другой программы, с этим должно быть все ясно.
Функции HAL_I2C_Mem_Write и HAL_I2C_Mem_Read предназначены для работы с памятью, и поэтому нет необходимости использовать общие функции работы с шиной I2C HAL_I2C_Master_Transmit и HAL_I2C_ Master_Receive, тем более, что с ними есть некоторые проблемы при работе с памятью. Адрес EEPROM необходимо передавать в смещенном виде I2C1_DEVICE_ADDRESS<<1, т.к. он является семибитным, а последний восьмой бит по спецификации I2C является флагом записи/чтения. HAL его настраивает самостоятельно.
В функциях HAL_I2C_Mem_Write и HAL_I2C_Mem_Read последним аргументом является время ожидания, за которое микроконтроллер стабильно будет получать реакцию от EEPROM на его запросы. Задержка в 10 мс osDelay(10) после функции HAL_I2C_Mem_Write необходима на совершение операции записи в EEPROM, хотя в даташите на EEPROM указано время записи 5 мс (Write cycle time (byte or page)). Но лучше перестраховаться, если не нужна большая скорость записи.
Другие аргументы функций HAL_I2C_Mem_Write и HAL_I2C_Mem_Read думается, не вызовут больших вопросов. Код проекта доступен по кнопке Скачать пример для всех пользователей.
Теги
Поделиться ссылкой на статью