Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Соединить 2 atmega168 по USART
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Filov
Здравствуйте!

Пытаюсь обеспечить передачу данными по USART между двумя мегами 168. Обе тактются от одного внешнего источника частотой 12.5МHz. BAUD=500 на обоих мегах.

Использую polled версия работы s USART из App.Note от производителя.

Соединяю так:
Код
Rx    --  Tx
Tx    --  Rx
XCK  --  XCK



Передаю число первой мегой - вторая Atmega должна принять и соответсвующее количество раз мигнуть светодиодом.

Передаю 1 - мигает 2 раза
Передаю 2 - мигант 12 раз
Передаю 3 - мигает 14 раз sad.gif

После того как 2 мега мигнула светодиодами она должна вернуть первой константу.
Но такое ощущение что в буфере приема первой меги находится больше чем одно число. Т.к. она принимает контсанту еще до того как вторая закончила мигать светодиодами. Причем число не совпадает с той константой, что должна передать 2 мега.

Подскажите, пожалуйста, что делать, чтобы заработало?
GDI
А зачем сигнал XCK - вы в синхронном режиме чтоли работаете? И вообще, код бы не помешало привести.
blackbit
оп-с.. а земли (GND) вы им действительно не соединили или только на рисунке не удосужились?
Filov
Цитата(GDI @ Mar 3 2008, 13:17) *
А зачем сигнал XCK - вы в синхронном режиме чтоли работаете?


Я так понял после прочтения документации, что по XCK происходит тактование. А разве допустим для асинхронной передачи достаточно соледенить допустим Rx одного с Tx другого? А для синхронной соответсвенно Rx1----Tx2 и Tx1----Rx2?


Цитата(GDI @ Mar 3 2008, 13:17) *
И вообще, код бы не помешало привести.


Код взят из appnote 306. Действителен для обоих МК:

Код
/* Initialize UART */
void USART0_Init( unsigned int baudrate )
{
        /* Set the baud rate */
        UBRR0H = (unsigned char) (baudrate>>8);
        UBRR0L = (unsigned char) baudrate;

        /* Enable UART receiver and transmitter */
        UCSR0B = ( ( 1 << RXEN0 ) | ( 1 << TXEN0 ) );

        /* Set frame format: 8 data 2stop */
        UCSR0C = (1<<USBS0)|(1<<UCSZ01)|(1<<UCSZ00);              //For devices with Extended IO
        //UCSR0C = (1<<URSEL)|(1<<USBS0)|(1<<UCSZ01)|(1<<UCSZ00);   //For devices without Extended IO
}

/* Read and write functions */
unsigned char USART0_Receive( void )
{
        /* Wait for incomming data */
        while ( !(UCSR0A & (1<<RXC0)) )
              ;
        /* Return the data */
        return UDR0;
}

void USART0_Transmit( unsigned char data )
{
        /* Wait for empty transmit buffer */
        while ( !(UCSR0A & (1<<UDRE0)) )
              ;
        /* Start transmittion */
        UDR0 = data;
}

В main:

USART0_Init( 500 );

передаю число так :

USART0_Transmit(0xAA);

принимаю так:

char data=USART0_Receive();



Вечером приведу полный листинг.

Цитата(blackbit @ Mar 3 2008, 13:32) *
оп-с.. а земли (GND) вы им действительно не соединили или только на рисунке не удосужились?



Земли и питание у обоих МК общие.
GDI
Цитата
Я так понял после прочтения документации, что по XCK происходит тактование. А разве допустим для асинхронной передачи достаточно соледенить допустим Rx одного с Tx другого? А для синхронной соответсвенно Rx1----Tx2 и Tx1----Rx2?

Тактирование нужно только в синхронном режиме, в асинхронном же нужно всего лишь соединить Rx1----Tx2 и Tx1----Rx2, ну и землю, естественно.
Aesthete Animus
2Filov
Скажите, а чем вызвано желание использовать именно USART, к тому же, в синхронном режиме?
Filov
Цитата(GDI @ Mar 3 2008, 15:40) *
Тактирование нужно только в синхронном режиме, в асинхронном же нужно всего лишь соединить Rx1----Tx2 и Tx1----Rx2, ну и землю, естественно.


