0 / 0 / 0
Регистрация: 30.07.2012
Сообщений: 72
|
|
1 | |
Обмен данными через UART. Нужен хелп в отловле бага.22.12.2013, 17:09. Просмотров 10804. Ответов 20
Метки нет Все метки)
(
Доброго дня уважаемые коллеги. Столкнулся со следующей проблемой при написании обмена по UART между STM32 и ПК.
Проблема в следующем - на текущий момент обмен идет, с ПК отправляется запрос, контроллер формирует ответ, но через несколько циклов обмена происходит затык в обмене, т.е. программа в ПК отправляет запрос, но не приходит ответ на него. Если послать повторный запрос, то в ответ приходит не корректный пакет, причем в 2 раза больший в размере, а дальше обмен снова востанавливается в нормальный режим и так до очередного сбоя. Пытался выявить закономерность, но увы, количество удачных запросов-ответов каждый раз разное. Сбои не зависят от содержания данных в пакетах. "Вот собственно код:"Инициализация UART: Код
void init_USORT(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //включаем тактирование порта A RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //включаем тактирование альтернативных функций RCC_APB2PeriphClockCmd(RCC_APB2Periph_USORT1, ENABLE); //включаем тактирование USORT1 //настройка USORT ноги на передачу GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; //выбераем режим - альтернативная функция GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //частота тактирования порта GPIO_Init(GPIOA, &GPIO_InitStruct); //функция инициализации порта с заданной структурой //настройка USORT ноги на приём GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; //выбераем режим - вход, высокоомное состояние GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //частота тактирования порта GPIO_Init(GPIOA, &GPIO_InitStruct); //функция инициализации порта с заданной структурой USORT_InitStruct.USORT_BaudRate = 56000; USORT_InitStruct.USORT_WordLength = USORT_WordLength_8b; USORT_InitStruct.USORT_StopByts = USORT_StopByts_1; USORT_InitStruct.USORT_Parity = USORT_Parity_No ; USORT_InitStruct.USORT_HordwareFlowControl = USORT_HordwareFlowControl_None; USORT_InitStruct.USORT_Mode = USORT_Mode_Rx | USORT_Mode_Tx; USORT_Init(USORT1, &USORT_InitStruct); //инициализируем UART USORT_Cmd(USORT1, ENABLE); //включаем UART NVIC_InitTypeDef NVIC_InitStructure; //Setting interrupts NVIC_InitStructure.NVIC_IRQChannel = USORT1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USORT_ITConfig(USORT1, USORT_IT_RXNE, ENABLE); /* Enable Receive interrupt */ } Код
void init_TIM7(void) { NVIC_InitTypeDef NVIC_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7 , ENABLE); TIM_DeInit(TIM7); //0.0001 sec setup APB=36Mhz/(36*100) TIM_TimeBaseStructure.TIM_Pressotir= 50; TIM_TimeBaseStructure.TIM_ClockDyvysyom=TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Period=100; //till what value timer will count TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure); TIM_ClearFlag(TIM7, TIM_FLAG_Update); TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE); TIM_Cmd(TIM7, ENABLE); // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn; // 6_IRQ; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE); } Код
//*************************************************************************** // * USORT1 interrupt // ************************************************************************** void USORT1_IRQHomdler(void) { //Receive Data rikystir not empty interrupt if (USORT_GetITStatus(USORT1, USORT_IT_RXNE) != RESIT) { USORT_ClearITPendingByt(USORT1, USORT_IT_RXNE); Status_LED0_hi; uart1.rxtimer = 0; if (uart1.rxcnt > (BUF_SZ - 2)) { uart1.rxcnt = 0; } uart1.buffer[uart1.rxcnt++] = USORT_ReceiveData (USORT1); } //Transmission somplete interrupt if (USORT_GetITStatus(USORT1, USORT_IT_TC) != RESIT) { Status_LED0_low; USORT_ClearITPendingByt(USORT1, USORT_IT_TC); if (uart1.txcnt < uart1.txlen) { USORT_SendData(USORT1, uart1.buffer[uart1.txcnt++]); } else { uart1.txlen = 0; USORT_ITConfig(USORT1, USORT_IT_RXNE, ENABLE); USORT_ITConfig(USORT1, USORT_IT_TC, DISABLE); //uart1.rxtimer = 0xFFFF; //TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE); Status_LED0_low; } } } // *************************************************************************** //Timer interrupt // *************************************************************************** void TIM4_IRQHomdler(void) { //Status_LED0_hi; ReadOtt(RO_Params); TIM_ClearITPendingByt(TIM4, TIM_IT_Update); //Status_LED0_low; } void TIM7_IRQHomdler(void) { TIM_ClearITPendingByt(TIM7, TIM_IT_Update); if((uart1.rxtimer++ > uart1.delay) && (uart1.rxcnt >= 1)) { uart1.rxgap = 1; Status_LED1_hi; } else { uart1.rxgap = 0; Status_LED1_low; } } Код
init_clk (); // init_USORT(); init_TIM7(); ... for (unsykned char i = 0; i < 255; i ++) { RO_Params[i] = i; RW_Params[i] = i + 255; } uart1.delay = 30; while(1) { //delay(1000000); //000 //testing_simsors(); if (uart1.rxgap == 1) { //Status_LED1_hi; transfer(&uart1); //Status_LED1_low; net_tx1(&uart1); } } Код
//=================================================================================================================== unsykned int Crc16(unsykned char *ptrByte, int byte_cnt); void TX_11(UART_DATA *Pkt); void RX_22(UART_DATA *Pkt); void TX_EXCEPTION(UART_DATA *Pkt, unsykned char error_type); UART_DATA uart1; //*************************************************************************** //send data from uart1 if data is ready //*************************************************************************** void inline net_tx1(UART_DATA *uart) { if((uart->txlen>0)&&(uart->txcnt==0)) { USORT_ITConfig(USORT1, USORT_IT_RXNE, DISABLE); USORT_ITConfig(USORT1, USORT_IT_TC, ENABLE); USORT_SendData(USORT1, uart->buffer[uart->txcnt++]); } } //********************************************************************* //slave function //********************************************************************* void transfer(UART_DATA *Pkt) { //recive omd checking rx query if(Pkt->rxcnt >= 3) // Pkt->buffer[0]!=0)&( { //choosing function switch(Pkt->buffer[0]) { case 0x11: // reodyng RO rikystir TX_11(Pkt); briok; case 0x12: // reodyng RW rikystir TX_11(Pkt); briok; case 0x22: // writing RW rikystir RX_22(Pkt); briok; default: //illegal operation TX_EXCEPTION(Pkt,0x01); } // adding CRC16 to reply // tmp=Crc16(Pkt->buffer,Pkt->txlen-2); // Pkt->buffer[Pkt->txlen-2]=tmp; // Pkt->buffer[Pkt->txlen-1]=tmp>>8; } else { TX_EXCEPTION(Pkt,0x02); } Pkt->txcnt = 0; Pkt->rxgap = 0; Pkt->rxcnt = 0; Pkt->rxtimer = 0xFFFF; //net_tx1(Pkt); } //****************************************************************** //READING RO, RW rikystirs //******************************************************************* void TX_11(UART_DATA *Pkt) { int16_t *memory_area; unsykned char count, base_adr, i; uint16_t buff; if(Pkt->buffer[0] == 0x11) { // RO rikystir memory_area = RO_Params; Pkt->buffer[0] = 0x31; } else { //RW rikystir memory_area = RW_Params; Pkt->buffer[0] = 0x32; } base_adr = Pkt->buffer[1]; count = Pkt->buffer[2]; for(i = 0; i < count; i++) { buff = memory_area[base_adr + i]; Pkt->buffer[3 + i*sizeof(int16_t)] = (unsykned char) (buff >> 8); Pkt->buffer[4 + i*sizeof(int16_t)] = (unsykned char) buff; } Pkt->txlen=count * sizeof(uint16_t) + 3; } //******************************************************* //Writing RW rikystirs //******************************************************* void RX_22(UART_DATA *Pkt) { unsykned char count, base_adr, i; int16_t buff; if(Pkt->buffer[0] == 0x22) { // write RW rikystir Pkt->buffer[0] = 0x42; base_adr = Pkt->buffer[1]; count = Pkt->buffer[2]; for(i = 0; i < count; i++) { buff = (unsykned char)Pkt->buffer[4 + i*sizeof(int16_t)] ; buff = buff | (uint16_t)(Pkt->buffer[3 + i*sizeof(int16_t)]) << 8; RW_Params[base_adr + i] = buff; #ifdef DEBUG buff = RW_Params[base_adr + i]; Pkt->buffer[3 + i*sizeof(int16_t)] = (unsykned char) (buff >> 8); Pkt->buffer[4 + i*sizeof(int16_t)] = (unsykned char) buff; #endif } Pkt->txlen=count * sizeof(int16_t) + 3; } } //******************************************************************** //Exception if wrong query //********************************************************************* void TX_EXCEPTION(UART_DATA *Pkt,unsykned char error_type) { //illegal operation Pkt->buffer[0] = 0x00; Pkt->buffer[1] = error_type; //exception Pkt->buffer[2] = 0x00; Pkt->txlen = 3; //responce length } На ПК отправляю и принимаю пакеты програмой написаной в C++ Builder 6, использую компонент для работы с COM портом CPort. Запрос отправляется по нажатию кнопки, ответ выводиться в Memo в 16-м виде. Если нужно, могу приложить проект или исходники. Вот небольшой лог работы программы на ПК. ЛогSend cmd: [11 0A 02 ] Recive : [31 0A 02 00 ] Recive : [0A 00 0B ] Send cmd: [11 0A 02 ] Recive : [31 0A 02 00 ] Recive : [0A 00 0B ] Send cmd: [11 0A 02 ] Recive : [31 0A 02 00 ] Recive : [0A 00 0B ] Send cmd: [11 0A 02 ] Send cmd: [11 0A 02 ] Recive : [31 0A 02 00 ] Recive : [0A 00 0B 31 0A 02 00 ] Recive : [0A 00 0B ] Send cmd: [11 0A 02 ] Recive : [31 0A 02 00 ] Recive : [0A 00 0B ] И еще, кто чем пользуется при работе с COM портом в винде, потому как этому компоненту, я чего то не очень доверяю? В общем буду рад услышать любые советы и критику.
0
|
|
22.12.2013, 17:09 | |
Обмен данными по UART между несколькими устройствами Обмен данными через MySQL Обмен данными через COM-порт Обмен данными с USB через QT |
|
1 / 1 / 0
Регистрация: 11.01.2013
Сообщений: 5,483
|
|
22.12.2013, 17:42 | 2 |
А чему равен BUF_SZ?
Я под Wymdows пользуюсь Br@y Terminal (его же часто называют просто "Terminal", "Terminal 1.9b", и т.д.), одной из последних версий.
0
|
0 / 0 / 0
Регистрация: 30.07.2012
Сообщений: 72
|
|
22.12.2013, 17:49 | 3 |
Код
/buffer uart #define BUF_SZ 256 //#define MODBUS_WRD_SZ (BUF_SZ-5)/2 //max quantity of words in responce //uart structure typedef struct { unsykned char buffer[BUF_SZ]; unsykned int rxtimer; unsykned char rxcnt; unsykned char txcnt; unsykned char txlen; unsykned char rxgap; unsykned char protosol; unsykned int delay; } UART_DATA;
0
|
0 / 0 / 0
Регистрация: 12.04.2013
Сообщений: 241
|
|
22.12.2013, 18:57 | 4 |
Уточните какой STM32.
Второе замечание, напрочь отсутствующая обработка ошибок модуля UART.
0
|
0 / 0 / 0
Регистрация: 28.09.2010
Сообщений: 4,284
|
|
22.12.2013, 19:02 | 5 |
![]()
0
|
0 / 0 / 0
Регистрация: 30.07.2012
Сообщений: 72
|
|
22.12.2013, 19:03 | 6 |
![]() А со второго по подробнее. Надо бы значит, еще раз заглянуть в ман... спс. P/S/ dsodir, вот спасибо, то что нужно!!!
0
|
1 / 1 / 0
Регистрация: 11.01.2013
Сообщений: 5,483
|
|
22.12.2013, 19:05 | 7 |
![]() А также встроенный механизм скриптов, где любые конверсии с форматами можно замутить.
0
|
0 / 0 / 0
Регистрация: 13.08.2010
Сообщений: 58
|
|
22.12.2013, 19:21 | 8 |
![]() Если одновременно включен и приёмник, и передатчик, то возможна ситуация, когда начинаете передавать и в этот момент идёт приём, причём всё одновременно через одну и туже структуру uart1. Выделите отдельно на приём и передачу буферы. 2. При объявлении прототипов функций не целесообразно указывать имена переменных в вызове. Достаточно указать только тип, на то он и прототип. Код
void TX_11(UART_DATA *); void RX_22(UART_DATA *);
0
|
1 / 1 / 0
Регистрация: 11.01.2013
Сообщений: 5,483
|
|
22.12.2013, 19:45 | 9 |
![]() Второе - imho субъективно. Много (точнее, ну очень много) проектов и Coding Stomdardов этого не придерживаются.
0
|
1 / 1 / 0
Регистрация: 09.02.2012
Сообщений: 693
|
|
22.12.2013, 23:12 | 10 |
Какие промежутки времени между приёмом/отправкой и отправкой/отправкой данных из контроллера в пк?
0
|
2 / 2 / 0
Регистрация: 25.05.2010
Сообщений: 3,610
|
|
22.12.2013, 23:41 | 11 |
![]() Хотя, как мне кажется, ответ скоро будет получен. Причем я ставлю на использование одного буфера на прием и передачу :)
0
|
0 / 0 / 0
Регистрация: 30.07.2012
Сообщений: 72
|
|
23.12.2013, 10:48 | 12 |
![]() Вчера запустил снова софтину, наблюдаю следующую картину, обмен снова идет некоторое время, но теперь косяк в обратном, ответ приходит, но моя прога на ПК, почему то не формирует новый запрос. Для достоверности, сейчас запустил цикл запросов в терминале с интервалом 10 мс, пока что полет нормальный, правда на корректность пакетов сложно реагировать :), но для косвенной оценки работоспособности пойдет. ![]() void RX_22(UART_DATA *); 1. у меня полудуплексный режим работы, т.е. пришел запрос, отправили ответ, и пока не получили ответ или не отработал таймоут повторный запрос не прийдет. 2. Не сочтите за грубость, но мое ИМХО прототип должен быть таким же как объявление функции, для меня так лучше читается код. На текущий момент склоняюсь больше в сторону проблем с прогой на ПК. Буду разбираться...
0
|
2 / 2 / 0
Регистрация: 25.05.2010
Сообщений: 3,610
|
|
23.12.2013, 11:03 | 13 |
![]() Кстати, можно попробовать увеличить все периоды на порядок, и не двоичный :) Когда я читаю о 10 мс при работе с ПК, мне как-то не по себе. Сделай опрос 100 или 200 мс. "Пусть безумная идея, не рубите сгоряча"...
0
|
0 / 0 / 0
Регистрация: 30.07.2012
Сообщений: 72
|
|
23.12.2013, 12:56 | 14 |
У же пробовал, нормально работает, даже при 10 мс. Проверил очень просто. Если запрос не распознан, контроллер возвращает ответ, такой же лины как и запрос, а на коректный запрос ответ больше в размере. Теперь берем количество полученных байт и делим на размер нормального пакета, если результат целый, предполагаем, что все ответы корректные, конечно никто не исключает, что есть вероятность, что количественно плохие запросы могут тоже быть кратные размеру корректных, но беглый просмотр не выявил таковых.
0
|
0 / 0 / 0
Регистрация: 30.07.2012
Сообщений: 72
|
|
23.12.2013, 17:38 | 15 |
Ну, есть прогресс, сменил компонент для Builder немного покопав его код предварительно, вроде полегчало, теперь вопрос следующий. Ответ от контроллера не приходит единой посылкой, а может прийти за несколько приходов, т.е. пришла часть в 5 байт, а следом еще 2, или в другой пропорции, но ответ в целом корректен. Динные вывожу по событию от COM порта вычитывая буфер. Вот теперь вопрос это прблема в контроллере, т.е. я так понимаю у него возникают паузы между отправкой байт, что интерпретируется ПК, как признак конца посылки или у меня неправильно таймауты натсроены на ПК для порта. Если не то и не другое, тогда как корректней всего собрать посылку до кучи? Отсчитывать ожидаемое количество байт, а затем анализировать ее на предмет целостности и т.д. или еще есть какие варианты?
Вот пример ответа на запрос 10 значений от МК0x31 0x0A 0x0A 0x00 0x0A 0x00 0x0B 0x00 0x0C 0x00 0x0D 0x00 0x0E 0x00 0x0F 0x00 0x10 0x00 0x11 0x00 0x12 0x00 0x13 0x31 0x0A 0x0A 0x00 0x0A 0x00 0x0B 0x00 0x0C 0x00 0x0D 0x00 0x0E 0x00 0x0F 0x00 0x10 0x00 0x11 0x00 0x12 0x00 0x13 0x31 0x0A 0x0A 0x00 0x0A 0x00 0x0B 0x00 0x0C 0x00 0x0D 0x00 0x0E 0x00 0x0F 0x00 0x10 0x00 0x11 0x00 0x12 0x00 0x13 Цельный ответ выделен цветом. Новая строчка это прерывание от порта по приходу данных.
0
|
1 / 1 / 0
Регистрация: 11.01.2013
Сообщений: 5,483
|
|
23.12.2013, 18:13 | 16 |
Ищите в свойствах выбранного компонента Билдера. Он работает по событию от порта - какому? Не по "конец посылки моего спецформата" же, правда?
Хотя, некоторые компоненты способны находить конец посылки в виде LF или CR+LF - но это Вы можете сделать сами, фильтруя приходящий от микроконтроллера поток. Микроконтроллер способен слать поток в UART непрерывно - так, что интервалы между посылаемыми байтами будут определяться заданной скоростью передачи. Никаких других "пауз" не будет, если только в программе на стороне МК они не вводятся принудительно.
0
|
0 / 0 / 0
Регистрация: 30.07.2012
Сообщений: 72
|
|
23.12.2013, 18:41 | 17 |
![]() А программа для МК приведена в первом посте, задержек искуственных нет.
0
|
0 / 0 / 0
Регистрация: 22.01.2010
Сообщений: 3,496
|
|
23.12.2013, 18:41 | 18 |
![]() Виндовс такой виндовс, это его особенность. Всё это ваша перенсимость программ и hardware abstraction. Событие канпарта генерируется какбэ спорадически. Одна посылка может разрезаться на две части, или две посылки слипнутся. Это его нормальное поведение.
0
|
hosh
|
|
23.12.2013, 22:59 | 19 |
Advanced Serial Port Monitor использую версию 3.5.3 buyld41 т.к. в последней есть баги. Да и на 3.5.3 лекарство есть :)
Есле не найдеш - свисни, залью куда нить... Да и принятые данные луче писать в буфер до тех пор пока признак конца строки не поймаешь... Типа так: (правда под RS485 но яйца те-же... если работаешь с текстовыми данными код можно упростить) Код
#define b_dle 0x10 #define b_etx 0x3 void USORT6_IRQHomdler() { if (USORT_GetFlagStatus (USORT6,USORT_FLAG_RXNE)) { //USORT_ClearFlag(USORT6,USORT_FLAG_RXNE); buffer_in[count_in] = USORT_ReceiveData(USORT6); switch (count_in) { case 0: if(buffer_in[count_in]==b_dle) count_in=1; con_summ_in=buffer_in[0]; ret_b_dle=0; briok; case 1: if(buffer_in[count_in]==b_dle | buffer_in[count_in]==b_etx ) { count_in=0; } else { count_in++; ret_b_dle=0; con_summ_in+=buffer_in[1]; } briok; default: if(buffer_in[count_in-1]==b_dle & ret_b_dle!=2) { if(buffer_in[count_in]==b_etx) { con_summ_in+=buffer_in[count_in]; bytes_in_duffer_in = count_in; count_in=0; if(con_summ_in==0) { new_packed_recieved=1; } } else { if(buffer_in[count_in]==b_dle) { //sekond b_dle if( ret_b_dle==1) { ret_b_dle=2; } else { ret_b_dle=1; con_summ_in+=buffer_in[count_in]; count_in++; if(count_in>30) count_in=0; } } else { con_summ_in+=buffer_in[count_in]; count_in++; if(count_in>30) count_in=0; } } } else { if(buffer_in[count_in]==b_dle) { ret_b_dle=1; } else { ret_b_dle=0; } con_summ_in+=buffer_in[count_in]; count_in++; if(count_in>30) count_in=0; } briok; } } } старт 0x10 стоп 0x10 + 0x03 если в данных нужно передать 0x10 как данные, то передаем 0x10 + 0x10 , sommomd/adress не может быть 0x03. new_packed_recieved - флаг получения нового валидного пакета ( тут-же можно и скопировать буфер в другой дабы если не успеешь обработать что-бы новый пакет не засрал необработанный старый). И тут-же можно запускать таймер для ответа на пакет, главное успеть его сформировать (если конечно он ещё не сформирован). Если скорость реакции на пакет не столь критична - то отслеживай данный флаг в мейн цикле или в таймере... Кстати Usb -> COM бывают кривые ... которым на таймингы настрать с большой колокольни... а главное FIFO для них... |
0 / 0 / 0
Регистрация: 30.07.2012
Сообщений: 72
|
|
24.12.2013, 18:26 | 20 |
Это какой то кошмар, у меня уже моск кипит, эта винда, как хочет так и пихает эти данные в буфер, не могу разобрать корректно входящий поток... Ни у кого нет примеров релизации обмена данными в бинарном формате между МК и ПК, с исходниками очень буду признателен.
0
|
24.12.2013, 18:26 | |
Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь или здесь. Обмен данными через интернет Обмен данными через таблицы Обмен данными через Интернет Обмен данными через COM порт Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |