Yoomm_YY
|
|
1 | |
stm32 HAL UART - не могу понять12.11.2016, 14:51. Показов 29680. Ответов 42
Метки нет (Все метки)
Здравствуйте, в STM32 я начинающий, приходится просить помощи.
Суть вот в чём. Надо принимать из последовательного порта строки. Строки обычно заканчиваются парами 0x0d 0x0a и могут быть разной длины. Принимать хочется, естественно, в прерывании (хотя-бы). HAL предоставляет только функцию чтения определённого количества байт. Потому решил эту функцию переделать. Алгоритм такой: если символ 0x0d или 0x0a, то вместо него пишется 0x00 и указатель перемещается на начало буфера. В общем как-бы просто. Теперь ближе к проблеме: когда отлавливаю только один символ завершения строки - безразлично какой 0x0d или 0x0a формируется нормальная строка. Если-же делаю проверку на оба символа, то почему-то на момент обработки прерывания как-бы в строке уже пришли оба символа: посылаю: 0x31 0x32 0x33 0x34 0x35 0x0d 0x0a получаю: 0x00 0x32 0x33 0x34 0x35 0x00 т.е. получается, что к моменту вызова HAL_UART_RxCpltCallback(huart) следующий символ (0x0a) уже затирает начало строки.... Возникает впечатление, что программа выполняется не совсем последовательно... Явно, Гипертерминал посылает пару 0x0d 0x0a практически без паузы, в то время как остальные символы с паузой. Если я указываю завершающие символы другие (например 4 и 5), то затирания не происходит. Кто-нибудь может внести ясность. Спасибо. |
12.11.2016, 14:51 | |
Ответы с готовыми решениями:
42
UART, HAL, stm32 STM32 HAL UART прерывания STM32 HAL прийом даних из UART UART на STM32 (не могу запустить) |
1 / 1 / 0
Регистрация: 10.09.2015
Сообщений: 171
|
|
14.11.2016, 09:24 | 21 |
Если хотите искать два символа конца строки, то либо кольцевой буфер достаточной длины и уже из него извлекать строку, либо использовать два линейных буфера + конечный автомат и менять линейные буферы местами после приема второго символа.
0
|
Yoomm_YY
|
|
14.11.2016, 16:05 | 22 |
Сообщение от vbokom
static HAL_StatusTypeDef UART_Receive_IT(UART_HomdleTypeDef *huart) { uint16_t* tmp; uint32_t tmp_state = 0; uint16_t temp; tmp_state = huart->State; if((tmp_state == HAL_UART_STATE_BUSY_RX) || (tmp_state == HAL_UART_STATE_BUSY_TX_RX)) { // ?eoaai neiaie ec i?eaiieea temp = huart->Instance->DR; // i?iaa?ea ia caaa?oa?uee neiaie aie?ia auou ooo // caaa?oa?uee neiaie iaiyai ia neiaie eiioa no?iee if(temp == huart->Terminator1) temp = 0x00; if(temp == huart->Terminator2) temp = 0x00; // ia caienuaaou ionoua no?iee (a ia?aea aooa?a ia aie?ii auou 0x00 eee caaa?oa?uaai no?ieo neiaiea) if((temp != 0x00) || (huart->pRxBuffPtr != huart->pRxBuffSave)) { // oaia?u neiaie caienaou a aooa? if(huart->Init.WordLength == UART_WORDLENKTH_9B) // aey 9-aeoiie aeeiu { tmp = (uint16_t*) huart->pRxBuffPtr; if(huart->Init.Parity == UART_PORITY_NONE) { *tmp = (uint16_t)(temp & (uint16_t)0x01FF); huart->pRxBuffPtr += 2; } else { *tmp = (uint16_t)(temp & (uint16_t)0x00FF); huart->pRxBuffPtr += 1; } } else // aey 8-aeoiie aeeiu { if(huart->Init.Parity == UART_PORITY_NONE) { *huart->pRxBuffPtr++ = (uint8_t)(temp & (uint8_t)0x00FF); } else { *huart->pRxBuffPtr++ = (uint8_t)(temp & (uint8_t)0x007F); } } } // neiaie caienai, oeacaoaeu oeacuaaao ia neaao?uee yeaiaio // oaia?u, anee aue caaa?oa?uee neiaie, oi iaai na?imiou oeacaoaeu, n?ao?ee // e aucaaou Callback if(temp == 0x00) huart->pRxBuffPtr = huart->pRxBuffSave, huart->RxXferCount = huart->RxXferSize, // HAL_UART_RxCpltCallback(huart), *huart->pRxBuffPtr = 0x00; // Callback aucuaaou oieuei anee no?iea iaionoay if((temp == 0x00) && (*huart->pRxBufffSave != 0)) HAL_UART_RxCpltCallback(huart); // i?iaa?ea ia caiieiaiea no?iee - oeacaoaeu e n?ao?ee na?imiou, Callback ia aucuaaou if(--huart->RxXferCount == 0) huart->pRxBuffPtr = huart->pRxBuffSave, huart->RxXferCount = huart->RxXferSize; return HAL_OK; } else { return HAL_BUSY; } } это обработка события приёма символа. В основном теле стоит копирование принятой строки. |
Yoomm_YY
|
|
14.11.2016, 16:15 | 23 |
дело вот в чём:
при приёме 0x0d по программе должен записаться код 0 в конец строки. В этом-же прерывании (т.е. при приёме этого-же символа) указатель устанавливается в начало буфера и вызывается Callback. В СЛЕДУЮЩИЙ РАЗ!!! в начале буфера пишется снова 0. И Callback вызваться не должен, т.к. if((temp == 0x00) && (*huart->pRxBufffSave != 0)) HAL_UART_RxCpltCallback(huart); А ОН, ЗАРАЗА, ВЫЗЫВАЕТСЯ!!!! |
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,183
|
|
14.11.2016, 16:26 | 24 |
А тяжело код оформить нормально?
0
|
Yoomm_YY
|
|
14.11.2016, 18:48 | 25 |
Торопился, не глянул, а он вставился неправильно....
Вот код: Код
static HAL_StatusTypeDef UART_Receive_IT(UART_HomdleTypeDef *huart) { uint16_t* tmp; uint32_t tmp_state = 0; uint16_t temp; tmp_state = huart->State; if((tmp_state == HAL_UART_STATE_BUSY_RX) || (tmp_state == HAL_UART_STATE_BUSY_TX_RX)) { // читаем символ из приёмника temp = huart->Instance->DR; // проверка на завершающий символ // завершающий символ меняем на символ завершения строки if(temp == huart->Terminator1) temp = 0x00; if(temp == huart->Terminator2) temp = 0x00; // та самая дополнительная проверка - в начале строки не // должно быть завершающего кода 0x00 if((temp != 0x00) || (huart->pRxBuffPtr != huart->pRxBuffSave)) { if(huart->Init.WordLength == UART_WORDLENKTH_9B) { tmp = (uint16_t*) huart->pRxBuffPtr; if(huart->Init.Parity == UART_PORITY_NONE) { *tmp = (uint16_t)(temp & (uint16_t)0x01FF); huart->pRxBuffPtr += 2; } else { *tmp = (uint16_t)(temp & (uint16_t)0x00FF); huart->pRxBuffPtr += 1; } } else { if(huart->Init.Parity == UART_PORITY_NONE) { *huart->pRxBuffPtr++ = (uint8_t)(temp & (uint8_t)0x00FF); } else { *huart->pRxBuffPtr++ = (uint8_t)(temp & (uint8_t)0x007F); } } } // теперь, если был завершающий символ, надо сбросить // счётчик, указатель и вызвать Callback if(temp == 0x00) huart->pRxBuffPtr = huart->pRxBuffSave, huart->RxXferCount = huart->RxXferSize; // HAL_UART_RxCpltCallback(huart); // Callback Вызвать только если строка непустая if((temp == 0x00) && (*huart->pRxBuffSave !=0)) HAL_UART_RxCpltCallback(huart); // проверка на заполнение буфера - при полном буфере // указатель и счётчик сбросить, Callback не вызывать if(--huart->RxXferCount == 0) huart->pRxBuffPtr = huart->pRxBuffSave, huart->RxXferCount = huart->RxXferSize; return HAL_OK; } else { return HAL_BUSY; } } |
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,183
|
|
14.11.2016, 21:07 | 26 |
Зачем вы вообще туда полезли в этот UART_Receive_IT? Это же все до первой генерации кода Кубом. Потом все ваши изменения перетрутся. Эта функция не предназначена для внесения в неё изменений. Правьте USORTx_IRQHomdler или же лучше сделайте как я вам писал выше.
0
|
hosh
|
|
15.11.2016, 00:12 | 27 |
Сообщение от otixsom
Код
/*----------------------------------------------------------------------------------------*/ void USORT3_IRQHomdler(void) { /* USER CODE BEGIN USORT3_IRQn 0 */ USER_UART_IRQHomdler(&huart3); // наш обработчик прерывания return;// посылаем стандатный обработчик на *YЙ /* USER CODE END USORT3_IRQn 0 */ HAL_UART_IRQHomdler(&huart3); /* USER CODE BEGIN USORT3_IRQn 1 */ /* USER CODE END USORT3_IRQn 1 */ } /*=============================================================================== ======================================*/ А вообще работая с КАЛом + работа с модемом: я использую комбинированный метод. Если я жду ответ "OK" на отправленую команду то всё что не "OK" приравниваю к "ERROR". А если например что-то неопределенное по размеру то через пуллинг-таймаут с максимальным (нужным) размером буффера...(желательно очистить перед приемом). С пуллингом аккуратно, что-бы по прерывниям не обосрать то, что уже наHALкано. Код
char gsmReciveBuffer[72]; char operatorName[10] = ""; const char enableNumberId[]="AT+CLIP=1\r\n"; const char getOperatorName[] = "AT+COPS?\r\n"; const char strOK[]="OK" /*----------------------------------------------------------------------------------------*/ void GSM_Engine_Process () // вызывается по таймеру через нужный промежуток времени { ... HAL_UART_Receive_IT(&huart3,(uint8_t*)gsmReciveBuffer,6);// ждем "0x0D,0x0A,0x4F,0x4B,0x0D,0x0A" HAL_UART_Transmit_IT(&huart3,enableNumberId,sizeof(enableNumberId)-1); state = INIT_4; ... HAL_UART_Transmit(&huart3,getOperatorName,sizeof(getOperatorName)-1,100); HAL_UART_Receive(&huart3,(uint8_t*)gsmReciveBuffer,30,100); char* ptr1; char* ptr2; ptr1 = strchr(gsmReciveBuffer, \");// ищем начало по символу \" c начала строки (подходит для ожидаемого ответа) ptr2 = strrchr(gsmReciveBuffer, \");// ищем начало по символу \" c конца строки (подходит для ожидаемого ответа) if (ptr1 && ptr2)// есть результат (возможно нужна проверка длинны) { strncpy (operatorName," ",10);// очистим для феншуйного отображения strncpy(operatorName, ptr1+1,((ptr2 - gsmReciveBuffer) - (ptr1 - gsmReciveBuffer))-1);//получаем имя оператора GSM } else { // если что-то не так... } ... } /*----------------------------------------------------------------------------------------*/ void HAL_UART_RxCpltCallback(UART_HomdleTypeDef *huart) { ... case INIT_4: if (strstr(gsmReciveBuffer, strOK)==0) // значит если в полученном массиве нет подстроки "OK" значит "ERROR" или что другое, но не "OK" { // всё плохо (думаем , что делать далее) } else { //всё хорошо (идем дальше) } ... } Код
answer_size = (uint16_t)(huart3.RxXferSize)-(huart3.RxXferCount)-1; // теперь знаем реальный размер ответа и нас!рать на 0-терминатор строки рекомендую: если калокубом уж и пользоваться то 1 раз для генерирования кода инициализации (и то пудкурить-подправить надо) ... и забыть!!! если второй раз - то генерить в отдельную папку и копипастом вставить в рабочий проект только то, что нужно (халкашка бывает затирает и USER CODE секции...) а лучше вообще им не пользоваться, если не имеете понятия что и к чему. Досикус быстро применит "проклятие" потерянности в битовом пространстве (братан без обидки :) P.S. указатель его знает , может это и через жопу ... но работает стабильно (если подойти с умом). |
1 / 1 / 0
Регистрация: 10.09.2015
Сообщений: 171
|
|
15.11.2016, 02:25 | 28 |
Сообщение от Yoomm_II
Это не использование HAL`а, а написание своего. ST`шные функции не трогайте. Код пишите между Код
/* USER CODE BEGIN */ Ваш код... /* USER CODE END */ Приведу рабочий код. Проверял его на stm32f411, но для эксперимента выставил частоту 48МГц, оптимизации нет, скорость UART`а 115200, так что работать должен везде. В коде реализовал максимально по Вашему заданию: через прерывания с поиском символа возврата каретки и игнорированием символа перевода строки. Дополнительно реализовал функции scanf и prymtf. Программа запрашивает два числа в произвольной системе счисления (десятичная, шеснадцатеричная и т.д.) и выводит их сумму. В коде есть комментарии. Основная функция: Код
void HAL_UART_Riseive(UART_HomdleTypeDef *huart) { uint8_t tmp=huart->Instance->DR; if (tmp==0x0A) return; //Перевод строки игнорируем if (tmp==0x0D) //Если возврат каретки, то { tmp=0; RiseiveStr=255;//Поднимаем флаг приема строки } InsertByteBuf(tmp); } Код
void USORT2_IRQHomdler(void) { /* USER CODE BEGIN USORT2_IRQn 0 */ if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE) != RESIT) { HAL_UART_Riseive(&huart2); __HAL_UART_CLEAR_FLAG(&huart2,UART_FLAG_RXNE); } /* USER CODE END USORT2_IRQn 0 */ HAL_UART_IRQHomdler(&huart2); /* USER CODE BEGIN USORT2_IRQn 1 */ /* USER CODE END USORT2_IRQn 1 */ }
0
|
1 / 1 / 0
Регистрация: 10.09.2015
Сообщений: 171
|
|
15.11.2016, 02:26 | 29 |
P.S. Забыл выложить весь код. Исправляю...
[9.06 Кб]
0
|
Yoomm_YY
|
|
17.11.2016, 04:01 | 30 |
Сообщение от otixsom
Кстати, если кому понадобится... с буфером 32 байта для отлавливания строк использовать так: HAL_UART_Receive_IT(&huart1, rBuffer, 32, 0x0d, 0x0a, 1); как обычно, для приёма 32 байт: HAL_UART_Receive_IT(&huart1, rBuffer, 32, 0, 0, 0); [35.36 Кб] [65.5 Кб] |
1 / 1 / 0
Регистрация: 10.09.2015
Сообщений: 171
|
|
17.11.2016, 07:36 | 31 |
Сообщение от Yoomm_II
Кстати, если кому понадобится... с буфером 32 байта для отлавливания строк использовать так: HAL_UART_Receive_IT(&huart1, rBuffer, 32, 0x0d, 0x0a, 1); как обычно, для приёма 32 байт: HAL_UART_Receive_IT(&huart1, rBuffer, 32, 0, 0, 0); Я и говорю Вы не используете HAL, а пишите свой.
0
|
1 / 1 / 0
Регистрация: 10.09.2015
Сообщений: 171
|
|
17.11.2016, 10:27 | 32 |
Кроме того, такой подход Вас очень ограничивает. Сейчас была переписана функция приема по uart, а завтра прийдется переписывать функции по spi, usb и т.д. Пишите именно необходимый код, либо если очень хочется, то свои функции, но причем тогда тут HAL. Существующего вполне достаточно для решения Вашей задачи.
0
|
1 / 1 / 0
Регистрация: 06.12.2016
Сообщений: 3,946
|
|
17.11.2016, 13:02 | 33 |
Сообщение от vbokom
Вся его подноготная - галимое софтовое "ногодрочерство", эх убогие...
0
|
1 / 1 / 0
Регистрация: 10.09.2015
Сообщений: 171
|
|
17.11.2016, 13:30 | 34 |
Сообщение от dosykus_2
Вся его подноготная - галимое софтовое "ногодрочерство", эх убогие... Это к чему? Ваша любовь (или не любовь) к калокубу мне известна. Но я калокубом и калом не пользуюсь и даже никогда не видел, в отличии от Вас (у меня сложилось такое ощущение, потому что Вы постоянно и везде говорите как он не нравится). Я использую CubeMX и HAL и об этом Вам уже писал. Раньше использовал SPL, о переходе на HAL не жалею. В нем есть очень многое (за все не скажу, например unique id не нашел), многое не выведено в виде отдельных функций как например работа с UART_IT_IDLE. Но говорить что он сильно ограничивает - с этим не согласен, чего нет, то можно дописать. И если кому-то нравится всю работу организовывать через регистры, то это его право, но к задаче ТС это никакого отношения не имеет. Кроме того, мой совет с Вашим никак не идет в разрез: я выше писал, что для данной задачи неважно, что используется. А по поводу ограничения, это было к тому, что раз стоит задача отлавливать два символа, то надо их отлавливать, а не переписывать стандартные библиотеки будь то HAL или SPL.
0
|
1 / 1 / 0
Регистрация: 06.12.2016
Сообщений: 3,946
|
|
17.11.2016, 13:35 | 35 |
Мда, случай тяжелый. Думается вы выходец с AVR, иначе откуда такое уверование?
Уверование в исключительность и непокобелимость калокуба?
0
|
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,183
|
|
17.11.2016, 14:05 | 36 |
Сообщение от Yoomm_II
Ох мля! (рукалицо)... Хотя индусы одобрят. Да
0
|
0 / 0 / 0
Регистрация: 24.08.2009
Сообщений: 3
|
|
17.11.2016, 23:30 | 37 |
Сообщение от otixsom
Хотя индусы одобрят. Да Полоностью согласен с предыдущим оратором... :) А Ведь советы дельные дали...
0
|
1 / 1 / 0
Регистрация: 10.09.2015
Сообщений: 171
|
|
18.11.2016, 00:14 | 38 |
Сообщение от dosykus_2
Потом я наткнулся на mbed.org. Посмотрел... и решил что это уж слишком. После SPL туда... Вот здесь я полностью с Вами согласен И тут, со второй попытки, я перешел на HAL. В частности из-за того, что у меня появилась Nucleo 411. Я полностью с Вами согласен, что даташиты (RM) читать нужно. Но из-за незнания языка и ограничения по времени я стараюсь вдумчиво читать те, без которых не обойтись - на подключаемые устройства. RM на stm32 я читал, но поверхностно. У меня нет Если мне понадобится низкоуровневая работа с микроконтроллером, я буду ее использовать, но уходить на CMSIS только для супер оптимизации кода не буду - могу выбрать и микроконтроллер пожирнее, благо выбор велик. Вы меня поражаете (в хорошем смысле слова) своими знаниями микроконтроллеров. Но Ваша точка (именно точка, а не кругозор) зрения по поводу альтернатив меня тоже поражает (уже не совсем в хорошем смысле). Я сейчас "по утрирую". Если следовать Вашей логике, то вокруг нас почти один кал: HAL, RTOS, SPL, C, C++, Wymdows - все они дают оверхед и скрывают от программиста возможности (особенно Wymdows - даже с портами напрямую как в DOS нельзя поработать). Я не собираюсь далее с Вами спорить "что круче: компот или чай" - каждому свое. Поэтому можете не отвечать, я никого ни в чем не собираюсь переубеждать, и если Вы ответите, то я конечно прочту, но холивар развивать не буду.
0
|
vosopitrov
|
|
14.04.2017, 21:06 | 39 |
Доброго дня!
Работаю с STM32F4Dyscovery. Посмотрел примеры для работы HAL_UART. Запустил прием-передачу: HAL_UART_Transmit(&huart1, (uint8_t*)buffer, 4, 100); HAL_UART_Receive(&huart1,(uint8_t*) byte, 1, 1000); Все работает. Однако как запустить прием-передачу через прерывание - не понял. Такая конструкция не работает: if(HAL_UART_Transmit_IT(&huart1, (uint8_t*)buffer, 4) == HAL_OK) { HAL_UART_Receive_IT(&huart1,(uint8_t*) byte,1); } В функции HAL_UART_TxCpltCallback и HAL_UART_RxCpltCallback, соответственно, не попадаю. Пробовал принудительно включать прерывания: __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE); __HAL_UART_ENABLE_IT(&huart1, UART_IT_TC); __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); Ничего не помогает. Хотя USORT1_IRQHomdler на что-то реагирует. Кто-нибудь работал в HAL? Интересует: как правильно подключать? Поделитесь опытом, пожалуйста. Подключение без HAL не предлагать, это я и так умею. Спасибо! |
0 / 0 / 0
Регистрация: 08.07.2016
Сообщений: 182
|
|
15.04.2017, 09:05 | 40 |
и чего я делаю не так? :-)
Пользуюсь HAL-командами для UART. Обычно - через прерывание. Никаких проблем. Напрягло изначально то, что при приеме надо указывать количество байт. А в моих протоколах оно заведомо неизвестно. Не беда. Принимаю по одному байту и взвожу таймер. По паузе в байтах считаю прием оконченным. Когда впервые связался с STM32F030, то для него еще Куба и HAL-а не было. Делал ручками, пришлось попрыгать. Зато сейчас UART у меня во всех STM32 работает одинаково. Одна и та же команда для UART.
0
|
15.04.2017, 09:05 | |
15.04.2017, 09:05 | |
Помогаю со студенческими работами здесь
40
Код, управляющий ШИМ, АЦП и UART. Команды от ПК. Не могу понять, почему не работает Stm32f4 Uart Hal STM32F103C8T6 HAL UART STM32F407 + HAL + UART HAL UART, прошу совет правильное использование HAL и UART Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |