STM32F4 и USART. Настройка и передача данных.

Совсем недавно мы начали использовать микроконтроллеры семейства STM32F4 (вот ссылочка), так что надо продолжать это хорошее дело 🙂 Сегодня посмотрим , как работает в STM32F4 USART, ну и, как обычно, создадим какой-нибудь проект для примера. Ковыряться в регистрах, пожалуй, не будем, там особо интересного ничего не найдем, да и все отлично описано в даташитах, так что останавливаться на этом смысла нету. Но и проект сразу создавать не будем, для начала полезем в Standard Peripheral Library и посмотрим, что там припрятано для работы с USART.

По большому счету, тут все похоже на то, что мы видели при работе с контроллерами 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()
{
	// Для начала заполним массив передаваемыми данными
	sendData[0] = 0x11;
	sendData[1] = 0x22;
	sendData[2] = 0x33;
	sendData[3] = 0x44;
	sendData[4] = 0x55;
	sendData[5] = 0x66;
	sendData[6] = 0x77;
	sendData[7] = 0x88;

	// Вызываем функцию инициализации
	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;
		}
	}
}  


/***************************************************************************************/

Вот и все! Микроконтроллер начинает постоянно по кругу высылать наши данные во внешний мир. Таким образом, с передачей мы разобрались. В следующей статье сразу же без лишних слов напишем пример для приема данных, так что заходите, читайте, приводите друзей 😉

Поделиться!

Подписаться
Уведомление о
guest
31 Комментарий
старее
новее большинство голосов
Inline Feedbacks
View all comments
Дмитрий
Дмитрий
7 лет назад

Это хорошо что есть люди которым не только интересно самому разобраться, но и находят время чтоб выложить свои достижения, пояснить профанам еще))) успехов!!!

Алексей
Алексей
7 лет назад

Не могу выразить признательность вашим трудам. Огромное человеческое спасибо !!! Мне недавно поставили задачу : к контролеру stm32f407vgt6 подключить дисплей + клавиатуру и написать управление.
Дали STM32f4 – Discavery и сказали : давай к июлю нужно разобраться и сделать. У меня выпали глаза из глазниц и волосы из фолликул, так как раньше не имел удовольствия работать с контролерами, только прошивки правил для Ethernet – платок. В общем благодаря вам начали появляться хоть кусочки этой мозаики в моей голове и приходит хоть какое-то понимание … Если можно потом по терзаю вас вопросами, когда они из общего разряда “АААААА как это все сделать !?!!?!” перейдут в более конкретный, осмысленый разряд.

Ktif
7 лет назад

Доброго времени суток. Если я правильно понял то на РА9 – выходят данные, а на РА10 – 1ца если смотреть осциллографом так?

Ярослав
Ярослав
6 лет назад

Здравствуйте, у Вас хорошие статьи.
Не могли бы Вы помочь мне при освоении карты Ethernet (DP83848) под эту Discovery?
Ну никак платка работать не хочет. Уже все примеры, которые были, перепробовал, перечитывал множество топиков и форумов – результата не дало.
Если можете, дайте код с подробными объяснениями, схему подключения, что нибудь.
Спасибо.

Ярослав
Ярослав
Reply to  Ярослав
6 лет назад

e-mail: rozmathplus@gmail.com
(если можете сбросить какие-то файлы)

Ярослав
Ярослав
Reply to  Ярослав
6 лет назад

Проекти пишу в IAR, CoIDE

Ярослав
Ярослав
6 лет назад

Буду очень благодарен. Для ускорения написания Вами статьи, могу сбросить собранный мною материал. В некоторых проектах впечатление, что “вот-вот” заработает, но недостаток опыта не позволяет решить проблемы или компиляции и др..

PAvel
PAvel
6 лет назад

Здравствуйте . Очень нравится ваш блог ссылка в избранных уже:) Пытаюсь завести USART по вашему примеру (CooCox) но STM32f4 — Discavery молчит ничего не передает . Пытался с другими примерами тоже никак. Есть вопрос про тактирование ,что плата по умолчанию тактируется от 8МГЦ это где то нужно поправлять?

PAvel
PAvel
Reply to  Aveal
6 лет назад

