STM32. Библиотека для приема и передачи данных по USART.

Недавно я упомянул (в статье про 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 🙂 В общем скачиваем:

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

/***************************************************************************************/
// Обратите внимание, что никакие другие файлы не надо тут прописывать, все 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():

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

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

Поделиться!

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

Вот класс а то упыхался уже с этим uart -ом разбираться!
Спасибо огромное буду пользоваться!

roma1141
7 лет назад

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

roma1141r1
7 лет назад

Проэкт в cocox сейчас выложу одну минутку… Спасибо!

roma1141r1
7 лет назад

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

roma1141r1
7 лет назад

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

roma1141r1
7 лет назад

Stm32f4 плата discovery

roma1141r1
7 лет назад

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

roma1141r1
7 лет назад

СПАСИБО пробую!

roma1141r1
7 лет назад

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

roma1141r1
7 лет назад

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

roma1141r1
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);
}

roma1141r1
7 лет назад

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

roma1141r1
7 лет назад

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

roma1141r1
7 лет назад

OK, Спасибо что помогаете!

roma1141r1
7 лет назад

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

roma1141r1
7 лет назад

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

roma1141r1
7 лет назад

Теперь другая проблемма, если не отвлекаю глянте быстренько навскидку что не так:
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 повесить, вот немогу никак.

Serg
Serg
Reply to  roma1141r1
7 лет назад

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);

roma1141r1
7 лет назад

Ага пробую дальше..

Василий
Василий
7 лет назад

А Вы пробовали портировать 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

Василий
Василий
Reply to  Aveal
7 лет назад

присутсвует. Прописал в вкладке 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

Serg
Serg
Reply to  Василий
7 лет назад

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

Serg
Serg
7 лет назад

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

Serg
Serg
7 лет назад

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

tester
tester
6 лет назад

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

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

Geka
Geka
6 лет назад

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

Geka
Geka
6 лет назад

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

Geka
Geka
6 лет назад

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

Geka
Geka
6 лет назад

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

Ясь
Ясь
Reply to  Aveal
3 лет назад

Столкнулся с тем, что библиотека перестает работать, если включить любую оптимизацию (gcc, Coocox). Есть пути решения проблемы?

Ясь
Ясь
Reply to  Aveal
3 лет назад

Передача не работает, приходит единственный левый байт и на этом все стопорится. Прием просто не проверял.

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

Profile Profile Profile Profile Profile
Vkontakte
Twitter

Язык сайта

Август 2020
Пн Вт Ср Чт Пт Сб Вс
 12
3456789
10111213141516
17181920212223
24252627282930
31  

© 2013-2020 MicroTechnics.ru