Официальный сайт компании Arduino по адресу arduino.cc
Arduino UNO + ATmega16, SPI и I2C
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Доброго времени суток, господа форумчане. Приношу свои извинения за много букв, чтобы описать проблему - писать надо много, но постараюсь максимально сжато.
Имеются уличные часы с 4-х разрядным светодиодными индикатором, на подобии тех, что частенько можно увидеть на школах, проходных заводов и т.п. Каждый разряд состоит из 24 сегментов и управляется микросхемой ATmega16. Эти 4 атмеги в свою очередь получали команды о выводе цифр от ещё одной ATmega16. Т.е. итого было пять атмег: одна основная и 4 дочерние.
Во время грозы сгорела основная атмега и часы были отданы товарищу-электронщику "на запчасти". Но он решил попытаться их восстановить. Рассмотрев различные варианты, остановились на том, что сгоревшую атмегу заменяем на ардуину, а в атмеги, управляющие разрядами - заливаем новую прошивку.
Изначально я даже не имел представления как прошивать ATmega16 через ардуино. Но с помощью этого видео: https://www.youtube.com/watch?v=P3CYDXBiIzM всё получилось.
Написал программу для атмег-разрядов, чтобы они перебирали цифры, написал программу для "головной ардуины", чтобы она считала время и разбивала его на 4 разряда. Оставалось дело за малым - отправлять эти цифры по SPI на дочерние платки. И вот тут меня ждало фиаско.
Кое-как, вписал я кусок кода для отправки/принятия данных по SPI . Писал не понимая чего я пишу, но с ардуины на ардуину оно заработало, а с ардуины на атмегу16 - нет. Хотел посмотреть что там принимает атмега16, подключил к ней LCD дисплейчик 1602 - на ардуине он работает, а на атмеге снова нет.
Собственно закрались подозрения, что используемые библиотеки #include <Wire.h> и #include <LiquidCrystal_I2C.h> - ссылаются где-то глубоко внутри себя на пины ардуины. Так ли это и если так, то как их переназначить, чтобы они соответствовали пинам атмеги16?
----------------------------------------------------
Прилагаю код, который зашивается в "основную" ардуину:
#define SS_m 10 // Пин отправки младшего разряда минут #define SS_M 9 // Пин отправки старшего разряда минут #define SS_h 8 // Пин отправки младшего разряда часов #define SS_H 7 // Пин отправки старшего разряда часов #define tperiod 1 // Периодичность считывания и отправки времени (сек) #include <SPI.h> // Подключаем протокол обмена данными #include <Wire.h> // Подключаем библиотеку Wire #include <TimeLib.h> // Подключаем библиотеку TimeLib #include <DS1307RTC.h> // Подключаем библиотеку DS1307RTC char HOUR,MIN,SEC,H,h,M,m,S,s; // Переменные для получения времени и разбития по разрядам tmElements_t tm; // Создаем объект tm для чтения времени // ---------- УСТАНОВКА ПАРАМЕТРОВ SPI-MASTER ---------- \\ void SPI_Setup() { SPI.setDataMode(SPI_MODE0); SPI.setBitOrder(MSBFIRST); SPI.setClockDivider(SPI_CLOCK_DIV4); SPI.begin(); pinMode(SS_m,OUTPUT); pinMode(SS_M,OUTPUT); pinMode(SS_h,OUTPUT); pinMode(SS_H,OUTPUT); digitalWrite(SS_m,HIGH); digitalWrite(SS_M,HIGH); digitalWrite(SS_h,HIGH); digitalWrite(SS_H,HIGH); } void setup() { SPI_Setup(); Serial.begin(9600); delay(200); } void loop() { // tmElements_t tm; // Создаем объект tm для чтения времени if (millis() % (tperiod * 1000) == 0) { RTC.read(tm); // Считываем время в объект tm HOUR = tm.Hour; // Записываем в переменную HOUR часы MIN = tm.Minute; // Записываем в переменную MIN минуты SEC = tm.Second; H = HOUR / 10; // Выделяем старший разряд из часов h = HOUR % 10; // Выделяем младший разряд из часов M = MIN / 10; // Выделяем старший разряд из минут m = MIN % 10; // Выделяем младшиый разряд из минут S = SEC / 10; s = SEC % 10; Serial.print(H,DEC); Serial.print(h,DEC); Serial.print(" : "); Serial.print(M,DEC); Serial.print(m,DEC); Serial.print(" : "); Serial.print(S,DEC); Serial.println(s,DEC); digitalWrite(SS_H,LOW); // Начинаем передачу в сегмент старшего разряда часов SPI.transfer(H); // Отправляем старший разряд часов digitalWrite(SS_H,HIGH); // Завершаем передачу в сегмент старшего разряда часов digitalWrite(SS_h,LOW); // Начинаем передачу в сегмент младшего разряда часов SPI.transfer(h); // Отправляем младший разряд часов digitalWrite(SS_h,HIGH); // Завершаем передачу в сегмент младшего разряда часов digitalWrite(SS_M,LOW); // Начинаем передачу в сегмент старшего разряда минут SPI.transfer(M); // Отправляем старший разряд минут digitalWrite(SS_M,HIGH); // Завершаем передачу в сегмент старшего разряда минут digitalWrite(SS_m,LOW); // Начинаем передачу в сегмент младшего разряда минут SPI.transfer(m); // Отправляем младший разряд минут digitalWrite(SS_m,HIGH); // Завершаем передачу в сегмент младшего разряда минут } //delay(500); }
----------------------------------------------------
...и код, который разливается по "дочерним" атмегам:
#define SS_PIN 11 // Пин получения данных (цифра для вывода) #define D0 0 #define D1 1 #define D2 2 #define D3 3 #define D4 4 #define D5 5 #define D6 6 #define D7 7 #define D16 16 #define D17 17 #define D18 18 #define D19 19 #define D20 20 #define D21 21 #define D22 22 #define D23 23 #include <SPI.h> char LNUM , NUM; // Переменные прошлая цифра , текущая цифра void SPI_Setup() // Установка параметров обмена { SPI.setDataMode(SPI_MODE0); SPI.setBitOrder(MSBFIRST); SPI.setClockDivider(SPI_CLOCK_DIV4); pinMode(MISO, OUTPUT); SPCR |= _BV(SPE); } byte SPI_read() // Процедура получения данных от Master { if (digitalRead(SS_PIN) == LOW) while(!(SPSR & (1<<SPIF))); return SPDR; } void DRAWS(char num) // Процедура вывода цифр в статическом режиме { digitalWrite(A0,LOW); digitalWrite(A1,LOW); digitalWrite(A2,LOW); // Выключаем индикатор digitalWrite(A3,LOW); digitalWrite(A4,LOW); digitalWrite(A5,LOW); // Выключаем индикатор digitalWrite(A6,LOW); digitalWrite(A7,LOW); digitalWrite(D0,LOW); // Выключаем индикатор digitalWrite(D2,LOW); digitalWrite(D3,LOW); digitalWrite(D4,LOW); // Выключаем индикатор digitalWrite(D5,LOW); digitalWrite(D6,LOW); digitalWrite(D7,LOW); // Выключаем индикатор digitalWrite(D16,LOW); digitalWrite(D17,LOW); digitalWrite(D18,LOW); // Выключаем индикатор digitalWrite(D19,LOW); digitalWrite(D20,LOW); digitalWrite(D21,LOW); // Выключаем индикатор digitalWrite(D22,LOW); digitalWrite(D23,LOW); digitalWrite(D1,LOW); // Выключаем индикатор switch (num) { // Маски вывода цифр (-1 = выкл.) case 1: digitalWrite(D0,HIGH); digitalWrite(D1,HIGH); digitalWrite(D3,HIGH); digitalWrite(D4,HIGH); digitalWrite(D7,HIGH); digitalWrite(D16,HIGH); digitalWrite(D20,HIGH); digitalWrite(D19,HIGH); digitalWrite(D18,HIGH); break; case 2: digitalWrite(A1,HIGH); digitalWrite(D1,HIGH); digitalWrite(D0,HIGH); digitalWrite(D3,HIGH); digitalWrite(D4,HIGH); digitalWrite(D5,HIGH); digitalWrite(D6,HIGH); digitalWrite(D1,HIGH); digitalWrite(A6,HIGH); digitalWrite(A7,HIGH); digitalWrite(D22,HIGH); digitalWrite(D21,HIGH); digitalWrite(D19,HIGH); digitalWrite(D18,HIGH); break; case 3: digitalWrite(A1,HIGH); digitalWrite(D1,HIGH); digitalWrite(D0,HIGH); digitalWrite(D3,HIGH); digitalWrite(D4,HIGH); digitalWrite(D5,HIGH); digitalWrite(D6,HIGH); digitalWrite(D17,HIGH); digitalWrite(D16,HIGH); digitalWrite(D20,HIGH); digitalWrite(D19,HIGH); digitalWrite(D21,HIGH); break; case 4: digitalWrite(A0,HIGH); digitalWrite(A3,HIGH); digitalWrite(A4,HIGH); digitalWrite(A6,HIGH); digitalWrite(D6,HIGH); digitalWrite(D0,HIGH); digitalWrite(D3,HIGH); digitalWrite(D4,HIGH); digitalWrite(D7,HIGH); digitalWrite(D16,HIGH); digitalWrite(D20,HIGH); digitalWrite(D19,HIGH); digitalWrite(D18,HIGH); break; case 5: digitalWrite(D1,HIGH); digitalWrite(A1,HIGH); digitalWrite(A0,HIGH); digitalWrite(A3,HIGH); digitalWrite(A4,HIGH); digitalWrite(A6,HIGH); digitalWrite(D6,HIGH); digitalWrite(D17,HIGH); digitalWrite(D16,HIGH); digitalWrite(D20,HIGH); digitalWrite(D19,HIGH); digitalWrite(D21,HIGH); break; case 6: digitalWrite(D1,HIGH); digitalWrite(A1,HIGH); digitalWrite(A2,HIGH); digitalWrite(A3,HIGH); digitalWrite(A4,HIGH); digitalWrite(D23,HIGH); digitalWrite(D22,HIGH); digitalWrite(D21,HIGH); digitalWrite(D19,HIGH); digitalWrite(D20,HIGH); digitalWrite(D16,HIGH); digitalWrite(D17,HIGH); digitalWrite(D6,HIGH); digitalWrite(A6,HIGH); break; case 7: digitalWrite(A2,HIGH); digitalWrite(A1,HIGH); digitalWrite(D1,HIGH); digitalWrite(D0,HIGH); digitalWrite(D3,HIGH); digitalWrite(D4,HIGH); digitalWrite(D7,HIGH); digitalWrite(D16,HIGH); digitalWrite(D20,HIGH); digitalWrite(D19,HIGH); digitalWrite(D18,HIGH); break; case 8: digitalWrite(A1,HIGH); digitalWrite(A2,HIGH); digitalWrite(A3,HIGH); digitalWrite(A4,HIGH); digitalWrite(A5,HIGH); digitalWrite(A6,HIGH); digitalWrite(A7,HIGH); digitalWrite(D0,HIGH); digitalWrite(D2,HIGH); digitalWrite(D3,HIGH); digitalWrite(D4,HIGH); digitalWrite(D5,HIGH); digitalWrite(D6,HIGH); digitalWrite(D1,HIGH); digitalWrite(D16,HIGH); digitalWrite(D17,HIGH); digitalWrite(D19,HIGH); digitalWrite(D20,HIGH); digitalWrite(D21,HIGH); digitalWrite(D22,HIGH); break; case 9: digitalWrite(A1,HIGH); digitalWrite(A2,HIGH); digitalWrite(A3,HIGH); digitalWrite(A4,HIGH); digitalWrite(A5,HIGH); digitalWrite(A6,HIGH); digitalWrite(A5,HIGH); digitalWrite(D0,HIGH); digitalWrite(D2,HIGH); digitalWrite(D3,HIGH); digitalWrite(D4,HIGH); digitalWrite(D5,HIGH); digitalWrite(D6,HIGH); digitalWrite(D7,HIGH); digitalWrite(D16,HIGH); digitalWrite(D17,HIGH); digitalWrite(D1,HIGH); digitalWrite(D19,HIGH); digitalWrite(D20,HIGH); digitalWrite(D21,HIGH); break; case 0: digitalWrite(A1,HIGH); digitalWrite(A2,HIGH); digitalWrite(A3,HIGH); digitalWrite(A4,HIGH); digitalWrite(D0,HIGH); digitalWrite(D1,HIGH); digitalWrite(D2,HIGH); digitalWrite(D3,HIGH); digitalWrite(D4,HIGH); digitalWrite(D7,HIGH); digitalWrite(D16,HIGH); digitalWrite(D19,HIGH); digitalWrite(D20,HIGH); digitalWrite(D21,HIGH); digitalWrite(D22,HIGH); digitalWrite(D23,HIGH); break; case -1: digitalWrite(A0,LOW); digitalWrite(A1,LOW); digitalWrite(A2,LOW); digitalWrite(A3,LOW); digitalWrite(A4,LOW); digitalWrite(A5,LOW); digitalWrite(A6,LOW); digitalWrite(A7,LOW); digitalWrite(D0,LOW); digitalWrite(D2,LOW); digitalWrite(D3,LOW); digitalWrite(D4,LOW); digitalWrite(D5,LOW); digitalWrite(D6,LOW); digitalWrite(D7,LOW); digitalWrite(D16,LOW); digitalWrite(D17,LOW); digitalWrite(D18,LOW); digitalWrite(D19,LOW); digitalWrite(D20,LOW); digitalWrite(D21,LOW); digitalWrite(D22,LOW); digitalWrite(D23,LOW); break; } } void setup() { SPI_Setup(); // Serial.begin(9600); pinMode(D0, OUTPUT); pinMode(D1, OUTPUT); pinMode(D2, OUTPUT); pinMode(D3, OUTPUT); pinMode(D4, OUTPUT); pinMode(D5, OUTPUT); pinMode(D6, OUTPUT); pinMode(D7, OUTPUT); pinMode(D16, OUTPUT); pinMode(D17, OUTPUT); pinMode(D18, OUTPUT); pinMode(D19, OUTPUT); pinMode(D20, OUTPUT); pinMode(D21, OUTPUT); pinMode(D22, OUTPUT); pinMode(D23, OUTPUT); pinMode(A1, OUTPUT); pinMode(A1, OUTPUT); pinMode(A2, OUTPUT); pinMode(A3, OUTPUT); pinMode(A4, OUTPUT); pinMode(A5, OUTPUT); pinMode(A6, OUTPUT); pinMode(A7, OUTPUT); digitalWrite(A0,LOW); digitalWrite(A1,LOW); digitalWrite(A2,LOW); digitalWrite(A3,LOW); digitalWrite(A4,LOW); digitalWrite(A5,LOW); digitalWrite(A6,LOW); digitalWrite(A7,LOW); digitalWrite(D0,LOW); digitalWrite(D2,LOW); digitalWrite(D3,LOW); digitalWrite(D4,LOW); digitalWrite(D5,LOW); digitalWrite(D6,LOW); digitalWrite(D7,LOW); digitalWrite(D16,LOW); digitalWrite(D17,LOW); digitalWrite(D18,LOW); digitalWrite(D19,LOW); digitalWrite(D20,LOW); digitalWrite(D21,LOW); digitalWrite(D22,LOW); digitalWrite(D23,LOW); LNUM = -1; delay(250); } void loop() { delay(100); NUM = SPI_read(); // Получаем цифру if (NUM != LNUM) { // Если полученная цифра отличается LNUM = NUM; // от нарисованной, то записываем её в LNUM DRAWS(NUM); // и выводим на индикатор // Serial.println(NUM,DEC); } // if (NUM < 9) NUM++; else NUM = -1; // Перебираем цифры // delay(2500); // DRAWS(NUM); // DRAWS(10); }
----------------------------------------------------
Простенький кодик и библиотека для LCD-Дисплея по I2C, которые работают на ардуине, но не работают на атмеге были взяты отсюда: https://lesson.iarduino.ru/page/urok-4-podklyuchenie-lcd1602-po-i2c-k-arduino