MikroC, UART. Запрос нескольких байтов

  • Микроконтроллер: dsPIC33EP512MU810
  • Компилятор: MikroC

Я пытаюсь запросить несколько байтов с удаленного устройства через UART. Чтобы получить необходимую информацию, вы отправляете один байт запроса, чтобы получить один байт данных. У меня возникают трудности с идентификацией байтов данных при запросе более одного.

Прием UART обрабатывается через прерывание:

void UART2RXInterrupt() iv IVT_ADDR_U2RXINTERRUPT 
{
   uart_rd2[LoopVar0] = UART2_Read();       //Read into buffer
   LoopVar0++;
   if (LoopVar0 >= 1)
   {
      LoopVar0 = 0;
      ready0 = 1;
   }
   U2RXIF_bit = 0;                          //Reset interrupt flag
}

Мой код для одного байта данных выглядит следующим образом:

 UART2_Write(0x11);    //Request byte
 if (ready0 == 1)      //Data received and ready
 {
   //Parse data byte
   ready0 = 0;         //Reset data received bit
 }

Это прекрасно работает.

Если мне нужно больше, чем один байт данных, я делаю следующее

 UART2_Write(0x11);    //Request byte 11h
 if (ready0 == 1)      //Data received and ready
 {
   //Parse data byte
   ready0 = 0;         //Reset data received bit
 }
 UART2_Write(0x14);    //Request byte 14h
 if (ready0 == 1)      //Data received and ready
 {
   //Parse data byte
   ready0 = 0;         //Reset data received bit
 }

Проблема с этим методом заключается в том, что следующий байт запроса может быть уже передан без уверенности в том, что последний байт данных получен должным образом.

Это приводит к «зашифрованию» данных. Это означает, что байт данных из последнего запроса может быть проанализирован в текущем запросе и так далее.

Кажется, я не могу найти для этого подходящего решения. Любые предложения были бы замечательными!

Реализация кругового буфера:

Прерывание UART:

void UART2RXInterrupt() iv IVT_ADDR_U2RXINTERRUPT 
{
  uart_rcv[write_buffer_pointer0] = UART2_Read();   // put received char in circular buffer
  write_buffer_pointer0++;                // increment pointer
  if (write_buffer_pointer0 > 511) {
  write_buffer_pointer0 = 0;            // reset pointer
  }

  U2RXIF_bit = 0;
 }

Обработка основного цикла:

void service_UART()
 {
 UART_send(0x14);       //MAP request
 UART_send(0x1D);       //ECT request

 if (read_buffer_pointer0 != write_buffer_pointer0) {  // new data in circular buffer
    ser_in();                                // handle incoming serial data
  }
 }

Процедура отправки UART:

void UART_send(volatile char data0)
{
uart_snd[write_buffer_pointer1] = data0;
write_buffer_pointer1++;                // increment pointer
if (write_buffer_pointer1 > 511) {
  write_buffer_pointer1 = 0;            // reset pointer
}
UART2_Write(data0);
}

Обработка полученных данных:

void ser_in() 
{
volatile char rqst;
volatile char resp;

resp = uart_rcv[read_buffer_pointer0]; // read next character from buffer
read_buffer_pointer0++;                 // increment read buffer pointer
if (read_buffer_pointer0 > 511) {       // if pointer past end of buffer
    read_buffer_pointer0 = 0;         // reset pointer
}
rqst = uart_snd[read_buffer_pointer1];
read_buffer_pointer1++;
if (read_buffer_pointer1 > 511) {
   read_buffer_pointer1 = 0;
}
// do something with the data here.
if (rqst == 0x14)    //If MAP request
{
//Handle MAP Data
} 
if (rqst == 0x1D)    //If ECT request
{
//Handle ECT Data
}   
}

