Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Работа TXC в USART
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
fmdost
Доброго времени суток!
Помогите разобраться с работой USART в tiny2313. Немогу понять как работает флаг TXC. В даташите написано что он выставляется по окончании передачи. Но там есть буферизация в 2 байта. Он выставляется если передал 1 байт или если передал всё?
Передаю сразу 2 байта, и жду прерывания, для переключения драйвера 485 на приём. Приёма на другом конце не происходит. Работает только если после передачи первого байта проверять флаг вручную и передавать второй байт после его установки. Соответственно так же переключаю на приём.
ЗЫ. В прерывании сбрасывал флаг записью в него 1. При передаче 2х байт запрещал прерывания для неразрывности, всё равно ничего не добился. Смотрел по осцылу время нахождения в режиме передача, но ничего непонял. Сколько реально времени (включая служебные биты 1-четности и 1-стоп 9-ый) будет передавать 2 байта усарт?
haker_fox
Цитата(Т.Достоевский @ Aug 20 2007, 08:46) *
Доброго времени суток!
Помогите разобраться с работой USART в tiny2313. Немогу понять как работает флаг TXC. В даташите написано что он выставляется по окончании передачи. Но там есть буферизация в 2 байта. Он выставляется если передал 1 байт или если передал всё?

Честно говоря никогда не испольвал этот флаг. Использую вместо него UDRE, он выставляется если регистр данных передатчика пуст и готов к отправке следующего байта. Рекомендую воспользоваться этим прерыванием.
Цитата(Т.Достоевский @ Aug 20 2007, 08:46) *
ЗЫ. В прерывании сбрасывал флаг записью в него 1. При передаче 2х байт запрещал прерывания для неразрывности, всё равно ничего не добился. Смотрел по осцылу время нахождения в режиме передача, но ничего непонял. Сколько реально времени (включая служебные биты 1-четности и 1-стоп 9-ый) будет передавать 2 байта усарт?

Флаг в прерывании сбрасывать ненужно. Это происходит автоматически, если прерывание было вызвано.

Вообще для отладки всего воспользуйтесь терминальной программой и подключите USART МК через MAX232 к com порту компьютера. Так Вы сумеете устранить все ошибки без особого усилия.
arttab
Заслали Вы в буфер байт или 2 байта.
начинается передача. если буфер пуст, то выставляется UDRE. Но передача еще идет и в случаее RS485 нельзя переключаться на прием. Когда буфер будет пуст и будет отправлен последний бит, то выставиться TXC.


Я использую оба флага. По UDRE подкачиваю данные в буфер, а поTXC перехожу на прием.
haker_fox
Цитата(arttab @ Aug 20 2007, 13:04) *
Но передача еще идет и в случаее RS485 нельзя переключаться на прием. Когда буфер будет пуст и будет отправлен последний бит, то выставиться TXC.

Прошу прощения, не учел особенностей RS485 01.gif
vesago
Для 485 я пользую следующие конструкции:
Код
//POPTE
#define RXD0                0
#define TXD0                1

#define RS485_DDR           DDRE
#define RS485_PORT          PORTE
#define RS485_PIN           PINE

#define GL_BUS_DIR          2
#define Global_Bus_RS485_Dir_RX() {RS485_PORT &= ~(1<<GL_BUS_DIR);}
#define Global_Bus_RS485_Dir_TX() {RS485_PORT |= (1<<GL_BUS_DIR);}

#define LL_BUS_DIR          3
#define Local_Bus_RS485_Dir_RX()  {RS485_PORT &= ~(1<<LL_BUS_DIR);}
#define Local_Bus_RS485_Dir_TX()  {RS485_PORT |= (1<<LL_BUS_DIR);}

//::::::::::::::::::::::::::::::::::::::::::::::::::::::
// Запрет приема
//::::::::::::::::::::::::::::::::::::::::::::::::::::::
void USART0_DisableRecive(void)
{
  UCSR0B &= ~(1 << RXEN0);
  Global_Bus_RS485_Dir_TX();
}

//::::::::::::::::::::::::::::::::::::::::::::::::::::::
// Разрешение приема
//::::::::::::::::::::::::::::::::::::::::::::::::::::::
void USART0_EnableRecive(void)
{
  Global_Bus_RS485_Dir_RX();
  UCSR0B |= (1 << RXEN0);
}


#pragma vector=USART0_TXC_vect
__interrupt void USART0_TX_interrupt( void )
{
  if((usart0.flags & (1<<USART0_FLAG_TX_COMPLETE)) != 0)
  {
    usart0.flags &= ~(1<<USART0_FLAG_TX_COMPLETE);
    usart0.flags |= (1<<USART0_FLAG_SHIFT_REG_EMPTY);
    USART0_EnableRecive();
  }
}


Перед передачей отключаю приемник и переключаю драйвер. По прерыванию переключаю драйвер и включаю приемник.
fmdost
Цитата(arttab @ Aug 20 2007, 08:04) *
Заслали Вы в буфер байт или 2 байта.
начинается передача. если буфер пуст, то выставляется UDRE. Но передача еще идет и в случаее RS485 нельзя переключаться на прием. Когда буфер будет пуст и будет отправлен последний бит, то выставиться TXC.
Я использую оба флага. По UDRE подкачиваю данные в буфер, а поTXC перехожу на прием.

