По просьбам трудящихся, было решено продолжить урок по передаче данных через UART. Основной проблемой, на мой взгляд, при общении двух микроконтроллеров является прием данных.
В качестве примера возьмем две Atmega8. Задача первого микроконтроллера переслать массив символов, задача второго принять их и вывести на экран LCD дисплея. Схема будет выглядеть так:
Код передающего микроконтроллера будет выглядеть так:
#include <mega8.h> #include <stdio.h> void main(void) { char massiv[5]={'h','e','l','l','o'}; bit on=0; int i=0; PORTC=0x01; DDRC=0x00; UCSRA=0x00; UCSRB=0x08; UCSRC=0x86; UBRRH=0x00; UBRRL=0x33; while (1) { if(PINC.0==0 && on==0) { UDR=massiv[i]; i++; if(i>4) { i=0; } on=1; } if(PINC.0!=0) { on=0; } }; } |
При нажатии на кнопку передается 1 элемент массива символов, при повторном нажатии — следующий символ и т.д. В результате должен передаться массив «hello». Переменная on нужна для исключения дребезга кнопки (для передачи следующего символа нужно отпустить кнопку и затем нажать).
Второй микроконтроллер принимает данные в прерывании. Код прерывания, CodeWizard создает автоматически. Обработка достаточно большая, пугаться не стоит. Отдельно посмотреть данный код можно выставив галочки как показано на рисунке и щелкнуть File — Program Preview.
Разберемся с нашим алгоритмом, для нас самое главное это само прерывание:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | // USART Receiver interrupt service routine interrupt [USART_RXC] void usart_rx_isr(void) { char status,data; status=UCSRA; data=UDR; if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0) { rx_buffer[rx_wr_index]=data; if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0; if (++rx_counter == RX_BUFFER_SIZE) { rx_counter=0; rx_buffer_overflow=1; }; }; //здесь мы помещаем приходящие данные в массив, заранее известно количество //принимаемых символов = 5 uart_data[i]=data; i++; if(i>4) { i=0; } } |
Прием производится в прерывании, т.е. как только символ пришел срабатывает прерывание — символ записывается в первый элемент массива, инкрементируется счетчик. В следующее прерывание приходит следующий символ и т.д. Сразу оговорюсь, что количество приходящих символов заранее известно.
Теперь осталось только вывести результат на экран, для этого в цикле выводятся все символы на экран.
1 2 3 4 5 6 7 8 | while(j<5) // цикл пока все 5 символов не будут выведены на экран { lcd_gotoxy(j,0); //выбираем место куда будет выводиться символ sprintf(lcd_buffer,"%c",uart_data[j]); //преобразовываем символ в понятный для дисплея вид lcd_puts(lcd_buffer); //выводим на экран j++; //увеличить счетчик } j=0; // обнулить счетчик |
Схема и прошивка доступны тут
Доброе время суток! Возник такой вопрос: Как быть если с одного и того же микроконтроллера и передавать, и принимать данные? Как я понял и для передачи и для приема используется UDR. Если прием то Х=UDR(читаем оттуда), если передача UDR=Х(записываем туда). А как работать и с приемом, и с передачей в одном микроконтроллере? Если сможете, небольшой примерчик.
Заранее благодарен!!!
Omad, абсолютно также, в CAVR можно использовать функцию getchar(), т.е. прочитать символ или putchar() — отправить символ
А что если передавать числа типа float? И будет ли работать схема если связать обе меги через юарт и через тот же юарт передавать данные этих микроконтроллеров в ПК?
Юарт за раз передает байт, а что передавать совершенно не важно. Работать будет, только лучше поставить развязывающие диоды
Я связал две меги16 где оба выполняют одну и ту же операцию в результате которой они получают некоторое значение. Один из них только передавал данные другому. Тот который принимает данные принимал с ошибками (значения плавают). Не понятно как упорядочить приём данных от второго контроллера а затем передать их и данные первого в компьютер. Нет ли здесь конфликта при приёме данных и отправке. Ни это ли делают прерывания?
Ошибки могут быть, только если кварц не используете. Если все 3 устройства юзают одну шину Rx Tx, то их нужно развязывать диодами. Все остальное программная логика, посмотрите пример http://avr-start.ru/?p=2230
http://avr-start.ru/wp-content/uploads/2014/09/uart2mk_IR_RECIEVER.rar
на основе урока сделал приемик ИК порта. спасибо! и забирайте кому нужно))
Уважаемый Админ, не могли бы вы рассказать как передавать данные из МК в компьютер, сохраняя их в текстовый документ или в Exel (что было бы дельным). Нашёл на сторонних ресурсах передачу через USB, но со стороны компьютера там отдельный софт принимает данные и код закрыт. Думаю, должна быть возможность организовать всё без наворотов простенько и силами только МК. Возможно ли это?
Возможно. В первой части есть объяснение как принимать данные в прогу на C#, остается лишь сохранить это дело в файл CSV, с разделителями. Этот файл можно открывать экселем.
добрый день , подскажите пожалуйста. как вместо массива передать 3 переменные data1=255 , data2=124 и так далее. а на другой мк принимать эти значения и так же записать. в первой мк передача по совпадению таймера всех трёх переменных сразу, во второй прерывание по приёму
внутри прерывания передатчика
putchar(data1);
putchar(data2);
putchar(data3);
пример приема http://avr-start.ru/?p=2230
Здравствуйте. Что изменить в коде чтобы «1» один раз отправлялась, а не постоянно?
void main(void)
{
UCSRA=0x00;
UCSRB=0x08;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;
while (1)
{
if(PINA.2==1)
{
UDR=’1′;
}
}
}
постоянно не должно, может только изза дребезга несколько раз и еще при отсутствии подтяжки
Здравствуйте. А подскажите пожалуйста. Я передаю с ПК с С# текс на микроконтроллер он отображается на экране, Как осуществить перевод текста в переменную INT пробую
int shim = atoi (buf [1]); но ничего не выходит переменная INT равна нулю чтобы не пришло. код который получает строку…
c = uart_getc();
if (c == ‘#’)// || ( c == ‘\r’ ) )
{
//вывод принятой строки
uart_puts(buf);
stroka=0;
}
else
{
//проверка на переполнение буфера
if( buf_cnt < BUF_SIZE )
{
buf[buf_cnt] = c;
buf_cnt++;
int shim = atol (c);
Lcd_clear();
Lcd_printf(2,4,FONT_1X,shim,0); Lcd_printf(4,4,FONT_1X,buf_cnt,0);
Lcd_update();
}
помогите пожалуйста ) хочу сделать чтобы скажем если пришло с ПК "#T12$" записывалось в переменную просто как 12. естественно #T будет работать как идентификатор определённой переменной.
Если #T идентификатор, то просто следите за его приходом, а дальше получайте свое число. Перевод из ASCII в числовой, просто отнимайте 0x30. Например знак 4 в кодировке 0x34, отнимаем 0x30 и получаем 4. Проверять можно просто. Допустим строка из UART пришла в массив buf[]
if((buf[0] == ‘#’) & (buf[1] == ‘T’))
{
// Здесь разбираем строку
}
int shim = atoi (buf [1]); <- это ерунда. Функция atoi() возвращает число преобразованное из числовой строки начиная с адреса первой ячейки массива, а Вы туда просто байт пихаете. А в CVAVR разве есть такая функция?
Александр:
delay_ms(100);
while(!( UCSRA & (1 < < UDRE))); // Ждем опусташения UDR
UDR=’1′;
while(PIN.2);
Задержка избавит от дребезга, а цикл будет ждать отпускания кнопки. И самая распространенная ошибка: Не забывайте проверять флаг опустошения регистра UDR. В нем могут быть еще не переданные данные. МК работает на частоте до 16 МГц, а UART и 1МГц не выжмет. Представте как вы его запинаете.
И он, как я понимаю, может быть только в роли передатчика?
я тут, как пример стал использовать ATTINY2313 — передающее устройство, а вот ATMEGA8 — принимающее устройство +Virtual Terminal
вот код, для ATTINY2313
+++++++++++++++++++++++++
#include
#include
#include
void main(void)
{
char massiv[6]={‘1′,’2′,’3′,’4′,’5′,’6’};
int i=0;
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: Off
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0x08;
UCSRC=0x06;
UBRRH=0x00;
UBRRL=0x33;
while (1)
{
{
for (i=0;i<5;i++) {
UDR=massiv[i];
delay_ms(100);
}
}
};
}
+++++++++++++++++++++++++++++++
Virtual Terminal видает букву "И"
в чем может быть проблемма?
в частоте на которой работает тинька
NRF24L01 передает в обе стороны, в зависимости от того как настроите. Да это тот же модуль только с антенной, про полноценную замену не понял
Ок. Заработало.!!!
что имеем.
есть значение в переменой dath, оно меняется от 0 до 8
есть массив massiv[]
а вот вопрос:
как положить значения переменной dath в массив.
как пример:
massiv[0]=’1′; //- работает
massiv[0]=dath; //- не работает
помогите плиз
скорее всего потому что в dath ложите не ‘1’, а просто 1
вот как преаратить 1 в ‘1’
result = 1 + 0x30;
Спасибо!!!
Что делать если терманал показывает только ИИИИИИИИИИИИИИИИИИИИИИИИИИИИИИИ
не зависимости от переданного символа
скорости неправильно настроены, или частота кварца не соответствует проекту
Здравствуйте! Подскажите, пожалуйста, как передать по UART число больше 256? прошу прощения за нубский вопрос, понятно, что как то склеить два байта на приемной стороне, предварительно разбив их на передающей. Если вас не затруднит, не могли бы привести пример кода или дать ссылку?
http://avr-start.ru/?p=2230
Там, увы, только для приема. Я же пытаюсь связать два МК (атмега128), и как с передающей стороны задать начало и окончание передачи посылки — не могу сообразить. Не поможете с денубизацией?
делаете массив char
char data[3];
data[0] = ‘*’;
data[1] = x;
data[3] = ‘#’
for(char i = 0; i < 3; i++){putchar(data[i];}
Спасибо огромное! Всё, разобрался. Единственное, не понятно, почему при заданном unsigned long int максимальное число — 65535. Вроде должно быть на порядок больше…
посмотрите типы данных в codevision user manual
Уже посмотрел, и неоднократно. Почему то как бы я ни задавал переменную, больше 65535 записать в неё не получается. Полез в настройки компилятора — замена int, with на long, with также не дала результатов
а как проверяете?
Смотрю на дисплее, прикрученном к приемнику. Шлю приемнику два байта — А и Б, со стороны приемника их складываю, домножаю на 1000 и записываю в С. И вот это С почему-то не хочет быть больше 65535.
так 2 байта это и есть 65535
Да, два байта это 65535. Так дело не в этом. Первый байт — А -от 2 до 100. Второй — от 1 до 10. Эти два числа складываются и только после этого результат сложения домножеается на 1000 и записывается в С. А С задано как long int.
нужен код, так сложно сказать. может числа нужно приводить к long int