Auratos 0 29 января, 2019 Опубликовано 29 января, 2019 (изменено) · Жалоба Добрый день. Есть контроллер серии PIC18. Возникла сейчас необходимость производить передачу по USART в прерывании. Раньше для этого я использовал функцию, и работало все без прерываний: void usart_Tx(void* buf,BYTE size) { BYTE i,j; UINT16 k; char* ptr = (char*)buf; TRAN; // установить признак передачи для переключения переходника TTL-RS485 PIE1bits.RCIE = 0; // запретить прерывание от приемника USART for(i = 0; i < size; i++) { TXREG1 = ptr[i]; // запись байта в буфер передатчика USART while(!PIR1bits.TXIF); // ожидание опустошения буфера for(j = 0; j < 255; j++) // временная выдержка для достижения скорости передачи k++; } REC; // установить признак приема для переключения переходника TTL-RS485 PIE1bits.RCIE = 1; // разрешить прерывание от приемника USART } Нужно именно использовать прерывания, чтобы контроллер не отвлекался надолго на передачу. Но что-то не могу найти хотя бы одного примера, как это организовывается.Все, что придумал, это char* ptr = (char*)usart_rx_buf; // количество данных для передачи void tx_str(BYTE cnt) { PIE1bits.TXIE = 1; TRAN; // установить признак передачи для переключения переходника TTL-RS485 PIE1bits.RCIE = 0; // запретить прерывание от приемника USART totalElementstoSend = cnt; sendPointer = 0; REC; // установить признак приема для переключения переходника TTL-RS485 PIE1bits.RCIE = 1; // разрешить прерывание от приемника USART } void usart_Tx_Int(void) { BYTE i,j; UINT16 k; TXREG = ptr[sendPointer]; while(!PIR1bits.TXIF); // ожидание опустошения буфера for(j = 0; j < 255; j++) // временная выдержка для достижения скорости передачи k++; sendPointer++; if (sendPointer >= totalElementstoSend) PIE1bits.TXIE = 0; PIR1bits.TXIF = 0; } Вроде все передается, но все равно как будто не то. Подскажите, пожалуйста, как это сделать лучше? Или может у кого небольшой фрагментик готового кода завалялся :)) Изменено 29 января, 2019 пользователем Auratos Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Integro 0 29 января, 2019 Опубликовано 29 января, 2019 · Жалоба Как бы смысла в такой реализации нет... TXREG = ptr[sendPointer]; while(!PIR1bits.TXIF); // ожидание опустошения буфера Вы в прерывании по завершению передачи дожидаетесь завершения передачи. Да и вот это тоже: for(j = 0; j < 255; j++) // временная выдержка для достижения скорости передачи k++; Если нужна задержка между байтами, в этом случае лучше использовать таймер Должно быть как-то так: - Сохраняете кол-во отправляемых байт - Включаете прерывание по завершению передачи - Отправляете первый байт - В обработчике завершения прерывания отправляете следующий байт - Как только все отправили отключаем прерывание, включаем режим приема. И помните, до момента завершения отправки, в вашей реализации, буфер нельзя модифицировать Соблюдая Ваш код стайл, возможная реализация: void tx_str(BYTE cnt) { //здесь не мешало бы проверить закончилась ли предыдущая транзакиця //проверяя кол-во отправленых байт или REC или TRAN totalElementstoSend = cnt; sendPointer = 1; PIR1bits.TXIF = 0; PIE1bits.TXIE = 1; TRAN; // установить признак передачи для переключения переходника TTL-RS485 PIE1bits.RCIE = 0; // запретить прерывание от приемника USART TXREG = ptr[0]; } void usart_Tx_Int(void) { BYTE i,j; UINT16 k; PIR1bits.TXIF = 0; if (sendPointer < totalElementstoSend) { TXREG = ptr[sendPointer]; sendPointer++; return; } PIE1bits.TXIE = 0; REC; // установить признак приема для переключения переходника TTL-RS485 PIE1bits.RCIE = 1; // разрешить прерывание от приемника USART } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Auratos 0 29 января, 2019 Опубликовано 29 января, 2019 · Жалоба 57 minutes ago, Integro said: Соблюдая Ваш код стайл, возможная реализация: if (sendPointer < totalElementstoSend) { TXREG = ptr[sendPointer]; sendPointer++; return; } Попробовал ваш вариант. Контроллер отвечает шустро, только ответ неверный на запрос. Вместо правильного ответа [01][03][0C][00][00][00][00][00][00][00][00][00][05][00][00][83][71] приходит [03][01][00][00][00][00][00][00][00][00][00][05][00][00][83][FD] Не подскажите, в чем может быть загвоздка? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Integro 0 29 января, 2019 Опубликовано 29 января, 2019 · Жалоба 17 minutes ago, Auratos said: Попробовал ваш вариант. Контроллер отвечает шустро, только ответ неверный на запрос. Вместо правильного ответа [01][03][0C][00][00][00][00][00][00][00][00][00][05][00][00][83][71] приходит [03][01][00][00][00][00][00][00][00][00][00][05][00][00][83][FD] Не подскажите, в чем может быть загвоздка? Странно что первый и второй байт поменялись местами. А потерялся третий) Из-за того что испорчены начало и конец пакета, можно предположить что на переключение режимов трансивера(TRAN и REC) нужно больше времени, по этому после TRAN и перед REC нужна задержка. Но задержка в прерывании... мягко говоря так нельзя делать. На данном этапе можно убедиться в этом ли проблема, а потом думать как поступить. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SSerge 4 29 января, 2019 Опубликовано 29 января, 2019 (изменено) · Жалоба 10 часов назад, Integro сказал: Странно что первый и второй байт поменялись местами. А потерялся третий) Вы сначала разрешаете прерывание от TX, оно немедленно происходит, обработчик записывает в регистр данных передатчика ptr[1], флаг TXnIF сбрасывается. Из регистра данных передатчика байт сразу же загружается в сдвиговый регистр, регистр данных теперь свободен, флаг TXnIF снова взводится. После выхода из обработчика немедленно происходит новое прерывание. Теперь в передатчик записывается ptr[2], флаг TXnIF сбрасывается. Байт остается в буферном регистре поскольку сдвиговый регистр пока занят. После возврата из второго прерывания выполняется TXREG = ptr[0]; а записанный только что ptr[2] теряется. Вот байты и поменялись местами, а ptr[2] потерялся. Флаги TXnIF и RCnIF только на чтение (read-only), писать в них что-либо бесполезно, они сами сбрасываются после записи в передатчик или чтения из приемника. В регистре TxSTAx есть флаг TRMT - Transmit Shift Register Status bit, сигнализирующий что сдвиговый регистр передатчика пуст. Но прерываний для него не предусмотрено, поэтому ожидать окончания передачи последнего байта пакета придется или программно опрашивая этот флаг или придумать что-то ещё. Изменено 29 января, 2019 пользователем SSerge Уточнил сценарий перепутывания и потери байт при передаче. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Integro 0 29 января, 2019 Опубликовано 29 января, 2019 · Жалоба 1 hour ago, SSerge said: Флаги TXnIF и RCnIF только на чтение (read-only), писать в них что-либо бесполезно, они сами сбрасываются после записи в передатчик или чтения из приемника. Да, точно! Забыл... Спасибо что поправили! Тогда должен работать такой вариант: void tx_str(BYTE cnt) { //здесь не мешало бы проверить закончилась ли предыдущая транзакиця //проверяя кол-во отправленых байт или REC или TRAN PIE1bits.RCIE = 0; // запретить прерывание от приемника USART TRAN; // установить признак передачи для переключения переходника TTL-RS485 totalElementstoSend = cnt; sendPointer = 1; TXREG = ptr[0]; PIE1bits.TXIE = 1; } Но проблему с последним байтом это не решает, можно сделать так, но это решение блокирует все прерывания пока отправляется последний байт... void usart_Tx_Int(void) { BYTE i,j; UINT16 k; PIR1bits.TXIF = 0; if (sendPointer < totalElementstoSend) { TXREG = ptr[sendPointer]; sendPointer++; return; } while(!TXSTA1bits.TRMT); //Так делать нельзя, если конечно не ожидаете другие прерывания!!! PIE1bits.TXIE = 0; REC; // установить признак приема для переключения переходника TTL-RS485 PIE1bits.RCIE = 1; // разрешить прерывание от приемника USART } Либо, можно запустить таймер на время соответствующее передаче двум байтам, и уже там переключить rs485 на прием Либо, блокировать отправку ожиданием индекса и флага в main, но тогда нет смысла от использования прерываний. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Auratos 0 30 января, 2019 Опубликовано 30 января, 2019 · Жалоба 11 hours ago, Integro said: Тогда должен работать такой вариант 12 hours ago, SSerge said: Вот байты и поменялись местами, а ptr[2] потерялся. Спасибо большое вам за помощь. Все работает :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться