Программирование ATTINY2313A-PU в среде Arduino IDE 1.8.2

nikolz

Well-known member
Светодиоды для наглядности.
Сработает прерывание при наж кнопок, светодиод мигнет.
nikolz - вы ничего не рассказали про ваш метод работы с кнопками.
Или это секрет?
Один из методов раза два уже рассказывал на форуме.
Поэтому рассказывать надцатый раз нет интереса.
===============
можно это написать иначе
PORTB |= (1 << 0) | (1 << 1 ) | (1 << 2);// Set bits - pullup
DDRB &= ~((1 << 0) | (1 << 1) | (1 << 2));// Clear bit - input
PCMSK |= (1 << 0) | (1 << 1) | (1 << 2);// Set bits
---------------------
так:
----------------------
#define mask (1 << 0) | (1 << 1 ) | (1 << 2)
PORTB |= mask;// Set bits - pullup
DDRB &= ~mask;// Clear bit - input
PCMSK |=mask;// Set bits
т е PCMSK равен PORTB верно ?
==============
#define mask (1 << 0) | (1 << 1 ) | (1 << 2)
так:
#define mask 0x7
=================
а сброс маски
DDRB &= ~mask;// Clear bit - input
так:
DDRB^=mask;// Clear bit - input
 

alexlaw

Member
Отслеживаем нажатие 3 кнопок в любом сочетании
Код:
ISR(PCINT_vect) {
  PORTB &= ~((1 << 7)  | (1 <<4)  | (1 <<3));// Clear bit - выкл все светодиоды
  switch(PINB & 0x07){
    case 6:PORTB |= (1 << 3);break;//наж кн pb0 - high pb3
    case 5:PORTB |= (1 << 4);break;//наж кн pb1 - high pb4
    case 4:PORTB |= (1 << 4) | (1 <<3);break;//наж кн pb0 pb1 - high pb4 pb3
    case 3:PORTB |= (1 << 7);break;//наж кн pb2 - high pb7
    case 2:PORTB |= (1 << 7) | (1 <<3);break;//наж кн pb2 pb0 - high pb7 pb3
    case 1:PORTB |= (1 << 7) | (1 <<4);break;//наж кн pb2 pb1 - high pb7 pb4
  }
}
 

alexlaw

Member
Задача подключить бесконечное число кнопок к любому пину или двум которые являются бинарными PIO.
Я конечно не смог, но используя метод
Отслеживаем нажатие 3 кнопок в любом сочетании
и задействовав все 8 портов, можно получить 8!+1=40321 различных состояний порта "B", что практически является бесконечностью.
Вместо кнопок лучше использовать переключатели.
Хотя программно обработать такое кол-во состояний вряд ли возможно.
 

alexlaw

Member
Например с помощью переключателей можно выставить время в RTC.
 

alexlaw

Member
Я конечно перегнул палку.
Всего 255 различных состояний порта "B".
Бывает.
 

nikolz

Well-known member
Я конечно перегнул палку.
Всего 255 различных состояний порта "B".
Бывает.
подсказка
В общем случае подобные задачи я решаю методом измерения времени разряда ( заряда) емкостей.
В частности это могут быть поверхностные , межслойные , слой и палец.
 

alexlaw

Member
Финальный аккорд. Ради чего все затевалось, а именно разгрузить основной МК.
Тинька спит, при этом контролирует кнопки. При нажатии кнопок - просыпается,
отсылает на основной МК какой-то код, соответствующий нажатым кнопкам и
снова засыпает.
Код:
char but;
void setup() {
initButton();
initUSART();
}
void loop() {
  sleepNow();
  USART_Transmit(but);
  delay(500);
}
ISR(PCINT_vect) {
  PORTB &= ~((1 <<4)  | (1 <<3));// Clear bit - выкл все светодиоды
  switch(PINB & 0x03){   
    case 2:{PORTB |= (1 <<3);
    but=0x41;//A
    break;}// - high  pb3
    case 1:{PORTB |= (1 <<4);
    but=0x42;//B
    break;}// - high  pb4
    case 0:{PORTB |=(1 <<4) | (1 <<3);
    but=0x43;//C
    break;}// - high pb4 pb3
  }
}
void sleepNow() {
/*
* Idle  (режим холостого хода)
* В этом режиме прекращается формирование тактовых сигналов clk CPU и  clk FLASH .
* При  этом  ЦПУ  микроконтроллера  останавливается,  а  все остальные  периферийные  устройства
* (интерфейсные  модули,  таймеры/счетчики,  аналоговый  компаратор,  АЦП,  сторожевой  таймер),
* а также  подсистема  прерываний  продолжают  функционировать.
*/
/*Если компаратор не используется, то при переводе микроконтроллера в
* режим Idle или ADC Noise Reduction его необходимо отключить. В других
* «спящих» режимах модуль аналогового компаратора отключается автома
* тически. */ 
DIDR |= (1 << AIN1D)  | (1 << AIN0D ); // Set bits - отключения  входных  цифровых буферов
ACSR |= (1 << ACD);// Set bits - Выключение компаратора
/*
*Аналогоцифровой преобразователь
* Если функционирование АЦП разрешено, то он будет работать во всех
* «спящих»  режимах.  Соответственно,  для  снижения  потребляемого  тока
* модуль АЦП необходимо отключать перед переводом микроконтроллера в
* любой из энергосберегающих режимов.
*/
//Режим энергосбережения
MCUCR |= (1 << SM0);// Set bits - Power Down
MCUCR |= (1 << SE);// Set bits -  sleep_enable
asm ("sleep");
MCUCR &= ~(1 << SE);// Clear bit - sleep_disable
}
void initButton() {
//pb0 pb1  кнопки
//pb3 pb4 светодиод  
PORTB |= (1 << 0) | (1 << 1 );// Set bits - pullup
DDRB &= ~((1 << 0)  | (1 << 1));// Clear bit - input 
PORTB &= ~((1 << 3)  |  (1 << 4));// Clear bit - low
DDRB |= (1 << 3) | (1 << 4);// Set bits - output
GIMSK |= (1 << PCIE);// Set bits - Разрешение прерывания по изменению состояния выводов 0й группы - PCINT.
//PCMSK Определяют условие генерации прерывания PCI0. Если какойлибо
//бит установлен в 1, то изменение состояния соответствующего вывода
//вызовет генерацию прерывания
PCMSK |= (1 << 0) | (1 << 1);// Set bits -прерывание по изменению состояния вывода 0 или 1 - PCINT 
}
void initUSART() {
//UCSRB &= ~((1 << TXEN) | (1 << RXEN)); // Clear bit 
//запретить прнерывания от передатчика
UCSRB &= ~((1 << RXCIE) | (1 << TXCIE) | (1 << UDRIE)); // Clear bit
//Если бит UMSEL сброшен в 0, то модуль работает в асинхронном режиме
//USBS Количество стопбитов. Если бит сброшен в 0, то передатчик посылает 1 стопбит,
//если установлен в 1, то 2 стопбита.
//UCPOL  При работе в асинхронном режиме он должен быть сброшен в 0. USART Mode: Asynchronous
//UPM1 UPM0 - Управление схемой контроля четности - 0 0 Выключена
UCSRC &= ~((1 << UMSEL) | (1 << USBS) | (1 << UCPOL) | (1 << UPM1) | (1 << UPM0)); // Clear bit
//Определение размера слова данных - 8 бит
UCSRC |= (1<<UCSZ1) | (1<<UCSZ0); // Set bits
UCSRA &= ~(1 << UCSZ2); // Clear bit
//UCSRC &= ~(1 << U2X); // Clear bit  обычная скорость
// Speed = 9600
UBRRH = 0;
UBRRL = 51;
//Разрешение передачи
UCSRB |=(1<<TXEN); // Set bits
}
void USART_Transmit(unsigned int data)
{
   /* Ждать очистки буфера передатчика */ 
   while ( !( UCSRA & (1<<UDRE))) {   
   };
   UDR = data;    
}
com_3.png
Светодиоды нужны только для наглядности.
IMG_20190715_074705.jpg
 

