Недавно я упомянул (в статье про 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 еще и два файла библиотеки:
- Для 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) { // Заполняем массив данными, которые будем отправлять 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. Я не тестировал библиотеку вдоль и поперек, пользовался только тем, что мне было нужно в конкретной задаче, поэтому, если что-то вдруг будет работать не так, как надо, не обижайтесь, пишите, будем исправлять )
Вот класс а то упыхался уже с этим uart -ом разбираться!
Спасибо огромное буду пользоваться!
Не за что, главное, чтобы все работало =)
Вот пытался связать 2 stm32 одна циклически посылает с помощью uarta данные а вторая должна их принимать но она принимает в receivedData
0*89 а посылаю 0*12 вопрос как организовать прием на 2 stm32 соединил rx-tx tx-rx но ничего не выходит... поможете?
Ща разберемся ) Выложи код куда-нибудь, на rusfolder.com, например
Проэкт в cocox сейчас выложу одну минутку... Спасибо!
Вот ссылка http://rusfolder.com/36099571
Там переменная в самом начале MASTER если она 1 то stm ка должна опрашивать другие а если 0 то она должна stm ке мастеру отвечать или хотяб данные от нее принимать....
Только не пинайте сильно за тупой код я только разбираюсь и делаю проект умного дома там все лишнее повыкидывал пока искал откуда глюки..
Если интересует я могу весь проект выложить там работа с аналоговым датчиком температуры и прерывание по кнопке... вот застопроился с обменом между 2 стм ками и все.. 2 месяца пробую и modbus прикрутить и 1 wire ничего пока думал хотяб uart заработает ан нет...
Жалко, что не в Keil'е =) Сейчас посмотрю, а, кстати, какие контроллеры то? stm32f10x?
А все, вижу, какие контроллеры)
Stm32f4 плата discovery
Вот я как хотел одна стм отправляет запрос например 12 другая стм принимает данные видит 12 и что-то делает к примеру моргает светодиодом о посылает подтверждение что приняла данные ..
А не получается принять эти данные я там отправку и прием сократил до 1 байта пока думал где глюк.
Я просто принципиально не знаю как организовывают прием на ведомых устройствах.
Вот этот файл main.c попробуй всунуть в проект вместо оригинального - http://rusfolder.com/36099999
36099999 - круто )
СПАСИБО пробую!
хм ничего не изменилось в receivedData[0] по прежнему 0x89 хотя с другой стм ки передаю sendData[0] 0x12...
может я принципиально неправильно принимаю данные (мастер=1 это 1-ая стм ка она соединенна через usart со второй в которой мастер =0)
провода tx и rx помененны местами rx -> tx а tx->rx.
не понимаю почему вторая не принимает кстати если принимаю 8 байт то весь массив заполняется от [0]
до [7] с каждым тактом значениями 0×89 и далее ничего не меняется..
Попробуй просто в один контроллер залить программу, в которой только прием и больше вообще ничего нет, а в другой только передачу, тогда понятно будет, есть ли проблема в линии связи самой
в 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);
}
http://rusfolder.com/36100439
Попробуй так, посмотрим, что получится
то же самое даже оставил 1 провод уже, принимается 0×89 в hex в receivedData[0] а в остальных 0×00..
Я могу завтра на discovery попробовать и тогда будет понятно в чем тут дело
ага спасибо! буду пока разбираться если разберусь обязательно отпишусь!
Хорошо) Я где-то около 8 завтра дома буду, соответственно где-то в это время, может чуть попозже, попробую
OK, Спасибо что помогаете!
Все разобрался!
Проблемма была в том что на stm32f4discovery на USART3 PC10 PC11 просто висит какая то железка usb может или просто непропай перешел на USART2 все заработало!!!!!
Хм..А в проекте в твоем в библиотеке был выбран USART1 по-моему
Да я просто перебирал порты + там у меня преобразователь интерфейсов висит в 485...
Главное, что все заработало )
Теперь другая проблемма, если не отвлекаю глянте быстренько навскидку что не так:
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);
Ага пробую дальше..
А Вы пробовали портировать 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
Не, не пробовал, не было необходимости ) А include "FreeRTOS.h" присутствует?
присутсвует. Прописал в вкладке 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. Файлы портирования можно найти в демоприложених к ОС.
Я тут так-то мимо проходил, но поскольку имею опыт работы с stm32 и уже сталкивался с необходимостью реализации подобых функций, то посоветую немного. Конекретно по данной статье: оптимальный и правильный метод реализации - через контроллер DMA. Это избавит от постоянного прыгания за каждым байтом по два раза в прерывание и вообще DMA замечательная штука.
В комментариях автора видел упоминание об умном доме и отсутвии опыта работы с FreeRTOS. Тем не менее эти 2 вещи очень близки. Применение ОСРВ значительно облегчит создание многозадачной системы.
Тут вот ещё в комментарих некоторые описываются свои проблемы. Когда-то я тоже сталкивался с чем-то похожим("чё-та не работает почему-та") и открыл для себя просто волшебный универсальный метод решения проблем. Как бы банально не звучало, и какой бы тратой времени это ни казалось, но чтение документации и примеров к софту можно самостоятельно решить большинство проблем. Более того, многие проблемы просто не появятся. Я сам это проходил и поэтому советую тут вам, сердечно.
Про проблемы - в точку) сам всегда пользовался этим же "методом" А чего там про умный дом? я не очень понял что-то)
А это я ошибся. Мне показалось, что видел здесь где-то упоминание об умном доме и тут же, что FreeRTOS не заведена. Но я не про умный дом, а про то, что программа рано или поздно разрастается. И лучше изначально предусмотреть масштабируемость и гибкость. Вот FreeRTOS очень хороший инструмент для этого. Всем кто занимается микроконтроллерами обязательно нужно изучить основы операционных систем реального времени. Где-то в сети гуляет цикл статей по FreeRTOS и документация, материалы объёмные но очень полезные.
Полностью согласен, у нас на работе, например, уже вообще абсолютно все ПО на ОСРВ реализовано
В объявлении прерывания на USART3 опечатка, проверяется USRT2.
void USART3_IRQHandler()
{
if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
....
Добрый день. У меня STM32F429I-Discovery и дальномер URM37. Подкдючение по USART. Надо отправить четыре байта 0х22 0х00 0х00 0х22 и получить четыре байта с информцией о расстоянии. Не удается получить ничего. Дальномер молчит. Установки USARTа соответствуют. Работаю через USART1. Отправку проверял USART2, байты уходят. Регистр данных пустой (нет ответа). Пробовал работать через вашу либу (по прерываниям) и напрямую. Не могу понять причину. Можете дать совет?
Ну тут явно проблема в дальномере...
Попробовал подключить у друзей к Ардуино. Все заработало с полпинка. Посмотрели осцилом посылку - у Ардуино пачка сжата более чем в два раза. Получается проблема в баудрейте. Но у меня он установлен как положено в 9600 (даташит на датчик). В чем может быть проблема? Может где частота стоит не та?
Видимо да,частота контроллера не соответствует.
Тогда вопрос по настройке баудрейта. Я считал, что при установке baudrate=9600, контроллер настравает его с учетом частоты шины. Если не так, то как правильно настроить?
Да, SPL настраивает исходя из тактовой частоты шины, по идее все должно работать корректно
Вобщем получилось следующее:
1) путем прогонки в цикле баудрейта, получили значение около 30000 (при рабочем 9600). В 3,125 (приблизительно) раз надо установить баудрейт больше. С чем это связано мне не понятно. Может подскажете в чем причина?
2) при использовании Вашей библиотеки была проблема с наложением байтов (ответ приходит из четырех байтов). При этом получали только один байт - остальные пропадали. Путем установки задержки после процедуры MT_USART_ReceiveData() проблема решилась.
Сейчас датчик работает вполне сносно. Спасибо за помощь
Это не очень хорошее решение проблемы... Надо смотреть, что неверно с тактированием. Может в переменной HSE_VALUE стоит не та частота, как вариант.
Столкнулся с тем, что библиотека перестает работать, если включить любую оптимизацию (gcc, Coocox). Есть пути решения проблемы?
И прием и передача не работают?
Передача не работает, приходит единственный левый байт и на этом все стопорится. Прием просто не проверял.
Надо смотртеть под отладчиком, что попадает в регистр данных.