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