nikolz

Well-known member
Финальный аккорд. Ради чего все затевалось, а именно разгрузить основной МК.
Тинька спит, при этом контролирует кнопки. При нажатии кнопок - просыпается,
отсылает на основной МК какой-то код, соответствующий нажатым кнопкам и
снова засыпает.
Код:
char but;
void setup() {
initButton();
initUSART();
}
void loop() {
  sleepNow();
  USART_Transmit(but);
  delay(500);
}
ISR(PCINT_vect) {
  PORTB &= ~((1 <<4)  | (1 <<3));// Clear bit - выкл все светодиоды
  switch(PINB & 0x03){  
    case 2:{PORTB |= (1 <<3);
    but=0x41;//A
    break;}// - high  pb3
    case 1:{PORTB |= (1 <<4);
    but=0x42;//B
    break;}// - high  pb4
    case 0:{PORTB |=(1 <<4) | (1 <<3);
    but=0x43;//C
    break;}// - high pb4 pb3
  }
}
void sleepNow() {
/*
* Idle  (режим холостого хода)
* В этом режиме прекращается формирование тактовых сигналов clk CPU и  clk FLASH .
* При  этом  ЦПУ  микроконтроллера  останавливается,  а  все остальные  периферийные  устройства
* (интерфейсные  модули,  таймеры/счетчики,  аналоговый  компаратор,  АЦП,  сторожевой  таймер),
* а также  подсистема  прерываний  продолжают  функционировать.
*/
/*Если компаратор не используется, то при переводе микроконтроллера в
* режим Idle или ADC Noise Reduction его необходимо отключить. В других
* «спящих» режимах модуль аналогового компаратора отключается автома
* тически. */
DIDR |= (1 << AIN1D)  | (1 << AIN0D ); // Set bits - отключения  входных  цифровых буферов
ACSR |= (1 << ACD);// Set bits - Выключение компаратора
/*
*Аналогоцифровой преобразователь
* Если функционирование АЦП разрешено, то он будет работать во всех
* «спящих»  режимах.  Соответственно,  для  снижения  потребляемого  тока
* модуль АЦП необходимо отключать перед переводом микроконтроллера в
* любой из энергосберегающих режимов.
*/
//Режим энергосбережения
MCUCR |= (1 << SM0);// Set bits - Power Down
MCUCR |= (1 << SE);// Set bits -  sleep_enable
asm ("sleep");
MCUCR &= ~(1 << SE);// Clear bit - sleep_disable
}
void initButton() {
//pb0 pb1  кнопки
//pb3 pb4 светодиод 
PORTB |= (1 << 0) | (1 << 1 );// Set bits - pullup
DDRB &= ~((1 << 0)  | (1 << 1));// Clear bit - input
PORTB &= ~((1 << 3)  |  (1 << 4));// Clear bit - low
DDRB |= (1 << 3) | (1 << 4);// Set bits - output
GIMSK |= (1 << PCIE);// Set bits - Разрешение прерывания по изменению состояния выводов 0й группы - PCINT.
//PCMSK Определяют условие генерации прерывания PCI0. Если какойлибо
//бит установлен в 1, то изменение состояния соответствующего вывода
//вызовет генерацию прерывания
PCMSK |= (1 << 0) | (1 << 1);// Set bits -прерывание по изменению состояния вывода 0 или 1 - PCINT
}
void initUSART() {
//UCSRB &= ~((1 << TXEN) | (1 << RXEN)); // Clear bit
//запретить прнерывания от передатчика
UCSRB &= ~((1 << RXCIE) | (1 << TXCIE) | (1 << UDRIE)); // Clear bit
//Если бит UMSEL сброшен в 0, то модуль работает в асинхронном режиме
//USBS Количество стопбитов. Если бит сброшен в 0, то передатчик посылает 1 стопбит,
//если установлен в 1, то 2 стопбита.
//UCPOL  При работе в асинхронном режиме он должен быть сброшен в 0. USART Mode: Asynchronous
//UPM1 UPM0 - Управление схемой контроля четности - 0 0 Выключена
UCSRC &= ~((1 << UMSEL) | (1 << USBS) | (1 << UCPOL) | (1 << UPM1) | (1 << UPM0)); // Clear bit
//Определение размера слова данных - 8 бит
UCSRC |= (1<<UCSZ1) | (1<<UCSZ0); // Set bits
UCSRA &= ~(1 << UCSZ2); // Clear bit
//UCSRC &= ~(1 << U2X); // Clear bit  обычная скорость
// Speed = 9600
UBRRH = 0;
UBRRL = 51;
//Разрешение передачи
UCSRB |=(1<<TXEN); // Set bits
}
void USART_Transmit(unsigned int data)
{
   /* Ждать очистки буфера передатчика */
   while ( !( UCSRA & (1<<UDRE))) {  
   };
   UDR = data;   
}
Посмотреть вложение 7635
Светодиоды нужны только для наглядности.
Посмотреть вложение 7636
Если это и есть цель, то вот простейшее решение
кнопки подключаются на RST или CH_ED
ESP спит либо вооще в дауне
нажимаем кнопки и ESP просыпается и делает по нужде и снова спит
и не надо ничего довешивать кроме кнопок на один пин
 