Спасибо, попробую вечером добиться верной пересылки в асинхронном режиме. Только инициалюзацию USART я так понимаю надо поменять немного.

Цитата(Aesthete Animus @ Mar 3 2008, 16:03) *
2Filov
Скажите, а чем вызвано желание использовать именно USART, к тому же, в синхронном режиме?


Я как начинающий понял, что это самый стандартный и безболезненный способ передавать данные от одного МК к другому. Или я ошибаюсь? И USART в асинхронном режиме реализовать проще?
Stanislav_S
Цитата(Filov @ Mar 3 2008, 18:17) *
Я как начинающий понял, что это самый стандартный и безболезненный способ передавать данные от одного МК к другому. Или я ошибаюсь? И USART в асинхронном режиме реализовать проще?

Скажем так, если меги стоят на одной плате, то еще их можно соединить через SPI. Мне лично так было проще. Кстати для приема лучше использовать прерывание.
Filov
Цитата(Stanislav_S @ Mar 3 2008, 16:29) *
Скажем так, если меги стоят на одной плате, то еще их можно соединить через SPI. Мне лично так было проще. Кстати для приема лучше использовать прерывание.


Да надо бы попытаться добить USART, не дело начатое бросать. Вроде бы такая вещь простая... А просидел уже не один вечер.

Спасибо. Попробую использовать прерывание по приему. Плюс попробую асинхронный режим - может чего получится.
GDI
Цитата
Только инициалюзацию USART я так понимаю надо поменять немного.

Да, вроде не надо, хотя я с мега168 не работал, потому не могу точно сказать.
А примеры кода для УСАРТа можете поискать в примерах программ - это первая тема в этом форуме http://electronix.ru/forum/index.php?showtopic=10934
УСАРТ, мне кажется, для межпроцессорного обмена стоит применять когда надо чтобы любой из контроллеров мог инициировать передачу, а если этого не надо, то SPI будет проще и быстрее по скорости обмена.
=GM=
Цитата(Filov @ Mar 3 2008, 14:10) *
Да надо бы попытаться добить USART, не дело начатое бросать. Вроде бы такая вещь простая... А просидел уже не один вечер

1) Конечо, не дело. Разобраться стоит в любом случае. Но если вы хотите принимать данные от одного МК и затем принимать ответ от второго, то лучше использовать асинхронный режим, потому что в синхронном режиме возможна только полудуплексная работа, т.е. один МК передаёт данные, второй принимает, или наоборот, но неодновременно. Затем надо перенастраивать режим первого МК с синхронного мастера на синхронный слейв и наоборот для второго. Для переключения XCK используется бит DDR_XCK0. Ну и соответственно, нужно как-то синхронизировать процессы, чтобы не было ситуации, когда выходы XCK обоих МК начнут палить друг друга.

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

3) Не моё это дело, но вам, как начинающему, всё-таки скажу, что в сишных фрагментах ввода-вывода лучше ставить точку с запятой после оператора while не так как у вас или в авр306
Код
unsigned char USART0_Receive(void)
{
while(!(UCSR0A&(1<<RXC0)))  /* Wait for incomming data */
            ;
return UDR0;                /* Return the data */
}

а так
Код
unsigned char USART0_Receive(void)
{
while(!(UCSR0A&(1<<RXC0))); /* Wait for incomming data */
return UDR0;                /* Return the data */
}

Будет более читабельно и меньше вероятность совершить ошибку.
mdmitry
Цитата(=GM= @ Mar 3 2008, 18:04) *
3) Не моё это дело, но вам, как начинающему, всё-таки скажу, что в сишных фрагментах ввода-вывода лучше ставить точку с запятой после оператора while не так как у вас или в авр306
Будет более читабельно и меньше вероятность совершить ошибку.