Тоесть флаг TXC выставляется только по окончании передачи ВСЕГО? Но у меня почемуто не работает! Вечером заменю камень и перепроверю.
IEC
Цитата(Т.Достоевский @ Aug 20 2007, 02:46) *
Сколько реально времени (включая служебные биты 1-четности и 1-стоп 9-ый) будет передавать 2 байта усарт?

Зависит от скорости передачи Ftx (Бод -> бит в секуду )
Ttx = 1/Ftx - передача одного бита данных в секундах.
fmdost
Цитата(vesago @ Aug 20 2007, 11:06) *
Код
#pragma vector=USART0_TXC_vect
__interrupt void USART0_TX_interrupt( void )
{
  if((usart0.flags & (1<<USART0_FLAG_TX_COMPLETE)) != 0) ???????????????????? ВОТ ЭТА ??????????
  {
    usart0.flags &= ~(1<<USART0_FLAG_TX_COMPLETE);
    usart0.flags |= (1<<USART0_FLAG_SHIFT_REG_EMPTY);
    USART0_EnableRecive();
  }
}

Перед передачей отключаю приемник и переключаю драйвер. По прерыванию переключаю драйвер и включаю приемник.

Не совсем понял Ваш код в прерывании. Зачем нужна проверка флага?
IEC
Цитата(Т.Достоевский @ Aug 20 2007, 13:44) *
Тоесть флаг TXC выставляется только по окончании передачи ВСЕГО? Но у меня почемуто не работает! Вечером заменю камень и перепроверю.

ВСЕГО байта, который был отправлен в буфер, т.е. после передачи стопового бита!!!
fmdost
Цитата(IEC @ Aug 20 2007, 14:49) *
ВСЕГО байта, который был отправлен в буфер, т.е. после передачи стопового бита!!!

Тоесть если Я отослал в буфер 2 байта то и прерываний будет 2?

Цитата(IEC @ Aug 20 2007, 14:46) *
Зависит от скорости передачи Ftx (Бод -> бит в секуду )
Ttx = 1/Ftx - передача одного бита данных в секундах.

Спасибо! Незнал длинну битов "старт" и "стоп". По привычке считал её отличающейся от длинны обычных бит.
SasaVitebsk
Цитата(Т.Достоевский @ Aug 20 2007, 14:02) *
Тоесть если Я отослал в буфер 2 байта то и прерываний будет 2?
Спасибо! Незнал длинну битов "старт" и "стоп". По привычке считал её отличающейся от длинны обычных бит.

Длина старт бита "по привычке" всегда была один бит. А длина стопа может быть 1-1.5-2 бита и задаётся вами же при инициализации УСАРТА. Смотрите внимательнее описалово.

Если вы отослали 2 байта, то вы получите 2 прерывания: сначала UDRE потом TXC. Если передадите по первому UDRE третий байт, то получите 2 UDRE и один TXC.

Цитата(haker_fox @ Aug 20 2007, 14:02) *
Честно говоря никогда не испольвал этот флаг. Использую вместо него UDRE, он выставляется если регистр данных передатчика пуст и готов к отправке следующего байта. Рекомендую воспользоваться этим прерыванием.
....
Прошу прощения, не учел особенностей RS485 01.gif


Если хотите получить максимальную скорость обмена, то правильно будет использовать оба флага и при работе с RS232. По-моему это очевидно.
defunct
Цитата
Работает только если после передачи первого байта проверять флаг вручную и передавать второй байт после его установки. Соответственно так же переключаю на приём.

Не надо ничего проверять.
Сделайте очередь.
В прерывании TXC посылайте следующий байт - если нечего слать - то переключайте линию на прием.

PS: вы на чем пишете программу? asm/c?

Цитата
Честно говоря никогда не испольвал этот флаг. Использую вместо него UDRE, он выставляется если регистр данных передатчика пуст

честно говоря никогда не использовал UDRE. Т.к. по TXC все что связано с 485-м реализуется гораздо удобнее, как бонус даже межсимвольный интервал непроизвольно получается.
fmdost
Цитата(defunct @ Aug 20 2007, 19:46) *
Не надо ничего проверять.
Сделайте очередь.
В прерывании TXC посылайте следующий байт - если нечего слать - то переключайте линию на прием.

PS: вы на чем пишете программу? asm/c?
честно говоря никогда не использовал UDRE. Т.к. по TXC все что связано с 485-м реализуется гораздо удобнее, как бонус даже межсимвольный интервал непроизвольно получается.

Пишу на асме. Вот и Я этот бонус захотел. Всётаки наверное камень глючит. Походу 2 прерывания даёт.
Посылаю сразу 2 байта. И получаю 2 прерывания по TXC! К сожалению новый будет только в четверг!
SasaVitebsk
Цитата(Т.Достоевский @ Aug 20 2007, 23:11) *
Пишу на асме. Вот и Я этот бонус захотел. Всётаки наверное камень глючит. Походу 2 прерывания даёт.
Посылаю сразу 2 байта. И получаю 2 прерывания по TXC! К сожалению новый будет только в четверг!


