Совсем недавно мы начали использовать микроконтроллеры семейства STM32F4 (вот ссылочка), так что надо продолжать это хорошее дело ) Сегодня посмотрим , как работает в STM32F4 USART, ну и, как обычно, создадим какой-нибудь проект для примера. Ковыряться в регистрах, пожалуй, не будем, все отлично описано в даташитах, так что останавливаться на этом смысла нету. Но и проект сразу создавать не будем, для начала полезем в SPL и посмотрим, что там припрятано для работы с USART.
Время традиционной вставки: поскольку компания STMicroelectronics прекратила поддержку библиотеки SPL, которая использовалась в этом курсе, я создал новый, посвященный работе уже с новыми инструментами, так что буду рад видеть вас там - STM32CubeMx. Кроме того, вот глобальная рубрика по STM32, а также статья на смежную тему из нового курса: STM32 UART. Прием и передача данных по UART в STM32CubeMx.
По большому счету, тут все похоже на то, что мы видели при работе с контроллерами STM32F10x (обязательно посмотрите). В файле stm32fxx_usart.h видим определение структуры, в которой мы зададим нужные нам параметры работы:
typedef struct { uint32_t USART_BaudRate; uint16_t USART_WordLength; uint16_t USART_StopBits; uint16_t USART_Parity; uint16_t USART_Mode; uint16_t USART_HardwareFlowControl; } USART_InitTypeDef;
Собственно, все что надо тут есть – и скорость и формат кадра, так что для настройки модуля USART в STM32F4xx нам надо лишь создать структуру USART_InitTypeDef, заполнить ее поля нужными значениями и передать ее в качестве параметра в функцию USART_Init(). Эта функция, как и все остальные функции, находятся в SPL в файле sm32f4xx_usart.c.
Для отправки данных в USART нужно вызвать функцию USART_SendData(), для приема - USART_ReceiveData(). В STM32 USART может работать в режиме, поддерживающем протокол передачи данных LIN, соответственно, для этого в Standard Peripheral Library есть ряд функций для работы с LIN. Вообще приемо-передатчик в контроллерах STM32, как и все остальное, довольно навороченный – там и обычные прием и передача, и, опять же, поддержка LIN, и работа совместно с DMA. Вот для всего этого есть множество готовых функций, ну и, конечно же, еще функции для работы с прерываниями и для проверки различных флагов.
Давайте уже на практике посмотрим, как все это работает. Напишем для STM32F4 пример для передачи данных с использованием соответствующего прерывания.
Итак, что вообще нужно сделать, чтобы USART запустился и начал работать:
- Во-первых включаем тактирование модуля.
- Затем включаем тактирование нужных портов контроллера (ножки Tx/Rx).
- Настраиваем пины для работы в режиме альтернативных функций.
- Запускаем модуль USART.
- И, наконец, включаем нужные прерывания и начинаем высылать/принимать данные.
Вроде бы все, что нужно упомянул, переходим к делу. Создаем новый проект и пишем программу:
/***************************************************************************************/ // Цепляем нужные файлы #include "stm32f4xx.h" #include "stm32f4xx_rcc.h" #include "stm32f4xx_gpio.h" #include "stm32f4xx_usart.h" /***************************************************************************************/ // Объявляем переменные GPIO_InitTypeDef gpio; USART_InitTypeDef usart; // Пусть нам надо передать 8 байт, объявим массив для этих данных uint8_t sendData[8]; uint8_t bytesToSend = 8; // Счетчик отправленных байт uint8_t sendDataCounter = 0; /***************************************************************************************/ // Инициализация всего, что нам надо void initAll() { // Включаем прерывания __enable_irq(); // Запускаем тактирование RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // Инициализация нужных пинов контроллера, для USART1 – PA9 и PA10 GPIO_StructInit(&gpio); gpio.GPIO_Mode = GPIO_Mode_AF; gpio.GPIO_Pin = GPIO_Pin_9; gpio.GPIO_Speed = GPIO_Speed_50MHz; gpio.GPIO_OType = GPIO_OType_PP; gpio.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA, &gpio); gpio.GPIO_Mode = GPIO_Mode_AF; gpio.GPIO_Pin = GPIO_Pin_10; gpio.GPIO_Speed = GPIO_Speed_50MHz; gpio.GPIO_OType = GPIO_OType_PP; gpio.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA, &gpio); // И вот еще функция, которой не было при работе с STM32F10x, но которую нужно вызывать при использовании STM32F4xx GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); // А теперь настраиваем модуль USART USART_StructInit(&usart); usart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; usart.USART_BaudRate = 9600; USART_Init(USART1, &usart); // Включаем прерывания и запускаем USART NVIC_EnableIRQ(USART1_IRQn); USART_Cmd(USART1, ENABLE); } /***************************************************************************************/ // Функция main() int main() { // Для начала заполним массив тестовыми данными for (uint8_t i = 0; i < 8; i++) { sendData[i] = i; } // Вызываем функцию инициализации initAll(); // Включаем прерывание по окончанию передачи USART_ITConfig(USART1, USART_IT_TC, ENABLE); while(1) { // А тут мы ничего не делаем, вся работа у нас в прерывании __NOP(); } } /***************************************************************************************/ // Обработчик прерывания void USART1_IRQHandler() { // Проверяем, действительно ли прерывание вызвано окончанием передачи if (USART_GetITStatus(USART1, USART_IT_TC) != RESET) { // Очищаем флаг прерывания USART_ClearITPendingBit(USART1, USART_IT_TC); // Отправляем байт данных USART_SendData(USART1, sendData[sendDataCounter]); // Увеличиваем счетчик отправленных байт sendDataCounter++; // Если отправили все данные, начинаем все сначала if (sendDataCounter == bytesToSend) { sendDataCounter = 0; } } } /***************************************************************************************/
Вот и все! Микроконтроллер начинает постоянно по кругу высылать наши данные во внешний мир. Таким образом, с передачей мы разобрались. В следующей статье сразу же без лишних слов напишем пример для приема данных.