Это вопрос нотации записи, кто к чему привык.
По теме: можно взять библиотеку AvrLib. в ней есть примеры работы с USART. Я пользовался идеями, заложенными в код. ИМХО, библиотека универсальная, значит, избыточно-функциональная и объемная по затратам.
KRS
Цитата(=GM= @ Mar 3 2008, 18:04) *
потому что в синхронном режиме возможна только полудуплексная работа, т.е. один МК передаёт данные, второй принимает, или наоборот, но неодновременно. Затем надо перенастраивать режим первого МК с синхронного мастера на синхронный слейв и наоборот для второго.

Это почему?
IMHO можно использовать дуплекс, просто один мастер, другой слейв или вообще оба слейва ( клоки от другого источника)

Другой вопрос, что при двух контроллерах на одной плате еще и с одним источником частоты - внешний клок для UART лишнее.
=GM=
Цитата(KRS @ Mar 3 2008, 15:26) *
Это почему?

Так атмелы захотели(:-).
Цитата(KRS @ Mar 3 2008, 15:26) *
IMHO можно использовать дуплекс, просто один мастер, другой слейв или вообще оба слейва ( клоки от другого источника)

1) У мастера ХСК является выходом, а у слейва входом. Как мастер примет данные от слейва, если ХСК уже занят на выдачу? Точно также для слейва, как слейв передаст данные, если ХСК уже занят на приём?

2) В усарте имеется только 4 режима для тактовой частоты, цитата из документа doc2545m, c.193
"The USART supports four modes of clock operation: Normal asynchronous, Double Speed asynchronous,
Master synchronous and Slave synchronous mode" Ну и какой из них дуплекс?

3) Оба слейва не помогут, кто тогда передавать будет? Да и проблема целая, как засинхронизировать смену битов данных с внешней тактовой частотой? Объясните, пожалуйста.
KRS
Цитата(=GM= @ Mar 3 2008, 19:27) *
1) У мастера ХСК является выходом, а у слейва входом. Как мастер примет данные от слейва, если ХСК уже занят на выдачу? Точно также для слейва, как слейв передаст данные, если ХСК уже занят на приём?

Клоки нужны только для синхронизации. Вместо виртуальных внтуренних стробов данные захватываются по фронту клока. Мало того клоки должны идти постоянно и приемник ловит стартовый бит, потом n бит данных и стоповый бит (только ловит по фронту клока). Ничем от обычного асинхронного не отличатеся (кроме точки sampling)!

Цитата(=GM= @ Mar 3 2008, 19:27) *
2) В усарте имеется только 4 режима для тактовой частоты, цитата из документа doc2545m, c.193
"The USART supports four modes of clock operation: Normal asynchronous, Double Speed asynchronous,
Master synchronous and Slave synchronous mode" Ну и какой из них дуплекс?

Все дуплекс!


Цитата(=GM= @ Mar 3 2008, 19:27) *
3) Оба слейва не помогут, кто тогда передавать будет? Да и проблема целая, как засинхронизировать смену битов данных с внешней тактовой частотой? Объясните, пожалуйста.

Могут! они оба не являются источником клока! Передает какждый по своей линии TX, которая крест на крест связана с RX. Тут нужен только источник клоков внешний.
GDI
Имхо, в синхронном режиме USART очень похож на SPI(не даром есть режим работы USARTа в режиме SPI), отличия незначительные, SPI просто байты передает по клоку в ОБЕ СТОРОНЫ, а УСАРТ еще и стартовые и стоповые биты но тоже в ОБЕ СТОРОНЫ, а уважаемый =GM= путает понятия мастер-слейв и дуплекс-полудуплекс.
Filov
Вообщем действительно USART работал у меня в асинхронном режиме (по умолчанию). Убрал проводок от XCK1 к XCK2 - ничего не изменилось.

Т.е. сейчас соединены:

Rx1-Tx2
Tx2-Rx1

земли и питание общие.

Так же изменил baudrate, чтобы скорость была близка к 4800. Точность 12500000/(16*(162+1.0))/4800*100=99.853%

Вот код для основного МК:

Код
#define F_CPU 12500000UL  // 12.5 MHz

