Урок 31
Часть 2
Связь ATtiny2313 и Atmega8 по SPI
В прошлой части занятия мы познакомились с реализацией SPI в контроллере ATtiny2313, тем самым подготовив данный МК к соединению посредством шины SPI и передачи данных контроллеру ATmega8.
Теперь начнём работать с контроллером ATmega8, чтобы он сумел данные, посланные ему, принять. Данные мы уже принимали, но с той разницей, что контроллер наш был ведомым, теперь он уже будет ведущим, что конечно внесёт определённые коррективы в написание исходного кода.
Откроем проект и добавим функцию инициализации выше функции main(), в имя которой мы ещё добавим определённый суффикс, чтобы было видно что мы подключаем устройство как ведомое (Slave)
//—————————————-
void SPI_init_SL(void)
{
}
//—————————————-
Сначала в теле данной функции мы инициализируем задействованные ножки портов
void SPI_init_SL(void)
{
DDRB |= (1<<PORTB4);//ножки SPI на выход
DDRB &= ~((1<<PORTB2)|(1<<PORTB3)|(1<<PORTB5));//ножки SPI на вход
Как мы видим, что теперь большинство ножек у нас настраивается на вход, что и логично, у нас же ведомый контроллер, поэтому на выход мы включаем только ножку MISO.
Теперь включим шину, настроив управляющий регистр
DDRB &= ~((1<<PORTB2)|(1<<PORTB3)|(1<<PORTB5));//ножки SPI на вход
SPCR = ((1<<SPE)|(1<<SPIE));//включим шину, включим прерывания
}
Мы видим, что у нас почти ничего не изменилось по сравнению с прошлыми проектами. Единственное отличие в том, что мы не включаем в единицу, бит устанавливающий устройство ведущим.
Теперь вопрос, где нам вообще ловить этот пришедший байт. Можно конечно где-то его долго ждать, но мы так поступать не будем, для того мы и включили прерывания.
По прерываниям от шины SPI мы используем вот такой вот вектор
Добавим обработчик прерывания над функцией main()
//—————————————-
ISR(SPI_STC_vect)//прерывание SPI прием байта
{
}
//—————————————-
Добавим переменную и занесём в неё байт из регистра
ISR(SPI_STC_vect)//прерывание SPI прием байта
{
unsigned char n;
n = SPDR;
То есть данное прерывание у нас произойдёт тогда, когда ATmega8 закончит полностью приём байта, а вернее не приём а обмен байтами, у нас же всё идёт по кругу.
И затем аналогично тому, как мы делали на ATTiny, мы данный принятый байт преобразуем в строку и отобразим на дисплее, не забывая его перед этим очистить
n = SPDR;
clearlcd();//очистим дисплей
setpos(0,0);
itoa(n,str,10);
str_lcd(str);
SPDR = n;
}
Объявление переменной str мы из функции main() перенесём вверх и сделаем её глобальной, немного добавив количество элементов
#include «main.h»
//—————————————-
char str[10];
Также функцию инициализации шины SPI мы должны вызвать в main(), а также включить глобальные прерывания
LCD_ini(); //»нициализируем дисплей
SPI_init_SL();//инициализируем SPI
sei();
Ну, в принципе можно проверить наш код на деле.
Соберём наш код и запустим его в протеусе
Всё у нас хорошо передаётся и принимается.
Прежде чем нам полюбоваться, как это всё происходит на практике, давайте посмотрим нашу конструкцию
Всё у нас соединено, единственное то, что шину питания и общий провод я пока не подсоединял от одного контроллера к другому. Для начала их нужно будет прошить. Делается это потому, чтобы код прошивки не залился один и тот же сразу в два контроллера, так как у нас соединение происходит по SPI, а прошивка у нас именно по такому интерфейсу и происходит.
Сначала прошьём контроллер ATmega8
И, если мы сейчас посмотрим, на дисплей, то он нам будет только отображать нашу инициализацию, так как код отображения принятых байтов у нас расположен в обработчике прерывания, а нам никто ничего не посылает и прерывания, соответственно, никакие не будет происходить.
Так как другой контроллер у нас уже прошит, то мы не будем в него подключать программатор, а просто подведём от отладочной платы с ATmega к нему плюс и общий провод
Воткнём программатор в разъём любого контроллера, чтобы у нас появилось питание для нашей схемы, и посмотрим результат нашей работы
Казалось бы, на этом можно и завершить, но мы ещё не пробовали принимать байты на ведущем контроллере, а также передавать с ведомого.
Давайте и этим заодно займёмся, благо контроллеры наши это делать позволяют. То есть обмен у нас пойдёт полнодуплесный и сдвиговые регистры наши будут работать на полную.
Сначала давайте, сделаем всё для контроллера ATtiny, раз уж у нас все равно программатор воткнут в его гнездо.
Первым делом по эстетическим соображением назовём и функцию передачи байтов по-другому, так как она будет работать в обе стороны, а также добавим ей возвращаемый тип
char SPI_ChangeByte(char byte)
И в конце тела данной функции вернём байт
return USIDR;
}
Добавим ещё одну переменную в main() для принимаемого байта
unsigned char n=0,m=0;//переменная для случайного числа
Также изменим имя и в вызове функции обмена в бесконечном цикле и добавим возврат значения
m = SPI_ChangeByte(n);
То есть здесь мы передадим n, а примем m.
Ну, и приблизительно таким же образом мы отобразим на дисплее ещё и принятый байт, а чтобы циферки между собой не соединились, мы спозиционируем перед этим курсор дисплея в другое место
str_lcd(str);
itoa(m,str,10);
setpos(0,1);
str_lcd(str);
Теперь перейдём к проекту с контроллером ATmega8 и подумаем, как же нам оттуда отправить байт.
Оказывается это сделать ещё проще. В обработчике прерывания в момент, когда принялся байт, то у нас регистр SPDR очищается. Поэтому давайте мы в него обратно запишем значение нашей переменной n
str_lcd(str);
SPDR = n;
}
И записанный в SPDR байт в следующем цикле обмена байтами в регистре уйдёт обратно в контроллер ATtiny2313.
Соберём сначала наши оба проекта.
Посмотрим результат в протеусе
Мы видим, что всё у нас отлично передаётся, также на другой ножке на осциллограмме появилась передача байтов.
Теперь нам нужно проверить всё на практической схеме.
Опять разъединим межконтроллерное питание и прошьём сначала контроллер ATtiny2313, затем, не соединяя питание, переключим разъём программатора в отладочную плату с контроллером ATmega8 и прошьём его. Затем отключим общее питание, соединим провод питания и общий провод между обеими схемами, подадим общее питание и посмотрим результат
У нас всё отлично работает и передаётся. Всё идёт по циклу. Теперь я думаю мы очень неплохо проработали знания по программированию шины SPI, причём на нескольких контроллерах.
Но не успокаивайтесь! Мы обязательно к этой шине ещё вернёмся, так как устройств работающих по данной шине, очень немало.
Предыдущая часть Программирование МК AVR Следующий урок
Программатор и дисплеи можно приобрести здесь:
Программатор USBASP USBISP с адаптером USBASP USBISP 3.3 с адаптером
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
Добавить комментарий