1

Тема: ATTINY2313 + ARDUINO IDE

http://forum.rcl-radio.ru/uploads/images/2021/03/33eb748b55c02bc6e8b8efb2dc2d76e0.png

http://drazzy.com/package_drazzy.com_index.json

http://forum.rcl-radio.ru/uploads/images/2021/03/1eb718f0b2d84a9107d1b4821613e04c.png

http://forum.rcl-radio.ru/uploads/images/2021/03/6f4b0737ffc2cca04743b9d70f014e64.png

http://forum.rcl-radio.ru/uploads/images/2021/03/26a83618c43f702b8bcf6b8f2ade3269.png

void setup() {
  pinMode(11, OUTPUT);// PIN14 PB2
}

void loop() {
  digitalWrite(11, HIGH);   
  delay(100);                       
  digitalWrite(11, LOW);   
  delay(100);              
}

2

Re: ATTINY2313 + ARDUINO IDE

void setup() {
  DDRB =  0b00000100; // PB2 OUTPUT
}

void loop() {
  PORTB |= (1 << 2);
  delay(100);
  PORTB &= ~(1 << 2);
  delay(100);             
}

Скетч использует 506 байт (24%) памяти устройства. Всего доступно 2048 байт.
Глобальные переменные используют 9 байт (7%) динамической памяти, оставляя 119 байт для локальных переменных. Максимум: 128 байт.


void setup() {
  pinMode(11, OUTPUT);// PIN14 PB2
}

void loop() {
  digitalWrite(11, HIGH);   
  delay(100);                       
  digitalWrite(11, LOW);   
  delay(100);              
}

Скетч использует 748 байт (36%) памяти устройства. Всего доступно 2048 байт.
Глобальные переменные используют 9 байт (7%) динамической памяти, оставляя 119 байт для локальных переменных. Максимум: 128 байт.

ПУСТОЙ СКЕТЧ

Скетч использует 256 байт (12%) памяти устройства. Всего доступно 2048 байт.
Глобальные переменные используют 9 байт (7%) динамической памяти, оставляя 119 байт для локальных переменных. Максимум: 128 байт.

3

Re: ATTINY2313 + ARDUINO IDE

http://forum.rcl-radio.ru/uploads/images/2021/03/92afe27d1b127ec3153667e0c8a23d07.png

В настройках платы нужно выбрать поддержку Attiny2313 и установить частоту кварца 16 МГц (16 MHz external), остальные параметры менять не нужно. Далее необходимо выставить нужные фьюзы для микроконтроллера, чтобы он всегда работал на выбранной Вами частоте. Для этого в настройках Arduino IDE выберите программатор USBasb и нажмите Инструменты > Записать загрузчик. Эту операцию необходимо проводить всего один и снова повторить если Вы будете менять частоту работы микроконтроллера.

4

Re: ATTINY2313 + ARDUINO IDE

EEPROM

void setup() {
  Serial.begin(9600);
  EEPROM_write(0,125);
  Serial.println(EEPROM_read(0));
}

void loop() {
  
}

unsigned char EEPROM_read(unsigned int uiAddress){
  while(EECR & (1<<EEPE));
    EEAR = uiAddress;
    EECR |= (1<<EERE);
    return EEDR;
}


void EEPROM_write(unsigned int uiAddress, unsigned char ucData){
    while(EECR & (1<<EEPE));
      EEAR = uiAddress;
      EEDR = ucData;
      EECR |= (1<<EEMPE);
      EECR |= (1<<EEPE);
}

5

Re: ATTINY2313 + ARDUINO IDE

tm1637

int i;

void setup() {
  DDRB =  0b00000000; 
 // EEPROM_write(0,125);

 // EEPROM_read(0);
}

void loop() {
  print_time(i++,1);
  delay(1000);
  
}

unsigned char EEPROM_read(unsigned int uiAddress){
  while(EECR & (1<<EEPE));
    EEAR = uiAddress;
    EECR |= (1<<EERE);
    return EEDR;
}


void EEPROM_write(unsigned int uiAddress, unsigned char ucData){
    while(EECR & (1<<EEPE));
      EEAR = uiAddress;
      EEDR = ucData;
      EECR |= (1<<EEMPE);
      EECR |= (1<<EEPE);
}


void tm_dec(byte dig){
         for(int i = 0; i < 8; i++) {
          DDRB |= (1 << 0);del();
         if (dig & 0x01)
          DDRB &= ~(1 << 1);
         else
          DDRB |= (1 << 1);del();
          DDRB &= ~(1 << 0);del();
           dig = dig >> 1;
  }
           DDRB |= (1 << 0);
           DDRB &= ~(1 << 1);del();
           DDRB &= ~(1 << 0);del();
           uint8_t ack = ((PINB >> 1) & 1);
         if (ack == 0)
           DDRB |= (1 << 1);del();
           DDRB |= (1 << 0);del();
  }  

void tm_stop(){
           DDRB |= (1 << 1);del();
           DDRB &= ~(1 << 0);del();
           DDRB &= ~(1 << 1);del();
  }  

void tm_start(){
           DDRB |= (1 << 1);del();
  }

void print_time(int t, bool pd_t){
        tm_start();tm_dec(0b10001000+7);tm_stop();tm_start();tm_dec(0x40);tm_stop();tm_start();
        
        int data0 = t/1000;
        int data1 = t/100%10;
        int data2 = t/10%10;
        int data3 = t%10;
        
        for(int n=0;n<4;n++){
        int data;
        if(n==0){data=data0;}
        if(n==1){data=data1;}
        if(n==2){data=data2;}
        if(n==3){data=data3;}
              
        switch(data){  // XGFEDCBA
        case 0:  data = 0b00111111;break;     // 0
        case 1:  data = 0b00000110;break;     // 1
        case 2:  data = 0b01011011;break;     // 2
        case 3:  data = 0b01001111;break;     // 3
        case 4:  data = 0b01100110;break;     // 4
        case 5:  data = 0b01101101;break;     // 5
        case 6:  data = 0b01111101;break;     // 6
        case 7:  data = 0b00000111;break;     // 7
        case 8:  data = 0b01111111;break;     // 8
        case 9:  data = 0b01101111;break;     // 9
        }
              
        if(n==0){data0=data;}
        if(n==1){data1=data;}
        if(n==2){data2=data;}
        if(n==3){data3=data;}
        }
        if(pd_t==1){data1=data1+0b10000000;}
        
        tm_dec(0xC0);tm_dec(data0);tm_dec(data1);tm_dec(data2);tm_dec(data3);tm_stop();
}  

void del(){delayMicroseconds(100);}

Скетч использует 976 байт (47%) памяти устройства. Всего доступно 2048 байт.
Глобальные переменные используют 11 байт (8%) динамической памяти, оставляя 117 байт для локальных переменных. Максимум: 128 байт.

6

Re: ATTINY2313 + ARDUINO IDE

часы

http://forum.rcl-radio.ru/uploads/images/2021/03/9d150011cc4861b6b98a523ace10245d.png


// tm1637 PB0 === CLK
// tm1637 PB1 === DIO

int i,i1,hh,mm,bb;

void setup() {
  DDRB = 0b00000000; 
  PORTB |= (1 << 2) | (1 << 3);
   cli();  
  TCCR1A = 0;   
  TCCR1B = 0;   
  OCR1A = 18750; // 0.1 s
  TCCR1B |= (1 << WGM12); 
  TCCR1B |= (1 << CS11) | (1 << CS10);  // 256  
  TIMSK |= (1 << OCIE1A);  
   sei(); 
}

void loop() {
  print_time(hh * 100 + mm, bb, 7);// int число выводимое на индикатор, двоеточие, яркость от 0 до 7
  if(i1 <= 5){bb = 1;}else{bb = 0;}

  if(((PINB >> 2) & 1) == 0){mm++; if(mm>59){mm = 0;} delay(200);}
  if(((PINB >> 3) & 1) == 0){hh++; if(hh>23){hh = 0;} delay(200);}
}

void tm_dec(byte dig){
       for(int i = 0; i < 8; i++) {
         DDRB |= (1 << 0);del();
       if (dig & 0x01)
         DDRB &= ~(1 << 1);
       else
         DDRB |= (1 << 1);del();
         DDRB &= ~(1 << 0);del();
         dig = dig >> 1;
  }
         DDRB |= (1 << 0);
         DDRB &= ~(1 << 1);del();
         DDRB &= ~(1 << 0);del();
     
       if (((PINB >> 1) & 1) == 0)
         DDRB |= (1 << 1);del();
         DDRB |= (1 << 0);del();
  }  

void tm_stop(){
         DDRB |= (1 << 1);del();
         DDRB &= ~(1 << 0);del();
         DDRB &= ~(1 << 1);del();
  }  

void tm_start(){
         DDRB |= (1 << 1);del();
  }

void print_time(int t, bool pd_t, int br){
        tm_start();tm_dec(0b10001000 + br);//tm_stop();tm_start();
        tm_dec(0x40);tm_stop();tm_start();
        
        int data0 = t / 1000;
        int data1 = t / 100 % 10;
        int data2 = t / 10 % 10;
        int data3 = t % 10;
        
      for(byte n = 0; n < 4; n++){
        int data;
      switch(n){
        case 0: data = data0;break;
        case 1: data = data1;break;
        case 2: data = data2;break;
        case 3: data = data3;break;
        }
              
      switch(data){  // XGFEDCBA
        case 0:  data = 0b00111111;break;     // 0
        case 1:  data = 0b00000110;break;     // 1
        case 2:  data = 0b01011011;break;     // 2
        case 3:  data = 0b01001111;break;     // 3
        case 4:  data = 0b01100110;break;     // 4
        case 5:  data = 0b01101101;break;     // 5
        case 6:  data = 0b01111101;break;     // 6
        case 7:  data = 0b00000111;break;     // 7
        case 8:  data = 0b01111111;break;     // 8
        case 9:  data = 0b01101111;break;     // 9
        }
              
        if(n == 0){data0 = data;}
        if(n == 1){data1 = data;}
        if(n == 2){data2 = data;}
        if(n == 3){data3 = data;}
        }
      if(pd_t == 1){data1+= 0b10000000;}
      tm_dec(0xC0);tm_dec(data0);tm_dec(data1);tm_dec(data2);tm_dec(data3);tm_stop();
}  

void del(){delayMicroseconds(100);}

ISR(TIMER1_COMPA_vect){
     i++;i1++;
     if(i1 > 9){i1 = 0;}
     if(i > 599){mm++;i = 0;}
     if(mm > 59){hh++;mm = 0;}
     if(hh > 23){hh = 0;}
     }

Скетч использует 1330 байт (64%) памяти устройства. Всего доступно 2048 байт.
Глобальные переменные используют 19 байт (14%) динамической памяти, оставляя 109 байт для локальных переменных. Максимум: 128 байт.

7

Re: ATTINY2313 + ARDUINO IDE

Часы + будильник

http://forum.rcl-radio.ru/uploads/images/2021/03/0753d3d16b1cdfd23e6f324611aeb32f.png


// tm1637       PB0 === CLK
// tm1637       PB1 === DIO
// zummer       PD5
// MM+          PB2
// HH+          PB3
// ALARM/TIME   PB4
// ALARM ON/OFF PD4
// led ALARM    PD3

int i,i1,hh,mm,bb,b_hh,b_mm,bud,blok;

void setup() {
  DDRB = 0b00000000; 
  DDRD = 0b00101000;
  PORTB |= (1 << 2) | (1 << 3) | (1 << 4);
  PORTD |= (1 << 4);
   cli();  
  TCCR1A = 0;   
  TCCR1B = 0;   
  OCR1A = 18750; // 0.1 s
  TCCR1B |= (1 << WGM12); 
  TCCR1B |= (1 << CS11) | (1 << CS10);  // 256  
  TIMSK |= (1 << OCIE1A);  
   sei(); 
   b_hh = EEPROM_read(1);
   b_mm = EEPROM_read(0);
}

void loop() {
  if(bud == 0){print_time(hh * 100 + mm, bb, 7);}// int число выводимое на индикатор, двоеточие, яркость от 0 до 7
  if(bud == 1){print_time(b_hh * 100 + b_mm, bb, 7);}// int число выводимое на индикатор, двоеточие, яркость от 0 до 7
  if(i1 <= 5){bb = 1;}else{bb = 0;} 
  if(bud == 1){bb = 1;}
  // button set time
  if(((PINB >> 2) & 1) == 0 && bud == 0){mm++; if(mm>59){mm = 0;} delay(200);}
  if(((PINB >> 3) & 1) == 0 && bud == 0){hh++; if(hh>23){hh = 0;} delay(200);}
  // button set alarm
  if(((PINB >> 4) & 1) == 0 && bud == 0){bud = 1; delay(200);}
  if(((PINB >> 4) & 1) == 0 && bud == 1){bud = 0; delay(200);}
  // button set time alarm
  if(((PINB >> 2) & 1) == 0 && bud == 1){b_mm++;  if(b_mm>59){b_mm = 0;}EEPROM_write(0,b_mm); delay(200);}
  if(((PINB >> 3) & 1) == 0 && bud == 1){b_hh++;  if(b_hh>23){b_hh = 0;}EEPROM_write(1,b_hh); delay(200);}
  // led alarm | button on/off
  if(((PIND >> 4) & 1) == 0 && blok == 1){blok = 0; delay(200);}
  if(((PIND >> 4) & 1) == 0 && blok == 0){blok = 1; delay(200);}
  if(blok == 1){PORTD &= ~(1 << 3);}else{PORTD |= (1 << 3);}
  // zummer
  if((hh * 100 + mm) == (b_hh * 100 + b_mm) && blok == 0){if(i1 <= 5){DDRD |= (1 << 5);pic();} else {DDRD &= ~(1 << 5);}}  
} // loop

void pic(){
  for(int g=0;g<1000;g++){
  PORTD |= (1 << 5);
  delayMicroseconds(150);
  PORTD &= ~(1 << 5);
  delayMicroseconds(100);}
  }

void tm_dec(byte dig){
       for(int i = 0; i < 8; i++) {
         DDRB |= (1 << 0);del();
       if (dig & 0x01)
         DDRB &= ~(1 << 1);
       else
         DDRB |= (1 << 1);del();
         DDRB &= ~(1 << 0);del();
         dig = dig >> 1;
  }
         DDRB |= (1 << 0);
         DDRB &= ~(1 << 1);del();
         DDRB &= ~(1 << 0);del();
     
       if (((PINB >> 1) & 1) == 0)
         DDRB |= (1 << 1);del();
         DDRB |= (1 << 0);del();
  }  

void tm_stop(){
         DDRB |= (1 << 1);del();
         DDRB &= ~(1 << 0);del();
         DDRB &= ~(1 << 1);del();
  }  

void tm_start(){
         DDRB |= (1 << 1);del();
  }

void print_time(int t, bool pd_t, int br){
        tm_start();tm_dec(0b10001000 + br);//tm_stop();tm_start();
        tm_dec(0x40);tm_stop();tm_start();
        
        int data0 = t / 1000;
        int data1 = t / 100 % 10;
        int data2 = t / 10 % 10;
        int data3 = t % 10;
        
      for(byte n = 0; n < 4; n++){
        int data;
      switch(n){
        case 0: data = data0;break;
        case 1: data = data1;break;
        case 2: data = data2;break;
        case 3: data = data3;break;
        }
              
      switch(data){  // XGFEDCBA
        case 0:  data = 0b00111111;break;     // 0
        case 1:  data = 0b00000110;break;     // 1
        case 2:  data = 0b01011011;break;     // 2
        case 3:  data = 0b01001111;break;     // 3
        case 4:  data = 0b01100110;break;     // 4
        case 5:  data = 0b01101101;break;     // 5
        case 6:  data = 0b01111101;break;     // 6
        case 7:  data = 0b00000111;break;     // 7
        case 8:  data = 0b01111111;break;     // 8
        case 9:  data = 0b01101111;break;     // 9
        }
              
        if(n == 0){data0 = data;}
        if(n == 1){data1 = data;}
        if(n == 2){data2 = data;}
        if(n == 3){data3 = data;}
        }
      if(pd_t == 1){data1+= 0b10000000;}
      tm_dec(0xC0);tm_dec(data0);tm_dec(data1);tm_dec(data2);tm_dec(data3);tm_stop();
}  

void del(){delayMicroseconds(100);}

ISR(TIMER1_COMPA_vect){
     i++;i1++;
     if(i1 > 9){i1 = 0;}
     if(i > 599){mm++;i = 0;}
     if(mm > 59){hh++;mm = 0;}
     if(hh > 23){hh = 0;}
     }

unsigned char EEPROM_read(unsigned int uiAddress){
  while(EECR & (1<<EEPE));
    EEAR = uiAddress;
    EECR |= (1<<EERE);
    return EEDR;
}

void EEPROM_write(unsigned int uiAddress, unsigned char ucData){
    while(EECR & (1<<EEPE));
      EEAR = uiAddress;
      EEDR = ucData;
      EECR |= (1<<EEMPE);
      EECR |= (1<<EEPE);
}       
      

Скетч использует 1884 байт (91%) памяти устройства. Всего доступно 2048 байт.
Глобальные переменные используют 27 байт (21%) динамической памяти, оставляя 101 байт для локальных переменных. Максимум: 128 байт.

8

Re: ATTINY2313 + ARDUINO IDE

Хотел узнать тайну , почему версия библиотеки 2313  не последняя ?
И схема часов attiny2313 и lcd1602 как упростить под i2c ?

9

Re: ATTINY2313 + ARDUINO IDE

Хотел узнать тайну , почему версия библиотеки 2313  не последняя ?

На последней не шьется

И схема часов attiny2313 и lcd1602 как упростить под i2c ?

Очень сложно, я не смогу сделать

10 (2023-03-26 14:16:40 отредактировано selan61)

Re: ATTINY2313 + ARDUINO IDE

liman324 пишет:

часы

void setup() {
  DDRB = 0b00000000; 
  PORTB |= (1 << 2) | (1 << 3);
 

А что эти строчки означают? В них нет ошибки, раз используются PB0 и PB1?
И можно использовать скетч без кварца?

11

Re: ATTINY2313 + ARDUINO IDE

Порт B весь как вход, установить подтягивающие резисторы на входах PB2 PB3

12 (2023-04-08 08:42:31 отредактировано selan61)

Re: ATTINY2313 + ARDUINO IDE

Собрал на 2313а, без кварца. Версия ATTinyCore 1.5.2. При первой прошивке получил ошибку "avrdude: AVR Part "attiny2313a" not found." Почитал интернет, исправил в avrdude.conf - attiny2313 на attiny2313a. Заработало. Прошивал для пробы 8MHz(internal).
Кварца 12МГц нет. Часы сильно отстают. Подскажите, каким образом часы зависят от частоты? Мне кажется, тайминги должны быть приблизительно одинаковы при любой частоте. Просто с внешним кварцем, часы идут точнее, например за сутки, а с внутренним немного убегать. А у меня, за час, убегают минут на 15. Странно это.

13

Re: ATTINY2313 + ARDUINO IDE

Надо менять настройки таймера Т1 под свою частоту:

  TCCR1A = 0;   
  TCCR1B = 0;   
  OCR1A = 18750; // 0.1 s
  TCCR1B |= (1 << WGM12);
  TCCR1B |= (1 << CS11) | (1 << CS10); 


Надо получить 100 мс

если CS11 и CS10 единицы, то исходя из даташита

http://forum.rcl-radio.ru/uploads/images/2023/04/b70c643acf78667f5c4e369f81d4d580.png

у Вас делитель 64

значит

(8000000/((12499+1)x64))=10 Hz

OCR1A должно быть равно 12499

14

Re: ATTINY2313 + ARDUINO IDE

liman324 пишет:

Надо менять настройки таймера Т1 под свою частоту:

Надо получить 100 мс

если CS11 и CS10 единицы, то у Вас делитель 64

значит

(8000000/((12499+1)x64))=10 Hz

OCR1A должно быть равно 12499

Спасибо за ответ. Но меня смутило, что у вас в комментариях к скетчу написано

TCCR1B |= (1 << CS11) | (1 << CS10);  // 256

Я понял что это делитель 256 и опираясь на это не мог пересчитать. А по даташиту действительно получается 64.

15 (2023-04-19 09:45:34 отредактировано selan61)

Re: ATTINY2313 + ARDUINO IDE

Если можно, ещё спрошу. Мне надо, чтобы при определенном событии, счет времени останавливался и индикатор показывал остановленное время. Сделал так:
ISR(TIMER1_COMPA_vect){
     i1++;
     if(detect == 0){i++;} // при detect не равном 0, счет останавливается
     if(i1 > 9) {i1 = 0;}
     if(i > 599){mm++; i = 0;}
     if(mm > 59){hh++; mm = 0;}
     if(hh > 23){hh = 0;}
Однако это почему то не работает и счет продолжается. Что не так?

16 (2025-02-17 12:35:42 отредактировано klause)

Re: ATTINY2313 + ARDUINO IDE

Другой вариант часов. Индикатор с общим катодом. Сегменты -PORTB.Разряды цифр PD2-PD5 через резисторы 220 Ом. Кнопка коррекции PD0. Внешний кварц на 8МГц.

char CharMap[11] = {
0x3F, //0
0x06, //1
0x5B, //2
0x4F, //3
0x66, //4
0x6D, //5
0x7D, //6
0x07, //7
0x7F, //8
0x6F, //9
0x00, //
};

char Buffer[] = { 1, 2, 5, 9, 0 };
int Size[] = { 2, 10, 6, 10, 60 };
char Columns[4] = { 4, 5, 6, 7};
int Digit;
int Point;
volatile int Counter;

void DisplayNextDigital() {
  char segs;
  Digit = (Digit+1) % 4;//считаем от 0 до 4
  char Char = Buffer[Digit];
  if (Digit == 0 && Char == 0) Char = 10; // delete zero
  if (Digit == 1)segs= CharMap[Char]|Point;
  else segs = CharMap[Char];
  DDRB = DDRB & 0x00;                  // B7-B0 all inputs
  PORTB = PORTB | segs;                 // 1 = high
  DDRB = DDRB | segs;                   // 1 = output
}

void SetTime() {
  int Speed = 2000;
  if ((PIND & 1)==0) Speed = 4;         // Check set time button
  if (Counter == 0) {                   // Runs at 1Hz
    Counter = Speed;
    Point = Point ^ 0x80;    // Flash point
    int Carry = 1;
    for (int p=4; p>=0; p--) {
      char temp = Buffer[p] + Carry;
      Buffer[p] = temp % Size[p];
      Carry = temp / Size[p];
      if (Buffer[0]==2 && Buffer[1]==4) { // 24 hour
        Buffer[0] = 0;
        Buffer[1] = 1;
      }
    }
  }
  Counter--;  
}


ISR (TIMER1_COMPA_vect) {
  pinMode(Columns[Digit], INPUT);       // Turn off display
  DisplayNextDigital();
  SetTime();
}

ISR (TIMER1_COMPB_vect) {
  pinMode(Columns[Digit], OUTPUT);      // Turn  on display
  digitalWrite(Columns[Digit], LOW);
}

void setup() {
  pinMode(0, INPUT);
  
  TCCR1A = 0<<WGM10;
  TCCR1B = 1<<WGM12 | 2<<CS10;           // Divide by 8
  OCR1A = 499;                           // Compare match at 2000Hz
  OCR1B = 0;                           // Brightness; reduce for brighter min=480 max=0
  TIMSK = TIMSK | 1<<OCIE1A | 1<<OCIE1B; // Compare match interrupt enable
}

// All done under interrupt!
void loop() {
}

+DS3231. Внутренний кварц на 8Мгц. Кнопки коррекции PDO - часы,PD1 - минуты

#define SDA  PA0
#define SCL  PA1
// plus_h PDO    
// plus_m PD1   
char CharMap[11] = {
0x3F, //0
0x06, //1
0x5B, //2
0x4F, //3
0x66, //4
0x6D, //5
0x7D, //6
0x07, //7
0x7F, //8
0x6F, //9
0x00, //
};

char Buffer[] = { 1, 2, 5, 9, 0 };
unsigned long Alarm,debonce;
char Columns[4] = { 4, 5, 6, 7};
int Digit;
int Point;
unsigned char hour,min;

void DisplayNextDigital() {
  char segs;
  Digit = (Digit+1) % 4;//считаем от 0 до 4
  char Char = Buffer[Digit];
  if (Digit == 0 && Char == 0) Char = 10; // delete zero
  if (Digit == 1)segs= CharMap[Char]|Point;
  else segs = CharMap[Char];
  DDRB = DDRB & 0x00;                  // B7-B0 all inputs
  PORTB = PORTB | segs;                 // 1 = high
  DDRB = DDRB | segs;                   // 1 = output
}



// Timer interrupts - multiplex display
ISR (TIMER1_COMPA_vect) {
  pinMode(Columns[Digit], INPUT);       // Turn off display
  DisplayNextDigital();

}

ISR (TIMER1_COMPB_vect) {
  pinMode(Columns[Digit], OUTPUT);      // Turn  on display
  digitalWrite(Columns[Digit], LOW);
}

void setup() {
  pinMode(0, INPUT);
  pinMode(1, INPUT);
 
  TCCR1A = 0<<WGM10;
  TCCR1B = 1<<WGM12 | 2<<CS10;           // Divide by 8
  OCR1A = 499;                           // Compare match at 2000Hz
  OCR1B = 0;                           // Brightness; reduce for brighter min=480 max=0
  TIMSK = TIMSK | 1<<OCIE1A | 1<<OCIE1B; // Compare match interrupt enable
  
}


void loop() {
   read_time();
      Buffer[0] = hour / 10;       
      Buffer[1] = hour % 10;       
      Buffer[2] = min / 10;        
      Buffer[3] = min % 10;          
    if (digitalRead(0) == 0&&millis()-debonce>300) 
        {hour++; 
         if (hour > 23) hour = 0;
         ds_write(0x02,(hour/10<<4)+hour%10);
         debonce= millis(); 
        }
    if (digitalRead(1) == 0&&millis()-debonce>300) 
        {min++;
         if (min > 59) min = 0;
        ds_write(0x01,(min/10<<4)+min%10);
         debonce= millis(); 
        } 
  if(millis()-Alarm>1000){
  Point= Point^0x80; Alarm=millis();
  }
}
bool i2c_read_bit() {
    bool i2c_bit = 1;        
    DDRA &= ~(1 << SDA);            
    delayMicroseconds(10); 
    DDRA &= ~(1 << SCL);                
    if((PINA >> SDA) & 1) i2c_bit=0;                            
    delayMicroseconds(10);  
    DDRA |= (1 << SCL);              
    return i2c_bit;  
}
 
byte i2c_write_byte(byte data){
    for (byte i=0; i<8; i++){i2c_write_bit((data&0x80)==0);data<<=1;}    
    return i2c_read_bit(); 
}
 
byte i2c_read_byte(byte a){
    byte i, data=0;                
    for(i=0; i<8; i++){if (!i2c_read_bit()) data++;if(i!=7) data<<=1;}        
    i2c_write_bit(a);return data;  
}
 
void i2c_write_bit(byte b){
    delayMicroseconds(5);
    if(b){DDRA |= (1 << SDA);}else{DDRA &= ~(1 << SDA);}
    delayMicroseconds(5);
    DDRA &= ~(1 << SCL);       
    delayMicroseconds(10);
    DDRA |= (1 << SCL);
}
 
void i2c_start(){
     delayMicroseconds(10);  
     DDRA &= ~(1 << SDA); DDRA &= ~(1 << SCL); 
     delayMicroseconds(10); 
     DDRA |= (1 << SDA);  PORTA &= ~(1 << SDA);
     delayMicroseconds(10); 
     DDRA |= (1 << SCL);  PORTA &= ~(1 << SCL);   
     delayMicroseconds(10);
}
 
void i2c_stop()  {
     DDRA |= (1 << SDA);            
     delayMicroseconds(10);
     DDRA &= ~(1 << SCL);               
     delayMicroseconds(10); 
     DDRA &= ~(1 << SDA);             
}
 
byte ds_read(byte reg){
     byte data = 0;
     i2c_start();
     i2c_write_byte(0b11010000);
     i2c_write_byte(reg);
     i2c_start(); 
     i2c_write_byte(0b11010001); 
     data = i2c_read_byte(0);
     i2c_stop();
     return data;
  }
 
void ds_write(byte reg, byte data){
     i2c_start();
     i2c_write_byte(0b11010000);
     i2c_write_byte(reg);
     i2c_write_byte(data);
     i2c_stop();
  }  
 
void set_time(byte hours ,byte minute, byte second){
    ds_write(0x00,(second/10<<4)+second%10);
    ds_write(0x01,(minute/10<<4)+minute%10);
    ds_write(0x02,(hours/10<<4)+hours%10);

  }
void read_time(){  
min =  (ds_read(1) & 0x0F) + (((ds_read(1) & 0x70) >> 4) * 10);
hour = (ds_read(2) & 0x0F) + (((ds_read(2) & 0x70) >> 4) * 10);
       
  } 

GPS часы без учета часового пояса.

// David Johnson-Davies - www.technoblogy.com - 9th July 2018
// ATtiny2313 @ 8 MHz (external crystal; BOD disabled)

// Seven-segment definitions
const int charArrayLen = 12;
uint8_t charArray[] = {
//  ABCDEFG  Segments
  0b1111110, // 0
  0b0110000, // 1
  0b1101101, // 2
  0b1111001, // 3
  0b0110011, // 4
  0b1011011, // 5
  0b1011111, // 6
  0b1110000, // 7
  0b1111111, // 8
  0b1111011, // 9
  0b0000001, // 10  '-'
  0b0000000  // 11  Space
};

const int Dash = 10;
const int Space = 11;
uint8_t Buffer[] = { Dash, Dash, Dash, Dash};
uint8_t dp = -1;  // Decimal point position 0 to 3
uint8_t digit = 0;

uint8_t Digits[] = {4, 7, 5, 6};
// Segments must all go to port B; this specifies how they're wired up:
//                    g  f  e  d  c  b  a  dp
uint8_t Segments[] = {2, 4, 5, 3, 1, 6, 7, 0};
//G-PB0,F-PB1..A-PB6,DP-PB6 without void ReorderBits()
void ReorderBits() {         //переупорядить биты.
  uint8_t segs, newsegs;
  for (int i=0; i<charArrayLen; i++) {
    segs = charArray[i];
    newsegs = 0;
    for (int i=0; i<8; i++) {
      newsegs = newsegs | ((segs & 1)<<Segments[i]);
      segs = segs >> 1;
    }
    charArray[i]=newsegs;
  }  
}

void DisplayNextDigit() {
  pinMode(Digits[digit], INPUT);
  digit = (digit+1) % 4;
  uint8_t segs = charArray[Buffer[digit]];
  // Display decimal point?
  if (digit == dp) segs = segs | (1<<Segments[7]);
  DDRB = 0;     // All inputs
  PORTB = segs; // 1 = high
  DDRB = segs;  // 1 = output
  pinMode(Digits[digit], OUTPUT);
  digitalWrite(Digits[digit], LOW);
}

// Display a four/five digit decimal number
void Display (unsigned int number) {
  boolean dig = false;
  int j;
  if (number>9999) { j=10000; dp=2; }
  else { j=1000; dp=1; }
  for (int d=0; d<4 ; d++) {
    int i = (number/j) % 10;
    if (!i && !dig && j>100) Buffer[d]=Space;
    else { Buffer[d]=i; dig = true; }
    j=j/10;
  }
}

// ParseGPS
// Example: $GPRMC,194509.000,A,4042.6142,N,07400.4168,W,2.03,221.11,160412,,,A*77
const char fmt[] PROGMEM =
           "$GPRMC,dddtdd.ddm,A,????.????,?,?????.????,?,djdk,???.??,??????,,,?*??";

int state = 0;
unsigned int temp;

// GPS variables
volatile unsigned int Time;


void ParseGPS (char c) {
  if (c == '$') { state = 0; temp = 0; }
  uint8_t mode = pgm_read_byte_near(fmt + state++);
  // If received character matches format string, or format is '?' - return
  if ((mode == c) || (mode == '?')) return;
  // d=decimal digit
  uint8_t d = c - '0';
  if (mode == 'd') temp = temp*10 + d;
  // t=Time - hhmm
  else if (mode == 't') { Time = temp*10 + d; temp = 0; }
  else state = 0;
}

// Timer interrupt - multiplexes display
ISR (TIMER1_COMPA_vect) {
  DisplayNextDigit();
}

// USART interrupt - receives data from GPS module
ISR (USART_RX_vect) {
  uint8_t c = UDR;
  ParseGPS(c);
}

void setup() {
  ReorderBits();
  // Set up Timer1 to multiplex the display
  TCCR1A = 0<<WGM10;
  TCCR1B = 1<<WGM12 | 2<<CS10;  // Divide by 8
  OCR1A = 4999;                 // Compare match at 200Hz
  TIMSK |= 1<<OCIE1A;           // Compare match interrupt enable
  // Set up USART
  UCSRB = 1<<RXEN | 1<<RXCIE;   // Enable Rx and interrupt
  UCSRC = 3<<UCSZ0;             // 8-bit UART mode
  UBRRL = 51;                   // 9600 baud
}

void loop() {
  unsigned int temp; 
  cli(); temp = Time; sei();
  Display(temp);
  
}

17 (2025-02-26 12:26:51 отредактировано klause)

Re: ATTINY2313 + ARDUINO IDE

+DHT11. Индикатор от АОНа запитан через ULN2803. Работает плавное гашение индикатора и показания температуры(влажности) с "эффектом волны" .   

#define DHT PD6
byte _hum, _temp;
char CharMap[15] = {

//GDBFCHEA  
 B01111011, //0
 B00101000, //1
 B11100011, //2
 B11101001, //3
 B10111000, //4
 B11011001, //5
 B11011011, //6
 B00101001, //7
 B11111011, //8
 B11111001, //9
 B00000000, //pusto
 B01010011, //gradus
 B10110001, // 12
 B11001010, // 13
 B10000000, // 14
};

char Buffer[] = {14,14,14,14,14,14,14,14};
char Digits[] = {7,6,5,4,3,2,1,0};
int Digit;
unsigned long Alarm;
void DisplayNextDigital() {
  pinMode(Digits[Digit], INPUT); 
  Digit = (Digit+1) % 8;//считаем от 0 до 8
  char Char = Buffer[Digit];
  char segs;
  segs = CharMap[Char];
  DDRB = 0;
  PORTB = segs;     
  DDRB = segs;
  pinMode(Digits[Digit], OUTPUT); 
  digitalWrite(Digits[Digit], HIGH);
           

}
// yield() работает только при delay()
void yield(){DisplayNextDigital();}
void Delay(){delay(50);}

void setup() {

}

void loop() {
 if(millis()-Alarm>3000){
 for(byte i=0;i<8;i++){ Buffer[i]=10;Delay();}
 delay(1000);
 dht_read(&_hum, &_temp);
 Alarm= millis();
  }
  Buffer[7]= 13;Delay();
  Buffer[6]= 12; Delay();
  Buffer[5] = _hum % 10; Delay();
  Buffer[4] = _hum / 10%10; Delay();
  Buffer[3]= 11; Delay();
  Buffer[2]= 12; Delay();
  Buffer[1] = _temp  % 10; Delay(); 
  Buffer[0] = _temp/ 10%10; Delay();
}

 byte dht_read(byte *hum, byte* temp) {
  byte data[5];
  
  byte error=dht_start();

 if (error) return error; 
  
  for (byte i=0; i<5; i++)
  {
    data[i]=dht_byte();
  }
  
  if (data[0]+data[1]+data[2]+data[3]!=data[4]) return 3; 
  
  *hum=data[0];
  *temp=data[2];
  return 0;
}
 byte  dht_start(){
  DDRD|=(1<<DHT);
  delay(18); 
  DDRD&=~(1<<DHT); 
  delayMicroseconds(40);
  if (PIND&(1<<DHT)) return 1; 
  delayMicroseconds(80); 
  if (!(PIND&(1<<DHT))) return 2; 
  while(PIND&(1<<DHT));
  return 0;
}
byte dht_byte(){
  byte i=8, byte=0;
  while(i--){
    while(!(PIND&(1<<DHT)));
    delayMicroseconds(40);
    if (PIND&(1<<DHT)) {
      byte|=(1<<i);
      while(PIND&(1<<DHT));
    }
  }
  return byte;
}

http://forum.rcl-radio.ru/uploads/images/2025/02/32c4675c3cc20aa945426585107f6a8f.jpg

DS18b20

int temp;
#define OUT  PIND6
char CharMap[14] = {

//GDBFCHEA  
 B01111011, //0
 B00101000, //1
 B11100011, //2
 B11101001, //3
 B10111000, //4
 B11011001, //5
 B11011011, //6
 B00101001, //7
 B11111011, //8
 B11111001, //9
 B00000000, //pusto
 B01010011, //gradus
 B10110001, // 12
 B10000000, // 13
};

char Buffer[] = {10,10,10,10,10,10,10};
char Digits[] = {7,6,5,4,3,2,1};
int Digit;
unsigned long Alarm;
void DisplayNextDigital() {
  pinMode(Digits[Digit], INPUT);
 
  Digit = (Digit+1) % 7;//считаем от 0 до 7
  char Char = Buffer[Digit];
  char segs;
  segs = CharMap[Char];
  if(Digit==3)segs=segs|B00000100;
  DDRB = 0;
  PORTB = segs;     
  DDRB = segs;
  pinMode(Digits[Digit], OUTPUT); 
  digitalWrite(Digits[Digit], HIGH);
           

}



// Timer interrupts - multiplex display
ISR (TIMER1_COMPA_vect) { 
  DisplayNextDigital();
   
}

void setup() {
  
  TCCR1A = 0<<WGM10;
  TCCR1B = 1<<WGM12 | 2<<CS10;  
  OCR1A = 499;                          
  TIMSK = TIMSK | 1<<OCIE1A ; 
  
}


void loop() {
  
 if(millis()-Alarm>1000){ 
  temp=read_temp();
   delay(50);
  Alarm=millis();
  }             
  if(temp<0){temp=-temp;
    Buffer[0] = 13;
    }
    else{
     Buffer[0]=10;}
     Buffer[1] = temp/1000%10;
     if( Buffer[1]==0)Buffer[1]=10;
     Buffer[2] = temp/100%10;
     if( Buffer[2]==0)Buffer[2]=10;
     Buffer[3] = temp/10%10;
     Buffer[4] = temp%10;
     Buffer[5]= 12;
     Buffer[6]= 11;
  
}

// reset
uint8_t therm_reset(){
    uint8_t i;
    PORTD &= ~(1 << OUT);
    DDRD |= (1 << OUT);
   
    delayMicroseconds(480);  
    DDRD &= ~(1 << OUT);
 
    delayMicroseconds(60);
    i=((PIND >> OUT) & 1);

    delayMicroseconds(420);
    
    return i;
}
// write bit
void therm_write_bit(uint8_t bit){
    PORTD &= ~(1 << OUT);
    DDRD |= (1 << OUT);
   delayMicroseconds(1);
    if(bit) DDRD &= ~(1 << OUT);
    delayMicroseconds(60);
    DDRD &= ~(1 << OUT);
}
// read bit
uint8_t therm_read_bit(void){
    uint8_t bit=0;
    PORTD &= ~(1 << OUT);
    DDRD |= (1 << OUT);
  delayMicroseconds(1);
    DDRD &= ~(1 << OUT);
    delayMicroseconds(14);
    if(PIND & (1 << OUT)) bit=1;
    delayMicroseconds(45);
    return bit;
}
 
// read byte
uint8_t therm_read_byte(void){
    uint8_t i=8, n=0;
    while(i--){n>>=1;n|=(therm_read_bit()<<7);}
    return n;
}
 
// write byte
void therm_write_byte(uint8_t byte){
    uint8_t i=8;
    while(i--){therm_write_bit(byte&1);byte >>= 1;
    }
}
// read temp
int read_temp(){
    uint8_t temperature[2];
    float temper;
    cli();
    therm_reset();
    sei();
    therm_write_byte(0xCC);
    therm_write_byte(0x44);
    while(!therm_read_bit());
    therm_reset();
    therm_write_byte(0xCC);
    therm_write_byte(0xBE);
    temperature[0]=therm_read_byte();
    temperature[1]=therm_read_byte();
    temper = (temperature[1] << 8 | temperature[0])*10/16;
    return (int)temper;
}

  

18

Re: ATTINY2313 + ARDUINO IDE

Поверка подключения usart на скорости 9600. Внутренний кварц на 8Мгц.

unsigned char USART_Receive( void ); //Функция приема данных по протоколу USART
void USART_Transmit( unsigned char data ); //Функция передачи данных по протоколу USART

int main( void )
{
UBRRL = 51;

UCSRB = (( 1 << RXEN)|(1 << TXEN)); //Разрешение на прием и на передачу через USART

UCSRC = (1 << UCSZ1) | (1 << UCSZ0); 
for (;;) 
{

USART_Transmit( USART_Receive()); //Отправка принятого символа назад

}
}

unsigned char USART_Receive( void ) 
{
while (!(UCSRA & (1 << RXC))); //Ожидание приема символа

return UDR; //Возврат содержимого буфера приема символа
}

void USART_Transmit( unsigned char data )
{
while (!(UCSRA & (1 << UDRE)) ); //Ожидание опустошения буфера приема

UDR = data; //Начало передачи данных

}

Работает через переходник USB-Uart. В мониторе порта отправленные данные возвращаются.

19

Re: ATTINY2313 + ARDUINO IDE

На сайте есть статья ATtiny2313 + LCD1602 (Arduino IDE).
Дополнение к скетчу. Прорисовка своих символов до 8шт.
Кусочек кода.

char smile[]={0x00,0x00,0x0a,0x00,0x11,0x0e,0x00,0x00};
char plus[]={0x04,0x04,0x1f,0x04,0x04,0x00,0x1f,0x00};
void setup() {
  
  lcdInit();
  lcd(0x40);
  for( byte i=0;i<8;i++)lcdSend(0,smile[i]);
  lcd(0x40+8);
  for( byte i=0;i<8;i++)lcdSend(0,plus[i]);
 // lcd(0x40+16);lcd(0x40+24);..lcd(0x40+56);
  }
 
void loop() {
 
   lcdCurs(0,3);
   lcdSend(0,0); 
   lcdCurs(0,5);
   lcdSend(0,1);
   delay(100);
}

///////////////////////////////////////////////////////////////////////////////////////////

20 (2025-03-26 06:35:38 отредактировано klause)

Re: ATTINY2313 + ARDUINO IDE

+RDA5807+Lcd1601.Настройка частоты кнопками. В настройках платы убрать millis()чтобы скетч вместился.

//#include <EEPROM.h>
#include <TinyWireM.h> 
byte channel=100;//EEPROM.read(0);
#define RDA5807M_ADDRESS   0x10
#define BOOT_CONFIG_LEN 12
#define TUNE_CONFIG_LEN 4
// sda = PB5 pin 17 
// scl = PB7 pin 19  
// PD3 ++
// PD4 --
bool flagCh1=0,flagCh2=0;
uint8_t boot_config[] = {
  /* register 0x02 */
  0b11100000,    
  0b00000111,       
  /* register 0x03 */   
  0b00000000,     
  0b00000000,        
  /* register 0x04 */
  0b00001010,     
  0b00000000,    
  /* register 0x05 */
  0b10001000,       
  0b00001111,      
  /* register 0x06 */
  0b00000000, 
  0b00000000,     
  /* register 0x07 */
  0b01000010,    
  0b00000010, 
    
};

uint8_t tune_config[] = {
  /* register 0x02 */
  0b11100000,  
  0b00000101,    
   /* register 0x03 */   
   (channel >> 2),    
   ((channel & 0b11) << 6 ) | 0b00010000
   
};



void setup() {
  
  TinyWireM.begin(); 
  TinyWireM.beginTransmission(RDA5807M_ADDRESS); 
  TinyWireM.write(boot_config, BOOT_CONFIG_LEN); 
  TinyWireM.endTransmission();
    
DDRD&=~(1<<3)|(1<<4);
//PORTD|=(1<<3)|(1<<4);
lcdInit();
delay(500);
myChangeChannel(channel);
  }
 
void loop() { 
  if (((PIND >> 3) & 1) == 0){  //настройка частоты       
       channel++;flagCh1=1;
      
    myChangeChannel(channel);
    del(); }
    
//  if(((PIND >> 3) & 1)!= 0&&flagCh1==1)
//   {EEPROM.update(0,channel);flagCh1=0;}
        
   if (((PIND >> 4) & 1) == 0){   
      channel--;flagCh2=1;   
    myChangeChannel(channel);
     del(); }
     
 //  if(((PIND >> 4) & 1)!= 0&&flagCh2==1)
 //  {EEPROM.update(0,channel);flagCh2=0;}

  channel = constrain(channel, 1, 210);   
  uint16_t frequency = channel+870; 
  lcdCurs(0,0);
  lcdString("Radio");
  lcdCurs(1,0);
  if(frequency/1000==0)lcdString(" ");
  lcdInt(frequency/10);lcdChar('.');lcdInt(frequency%10);
  lcdString(" FM");
    del();
}


void myChangeChannel(int channel){ /* void if nothing is returned else int */
  
   tune_config[2] = (channel >> 2); 
   tune_config[3] = ((channel & 0b11) << 6 ) | 0b00010000;
      
     TinyWireM.begin();
     TinyWireM.beginTransmission(RDA5807M_ADDRESS);
     TinyWireM.write(tune_config, TUNE_CONFIG_LEN);
     TinyWireM.endTransmission();
  }
 
///////////////////////////////////////////////////////////////////////////////////////////
void lcdSend(bool rs, byte data) {
    if(rs==0){PORTD |= (1 << 6);} else{PORTD &= ~(1 << 6);}//RS
    del();
    if(((data >> 7) & 1) ==1){PORTB |= (1 << 3);}else{PORTB &= ~(1 << 3);}
    if(((data >> 6) & 1) ==1){PORTB |= (1 << 2);}else{PORTB &= ~(1 << 2);}
    if(((data >> 5) & 1) ==1){PORTB |= (1 << 1);}else{PORTB &= ~(1 << 1);}
    if(((data >> 4) & 1) ==1){PORTB |= (1 << 0);}else{PORTB &= ~(1 << 0);}
    e_pin();
    if(((data >> 3) & 1) ==1){PORTB |= (1 << 3);}else{PORTB &= ~(1 << 3);}
    if(((data >> 2) & 1) ==1){PORTB |= (1 << 2);}else{PORTB &= ~(1 << 2);}
    if(((data >> 1) & 1) ==1){PORTB |= (1 << 1);}else{PORTB &= ~(1 << 1);}
    if(((data >> 0) & 1) ==1){PORTB |= (1 << 0);}else{PORTB &= ~(1 << 0);}
    e_pin();
}
 
void lcd(uint8_t cmd) {lcdSend(true, cmd);}
void lcdChar(const char chr) {lcdSend(false, (uint8_t)chr);}
void lcdString(const char* str) {while(*str != '\0') {del();lcdChar(*str);str++;}}
void del(){delay(5);}
void e_pin(){PORTB |= (1 << 4);del();PORTB &= ~(1 << 4);}
void lcdCurs(byte str, byte mesto){
  if(str==0){lcd(0b10000000+mesto);}
  if(str==1){lcd(0b11000000+mesto);}
  }
void lcdInit(){ 
    DDRB |= (1 << 0) | (1 << 1)| (1 << 2) | (1 << 3) | (1 << 4);
    DDRD |= (1 << 6);  
    delay(100);
    lcd(0x03);delayMicroseconds(4500);
    lcd(0x03);delayMicroseconds(4500);
    lcd(0x03);delayMicroseconds(200);

    lcd(0b00000010);del();
    lcd(0b00001100);del();
    lcd(0b00101000);del();
    lcdClear();
   
  } 
void lcdInt(int x){
   byte h[8];
   int y= x;
   int i,i_kol;
 
  for(i_kol=0;x>0;i_kol++){x=x/10;}  // определяем кол-во цифр в long
  for(i=0;i<i_kol;i++){h[i]=y%10; y=y/10;}// разбиваем число на отдельные цифры
  for(i=i_kol-1;i>=0;i--){lcdChar(h[i] +'0');} // преобразуем числа в char
  if(i_kol==0){lcdChar('0');} // если long = 0, то выводить ноль
  }
void lcdClear(){lcd(0b00000001);} 
 
 

Данный контент доступен только зарегистрированным пользователям. http://forum.rcl-radio.ru/uploads/images/2025/03/8e93766ca4f645b3f9f3202f5d81799c.jpg
Вариант с энкодером

#include <TinyWireM.h> 
byte channel=100;
volatile uint8_t _prevValueAB = 0;    
volatile uint8_t _currValueAB = 0;
#define RDA5807M_ADDRESS   0x10
#define BOOT_CONFIG_LEN 12
#define TUNE_CONFIG_LEN 4
// sda = PB5 pin 17 
// scl = PB7 pin 19  
// PD3 encoder
// PD4 encoder
uint8_t boot_config[] = {
  /* register 0x02 */
  0b11100000,    
  0b00000111,       
  /* register 0x03 */   
  0b00000000,     
  0b00000000,        
  /* register 0x04 */
  0b00001010,     
  0b00000000,    
  /* register 0x05 */
  0b10001000,       
  0b00001111,      
  /* register 0x06 */
  0b00000000, 
  0b00000000,     
  /* register 0x07 */
  0b01000010,    
  0b00000010, 
    
};

uint8_t tune_config[] = {
  /* register 0x02 */
  0b11100000,  
  0b00000101,    
   /* register 0x03 */   
   (channel >> 2),    
   ((channel & 0b11) << 6 ) | 0b00010000
   
};



void setup() {
  TCCR1A = 0;   
  TCCR1B = 0;   
  OCR1A = 1249; // 0.01 s
  TCCR1B |= (1 << WGM12); 
  TCCR1B |= (1 << CS11) | (1 << CS10);  // 64  
  TIMSK |= (1 << OCIE1A);  
  TinyWireM.begin(); 
  TinyWireM.beginTransmission(RDA5807M_ADDRESS); 
  TinyWireM.write(boot_config, BOOT_CONFIG_LEN); 
  TinyWireM.endTransmission();
    
DDRD&=~(1<<3)|(1<<4);
//PORTD|=(1<<3)|(1<<4);
lcdInit();
delay(500);
myChangeChannel(channel);
  }
 
void loop() { 
  
  uint16_t frequency = channel+870; 
  lcdCurs(0,0);
  lcdString("Radio");
  lcdCurs(1,0);
  if(frequency/1000==0)lcdString(" ");
  lcdInt(frequency/10);lcdChar('.');lcdInt(frequency%10);
  lcdString(" FM");
    del();
}


void myChangeChannel(int channel){ /* void if nothing is returned else int */
  
   tune_config[2] = (channel >> 2); 
   tune_config[3] = ((channel & 0b11) << 6 ) | 0b00010000;
      
     TinyWireM.begin();
     TinyWireM.beginTransmission(RDA5807M_ADDRESS);
     TinyWireM.write(tune_config, TUNE_CONFIG_LEN);
     TinyWireM.endTransmission();
  }
 
///////////////////////////////////////////////////////////////////////////////////////////
void lcdSend(bool rs, byte data) {
    if(rs==0){PORTD |= (1 << 6);} else{PORTD &= ~(1 << 6);}//RS
    del();
    if(((data >> 7) & 1) ==1){PORTB |= (1 << 3);}else{PORTB &= ~(1 << 3);}
    if(((data >> 6) & 1) ==1){PORTB |= (1 << 2);}else{PORTB &= ~(1 << 2);}
    if(((data >> 5) & 1) ==1){PORTB |= (1 << 1);}else{PORTB &= ~(1 << 1);}
    if(((data >> 4) & 1) ==1){PORTB |= (1 << 0);}else{PORTB &= ~(1 << 0);}
    e_pin();
    if(((data >> 3) & 1) ==1){PORTB |= (1 << 3);}else{PORTB &= ~(1 << 3);}
    if(((data >> 2) & 1) ==1){PORTB |= (1 << 2);}else{PORTB &= ~(1 << 2);}
    if(((data >> 1) & 1) ==1){PORTB |= (1 << 1);}else{PORTB &= ~(1 << 1);}
    if(((data >> 0) & 1) ==1){PORTB |= (1 << 0);}else{PORTB &= ~(1 << 0);}
    e_pin();
}
 
void lcd(uint8_t cmd) {lcdSend(true, cmd);}
void lcdChar(const char chr) {lcdSend(false, (uint8_t)chr);}
void lcdString(const char* str) {while(*str != '\0') {del();lcdChar(*str);str++;}}
void del(){delay(5);}
void e_pin(){PORTB |= (1 << 4);del();PORTB &= ~(1 << 4);}
void lcdCurs(byte str, byte mesto){
  if(str==0){lcd(0b10000000+mesto);}
  if(str==1){lcd(0b11000000+mesto);}
  }
void lcdInit(){ 
    DDRB |= (1 << 0) | (1 << 1)| (1 << 2) | (1 << 3) | (1 << 4);
    DDRD |= (1 << 6);  
    delay(100);
    lcd(0x03);delayMicroseconds(4500);
    lcd(0x03);delayMicroseconds(4500);
    lcd(0x03);delayMicroseconds(200);

    lcd(0b00000010);del();
    lcd(0b00001100);del();
    lcd(0b00101000);del();
    lcdClear();
   
  } 
void lcdInt(int x){
   byte h[8];
   int y= x;
   int i,i_kol;
 
  for(i_kol=0;x>0;i_kol++){x=x/10;}  // определяем кол-во цифр в long
  for(i=0;i<i_kol;i++){h[i]=y%10; y=y/10;}// разбиваем число на отдельные цифры
  for(i=i_kol-1;i>=0;i--){lcdChar(h[i] +'0');} // преобразуем числа в char
  if(i_kol==0){lcdChar('0');} // если long = 0, то выводить ноль
  }
void lcdClear(){lcd(0b00000001);} 
 ISR(TIMER1_COMPA_vect){
  bool pinA = (PIND >> 3) & 1;   
  bool pinB = (PIND >> 4) & 1;    
  _currValueAB  = pinA << 1;
   _currValueAB |= pinB;
   switch ((_prevValueAB | _currValueAB)){
    case 0b0001: channel++; myChangeChannel(channel);break;
    case 0b0100: channel--; myChangeChannel(channel);break;
  }
  channel = constrain(channel,1,210);
  _prevValueAB = _currValueAB << 2;       
  }

21 (2025-03-24 08:05:16 отредактировано klause)

Re: ATTINY2313 + ARDUINO IDE

С регулировкой громкости.

#include <EEPROM.h>
#include <TinyWireM.h> 
#define ACCESS_ADDRESS 0x11
// регистры
#define REG_CONFIG 0x02
#define REG_TUNING 0x03
#define REG_VOLUME 0x05
#define REG_RSSI   0x0B
// флаги
#define FLG_DHIZ 0x8000
#define FLG_DMUTE 0x4000
#define FLG_BASS 0x1000
#define FLG_ENABLE word(0x0001)
#define FLG_TUNE word(0x0010)
//маски
#define CHAN_MASK 0xFFC0
#define CHAN_SHIFT 6
#define VOLUME_MASK word(0x000F)
#define VOLUME_SHIFT 0
#define RSSI_MASK 0x100
#define RSSI_SHIFT 8
// sda = PB5 pin 17 
// scl = PB7 pin 19  
// PD3 ++channel
// PD4 --channel
// PD0 ++volume
// PD1 --volume
 
uint8_t volume = EEPROM.read(1);
uint16_t channel = EEPROM.read(0); 
uint16_t reg02h, reg03h, reg05h,reg0Bh;
byte customChar[] = {B00011,B00111,B11101,B10001,B10001,B11101,B00111,B00011};
bool flag=1,flagV1=0,flagV2=0,flagCh1=0,flagCh2=0;
void setup() {   
  reg02h = FLG_ENABLE | FLG_DHIZ | FLG_DMUTE;
  setRegister(REG_CONFIG, reg02h);
  /* усилить басы
  reg02h |= FLG_BASS;
  setRegister(REG_CONFIG, reg02h);
  */
  myChangeVolume(volume);  
  
DDRD&=~(1<<3)|(1<<4)|(1<<0)|(1<<1);
//PORTD|=(1<<3)|(1<<4)|(1<<0)|(1<<1);// Pull-Up
lcdInit();
lcd(0x40); // запись символа в lcd
  for( byte i=0;i<8;i++)lcdSend(0,customChar[i]);    
lcdCurs(0,0);
lcdSend(0,0);  
delay(500);
myChangeChannel(channel);
  }
 
void loop() {
   if (((PIND >> 0) & 1) == 0){ // регулировка звука         
       volume++;flagV1=1;
    if(volume>15)volume=15;   
    myChangeVolume(volume);
     del();}
  if(((PIND >> 0) & 1)!= 0&&flagV1==1) //запись уровня звука после отпускания кнопки
   {EEPROM.update(1,volume);flagV1=0;}
    
   if (((PIND >> 1) & 1) == 0){   
      volume--;flagV2=1;
    if (volume<=1)volume=1;  
    myChangeVolume(volume);
    del(); }    
  if(((PIND >> 1) & 1)!= 0&&flagV2==1) //запись уровня звука после отпускания кнопки
   {EEPROM.update(1,volume);flagV2=0;}
   
   if (((PIND >> 3) & 1) == 0){  //настройка частоты       
       channel++;flag=0;flagCh1=1;
     if(channel>210)channel=210;  
    myChangeChannel(channel);
    del(); }
  if(((PIND >> 3) & 1)!= 0&&flagCh1==1)  //запись частоты после отпускания кнопки
   {EEPROM.update(0,channel);flagCh1=0;}
        
   if (((PIND >> 4) & 1) == 0){   
      channel--;flag=0;flagCh2=1;
     if (channel<=1)channel=1; 
    myChangeChannel(channel);
    del(); }
   if(((PIND >> 4) & 1)!= 0&&flagCh2==1)  //запись частоты после отпускания кнопки
   {EEPROM.update(0,channel);flagCh2=0;}  

  reg0Bh = getRegister(REG_RSSI);
  uint8_t rssi = (reg0Bh & RSSI_MASK) >> RSSI_SHIFT;//флаг сигнализирует о наличии передачи на текущей частоте  
  uint16_t frequency = channel+870;
  lcdCurs(0,1);
  lcdInt(volume/10);
  lcdCurs(0,2);
  lcdInt(volume%10);
  lcdCurs(0,5);
  if(flag==1)lcdString("St ");
  if(rssi==1)lcdString("St ");
  else if(flag==0&&rssi==0) lcdString("   ");
  lcdCurs(1,0);
  if(frequency/1000==0)lcdString(" ");
  lcdInt(frequency/10);lcdChar('.');lcdInt(frequency%10);
  lcdString(" FM");
    del();
}
void setRegister(uint8_t reg, const uint16_t value) {
  TinyWireM.begin();
  TinyWireM.beginTransmission(0x11);
  TinyWireM.write(reg);
  TinyWireM.write(highByte(value));
  TinyWireM.write(lowByte(value));
  TinyWireM.endTransmission();
}

void myChangeChannel(int channel){   
  reg03h = (channel) << CHAN_SHIFT; 
  setRegister(REG_TUNING, reg03h | FLG_TUNE);
  }
void myChangeVolume(byte volume) {
  reg05h = getRegister(REG_VOLUME); // Считываем текущее значение
  reg05h &= ~VOLUME_MASK; // Сбрасываем биты VOLUME
  reg05h |= volume << VOLUME_SHIFT; // Устанавливаем новую громкость
  setRegister(REG_VOLUME, reg05h);         
  }
 uint16_t getRegister(uint8_t reg) {
  uint16_t result;
  TinyWireM.beginTransmission(ACCESS_ADDRESS);
  TinyWireM.write(reg);
  TinyWireM.endTransmission();
  TinyWireM.requestFrom(0x11, 2);
  result = (uint16_t)TinyWireM.read() << 8;
  result |= TinyWireM.read();
  return result;
}
/////////////////lcd//////////////////////////////////////////
void lcdSend(bool rs, byte data) {
    if(rs==0){PORTD |= (1 << 6);} else{PORTD &= ~(1 << 6);}//RS
    del();
    if(((data >> 7) & 1) ==1){PORTB |= (1 << 3);}else{PORTB &= ~(1 << 3);}
    if(((data >> 6) & 1) ==1){PORTB |= (1 << 2);}else{PORTB &= ~(1 << 2);}
    if(((data >> 5) & 1) ==1){PORTB |= (1 << 1);}else{PORTB &= ~(1 << 1);}
    if(((data >> 4) & 1) ==1){PORTB |= (1 << 0);}else{PORTB &= ~(1 << 0);}
    e_pin();
    if(((data >> 3) & 1) ==1){PORTB |= (1 << 3);}else{PORTB &= ~(1 << 3);}
    if(((data >> 2) & 1) ==1){PORTB |= (1 << 2);}else{PORTB &= ~(1 << 2);}
    if(((data >> 1) & 1) ==1){PORTB |= (1 << 1);}else{PORTB &= ~(1 << 1);}
    if(((data >> 0) & 1) ==1){PORTB |= (1 << 0);}else{PORTB &= ~(1 << 0);}
    e_pin();
}
 
void lcd(uint8_t cmd) {lcdSend(true, cmd);}
void lcdChar(const char chr) {lcdSend(false, (uint8_t)chr);}
void lcdString(const char* str) {while(*str != '\0') {del();lcdChar(*str);str++;}}
void del(){delay(5);}
void e_pin(){PORTB |= (1 << 4);del();PORTB &= ~(1 << 4);}
void lcdCurs(byte str, byte mesto){
  if(str==0){lcd(0b10000000+mesto);}
  if(str==1){lcd(0b11000000+mesto);}
  }
void lcdInit(){ 
    DDRB |= (1 << 0) | (1 << 1)| (1 << 2) | (1 << 3) | (1 << 4);
    DDRD |= (1 << 6);  
    delay(100);
    lcd(0x03);delayMicroseconds(4500);
    lcd(0x03);delayMicroseconds(4500);
    lcd(0x03);delayMicroseconds(200);

    lcd(0b00000010);del();
    lcd(0b00001100);del();
    lcd(0b00101000);del();
    lcdClear();
   
  } 
void lcdInt(int x){
   byte h[8];
   int y= x;
   int i,i_kol;
  for(i_kol=0;x>0;i_kol++){x=x/10;}  // определяем кол-во цифр в long
  for(i=0;i<i_kol;i++){h[i]=y%10; y=y/10;}// разбиваем число на отдельные цифры
  for(i=i_kol-1;i>=0;i--){lcdChar(h[i] +'0');} // преобразуем числа в char
  if(i_kol==0){lcdChar('0');} // если long = 0, то выводить ноль
  }
void lcdClear(){lcd(0b00000001);}

http://forum.rcl-radio.ru/uploads/images/2025/03/c66e18e056605769be630137250eaf2f.jpg

22 (2025-03-26 12:35:44 отредактировано klause)

Re: ATTINY2313 + ARDUINO IDE

Вариант с автопоиском.

#include <TinyWireM.h> 
#define ACCESS_ADDRESS 0x11
// регистры
#define REG_CONFIG 0x02
#define REG_TUNING 0x03
#define REG_VOLUME 0x05
#define REG_STATE  0x0A
#define REG_RSSI   0x0B
// флаги
#define FLG_DHIZ 0x8000
#define FLG_DMUTE 0x4000
#define FLG_BASS 0x1000
#define FLG_ENABLE word(0x0001)
#define FLG_TUNE word(0x0010)
#define BIT_SEEKUP 9
#define BIT_SEEK 8
#define BIT_STC 14
#define BIT_SEEKMODE 7
//маски
#define CHAN_MASK 0xFFC0
#define CHAN_SHIFT 6
#define VOLUME_MASK word(0x000F)
#define VOLUME_SHIFT 0
#define READCHAN_MASK 0x3FF
#define RSSI_MASK 0x100
#define RSSI_SHIFT 8
// sda = PB5 pin 17 
// scl = PB7 pin 19  
// PD3 ++channel
// PD4 --channel
// PD1,PD2 - автопоиск
uint8_t volume = 15; // 0..15
byte channel = 151; 
uint16_t reg02h, reg03h, reg05h,reg0Ah,reg0Bh;


void setup() {   
beginRda();  
myChangeVolume(volume);           
DDRD&=~(1<<3)|(1<<4)|(1<<0)|(1<<1);
//PORTD|=(1<<3)|(1<<4);
lcdInit();
delay(500);
myChangeChannel(channel);
  }
 
void loop() {
     
   if (((PIND >> 0) & 1) == 0){         
    SEEK(1);}     
       
   if (((PIND >> 1) & 1) == 0){   
    SEEK(0); }       
     
if (((PIND >> 3) & 1) == 0){  //настройка частоты       
       channel++;
   
    myChangeChannel(channel);
    del(); }

   if (((PIND >> 4) & 1) == 0){   
      channel--;       
    myChangeChannel(channel);
    del(); }
    
  channel = getFrequency();
  channel = constrain(channel,1,210);

  reg0Bh = getRegister(REG_RSSI);
  uint8_t rssi = (reg0Bh & RSSI_MASK) >> RSSI_SHIFT;   
  uint16_t frequency = channel+870;
  lcdCurs(0,0);
  if(rssi==1)lcdString("Station ");
  else lcdString("Radio   ");  
  lcdCurs(1,0);
  if(frequency/1000==0)lcdString(" ");
  lcdInt(frequency/10);lcdChar('.');lcdInt(frequency%10);
  lcdString(" FM");
    del();
}
void setRegister(uint8_t reg, const uint16_t value) {
  TinyWireM.begin();
  TinyWireM.beginTransmission(0x11);
  TinyWireM.write(reg);
  TinyWireM.write(highByte(value));
  TinyWireM.write(lowByte(value));
  TinyWireM.endTransmission();
}

void myChangeChannel(int channel){   
  reg03h = (channel) << CHAN_SHIFT; 
  setRegister(REG_TUNING, reg03h | FLG_TUNE);
  }
void myChangeVolume(byte volume) {
 reg05h = getRegister(REG_VOLUME); // Считываем текущее значение
  reg05h &= ~VOLUME_MASK; // Сбрасываем биты VOLUME
  reg05h |= volume << VOLUME_SHIFT; // Устанавливаем новую громкость
  setRegister(REG_VOLUME, reg05h);   
  }
 uint16_t getRegister(uint8_t reg) {
  uint16_t result;
  TinyWireM.beginTransmission(ACCESS_ADDRESS);
  TinyWireM.write(reg);
  TinyWireM.endTransmission();
  TinyWireM.requestFrom(0x11, 2);
  result = (uint16_t)TinyWireM.read() << 8;
  result |= TinyWireM.read();
  return result;
}
void SEEK(bool Direction) {
  reg02h = getRegister(REG_CONFIG);
  if (Direction)// Направление поиска
    reg02h |= 1 << BIT_SEEKUP;
  else
    reg02h &= ~(1 << BIT_SEEKUP);
  reg02h |= 1 << BIT_SEEKMODE;// Ищем до границы и останавливаемся на 108 или 88
  reg02h |= 1 << BIT_SEEK;// Разрешаем начать поиск станции  
  do {                     // Ждем окончания настройки частоты
    reg0Ah = getRegister(REG_STATE);
  lcdCurs(0,0);
  lcdString("Loading.");
  lcdCurs(1,0);
  lcdString("...     "); 
  } while (~reg0Ah & (1 << BIT_STC));
  setRegister(REG_CONFIG, reg02h);
}
uint16_t getFrequency () {
  do { // Ждем окончания настройки частоты
    reg0Ah = getRegister(REG_STATE);
  } while (~reg0Ah & (1 << BIT_STC));
  reg0Ah &= READCHAN_MASK;
  return (reg0Ah);
}
void beginRda(){
 reg02h = FLG_ENABLE | FLG_DHIZ | FLG_DMUTE;
  setRegister(REG_CONFIG, reg02h); 
    }
    
///////////////////////////////////////////////////////////////////////////////////////////
void lcdSend(bool rs, byte data) {
    if(rs==0){PORTD |= (1 << 6);} else{PORTD &= ~(1 << 6);}//RS
    del();
    if(((data >> 7) & 1) ==1){PORTB |= (1 << 3);}else{PORTB &= ~(1 << 3);}
    if(((data >> 6) & 1) ==1){PORTB |= (1 << 2);}else{PORTB &= ~(1 << 2);}
    if(((data >> 5) & 1) ==1){PORTB |= (1 << 1);}else{PORTB &= ~(1 << 1);}
    if(((data >> 4) & 1) ==1){PORTB |= (1 << 0);}else{PORTB &= ~(1 << 0);}
    e_pin();
    if(((data >> 3) & 1) ==1){PORTB |= (1 << 3);}else{PORTB &= ~(1 << 3);}
    if(((data >> 2) & 1) ==1){PORTB |= (1 << 2);}else{PORTB &= ~(1 << 2);}
    if(((data >> 1) & 1) ==1){PORTB |= (1 << 1);}else{PORTB &= ~(1 << 1);}
    if(((data >> 0) & 1) ==1){PORTB |= (1 << 0);}else{PORTB &= ~(1 << 0);}
    e_pin();
}
 
void lcd(uint8_t cmd) {lcdSend(true, cmd);}
void lcdChar(const char chr) {lcdSend(false, (uint8_t)chr);}
void lcdString(const char* str) {while(*str != '\0') {del();lcdChar(*str);str++;}}
void del(){delay(5);}
void e_pin(){PORTB |= (1 << 4);del();PORTB &= ~(1 << 4);}
void lcdCurs(byte str, byte mesto){
  if(str==0){lcd(0b10000000+mesto);}
  if(str==1){lcd(0b11000000+mesto);}
  }
void lcdInit(){ 
    DDRB |= (1 << 0) | (1 << 1)| (1 << 2) | (1 << 3) | (1 << 4);
    DDRD |= (1 << 6);  
    delay(100);
    lcd(0x03);delayMicroseconds(4500);
    lcd(0x03);delayMicroseconds(4500);
    lcd(0x03);delayMicroseconds(200);

    lcd(0b00000010);del();
    lcd(0b00001100);del();
    lcd(0b00101000);del();
    lcdClear();
   
  } 
void lcdInt(int x){
   byte h[8];
   int y= x;
   int i,i_kol;
  for(i_kol=0;x>0;i_kol++){x=x/10;}  // определяем кол-во цифр в long
  for(i=0;i<i_kol;i++){h[i]=y%10; y=y/10;}// разбиваем число на отдельные цифры
  for(i=i_kol-1;i>=0;i--){lcdChar(h[i] +'0');} // преобразуем числа в char
  if(i_kol==0){lcdChar('0');} // если long = 0, то выводить ноль
  }
void lcdClear(){lcd(0b00000001);} 
 

Для запоминания последней радиостанции при выключении и сбережения ресурса EEPROM  ?

#include <EEPROM.h>
byte channel=EEPROM.read(0);
void setup() {
 MCUCR |= (1<<ISC10);//нисходящий фронт на ножке INT0
 GIMSK |= (1<<INT0); 
}
 
void loop() { 
    
}
ISR(INT0_vect){EEPROM.update(0,channel); } 

PD2 через резистивный делитель на нижнюю границу логической 1 ~2.7-3в. Запитка МК через диод шоттки с накопительным конденсатором к +5В. Для того, чтобы МК смог записать в память частоту станции. BOD на 1.8в.