диодиками моргаю нормально, находил исходник где генерируют файл через макрос с ним работает вот у меня возникает вопрос, что может такая загвоздка и у меня, в KEIL может сразу проект под плату Discovery stm34f4 создается и автоматом настраивает, в кокосе под чип по дефаулту.

Виталик
Виталик
6 лет назад

Привет!
Зачем нужно писать GPIO_StructInit(&gpio);
Включаем все ноги на вход, а потом две из них на AF? Зачем?

ATH
ATH
6 лет назад

Здравствуйте, Вы сделали обработчик прерывания, которые будет вызываться по окончанию приема, но чтобы начать процесс передачи вроде надо же что то передать, или я что то упустил?

ATH
ATH
6 лет назад

по окончанию передачи*

Виталик
Виталик
6 лет назад

до речі
1. закрийте тіло main-a
2. програма не працюватиме, якщо не причепитись до правильних ніг b6 b7, а не а9 а10.
3. дякую)

CROW
CROW
6 лет назад

Хочу задействовать два USART в МК STM32F4, настраиваю два USARTA`а но работает тока один почему так? Нужно принимать данные по USART 2 затем сохранять их в памяти и со скоростью 9600 отправлять из USART6 в ПК.

CROW
CROW
6 лет назад

Товарищи как одновременно принимать данные по USART2 на скорости 115200 сохранять в память и передавать на ПК с USART6 на скорости 9600?

ali00ff
5 лет назад

Ну так забей 2 отдельных инит. структуры
к примеру :
USART_InitTypeDef _MY_USART_INIT2;
USART_InitTypeDef _MY_USART_INIT6;
точнее 4, т.к. GPIO нежно как AF сконфигурировать, значит
GPIO_InitTypeDef _GPIO_AF_USART2_INIT;
GPIO_InitTypeDef _GPIO_AF_USART6_INIT;

Дальше все так же как в статье выше, НО

в той что инициализирует USART2
_MY_USART_INIT2.USART_BaudRate = 115200;
_MY_USART_INIT2.USART_Mode = USART_Mode_Rx;
———————————————————————————–
Ну а ту что USART 6
_MY_USART_INIT2.USART_BaudRate = 9600;
_MY_USART_INIT2.USART_Mode = USART_Mode_Tx;

//——————————————
А в остальном все так же.

ali00ff
5 лет назад

Ну и если на прерываниях, то разные “Хендлеры” для вызова прерываний на прием со 2ого и передачи с 6ого.

Описываешь их в маин, как ф-ции
void USART2_IRQHandler(void)
{
Твой прием
}

void USART6_IRQHandler(void)
{
твоя передача
}

А в инициализации
тож 2 раза 🙂
NVIC_EnableIRQ(USART2_IRQn);
NVIC_EnableIRQ(USART6_IRQn);
———————————————-
все “хендлеры”, ака обработчики при необходимости смотрите. в startup_stm32f4xx.s

там вот такого плана будет :
DCD SPI1_IRQHandler ; SPI1
DCD SPI2_IRQHandler ; SPI2
DCD USART1_IRQHandler ; USART1
DCD USART2_IRQHandler ; USART2
DCD USART3_IRQHandler ; USART3

========================================
К автору и хозяину статьи – надеюсь не помешал ?, просто рад помочь в твоем нужном, альтруистическом деле 🙂

Марк
Марк
5 лет назад

Здравствуйте! Пытался повторить данный пример, и столкнулся с небольшой проблемой. После передачи 0 байта массива, регистр SR заполняется нулями, передача останавливается. Тот же эффект если передавать данные в while
while(1)
{

for(i=0;iSR & USART_SR_TC));
}
}

Марк
Марк
5 лет назад

Прошу прощения
while(1)
{
for(i=0;iSR&USART_SR_TC));
}
}

Денис
4 лет назад

Помогите пожалуйста с такой проблемой:
Я сделал программу основываясь на вашем примере, но есть косяк – постоянно срабатывает прерывание на окончание передачи(даже если ничего не передавал), оно срабатывает настолько часто, что никакой другой код не выполняется.
Подскажите как поступать в данном случае?!

Присоединяйтесь!

Profile Profile Profile Profile Profile
Vkontakte
Twitter

Язык сайта

Июнь 2020
Пн Вт Ср Чт Пт Сб Вс
« Май    
1234567
891011121314
15161718192021
22232425262728
2930  

© 2013-2020 MicroTechnics.ru