|
USART на АTmega48, не работает |
|
|
|
Dec 9 2008, 19:01
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(NikitoS-86 @ Dec 9 2008, 16:27)  - если оциллографом смотреть на ногах самой Атмеги, то приходит всегда то, что нужно, а в ответ уходит какая-то ересь... (в моём случае это 0x80) Мне кажется, поведение вашего кода можно объяснить следующим. После принятия очередного байта программа обработки прерывания приёмника начинает анализировать флаг готовности передатчика, но прерывание от передатчика срабатывает быстрее и успевает обнулить ваш буфер, так что вы всё время передаёте чистый нуль. А 0х80 возможно получается из-за того, что неправильно выбрана скорость приёмника писюка или вы неправильно измерили. Чтобы проверить мои предположения, вам нужно удалить обработчик прерывания от передатчика, всё равно он там ни к селу ни к городу и запустить программу. Ну или записывайте в буфер некое число, отличное от нуля, например, 0х41. Если не поможет, то проверьте передачу символов от МК на ПК. Передавайте в цикле известный символ, например, В Код while(1) { UDR0=0х42; delay(10000); }
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Dec 10 2008, 09:07
|
Участник

Группа: Новичок
Сообщений: 28
Регистрация: 22-09-08
Пользователь №: 40 380

|
Значится так... 1) Всем спасибо, поскольку полезной инфы для себя ещё подчерпнул... 2) Правы оказались товарищи Палыч и man with no name, сегодня первым делом прочитал, что было написано в ветке и за место 20 Мгц поставил 2,5 Мгц (как деление на 8) - всё заработало... Для меня если честно стало сюрпризом... Поясню почему - когда прошивал фьюзы - был абсолютно уверен, что если выбрать в закладке фьюзов в последней строке что-то типа внешнего тактового источника и нажать програм, то всё будет как надо... Как видно я ошибался... Разве это не так? К тому же теперь я не доберусь до фьюзов никак, поскольку у меня на руках mk2, то теперь он мне не даст без СТК500 добраться до фьюзов... Или я опять ошибаюсь?
3) Теперь по поводу моего кода... Да, прерывание по передаче, возможно и лишнее, как и цикл, но тогда у меня встаёт вопрос - а как обойтись без цикла (ну который у меня под вайлом идёт)? Просто когда мне надо переслать 1 байт - всё замечательно, он ушёл и бог с ним... А если целый пакет? Не получится ли так, что просто в цикле будет так, что следующий пакет будет наступать на пятки предыдущему? Или может тут как раз стоит подумать о прерывании по окончании передачи?
4) И ещё вопрос... Ситуация - надо отослать массив данных, например, short (2 байта)... Мне достаточно написать: UDDR0=Mass[i] и он сам поймёт, что надо просто тупо запихать сначала первый байт инта, потом второй? Или же надо самостоятельно ему поочереди запихнуть сначала первый байт, потом второй?
Спасибо.
Сообщение отредактировал NikitoS-86 - Dec 10 2008, 09:15
|
|
|
|
|
Dec 10 2008, 09:53
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(NikitoS-86 @ Dec 10 2008, 11:07)  когда прошивал фьюзы - был абсолютно уверен, что если выбрать в закладке фьюзов в последней строке что-то типа внешнего тактового источника и нажать програм, то всё будет как надо... Вот-вот... тоже попался на удочку визардов. Пользуюсь AVReal. Читаю описание всех фузов, пишу .bat с командной строкой, абсолютно уверен, что "оно само" ничего лишнего не сделает. Цитата(NikitoS-86 @ Dec 10 2008, 11:07)  Просто когда мне надо переслать 1 байт - всё замечательно, он ушёл и бог с ним... А если целый пакет? В данном случае целый пакет вы не получите, потому что уже сидите в прерывании приема. Если надо переслать несколько байт, то используют промежуточный буфер в озу и прерывание по освобождению UDR, а не по окончанию передачи. Примерно вот так (код для меги8, но идея понятна): CODE #define TX_BUFFER_SIZE 8 uint8_t volatile TxHead; uint8_t volatile TxTail; uint8_t TxPool[TX_BUFFER_SIZE];
void send_byte(unsigned char byte) { uint8_t Tmp = TxHead; while((uint8_t)(Tmp - TxTail) >= (uint8_t) TX_BUFFER_SIZE) ; // buffer full, wait
TxBuffer[ Tmp ] = Byte; Tmp = (Tmp + 1) & (TX_BUFFER_SIZE - 1); TxHead = Tmp; UCSRB |= (1<<UDRIE); }
void send_str(PGM_P string) { char c; while( (c = pgm_read_byte(string++)) != '\x0' ) { send_byte( c ); } } void send_str_P(char * string) { char c; while( (c = *string++) != '\x0' ) { send_byte( c ); } }
ISR(USART_UDRE_vect) { UCSRB &= ~(1<<UDRIE); sei(); { uint8_t Tmp = TxTail; UDR = TxBuffer[ Tmp ]; Tmp = (Tmp + 1) & (TX_BUFFER_SIZE - 1) TxTail = Tmp; if(Tmp != TxHead) // more data pending in buffer { UCSRB |= (1<<UDRIE); } } } или, в простейшем случае, без прерываний: Код void send_byte(uint8_t Byte) { while(!(UCSRA & (1<<UDRE))); UDR = Byte; } В любом случае ожидание должно происходить вне обработчика прерывания. Цитата(NikitoS-86 @ Dec 10 2008, 11:07)  Не получится ли так, что просто в цикле будет так, что следующий пакет будет наступать на пятки предыдущему? Или может тут как раз стоит подумать о прерывании по окончании передачи? В случае "эха" - не получится. И прерывание по освобождению UDR. Прерывание об окончании передачи используется для другого - например, для отключения передатчика в RS485. Цитата(NikitoS-86 @ Dec 10 2008, 11:07)  4) И ещё вопрос... Ситуация - надо отослать массив данных, например, short (2 байта)... Мне достаточно написать: UDDR0=Mass[i] и он сам поймёт, что надо просто тупо запихать сначала первый байт инта, потом второй? Или же надо самостоятельно ему поочереди запихнуть сначала первый байт, потом второй? Конечно самостоятельно. В вашей строке он запихнет только i-тый элемент массива. Можно написать универсальную функцию: Код void send_block(void const *ptr, uint8_t size) { while(size--) { send_byte(*ptr++); } }
void test() { unsigned char Mass[2]; unsigned short Short;
send_block(Mass, sizeof(Mass)); send_block(&Short, sizeof(Short)); }
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 10 2008, 13:11
|
Участник

Группа: Новичок
Сообщений: 28
Регистрация: 22-09-08
Пользователь №: 40 380

|
Цитата(Сергей Борщ @ Dec 10 2008, 12:53)  В данном случае целый пакет вы не получите, потому что уже сидите в прерывании приема. /.../или, в простейшем случае, без прерываний: Код void send_byte(uint8_t Byte) { while(!(UCSRA & (1<<UDRE))); UDR = Byte; } В любом случае ожидание должно происходить вне обработчика прерывания. Вот тут я несколько не понял, что мне мешает, сидя в прерывании, отсылать ему всё, что у меня так накопилось... Как раз таки вставив код "простейшего случая" у меня получилось отослать всё своё, правда конечно реализация выборки байтов элементов массива была ужасная... Я просто не понимаю в чем тут подводный камень? Цитата Конечно самостоятельно. В вашей строке он запихнет только i-тый элемент массива. Можно написать универсальную функцию: Код void send_block(void const *ptr, uint8_t size) { while(size--) { send_byte(*ptr++); } }
void test() { unsigned char Mass[2]; unsigned short Short;
send_block(Mass, sizeof(Mass)); send_block(&Short, sizeof(Short)); } А вот тут меня смущает только одно: цикл while мы проходим по уменьшению размера в байтах, что логично, однако send_byte при этом идёт по увеличению указателя... В случае массива разве не получится, что тут же перепрыгнем на второй элемент массива? Спасибо.
|
|
|
|
|
Dec 10 2008, 13:22
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(NikitoS-86 @ Dec 10 2008, 15:11)  Вот тут я несколько не понял, что мне мешает, сидя в прерывании, отсылать ему всё, что у меня так накопилось... Да потому что не накопится ничего. Неоткуда накопиться - вы уже сидите в прерывании приема. Значит все остальные прерывания запрещены. Цитата(NikitoS-86 @ Dec 10 2008, 15:11)  Как раз таки вставив код "простейшего случая" у меня получилось отослать всё своё, правда конечно реализация выборки байтов элементов массива была ужасная... Я просто не понимаю в чем тут подводный камень? В том, что этот код выполняется не из прерывания, а из основной программы. Все другие прерывания, в том числе и прерывание приема, в этом случае работают. Цитата(NikitoS-86 @ Dec 10 2008, 15:11)  А вот тут меня смущает только одно: цикл while мы проходим по уменьшению размера в байтах, что логично, однако send_byte при этом идёт по увеличению указателя... В случае массива разве не получится, что тут же перепрыгнем на второй элемент массива? Керниган и Ритчи. "Язык программирования С". Второе издание. Ссылку найдете через Гугля. Прочитать от начала до конца. Потом внимательно перечитать раздел 2.8 "Операторы инкремента и декремента". Обратите внимание, чем отличаются постфиксная и префиксная формы этих операторов. P.S. Да, там у меня ошибка, должно быть Код void send_block(void const *buffer, uint8_t size) { uint8_t *ptr = (uint8_t *)buffer; while(size--) { send_byte(*ptr++); } }
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|