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
2 лет назад

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

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

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

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

Profile Profile Profile Profile Profile
Vkontakte
Twitter

Язык сайта

Июль 2020
Пн Вт Ср Чт Пт Сб Вс
« Июн    
 12345
6789101112
13141516171819
20212223242526
2728293031  

© 2013-2020 MicroTechnics.ru