/* Initialize UART */
void USART0_Init( unsigned int baudrate )
{
        /* Set the baud rate */
        UBRR0H = (unsigned char) (baudrate>>8);
        UBRR0L = (unsigned char) baudrate;

        /* Enable UART receiver and transmitter */
        UCSR0B = ( ( 1 << RXEN0 ) | ( 1 << TXEN0 ) );

        /* Set frame format: 8 data 2stop */
        UCSR0C = (1<<USBS0)|(1<<UCSZ01)|(1<<UCSZ00);              //For devices with Extended IO
}


/* Read and write functions */
unsigned char USART0_Receive( void )
{
        /* Wait for incomming data */
        while ( !(UCSR0A & (1<<RXC0)) );
        /* Return the data */
        return UDR0;
}

void USART0_Transmit( unsigned char data )
{
        /* Wait for empty transmit buffer */
        while ( !(UCSR0A & (1<<UDRE0)) );
        /* Start transmittion */
        UDR0 = data;
}


void init_all(void){

        /***initialize clock***/  // Set the clock speed to 8MHz
        // set the clock prescaler. First write CLKPCE to enable setting of clock the next four instructions.
        CLKPR=(1<<CLKPCE);
        CLKPR=0;                                // 8 MHz
        delay_ms(20);

       // change clkout from 6.25MHz to 12.5MHz. Тактуется все от 25MHz. Получается 25/2=12.5Mhz
        delay_ms(10);
        USART0_Init(162);  /* 12500000/(16*(162+1.0))/4800*100=99.853 Set the baudrate to 4800 using a 12,5MHz int osc */

        /***enable interrupt***/
        sei();
}

int main(void){
        init_all();

        USART0_Transmit(3); // передать 2 МК число 3
        uint8_t XXX[3];
        XXX[0]= USART0_Receive;

        //записать XXX[0]  в память

        return (0);
}                               //end main



А вот код для 2 МК (почти то же самое) Вчера ограничил задачу - принять число - и столько раз мигнуть светодиодом
Код
#define F_CPU 12500000UL  // 12.5 MHz

/* Prototypes */
void USART0_Init( unsigned int baudrate );
unsigned char USART0_Receive( void );
void USART0_Transmit( unsigned char data );

/* Initialize UART */
void USART0_Init( unsigned int baudrate )
{
        /* Set the baud rate */
        UBRR0H = (unsigned char) (baudrate>>8);
        UBRR0L = (unsigned char) baudrate;

        /* Enable UART receiver and transmitter */
        UCSR0B = ( ( 1 << RXEN0 ) | ( 1 << TXEN0 ) );

        /* Set frame format: 8 data 2stop */
        UCSR0C = (1<<USBS0)|(1<<UCSZ01)|(1<<UCSZ00);              //For devices with Extended IO
}

void USART0_Transmit( unsigned char data )
{

        /* Wait for empty transmit buffer */
        while ( !(UCSR0A & (1<<UDRE0)) );

        /* Start transmittion */
        UDR0 = data;
}

/* Read and write functions */
unsigned char USART0_Receive( void )
{

        /* Wait for incomming data */
        while ( !(UCSR0A & (1<<RXC0)) );

        /* Return the data */
        return UDR0;
}

void init_all(void){

        /***initialize clock***/                //Set the clock speed to 8MHz
        // set the clock prescaler. First write CLKPCE to enable setting of clock the next four instructions.
        CLKPR=(1<<CLKPCE);
        CLKPR=0;                                // 8 MHz
        delay_ms(3000);                         //change clkout from 6.25MHz to 12.5MHz
        USART0_Init(162);                       /* 12500000/(16*(162+1.0))/4800*100=99.853 error Set the baudrate to 4800 using a 12,5MH*/

        /***enable interrupt***/
        sei();
}


void led_on( unsigned int cikle){

        uint8_t i=0;
        while(i<cikle){
                /* led on, pin=0 */
                PORTC &= ~(1<<PC5);
                delay_ms(500);
                /* set output to 5V, LED off */
                PORTC|= (1<<PC5);
                delay_ms(500);
                i++;
        }
}