alexlaw

Member
Код:
//-----------------------------------------------------------------------------
/*                                   ATTINY2313
                             =========================
                          ATTINY      ARDUINO     ATTINY
                   PA0/XTAL1 || 5 -  3        9 - 12 || PB0/AIN0/PCINT0    
                   PA1/XTAL2 || 4 -  2       10 - 13 || PB1/AIN1/PCINT1
                   PA2/RESET || 1 -  17      11 - 14 || PB2/OC0A/PCINT2
                             ||              12 - 15 || PB3/OC1A/PCINT3   
                     PD0/RXD || 2 -  0       13 - 16 || PB4/OC1B/PCINT4
                     PD1/TXD || 3 -  1       14 - 17 || PB5/MOSI/DI/SDA/PCINT5
          PD2/INT0/XCK/CKOUT || 6 -  4       15 - 18 || PB6/MISO/DO/PCINT6
                    PD3/INT1 || 7 -  5       16 - 19 || PB7/USCK/SCL/PCINT7
                      PD4/T0 || 8 -  6               ||
                 PD5/T1/OC0B || 9 -  7               ||
                     PD6/ICP || 11 - 8               ||
                          ATTINY      ARDUINO     ATTINY                  
                             =========================
                                     ATTINY2313    */
//-----------------------------------------------------------------------------                                    
const int clock1 = 3;
const int data1 = 2;
                 /*0*/ /*1*/ /*2*/ /*3*/ /*4*/ /*5*/ /*6*/ /*7*/ /*8*/ /*9*/
uint8_t digits1[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71};
//uint8_t digits1[] = { 0x3f, 0x30, 0x5b, 0x79, 0x74, 0x6d, 0x6F, 0x38, 0x7f, 0x7D };
int slaveSelect=14;//PB5
int din=16;//PB7
int clk=15;//PB6
uint8_t TimeBytes[] ={0x00,0x00,0x00,0x00,0x00,0x00,0x00};
boolean b = false;
byte dot = 128;//двоеточие на дисплее индикатора
void setup() { 
PORTB |= (1 << 4);// Set bits - pullup
DDRB &= ~(1 << 4);// Clear bit - input 
PORTB &= ~(1 << 3);// Clear bit - low
DDRB |= (1 << 3) | (1 << 5) | (1 << 6) | (1 << 7) ;// Set bits - output
GIMSK |= (1 << PCIE);// Set bits - Разрешение прерывания по изменению состояния выводов 0й группы - PCINT.
//PCMSK Определяют условие генерации прерывания PCI0. Если какойлибо
//бит установлен в 1, то изменение состояния соответствующего вывода
//вызовет генерацию прерывания
PCMSK |= (1 << 4);// Set bits -прерывание по изменению состояния вывода 4
pinMode(clock1, OUTPUT);
pinMode(data1, OUTPUT);
start(clock1,data1);
writeValue(clock1,data1,0x8c);
stop(clock1,data1);
// clear display
write(clock1,data1,0x00, 0x00, 0x00, 0x00);
watch_dog_ext();
}
void loop() {
if (b) SetTime(); 
data1302();
uint8_t h = TimeBytes[2];
uint8_t m = TimeBytes[1];
if (TimeBytes[0]&0x01) dot=0; else dot=128;
write(clock1,data1,digits1[(h & 0xF0) >> 4],digits1 [h & 0x0F] | dot,digits1[(m & 0xF0) >> 4],digits1 [m & 0x0F]);
//delay(1000);
sleepNow();
}
void sendCommand1302(byte cmd, byte data)
{
digitalWrite(slaveSelect,HIGH); //chip select is active HIGH
// передать старший байт
shiftOut(din, clk, LSBFIRST, cmd);
// передать младший байт
shiftOut(din, clk, LSBFIRST, data);
digitalWrite(slaveSelect,LOW);
}
void data1302()
{
//Команда clock burst read с кодом 0xBF считывает текущее состояние часов
//В ответ RTC посылают 7 байт, в которых хранятся соответственно
//секунды, минуты, часы, день, месяц, день недели, год, и кое-какие флаги 
digitalWrite(slaveSelect,HIGH); //chip select is active HIGH
// передать  байт
shiftOut(din, clk, LSBFIRST, 0xBF);
pinMode(din, INPUT);
for(int i = 0; i < 7; i++){
TimeBytes[i]=readByte();
}
digitalWrite(slaveSelect,LOW);
pinMode(din, OUTPUT);
}
uint8_t readByte()
{
  uint8_t value = 0;
  uint8_t currentBit = 0;

  for (int i = 0; i < 8; ++i)
  {
    currentBit = digitalRead(din);
    value |= (currentBit << i);
    digitalWrite(clk, HIGH);
    delayMicroseconds(1);
    digitalWrite(clk, LOW);
  }
  return value;
}
void SetTime()
{
//УСТАНОВИТЬ ВРЕМЯ
  sendCommand1302(0x86, 0x24);//день
  sendCommand1302(0x88, 0x07);//месяц
  sendCommand1302(0x8C, 0x19);//год
  sendCommand1302(0x84, 0x21);//час
  sendCommand1302(0x82, 0x00);//мин
  sendCommand1302(0x80, 0x00);//сек
  sendCommand1302(0x8A, 0x03);//день недели
  b = false;
}
ISR(PCINT_vect) {
  if (PINB>>4 & 0x01) PORTB &= ~(1 << 3);// Clear bit - low
  else PORTB |= (1 << 3);// Set bits - high
  b = true;
}
void write(int clock,int data,uint8_t first, uint8_t second, uint8_t third, uint8_t fourth)
{
start(clock,data);
writeValue(clock,data,0x40);
stop(clock,data);
start(clock,data);
writeValue(clock,data,0xc0);
writeValue(clock,data,first);
writeValue(clock,data,second);
writeValue(clock,data,third);
writeValue(clock,data,fourth);
stop(clock,data);
}

void start(int clock,int data)
{
digitalWrite(clock,HIGH);//send start signal to TM1637
digitalWrite(data,HIGH);
delayMicroseconds(5);
digitalWrite(data,LOW);
digitalWrite(clock,LOW);
delayMicroseconds(5);
}
void stop(int clock,int data)
{
digitalWrite(clock,LOW);
digitalWrite(data,LOW);
delayMicroseconds(5);
digitalWrite(clock,HIGH);
digitalWrite(data,HIGH);
delayMicroseconds(5);
}
bool writeValue(int clock,int data,uint8_t value)
{
for(uint8_t i = 0; i < 8; i++)
{
digitalWrite(clock, LOW);
delayMicroseconds(5);
digitalWrite(data, (value & (1 << i)) >> i);
delayMicroseconds(5);
digitalWrite(clock, HIGH);
delayMicroseconds(5);
}
// wait for ACK
digitalWrite(clock,LOW);
delayMicroseconds(5);
pinMode(data,INPUT);
digitalWrite(clock,HIGH);
delayMicroseconds(5);
bool ack = digitalRead(data) == 0;
pinMode(data,OUTPUT);
return ack;
}
void sleepNow() {
/*
* Idle  (режим холостого хода)
* В этом режиме прекращается формирование тактовых сигналов clk CPU и  clk FLASH .
* При  этом  ЦПУ  микроконтроллера  останавливается,  а  все остальные  периферийные  устройства
* (интерфейсные  модули,  таймеры/счетчики,  аналоговый  компаратор,  АЦП,  сторожевой  таймер),
* а также  подсистема  прерываний  продолжают  функционировать.
*/
/*Если компаратор не используется, то при переводе микроконтроллера в
* режим Idle или ADC Noise Reduction его необходимо отключить. В других
* «спящих» режимах модуль аналогового компаратора отключается автома
* тически. */ 
DIDR |= (1 << AIN1D)  | (1 << AIN0D ); // Set bits - отключения  входных  цифровых буферов
ACSR |= (1 << ACD);// Set bits - Выключение компаратора
/*
*Аналогоцифровой преобразователь
* Если функционирование АЦП разрешено, то он будет работать во всех
* «спящих»  режимах.  Соответственно,  для  снижения  потребляемого  тока
* модуль АЦП необходимо отключать перед переводом микроконтроллера в
* любой из энергосберегающих режимов.
*/
//Режим энергосбережения
//MCUCR &= ~((1 << SM1) | (1 << SM0));// Clear bit  - Idle -не у меня не работает?
MCUCR |= (1 << SM0);// Set bits - Power Down
MCUCR |= (1 << SE);// Set bits -  sleep_enable
asm ("sleep");
MCUCR &= ~(1 << SE);// Clear bit - sleep_disable
}
void watch_dog_ext(){
//расширенный  сторожевой  таймер
/*
* для выключения таймера (сброса бита WDE) необходимо выполнить следующие действия:
* 1. Одной командой записать 1 в биты WDE и WDCE.
* 2. В течение следующих четырех тактов записать 0 в бит WDE.
*/
/*
* Обратите внимание на то, что состояние флага сброса WDRF регистра MCUSR отменяет состояние бита WDE. Это означает, что бит WDE уста
* новлен всегда, когда установлен флаг WDRF, поэтому перед сбросом WDE необходимо также сбросить WDRF.
*/
//MCUSR &= ~(1 << WDRF);// Clear bit
//WDTCSR |= (1 << WDE)  | (1 << WDCE); // Set bits
//WDTCSR &= ~(1 << WDE);// Clear bit
/*
* Для изменения периода таймаута необходимо выполнить следующие действия:
* 1. Одной командой записать 1 в биты WDE и WDCE.
* 2. В течение следующих четырех тактов записать требуемое значение в биты WDP3:0 и WDE, одновременно сбрасывая бит WDCE.
* Перед  изменением  битов  WDP3:0  сторожевой  таймер  рекомендуется сбрасывать.
* Сброс сторожевого таймера осуществляется командой WDR.
*/
asm ("WDR");
WDTCSR |= (1 << WDE)  | (1 << WDCE); // Set bits
//1 сек
WDTCSR |= (1 << WDP1  | (1 << WDP2)); // Set bits
WDTCSR &= ~((1 << WDP0)  | (1 << WDP3));// Clear bit
WDTCSR &= ~(1 << WDCE);// Clear bit

MCUSR &= ~(1 << WDRF);// Clear bit
WDTCSR |= (1 << WDE)  | (1 << WDCE); // Set bits
WDTCSR &= ~(1 << WDE);// Clear bit

WDTCSR |= (1 << WDIE);// Set bits - Разрешение прерывания от сторожевого таймера (сбрасывается после сраб тайм аута)
}
ISR(WDT_OVERFLOW_vect) { //1 сек
dot = 128;
}
На досуге собрал часы (на дальнем плане).
Работают на CR2032.
IMG_20190722_141009.jpg
Может кому пригодится.
ds1302_tm1637.png
 

nikolz

Well-known member
мощные.
Но индикатор почему-то меньше платы.
Наверное поверхностный монтаж ?
На руси так всегда
вроде нормальная идея - а воплощение - ужас какой-то.
 

alexlaw

Member
Недавно перечитал эту ветку и увидел, что забыл важную деталь.
Попробовать i2c.
Попробовал на на часах ds3231.
Код:
/*                 DS3231
/                 ___________  
/        32kHz   | 1      16 | SCL
/         Vcc    | 2      15 | SDA
/       INT/SOW  | 3      14 | Vbat
/         RST    | 4      13 | GND
/                | 5      12 |
/                | 6      11 |
/                | 7      10 |
/                | 8      9  |
/                |___________|
/ SCL,SDA,INT/SOW,32kHz подтянуть к + через резистор 4,7к
//-----------------------------------------------------------------------------
                                    ATTINY2313
                             =========================
                          ATTINY      ARDUINO     ATTINY
                   PA0/XTAL1 || 5 -  3        9 - 12 || PB0/AIN0/PCINT0   
                   PA1/XTAL2 || 4 -  2       10 - 13 || PB1/AIN1/PCINT1
                   PA2/RESET || 1 -  17      11 - 14 || PB2/OC0A/PCINT2
                             ||              12 - 15 || PB3/OC1A/PCINT3  
                     PD0/RXD || 2 -  0       13 - 16 || PB4/OC1B/PCINT4
                     PD1/TXD || 3 -  1       14 - 17 || PB5/MOSI/DI/ SDA /PCINT5
          PD2/INT0/XCK/CKOUT || 6 -  4       15 - 18 || PB6/MISO/DO/PCINT6
                    PD3/INT1 || 7 -  5       16 - 19 || PB7/USCK/ SCL /PCINT7
                      PD4/T0 || 8 -  6               ||
                 PD5/T1/OC0B || 9 -  7               ||
                     PD6/ICP || 11 - 8               ||
                          ATTINY      ARDUINO     ATTINY                 
                             =========================
                                     ATTINY2313  
//-----------------------------------------------------------------------------
*/

//http://www.technoblogy.com/show?24R7
//https://github.com/technoblogy/tiny-i2c
#include <TinyI2CMaster.h>
const int RTCaddress = 0x68;
const int clock1 = 6;
const int data1 = 7;
                 /*0*/ /*1*/ /*2*/ /*3*/ /*4*/ /*5*/ /*6*/ /*7*/ /*8*/ /*9*/
//uint8_t digits1[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71};
uint8_t digits1[] = { 0x3f, 0x30, 0x5b, 0x79, 0x74, 0x6d, 0x6F, 0x38, 0x7f, 0x7D, 0x7E, 0x67, 0x0F, 0x73, 0x4F, 0x4E};
//byte second, minute, hour, date, month, year;
uint8_t TimeBytes[] ={0x00,0x00,0x00,0x00,0x00,0x00,0x00};
byte dot = 128;//двоеточие на дисплее индикатора
uint8_t temp;
boolean viewTemperature;
uint8_t _reg_status;
void setup() {
TinyI2C.init();
pinMode(clock1, OUTPUT);
pinMode(data1, OUTPUT);
start(clock1,data1);
writeValue(clock1,data1,0x8c);
stop(clock1,data1);
// clear display
write(clock1,data1,0x00, 0x00, 0x00, 0x00);
//SetTime_ds3231();
resetAlarm();
}

void loop() {
GetTime_ds3231();
uint8_t h = TimeBytes[2];
uint8_t m = TimeBytes[1];
if (TimeBytes[0]&0x01) dot=0; else dot=128;
// write(clock1,data1,digits1[(h & 0xF0) >> 4],digits1 [h & 0x0F] | dot,digits1[(m & 0xF0) >> 4],digits1 [m & 0x0F]);
if (viewTemperature){
write(clock1,data1,0x0F,0x5C,digits1 [temp % 10],digits1[(temp / 10)]);
} else {
write(clock1,data1,digits1 [m & 0x0F],digits1[(m & 0xF0) >> 4] | dot,digits1 [h & 0x0F],digits1[(h & 0xF0) >> 4]);
}
delay(1000);
}

void GetTime_ds3231() {
    TinyI2C.start(RTCaddress, 0);                // Start I2C protocol with DS3231 address
    TinyI2C.write(0);                            // Send register address
    TinyI2C.restart(RTCaddress, 7);               // Request 7 bytes from DS3231 and release I2C bus at end of reading
//    second = TinyI2C.read();                         // Read seconds from register 0
//    minute = TinyI2C.read();                         // Read minuts from register 1
//    hour   = TinyI2C.read();                         // Read hour from register 2
//    TinyI2C.read();                                  // Read day from register 3 (not used)
//    date   = TinyI2C.read();                         // Read date from register 4
//    month  = TinyI2C.read();                         // Read month from register 5
//    year   = TinyI2C.read();                         // Read year from register 6
    for(int i = 0; i < 7; i++){
      TimeBytes[i]=TinyI2C.read();
    }
    TinyI2C.stop();
      if ((int)(TimeBytes[0] & 0x0F) % 10 == 0){//каждые 10 сек показ температуру
         viewTemperature=true;
        getTemperture();
      } else viewTemperature=false;
}
void SetTime_ds3231() {
        // Write data to DS3231 RTC
      TinyI2C.start(RTCaddress, 0);                  // Start I2C protocol with DS3231 address
      TinyI2C.write(0);                              // Send register address    
      TinyI2C.write(0);                              // Reset sesonds and start oscillator
      TinyI2C.write(0x48);                           // Write minute
      TinyI2C.write(0x21);                           // Write hour
      TinyI2C.write(0x06);                           // Write day (not used)
      TinyI2C.write(0x31);                           // Write date
      TinyI2C.write(0x08);                           // Write month
      TinyI2C.write(0x19);                           // Write year
      TinyI2C.stop();                                // Stop transmission and release the I2C bus
}
void getTemperture()
{
  TinyI2C.start(RTCaddress, 0);                 // Start I2C protocol with DS3231 address
  TinyI2C.write(0x11);                        // Send register address
  TinyI2C.restart(RTCaddress, 2);                    // Request 2 bytes from DS3231 and release I2C bus at end of reading
  uint8_t _msb = TinyI2C.read();
  uint8_t _lsb = TinyI2C.read();
//  float temp = (float)_msb + ((_lsb >> 6) * 0.25f);
  TinyI2C.stop(); 
            temp = _msb;
}
//Поскольку при первом включении питания бит INTCN устанавливается в логическую единицу,
//на выводе по умолчанию выводится прерывание с отключенными тревогами.
void resetAlarm()//
{
readStatus();
//сброс флагов Alarm1 и Alarm2
_reg_status &= ~((1 << 0) | (1 << 1));// Clear bit 0(Alarm1), bit 1(Alarm2)
      TinyI2C.start(RTCaddress, 0);                  // Start I2C protocol with DS3231 address
      TinyI2C.write(0x0F);                           // Send register address  Status Register (0Fh)        
      TinyI2C.write(_reg_status);                    // сброс флагов Alarm1 и Alarm2
      TinyI2C.stop();
//Alarm1    
      TinyI2C.start(RTCaddress, 0);                  // Start I2C protocol with DS3231 address
      TinyI2C.write(0x07);                           // Send register address  Alarm 1          
      TinyI2C.write(0x00);                           // Alarm 1
      TinyI2C.write(0x00);                         
      TinyI2C.write(0x00);
      TinyI2C.write(0x00);
      TinyI2C.stop();                               // Stop transmission and release the I2C bus  
//Alarm1
//Alarm2    
      TinyI2C.start(RTCaddress, 0);                  // Start I2C protocol with DS3231 address
      TinyI2C.write(0x0B);                           // Send register address  Alarm 2          
      TinyI2C.write(0x00);                         
      TinyI2C.write(0x00);                  
      TinyI2C.write(0x00);
      TinyI2C.stop();                     // Stop transmission and release the I2C bus   
//Alarm2
      TinyI2C.start(RTCaddress, 0);                   // Start I2C protocol with DS3231 address
      TinyI2C.write(0x0E);                           // Send register address - Control Register (0Eh)
//Bit 2: Interrupt Control (INTCN). This bit controls the
//INT/SQW signal. When the INTCN bit is set to logic 0, a
//square wave is output on the INT/SQW pin         
      TinyI2C.write(0x04);                           // Alarm  Interrupt desable
      TinyI2C.stop();                               // Stop transmission and release the I2C bus
      
}
void readStatus(){
  TinyI2C.start(RTCaddress, 0);                    // Start I2C protocol with DS3231 address
  TinyI2C.write(0x0F);                             // Send register address REG_STATUS
  TinyI2C.restart(RTCaddress, 1);                  // Request 1 bytes from DS3231 and release I2C bus at end of reading                
  _reg_status = TinyI2C.read();
  TinyI2C.stop();  
}
void write(int clock,int data,uint8_t first, uint8_t second, uint8_t third, uint8_t fourth)
{
start(clock,data);
writeValue(clock,data,0x40);
stop(clock,data);
start(clock,data);
writeValue(clock,data,0xc0);
writeValue(clock,data,first);
writeValue(clock,data,second);
writeValue(clock,data,third);
writeValue(clock,data,fourth);
stop(clock,data);
}

void start(int clock,int data)
{
digitalWrite(clock,HIGH);//send start signal to TM1637
digitalWrite(data,HIGH);
delayMicroseconds(5);
digitalWrite(data,LOW);
digitalWrite(clock,LOW);
delayMicroseconds(5);
}


void stop(int clock,int data)
{
digitalWrite(clock,LOW);
digitalWrite(data,LOW);
delayMicroseconds(5);
digitalWrite(clock,HIGH);
digitalWrite(data,HIGH);
delayMicroseconds(5);
}

bool writeValue(int clock,int data,uint8_t value)
{
for(uint8_t i = 0; i < 8; i++)
{
digitalWrite(clock, LOW);
delayMicroseconds(5);
digitalWrite(data, (value & (1 << i)) >> i);
delayMicroseconds(5);
digitalWrite(clock, HIGH);
delayMicroseconds(5);
}
// wait for ACK
digitalWrite(clock,LOW);
delayMicroseconds(5);
pinMode(data,INPUT);
digitalWrite(clock,HIGH);
delayMicroseconds(5);
bool ack = digitalRead(data) == 0;
pinMode(data,OUTPUT);
return ack;
}
 