Простите пожалуйста, но лично у меня фраза "камень глючит" или "винда не так села" вызывает пену у рта и лёгкое подколбашивание. Кто-то на форуме собирал камни которые "глючат" как редкую реликвию. И, наверное перекупили бы у вас такой камень. К сожалению, скорее всего "глючит" другой прибор не техногенного происхождения. Во всяком случае с очень большой долей вероятности.

Я бы рекомендовал провести больше тестов и лучше изучить работу USARTа на большем числе простейших тестах. Прерывание пока отложить, а просто анализировать регистр флагов выводя его в какой-нибудь порт. Так как похоже отладчика у вас нет.
defunct
Цитата(Т.Достоевский @ Aug 20 2007, 23:11) *
Пишу на асме. Вот и Я этот бонус захотел. Всётаки наверное камень глючит. Походу 2 прерывания даёт.
Посылаю сразу 2 байта. И получаю 2 прерывания по TXC! К сожалению новый будет только в четверг!

Я где-то приводил пример работы с UART на asm'e..
Искать долго, поэтому просто прикляю его еще раз.
смотрите в атаче.

Пример написан под AT90S2313, чтобы переделать под Tiny2313 надо будет поменять таблицу векторов и возможно пару штрихов с настройкой UART'a. Так же надо будет выставить константы Fosc и BaudRate согласно вашим потребностям.

константа
.equ PD7 = 7 ; // объявим константу которая не прописана в .inc файле

используется как флажек (прием/передачи)
поменяйте ее на Pin которым у вас меняется направление (прием/передача) 485-го.

Цитата
у меня фраза "камень глючит" или "винда не так села" вызывает ....

Согласен. Камень тут не причем.
2 TXC на 2 переданных байта - абсолютно нормальное поведение чипа.
fmdost
Цитата(defunct @ Aug 21 2007, 04:41) *
2 TXC на 2 переданных байта - абсолютно нормальное поведение чипа.

Вот именно такой прямой ответ я и хотел получить! Огромное спасибо! Ибо "Атмеловский английский" неразумею. Им наверное построчно плотют. Ка-кто смутно и коротко у них там описана работа буферизации USART. Было бы логично если бы флаг TXC устанавливался по ОПУСТОШЕНИЮ буфера. Но похоже он устанавливается по окончанию передачи одного байта из двух что в буфере. Соответственно возникают 2 прерывания вместо ожидаемого 1го. То-есть не получится сделать совсем красиво. Досадно.
Спасибо за исходники.


Цитата(SasaVitebsk @ Aug 21 2007, 02:56) *
Простите пожалуйста, но лично у меня фраза "камень глючит" или "винда не так села" вызывает пену у рта и лёгкое подколбашивание. Кто-то на форуме собирал камни которые "глючат" как редкую реликвию. И, наверное перекупили бы у вас такой камень. К сожалению, скорее всего "глючит" другой прибор не техногенного происхождения. Во всяком случае с очень большой долей вероятности.

Впоне возможно что глючу Я. А камень продам по сходящей тк. он уже в 2 раза питался 12 вольтами.

Что вы понимаете под словом "отладчик"?
arttab
Почему получается 2 прерывания по TXC при передачи 2-х байт не понял. может я не правильно помню и делаю иначе, но с таким не встречался.
На память TXC возникает при пустом буфере и выдачи стопового бита.
На я передачу делал так.
2 байта в буфер;
включить UDRE
по UDRE подкачивать данные
если новых двнных нет, то выключить UDRE и включить TXC
если TXC, то все переданно, переключиться на прием.

и таких вещей
Цитата
как бонус даже межсимвольный интервал непроизвольно получается.
у меня не было
Igor26
Цитата
Что вы понимаете под словом "отладчик"?


JTAGICE
WHALE
А AVRSTUDIO че не пользуете?Такие вещи там нормально симулируются.
fmdost
Цитата(WHALE @ Aug 21 2007, 10:10) *
А AVRSTUDIO че не пользуете?Такие вещи там нормально симулируются.

А разве там есть окно COM порта? У меня 4,12 с обработкой прерываний там туго.
vesago
Цитата(Т.Достоевский @ Aug 20 2007, 13:47) *
Не совсем понял Ваш код в прерывании. Зачем нужна проверка флага?

Я выложил свои дровишки. Там у меня передача и прем идет через кольцевые буфера. По прерыванию передатчика при загрузке последнего байта в уарт, выставляется флаг окончания передачи. Далее по прерыванию TXC, которое свидетельствует о опустошении сдвигового регистра, при выставленном упомянутом флаге снова разрешается прием данных и переключение драйвера 485. То есть прием будет включен только после полной передачи пакета.
Rst7
Цитата(arttab @ Aug 21 2007, 07:53) *
Почему получается 2 прерывания по TXC при передачи 2-х байт не понял. может я не правильно помню и делаю иначе, но с таким не встречался.
На память TXC возникает при пустом буфере и выдачи стопового бита.


Безусловно. Прямо так и написано:

Цитата
The Transmit Complete (TXC) flag bit is set one when the entire frame in the Transmit
Shift Register has been shifted out and there are no new data currently present in the
transmit buffer


Цитата
На я передачу делал так.
2 байта в буфер;
включить UDRE
по UDRE подкачивать данные
если новых двнных нет, то выключить UDRE и включить TXC
если TXC, то все переданно, переключиться на прием.

и таких вещей у меня не было


Ну в принципе даже разрешение TXC можно не дергать, если вы можете дать гарантию, что время реакции на UDRE не превысит времени передачи символа. Тогда TXC придет ТОЛЬКО ОДИН в конце пакета. Как раз, чтобы выключить передатчик на ADM485 smile.gif

Вообщем-то все культурно и правильно в камне. Работать в принципе по UDRE и надо, чтобы не было дырок между символами (они только уменьшают общую скорость передачи).
defunct
Цитата(Rst7 @ Aug 21 2007, 13:59) *
Вообщем-то все культурно и правильно в камне. Работать в принципе по UDRE и надо, чтобы не было дырок между символами (они только уменьшают общую скорость передачи).

Они (всмысле межсимвольные интервалы) добавляют стабильности передачи. В Modbus - межсимвольный интервал is a MUST.
А скорость, кому она нужна в 485?

Цитата
Почему получается 2 прерывания по TXC при передачи 2-х байт не понял.

Потому что отправляется два символа. После отправки каждого генерится TXC, если игнорировать UDRE.
Rst7
Цитата(defunct @ Aug 21 2007, 14:47) *
Они (всмысле межсимвольные интервалы) добавляют стабильности передачи.


Обоснуйте?

Цитата
В Modbus - межсимвольный интервал is a MUST.


Межпакетный да, а вот межсимвольный??? Можно цитату?

Цитата
А скорость, кому она нужна в 485?


Ну не скажите... Разные случаи есть..
IEC
Цитата(Rst7 @ Aug 21 2007, 13:59) *
Работать в принципе по UDRE и надо, чтобы не было дырок между символами (они только уменьшают общую скорость передачи).

Оно то может и так, но привычка с 51 осталась. Там аналога UDRE нет.
Да и немного неудобно. UDRE устанавливается всегда, когда буфер на передачу пуст (срабатывание по состоянию). А если я не хочу передавать, надо прерывание запрещать.
Прерывание ТХС устанавливается по событию, сбросил после передачи последнего байта и свободен до следующей передачи.
Maik-vs
Цитата(Т.Достоевский @ Aug 21 2007, 13:44) *
А разве там есть окно COM порта? У меня 4,12 с обработкой прерываний там туго.

07.gif Чойто туго??! Там можешь руками поднять бит прерывания - и вот оно, появилось. Или маску. Или ещё что, всё работает. Наоборот, оч. хорошо там с прерываниями вручную. Приём только так и отлаживал - включаешь RXC - сразу прерываание, побежал обрабатывать байт... smile.gif
По поводу TXC/UDRE. Пользую их оба, для 485, ага. Чтобы отправить строку байтов, переключаю интерфейс на выход и записываю байт в UDR. Всё! дальше прерывания сами. Тут же байт из UDR проваливается в регистр сдвига и возникает прерывание UDRI. Обработчик смотрит: все байты передал? нет: следующий в UDR; да: ничего. Когда последний байт передан, возникает TXCI. Его обработчик переключает RS485 на приём. Всё.
defunct
Цитата(Rst7 @ Aug 21 2007, 14:59) *
Обоснуйте?

Ну например - передатчик работает 8-1-N, а приемник включили 8-2-N.
С отправкой "по TXC" с большой долей вероятности ошибок приема не будет.

Цитата
Межпакетный да, а вот межсимвольный??? Можно цитату?

Таки действительно органичение "снизу" только на межпакетный - "Character gap interval".

На межсимвольный "silent interval" ограничение "сверху":
Цитата
The entire message must be transmitted as a continuous stream. If a silent interval of
more than 1.5 character times occurs before completion of the frame (not a continuous stream),
the receiving device flushes the incomplete message and assumes the next byte will be the
address field of a new message.

источник:
http://www.sena.com/download/tutorial/tech_Modbus_v1r0c0.pdf (150k)
cм. секцию 5.2

Цитата
Ну не скажите... Разные случаи есть..

Может быть, но мне что-то такие случаи в сетях 485 не подворачивались.
WHALE
Цитата(Maik-vs @ Aug 21 2007, 17:59) *
07.gif Чойто туго??! Там можешь руками поднять бит прерывания - и вот оно, появилось. Или маску. Или ещё что, всё работает. Наоборот, оч. хорошо там с прерываниями вручную. Приём только так и отлаживал - включаешь RXC - сразу прерываание, побежал обрабатывать байт... smile.gif

Дык у аффтара проблемы с передачей,значит руками флаги дергать ваще не надо.байт в UDR -и смотри
чего-там с прерываниями.И скачайте версию 4.13,там атымельцы здорово над переферией поработали.
SasaVitebsk
А я был очень рад увидеть два флага. Наверное после х51. Да и в 4414 только один байт буферизовался. Иногда для RS232 при высокой скорости и плотности передачи Именно чтобы избежать межбайтовых интервалов очень необходимы оба флага. В идеале конечно можно было бы и байт 16 впихнуть в аппаратный буфер. Но два лучше чем один. Короче использовать или нет - это программисту решать, а вот наличие - это замечательно. Использую 2 флага и в 485 и в 232.
Rst7
Цитата(defunct @ Aug 21 2007, 18:48) *
Ну например - передатчик работает 8-1-N, а приемник включили 8-2-N.
С отправкой "по TXC" с большой долей вероятности ошибок приема не будет.


Так включите и в передатчике 9 бит с установленным девятым битом... А ручные задержки для добавления бита - это моветон... А задержки, которые еще и неизвестно какой длительности (ну сколько времени там будет от TXC до записи в UDR) - как говорится, это ваще wink.gif

Цитата
Таки действительно органичение "снизу" только на межпакетный - "Character gap interval".

На межсимвольный "silent interval" ограничение "сверху":

источник:
http://www.sena.com/download/tutorial/tech_Modbus_v1r0c0.pdf (150k)
cм. секцию 5.2


Посему оптимально будет посылка именно без интервалов.

Цитата
Может быть, но мне что-то такие случаи в сетях 485 не подворачивались.


Ну надо минимизировать время опроса в сети при ограничении битовой скорости. Вот и весь случай.
Maik-vs
Цитата(WHALE @ Aug 21 2007, 21:45) *
Дык у аффтара проблемы с передачей,значит руками флаги дергать ваще не надо.байт в UDR -и смотри
чего-там с прерываниями.И скачайте версию 4.13,там атымельцы здорово над переферией поработали.


Согласен. Я удивился, как он этих флагов не видел. Или мышой не ткнул?
А что нового в периферии в 4.13? У меня только нумерацию битов приходится всё время включать, больше новостей не заметил. Проц М16.
ReAl
Цитата(Rst7 @ Aug 21 2007, 12:59) *
Ну в принципе даже разрешение TXC можно не дергать, если вы можете дать гарантию, что время реакции на UDRE не превысит времени передачи символа.
Ещё можно тупо в прерывании UDRE - если производится запись очередного байта в UDR, то не глядя заодно сбрасывать флаг TXC. В суме это даёт меньше кода, чем разрешение/запрещение TXCIE и защищает от задержки отработки UDRE.
Так как если были запрещены прерывания и UDRE не отработало своевременно, успел установиться флаг TXC, то при разрешении прерываний (выходе из другого прерывания) первым будет передано управление на UDRE_vect.
=GM=
To defunct. Посмотрел на ваш код.
Цитата(defunct @ Aug 20 2007, 23:41) *
Пример написан под AT90S2313, чтобы переделать под Tiny2313 надо будет поменять таблицу векторов и возможно пару штрихов с настройкой UART'a

Одно место меня озадачило, в теле подпрограммы PutChar вы снова вызываете PutChar. Это что, такая рекурсия заложена, или как? Вроде не должно работать.
defunct
Цитата(=GM= @ Aug 22 2007, 13:09) *
Одно место меня озадачило, в теле подпрограммы PutChar вы снова вызываете PutChar. Это что, такая рекурсия заложена, или как?

Спасибо что проявили интерес ;>
Да - там рекурсия.
посылаем строку "hello\n"
putchar автоматически добавит возврат каретки и терминал примет "hello\r\n".

Цитата
Вроде не должно работать.

Попробуйте код. ;>
Какой резон мне выкладывать что-то нерабочее?
=GM=
Цитата(defunct @ Aug 22 2007, 11:55) *
Да - там рекурсия

Посмотрел попристальнее - нет там никакой рекурсии. И вообще, проще было бы вызывать не rcall PutChar, a rcall __skip_add_cr (ну и названьице(:-)). И выполнение было бы быстрее, ведь рутина у вас и в прерывании вызывается...

Цитата(defunct @ Aug 22 2007, 11:55) *
Попробуйте код

А чего его пробовать, и так видно, что тяжеловесно и неоптимально. Например, фрагмент с кольцевым буфером можно написать в два раза короче. А что там за пляски с бубнами в PutChar: in AH,SREG cli + out SREG,AH? Не проще ли обойтись связкой cli/sei. Или вот: зачем стоит tst AL перед rcall PutChar в рутине Print?
defunct
Цитата(=GM= @ Aug 23 2007, 12:19) *
Посмотрел попристальнее - нет там никакой рекурсии.

Смотрите пристальнее сразу. Ок?
Есть там рекурсия, коль скоро функция вызывает сама себя.

Цитата
проще было бы вызывать не rcall PutChar, a rcall __skip_add_cr (ну и названьице(:-)).

Не сомневаюсь что вы именно так и поступаете, у меня же все метки начинающиеся с "__" внутренние и я стараюсь их не вызывать, чтобы было меньше путаницы.

Цитата
А что там за пляски с бубнами в PutChar: in AH,SREG cli + out SREG,AH? Не проще ли обойтись связкой cli/sei. Или вот: зачем стоит tst AL перед rcall PutChar в рутине Print?

Не проще. Потому что вызывается эта функция еще и в прерывании.

И вообще прежде чем хаить хамоватым тоном - разберитесь с кодом.

Цитата
Или вот: зачем стоит tst AL перед rcall PutChar в рутине Print?

опечатка.
=GM=
Цитата(defunct @ Aug 23 2007, 11:49) *
Есть там рекурсия, коль скоро функция вызывает сама себя.

Ну-ну, tell it your sailors(:-). Рекурсии там нет. Рекурсия – это сведение вычисления задачи некоторой размерности N к вычислению аналогичных задач меньшей размерности. Вот пример классической рекурсии.
Код
Задача заключается в том, чтобы найти по заданному n число последовательности Фибоначчи Fn.
#include <stdio.h>
#include <time.h>
long F(unsigned int n)
{
  return n <= 1 ? n : F(n-1) + F(n-2);
}
int main()
{
  time_t begin, end;
  long res;
  for(int n = 0; n < 40; n++)
  {
    time(&begin);
    res = F(n);
    time(&end);
    printf("%-3i\t%-9li\t%-20.3f\n",n,res,difftime(end,begin));
  }
  return 0;
}

Кстати, цикл является частным видом рекурсии. У вас ни того, ни другого.
Цитата(defunct @ Aug 23 2007, 11:49) *
Не сомневаюсь что вы именно так и поступаете, у меня же все метки начинающиеся с "__" внутренние и я стараюсь их не вызывать, чтобы было меньше путаницы.

Дорогой мой, зачем метки тогда вообще писать. Я пишу программы так, чтобы они были эффективные и красивые, а не какие-то там крокозябры (это не вам).
Цитата(defunct @ Aug 23 2007, 11:49) *
Не проще. Потому что вызывается эта функция еще и в прерывании.

Ну хорошо, не проще, так не проще. Сейчас я вам покажу как ваш код работает. Выполняется программа Print, перед brne возникает прерывание по приему с rx. Программа прерывания запишет принятый байт внутрь строки, которую программа Print собирается поместить в кольцевой буфер. В результате вы получите не ту строку, которую копировали из флеши, а несколько другую. Я бы назвал сиё скрытым (неявным) багом.
Цитата(defunct @ Aug 23 2007, 11:49) *
И вообще прежде чем хаить хамоватым тоном - разберитесь с кодом

Прошу прощения, если кого-то обидел, но я никому не хамил и никого не хаял. Была выложена программа, идёт её обсуждение, ничего личного.
defunct
Цитата(=GM= @ Aug 23 2007, 19:14) *
Ну-ну, tell it your sailors(:-). Рекурсии там нет. Рекурсия – это сведение вычисления задачи некоторой размерности N к вычислению аналогичных задач меньшей размерности. Вот пример классической рекурсии.


Ваше определение рекурсии и пример - неверны. либо взяты не из той предметной области.

рекурсия — частичное определение объекта через себя, определение объекта с использованием ранее определённых. Рекурсия используется, когда можно выделить самоподобие задачи.

В программировании рекурсия — вызов функции или процедуры из неё же самой

источник:
http://ru.wikipedia.org/wiki/Рекурсия

Цитата
Ну хорошо, не проще, так не проще. Сейчас я вам покажу как ваш код работает.

lol.gif

Цитата
Выполняется программа Print, перед brne возникает прерывание по приему с rx. Программа прерывания запишет принятый байт внутрь строки, которую программа Print собирается поместить в кольцевой буфер. В результате вы получите не ту строку, которую копировали из флеши, а несколько другую. Я бы назвал сиё скрытым (неявным) багом.

Теоретически возможно. Атомарность Print я не организовывал.
Но конструкция реализованная в PutChar не препятствует организации атомарности Print.

тем же самым in Rr, SREG - cli - out SREG, Rr

Цитата
Дорогой мой, зачем метки тогда вообще писать.

Во-первых выбирайте выражения. Своему бойфренду можете говорить "дорогой мой".
Во-вторых, я не виноват что русский язык порождает неоднозначность ("не вызывать" - имелось в виду "call" не делать. )
в третьих - это такой стиль - для обозначения внутренних меток (локальных для функций) на которые осуществяется условный переход я применю "тэг" - "__".
SasaVitebsk
=GM=, при всём уважении к Вашим знаниям давайте будем добрее друг к другу. Так вы отобъёте всякое желание выложить свою прогу, чтобы кому-то помочь. smile.gif
Любая маломальски приличная прога содержит ошибки. Иногда их вылавливаешь годами. Плюс различные предпочтения у каждого программиста. Это как аккорды на гитаре. Один пользуется чаще такими а другой другими. Но если оба музыканта, то музыка всё равно звучит. smile.gif
WHALE
Цитата
Рекурсия – это сведение вычисления задачи некоторой размерности N к вычислению аналогичных задач меньшей размерности

А откуда такое определение рекурмии,ссылку можно?

Цитата
В программировании рекурсия — вызов функции или процедуры из неё же самой