/* Main - a simple test program*/
void main( void )
{
        init_all();

        /* INITIALIZE */
        /* enable PC5 as output */
        DDRC|= (1<<DDC5);

        led_on(3);                                   //Тут все верно при старте мигает 3 раза
        delay_ms(1000);                        

        for(;;){                                        /* Forever */

                unsigned charinput=USART0_Receive();
                led_on(charinput);
        }
}


Мигает по прежнему 14 раз каждый раз. А должно 3. Но хоть стабильность в этом вопросе. Подскажите, почему доходит не то что нужно?
GDI
Ну, во первых, посмотрите осциллографом, что у вас и как передается, на какой реально скорости и т.п.
Я бы сделал постоянную передачу символа в цикле, а на приеме просто бы зажигал светодиод если число совпало с ожидаемым, тогда и осцилом можно проверить, да и меняя константу можно выяснить, это действительно 14 принимается или это просто какое то левое начальное значение переменной.

Ну и замечания по коду, не всегда существенные, но все же.. smile.gif
unsigned charinput - это какой тип данных будет? по-умолчанию? int? а передаете из функции вы что - char. Обьявление переменных внутри цикла - это плохой тон для контроллеров, лучше везде использовать тип char если это подходит, т.к. контроллер 8и разрядный и для него именно char является нативным типом, а не int как обычно принято у 16/32 разрядных процов, а судя по коду именно с ними вы раньше имели дело. Функция main возвращает void обычно, потому что в МК некуда выходить если у вас просто программа а не ОСь стоит.
KRS
Цитата(GDI @ Mar 4 2008, 10:22) *
Имхо, в синхронном режиме USART очень похож на SPI(не даром есть режим работы USARTа в режиме SPI)

Кстати не во всех чипах есть режим SPI, (напримре в Atmega128 нет sad.gif ). Есть еще существенное отличие от SPI в SPI сами посылки (фреймы) туда и обратно синхронны и жестко привязаны к количеству клоков, поэтому нет стартовых и стоповых бит, а в UART передача асинхронна (клоки просто sapmling point задают) поэтому клоки идут постоянно и нужны и старт бит и стоп.
Filov
Цитата(GDI @ Mar 4 2008, 12:49) *
Ну, во первых, посмотрите осциллографом, что у вас и как передается, на какой реально скорости и т.п.,


Нашел вот какой-то старый. попробую использовать...

Цитата(GDI @ Mar 4 2008, 12:49) *
unsigned charinput - это какой тип данных будет? по-умолчанию? int? а передаете из функции вы что - char.


Тьфу опростоволосился похоже. sad.gif

Цитата(GDI @ Mar 4 2008, 12:49) *
Обьявление переменных внутри цикла - это плохой тон для контроллеров, лучше везде использовать тип char если это подходит, т.к. контроллер 8и разрядный и для него именно char является нативным типом, а не int как обычно принято у 16/32 разрядных процов, а судя по коду именно с ними вы раньше имели дело.


Да, некрасиво, понимаю. Но обычно когда начинает хоть как-то работать переношу объявление переменных в нужное место. А так - замучаешься - ведь не все сразу получается...

Цитата(GDI @ Mar 4 2008, 12:49) *
Функция main возвращает void обычно, потому что в МК некуда выходить если у вас просто программа а не ОСь стоит.


Ясно.
GDI
Цитата
Кстати не во всех чипах есть режим SPI, (напримре в Atmega128 нет sad.gif ).

Это я знаю, сам с новыми еще не работал smile.gif, но у автора мега168, а там это режим есть.

..как быстро отвечает автор, не успел сообщение запостить а он уже отвечает... я, кстати пост тот поправил, перечитайте..
Filov
Цитата(GDI @ Mar 4 2008, 12:57) *
Это я знаю, сам с новыми еще не работал smile.gif, но у автора мега168, а там это режим есть.


Кстати этот режим тоже любопытнаю штука smile.gif Буду его тоже пробовать позже smile.gif

Цитата(GDI @ Mar 4 2008, 12:57) *
..как быстро отвечает автор, не успел сообщение запостить а он уже отвечает... я, кстати пост тот поправил, перечитайте..


Ну так что лучше работать или на форуме сидеть???? smile.gif

Константу менял - передавал
1 - мигало 2 раза
2 - мигало 12 раз
3 - мигало 14 раз.

