У меня вот сейчас весьма сложный проект более 20к строк, там активно юзается can и usart, и вот с usart-ом начинаются какие-то гонки если канал загружать...Я вот боюсь что связано как раз с моим не грамотным подходом в силу юности и неопытности =(
Мелкие вопросы по МК и ПЛИС.
- Сообщения: 118
- Зарегистрирован: Ср фев 05, 2014 18:54:39
Добрый день(точнее утро). Немного глупый вопрос - зачем существует прерывание по передаче?Ну к примеру в usart или в i2c или can...Я вот не понимаю, с прерыванием по приём - всё понятно, а вот передача....мы же итак отправляем посылку из тела main в нужное нам время, зачем тогда оно существует? какие задачи на практике решает?
У меня вот сейчас весьма сложный проект более 20к строк, там активно юзается can и usart, и вот с usart-ом начинаются какие-то гонки если канал загружать...Я вот боюсь что связано как раз с моим не грамотным подходом в силу юности и неопытности =(
У меня вот сейчас весьма сложный проект более 20к строк, там активно юзается can и usart, и вот с usart-ом начинаются какие-то гонки если канал загружать...Я вот боюсь что связано как раз с моим не грамотным подходом в силу юности и неопытности =(
- Реклама
2sanyo.95:
Кнопку вы считали и даже переменную нарастили. И ее же считываете процедурой ShowTime. Ясен пень результата работы кнопки не увидите. Вам нужно позаботиться о том, чтобы содержимое hour попало в RTC, т.е. записать его туда.
2jazz393:
Прерывание - всё, канал свободен, можно пихать следующее.
Кнопку вы считали и даже переменную нарастили. И ее же считываете процедурой ShowTime. Ясен пень результата работы кнопки не увидите. Вам нужно позаботиться о том, чтобы содержимое hour попало в RTC, т.е. записать его туда.
2jazz393:
Прерывание - всё, канал свободен, можно пихать следующее.
Docendo discimus
- Сообщения: 118
- Зарегистрирован: Ср фев 05, 2014 18:54:39
не понимаю...итак же данные в канал идут последовательно, или что вы имеете ввиду...pyzhman писал(а):2sanyo.95:
Кнопку вы считали и даже переменную нарастили. И ее же считываете процедурой ShowTime. Ясен пень результата работы кнопки не увидите. Вам нужно позаботиться о том, чтобы содержимое hour попало в RTC, т.е. записать его туда.
2jazz393:
Прерывание - всё, канал свободен, можно пихать следующее.
Чаще всего передавать приходится не 1 байт, а целый пакет. Делать передачу с программным опросом флага готовности неэффективно. Поэтому обычно сначала заполняют буфер, а затем по прерываниям идет его передача. Нужно отметить, что часто существуют два разных флага готовности передатчика: буфер передатчика пуст и передача байта завершена. По первому можно загружать следующий байт для передачи, а по второму можно, скажем, переключать направление трансиверов RS-485.jazz393 писал(а):зачем существует прерывание по передаче?
Прерывания по событиям вообще существуют для разгрузки вычислительного ядра от монотонной работы. Используется при использовании модулей периферии, например аппаратный модуль SPI.
- Реклама
Во время передачи, если не использовать прерывания по передаче или опустошению буфера, контроллер будет простаивать ожидая этот флаг в тупом цикле. На скорости 9600 при тактовой 16М это между прочим 1600 тактов на бит.jazz393 писал(а):Добрый день(точнее утро). Немного глупый вопрос - зачем существует прерывание по передаче?Ну к примеру в usart или в i2c или can...Я вот не понимаю, с прерыванием по приём - всё понятно, а вот передача....мы же итак отправляем посылку из тела main в нужное нам время, зачем тогда оно существует?
Если использовать прерывания, то во время передачи символа контроллер будет делать другие полезные вещи.
А если вам надо килобайт данных переслать на скорости 9600? Вы будете 10 секунд ждать и ничего не делать?
PS:пока писал, уже ответили
Видимо ваши 20к строк надо как-то оптимизировать. У меня в самом сложном проекте всего около 1500 строк (а в ассемблере каждая строка это отдельная инструкция, не считая директив компилятора), при этом UART используются 95% времени, SPI 50% и контроллер приспокойно успевает просчитать практически в реальном времени 3 сотни хитрых функций. Без прерываний хрен бы он что успел...
Неправильно собранная из неисправных деталей схема нуждается в отладке и сразу не работает... (С)
- Сообщения: 118
- Зарегистрирован: Ср фев 05, 2014 18:54:39
всем спасибо, сейчас буду пытаться настроить прерывание и оптимизировать всё
О, теперь уже что-то проясняеться. То есть после чтения кнопки и инкремента переменной hour, мне как то нужно записать её в RTC? И как мне это сделать. Спасибо.pyzhman писал(а):Вам нужно позаботиться о том, чтобы содержимое hour попало в RTC, т.е. записать его туда.
- Сообщения: 118
- Зарегистрирован: Ср фев 05, 2014 18:54:39
блин я всёравно не понимаю...ну есть эти 2 флага...
1) генерирует прерывание когда буфер передатчика пуст
т.е. допустим в программе у меня передача сделана так, тюею я в строке while ((UCSR1A & DATA_REGISTER_EMPTY)==0); жду когда флаг освободится...
Не понимаю следующего - как его использовать...если буфер передатчика всёвремя свободен, и мне надо скажем отправить какую-то строку char *str , то как это всё организовывается...? Мне что нужно будет разрешить прерывание, оно (если свободен буфер) вызывается, и записывает в буфер UDR1 = data[z]; затем прерывание возвращается и продолжается выполнять main, когда
флаг UDRE опять сработает, то снова вызывается прерывание и пишется UDR1 = data[z]; , а когда я дохожу до data[z]==0x03 (это признак конца сообщения) то я запрещаю это прерывание и обнуляю z =0; который должен быть глобальным счетчиком...
я правильно понимаю пункт 1?
или же я сначала всё должен записать в UDR1 т.е. UDR1 = data[z++]; в цикле пока data[z]!=0x03, и только затем уже давать добро на отправку?
2)Прерывание по завершению передачи - всёравно не представляю для чего оно на практике ....
и вызывается оно после каждого байта, или после того, как весь UDR1 завершит передачу?
я переводил сейчас даташит но всёравно лучше объясните, а то оттуда картина не очень понятна
1) генерирует прерывание когда буфер передатчика пуст
т.е. допустим в программе у меня передача сделана так, тюею я в строке while ((UCSR1A & DATA_REGISTER_EMPTY)==0); жду когда флаг освободится...
Код: Выделить всё
void uasrt_tx_1(char *data){
unsigned char z=0;
z=0;
do
{
while ((UCSR1A & (1<<UDRE))==0);
UDR1 = data[z++];
}while(data[z-1]!=0x03);
}флаг UDRE опять сработает, то снова вызывается прерывание и пишется UDR1 = data[z]; , а когда я дохожу до data[z]==0x03 (это признак конца сообщения) то я запрещаю это прерывание и обнуляю z =0; который должен быть глобальным счетчиком...
я правильно понимаю пункт 1?
или же я сначала всё должен записать в UDR1 т.е. UDR1 = data[z++]; в цикле пока data[z]!=0x03, и только затем уже давать добро на отправку?
2)Прерывание по завершению передачи - всёравно не представляю для чего оно на практике ....
и вызывается оно после каждого байта, или после того, как весь UDR1 завершит передачу?
я переводил сейчас даташит но всёравно лучше объясните, а то оттуда картина не очень понятна
Вроде верноjazz393 писал(а):блин я всёравно не понимаю...ну есть эти 2 флага...
1)Не понимаю следующего - как его использовать...если буфер передатчика всёвремя свободен, и мне надо скажем отправить какую-то строку char *str , то как это всё организовывается...? Мне что нужно будет разрешить прерывание, оно (если свободен буфер) вызывается, и записывает в буфер UDR1 = data[z]; затем прерывание возврощается и продолжается выполнять main, когда
флаг UDRE опять сработает, то снова вызывается прерывание и пишется UDR1 = data[z]; , а когда я дохожу до data[z]==0x03 (это признак конца сообщения) то я запрещаю это прерывание и обнуляю z -= который должен быть глобальным счетчиком...
я правильно понимаю пункт 1?
Если вы так сделаете, то контроллер быстро перезапишет в UDR1 всю строку посимвольно, а т.к. UDR1 это всего лишь 8 битный регистр, то в нем просто останется последний символ, при этом запись первого запустит процесс передачи (первый байт попадет в сдвиговый регистр). После передачи первого байта, в регистр запишется последний байт и отправится на передачу, т.е. передадутся 1 и последний символы, а вся середина потеряется, вот что примерно получится...jazz393 писал(а): или же я сначала всё должен записать в UDR1 т.е. UDR1 = data[z++]; в цикле пока dztz[z]!=0x03, и только затем уже давать добро на отправку?
Как работает UART подробно описано в даташите на контроллер.
Никакого "всего UDR1" нету, есть 8 битный буферный регистр UDR1 (точнее 2, на вход и выход), так что прерывание вызовется после передачи байта. Контроллер ничего не знает о строках и массивах, он 8 битный, так что вся работа по реализации алгоритмов отправки/приема/обработки массивов данных лежит на разработчике.jazz393 писал(а): 2)Прерывание по завершению передачи - всёравно не представляю для чего оно на практике ....
и вызывается оно после каждого байта, или после того, как весь UDR1 завершит передачу?
Разница в том, что прерывание по пустому буферу, если его включить, будет срабатывать постоянно, если в буфере будет пусто, а прерывание по окончанию передачи срабатывает один раз (до следующей передачи). И срабатывают они в разное время. По пустому буферу прерывание начинает срабатывать как только из UDR байт перемещается в выходной сдвиговый регистр, а по окончанию передачи срабатывает как только из выходного регистра уходят последний байт со стоп битами.
Неправильно собранная из неисправных деталей схема нуждается в отладке и сразу не работает... (С)
- Сообщения: 118
- Зарегистрирован: Ср фев 05, 2014 18:54:39
Да спасибо, впринципе я уже примерно понял как делать - кольцевой буфер на отправку, и в прерывании считывать из него если счетчики записанной инфы и переданной инфы не совпадают
иначе говоря:
Код: Выделить всё
буфер;
флаг_окончания_передачи=0;
обработчик_прерываний_по_передаче_символа{
если буфер не пуст{
извечь из буфера очередной символ и поместить его в UDR;
} иначе {
флаг_окончания_передачи=1;
}
}
передача_строки(строка){
ждать пока флаг_окончания_передачи =0;
флаг_окончания_передачи=0;
буфер=строка;
извлечь из буфера первый символ и поместить его в UDR;
}
главная_функция{
...
разрешить прерывания по передаче символа;
...
передача_строки("Туды её в качель!");
...
}если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Сообщения: 118
- Зарегистрирован: Ср фев 05, 2014 18:54:39
в само прерывание не попадает, отправляет только 1 байт из тела самой функции...
глоб прерывания разрешены и собственно все др прерывания работают...
функция передачи
обр прерываний
глоб прерывания разрешены и собственно все др прерывания работают...
функция передачи
Код: Выделить всё
void transmit_Usart_INT_1(unsigned char *data)
{
unsigned char i=0;
if(flag_tx_rdy_1)
return;
do
{
flag_tx_rdy_1=1;
buf_tx_usart_1[tail_tx_usart_1++]=data[i++];
if(tail_tx_usart_1==48)
tail_tx_usart_1=0;
}while(data[i-1] != 0x03);
if(head_tx_usart_1 != tail_tx_usart_1)
{
UDR1=data[head_tx_usart_1++];
flag_tx_rdy_1=1;
}
UCSR1B |= (1<<UDRIE1)); // разрешаем прерывание
}Код: Выделить всё
interrupt [USART1_TXC] void usart1_tx_isr(void)
{
#asm("cli")
UDR1='k';
// UDR1=buf_tx_usart_1[head_tx_usart_1];
flag_tx_rdy_1=0;
if (++head_tx_usart_1 == 48)
head_tx_usart_1=0;
#asm("sei")
if(head_tx_usart_1 == tail_tx_usart_1)
UCSR1B &= ~(1<<UDRIE1);
return;
}Лишнее. Поправьте если не прав.jazz393 писал(а):Код: Выделить всё
#asm("cli") #asm("sei")
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
- Сообщения: 118
- Зарегистрирован: Ср фев 05, 2014 18:54:39
да там что с ними что без них, просто ещё куча таймеров, это на всякийGudd-Head писал(а):Лишнее. Поправьте если не прав.jazz393 писал(а):Код: Выделить всё
#asm("cli") #asm("sei")
Глобальные прерывания отключаются автоматически при переходе на обработчик прерывания, и автоматически же восстанавливаются при выходе из него. Сказать что будет, если разрешить прерывание внутри самого обработчика прерывания? А если в этот момент взведется как раз флаг ЭТОГО прерывания? Так что для начала cli-sei таки уберите оттудова...jazz393 писал(а):да там что с ними что без них, просто ещё куча таймеров, это на всякий
Неправильно собранная из неисправных деталей схема нуждается в отладке и сразу не работает... (С)
Уточню. Только при выходе по RETI.Engineer_Keen писал(а):... автоматически же восстанавливаются при выходе из него.
- Сообщения: 118
- Зарегистрирован: Ср фев 05, 2014 18:54:39
убрал, результат тот же самый=(Engineer_Keen писал(а):Глобальные прерывания отключаются автоматически при переходе на обработчик прерывания, и автоматически же восстанавливаются при выходе из него. Сказать что будет, если разрешить прерывание внутри самого обработчика прерывания? А если в этот момент взведется как раз флаг ЭТОГО прерывания? Так что для начала cli-sei таки уберите оттудова...jazz393 писал(а):да там что с ними что без них, просто ещё куча таймеров, это на всякий
Думаю любителям ЯВУ этого знать не нужно не обязательноakl писал(а):Уточню. Только при выходе по RETI.
jazz393, очевидно что дело было не только в cli-sei, но sei явно мог породить еще большие глюки...
Конкретно в чем косяк не скажу, т.к. Си не воспринимаю на 100%, у меня все проще...
Спойлер
Код: Выделить всё
[...]
;отправка
LDIW XH,CMD ;ставим указатель (X) на строку
LD R16,X+ ;читаем первый символ
OUT UDR,R16 ;отправляем в UART
OUTI UCSRB,(1<<RXCIE)|(1<<TXCIE)|(1<<RXEN)|(1<<TXEN) ;включаем прерывание
STW CMD_PTR,XH
[...]
;прерывание по передаче
UART_TX:
PUSHS3 R16,XH,XL ;сохраняем регистры
LDW XH,CMD_PTR ;читаем указатель
LD R16,X+ ;читаем строку
OUT UDR,R16 ;отправляем в UART
STW CMD_PTR,XH ;сохраняем указатель
CJNE R16,0x03,TX_EX ;проверяем что не конец строки
OUTI UCSRB,(1<<RXCIE)|(0<<TXCIE)|(1<<RXEN)|(1<<TXEN) ;отключаем прерывание
TX_EX: POPS3 R16,XH,XL ;восстанавливаем регистры
RETI ;выходим из прерывания
Неправильно собранная из неисправных деталей схема нуждается в отладке и сразу не работает... (С)
- Сообщения: 118
- Зарегистрирован: Ср фев 05, 2014 18:54:39
оу кстати разобрался - cvavr генерировал обработчик для др прерывания)


