<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[forum.rcl-radio.ru &mdash; ATTINY2313 + ARDUINO IDE]]></title>
		<link>http://forum.rcl-radio.ru/viewtopic.php?id=278</link>
		<atom:link href="http://forum.rcl-radio.ru/extern.php?action=feed&amp;tid=278&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[Недавние сообщения в теме «ATTINY2313 + ARDUINO IDE».]]></description>
		<lastBuildDate>Fri, 11 Apr 2025 06:12:50 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[Re: ATTINY2313 + ARDUINO IDE]]></title>
			<link>http://forum.rcl-radio.ru/viewtopic.php?pid=11740#p11740</link>
			<description><![CDATA[<p>МикроАТС на 4телефона. Разработка не моя.Единственный недостаток ,что имеется только один общий канал связи и одновременно позволяет связать только 2 аппарата из четырех. Замысел понравился.</p><div class="codebox"><pre><code>unsigned char busy,cnt1,cnt2,Read=0,Tone,voice,state=0,ab1,ab2,bl,cnt3;
unsigned int timer;

//main function
int main(void)
{
   // DDRA=0x00;          //init ports
   // PORTA=0x00;
    DDRB=0x10;
    PORTB=0x10;
    DDRD=0x1F;
    PORTD=0x1F;

    TCCR0A=0x02;            //init timers
    TCCR0B=0x02;
    OCR0A=0x92;
    TCCR1A=0x00;
    TCCR1B=0x0A;
   // TCCR1C=0x00;
    OCR1A=0xA000;

    MCUCR=0x80;         // подтягивающие резисторы запрещены
    TIMSK=0x41;
    SREG|=128;

  while(1)              //main loop
  {
        if(cnt3&gt;16)     //получаем 25гц для индуктора вызова
        {
            cnt3=0;
            PORTD^=0x10; //выводим в PD4
        }

        switch(state)
        {
            case 0:    //режим &quot;трубка повешена&quot;
                ab1=0;      //вызывающий абонент
                ab2=0;      //вызываемый абонент
                voice=1;   // флаг блокировки голоса
                Tone=0;    // выбор интервала сигнала
                PORTD|=0x0F; // посылка вызова отключена

                if(Read)     // если трубка снята
                {
                    state=1; // переход в режим  &quot;трубка снята&quot;
                    timer=0; //  обнуление таймера
                }
                break;

            case 1: // режим &quot;трубка снята&quot;
                Tone=Read; //определение номера  вызывающего абонента 
      //если трубка снята больше положенного и не начат набор номера
                if(timer&gt;65000)//тикает таймер
                    state=5; //переход в режим &quot;отбой&quot;  
                              
                switch(Tone)
                {
                case 0: // начался набор номера или положили трубку 
                    state=2; //переход к режиму &quot;набор номера&quot;
                    timer=0; //  обнуление таймера
                    bl=0; // флаг набор номера
                    break;
           
                case 1:
                    ab1=1;                 
                    break;

                case 2:
                    ab1=2;
                    break;

                case 4:
                    ab1=3;
                    break;

                case 8:
                    ab1=4;
                    break;

                default:
                    ab1=0;   // если сняли трубку 2 абонента
                    state=5; // переход в режим &quot;отбой &quot; 
                }

                break;

            case 2: //режим &quot;набор номера&quot; 

                if((timer&gt;200) &amp;&amp; (ab2==0))// трубку положили надолго 
                    state=0;               // переход в режим &quot;трубка повешена &quot;
            
            /*детектируется короткий перепад (от 40 до 60 мс), 
            то это означает начала набора номера*/
                if((Read&amp;(1&lt;&lt;(ab1-1))) &amp;&amp; (timer&lt;60) &amp;&amp; (timer&gt;40) &amp;&amp; (!bl)) 
                {
                    timer=0; //  обнуление таймера
                    ab2++;  // набранный номер
                    bl=1;
                }
            /*анализ длительности замкнутого и разомкнутого состояния линии, 
              чтобы гарантированно отсечь короткие помехи в линии */
             
                if((!Read) &amp;&amp; (timer&lt;60) &amp;&amp; (timer&gt;20) &amp;&amp; bl)
                {
                    bl=0;
                    timer=0; //  обнуление таймера
                }
             //После приема цифры переход в режим &quot;посылка вызова&quot;
                if(Read &amp;&amp; (timer&gt;200) &amp;&amp; ab2)
                {
                    state=3; //переход на режим &quot;посылка вызова&quot;
                    bl=0;
                }
                break;

            case 3: //режим &quot;посылка вызова&quot;
			/*если абонент набрал свой собственный номер 
			или несуществующий номер */
                if((ab1==ab2)||(ab2&gt;4))
                    state=5;       // переход в режим &quot;отбой &quot;     
                else                   
                    if(cnt2&lt;3)//вызов абонента
                    {
                        PORTD&amp;=~(0x01&lt;&lt;(ab2-1));// включение посылки вызова вызываемого абонента
                        Tone=(0x01&lt;&lt;(ab1-1));   //длинные гудки  вызывающему абоненту
                    }
                    else
                    {
                        PORTD|=0x0F; // посылка вызова отключена
                        Tone=0;      //контроль посылки вызова отключен
                    /*Если вызываемый абонент снял трубку */    
                        if((Read&amp;(0x01&lt;&lt;(ab2-1))) &amp;&amp; (cnt2&gt;3))
                        {
                            PORTD|=0x0F;   // посылка вызова отключена
                            state=4;      // переход в режим &quot;разговор&quot;
                            voice=0;      // блокировка голоса отключена
                        }
                    }

                if((!Read) &amp;&amp; (!bl))
                {
                    bl=1;
                    timer=0; //  обнуление таймера
                }
                // если повесили трубку до раговора?
                if((!Read) &amp;&amp; (timer&gt;100) &amp;&amp; bl)
                    state=0;  // переход в режим &quot;трубка повешена &quot;              
                // если трубку подняли на 3 аппарате?
                if(Read&amp;(~((0x01&lt;&lt;(ab2-1))|(0x01&lt;&lt;(ab1-1))))) 
                {
                    state=5;      // переход в режим &quot;отбой &quot; 
                    PORTD|=0x0F; // посылка вызова отключена
                }
                break;

            case 4: //режим &quot;разговор&quot;
            /*Если один из разговаривающих абонентов кладет трубку или 
			кто-то во время разговора снимает трубку на третьем аппарате*/
                if(Read!=((0x01&lt;&lt;(ab2-1))|(0x01&lt;&lt;(ab1-1))))
                    state=5; // переход в режим &quot;отбой &quot;
                break;

            case 5: //режим &quot;отбой&quot;
            /*блокируется разговорная линия и выдается звуковой сигнал отбоя всем абонентам. 
              Когда все положат трубки, автомат вернется в состояние 0.*/
                Tone=busy; // сигнал занятости
                voice=1;   // блокировка голоса

                if(!Read)    // Когда все положат трубки
                    state=0; // переход в режим &quot;трубка повешена &quot; 
                break;

            default:
                break;
        }
    }
}

/*В обработчике таймера 0 дополнительно постоянно опрашивается состояние линий. 
 * Опрос происходит в момент между формированием импульсов тонального сигнала. 
 * Также в нем постоянно инкрементируется счетчик таймера.
 */
 //генерация тона ответа станции (425 Гц)
ISR(TIMER0_COMPA_vect)          
{
    cnt1^=0x01;
    cnt3++;

    if(timer&lt;255) //счетчик таймера
        timer++;

    if(cnt1) // переключение режимов
    {
        DDRB=0x10|Tone; // вывод тонального сигнала
        PORTB=voice&lt;&lt;4; // вывод блокировки голоса
    }
    else   /* опрос состояний линий.*/
    {  
        DDRB=0x10; 
        DDRB=0x10;
        DDRB=0x10;
        Read=PINB&amp;0x0F; // чтение состояния линий.
    }
    return;
}

//генерирует интервалы длительности сигнала
ISR(TIMER1_COMPA_vect)  
{
    busy^=0x0F;// сигнал занятости.Посылка 0.3-0.4с.Пауза — 0.3-0.4с
    cnt2++;
    cnt2&amp;=0x0F; //длительность сигнала
    return;
}</code></pre></div><p>Источник <a href="https://habr.com/ru/companies/timeweb/articles/897696/">https://habr.com/ru/companies/timeweb/articles/897696/</a></p>]]></description>
			<author><![CDATA[null@example.com (klause)]]></author>
			<pubDate>Fri, 11 Apr 2025 06:12:50 +0000</pubDate>
			<guid>http://forum.rcl-radio.ru/viewtopic.php?pid=11740#p11740</guid>
		</item>
		<item>
			<title><![CDATA[Re: ATTINY2313 + ARDUINO IDE]]></title>
			<link>http://forum.rcl-radio.ru/viewtopic.php?pid=11493#p11493</link>
			<description><![CDATA[<p>Вариант с автопоиском. <br /></p><div class="codebox"><pre><code>#include &lt;TinyWireM.h&gt; 
#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&amp;=~(1&lt;&lt;3)|(1&lt;&lt;4)|(1&lt;&lt;0)|(1&lt;&lt;1);
//PORTD|=(1&lt;&lt;3)|(1&lt;&lt;4);
lcdInit();
delay(500);
myChangeChannel(channel);
  }
 
void loop() {
     
   if (((PIND &gt;&gt; 0) &amp; 1) == 0){         
    SEEK(1);}     
       
   if (((PIND &gt;&gt; 1) &amp; 1) == 0){   
    SEEK(0); }       
     
if (((PIND &gt;&gt; 3) &amp; 1) == 0){  //настройка частоты       
       channel++;
   
    myChangeChannel(channel);
    del(); }

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

  reg0Bh = getRegister(REG_RSSI);
  uint8_t rssi = (reg0Bh &amp; RSSI_MASK) &gt;&gt; RSSI_SHIFT;   
  uint16_t frequency = channel+870;
  lcdCurs(0,0);
  if(rssi==1)lcdString(&quot;Station &quot;);
  else lcdString(&quot;Radio   &quot;);  
  lcdCurs(1,0);
  if(frequency/1000==0)lcdString(&quot; &quot;);
  lcdInt(frequency/10);lcdChar(&#039;.&#039;);lcdInt(frequency%10);
  lcdString(&quot; FM&quot;);
    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) &lt;&lt; CHAN_SHIFT; 
  setRegister(REG_TUNING, reg03h | FLG_TUNE);
  }
void myChangeVolume(byte volume) {
 reg05h = getRegister(REG_VOLUME); // Считываем текущее значение
  reg05h &amp;= ~VOLUME_MASK; // Сбрасываем биты VOLUME
  reg05h |= volume &lt;&lt; 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() &lt;&lt; 8;
  result |= TinyWireM.read();
  return result;
}
void SEEK(bool Direction) {
  reg02h = getRegister(REG_CONFIG);
  if (Direction)// Направление поиска
    reg02h |= 1 &lt;&lt; BIT_SEEKUP;
  else
    reg02h &amp;= ~(1 &lt;&lt; BIT_SEEKUP);
  reg02h |= 1 &lt;&lt; BIT_SEEKMODE;// Ищем до границы и останавливаемся на 108 или 88
  reg02h |= 1 &lt;&lt; BIT_SEEK;// Разрешаем начать поиск станции  
  do {                     // Ждем окончания настройки частоты
    reg0Ah = getRegister(REG_STATE);
  lcdCurs(0,0);
  lcdString(&quot;Loading.&quot;);
  lcdCurs(1,0);
  lcdString(&quot;...     &quot;); 
  } while (~reg0Ah &amp; (1 &lt;&lt; BIT_STC));
  setRegister(REG_CONFIG, reg02h);
}
uint16_t getFrequency () {
  do { // Ждем окончания настройки частоты
    reg0Ah = getRegister(REG_STATE);
  } while (~reg0Ah &amp; (1 &lt;&lt; BIT_STC));
  reg0Ah &amp;= 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 &lt;&lt; 6);} else{PORTD &amp;= ~(1 &lt;&lt; 6);}//RS
    del();
    if(((data &gt;&gt; 7) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 3);}else{PORTB &amp;= ~(1 &lt;&lt; 3);}
    if(((data &gt;&gt; 6) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 2);}else{PORTB &amp;= ~(1 &lt;&lt; 2);}
    if(((data &gt;&gt; 5) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 1);}else{PORTB &amp;= ~(1 &lt;&lt; 1);}
    if(((data &gt;&gt; 4) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 0);}else{PORTB &amp;= ~(1 &lt;&lt; 0);}
    e_pin();
    if(((data &gt;&gt; 3) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 3);}else{PORTB &amp;= ~(1 &lt;&lt; 3);}
    if(((data &gt;&gt; 2) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 2);}else{PORTB &amp;= ~(1 &lt;&lt; 2);}
    if(((data &gt;&gt; 1) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 1);}else{PORTB &amp;= ~(1 &lt;&lt; 1);}
    if(((data &gt;&gt; 0) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 0);}else{PORTB &amp;= ~(1 &lt;&lt; 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 != &#039;\0&#039;) {del();lcdChar(*str);str++;}}
void del(){delay(5);}
void e_pin(){PORTB |= (1 &lt;&lt; 4);del();PORTB &amp;= ~(1 &lt;&lt; 4);}
void lcdCurs(byte str, byte mesto){
  if(str==0){lcd(0b10000000+mesto);}
  if(str==1){lcd(0b11000000+mesto);}
  }
void lcdInit(){ 
    DDRB |= (1 &lt;&lt; 0) | (1 &lt;&lt; 1)| (1 &lt;&lt; 2) | (1 &lt;&lt; 3) | (1 &lt;&lt; 4);
    DDRD |= (1 &lt;&lt; 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&gt;0;i_kol++){x=x/10;}  // определяем кол-во цифр в long
  for(i=0;i&lt;i_kol;i++){h[i]=y%10; y=y/10;}// разбиваем число на отдельные цифры
  for(i=i_kol-1;i&gt;=0;i--){lcdChar(h[i] +&#039;0&#039;);} // преобразуем числа в char
  if(i_kol==0){lcdChar(&#039;0&#039;);} // если long = 0, то выводить ноль
  }
void lcdClear(){lcd(0b00000001);} 
 </code></pre></div><p>Для запоминания последней радиостанции при выключении и сбережения ресурса EEPROM&nbsp; ?<br /></p><div class="codebox"><pre><code>#include &lt;EEPROM.h&gt;
byte channel=EEPROM.read(0);
void setup() {
 MCUCR |= (1&lt;&lt;ISC10);//нисходящий фронт на ножке INT0
 GIMSK |= (1&lt;&lt;INT0); 
}
 
void loop() { 
    
}
ISR(INT0_vect){EEPROM.update(0,channel); } </code></pre></div><p>PD2 через резистивный делитель на нижнюю границу логической 1 ~2.7-3в. Запитка МК через диод шоттки с накопительным конденсатором к +5В. Для того, чтобы МК смог записать в память частоту станции. BOD на 1.8в.<br /><span class="postimg"><img src="http://forum.rcl-radio.ru/uploads/images/2025/04/72fc6acc3de4ed7a11b7a7c82de3b78e.bmp" alt="http://forum.rcl-radio.ru/uploads/images/2025/04/72fc6acc3de4ed7a11b7a7c82de3b78e.bmp" /></span><br /></p><div class="codebox"><pre><code>#include &lt;EEPROM.h&gt;
#include &lt;TinyWireM.h&gt; 
#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=EEPROM.read(0);
uint16_t reg02h, reg03h, reg05h,reg0Ah,reg0Bh;


void setup() {  
MCUCR |= (1&lt;&lt;ISC10);
GIMSK |= (1&lt;&lt;INT0);     
beginRda();  
myChangeVolume(volume);           
DDRD&amp;=~(1&lt;&lt;3)|(1&lt;&lt;4)|(1&lt;&lt;0)|(1&lt;&lt;1);
//PORTD|=(1&lt;&lt;3)|(1&lt;&lt;4);
lcdInit();
delay(700);
myChangeChannel(channel);
  }
 
void loop() {
     
   if (((PIND &gt;&gt; 0) &amp; 1) == 0){         
    SEEK(1);}     
       
   if (((PIND &gt;&gt; 1) &amp; 1) == 0){   
    SEEK(0); } 
          
 if (((PIND &gt;&gt; 3) &amp; 1) == 0){  //настройка частоты       
       channel++;
   
    myChangeChannel(channel);
    del(); }

   if (((PIND &gt;&gt; 4) &amp; 1) == 0){   
      channel--;       
    myChangeChannel(channel);
    del(); }
    
  channel = getFrequency();
  channel = constrain(channel,1,210);    
  reg0Bh = getRegister(REG_RSSI);
  uint8_t rssi = (reg0Bh &amp; RSSI_MASK) &gt;&gt; RSSI_SHIFT;   
  uint16_t frequency = channel+870;
  lcdCurs(0,0);
  if(rssi==1)lcdString(&quot;Station &quot;);
  else lcdString(&quot;Radio   &quot;);  
  lcdCurs(1,0);
  if(frequency/1000==0)lcdString(&quot; &quot;);
  lcdInt(frequency/10);lcdChar(&#039;.&#039;);lcdInt(frequency%10);
  lcdString(&quot; FM&quot;);
    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) &lt;&lt; CHAN_SHIFT; 
  setRegister(REG_TUNING, reg03h | FLG_TUNE);
  }
void myChangeVolume(byte volume) {
 reg05h = getRegister(REG_VOLUME); // Считываем текущее значение
  reg05h &amp;= ~VOLUME_MASK; // Сбрасываем биты VOLUME
  reg05h |= volume &lt;&lt; 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() &lt;&lt; 8;
  result |= TinyWireM.read();
  return result;
}
void SEEK(bool Direction) {
  reg02h = getRegister(REG_CONFIG);
  if (Direction)// Направление поиска
    reg02h |= 1 &lt;&lt; BIT_SEEKUP;
  else
    reg02h &amp;= ~(1 &lt;&lt; BIT_SEEKUP);
  reg02h |= 1 &lt;&lt; BIT_SEEKMODE;// Ищем до границы и останавливаемся на 108 или 88
  reg02h |= 1 &lt;&lt; BIT_SEEK;// Разрешаем начать поиск станции  
  do {                     // Ждем окончания настройки частоты
    reg0Ah = getRegister(REG_STATE);
  lcdCurs(0,0);
  lcdString(&quot;Loading.&quot;);
  lcdCurs(1,0);
  lcdString(&quot;...     &quot;); 
  } while (~reg0Ah &amp; (1 &lt;&lt; BIT_STC));
  setRegister(REG_CONFIG, reg02h);
}
uint16_t getFrequency () {
  do { // Ждем окончания настройки частоты
    reg0Ah = getRegister(REG_STATE);
  } while (~reg0Ah &amp; (1 &lt;&lt; BIT_STC));
  reg0Ah &amp;= 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 &lt;&lt; 6);} else{PORTD &amp;= ~(1 &lt;&lt; 6);}//RS
    del();
    if(((data &gt;&gt; 7) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 3);}else{PORTB &amp;= ~(1 &lt;&lt; 3);}
    if(((data &gt;&gt; 6) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 2);}else{PORTB &amp;= ~(1 &lt;&lt; 2);}
    if(((data &gt;&gt; 5) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 1);}else{PORTB &amp;= ~(1 &lt;&lt; 1);}
    if(((data &gt;&gt; 4) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 0);}else{PORTB &amp;= ~(1 &lt;&lt; 0);}
    e_pin();
    if(((data &gt;&gt; 3) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 3);}else{PORTB &amp;= ~(1 &lt;&lt; 3);}
    if(((data &gt;&gt; 2) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 2);}else{PORTB &amp;= ~(1 &lt;&lt; 2);}
    if(((data &gt;&gt; 1) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 1);}else{PORTB &amp;= ~(1 &lt;&lt; 1);}
    if(((data &gt;&gt; 0) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 0);}else{PORTB &amp;= ~(1 &lt;&lt; 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 != &#039;\0&#039;) {del();lcdChar(*str);str++;}}
void del(){delay(5);}
void e_pin(){PORTB |= (1 &lt;&lt; 4);del();PORTB &amp;= ~(1 &lt;&lt; 4);}
void lcdCurs(byte str, byte mesto){
  if(str==0){lcd(0b10000000+mesto);}
  if(str==1){lcd(0b11000000+mesto);}
  }
void lcdInit(){ 
    DDRB |= (1 &lt;&lt; 0) | (1 &lt;&lt; 1)| (1 &lt;&lt; 2) | (1 &lt;&lt; 3) | (1 &lt;&lt; 4);
    DDRD |= (1 &lt;&lt; 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&gt;0;i_kol++){x=x/10;}  // определяем кол-во цифр в long
  for(i=0;i&lt;i_kol;i++){h[i]=y%10; y=y/10;}// разбиваем число на отдельные цифры
  for(i=i_kol-1;i&gt;=0;i--){lcdChar(h[i] +&#039;0&#039;);} // преобразуем числа в char
  if(i_kol==0){lcdChar(&#039;0&#039;);} // если long = 0, то выводить ноль
  }
void lcdClear(){lcd(0b00000001);} 

ISR(INT0_vect){  EEPROM.update(0, channel);}</code></pre></div><p>Вариант с энкодером<br /></p><div class="codebox"><pre><code>#include &lt;EEPROM.h&gt;
#include &lt;TinyWireM.h&gt; 
#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 encoder
// PD4 encoder
// PD1,PD2 - автопоиск
uint8_t volume = 15; // 0..15
byte channel=EEPROM.read(0);
uint16_t reg02h, reg03h, reg05h,reg0Ah,reg0Bh;
volatile uint8_t _prevValueAB = 0;    
volatile uint8_t _currValueAB = 0;

void setup() {
  TCCR1A = 0;   
  TCCR1B = 0;   
  OCR1A = 1249; // 0.01 s
  TCCR1B |= (1 &lt;&lt; WGM12); 
  TCCR1B |= (1 &lt;&lt; CS11) | (1 &lt;&lt; CS10);  // 64  
  TIMSK |= (1 &lt;&lt; OCIE1A);     
MCUCR |= (1&lt;&lt;ISC10);
GIMSK |= (1&lt;&lt;INT0);     
beginRda();  
myChangeVolume(volume);           
DDRD&amp;=~(1&lt;&lt;3)|(1&lt;&lt;4)|(1&lt;&lt;0)|(1&lt;&lt;1);
//PORTD|=(1&lt;&lt;3)|(1&lt;&lt;4);
lcdInit();
delay(1000);
myChangeChannel(channel);
  }
 
void loop() {
     
   if (((PIND &gt;&gt; 0) &amp; 1) == 0){         
    SEEK(1);}     
       
   if (((PIND &gt;&gt; 1) &amp; 1) == 0){   
    SEEK(0); }       
     

  channel = getFrequency();
  reg0Bh = getRegister(REG_RSSI);
  uint8_t rssi = (reg0Bh &amp; RSSI_MASK) &gt;&gt; RSSI_SHIFT;   
  uint16_t frequency = channel+870;
  lcdCurs(0,0);
  if(rssi==1)lcdString(&quot;Station &quot;);
  else lcdString(&quot;Radio   &quot;);  
  lcdCurs(1,0);
  if(frequency/1000==0)lcdString(&quot; &quot;);
  lcdInt(frequency/10);lcdChar(&#039;.&#039;);lcdInt(frequency%10);
  lcdString(&quot; FM&quot;);
    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) &lt;&lt; CHAN_SHIFT; 
  setRegister(REG_TUNING, reg03h | FLG_TUNE);
  }
void myChangeVolume(byte volume) {
 reg05h = getRegister(REG_VOLUME); // Считываем текущее значение
  reg05h &amp;= ~VOLUME_MASK; // Сбрасываем биты VOLUME
  reg05h |= volume &lt;&lt; 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() &lt;&lt; 8;
  result |= TinyWireM.read();
  return result;
}
void SEEK(bool Direction) {
  reg02h = getRegister(REG_CONFIG);
  if (Direction)// Направление поиска
    reg02h |= 1 &lt;&lt; BIT_SEEKUP;
  else
    reg02h &amp;= ~(1 &lt;&lt; BIT_SEEKUP);
  reg02h |= 1 &lt;&lt; BIT_SEEKMODE;// Ищем до границы и останавливаемся на 108 или 88
  reg02h |= 1 &lt;&lt; BIT_SEEK;// Разрешаем начать поиск станции  
  do {                     // Ждем окончания настройки частоты
    reg0Ah = getRegister(REG_STATE);
  lcdCurs(0,0);
  lcdString(&quot;Loading.&quot;);
  lcdCurs(1,0);
  lcdString(&quot;...     &quot;); 
  } while (~reg0Ah &amp; (1 &lt;&lt; BIT_STC));
  setRegister(REG_CONFIG, reg02h);
}
uint16_t getFrequency () {
  do { // Ждем окончания настройки частоты
    reg0Ah = getRegister(REG_STATE);
  } while (~reg0Ah &amp; (1 &lt;&lt; BIT_STC));
  reg0Ah &amp;= 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 &lt;&lt; 6);} else{PORTD &amp;= ~(1 &lt;&lt; 6);}//RS
    del();
    if(((data &gt;&gt; 7) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 3);}else{PORTB &amp;= ~(1 &lt;&lt; 3);}
    if(((data &gt;&gt; 6) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 2);}else{PORTB &amp;= ~(1 &lt;&lt; 2);}
    if(((data &gt;&gt; 5) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 1);}else{PORTB &amp;= ~(1 &lt;&lt; 1);}
    if(((data &gt;&gt; 4) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 0);}else{PORTB &amp;= ~(1 &lt;&lt; 0);}
    e_pin();
    if(((data &gt;&gt; 3) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 3);}else{PORTB &amp;= ~(1 &lt;&lt; 3);}
    if(((data &gt;&gt; 2) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 2);}else{PORTB &amp;= ~(1 &lt;&lt; 2);}
    if(((data &gt;&gt; 1) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 1);}else{PORTB &amp;= ~(1 &lt;&lt; 1);}
    if(((data &gt;&gt; 0) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 0);}else{PORTB &amp;= ~(1 &lt;&lt; 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 != &#039;\0&#039;) {del();lcdChar(*str);str++;}}
void del(){delay(5);}
void e_pin(){PORTB |= (1 &lt;&lt; 4);del();PORTB &amp;= ~(1 &lt;&lt; 4);}
void lcdCurs(byte str, byte mesto){
  if(str==0){lcd(0b10000000+mesto);}
  if(str==1){lcd(0b11000000+mesto);}
  }
void lcdInit(){ 
    DDRB |= (1 &lt;&lt; 0) | (1 &lt;&lt; 1)| (1 &lt;&lt; 2) | (1 &lt;&lt; 3) | (1 &lt;&lt; 4);
    DDRD |= (1 &lt;&lt; 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&gt;0;i_kol++){x=x/10;}  // определяем кол-во цифр в long
  for(i=0;i&lt;i_kol;i++){h[i]=y%10; y=y/10;}// разбиваем число на отдельные цифры
  for(i=i_kol-1;i&gt;=0;i--){lcdChar(h[i] +&#039;0&#039;);} // преобразуем числа в char
  if(i_kol==0){lcdChar(&#039;0&#039;);} // если long = 0, то выводить ноль
  }
void lcdClear(){lcd(0b00000001);} 

ISR(INT0_vect){  EEPROM.update(0, channel);}
 ISR(TIMER1_COMPA_vect){
  bool pinA = (PIND &gt;&gt; 3) &amp; 1;   
  bool pinB = (PIND &gt;&gt; 4) &amp; 1;    
  _currValueAB  = pinA &lt;&lt; 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 &lt;&lt; 2;       
  }
  </code></pre></div>]]></description>
			<author><![CDATA[null@example.com (klause)]]></author>
			<pubDate>Mon, 24 Mar 2025 08:07:50 +0000</pubDate>
			<guid>http://forum.rcl-radio.ru/viewtopic.php?pid=11493#p11493</guid>
		</item>
		<item>
			<title><![CDATA[Re: ATTINY2313 + ARDUINO IDE]]></title>
			<link>http://forum.rcl-radio.ru/viewtopic.php?pid=11479#p11479</link>
			<description><![CDATA[<p>С регулировкой громкости.<br /></p><div class="codebox"><pre><code>#include &lt;EEPROM.h&gt;
#include &lt;TinyWireM.h&gt; 
#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&amp;=~(1&lt;&lt;3)|(1&lt;&lt;4)|(1&lt;&lt;0)|(1&lt;&lt;1);
//PORTD|=(1&lt;&lt;3)|(1&lt;&lt;4)|(1&lt;&lt;0)|(1&lt;&lt;1);// Pull-Up
lcdInit();
lcd(0x40); // запись символа в lcd
  for( byte i=0;i&lt;8;i++)lcdSend(0,customChar[i]);    
lcdCurs(0,0);
lcdSend(0,0);  
delay(500);
myChangeChannel(channel);
  }
 
void loop() {
   if (((PIND &gt;&gt; 0) &amp; 1) == 0){ // регулировка звука         
       volume++;flagV1=1;
    if(volume&gt;15)volume=15;   
    myChangeVolume(volume);
     del();}
  if(((PIND &gt;&gt; 0) &amp; 1)!= 0&amp;&amp;flagV1==1) //запись уровня звука после отпускания кнопки
   {EEPROM.update(1,volume);flagV1=0;}
    
   if (((PIND &gt;&gt; 1) &amp; 1) == 0){   
      volume--;flagV2=1;
    if (volume&lt;=1)volume=1;  
    myChangeVolume(volume);
    del(); }    
  if(((PIND &gt;&gt; 1) &amp; 1)!= 0&amp;&amp;flagV2==1) //запись уровня звука после отпускания кнопки
   {EEPROM.update(1,volume);flagV2=0;}
   
   if (((PIND &gt;&gt; 3) &amp; 1) == 0){  //настройка частоты       
       channel++;flag=0;flagCh1=1;
     if(channel&gt;210)channel=210;  
    myChangeChannel(channel);
    del(); }
  if(((PIND &gt;&gt; 3) &amp; 1)!= 0&amp;&amp;flagCh1==1)  //запись частоты после отпускания кнопки
   {EEPROM.update(0,channel);flagCh1=0;}
        
   if (((PIND &gt;&gt; 4) &amp; 1) == 0){   
      channel--;flag=0;flagCh2=1;
     if (channel&lt;=1)channel=1; 
    myChangeChannel(channel);
    del(); }
   if(((PIND &gt;&gt; 4) &amp; 1)!= 0&amp;&amp;flagCh2==1)  //запись частоты после отпускания кнопки
   {EEPROM.update(0,channel);flagCh2=0;}  

  reg0Bh = getRegister(REG_RSSI);
  uint8_t rssi = (reg0Bh &amp; RSSI_MASK) &gt;&gt; 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(&quot;St &quot;);
  if(rssi==1)lcdString(&quot;St &quot;);
  else if(flag==0&amp;&amp;rssi==0) lcdString(&quot;   &quot;);
  lcdCurs(1,0);
  if(frequency/1000==0)lcdString(&quot; &quot;);
  lcdInt(frequency/10);lcdChar(&#039;.&#039;);lcdInt(frequency%10);
  lcdString(&quot; FM&quot;);
    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) &lt;&lt; CHAN_SHIFT; 
  setRegister(REG_TUNING, reg03h | FLG_TUNE);
  }
void myChangeVolume(byte volume) {
  reg05h = getRegister(REG_VOLUME); // Считываем текущее значение
  reg05h &amp;= ~VOLUME_MASK; // Сбрасываем биты VOLUME
  reg05h |= volume &lt;&lt; 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() &lt;&lt; 8;
  result |= TinyWireM.read();
  return result;
}
/////////////////lcd//////////////////////////////////////////
void lcdSend(bool rs, byte data) {
    if(rs==0){PORTD |= (1 &lt;&lt; 6);} else{PORTD &amp;= ~(1 &lt;&lt; 6);}//RS
    del();
    if(((data &gt;&gt; 7) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 3);}else{PORTB &amp;= ~(1 &lt;&lt; 3);}
    if(((data &gt;&gt; 6) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 2);}else{PORTB &amp;= ~(1 &lt;&lt; 2);}
    if(((data &gt;&gt; 5) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 1);}else{PORTB &amp;= ~(1 &lt;&lt; 1);}
    if(((data &gt;&gt; 4) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 0);}else{PORTB &amp;= ~(1 &lt;&lt; 0);}
    e_pin();
    if(((data &gt;&gt; 3) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 3);}else{PORTB &amp;= ~(1 &lt;&lt; 3);}
    if(((data &gt;&gt; 2) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 2);}else{PORTB &amp;= ~(1 &lt;&lt; 2);}
    if(((data &gt;&gt; 1) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 1);}else{PORTB &amp;= ~(1 &lt;&lt; 1);}
    if(((data &gt;&gt; 0) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 0);}else{PORTB &amp;= ~(1 &lt;&lt; 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 != &#039;\0&#039;) {del();lcdChar(*str);str++;}}
void del(){delay(5);}
void e_pin(){PORTB |= (1 &lt;&lt; 4);del();PORTB &amp;= ~(1 &lt;&lt; 4);}
void lcdCurs(byte str, byte mesto){
  if(str==0){lcd(0b10000000+mesto);}
  if(str==1){lcd(0b11000000+mesto);}
  }
void lcdInit(){ 
    DDRB |= (1 &lt;&lt; 0) | (1 &lt;&lt; 1)| (1 &lt;&lt; 2) | (1 &lt;&lt; 3) | (1 &lt;&lt; 4);
    DDRD |= (1 &lt;&lt; 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&gt;0;i_kol++){x=x/10;}  // определяем кол-во цифр в long
  for(i=0;i&lt;i_kol;i++){h[i]=y%10; y=y/10;}// разбиваем число на отдельные цифры
  for(i=i_kol-1;i&gt;=0;i--){lcdChar(h[i] +&#039;0&#039;);} // преобразуем числа в char
  if(i_kol==0){lcdChar(&#039;0&#039;);} // если long = 0, то выводить ноль
  }
void lcdClear(){lcd(0b00000001);}</code></pre></div><p><span class="postimg"><img src="http://forum.rcl-radio.ru/uploads/images/2025/03/c66e18e056605769be630137250eaf2f.jpg" alt="http://forum.rcl-radio.ru/uploads/images/2025/03/c66e18e056605769be630137250eaf2f.jpg" /></span></p>]]></description>
			<author><![CDATA[null@example.com (klause)]]></author>
			<pubDate>Wed, 19 Mar 2025 10:54:47 +0000</pubDate>
			<guid>http://forum.rcl-radio.ru/viewtopic.php?pid=11479#p11479</guid>
		</item>
		<item>
			<title><![CDATA[Re: ATTINY2313 + ARDUINO IDE]]></title>
			<link>http://forum.rcl-radio.ru/viewtopic.php?pid=11475#p11475</link>
			<description><![CDATA[<p>+RDA5807+Lcd1601.Настройка частоты кнопками. В настройках платы убрать millis()чтобы скетч вместился.<br /></p><div class="codebox"><pre><code>//#include &lt;EEPROM.h&gt;
#include &lt;TinyWireM.h&gt; 
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 &gt;&gt; 2),    
   ((channel &amp; 0b11) &lt;&lt; 6 ) | 0b00010000
   
};



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

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


void myChangeChannel(int channel){ /* void if nothing is returned else int */
  
   tune_config[2] = (channel &gt;&gt; 2); 
   tune_config[3] = ((channel &amp; 0b11) &lt;&lt; 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 &lt;&lt; 6);} else{PORTD &amp;= ~(1 &lt;&lt; 6);}//RS
    del();
    if(((data &gt;&gt; 7) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 3);}else{PORTB &amp;= ~(1 &lt;&lt; 3);}
    if(((data &gt;&gt; 6) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 2);}else{PORTB &amp;= ~(1 &lt;&lt; 2);}
    if(((data &gt;&gt; 5) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 1);}else{PORTB &amp;= ~(1 &lt;&lt; 1);}
    if(((data &gt;&gt; 4) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 0);}else{PORTB &amp;= ~(1 &lt;&lt; 0);}
    e_pin();
    if(((data &gt;&gt; 3) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 3);}else{PORTB &amp;= ~(1 &lt;&lt; 3);}
    if(((data &gt;&gt; 2) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 2);}else{PORTB &amp;= ~(1 &lt;&lt; 2);}
    if(((data &gt;&gt; 1) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 1);}else{PORTB &amp;= ~(1 &lt;&lt; 1);}
    if(((data &gt;&gt; 0) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 0);}else{PORTB &amp;= ~(1 &lt;&lt; 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 != &#039;\0&#039;) {del();lcdChar(*str);str++;}}
void del(){delay(5);}
void e_pin(){PORTB |= (1 &lt;&lt; 4);del();PORTB &amp;= ~(1 &lt;&lt; 4);}
void lcdCurs(byte str, byte mesto){
  if(str==0){lcd(0b10000000+mesto);}
  if(str==1){lcd(0b11000000+mesto);}
  }
void lcdInit(){ 
    DDRB |= (1 &lt;&lt; 0) | (1 &lt;&lt; 1)| (1 &lt;&lt; 2) | (1 &lt;&lt; 3) | (1 &lt;&lt; 4);
    DDRD |= (1 &lt;&lt; 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&gt;0;i_kol++){x=x/10;}  // определяем кол-во цифр в long
  for(i=0;i&lt;i_kol;i++){h[i]=y%10; y=y/10;}// разбиваем число на отдельные цифры
  for(i=i_kol-1;i&gt;=0;i--){lcdChar(h[i] +&#039;0&#039;);} // преобразуем числа в char
  if(i_kol==0){lcdChar(&#039;0&#039;);} // если long = 0, то выводить ноль
  }
void lcdClear(){lcd(0b00000001);} 
 
 </code></pre></div><p><span class="attention-yellow"></span> <span class="postimg"><img src="http://forum.rcl-radio.ru/uploads/images/2025/03/8e93766ca4f645b3f9f3202f5d81799c.jpg" alt="http://forum.rcl-radio.ru/uploads/images/2025/03/8e93766ca4f645b3f9f3202f5d81799c.jpg" /></span><br />Вариант с энкодером<br /></p><div class="codebox"><pre><code>#include &lt;TinyWireM.h&gt; 
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 &gt;&gt; 2),    
   ((channel &amp; 0b11) &lt;&lt; 6 ) | 0b00010000
   
};



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


void myChangeChannel(int channel){ /* void if nothing is returned else int */
  
   tune_config[2] = (channel &gt;&gt; 2); 
   tune_config[3] = ((channel &amp; 0b11) &lt;&lt; 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 &lt;&lt; 6);} else{PORTD &amp;= ~(1 &lt;&lt; 6);}//RS
    del();
    if(((data &gt;&gt; 7) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 3);}else{PORTB &amp;= ~(1 &lt;&lt; 3);}
    if(((data &gt;&gt; 6) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 2);}else{PORTB &amp;= ~(1 &lt;&lt; 2);}
    if(((data &gt;&gt; 5) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 1);}else{PORTB &amp;= ~(1 &lt;&lt; 1);}
    if(((data &gt;&gt; 4) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 0);}else{PORTB &amp;= ~(1 &lt;&lt; 0);}
    e_pin();
    if(((data &gt;&gt; 3) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 3);}else{PORTB &amp;= ~(1 &lt;&lt; 3);}
    if(((data &gt;&gt; 2) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 2);}else{PORTB &amp;= ~(1 &lt;&lt; 2);}
    if(((data &gt;&gt; 1) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 1);}else{PORTB &amp;= ~(1 &lt;&lt; 1);}
    if(((data &gt;&gt; 0) &amp; 1) ==1){PORTB |= (1 &lt;&lt; 0);}else{PORTB &amp;= ~(1 &lt;&lt; 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 != &#039;\0&#039;) {del();lcdChar(*str);str++;}}
void del(){delay(5);}
void e_pin(){PORTB |= (1 &lt;&lt; 4);del();PORTB &amp;= ~(1 &lt;&lt; 4);}
void lcdCurs(byte str, byte mesto){
  if(str==0){lcd(0b10000000+mesto);}
  if(str==1){lcd(0b11000000+mesto);}
  }
void lcdInit(){ 
    DDRB |= (1 &lt;&lt; 0) | (1 &lt;&lt; 1)| (1 &lt;&lt; 2) | (1 &lt;&lt; 3) | (1 &lt;&lt; 4);
    DDRD |= (1 &lt;&lt; 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&gt;0;i_kol++){x=x/10;}  // определяем кол-во цифр в long
  for(i=0;i&lt;i_kol;i++){h[i]=y%10; y=y/10;}// разбиваем число на отдельные цифры
  for(i=i_kol-1;i&gt;=0;i--){lcdChar(h[i] +&#039;0&#039;);} // преобразуем числа в char
  if(i_kol==0){lcdChar(&#039;0&#039;);} // если long = 0, то выводить ноль
  }
void lcdClear(){lcd(0b00000001);} 
 ISR(TIMER1_COMPA_vect){
  bool pinA = (PIND &gt;&gt; 3) &amp; 1;   
  bool pinB = (PIND &gt;&gt; 4) &amp; 1;    
  _currValueAB  = pinA &lt;&lt; 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 &lt;&lt; 2;       
  }</code></pre></div>]]></description>
			<author><![CDATA[null@example.com (klause)]]></author>
			<pubDate>Mon, 17 Mar 2025 07:02:04 +0000</pubDate>
			<guid>http://forum.rcl-radio.ru/viewtopic.php?pid=11475#p11475</guid>
		</item>
		<item>
			<title><![CDATA[Re: ATTINY2313 + ARDUINO IDE]]></title>
			<link>http://forum.rcl-radio.ru/viewtopic.php?pid=11436#p11436</link>
			<description><![CDATA[<p>На сайте есть статья ATtiny2313 + LCD1602 (Arduino IDE). <br />Дополнение к скетчу. Прорисовка своих символов до 8шт.<br />Кусочек кода.<br /></p><div class="codebox"><pre><code>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&lt;8;i++)lcdSend(0,smile[i]);
  lcd(0x40+8);
  for( byte i=0;i&lt;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);
}

///////////////////////////////////////////////////////////////////////////////////////////</code></pre></div>]]></description>
			<author><![CDATA[null@example.com (klause)]]></author>
			<pubDate>Thu, 27 Feb 2025 11:45:38 +0000</pubDate>
			<guid>http://forum.rcl-radio.ru/viewtopic.php?pid=11436#p11436</guid>
		</item>
		<item>
			<title><![CDATA[Re: ATTINY2313 + ARDUINO IDE]]></title>
			<link>http://forum.rcl-radio.ru/viewtopic.php?pid=11434#p11434</link>
			<description><![CDATA[<p>Поверка подключения usart на скорости 9600. Внутренний кварц на 8Мгц. <br /></p><div class="codebox"><pre><code>unsigned char USART_Receive( void ); //Функция приема данных по протоколу USART
void USART_Transmit( unsigned char data ); //Функция передачи данных по протоколу USART

int main( void )
{
UBRRL = 51;

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

UCSRC = (1 &lt;&lt; UCSZ1) | (1 &lt;&lt; UCSZ0); 
for (;;) 
{

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

}
}

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

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

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

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

}</code></pre></div><p>Работает через переходник USB-Uart. В мониторе порта отправленные данные возвращаются.</p>]]></description>
			<author><![CDATA[null@example.com (klause)]]></author>
			<pubDate>Wed, 26 Feb 2025 12:25:19 +0000</pubDate>
			<guid>http://forum.rcl-radio.ru/viewtopic.php?pid=11434#p11434</guid>
		</item>
		<item>
			<title><![CDATA[Re: ATTINY2313 + ARDUINO IDE]]></title>
			<link>http://forum.rcl-radio.ru/viewtopic.php?pid=11419#p11419</link>
			<description><![CDATA[<p>+DHT11. Индикатор от АОНа запитан через ULN2803. Работает плавное гашение индикатора и показания температуры(влажности) с &quot;эффектом волны&quot; .&nbsp; &nbsp;<br /></p><div class="codebox"><pre><code>#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&gt;3000){
 for(byte i=0;i&lt;8;i++){ Buffer[i]=10;Delay();}
 delay(1000);
 dht_read(&amp;_hum, &amp;_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&lt;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&lt;&lt;DHT);
  delay(18); 
  DDRD&amp;=~(1&lt;&lt;DHT); 
  delayMicroseconds(40);
  if (PIND&amp;(1&lt;&lt;DHT)) return 1; 
  delayMicroseconds(80); 
  if (!(PIND&amp;(1&lt;&lt;DHT))) return 2; 
  while(PIND&amp;(1&lt;&lt;DHT));
  return 0;
}
byte dht_byte(){
  byte i=8, byte=0;
  while(i--){
    while(!(PIND&amp;(1&lt;&lt;DHT)));
    delayMicroseconds(40);
    if (PIND&amp;(1&lt;&lt;DHT)) {
      byte|=(1&lt;&lt;i);
      while(PIND&amp;(1&lt;&lt;DHT));
    }
  }
  return byte;
}</code></pre></div><p><span class="postimg"><img src="http://forum.rcl-radio.ru/uploads/images/2025/02/32c4675c3cc20aa945426585107f6a8f.jpg" alt="http://forum.rcl-radio.ru/uploads/images/2025/02/32c4675c3cc20aa945426585107f6a8f.jpg" /></span></p><p>DS18b20<br /></p><div class="codebox"><pre><code>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&lt;&lt;WGM10;
  TCCR1B = 1&lt;&lt;WGM12 | 2&lt;&lt;CS10;  
  OCR1A = 499;                          
  TIMSK = TIMSK | 1&lt;&lt;OCIE1A ; 
  
}


void loop() {
  
 if(millis()-Alarm&gt;1000){ 
  temp=read_temp();
   delay(50);
  Alarm=millis();
  }             
  if(temp&lt;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 &amp;= ~(1 &lt;&lt; OUT);
    DDRD |= (1 &lt;&lt; OUT);
   
    delayMicroseconds(480);  
    DDRD &amp;= ~(1 &lt;&lt; OUT);
 
    delayMicroseconds(60);
    i=((PIND &gt;&gt; OUT) &amp; 1);

    delayMicroseconds(420);
    
    return i;
}
// write bit
void therm_write_bit(uint8_t bit){
    PORTD &amp;= ~(1 &lt;&lt; OUT);
    DDRD |= (1 &lt;&lt; OUT);
   delayMicroseconds(1);
    if(bit) DDRD &amp;= ~(1 &lt;&lt; OUT);
    delayMicroseconds(60);
    DDRD &amp;= ~(1 &lt;&lt; OUT);
}
// read bit
uint8_t therm_read_bit(void){
    uint8_t bit=0;
    PORTD &amp;= ~(1 &lt;&lt; OUT);
    DDRD |= (1 &lt;&lt; OUT);
  delayMicroseconds(1);
    DDRD &amp;= ~(1 &lt;&lt; OUT);
    delayMicroseconds(14);
    if(PIND &amp; (1 &lt;&lt; OUT)) bit=1;
    delayMicroseconds(45);
    return bit;
}
 
// read byte
uint8_t therm_read_byte(void){
    uint8_t i=8, n=0;
    while(i--){n&gt;&gt;=1;n|=(therm_read_bit()&lt;&lt;7);}
    return n;
}
 
// write byte
void therm_write_byte(uint8_t byte){
    uint8_t i=8;
    while(i--){therm_write_bit(byte&amp;1);byte &gt;&gt;= 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] &lt;&lt; 8 | temperature[0])*10/16;
    return (int)temper;
}

  </code></pre></div>]]></description>
			<author><![CDATA[null@example.com (klause)]]></author>
			<pubDate>Sat, 22 Feb 2025 05:48:59 +0000</pubDate>
			<guid>http://forum.rcl-radio.ru/viewtopic.php?pid=11419#p11419</guid>
		</item>
		<item>
			<title><![CDATA[Re: ATTINY2313 + ARDUINO IDE]]></title>
			<link>http://forum.rcl-radio.ru/viewtopic.php?pid=11303#p11303</link>
			<description><![CDATA[<p>Другой вариант часов. Индикатор с общим катодом. Сегменты -PORTB.Разряды цифр PD2-PD5 через резисторы 220 Ом. Кнопка коррекции PD0. Внешний кварц на 8МГц.</p><div class="codebox"><pre><code>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 &amp;&amp; Char == 0) Char = 10; // delete zero
  if (Digit == 1)segs= CharMap[Char]|Point;
  else segs = CharMap[Char];
  DDRB = DDRB &amp; 0x00;                  // B7-B0 all inputs
  PORTB = PORTB | segs;                 // 1 = high
  DDRB = DDRB | segs;                   // 1 = output
}

void SetTime() {
  int Speed = 2000;
  if ((PIND &amp; 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&gt;=0; p--) {
      char temp = Buffer[p] + Carry;
      Buffer[p] = temp % Size[p];
      Carry = temp / Size[p];
      if (Buffer[0]==2 &amp;&amp; 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&lt;&lt;WGM10;
  TCCR1B = 1&lt;&lt;WGM12 | 2&lt;&lt;CS10;           // Divide by 8
  OCR1A = 499;                           // Compare match at 2000Hz
  OCR1B = 0;                           // Brightness; reduce for brighter min=480 max=0
  TIMSK = TIMSK | 1&lt;&lt;OCIE1A | 1&lt;&lt;OCIE1B; // Compare match interrupt enable
}

// All done under interrupt!
void loop() {
}</code></pre></div><p>+DS3231. Внутренний кварц на 8Мгц. Кнопки коррекции PDO - часы,PD1 - минуты<br /></p><div class="codebox"><pre><code>#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 &amp;&amp; Char == 0) Char = 10; // delete zero
  if (Digit == 1)segs= CharMap[Char]|Point;
  else segs = CharMap[Char];
  DDRB = DDRB &amp; 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&lt;&lt;WGM10;
  TCCR1B = 1&lt;&lt;WGM12 | 2&lt;&lt;CS10;           // Divide by 8
  OCR1A = 499;                           // Compare match at 2000Hz
  OCR1B = 0;                           // Brightness; reduce for brighter min=480 max=0
  TIMSK = TIMSK | 1&lt;&lt;OCIE1A | 1&lt;&lt;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&amp;&amp;millis()-debonce&gt;300) 
        {hour++; 
         if (hour &gt; 23) hour = 0;
         ds_write(0x02,(hour/10&lt;&lt;4)+hour%10);
         debonce= millis(); 
        }
    if (digitalRead(1) == 0&amp;&amp;millis()-debonce&gt;300) 
        {min++;
         if (min &gt; 59) min = 0;
        ds_write(0x01,(min/10&lt;&lt;4)+min%10);
         debonce= millis(); 
        } 
  if(millis()-Alarm&gt;1000){
  Point= Point^0x80; Alarm=millis();
  }
}
bool i2c_read_bit() {
    bool i2c_bit = 1;        
    DDRA &amp;= ~(1 &lt;&lt; SDA);            
    delayMicroseconds(10); 
    DDRA &amp;= ~(1 &lt;&lt; SCL);                
    if((PINA &gt;&gt; SDA) &amp; 1) i2c_bit=0;                            
    delayMicroseconds(10);  
    DDRA |= (1 &lt;&lt; SCL);              
    return i2c_bit;  
}
 
byte i2c_write_byte(byte data){
    for (byte i=0; i&lt;8; i++){i2c_write_bit((data&amp;0x80)==0);data&lt;&lt;=1;}    
    return i2c_read_bit(); 
}
 
byte i2c_read_byte(byte a){
    byte i, data=0;                
    for(i=0; i&lt;8; i++){if (!i2c_read_bit()) data++;if(i!=7) data&lt;&lt;=1;}        
    i2c_write_bit(a);return data;  
}
 
void i2c_write_bit(byte b){
    delayMicroseconds(5);
    if(b){DDRA |= (1 &lt;&lt; SDA);}else{DDRA &amp;= ~(1 &lt;&lt; SDA);}
    delayMicroseconds(5);
    DDRA &amp;= ~(1 &lt;&lt; SCL);       
    delayMicroseconds(10);
    DDRA |= (1 &lt;&lt; SCL);
}
 
void i2c_start(){
     delayMicroseconds(10);  
     DDRA &amp;= ~(1 &lt;&lt; SDA); DDRA &amp;= ~(1 &lt;&lt; SCL); 
     delayMicroseconds(10); 
     DDRA |= (1 &lt;&lt; SDA);  PORTA &amp;= ~(1 &lt;&lt; SDA);
     delayMicroseconds(10); 
     DDRA |= (1 &lt;&lt; SCL);  PORTA &amp;= ~(1 &lt;&lt; SCL);   
     delayMicroseconds(10);
}
 
void i2c_stop()  {
     DDRA |= (1 &lt;&lt; SDA);            
     delayMicroseconds(10);
     DDRA &amp;= ~(1 &lt;&lt; SCL);               
     delayMicroseconds(10); 
     DDRA &amp;= ~(1 &lt;&lt; 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&lt;&lt;4)+second%10);
    ds_write(0x01,(minute/10&lt;&lt;4)+minute%10);
    ds_write(0x02,(hours/10&lt;&lt;4)+hours%10);

  }
void read_time(){  
min =  (ds_read(1) &amp; 0x0F) + (((ds_read(1) &amp; 0x70) &gt;&gt; 4) * 10);
hour = (ds_read(2) &amp; 0x0F) + (((ds_read(2) &amp; 0x70) &gt;&gt; 4) * 10);
       
  } </code></pre></div><p>GPS часы без учета часового пояса.<br /></p><div class="codebox"><pre><code>// 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  &#039;-&#039;
  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&#039;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&lt;charArrayLen; i++) {
    segs = charArray[i];
    newsegs = 0;
    for (int i=0; i&lt;8; i++) {
      newsegs = newsegs | ((segs &amp; 1)&lt;&lt;Segments[i]);
      segs = segs &gt;&gt; 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&lt;&lt;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&gt;9999) { j=10000; dp=2; }
  else { j=1000; dp=1; }
  for (int d=0; d&lt;4 ; d++) {
    int i = (number/j) % 10;
    if (!i &amp;&amp; !dig &amp;&amp; j&gt;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 =
           &quot;$GPRMC,dddtdd.ddm,A,????.????,?,?????.????,?,djdk,???.??,??????,,,?*??&quot;;

int state = 0;
unsigned int temp;

// GPS variables
volatile unsigned int Time;


void ParseGPS (char c) {
  if (c == &#039;$&#039;) { state = 0; temp = 0; }
  uint8_t mode = pgm_read_byte_near(fmt + state++);
  // If received character matches format string, or format is &#039;?&#039; - return
  if ((mode == c) || (mode == &#039;?&#039;)) return;
  // d=decimal digit
  uint8_t d = c - &#039;0&#039;;
  if (mode == &#039;d&#039;) temp = temp*10 + d;
  // t=Time - hhmm
  else if (mode == &#039;t&#039;) { 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&lt;&lt;WGM10;
  TCCR1B = 1&lt;&lt;WGM12 | 2&lt;&lt;CS10;  // Divide by 8
  OCR1A = 4999;                 // Compare match at 200Hz
  TIMSK |= 1&lt;&lt;OCIE1A;           // Compare match interrupt enable
  // Set up USART
  UCSRB = 1&lt;&lt;RXEN | 1&lt;&lt;RXCIE;   // Enable Rx and interrupt
  UCSRC = 3&lt;&lt;UCSZ0;             // 8-bit UART mode
  UBRRL = 51;                   // 9600 baud
}

void loop() {
  unsigned int temp; 
  cli(); temp = Time; sei();
  Display(temp);
  
}</code></pre></div>]]></description>
			<author><![CDATA[null@example.com (klause)]]></author>
			<pubDate>Wed, 29 Jan 2025 10:04:17 +0000</pubDate>
			<guid>http://forum.rcl-radio.ru/viewtopic.php?pid=11303#p11303</guid>
		</item>
		<item>
			<title><![CDATA[Re: ATTINY2313 + ARDUINO IDE]]></title>
			<link>http://forum.rcl-radio.ru/viewtopic.php?pid=7760#p7760</link>
			<description><![CDATA[<p>Если можно, ещё спрошу. Мне надо, чтобы при определенном событии, счет времени останавливался и индикатор показывал остановленное время. Сделал так:<br />ISR(TIMER1_COMPA_vect){<br />&nbsp; &nbsp; &nbsp;i1++;<br />&nbsp; &nbsp; &nbsp;if(detect == 0){i++;} // при detect не равном 0, счет останавливается<br />&nbsp; &nbsp; &nbsp;if(i1 &gt; 9) {i1 = 0;}<br />&nbsp; &nbsp; &nbsp;if(i &gt; 599){mm++; i = 0;}<br />&nbsp; &nbsp; &nbsp;if(mm &gt; 59){hh++; mm = 0;}<br />&nbsp; &nbsp; &nbsp;if(hh &gt; 23){hh = 0;}<br />Однако это почему то не работает и счет продолжается. Что не так?</p>]]></description>
			<author><![CDATA[null@example.com (selan61)]]></author>
			<pubDate>Wed, 19 Apr 2023 05:19:07 +0000</pubDate>
			<guid>http://forum.rcl-radio.ru/viewtopic.php?pid=7760#p7760</guid>
		</item>
		<item>
			<title><![CDATA[Re: ATTINY2313 + ARDUINO IDE]]></title>
			<link>http://forum.rcl-radio.ru/viewtopic.php?pid=7720#p7720</link>
			<description><![CDATA[<div class="quotebox"><cite>liman324 пишет:</cite><blockquote><p>Надо менять настройки таймера Т1 под свою частоту:</p><p>Надо получить 100 мс</p><p>если CS11 и CS10 единицы, то у Вас делитель 64</p><p>значит</p><p>(8000000/((12499+1)x64))=10 Hz</p><p>OCR1A должно быть равно 12499</p></blockquote></div><p> Спасибо за ответ. Но меня смутило, что у вас в комментариях к скетчу написано<br /></p><div class="quotebox"><blockquote><p>TCCR1B |= (1 &lt;&lt; CS11) | (1 &lt;&lt; CS10);&nbsp; // 256</p></blockquote></div><p>Я понял что это делитель 256 и опираясь на это не мог пересчитать. А по даташиту действительно получается 64.</p>]]></description>
			<author><![CDATA[null@example.com (selan61)]]></author>
			<pubDate>Sat, 08 Apr 2023 12:32:42 +0000</pubDate>
			<guid>http://forum.rcl-radio.ru/viewtopic.php?pid=7720#p7720</guid>
		</item>
		<item>
			<title><![CDATA[Re: ATTINY2313 + ARDUINO IDE]]></title>
			<link>http://forum.rcl-radio.ru/viewtopic.php?pid=7719#p7719</link>
			<description><![CDATA[<p>Надо менять настройки таймера Т1 под свою частоту:</p><p>&nbsp; TCCR1A = 0;&nbsp; &nbsp;<br />&nbsp; TCCR1B = 0;&nbsp; &nbsp;<br />&nbsp; OCR1A = 18750; // 0.1 s<br />&nbsp; TCCR1B |= (1 &lt;&lt; WGM12); <br />&nbsp; TCCR1B |= (1 &lt;&lt; CS11) | (1 &lt;&lt; CS10);&nbsp; </p><br /><p>Надо получить 100 мс</p><p>если CS11 и CS10 единицы, то исходя из даташита</p><p><span class="postimg"><img src="http://forum.rcl-radio.ru/uploads/images/2023/04/b70c643acf78667f5c4e369f81d4d580.png" alt="http://forum.rcl-radio.ru/uploads/images/2023/04/b70c643acf78667f5c4e369f81d4d580.png" /></span> </p><p>у Вас делитель 64</p><p>значит</p><p>(8000000/((12499+1)x64))=10 Hz</p><p>OCR1A должно быть равно 12499</p>]]></description>
			<author><![CDATA[null@example.com (liman324)]]></author>
			<pubDate>Sat, 08 Apr 2023 08:54:55 +0000</pubDate>
			<guid>http://forum.rcl-radio.ru/viewtopic.php?pid=7719#p7719</guid>
		</item>
		<item>
			<title><![CDATA[Re: ATTINY2313 + ARDUINO IDE]]></title>
			<link>http://forum.rcl-radio.ru/viewtopic.php?pid=7718#p7718</link>
			<description><![CDATA[<p>Собрал на 2313а, без кварца. Версия ATTinyCore 1.5.2. При первой прошивке получил ошибку &quot;avrdude: AVR Part &quot;attiny2313a&quot; not found.&quot; Почитал интернет, исправил в avrdude.conf - attiny2313 на attiny2313a. Заработало. Прошивал для пробы 8MHz(internal).<br />Кварца 12МГц нет. Часы сильно отстают. Подскажите, каким образом часы зависят от частоты? Мне кажется, тайминги должны быть приблизительно одинаковы при любой частоте. Просто с внешним кварцем, часы идут точнее, например за сутки, а с внутренним немного убегать. А у меня, за час, убегают минут на 15. Странно это.</p>]]></description>
			<author><![CDATA[null@example.com (selan61)]]></author>
			<pubDate>Sat, 08 Apr 2023 08:41:20 +0000</pubDate>
			<guid>http://forum.rcl-radio.ru/viewtopic.php?pid=7718#p7718</guid>
		</item>
		<item>
			<title><![CDATA[Re: ATTINY2313 + ARDUINO IDE]]></title>
			<link>http://forum.rcl-radio.ru/viewtopic.php?pid=7612#p7612</link>
			<description><![CDATA[<p>Порт B весь как вход, установить подтягивающие резисторы на входах PB2 PB3</p>]]></description>
			<author><![CDATA[null@example.com (liman324)]]></author>
			<pubDate>Sun, 26 Mar 2023 14:13:38 +0000</pubDate>
			<guid>http://forum.rcl-radio.ru/viewtopic.php?pid=7612#p7612</guid>
		</item>
		<item>
			<title><![CDATA[Re: ATTINY2313 + ARDUINO IDE]]></title>
			<link>http://forum.rcl-radio.ru/viewtopic.php?pid=7611#p7611</link>
			<description><![CDATA[<div class="quotebox"><cite>liman324 пишет:</cite><blockquote><p>часы<br /></p><div class="codebox"><pre><code>void setup() {
  DDRB = 0b00000000; 
  PORTB |= (1 &lt;&lt; 2) | (1 &lt;&lt; 3);
 </code></pre></div></blockquote></div><p>А что эти строчки означают? В них нет ошибки, раз используются PB0 и PB1? <br />И можно использовать скетч без кварца?</p>]]></description>
			<author><![CDATA[null@example.com (selan61)]]></author>
			<pubDate>Sun, 26 Mar 2023 14:12:10 +0000</pubDate>
			<guid>http://forum.rcl-radio.ru/viewtopic.php?pid=7611#p7611</guid>
		</item>
		<item>
			<title><![CDATA[Re: ATTINY2313 + ARDUINO IDE]]></title>
			<link>http://forum.rcl-radio.ru/viewtopic.php?pid=3210#p3210</link>
			<description><![CDATA[<div class="quotebox"><blockquote><p>Хотел узнать тайну , почему версия библиотеки 2313&nbsp; не последняя ?</p></blockquote></div><p>На последней не шьется<br /></p><div class="quotebox"><blockquote><p>И схема часов attiny2313 и lcd1602 как упростить под i2c ?</p></blockquote></div><p>Очень сложно, я не смогу сделать</p>]]></description>
			<author><![CDATA[null@example.com (liman324)]]></author>
			<pubDate>Mon, 08 Mar 2021 02:38:53 +0000</pubDate>
			<guid>http://forum.rcl-radio.ru/viewtopic.php?pid=3210#p3210</guid>
		</item>
	</channel>
</rss>
