Программирование STM32F4. USART. Пример программы.

Совсем недавно мы начали использовать микроконтроллеры STM32F4xx (вот ссылочка), так что надо продолжать это хорошее дело ) Сегодня посмотрим , как работает в 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 запустился и начал работать.

1. Во-первых включаем тактирование модуля.
2. Затем включаем тактирование нужных портов контроллера (ножки Tx/Rx).
3. Настраиваем пины для работы в режиме альтернативных функций.
4. Запускаем модуль USART.
5. И наконец, включаем нужные прерывания и начинаем высылать/принимать данные.

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

/*******************************************************************/
// Цепляем нужные файлы
#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;
        }
    }
}  
 
 
 
/*******************************************************************/

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

Понравилась статья? Поделись с друзьями!

Программирование STM32F4. USART. Пример программы.: 31 комментарий
  1. Это хорошо что есть люди которым не только интересно самому разобраться, но и находят время чтоб выложить свои достижения, пояснить профанам еще))) успехов!!!

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

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

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

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

    • Но я пока правда даже не представляю, когда у меня предвидится свободное время..очень много работы сейчас

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

    • День добрый )
      Вообще под discovery все должно с ходу заработать. А если просто светодиод попробовать заставить помигать?

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

        • Да нет, в Keil’e нет ничего специфического в начальной конфигурации, по идее в CooCox’е то же самое должно происходить по умолчанию на этапе настройки

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

    • Для того, чтобы гарантировать то, что все неиспользуемые поля структуры будут заполнены дефолтными значениями

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

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

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

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

  12. Ну так забей 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;

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

  13. Ну и если на прерываниях, то разные «Хендлеры» для вызова прерываний на прием со 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

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

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

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

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

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *