Top.Mail.Ru

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

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

Время традиционной вставки: поскольку компания STMicroelectronics прекратила поддержку библиотеки SPL, которая использовалась в этом курсе, я создал новый, посвященный работе уже с новыми инструментами, так что буду рад видеть вас там - STM32CubeMx. Кроме того, вот глобальная рубрика по STM32, а также статья на смежную тему из нового курса: STM32 UART. Прием и передача данных по UART в STM32CubeMx.

Итак, состоит библиотека из двух файлов – заголовочного, ну и собственно файла с исходным кодом. Открываем файл 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 еще и два файла библиотеки:

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

/***************************************************************************************/
// Обратите внимание, что никакие другие файлы не надо тут прописывать, все 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)
{
	// Заполняем массив данными, которые будем отправлять
	for (uint8_t i = 0; i < 8; i++)
	{
		sendData[i] = i;
	}
	
	// Инициализация
	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, в которых все уже подключено и настроено:

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

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

Подписаться
Уведомить о
guest

54 комментариев
Старые
Новые
Межтекстовые Отзывы
Посмотреть все комментарии
roma1141
10 лет назад

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

roma1141
10 лет назад

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

roma1141r1
10 лет назад

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

roma1141r1
10 лет назад

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

roma1141r1
10 лет назад

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

roma1141r1
10 лет назад

Stm32f4 плата discovery

roma1141r1
10 лет назад

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

roma1141r1
10 лет назад

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

roma1141r1
10 лет назад

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

roma1141r1
10 лет назад

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

roma1141r1
10 лет назад

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

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

roma1141r1
10 лет назад

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

roma1141r1
10 лет назад

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

roma1141r1
10 лет назад

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

roma1141r1
10 лет назад

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

roma1141r1
10 лет назад

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

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

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

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

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

Василий
Василий
Ответ на комментарий  Aveal
10 лет назад

присутсвует. Прописал в вкладке 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
Ответ на комментарий  Василий
10 лет назад

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

Serg
Serg
10 лет назад

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

Serg
Serg
10 лет назад

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

tester
tester
10 лет назад

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

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

Geka
Geka
10 лет назад

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

Geka
Geka
10 лет назад

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

Geka
Geka
10 лет назад

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

Geka
Geka
10 лет назад

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

Ясь
Ясь
Ответ на комментарий  Aveal
6 лет назад

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

Ясь
Ясь
Ответ на комментарий  Aveal
6 лет назад

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

54
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x