person Felix    schedule 25.09.2015    source источник
comment
Какая у вас платформа? Какой у вас Framework / SDK? Как и где управляется ready0? Нам нужно больше информации и кода, чтобы помочь вам.   -  person LPs    schedule 25.09.2015
comment
Я добавил информацию. Спасибо!   -  person Felix    schedule 25.09.2015
comment
Почему вы сбрасываете индекс буфера каждый раз при получении байта?   -  person LPs    schedule 25.09.2015
comment
Поскольку я имею дело только с однобайтовыми ответами, я решил, что в буфере должно быть место только для одного байта?   -  person Felix    schedule 25.09.2015
comment
Где работает ваш код получающей стороны? В каком-то бесконечном цикле? Вам нужно дождаться, пока вы определенно не получите свой первый ответ, прежде чем передавать следующую команду. Или похоже, что @LPs рекомендовал бы вам увеличить размер приемного буфера, чтобы они отображались в буфере в том порядке, в котором они были получены.   -  person Ian    schedule 25.09.2015
comment
Я тебя не понимаю. Думаю, вам следует заменить if (ready0 == 1) на while (ready0 == 0). Это означает, что вы ждете каждого отдельного символа после одного запроса.   -  person LPs    schedule 25.09.2015
comment
Это будет означать, что после запроса он будет ждать, пока данные станут доступны. Затем вам нужно будет проанализировать данные и сбросить ready0 = 1 после цикла while. Я правильно понимаю?   -  person Felix    schedule 25.09.2015
comment
Да, это то, что я имел в виду.   -  person LPs    schedule 25.09.2015
comment
@Ian Это весь код. Это неадекватно, это правда. Конечно, можно увеличить размер буфера, но как узнать, в каком месте буфера какой именно байт данных содержится?   -  person Felix    schedule 25.09.2015
comment
Если вы хотите увеличить размер буфера, вы должны реализовать диспетчер очереди печати. Затем индекс входа в прерывании и индекс выхода для потребителя. В этом случае ваш буфер становится кольцевой очередью.   -  person LPs    schedule 25.09.2015


Ответы (1)


Реализуйте две кольцевые очереди с указателями (индексами) начала и конца, достаточно большими для обеспечения пропускной способности. Определите минимальное время, которое требуется респонденту между запросами, и соблюдайте его. Каждый раз, когда вы отправляете запрос, добавляйте его в первую очередь, «очередь отправленных запросов». Когда приходит ответ, добавьте его во вторую очередь в вашей программе обработки прерывания и увеличьте указатель заголовка. Это ваша «очередь полученных ответов».

Затем вы можете обрабатывать транзакции асинхронно в основном цикле. Сравните голову второй очереди с ее хвостом. Каждый раз, когда вторая очередь становится несбалансированной (голова не равна хвосту), вы получаете как минимум один ответ. Первая очередь сообщает вам запрос, на который она была ответом. Каждый раз, когда вы завершаете обработку ответа, конечные указатели обеих очередей перемещаются.

Вы, вероятно, захотите сбросить очереди, если не получите ответа (если очереди остаются несбалансированными слишком долго), и убедитесь, что очереди не перезаписываются.

person jolati    schedule 25.09.2015
comment
Я пытаюсь разобраться в этом, так как я еще не знаком с круговыми очередями. Если я правильно понимаю, мне нужно сделать следующее: - Каждый раз, когда отправляется запрос, добавляйте его в «очередь запросов» - Каждый раз, когда «очередь приема» продвигается вперед, потому что произошло прерывание UART Rx; Удалите из очереди или извлеките из обеих очередей, чтобы получить байт запроса с соответствующим байтом данных. - person Felix; 26.09.2015
comment
@Felix Да, процедура прерывания будет продолжать помещать новые данные в очередь по мере их поступления, независимо от того, завершилась ли обработка предыдущих обменов. Поддержка очереди запросов сообщает вам, к какому запросу принадлежит следующий ответ, который вы отправите. - person jolati; 26.09.2015
comment
В порядке. Мне нужно будет найти время для внедрения и тестирования. Это звучит как хорошее решение. Думаете, размер должен быть эквивалентен сумме различных запросов? - person Felix; 26.09.2015
comment
@Felix Нет, размер определяется пропускной способностью. Рассмотрим случай только с одним типом запроса, но отвечающая сторона может ответить быстрее, чем запрашивающая сторона может обработать ответы. Если несколько запросов отправляются слишком быстро, очереди будут буферизовать обмены до тех пор, пока запрашивающая сторона не сможет их догнать. - person jolati; 26.09.2015
comment
Я добавил свою первую попытку создания круговой буферной структуры в исходный пост. Хотя у меня еще не было возможности проверить это. Что вы думаете? - person Felix; 28.09.2015
comment
@Felix Да, это один из способов. Независимые указатели заголовка и хвоста для каждой очереди добавят дисбаланса гибкости обработки (отправлено больше запросов, чем получено ответов). Посмотрите, как проходят ваши тесты. - person jolati; 29.09.2015
comment
У меня ведь есть независимые указатели для каждой очереди? У меня проблемы с поиском способа справиться с отсутствием ответа. На данный момент очереди работают, но если один ответ не получен, все еще сдвигается. - person Felix; 01.10.2015
comment
Не следует service_UART() проверять заголовок входной очереди по ее собственному хвосту, а не по отправленной очереди. И вам, вероятно, потребуется поддерживать таймер, который удаляет неотвеченный запрос, если он истекает. - person jolati; 01.10.2015