Вот с этим не поспоришь.
И чего-вы к обозначению внутренних меток прицепились?По моему,нормальная идея визуально разделять локальные и глобальные метки.
З.Ы. вы кодер,не знающий ошибок?
=GM=
Цитата(defunct @ Aug 23 2007, 17:54) *
Ваше определение рекурсии и пример - неверны. либо взяты не из той предметной области. рекурсия — частичное определение объекта через себя, определение объекта с использованием ранее определённых. Рекурсия используется, когда можно выделить самоподобие задачи.

Мой пример классический, не я его выдумал, взгляните на него непредвзято (заменил там рекурсивную функцию F на более заметную RECURRENCE).
Код
long RECURRENCE(unsigned int n)
{
  return n <= 1 ? n : RECURRENCE(n-1) + RECURRENCE(n-2);
}

Напишите ваш код PutChar на си в таком же виде, тогда и будем говорить, что верно, а что неверно. Интересно, что у вас будет параметром рекурсии?
Цитата(defunct @ Aug 23 2007, 17:54) *
Теоретически возможно. Атомарность Print я не организовывал.
Но конструкция, реализованная в PutChar не препятствует организации атомарности Print.
тем же самым in Rr, SREG - cli - out SREG, Rr

Так я и сказал. что все эти примочки внутри PutChar не нужны, не решают они задачу до конца, а снаружи атомарность передачи строки вы не обеспечили. И не теоретически, а сугубо практически, поверьте.
Цитата(defunct @ Aug 23 2007, 17:54) *
Во-первых, выбирайте выражения. Своему бойфренду можете говорить "дорогой мой"

Да что ж такое! Такое впечатление, что или у всех мозги такие извращенные, или все свихнулись на этой секссвободе, что ни скажешь, всё переводят в плоскость гениталий. Вы уж, уважаемый, тоже слова выбирайте.


Цитата(SasaVitebsk @ Aug 23 2007, 18:16) *
=GM=, при всём уважении к Вашим знаниям давайте будем добрее друг к другу. Так вы отобъёте всякое желание выложить свою прогу, чтобы кому-то помочь. smile.gif

Знаний как раз маловато, спасибо форуму, много даёт в плане самообразования. Да я...белый и пушистый, defunct'а почти люблю (как брата, а то опять поймет не в той плоскости(:-)). Что касается проги, не собирался я её критиковать, с первого взгляда она мне понравилась, посмотрел по диагонали - в подпрограмме вывода символа вроде используется рекурсия, вот думаю, люди рекурсию применяют, а я от неё как чёрт от ладана, ну я и спросил спроста, а потом уж стал смотреть, а он мне отвечает, да, там рекурсия, да какая рекурсия, курам на смех
Цитата(SasaVitebsk @ Aug 23 2007, 18:16) *
Любая мало-мальски приличная прога содержит ошибки. Иногда их вылавливаешь годами. Плюс различные предпочтения у каждого программиста. Это как аккорды на гитаре. Один пользуется чаще такими, а другой другими. Но если оба музыканта, то музыка всё равно звучит. smile.gif

Согласен. Ошибок в любой программе полно, у самого так. Смотришь на программу годичной давности, и думаешь, неужели это я написал такое гуано? Ну посмотрел я его программу, ну высказал замечания, будь благодарен, что кто-то потратил своё время, разобрался, принял участие, ответил, что плохого? Почему сразу надо воспринимать как наезд, которого и в помине не было. Дефункту не надо было говорить, чтоб код испытал(:-). Да если б все мои программы так критиковали, это было бы здорово, и программы были бы в стократ лучше...
defunct
Цитата(=GM= @ Aug 24 2007, 00:29) *
Мой пример классический, не я его выдумал, взгляните на него непредвзято (заменил там рекурсивную функцию F на более заметную RECURRENCE).

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

Цитата
Напишите ваш код PutChar на си в таком же виде, тогда и будем говорить, что верно, а что неверно. Интересно, что у вас будет параметром рекурсии?

отправляемый char, а что еще может быть параметром?
функциональный аналог ассемблерной функции:

Код
void put(U8 ch)
{
    if (ch == 0x0A) // add CR char ahead of LF
        put(0x0D);
    {
        U8 IStatus = ILock()
        pRing->storage[ pRing->tail ] = ch;
        pRing->tail = RingNextTail( pRing );
        IUnlock( IStatus );
    }
}



Цитата
Так я и сказал. что все эти примочки внутри PutChar не нужны, не решают они задачу до конца,

Это вам так кажется.
Примочки внутри putchar решают свои задачи:
- атомарность выгрузки символа в очередь
- добавление символа CR

Цитата
а снаружи атомарность передачи строки вы не обеспечили. И не теоретически, а сугубо практически, поверьте.

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

поменять Print так:
Код
/*
* Print()
* Выводит строки размещенные во флеш памяти через PutChar
* ---> Z - указатель на строку оканчиваемую \0 во флеш
* <--- ничего не возвращает
*/
Print:
    in    AH, SREG
    push  AH
    cli
__do_output:    
    lpm; // читаем данные флеш
    adiw  Z, 1  // увеличим указатель на 1 (z++)
    mov   AL, R0
    rcall PutChar
    tst   AL
    brne  __do_output
    
    pop   AH
    out   SREG, AH
    ret

