Библиотека для работы с USART в STM32.

Недавно я упомянул (в статье про USART) о библиотеке, которую я тут сваял. Мне она очень пригодилась и помогла, так что решил поделиться, вдруг кому то еще будет полезна ) Так что, сегодня просто кратенько расскажу что там и как сделано, ну и, самое главное, рассмотрим пример использования.

Итак, состоит библиотека из двух файлов – заголовочного, ну и собственно файла с исходным кодом. Открываем файл MT_STM32F4xx_USART.h. Здесь мы должны выбрать номер модуля USART, который мы будем использовать в нашей программе:

// Library configuration
// Select USART number
#define MT_USART_MODULE_IN_USE				(USART_MODULE6)

Сейчас соответственно выбран USART6, можно поменять это значение на USART_MODULE1, USART_MODULE2 или USART_MODULE3. Там еще кстати надо задать скорость, по умолчанию стоит 9600 б/с:

//Set USART baudrate
#define MT_USART_BAUDRATE					(9600)

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

MT_USART_Init();

Для передачи и приема данных соответственно функции:

MT_USART_SendData(uint8_t *pSendData, uint8_t nNumOfDataToSend)
MT_USART_ReceiveData(uint8_t* pReceivedData, uint8_t nNumOfDataToReceive)

В качестве параметров передаем в функции указатель на буфер для передаваемых/принимаемых данных, а также количество байт, которые будем отсылать/принимать. Чуть не забыл! Передача и прием данных происходит в прерываниях, обработчики уже написаны и содержатся все в том же файле, что и функции. Теперь вроде все, переходим к примеру )

Создаем новый проект для STM32F4, например, и добавляем помимо файлов CMSIS и SPL еще и два файла библиотеки, которую я назвал, кстати MT_STM32F4xx_USART Library 😉 В общем скачиваем:

для STM32F4 — MT_STM32F4xx_USART Library
для STM32F10x — MT_STM32F10x_USART Library

И добавляем файлы в проект. Получили пустой проект, пишем код. Для начала подключаем файл:

/*******************************************************************/
// Обратите внимание, что никакие другие файлы не надо тут прописывать,
// все include’ы уже содержатся внутри библиотеки
#include "MT_STM32F4xx_USART.h"
 
 
 
/*******************************************************************/
// Объявляем переменные - массивы для хранения данных и переменные
// для количества байт
uint8_t sendData[8];
uint8_t receivedData[10];
uint8_t num = 8;
uint8_t numRx = 10;
 
 
 
/*******************************************************************/

Пусть нам надо отправить запрос какому-то устройству (8 байт), и в ответ получить данные (10 байт).

/*******************************************************************/
int main(void)
{	
    // Заполняем массив данными, которые будем отправлять 
    sendData[0] = 0x00;
    sendData[1] = 0x11;
    sendData[2] = 0x22;
    sendData[3] = 0x33;
    sendData[4] = 0x44;
    sendData[5] = 0x55;
    sendData[6] = 0x66;
    sendData[7] = 0x77;
    // Инициализация
    MT_USART_Init();
    // Отправка
    MT_USART_SendData(sendData, num);
    // Ждем, пока передача завершится
    while(!MT_USART_ReadyToExchange);
    // Прием
    MT_USART_ReceiveData(receivedData, numRx);
    while(1)
    {
    }
}
 
/*******************************************************************/

Вот и все! В итоге у нас программа сократилась до вызова трех функций, ну и объявления пары переменных ) По-моему, удобно 😉

Если мы запустили передачу функцией MT_USART_SendData(), то по окончанию передачи у нас флаг MT_USART_ReadyToExchange станет равным 1, аналогично и для приема данных. Так что, запустили процесс, все крутится в прерываниях, а мы только ждем, пока взлетит наш флаг.

Библиотека для STM32F10x содержит в себе то же самое, принципиальных различий нет, поэтому не будем отдельно обсуждать ) Выкладываю еще два готовых проекта для Keil, в которых все уже подключено и настроено, осталось лишь написать функцию main() 😉

Ссылки:
Проект в Keil для STM32F4
Проект в Keil для STM32F10x

Итак, вроде бы все рассказал и показал ) Надеюсь, что кому-нибудь материал и, собственно, библиотека будут полезны =)

P. S. Я не тестировал библиотеку вдоль и поперек, пользовался только тем, что мне было нужно в конкретной задаче, поэтому, если что-то вдруг будет работать не так, как надо, не обижайтесь, пишите, будем исправлять )

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