alexlaw

Member
Удалось подключить дисплей lcd1602 по I2C к Attiny2313.
Правда библиотеку LiquidCrystal_I2C до конца не допилил,
чтобы одновременно работала и для Attiny и для Ардуино.
С Attiny2313 - работает.
 

Вложения

alexlaw

Member
Удалось подключить дисплей lcd1602 по I2C к Attiny2313.
Правда библиотеку LiquidCrystal_I2C до конца не допилил,
чтобы одновременно работала и для Attiny и для Ардуино.
С Attiny2313 - работает.
 

Вложения

alexlaw

Member
Удалось подключить дисплей lcd1602 по I2C к Attiny2313.
Правда библиотеку LiquidCrystal_I2C до конца не допилил,
чтобы одновременно работала и для Attiny и для Ардуино.
С Attiny2313 - работает.
 

alexlaw

Member
Пожалуйста удалите лишние посты.
Случайно продублировались.
 

alexlaw

Member
Решил сделать выносной терминал на Attiny2313.
Technoblogy - Tiny Terminal - оригинальный проект на ATtiny85.
1-й этап - подключение дисплея ssd1306.
Код:
int const clk = 0;//9; //D0,SCL,CLK,SCK - Clock - PB0
int const data = 1;//10;//D1,SDA,MOSI - Data - PB1
int const res = 2;//11,RES - Reset - PB2//можно сразу к +
int const dc = 3;//12;DC - Data/Command - PB3
int const cs = 4;//13;CS - Chip Select - PB4

// Initialisation sequence for OLED module
int const InitLen = 23;
unsigned char Init[InitLen] = {
  0xAE, // Display off
  0xD5, // Set display clock
  0x80, // Recommended value
  0xA8, // Set multiplex
  0x3F,
  0xD3, // Set display offset
  0x00,
  0x40, // Zero start line
  0x8D, // Charge pump
  0x14,
  0x20, // Memory mode
  0x02, // Page addressing
  0xA1, // 0xA0/0xA1 flip horizontally
  0xC8, // 0xC0/0xC8 flip vertically
  0xDA, // Set comp ins
  0x12,
  0x81, // Set contrast
  0x7F,
  0xD9, // Set pre charge
  0xF1,
  0xDB, // Set vcom detect
  0x40,
  0xA6  // Normal (0xA7=Inverse)
};
// Character set - stored in program memory
const uint8_t CharMap[96][6] PROGMEM = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00 },
{ 0x00, 0x07, 0x00, 0x07, 0x00, 0x00 },
{ 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00 },
{ 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00 },
{ 0x23, 0x13, 0x08, 0x64, 0x62, 0x00 },
{ 0x36, 0x49, 0x56, 0x20, 0x50, 0x00 },
{ 0x00, 0x08, 0x07, 0x03, 0x00, 0x00 },
{ 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00 },
{ 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00 },
{ 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00 },
{ 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00 },
{ 0x00, 0x80, 0x70, 0x30, 0x00, 0x00 },
{ 0x08, 0x08, 0x08, 0x08, 0x08, 0x00 },
{ 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 },
{ 0x20, 0x10, 0x08, 0x04, 0x02, 0x00 },
{ 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00 },
{ 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00 },
{ 0x72, 0x49, 0x49, 0x49, 0x46, 0x00 },
{ 0x21, 0x41, 0x49, 0x4D, 0x33, 0x00 },
{ 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00 },
{ 0x27, 0x45, 0x45, 0x45, 0x39, 0x00 },
{ 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00 },
{ 0x41, 0x21, 0x11, 0x09, 0x07, 0x00 },
{ 0x36, 0x49, 0x49, 0x49, 0x36, 0x00 },
{ 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00 },
{ 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 },
{ 0x00, 0x40, 0x34, 0x00, 0x00, 0x00 },
{ 0x00, 0x08, 0x14, 0x22, 0x41, 0x00 },
{ 0x14, 0x14, 0x14, 0x14, 0x14, 0x00 },
{ 0x00, 0x41, 0x22, 0x14, 0x08, 0x00 },
{ 0x02, 0x01, 0x59, 0x09, 0x06, 0x00 },
{ 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00 },
{ 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00 },
{ 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00 },
{ 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00 },
{ 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00 },
{ 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00 },
{ 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00 },
{ 0x3E, 0x41, 0x41, 0x51, 0x73, 0x00 },
{ 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00 },
{ 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00 },
{ 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00 },
{ 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00 },
{ 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00 },
{ 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00 },
{ 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00 },
{ 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00 },
{ 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00 },
{ 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00 },
{ 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00 },
{ 0x26, 0x49, 0x49, 0x49, 0x32, 0x00 },
{ 0x03, 0x01, 0x7F, 0x01, 0x03, 0x00 },
{ 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00 },
{ 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00 },
{ 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00 },
{ 0x63, 0x14, 0x08, 0x14, 0x63, 0x00 },
{ 0x03, 0x04, 0x78, 0x04, 0x03, 0x00 },
{ 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00 },
{ 0x00, 0x7F, 0x41, 0x41, 0x41, 0x00 },
{ 0x02, 0x04, 0x08, 0x10, 0x20, 0x00 },
{ 0x00, 0x41, 0x41, 0x41, 0x7F, 0x00 },
{ 0x04, 0x02, 0x01, 0x02, 0x04, 0x00 },
{ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00 },
{ 0x00, 0x03, 0x07, 0x08, 0x00, 0x00 },
{ 0x20, 0x54, 0x54, 0x78, 0x40, 0x00 },
{ 0x7F, 0x28, 0x44, 0x44, 0x38, 0x00 },
{ 0x38, 0x44, 0x44, 0x44, 0x28, 0x00 },
{ 0x38, 0x44, 0x44, 0x28, 0x7F, 0x00 },
{ 0x38, 0x54, 0x54, 0x54, 0x18, 0x00 },
{ 0x00, 0x08, 0x7E, 0x09, 0x02, 0x00 },
{ 0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x00 },
{ 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00 },
{ 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00 },
{ 0x20, 0x40, 0x40, 0x3D, 0x00, 0x00 },
{ 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00 },
{ 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00 },
{ 0x7C, 0x04, 0x78, 0x04, 0x78, 0x00 },
{ 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00 },
{ 0x38, 0x44, 0x44, 0x44, 0x38, 0x00 },
{ 0xFC, 0x18, 0x24, 0x24, 0x18, 0x00 },
{ 0x18, 0x24, 0x24, 0x18, 0xFC, 0x00 },
{ 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00 },
{ 0x48, 0x54, 0x54, 0x54, 0x24, 0x00 },
{ 0x04, 0x04, 0x3F, 0x44, 0x24, 0x00 },
{ 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00 },
{ 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00 },
{ 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00 },
{ 0x44, 0x28, 0x10, 0x28, 0x44, 0x00 },
{ 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00 },
{ 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00 },
{ 0x00, 0x08, 0x36, 0x41, 0x00, 0x00 },
{ 0x00, 0x00, 0x77, 0x00, 0x00, 0x00 },
{ 0x00, 0x41, 0x36, 0x08, 0x00, 0x00 },
{ 0x02, 0x01, 0x02, 0x04, 0x02, 0x00 },
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 }
};
int Line, Column, Scroll;
int thisByte = 33;
void setup() {
//clk = 0;//9; //D0,SCL,CLK,SCK - Clock - PB0
//data = 1;//10;//D1,SDA,MOSI - Data - PB1
//res = 2;//11 - PB2
//dc = 3;//12; //-Data/Command - PB3
//cs = 4;//13;//-Chip Select - PB4
  // Define pins
//  pinMode(11, OUTPUT); digitalWrite(11,HIGH);//res
//  pinMode(12, OUTPUT); digitalWrite(12,HIGH);//dc
//  pinMode(9, OUTPUT); digitalWrite(9,HIGH);//clk
//  pinMode(10, OUTPUT);//data
//  pinMode(13, OUTPUT); digitalWrite(13,HIGH);//cs
  PORTB |= (1 << res);/// Set bits - high
  DDRB |= (1 << res);// Set bits - output
  PORTB &= ~(1 << data);// Clear bit - low
  PORTB |= (1 << cs) | (1 << dc) | (1 << clk);/// Set bits - high
  DDRB |= (1 << data) | (1 << cs) | (1 << dc) | (1 << clk);// Set bits - output

  InitDisplay();
  ClearDisplay();
  Command(0xAF);  // Display on
//  Print('q');Print('w');Print('e');Print('r');Print('t');Print('y');
}