Действительно попробую в цикле. И unsigned charinput заменю на unsigned char charinput Ж). Может чего и выйдет.
defunct
Цитата(Filov @ Mar 4 2008, 12:04) *
Константу менял - передавал
1 - мигало 2 раза
2 - мигало 12 раз
3 - мигало 14 раз.

А теперь давайте посмотрим что такое 2, 12 и 14.

2 - 0x02 == 00000010 вместо 000000001
12 - 0x0C == 00001100 вместо 000000010
14 - 0x0E == 00001110 вместо 000000011

У вас установлены разные бодрейты.
Отличие в скорости на глаз в 1.5..2 раза.

Совет - напишите и залейте одну и ту же программу в оба МК. Если так и будет сбоить - значит настройки осциллятора разные. Прошейте одинаково fuses.

Еще - совсем не важно вычислять бодрейт когда МК работают от одного источника тактирования, нужно чтобы число записываемое в UBRR было одинаковым для обоих МК, а скорость можно ставить максимально допустимую.
mdmitry
Цитата(Filov @ Mar 4 2008, 13:04) *
Кстати этот режим тоже любопытнаю штука smile.gif Буду его тоже пробовать позже smile.gif

Atmega1281,2561 UART в режиме MASTER SPI, а не Slave. Будьте внимательны
Filov
Цитата(defunct @ Mar 4 2008, 13:47) *
А теперь давайте посмотрим что такое 2, 12 и 14.

2 - 0x02 == 00000010 вместо 000000001
12 - 0x0C == 00001100 вместо 000000010
14 - 0x0E == 00001110 вместо 000000011

У вас установлены разные бодрейты.
Отличие в скорости на глаз в 1.5..2 раза.

Совет - напишите и залейте одну и ту же программу в оба МК. Если так и будет сбоить - значит настройки осциллятора разные. Прошейте одинаково fuses.


Спасибо большое! У Вас глаз-алмаз! Вытащил проводочек ко которому идут клоки с первого МК - не работет - все ОК. Из второго - продолжает мигать! Соостветсвенно не были правильно установлены fuses и вместо внешних 12.5MHz чип работал на 8MHz. Отличие в скорости в 1.5 раза.

Вообщем извлек еще раз урок - что не стоит быть излишне самоуверенным, а проверять, проверять и еще раз проверять. Но зато хоть разобрался как USART работает.


Цитата(defunct @ Mar 4 2008, 13:47) *
Еще - совсем не важно вычислять бодрейт когда МК работают от одного источника тактирования, нужно чтобы число записываемое в UBRR было одинаковым для обоих МК, а скорость можно ставить максимально допустимую.


Т.е. можно ставить регистры UBRR0(H,L) в 1 ?


Цитата(mdmitry @ Mar 4 2008, 13:48) *
Atmega1281,2561 UART в режиме MASTER SPI, а не Slave. Будьте внимательны


Это я вроде понял, только мне непонятна одна вешь - на что влияет бодрейт когда я использую USART как SPI? Допустим хочу соедениться по SPI с чипом который имеет частоту тактования X. Какой бодрейт мне стоит указать?


-------------

Господа, спасибо за Ваши ответы. Они прям открыли мне глаза на USART!
mdmitry
Цитата(Filov @ Mar 5 2008, 12:39) *
Это я вроде понял, только мне непонятна одна вешь - на что влияет бодрейт когда я использую USART как SPI? Допустим хочу соедениться по SPI с чипом который имеет частоту тактования X. Какой бодрейт мне стоит указать?

Вы ставите желаемую скорость с помощью UBRR. Он MASTER и, соответственно, тактирует ведомого. Сделать USART ведомым в режиме SPI невозможно. Читайте внимательно описание контроллера.
Проблем с работой нет. Тонкость только в правильном задании режима (всего 4), чтобы ведомый понимал.
defunct
Цитата(Filov @ Mar 5 2008, 11:39) *
Т.е. можно ставить регистры UBRR0(H,L) в 1 ?

Да, плюс установить бит удвоенной скорости (U2X в UCSRA).
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.