Итак, совсем недавно мы познакомились с приемо-передатчиком USART в микроконтроллерах STM32F4 и создали пример для передачи данных в окружающий мир (вот). Как и обещал, сегодня разберемся с приемом данных. Теории не будет, все уже вроде обсудили при работе с передачей, так что без лишних прелюдий переходим сразу к написанию программы )
Время традиционной вставки: поскольку компания STMicroelectronics прекратила поддержку библиотеки SPL, которая использовалась в этом курсе, я создал новый, посвященный работе уже с новыми инструментами, так что буду рад видеть вас там - STM32CubeMx. Кроме того, вот глобальная рубрика по STM32, а также статья на смежную тему из нового курса: STM32 UART. Прием и передача данных по UART в STM32CubeMx.
Для начала рассмотрим общую последовательность действий, необходимых для запуска USART в STM32F4 и настройки его для работы в качестве приемника:
- Работаем с тактированием – включаем тактирование приемо-передатчика, а заодно и тактирование порта, который отвечает за ножки Rx/Tx.
- Сначала настраиваем нужные ножки микроконтроллера, а затем и сам USART.
- Включаем прерывания – функция NVIC_EnableIRQ() и запускаем USART - USART_Cmd().
- Наконец включаем прерывание, которое нам в данном случае понадобится, то есть прерывание по приему данных - для этого нам пригодится функция USART_ITConfig().
Вот в принципе и все. Вся работа будет в прерывании, соответственно необходимо будет реализовать соответствующий обработчик. Будем использовать, как и при передаче данных, модуль USART1, так что многое будет точно таким же, как и в том примере.
/***************************************************************************************/ // Подключаем файлы #include "stm32f4xx.h" #include "stm32f4xx_rcc.h" #include "stm32f4xx_gpio.h" #include "stm32f4xx_usart.h" /***************************************************************************************/ // Объявляем переменные GPIO_InitTypeDef gpio; USART_InitTypeDef usart; // Будем принимать 16 байт, к примеру uint8_t receivedData[16]; uint8_t bytesToReceive = 16; // Счетчик принятых байт uint8_t receivedDataCounter = 0; // Пока все идет точно также, как и в случае с передачей /***************************************************************************************/ // Инициализируем все подряд void initAll() { // Глобальное разрешение прерываний __enable_irq(); // Тактирование, куда ж без него-то RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // Настраиваем ножки контроллера, тут все понятно 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); // Обязательно вызываем эту функцию 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() { // Тут нам нужно лишь вызвать функцию инициализации и запустить процесс – то есть включить прерывание по приему данных initAll(); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); while(1) { __NOP(); } } /***************************************************************************************/ // Прерывание void USART1_IRQHandler() { // Убеждаемся, что прерывание вызвано новыми данными в регистре данных if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { // Чистим флаг прерывания USART_ClearITPendingBit(USART1, USART_IT_RXNE); // То ради чего все затеяли – принимаем данные ) receivedData[receivedDataCounter] = USART_ReceiveData(USART1); // Приняли? Увеличиваем значение счетчика! receivedDataCounter ++; // Приняли 16 байт – выключаем if (receivedDataCounter == bytesToReceive) { USART_ITConfig(USART1, USART_IT_RXNE, DISABLE); } } } /***************************************************************************************/
Вот такой получился пример. За исключением обработчика прерывания все также как и с передачей данных, можно было, в принципе, и в одну статью все уместить. Отмечу, кстати вызов функции GPIO_PinAFConfig():
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
Я когда первый раз работал в STM32F4 с USART’ом, упустил из виду то, что надо вызывать эту функцию и некоторое время не мог понять, почему ничего не работает... После STM32F10x казалось, что достаточно вот этого:
gpio.GPIO_Mode = GPIO_Mode_AF;
Но нет, тут все чуть иначе. Так что при работе с любой периферией в STM32F4 не забываем про вызов функции GPIO_PinAFConfig(). Что еще можно сказать про USART? Да вроде бы все… Так что, если возникли какие-нибудь вопросы, обязательно спрашивайте в комментариях, а на сегодня это пожалуй все, до скорого!
P. S. Я тут кстати себе сделал небольшую библиотеку для ускорения работы с USART’ом, на днях обязательно выложу, буду рад, если кому-нибудь пригодится.