и будет обеспечиваться атомарность.
push/pop конечно же можно сократить если использовать какой-либо другой регистр для хранения SREG вместо AH, но поставил специально для наглядности.

Цитата
да какая рекурсия, курам на смех

Маленькая простенькая - но рекурсия, т.к. функция вызывает сама себя.
Прочитайте определение рекурсии на wiki.


Цитата
Ну посмотрел я его программу, ну высказал замечания, будь благодарен, что кто-то потратил своё время, разобрался, принял участие, ответил, что плохого?

Я выразил вам благодарность и попытался нормально ответить на ваши вопросы вначале.

PS: я и сейчас пытаюсь отвечать на ваши вопросы по-сущесту, с приведением ссылок и примеров. Может вы просто не замечаете?
=GM=
Цитата(defunct @ Aug 23 2007, 21:57) *
Уж не пойму или у меня там полный бред в коде или у вас проблемы с прочтением алгоритма из асм программы. поменять Print так:
Код
/*
* Print()
* Выводит строки размещенный во флеш памяти через UART
* ---> Z - указатель на строку оканчиваемую \0 во флеш
* <--- ничего не возвращает
*/
Print:    in    AH, SREG
    push  AH
    cli
__do_output:    
    lpm; // читаем данные флеш
    adiw  Z, 1  // увеличим указатель на 1 (z++)
    mov   AL, R0
    rcall PutChar
    tst   AL
    brne  __do_output
    pop   AH
    out   SREG, AH
    ret

и будет обеспечиваться атомарность

Ну, это другое дело. Но тогда сохранение/восстановление статус-регистра в PutChar не нужно, о чём я и толкую последние две страницы.

Кстати, неплохо бы добавить проверку на переполнение буфера в подпрограмме обработки прерываний по приему. UART_RX_ISR так и будет писать по кругу, никаких ограничений у вас нет, возможен скрытый баг.
defunct
Цитата(=GM= @ Aug 24 2007, 01:22) *
Ну, это другое дело. Но тогда сохранение/восстановление статус-регистра в PutChar не нужно, о чём я и толкую последние две страницы.

Нужно! Т.к. PutChar автономная функция, и кроме Print может быть использована где угодно.
"Лучше перебдеть чем "недобдеть" ;>

Цитата
Кстати, неплохо бы добавить проверку на переполнение буфера в подпрограмме обработки прерываний по приему.

Это так и было задумано..
Практика показывает что для консольных приложений (а пример относился как раз консоли) много лучше допускать опустошение Tx (при переполнении) чем притормаживать CPU ожиданием освобождения места.

Цитата
UART_RX_ISR так и будет писать по кругу, никаких ограничений у вас нет, возможен скрытый баг.

RX_ISR в идеале должен работать со входной очередью.
Вывод "Эхо" по скорости заполнения не быстрее TX, переполнений по вине RX потока быть не должно. Ну а в случае когда полный overload, то деваться некуда или сбросить TX очередь или ждать окончания TX. Но мы не можем торчать в прерывании и ждать когда освободится место в очереди..
=GM=
Открыл новую тему на предмет написания и использования циклических буферов, показал своё видение предмета. Приглашаю к обсуждению.
fmdost
С новым камнем всё заработало. Проблема была не с USART а с подпаленными ногами.
Да, действительно флаг TXC появляется только по опустошению буфера. А не на каждый байт.
В авр студио флаг UDRE появляется если оба байта буфера пусты. В прерывании по UDRE передаю байт и прерывание повторяется ещё раз. Тоесть по флагу UDRE можно передавать сразу 2 байта! Передачу сразу 2х байт по UDRE в железе не проверял(нет времени, чуть позже проверю), всё остальное работает прекрасно!
Rst7
Цитата(Т.Достоевский @ Aug 28 2007, 00:29) *
С новым камнем всё заработало. Проблема была не с USART а с подпаленными ногами.
Да, действительно флаг TXC появляется только по опустошению буфера. А не на каждый байт.
В авр студио флаг UDRE появляется если оба байта буфера пусты. В прерывании по UDRE передаю байт и прерывание повторяется ещё раз. Тоесть по флагу UDRE можно передавать сразу 2 байта! Передачу сразу 2х байт по UDRE в железе не проверял(нет времени, чуть позже проверю), всё остальное работает прекрасно!


2 раза сразу только ПЕРВЫЙ раз. UDRE уже выставлен, передачи еще нет. Первый байт сразу влетает в сдвиговый регистр и буфер опустошается, выставляется сразу опять UDRE. А вот следующий будет только тогда, когда вытолкнется самый первый.
Maik-vs
Цитата(Rst7 @ Aug 28 2007, 09:16) *
2 раза сразу только ПЕРВЫЙ раз. UDRE уже выставлен, передачи еще нет. Первый байт сразу влетает в сдвиговый регистр и буфер опустошается, выставляется сразу опять UDRE. А вот следующий будет только тогда, когда вытолкнется самый первый.


Именно так! А не "передавать сразу 2 байта"... И АВРстудио честно всё показывает. Не "флаг UDRE появляется если оба байта буфера пусты", а если пуст только UDR. Тщательнее надо, тов. Достоевский!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.