Сделай на IDLE и не мучайся. После этого и DMA прикручивается просто и логично. И таймер сэкономишь. Механизм IDLE как и RTO измеряет паузу в битах передаваемых данных, потому не зависит от скорости обмена в отличие от метода с таймером TIM.
STM32 новичку в ARM что к чему
- Сообщения: 1379
- Зарегистрирован: Вт ноя 19, 2019 06:10:18
[uquote="Lum1noFor",url="/forum/viewtopic.php?p=4236080#p4236080"]Судя по моим мучениям с этой простейшей штукой...[/uquote]
Сделай на IDLE и не мучайся. После этого и DMA прикручивается просто и логично. И таймер сэкономишь. Механизм IDLE как и RTO измеряет паузу в битах передаваемых данных, потому не зависит от скорости обмена в отличие от метода с таймером TIM.
Сделай на IDLE и не мучайся. После этого и DMA прикручивается просто и логично. И таймер сэкономишь. Механизм IDLE как и RTO измеряет паузу в битах передаваемых данных, потому не зависит от скорости обмена в отличие от метода с таймером TIM.
- Реклама
- Сообщения: 65
- Зарегистрирован: Ср сен 24, 2014 12:30:09
Появилось понимание, откуда растут ноги: проблема всегда была перед глазами:
Если убрать строчку с передачей текста ошибки через USART1, все работает нормально. Все прерывания, кроме RXNE выключены. Код инициализации прерывания прикрепляю ниже.
В чем может быть причина?
Код: Выделить всё
void USART1_IRQHandler(void) {
if (SymbolCount == 0) {
TIM4->CNT = 0;
TIM4->CR1 |= TIM_CR1_CEN;
}
ReceivedText[SymbolCount++] = USART1->DR;
}
void TIM4_IRQHandler(void) {
TIM4->SR &=~ TIM_SR_UIF;
TIM4->CR1 &=~ TIM_CR1_CEN;
USART_SendStr("Time out!"); // ПРОБЛЕМА ЗДЕСЬ!
SymbolCount = 0;
}Код: Выделить всё
#define USART_TX_ON (GPIOB->ODR |= GPIO_ODR_ODR5)
#define USART_TX_OFF (GPIOB->ODR &=~ GPIO_ODR_ODR5)
const Baudrate = 9600;
void USART1_Init(void) {
GPIOA->CRH &=~ GPIO_CRH_CNF9_0 ; // PA9 as alternate funtion Push-Pull (TX). (CNF = "0b10").
GPIOA->CRH |= GPIO_CRH_CNF9_1 ;
GPIOA->CRH |= (GPIO_CRH_MODE9 | GPIO_CRH_MODE9) ; // PA9 is OUTPUT, 50MHz max. (MODE = "0b11").
GPIOA->CRH &=~ GPIO_CRH_CNF10_0 ; // PA10 as input with Pull-Up (RX) (CNF = "0b10").
GPIOA->CRH |= GPIO_CRH_CNF10_1 ;
GPIOA->CRH &=~ (GPIO_CRH_MODE10 | GPIO_CRH_MODE10) ; // PA10 as Input.
GPIOB->CRL &=~ (GPIO_CRL_CNF5_0 | GPIO_CRL_CNF5_1) ; // PB5 as output with Push-Pull (RX/TX). (CNF = "0b00").
GPIOB->CRL |= (GPIO_CRL_MODE5_0 | GPIO_CRL_MODE5_1) ; // PA5 is OUTPUT, 50MHz max. (MODE = "0b11").
GPIOB->ODR &=~ GPIO_ODR_ODR5 ; // TX = 0;
USART1->BRR = SystemCoreClock/Baudrate;
USART1->CR1 = 0;
USART1->CR2 = 0;
USART1->CR3 = 0;
USART1->CR1 |= USART_CR1_RXNEIE ; // Enable RX interrupt.
USART1->CR1 &=~ USART_CR1_TXEIE ; // Disable TX interrupt.
USART1->CR1 &=~ USART_CR1_IDLEIE ; // Disable Idle interrupt.
USART1->CR1 &=~ USART_CR1_TCIE ; // Disable transmit complete interrupt.
USART1->CR1 &=~ USART_CR1_PEIE ; // Disable PEIE interrupt.
USART1->CR3 &=~ USART_CR3_CTSIE ; // Disable CTSIE interrupt.
NVIC_SetPriority(USART1_IRQn, 5) ; // Set USART1 IRQ Priority.
NVIC_EnableIRQ (USART1_IRQn) ;
USART1->CR1 |= USART_CR1_UE ; // Enable USART1.
USART1->CR1 |= USART_CR1_RE ; // Enable USART1 Reciever.
USART1->CR1 |= USART_CR1_TE ; // Enable USART1 Transmitter.
}Код: Выделить всё
void USART_SendSymbol(uint8_t usymb) {
USART_TX_ON;
while (((USART1->SR & USART_SR_TXE) >> USART_SR_TXE_Pos) == 0); // Wait for TXE flag.
USART1->DR = usymb; // Trancieve data.
while (((USART1->SR & USART_SR_TXE) >> USART_SR_TXE_Pos) == 0); // Wait for TXE flag.
Delay_us(1000);
USART_TX_OFF;
}
void USART_SendStr(char *ustr) {
char *q = ustr;
while (*q)
{
USART_SendSymbol(*q++);
}
}В чем может быть причина?
Миллисекундная задержка на каждый символ - итого, USART_SendStr() висит несколько миллисекунд в прерывании таймера. - как-то некрасиво
- Сообщения: 65
- Зарегистрирован: Ср сен 24, 2014 12:30:09
Согласен, но без нее у меня не получилось. У меня стоит конвертер USART -> RS485, и для его работы мне нужно переключать линию Read/Write. Соответственно, при передаче я подаю на линию Read/Write единицу, а в конце передачи я должен перевести ее обратно в 0. И если после окончания передачи я переведу линию Read/Write раньше, чем через 1 мс, передача идет криво. Переписал код вот так (теперь задержка всего одна):WiseLord писал(а):Миллисекундная задержка на каждый символ - итого, USART_SendStr() висит несколько миллисекунд в прерывании таймера. - как-то некрасиво
Код: Выделить всё
void USART_SendSymbol(uint8_t usymb) {
while (((USART1->SR & USART_SR_TXE) >> USART_SR_TXE_Pos) == 0); // Wait for TXE flag.
USART1->DR = usymb; // Trancieve data.
}
void USART_SendStr(char *ustr) {
char *q = ustr;
USART_TX_ON;
while (*q)
{
USART_SendSymbol(*q++);
}
Delay_us(1000);
USART_TX_OFF;
}- Сообщения: 1379
- Зарегистрирован: Вт ноя 19, 2019 06:10:18
Открою тебе страшную тайну: у USART есть ещё флаги, кроме USART_SR_TXE, показывающие состояние передатчика. А ещё у USART есть ДВА регистра: один для загрузки передаваемого байта, а второй сдвиговый, содержимое которого выдаётся на ножку TX. Флаг USART_SR_TXE показывает тебе, что регистр для получения от тебя байта свободен, а вот окончание выдачи битиков в линию из второго регистра показывает флаг USART_SR_TC. Вот по прерыванию от него-то тебе и нужно переключать линию.Lum1noFor писал(а):И если после окончания передачи я переведу линию Read/Write раньше, чем через 1 мс, передача идет криво
Это всё нарисовано в мурзилке у СТМ.
А ещё одна страшная тайна- это MAX13487...
Последний раз редактировалось tonyk Ср май 25, 2022 14:04:33, всего редактировалось 1 раз.
- Реклама
- Сообщения: 65
- Зарегистрирован: Ср сен 24, 2014 12:30:09
[uquote="tonyk",url="/forum/viewtopic.php?p=4236343#p4236343"]
Это всё нарисовано в мурзилке у СТМ.[/uquote]
Исправил, спасибо за замечание. Но проблему с перекрывающимися прерываниями это не решает.
UPD:
Мое заключение о том, что после возврата из одного прерывания в другое по стеку, выполнение первого прерывания начинается сначала НЕВЕРНО - проверил. Все выполняется откуда надо. Чтобы не вводить людей в заблуждение.
Открою тебе страшную тайну: у USART есть ещё флаги, кроме USART_SR_TXE, показывающие состояние передатчика. А ещё у USART есть ДВА регистра: один для загрузки передаваемого байта, а второй сдвиговый, содержимое которого выдаётся на ножку TX. Флаг USART_SR_TXE показывает тебе, что регистр для получения от тебя байта свободен, а вот окончание выдачи битиков в линию из второго регистра показывает флаг USART_SR_TC. Вот по прерыванию от него-то тебе и нужно переключать линию.Lum1noFor писал(а):И если после окончания передачи я переведу линию Read/Write раньше, чем через 1 мс, передача идет криво
Это всё нарисовано в мурзилке у СТМ.[/uquote]
Исправил, спасибо за замечание. Но проблему с перекрывающимися прерываниями это не решает.
UPD:
Мое заключение о том, что после возврата из одного прерывания в другое по стеку, выполнение первого прерывания начинается сначала НЕВЕРНО - проверил. Все выполняется откуда надо. Чтобы не вводить людей в заблуждение.
Последний раз редактировалось Lum1noFor Ср май 25, 2022 14:17:59, всего редактировалось 1 раз.
- Сообщения: 1379
- Зарегистрирован: Вт ноя 19, 2019 06:10:18
Я ж тебе с самого начала предлагал делать на IDLE, а ты сам себе геморрой устроил на ровном месте.
А ещё одна страшная тайна- это MAX13487...
Добавлено after 1 minute 40 seconds:
Не вижу твоих обработчиков прерываний. По-идее, в каждом из них должно запрещаться прерывание от другого.
А ещё одна страшная тайна- это MAX13487...
Добавлено after 1 minute 40 seconds:
Не вижу твоих обработчиков прерываний. По-идее, в каждом из них должно запрещаться прерывание от другого.
- Сообщения: 65
- Зарегистрирован: Ср сен 24, 2014 12:30:09
[uquote="tonyk",url="/forum/viewtopic.php?p=4236346#p4236346"]Я ж тебе с самого начала предлагал делать на IDLE, а ты сам себе геморрой устроил на ровном месте.
А ещё одна страшная тайна- это MAX13487...
Добавлено after 1 minute 40 seconds:
Не вижу твоих обработчиков прерываний. По-идее, в каждом из них должно запрещаться прерывание от другого.[/uquote]
Если я в прерывании USART1 запрещу выполнение прерывания таймера, то он не будет запускаться вообще.
Вот мои обработчики прерываний (USART1 - приоритет 5, TIM4 - приоритет 4):
А ещё одна страшная тайна- это MAX13487...
Добавлено after 1 minute 40 seconds:
Не вижу твоих обработчиков прерываний. По-идее, в каждом из них должно запрещаться прерывание от другого.[/uquote]
Если я в прерывании USART1 запрещу выполнение прерывания таймера, то он не будет запускаться вообще.
Вот мои обработчики прерываний (USART1 - приоритет 5, TIM4 - приоритет 4):
Код: Выделить всё
void USART1_IRQHandler(void) {
if (SymbolCount == 0) {
TIM4->CNT = 0;
TIM4->CR1 |= TIM_CR1_CEN;
}
ReceivedText[SymbolCount++] = USART1->DR;
}
void TIM4_IRQHandler(void) {
TIM4->SR &=~ TIM_SR_UIF;
TIM4->CR1 &=~ TIM_CR1_CEN;
USART_SendStr("Time out!");
SymbolCount = 0;
}- Сообщения: 1379
- Зарегистрирован: Вт ноя 19, 2019 06:10:18
у тебя не правильный алгоритм.
Ты должен запускать таймер в режиме OPM сразу после загрузки UART_DR, а внутри обработчиков запрещать оба прерывания и сбрасывать, например, в обработчике от таймера запрос от UART и наоборот. Тогда будет работать. Только, по-сути, так ты просто повторяешь алгоритм формирования IDLE в UART.
Ты должен запускать таймер в режиме OPM сразу после загрузки UART_DR, а внутри обработчиков запрещать оба прерывания и сбрасывать, например, в обработчике от таймера запрос от UART и наоборот. Тогда будет работать. Только, по-сути, так ты просто повторяешь алгоритм формирования IDLE в UART.
- Сообщения: 65
- Зарегистрирован: Ср сен 24, 2014 12:30:09
Весь день проковырялся с этой штукой, выяснил кое-что странное. Оказывается, таймер вообще тут не при чем - зря его обвиняли. Вешаю светодиод на любую ногу МК и беру простейшее прерывание USART1 (для исключения влияния чего-либо даже задержку делаю на цикле):
Шлю один любой символ через терминал - светодиод моргает, как положено, 1 раз. Шлю его несколько раз вручную - все работает отлично. Но стоит только отправить через терминал не один символ (например, "Q"), а два или более подряд ("QE"), то светодиод начинает моргать бесконечно. То есть МК не может выйти из прерывания вообще, и гоняет его в цикле. Я так понимаю это из-за того, что следующий символ приходит раньше, чем закончилось предыдущее прерывание. Из-за чего такое может происходить?
Код: Выделить всё
void USART1_IRQHandler(void) {
uint32_t i = 0;
USART1->SR &=~ USART_SR_RXNE; // Clear USART1 RXNE Interrupt flag
GPIOC->ODR |= GPIO_ODR_ODR12; // Enable LED
for (i = 0; i < 65535; i++); // Delay
GPIOC->ODR &=~ GPIO_ODR_ODR12; // Disable LED
for (i = 0; i < 65535; i++); // Delay
}- Сообщения: 1525
- Зарегистрирован: Чт июн 10, 2010 20:11:19
Уберите задержки из прерывания!
Перед сбросом флага проверяйте из-за него вы туда попали или нет.
Проверяйте как настроены прерывания от UART - по каким причинам они могут возникнуть. Могут ли, например, из-за ошибок.
Перед сбросом флага проверяйте из-за него вы туда попали или нет.
Проверяйте как настроены прерывания от UART - по каким причинам они могут возникнуть. Могут ли, например, из-за ошибок.
- Сообщения: 1379
- Зарегистрирован: Вт ноя 19, 2019 06:10:18
У тебя не правильный алгоритм.
Ессно, у тебя так будет. Тебе надо разрешать прерывание после загрузки DR, а в обработчике, после окончания передачи, его запрещать.
Ессно, у тебя так будет. Тебе надо разрешать прерывание после загрузки DR, а в обработчике, после окончания передачи, его запрещать.
Есть вопрос. У меня возникает глюк и я не могу выцепить в чем причина. Поэтому пытаюсь всё проверять. Сейчас на подозрении - стек. Глюк появлялся у меня спустя около 20 секунд после начала хода. Я увеличил размер стека с 4096 до 8192 байт и один проход выполнился нормально. Второй тоже нормально, но на третьем проходе - опять появился глюк. На подозрении прерывания. Их у меня толпы.
И вот вопрос про прерывание PendSV - оно у меня довольно длинное. Но имеет самый низкий приоритет. Может ли быть так, что оно вызовется снова не завершив текущее. А как он знает, что текущее завершилось? Собственно, я иногда и в самом этом обработчике взвожу запрос на PendSV, чтобы обработчик перезапустился (там у меня машина состояний).
Приоритеты распределены так:
Память распределена следующим образом:
А можно как-нибудь узнать, что стек вылез за рамки?
И вот вопрос про прерывание PendSV - оно у меня довольно длинное. Но имеет самый низкий приоритет. Может ли быть так, что оно вызовется снова не завершив текущее. А как он знает, что текущее завершилось? Собственно, я иногда и в самом этом обработчике взвожу запрос на PendSV, чтобы обработчик перезапустился (там у меня машина состояний).
Код: Выделить всё
void PendSV_Handler(void) {
profiler();
}
void profiler(void) {
...
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; // перезапуск, чтобы начать двигаться сразу
...
}Код: Выделить всё
// IRQ priorities:
#define SysTick_IRQ_Priority 2
#define I2C_IRQ_PRI 2
#define TIMER0_IRQ_PRI 3
#define TIMER1_IRQ_PRI 3
#define USART0_IRQ_PRI 4
#define USART3_TX_IRQ_PRI 4
#define LDMA_IRQ_PRI 5
#define ADC0_IRQ_Priority 5
#define LETIMER0_IRQ_Priority 5
#define PendSV_IRQ_priority 7
Код: Выделить всё
section size addr
.text 72968 0
.ARM.exidx 8 72968
.stack 8192 536870912
.data 1856 536879104
.bss 173420 536880960
.heap 13136 537054384- Сообщения: 362
- Зарегистрирован: Вс апр 03, 2022 07:01:29
Это влияет только на предупреждение при компиляции. Физически во время работы МК размер стека не контролируется. Можно посмотреть только в аналитике (Static Stack Analyzer) величину максимального потребления стека функциями. В ОЗУ вот так всё это укладывается:Я увеличил размер стека с 4096 до 8192 байт
Каждый вызов вложенной функции или прерывания увеличивает потребление стека. При возврате из вложенных функций и прерываний потребление стека уменьшается. А если стек увеличивается слишком сильно, он наползет на область хранения статических переменных и повредит их содержимое. В этом и будет проявляться косяк - в повреждении значений статических переменных.
Для контроля положения вершины стека есть регистр ядра SP (Stack Pointer). Регистр не имеет адреса и доступен либо через ассемблер, либо через сишную обертку __get_MSP(), возвращается текущий адрес вершины стека.
Поскольку вы используете динамическое выделение памяти, под него будет выделяться место, начиная от конца хранения статических переменных (по рисунку выше - в белой части). И вот тут возможно взаимное столкновение динамического выделения памяти (которое идет вверх по адресам) и стека (который идет вниз по адресам).
В чем именно проявляется глюк? В каком поведении? Проанализируйте, что конкретно портится.
Нет, то же самое прерывание имеет тот же самый приоритет и вытеснить само себя не может. Поэтому, флаг запроса будет выставлен, но как только произойдет выход из текущего прерывания, МК снова войдет в это прерывание с его начала. Более подробно о работе прерываний прочтите в Programming Manual.Может ли быть так, что оно вызовется снова не завершив текущее. А как он знает, что текущее завершилось?
Спасибо за подсказку. попробую вставить контроль значений вершины стека в журнал, чтобы узнать в этом ли проблема.
Расположение стека я показал. Причем в отличии от того, что делал Keil, у силабов стек расположен внизу памяти и данные запортить не может. Он может только наехать на область где мог бы быть флеш. Но тогда, если бы адрес возврата был бы записан в пустоту, я бы наверняка получил бы HardFault.
Ок, проведу тесты и посмотрю, может зря я на стек бочку качу.
Расположение стека я показал. Причем в отличии от того, что делал Keil, у силабов стек расположен внизу памяти и данные запортить не может. Он может только наехать на область где мог бы быть флеш. Но тогда, если бы адрес возврата был бы записан в пустоту, я бы наверняка получил бы HardFault.
Ок, проведу тесты и посмотрю, может зря я на стек бочку качу.
- Сообщения: 65
- Зарегистрирован: Ср сен 24, 2014 12:30:09
[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4236415#p4236415"]Уберите задержки из прерывания!
Перед сбросом флага проверяйте из-за него вы туда попали или нет.
Проверяйте как настроены прерывания от UART - по каким причинам они могут возникнуть. Могут ли, например, из-за ошибок.[/uquote]
Специально проверил - все прерывания кроме RX отключены. Даже пошел в лоб вот так:
Симптомы те же: если к моменту прихода следующей посылки предыдущее прерывание USART1 еще не закончило свое выполнение (например, внутри прерывания оказалась большая задержка, как у меня), тогда это самое прерывание начнет бесконечно крутиться в цикле, хоть флаги обобнуляйся. Я понимаю, что это не правильно пихать в прерывание задержки, но я хочу понять, из-за чего это, и как с этим бороться.
UPD: разобрался.
Чтобы отработать такую ситуацию, есть флаг ORE - "Overrun error". Прерывание по этому флагу то же самое, что и для RX - RXNEIE. Поэтому оно и вылезает у меня всегда. Проблема была в том, что этот флаг невозможно сбросить простым обнулением, нужно выполнить сначала чтение из USART1->DR, а затем чтение из USART1->SR. Только тогда он сбрасывается.
В итоге, эта проблема решилась вот так:
Здесь проверяется флаг RXNE (хотя, в любом случае мы попали в это прерывание именно через него, но если в друг включены другие прерывания, то проверять его нужно), и флаг ORE не должен быть равен единице. Если все нормально, читаем данные. Если Overrun, то просто сбрасываем все флаги и ничего не делаем. Ну, либо, выдаем ошибку.
Перед сбросом флага проверяйте из-за него вы туда попали или нет.
Проверяйте как настроены прерывания от UART - по каким причинам они могут возникнуть. Могут ли, например, из-за ошибок.[/uquote]
Специально проверил - все прерывания кроме RX отключены. Даже пошел в лоб вот так:
Код: Выделить всё
void USART1_IRQHandler(void) {
uint32_t i = 0;
NVIC->ICER[1] |= 0x20 ; // Disable USART1 interrupt.
USART1->SR = 0 ;
GPIOC->ODR |= GPIO_ODR_ODR12 ; // Enable LED.
for (i = 0; i < 65535; i++) ; // Delay
GPIOC->ODR &=~ GPIO_ODR_ODR12 ; // Disable LED.
for (i = 0; i < 65535; i++) ; // Delay
NVIC->ISER[1] |= 0x20 ; // Enable USART1 interrupt.
}UPD: разобрался.
Чтобы отработать такую ситуацию, есть флаг ORE - "Overrun error". Прерывание по этому флагу то же самое, что и для RX - RXNEIE. Поэтому оно и вылезает у меня всегда. Проблема была в том, что этот флаг невозможно сбросить простым обнулением, нужно выполнить сначала чтение из USART1->DR, а затем чтение из USART1->SR. Только тогда он сбрасывается.
В итоге, эта проблема решилась вот так:
Код: Выделить всё
void USART1_IRQHandler(void) {
if ((((USART1->SR & USART_SR_RXNE) >> USART_SR_RXNE_Pos) == 1) & (((USART1->SR & USART_SR_ORE) >> USART_SR_ORE_Pos) != 1)) {
ReceivedText[SymbolCount++] = USART1->DR;
} else {
(void)USART1->DR;
(void)USART1->SR;
}- Сообщения: 1379
- Зарегистрирован: Вт ноя 19, 2019 06:10:18
Мне страшно представить, когда ты начнёшь осваивать UART+DMA... А ведь там без IDLE или RTO никак...
как я понял, истинная причина проблемы в отсутствии считывания регистра принятых данных
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Сообщения: 65
- Зарегистрирован: Ср сен 24, 2014 12:30:09
Проблема была в том, что на одном бите разрешения прерывания RXNEIE висело два флага от разных событий - RXNE и ORE. И чтобы сбросить один из этих флагов, ORE, нужно не просто считать регистр, а выполнить определенную последовательность действий. В итоге, я получаю 10 символов по USART1 вот таким кодом:
Вроде все работает как надо, но после приема 10 символов почему-то еще один лишний раз срабатывает прерывание и выдается одна ошибка Time out. Как будто принимается один лишний символ. В счетчике SymbolCount на тот момент оказывается число 1, а должно быть 0.
Код: Выделить всё
void USART1_IRQHandler(void) {
uint8_t i = 0;
if ((((USART1->SR & USART_SR_RXNE) >> USART_SR_RXNE_Pos) == 1) & (((USART1->SR & USART_SR_ORE) >> USART_SR_ORE_Pos) != 1) & (((USART1->SR & USART_SR_IDLE) >> USART_SR_IDLE_Pos) != 1)) {
ReceivedText[SymbolCount++] = USART1->DR;
(void)USART1->SR;
} else {
if (((USART1->SR & USART_SR_ORE) >> USART_SR_ORE_Pos) == 1) {
USART_SendStr("Overrun!");
(void)USART1->DR;
(void)USART1->SR;
memset(ReceivedText, 0, sizeof ReceivedText);
SymbolCount = 0;
}
if (((USART1->SR & USART_SR_IDLE) >> USART_SR_IDLE_Pos) == 1) {
if (SymbolCount != 10) {
USART_SendStr("Time out!");
memset(ReceivedText, 0, sizeof ReceivedText);
SymbolCount = 0;
(void)USART1->DR;
(void)USART1->SR;
} else {
SymbolCount = 0;
for (i = 0; i < 11; i++) {
ReceivedCommand[i] = ReceivedText[i];
}
ReceivedCommand[11] = 0;
(void)USART1->DR;
(void)USART1->SR;
}
}
}
}Вроде все работает как надо, но после приема 10 символов почему-то еще один лишний раз срабатывает прерывание и выдается одна ошибка Time out. Как будто принимается один лишний символ. В счетчике SymbolCount на тот момент оказывается число 1, а должно быть 0.
- Сообщения: 26
- Зарегистрирован: Вт май 17, 2022 09:49:48