void loop() {
  //"ASCII Table"
  if (thisByte < 126){
    Print(thisByte);Print(' ');
    thisByte++;
  } 
  delay(1000); 
}

// Write a data byte to the display
void Data(uint8_t d) { 
  PINB = 1<<cs; // cs low
  for (uint8_t bit = 0x80; bit; bit >>= 1) {
    PINB = 1<<clk; // clk low
    if (d & bit) PORTB = PORTB | (1<<data); else PORTB = PORTB & ~(1<<data);
    PINB = 1<<clk; // clk high
  }
  PINB = 1<<cs; // cs high
}

// Write a command byte to the display
void Command(uint8_t c) {
  PINB = 1<<dc; // dc low
 
  Data(c);
  PINB = 1<<dc; // dc high
}

void InitDisplay () {
  for (uint8_t c=0; c<InitLen; c++) Command(Init[c]);
 
}
// Character terminal **********************************************
void Clear256() {
  uint8_t b = 0;
  do {
    PINB = 1<<clk; // clk low
    b++;
    PINB = 1<<clk; // clk high
  } while (b != 0);
}

// Optimised for fast scrolling
void ClearLine (int line) {
  Command(0xB0 + line);
  Command(0x00); // Column start low
  Command(0x00); // Column start high
  PINB = 1<<cs; // cs low
  PORTB = PORTB & ~(1<<data); // data low
  Clear256(); Clear256(); Clear256(); Clear256();
  PINB = 1<<cs; // cs high
}

void ClearDisplay () {
  for (uint8_t p=0; p < 8; p++) ClearLine(p);
  Line = Scroll;
  Column = 0;
}

// Clears the top line, then scrolls the display up by one line
void ScrollDisplay () {
  ClearLine(Scroll);
  Scroll = (Scroll + 1) & 0x07;
  Command(0xD3);
  Command(Scroll << 3);
}

// Plots a character; line = 0 to 7; column = 0 to 20
void PlotChar(char c, int line, int column) {
  column = column*6;
  Command(0xB0 + ((line + Scroll) & 0x07));
  Command(0x00 + (column & 0x0F)); // Column start low
  Command(0x10 + (column >> 4));   // Column start high
  for (uint8_t col = 0 ; col < 6; col++) {
    Data(pgm_read_byte(&CharMap[c-32][col]));
  }
}

// Prints a character, handling control characters
void Print(char c) {
  c = c & 0x7F; // Ignore top bit
  if (c >= 32) {
    PlotChar(c, Line, Column++);
    if (Column > 20) {
      Column = 0;
      if (Line == 7) ScrollDisplay(); else Line++;
    }
  }
  // Return character
  else if (c == 13) {
    Column = 0;
    if (Line == 7) ScrollDisplay(); else Line++;
  }
}
ssd1306_terminal.png
 
Сверху Снизу