Библиотека для работы с USART в STM32.: 50 комментариев
  1. Вот пытался связать 2 stm32 одна циклически посылает с помощью uarta данные а вторая должна их принимать но она принимает в receivedData
    0*89 а посылаю 0*12 вопрос как организовать прием на 2 stm32 соединил rx-tx tx-rx но ничего не выходит… поможете?

  2. Вот ссылка http://rusfolder.com/36099571
    Там переменная в самом начале MASTER если она 1 то stm ка должна опрашивать другие а если 0 то она должна stm ке мастеру отвечать или хотяб данные от нее принимать….

  3. Только не пинайте сильно за тупой код я только разбираюсь и делаю проект умного дома там все лишнее повыкидывал пока искал откуда глюки..
    Если интересует я могу весь проект выложить там работа с аналоговым датчиком температуры и прерывание по кнопке… вот застопроился с обменом между 2 стм ками и все.. 2 месяца пробую и modbus прикрутить и 1 wire ничего пока думал хотяб uart заработает ан нет…

  4. Вот я как хотел одна стм отправляет запрос например 12 другая стм принимает данные видит 12 и что-то делает к примеру моргает светодиодом о посылает подтверждение что приняла данные ..
    А не получается принять эти данные я там отправку и прием сократил до 1 байта пока думал где глюк.
    Я просто принципиально не знаю как организовывают прием на ведомых устройствах.

  5. хм ничего не изменилось в receivedData[0] по прежнему 0x89 хотя с другой стм ки передаю sendData[0] 0x12…

  6. может я принципиально неправильно принимаю данные (мастер=1 это 1-ая стм ка она соединенна через usart со второй в которой мастер =0)
    провода tx и rx помененны местами rx -> tx а tx->rx.
    не понимаю почему вторая не принимает кстати если принимаю 8 байт то весь массив заполняется от [0]
    до [7] с каждым тактом значениями 0×89 и далее ничего не меняется..

    • Попробуй просто в один контроллер залить программу, в которой только прием и больше вообще ничего нет, а в другой только передачу, тогда понятно будет, есть ли проблема в линии связи самой

  7. в 1 ом— if (MASTER==0){

    // Заполняем массив данными, которые будем отправлять
    sendData[0] = 0x15;
    sendData[1] = 0x88;
    sendData[2] = 0x00;
    sendData[3] = 0x88;
    sendData[4] = 0x88;
    sendData[5] = 0x00;
    sendData[6] = 0x00;
    sendData[7] = 0x77;
    MT_USART_ReceiveData(receivedData, numRx);

    // Прием

    if (receivedData[0]==0x12){
    // Отправка
    MT_USART_SendData(sendData, num);
    // Ждем, пока передача завершится
    while(!MT_USART_ReadyToExchange);
    GPIO_ToggleBits(GPIOD, BLUE_LED);
    // MT_USART_ReceiveData(receivedData, numRx);
    }

    во втором—if (MASTER==1){

    // Заполняем массив данными, которые будем отправлять
    sendData[0] = 0x12;
    sendData[1] = 0x77;
    sendData[2] = 0x00;
    sendData[3] = 0x10;
    sendData[4] = 0x20;
    sendData[5] = 0x00;
    sendData[6] = 0x00;
    sendData[7] = 0x10;

    // Отправка
    MT_USART_SendData(sendData, num);
    // Ждем, пока передача завершится
    while(!MT_USART_ReadyToExchange);
    // Прием
    // MT_USART_ReceiveData(receivedData, numRx);
    }

  8. то же самое даже оставил 1 провод уже, принимается 0×89 в hex в receivedData[0] а в остальных 0×00..

  9. ага спасибо! буду пока разбираться если разберусь обязательно отпишусь!

    • Хорошо) Я где-то около 8 завтра дома буду, соответственно где-то в это время, может чуть попозже, попробую

  10. Все разобрался!
    Проблемма была в том что на stm32f4discovery на USART3 PC10 PC11 просто висит какая то железка usb может или просто непропай перешел на USART2 все заработало!!!!!

  11. Да я просто перебирал порты + там у меня преобразователь интерфейсов висит в 485…

  12. Теперь другая проблемма, если не отвлекаю глянте быстренько навскидку что не так:
    void USART2_RX_Channel4_Stream5_DMA1_Config(void)
    {
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

    DMA_InitTypeDef dma;
    DMA_StructInit(&dma);

    DMA_DeInit(DMA1_Stream5);

    dma.DMA_Channel = DMA_Channel_4;
    dma.DMA_DIR = DMA_DIR_PeripheralToMemory;
    dma.DMA_FIFOMode = DMA_FIFOMode_Disable;
    dma.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    dma.DMA_Memory0BaseAddr = (uint32_t)&rx_buffer;
    dma.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
    dma.DMA_Mode = DMA_Mode_Circular;
    dma.DMA_PeripheralBaseAddr = (uint32_t)&(USART2->DR);
    dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    dma.DMA_Priority = DMA_Priority_Medium;

    DMA_Init(DMA1_Stream5, &dma);

    USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);

    DMA_Cmd(DMA1_Stream5, ENABLE);

    DMA_ITConfig(DMA1_Stream5, DMA_IT_TC | DMA_IT_HT, ENABLE );
    }

    void DMA1_Stream5_IRQHandler(void)
    {
    if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_TCIF5))
    {
    USART_DMACmd(USART2, USART_DMAReq_Rx, DISABLE);
    DMA_Cmd(DMA1_Stream5, DISABLE);
    }
    }

    В буфере rx_buffer пусто, событие не возникает что я не так делаю убился об стенку уже…..
    В обычном режиме с помошью вашей библиотеки все принимается но понял что надо прием на DMA повесить, вот немогу никак.

    • Навскидку то все вроде нормально)) Но так сходу редко когда удается понять в чем именно проблема

    • 1. После команды деинициализации канал DMA желательно дождаться файктического сброса: while(DMA_GetCmdStatus(DMA1_Stream5) != DISABLE){}
      2. DMA_Memory0BaseAddr требует указателя. Наверняка rx_buffer инициализировался массивом, а не указателем. Тогда указывать нужно DMA_Memory0BaseAddr = (uint32_t)rx_buffer;
      либо
      DMA_Memory0BaseAddr = (uint32_t)&rx_buffer[0];

      3. Прерывание включено, а контроллер прерываний NVIC не настроен. Напиример
      NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);

  13. А Вы пробовали портировать FreeRTOS 7.4.1 на STM32F4 (Discovery M4)? Я пытаюсь,но ничего не получаеться,все делаю по аналогии с Вашей методике для F103, но не могу собрать . Не видит файла «FreeRTOS.h»-хотя путь правильно указан. И море ошибок:

    STM32F4.axf: Error: L6218E: Undefined symbol pvPortMalloc (referred from croutine.o).
    STM32F4.axf: Error: L6218E: Undefined symbol ulPortSetInterruptMask (referred from croutine.o).
    STM32F4.axf: Error: L6218E: Undefined symbol vPortClearInterruptMask (referred from croutine.o).
    STM32F4.axf: Error: L6218E: Undefined symbol vPortEnterCritical (referred from queue.o).
    STM32F4.axf: Error: L6218E: Undefined symbol vPortExitCritical (referred from queue.o).
    STM32F4.axf: Error: L6218E: Undefined symbol vPortFree (referred from queue.o).
    STM32F4.axf: Error: L6218E: Undefined symbol vPortYield (referred from queue.o).
    STM32F4.axf: Error: L6218E: Undefined symbol pxPortInitialiseStack (referred from tasks.o).
    STM32F4.axf: Error: L6218E: Undefined symbol vApplicationIdleHook (referred from tasks.o).
    STM32F4.axf: Error: L6218E: Undefined symbol vApplicationStackOverflowHook (referred from tasks.o).
    STM32F4.axf: Error: L6218E: Undefined symbol vApplicationTickHook (referred from tasks.o).
    STM32F4.axf: Error: L6218E: Undefined symbol vPortEndScheduler (referred from tasks.o).
    STM32F4.axf: Error: L6218E: Undefined symbol xPortStartScheduler (referred from tasks.o).
    Target not created

      • присутсвует. Прописал в вкладке Define : STM32F4XX USE_STDPERIPH_DRIVER . Теперь все файлы видны. Но ошибки остались:
        Rebuild target ‘STM32F4’
        assembling startup_stm32f4xx.s…
        compiling system_stm32f4xx.c…
        compiling stm32f4xx_rcc.c…
        compiling stm32f4xx_gpio.c…
        compiling main.c…
        compiling croutine.c…
        compiling list.c…
        compiling queue.c…
        compiling tasks.c…
        compiling timers.c…
        linking…
        STM32F4.axf: Error: L6218E: Undefined symbol pvPortMalloc (referred from croutine.o).
        STM32F4.axf: Error: L6218E: Undefined symbol ulPortSetInterruptMask (referred from croutine.o).
        STM32F4.axf: Error: L6218E: Undefined symbol vPortClearInterruptMask (referred from croutine.o).
        STM32F4.axf: Error: L6218E: Undefined symbol vPortEnterCritical (referred from queue.o).
        STM32F4.axf: Error: L6218E: Undefined symbol vPortExitCritical (referred from queue.o).
        STM32F4.axf: Error: L6218E: Undefined symbol vPortFree (referred from queue.o).
        STM32F4.axf: Error: L6218E: Undefined symbol vPortYield (referred from queue.o).
        STM32F4.axf: Error: L6218E: Undefined symbol pxPortInitialiseStack (referred from tasks.o).
        STM32F4.axf: Error: L6218E: Undefined symbol vApplicationIdleHook (referred from tasks.o).
        STM32F4.axf: Error: L6218E: Undefined symbol vApplicationStackOverflowHook (referred from tasks.o).
        STM32F4.axf: Error: L6218E: Undefined symbol vApplicationTickHook (referred from tasks.o).
        STM32F4.axf: Error: L6218E: Undefined symbol vPortEndScheduler (referred from tasks.o).
        STM32F4.axf: Error: L6218E: Undefined symbol xPortStartScheduler (referred from tasks.o).
        Target not created

        • Ошибки, скорее всего, связаны с отсутвием файлов портирования(port.c portmacro.c и заголовочники). Файлы индивидуальны для каждоый платформы и, например, порт на STM32F1xx не подойдёт для STM32F4xx. Файлы портирования можно найти в демоприложених к ОС.

  14. Я тут так-то мимо проходил, но поскольку имею опыт работы с stm32 и уже сталкивался с необходимостью реализации подобых функций, то посоветую немного. Конекретно по данной статье: оптимальный и правильный метод реализации — через контроллер DMA. Это избавит от постоянного прыгания за каждым байтом по два раза в прерывание и вообще DMA замечательная штука.
    В комментариях автора видел упоминание об умном доме и отсутвии опыта работы с FreeRTOS. Тем не менее эти 2 вещи очень близки. Применение ОСРВ значительно облегчит создание многозадачной системы.
    Тут вот ещё в комментарих некоторые описываются свои проблемы. Когда-то я тоже сталкивался с чем-то похожим(«чё-та не работает почему-та») и открыл для себя просто волшебный универсальный метод решения проблем. Как бы банально не звучало, и какой бы тратой времени это ни казалось, но чтение документации и примеров к софту можно самостоятельно решить большинство проблем. Более того, многие проблемы просто не появятся. Я сам это проходил и поэтому советую тут вам, сердечно.

    • Про проблемы — в точку) сам всегда пользовался этим же «методом» А чего там про умный дом? я не очень понял что-то)

  15. А это я ошибся. Мне показалось, что видел здесь где-то упоминание об умном доме и тут же, что FreeRTOS не заведена. Но я не про умный дом, а про то, что программа рано или поздно разрастается. И лучше изначально предусмотреть масштабируемость и гибкость. Вот FreeRTOS очень хороший инструмент для этого. Всем кто занимается микроконтроллерами обязательно нужно изучить основы операционных систем реального времени. Где-то в сети гуляет цикл статей по FreeRTOS и документация, материалы объёмные но очень полезные.

    • Полностью согласен, у нас на работе, например, уже вообще абсолютно все ПО на ОСРВ реализовано

  16. В объявлении прерывания на USART3 опечатка, проверяется USRT2.
    void USART3_IRQHandler()
    {

    if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
    ….

  17. Добрый день. У меня STM32F429I-Discovery и дальномер URM37. Подкдючение по USART. Надо отправить четыре байта 0х22 0х00 0х00 0х22 и получить четыре байта с информцией о расстоянии. Не удается получить ничего. Дальномер молчит. Установки USARTа соответствуют. Работаю через USART1. Отправку проверял USART2, байты уходят. Регистр данных пустой (нет ответа). Пробовал работать через вашу либу (по прерываниям) и напрямую. Не могу понять причину. Можете дать совет?

  18. Попробовал подключить у друзей к Ардуино. Все заработало с полпинка. Посмотрели осцилом посылку — у Ардуино пачка сжата более чем в два раза. Получается проблема в баудрейте. Но у меня он установлен как положено в 9600 (даташит на датчик). В чем может быть проблема? Может где частота стоит не та?

  19. Тогда вопрос по настройке баудрейта. Я считал, что при установке baudrate=9600, контроллер настравает его с учетом частоты шины. Если не так, то как правильно настроить?

    • Да, SPL настраивает исходя из тактовой частоты шины, по идее все должно работать корректно

  20. Вобщем получилось следующее:
    1) путем прогонки в цикле баудрейта, получили значение около 30000 (при рабочем 9600). В 3,125 (приблизительно) раз надо установить баудрейт больше. С чем это связано мне не понятно. Может подскажете в чем причина?
    2) при использовании Вашей библиотеки была проблема с наложением байтов (ответ приходит из четырех байтов). При этом получали только один байт — остальные пропадали. Путем установки задержки после процедуры MT_USART_ReceiveData() проблема решилась.
    Сейчас датчик работает вполне сносно. Спасибо за помощь

    • Это не очень хорошее решение проблемы… Надо смотреть, что неверно с тактированием. Может в переменной HSE_VALUE стоит не та частота, как вариант.

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

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