ATMega48上的时钟故障

发光的LCD显示屏和ATMega48超微电路上的优秀手表。 但是他们没有解决。



UPD :克罗恩(Crohn)死亡,切断两条电线,施加睡眠,0.3-1.6mA


也就是说,手表当然可以工作,但是,可惜它们不会长期工作。


曾几何时,在遥远的床头柜上的一个盒子里,我挂了几个七段液晶显示器。 就在不久前,我想让它们流通,并根据其中一个制作手表。 从前:从字面上看,这是七年。 到了2011年,我开始对电子学产生兴趣。 不用长时间思考,我就在一家不错的在线商店订购了各种东西(不,不在阿里;我不确定他当时已经在那儿了)。 但是以某种方式,对我来说创造永恒是没有用的。 在刻蚀了几张木板之后,我放弃了这种娱乐并忘记了。


因此,当Ali收到一个包含模型的包装,一个浸入盒中的595包,ds1307上的Tiny RTC以及最重要的USBasp时 ,就该回到旧的观念了。 在旧的存储库中,我有一个ATMega48 ,它有28条腿,即lm7805 ,所有小东西都是电阻器,电容器/按钮,实际上还有40条腿的指示器。


一般而言,最初计划使用AtTiny13,我也可以使用它,但是通过这种方式进行了估算,但我不知道如何用5条腿走动以显示指示器,读取两个按钮并与i2c时钟通讯。 拥有28个巨型腿,不再需要通过腿的结合来保存和变形。 尽管在这种情况下当然不能没有595。 但是,如果我计划串联输出来自青少年的指示器的所有32位数据,那么使用mega,您可以一次在所有四个微电路上显示图片。



所有595均隐藏在指示器下方。 照片显示了微电路外壳的结论。


595恰好使用了四块,因为该指标虽然有40条腿,但在段上只显示32条;可惜,它只有3.5条指标,也就是说,它有3位全数字,再加上一位。 有秒的符号,但没有AM / PM的名称。 但是确实有。 如果我一生中没有在LCD指示器中收集任何东西,我就不想订购更高级的指示器。



指标的工作文件。 测试人员必须找出哪条腿对应于哪段。


好吧,那是技术问题。 从来没有一个计划,但在那里一切都是显而易见的。 只需选择四个脚来输入缓冲器,一个公共脚用于指示器,一个脚用于SCLK / RCLK,一个脚用于OE,两个脚用于i2c,两个脚用于按钮。 当然,所有这些都是错误的。 为什么我决定在控制器上安装OE,并把SCLK和RCLK结合在一起-我自己不记得它了。 有必要做相反的事情。 而且根本不需要控制器上的通用指示器线,可以省去第595个结论中的一个(最后我也做了)。



电线。 很多。 内部视图。



从外面看。


在此项目中,最有趣的是:指标的输出代码。 精妙之处在于,您不能只是将电压施加到LCD指示器上而忘了它。 有必要每秒大约改变一百次,以改变各部分和公共触点之间的极性,以使一切都变得美丽而悦目。 作为开发环境,事不宜迟,我使用了Arduino IDE,在几点上只有一点点折磨。 首先,我必须使用MiniCore软件包( https://github.com/MCUdude/MiniCore ),因为我不必写大型的现成的arduino,而是写虚弱的ATMega48。 其次,直接尝试将内置库用于i2c失败。 由于某种原因,它不想工作,我不得不找到另一个库,然后根据需要对其进行修剪。


事实证明,4 KB很小。 尤其是如果您使用C语言编写。也许如果我决定改用汇编程序,那么此限制可能不会受到那么严重的影响,但是回想起我过去为AVR编写汇编程序时所摘录的部分,我并没有这样的愿望。 而用C编写-需要大量空间。 我无意中放了一个小括号-管道中有一百个字节。


实际注释的代码
#include <avr/io.h>
#include <util/delay.h>
#include <avr/power.h>

#define cbi(sfr, bit)   (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit)   (_SFR_BYTE(sfr) |= _BV(bit))

//      ds1307,    
#define DS3231_I2C_ADDRESS 0x68

#define LCD_PORT PORTD
#define LCD_DDR DDRD
#define LCD_DATA1 PD0
#define LCD_DATA2 PD1
#define LCD_DATA3 PD2
#define LCD_DATA4 PD3
#define LCD_SCLK PD4
#define LCD_OE PD5
#define LCD_COM PD6

#define KEY1_PORT PORTB
#define KEY1_DDR DDRB
#define KEY1_PIN PINB
#define KEY1 PB0
#define KEY2_PORT PORTD
#define KEY2_DDR DDRD
#define KEY2_PIN PIND
#define KEY2 PD7

#define DS1307SQ PB1
#define DS1307SQ_INT PCIE0
#define DS1307SQ_PORT PORTB
#define DS1307SQ_DDR DDRB
#define DS1307SQ_PIN PINB
#define DS1307SQ_VEC PCINT0_vect
#define DS1307SQ_MSK PCMSK0

//  . , -, , -     
#define LM335_PORT PORTC
#define LM335_DDR DDRC
#define LM335 PC3

//  
unsigned char lcd_buf[4];

#define MODE_MAIN 0
#define MODE_CALENDAR 1
#define MODE_YEAR 2
#define MODE_TERMOMETER 3 // 
#define MODE_VOLTMETER 4 // 
#define MODE_SET_MINUTE 5
#define MODE_SET_HOUR 6
#define MODE_SET_DAY 7
#define MODE_SET_MONTH 8
#define MODE_SET_YEAR 9
#define MODE_SECOND 10
#define MODE_DEBUG 11 //  

//        10ms ()
#define MODE_TIMEOUT 20 // 2 
#define MODE_TIMEOUT_SET 100 // 10 
#define KEY_TIMEOUT 10 // 1 

byte mode = MODE_MAIN;
byte mode_timeout = 0;

byte key1_press = 0;
byte key1_time = 0;
byte key2_press = 0;
byte key2_time = 0;

byte cycle_count_10 = 0; //   
byte even_10 = 0; //    1/10 

//    ds1307
byte second;
byte minute;
byte hour;
byte dayOfWeek;
byte dayOfMonth;
byte month;
byte year;

volatile byte need_render_int = 1;
uint8_t porthistory = 0xFF;
volatile uint8_t debug_value = 0;

byte twi_problems = 0;

//    ds1307   SQ
//   ,     
ISR(DS1307SQ_VEC) {
  uint8_t changedbits = DS1307SQ_PIN ^ porthistory;
  porthistory = DS1307SQ_PIN;
  if (changedbits & _BV(DS1307SQ) && porthistory & _BV(DS1307SQ)) {
    need_render_int = 1;
  }
}

//       
void lcd_num(char pos, char num) {
  unsigned char buf = 0b01110110;
  if (pos < 1 || pos > 3) {
    return;
  }
  switch (num) {
    case 0:
      //      3-   ,   ?
      // ,     ,     
      //   :-(
      if (pos == 3) {
        buf = 0b11101110;
      } else {
        buf = 0b11100111;
      }
      break;
    case 1:
      if (pos == 3) {
        buf = 0b10001000;
      } else {
        buf = 0b10000001;
      }
      break;
    case 2:
      buf = 0b11010110;
      break;
    case 3:
      if (pos == 3) {
        buf = 0b11011100;
      } else {
        buf = 0b11010011;
      }
      break;
    case 4:
      if (pos == 3) {
        buf = 0b10111000;
      } else {
        buf = 0b10110001;
      }
      break;
    case 5:
      if (pos == 3) {
        buf = 0b01111100;
      } else {
        buf = 0b01110011;
      }
      break;
    case 6:
      if (pos == 3) {
        buf = 0b01111110;
      } else {
        buf = 0b01110111;
      }
      break;
    case 7:
      if (pos == 3) {
        buf = 0b11001000;
      } else {
        buf = 0b11000001;
      }
      break;
    case 8:
      if (pos == 3) {
        buf = 0b11111110;
      } else {
        buf = 0b11110111;
      }
      break;
    case 9:
      if (pos == 3) {
        buf = 0b11111100;
      } else {
        buf = 0b11110011;
      }
      break;
  }
  lcd_buf[pos] = buf;
}

//  
void lcd_one(bool e) {
  if (e) {
    lcd_buf[0] |= (1 << 0);
  } else {
    lcd_buf[0] &= ~(1 << 0);
  }
}
void lcd_sec(bool e) {
  if (e) {
    lcd_buf[0] |= (1 << 7);
  } else {
    lcd_buf[0] &= ~(1 << 7);
  }
}
void lcd_minus(bool e) {
  if (e) {
    lcd_buf[0] |= (1 << 1);
  } else {
    lcd_buf[0] &= ~(1 << 1);
  }
}
void lcd_plus(bool e) {
  if (e) {
    lcd_buf[0] |= (1 << 6);
  } else {
    lcd_buf[0] &= ~(1 << 6);
  }
}
void lcd_lo(bool e) {
  if (e) {
    lcd_buf[0] |= (1 << 5);
  } else {
    lcd_buf[0] &= ~(1 << 5);
  }
}
void lcd_over(bool e) {
  if (e) {
    lcd_buf[0] |= (1 << 4);
  } else {
    lcd_buf[0] &= ~(1 << 4);
  }
}
void lcd_dot(int pos, bool e) {
  int pos_buf;
  if (pos == 1) {
    pos_buf = 3;
  } else if (pos == 2) {
    pos_buf = 2;
  } else if (pos == 3) {
    pos_buf = 1;
  } else {
    return;
  }
  if (pos_buf == 3) {
    if (e) {
      lcd_buf[pos_buf] |= (1 << 0);
    } else {
      lcd_buf[pos_buf] &= ~(1 << 0);
    }
  } else {
    if (e) {
      lcd_buf[pos_buf] |= (1 << 3);
    } else {
      lcd_buf[pos_buf] &= ~(1 << 3);
    }
  }
}

//     100   
//    595-,    
void lcd_refresh() {
  unsigned char data1 = lcd_buf[0];
  unsigned char data2 = lcd_buf[1];
  unsigned char data3 = lcd_buf[2];
  unsigned char data4 = lcd_buf[3];
  byte reverse = data1 & (1 << 3); //      
  if (reverse) { //    ,  
    data1 = ~data1;
    data2 = ~data2;
    data3 = ~data3;
    data4 = ~data4;
  }
  for (int i = 0; i < 8; i++) {
    //          
    if (data1 & (1 << i)) {
      LCD_PORT |= _BV(LCD_DATA1);
    } else {
      LCD_PORT &= ~_BV(LCD_DATA1);
    }
    if (data2 & (1 << i)) {
      LCD_PORT |= _BV(LCD_DATA2);
    } else {
      LCD_PORT &= ~_BV(LCD_DATA2);
    }
    if (data3 & (1 << i)) {
      LCD_PORT |= _BV(LCD_DATA3);
    } else {
      LCD_PORT &= ~_BV(LCD_DATA3);
    }
    if (data4 & (1 << i)) {
      LCD_PORT |= _BV(LCD_DATA4);
    } else {
      LCD_PORT &= ~_BV(LCD_DATA4);
    }
    // SCLK 595- 
    sbi(LCD_PORT, LCD_SCLK);
    // SCLK 595- 
    cbi(LCD_PORT, LCD_SCLK);
  }
  //    SCLK
  //       SCLK   RCLK     ,    
  //     .
  //   , -, .       
  // SCLK  RCLK,  OE     (.   74HC595)
  //    .
  sbi(LCD_PORT, LCD_SCLK);
  cbi(LCD_PORT, LCD_SCLK);
  //    -   
  // -   -   ,  1  40
  // (-    ;     )
  //      4   595-,     
  //   ,    
  if (reverse) {
    sbi(LCD_PORT, LCD_COM);
  } else {
    cbi(LCD_PORT, LCD_COM);
  }
  //     
  lcd_buf[0] ^= (1 << 3);
}

//        ,     
void do_render() {
  lcd_buf[0] = 0;
  lcd_buf[1] = 0;
  lcd_buf[2] = 0;
  lcd_buf[3] = 0;
  if (twi_problems) {
    lcd_lo(1);
  }
  if (mode == MODE_MAIN) {
    lcd_num(3, minute % 10);
    lcd_num(2, minute / 10);
    byte hour1 = (hour <= 12) ? hour : (hour % 12);
    lcd_num(1, hour1 % 10);
    if (hour1 >= 10) {
      lcd_one(1);
    }
    //     ,   . .
    //         SQ  ,
    //     ,        
    //     
    if (second % 2) {
      lcd_sec(1);
    }
  } else if (mode == MODE_CALENDAR) {
    lcd_num(3, dayOfMonth % 10);
    lcd_num(2, dayOfMonth / 10);
    lcd_num(1, month % 10);
    if (month >= 10) {
      lcd_one(1);
    } else {
      lcd_one(0);
    }
    lcd_dot(2, 1);
  } else if (mode == MODE_YEAR) {
    lcd_num(3, year % 10);
    lcd_num(2, year / 10);
    lcd_buf[1] = 0b10110011; //   y. 
  } else if (mode == MODE_TERMOMETER) {
  } else if (mode == MODE_VOLTMETER) {
  } else if (mode == MODE_SET_MINUTE) {
    if (even_10) {
      lcd_num(3, minute % 10);
      lcd_num(2, minute / 10);
    }
    byte hour1 = (hour <= 12) ? hour : (hour % 12);
    lcd_num(1, hour1 % 10);
    if (hour1 >= 10) {
      lcd_one(1);
    } else {
      lcd_one(0);
    }
    lcd_sec(1);
  } else if (mode == MODE_SET_HOUR) {
    lcd_num(3, minute % 10);
    lcd_num(2, minute / 10);
    if (even_10) {
      byte hour1 = (hour <= 12) ? hour : (hour % 12);
      lcd_num(1, hour1 % 10);
      if (hour1 >= 10) {
        lcd_one(1);
      } else {
        lcd_one(0);
      }
      if (hour > 12) {
        lcd_over(1);
      } else {
        lcd_over(0);
      }
    }
    lcd_sec(1);
  } else if (mode == MODE_SET_DAY) {
    if (even_10) {
      lcd_num(3, dayOfMonth % 10);
      lcd_num(2, dayOfMonth / 10);
    }
    lcd_num(1, month % 10);
    if (month >= 10) {
      lcd_one(1);
    } else {
      lcd_one(0);
    }
    lcd_dot(2, 1);
  } else if (mode == MODE_SET_MONTH) {
    lcd_num(3, dayOfMonth % 10);
    lcd_num(2, dayOfMonth / 10);
    if (even_10) {
      lcd_num(1, month % 10);
      if (month >= 10) {
        lcd_one(1);
      } else {
        lcd_one(0);
      }
    }
    lcd_dot(2, 1);
  } else if (mode == MODE_SET_YEAR) {
    if (even_10) {
      lcd_num(3, year % 10);
      lcd_num(2, year / 10);
    }
    lcd_buf[1] = 0b10110011;
  } else if (mode == MODE_SECOND) {
    lcd_sec(1);
    lcd_num(3, second % 10);
    lcd_num(2, second / 10);
  } else if (mode == MODE_DEBUG) {
    byte d = debug_value;
    lcd_num(3, d % 10);
    d /= 10;
    lcd_num(2, d % 10);
    lcd_num(2, d / 10);
  }
}

int main(void)
{
  // -    .
  // , ,  .
  // ACSR = (1<<ACD);
  ADCSRA = (0<<ADEN);
  PRR = (1<<PRTIM0) | (1<<PRTIM1) | (1<<PRTIM2) | (1<<PRSPI) | (1<<PRADC) | (1<<PRUSART0);

  // 
  DDRB = 0x00;
  PORTB = 0xff;
  DDRC = 0x00;
  PORTC = 0xff;
  DDRD = 0x00;
  PORTD = 0xff;

  lcd_buf[0] = 0x0;
  lcd_buf[1] = 0x0;
  lcd_buf[2] = 0x0;
  lcd_buf[3] = 0x0;

  twi_begin();

  //   .    usbasp,     
  // ,  ,   
  // DDRB |= _BV(PB7);
  // PORTB |= _BV(PB7); // off

  //   -
  LCD_DDR |= (_BV(LCD_DATA1) | _BV(LCD_DATA2) | _BV(LCD_DATA3) | _BV(LCD_DATA4) | _BV(LCD_SCLK) | _BV(LCD_OE) | _BV(LCD_COM));
  cbi(LCD_PORT, LCD_SCLK);
  cbi(LCD_PORT, LCD_OE);

  // 
  KEY1_DDR &= ~(_BV(KEY1));
  KEY1_PORT |= _BV(KEY1);
  KEY2_DDR &= ~(_BV(KEY2));
  KEY2_PORT |= _BV(KEY2);

  //    ds1307   
  DS1307SQ_DDR &= ~_BV(DS1307SQ);
  DS1307SQ_PORT |= _BV(DS1307SQ);
  PCICR |= _BV(DS1307SQ_INT);
  DS1307SQ_MSK |= _BV(DS1307SQ);
  sei();

  // ds1307     ,     ,   
  //    ,    - 
  // setDS3231time(30,40,21,6,11,3,18);

  while(1)
  {
    byte need_render = 0;
    byte need_date_set = 0;

    //    ds1307,   
    // 
    if (need_render_int) {
      byte rc;
      if (mode == MODE_MAIN) {
        rc = readDS3231time_hms(&second, &minute, &hour);
      } else {
        rc = readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
      }
      if ( ! rc && twi_problems) {
        twi_problems -= 1;
      } else {
        twi_problems += rc;
      }
      need_render = 1;
      need_render_int = 0;
    }

    //    1/10 
    if ( ! cycle_count_10) {
      even_10 = ! even_10;

      //    ,   
      if (mode_timeout > 0) {
        mode_timeout -= 1;
      }
      //    ,    
      if (mode != MODE_MAIN && ! mode_timeout) {
        mode = MODE_MAIN;
        need_render = 1;
      }
      //      ,  10   
      if (mode == MODE_SET_MINUTE || mode == MODE_SET_HOUR || mode == MODE_SET_DAY || mode == MODE_SET_MONTH || mode == MODE_SET_YEAR) {
        need_render = 1; 
      }

      //  
      byte key1_down = (KEY1_PIN & _BV(KEY1)) ? 0 : 1;
      byte key2_down = (KEY2_PIN & _BV(KEY2)) ? 0 : 1;
      if (key1_down || key2_down || key1_press || key2_press) {
        need_render = 1;
      }
      if (key1_down && key1_press) {
        key1_time += 1;
      }
      if (key2_down && key2_press) {
        key2_time += 1;
      }
      //     
      if (key1_down && ! key1_press) {
          if (mode == MODE_SET_MINUTE) {
            mode = MODE_SET_HOUR;
            mode_timeout = MODE_TIMEOUT_SET;
          } else if (mode == MODE_SET_HOUR) {
            mode = MODE_SET_DAY;
            mode_timeout = MODE_TIMEOUT_SET;
          } else if (mode == MODE_SET_DAY) {
            mode = MODE_SET_MONTH;
            mode_timeout = MODE_TIMEOUT_SET;
          } else if (mode == MODE_SET_MONTH) {
            mode = MODE_SET_YEAR;
            mode_timeout = MODE_TIMEOUT_SET;
          } else if (mode == MODE_SET_YEAR) {
            mode = MODE_MAIN;
          } else if (mode == MODE_MAIN) {
            mode = MODE_SECOND;
            mode_timeout = MODE_TIMEOUT_SET;
          } else if (mode == MODE_SECOND) {
            mode = MODE_MAIN;
            mode_timeout = 0;
          }
      } else if ( ! key1_down && key1_press) {
        if (key1_time >= KEY_TIMEOUT) {
        } else {
        }
      } else if (key1_down && key1_press) {
        if (key1_time >= KEY_TIMEOUT) {
          if (mode == MODE_MAIN || mode == MODE_SECOND) {
            mode = MODE_SET_MINUTE;
            mode_timeout = MODE_TIMEOUT_SET;
          }
        } else {
        }
      }
      if (key2_down && ! key2_press) {
        if (mode == MODE_MAIN) {
          mode = MODE_CALENDAR;
          mode_timeout = MODE_TIMEOUT;
        } else if (mode == MODE_CALENDAR) {
          mode = MODE_YEAR;
          mode_timeout = MODE_TIMEOUT;
        } else if (mode == MODE_YEAR) {
          mode = MODE_MAIN;
          mode_timeout = 0;
        } else if (mode == MODE_SET_MINUTE) {
          minute += 1;
          mode_timeout = MODE_TIMEOUT_SET;
          need_date_set = 1;
        } else if (mode == MODE_SET_HOUR) {
          hour += 1;
          mode_timeout = MODE_TIMEOUT_SET;
          need_date_set = 1;
        } else if (mode == MODE_SET_DAY) {
          dayOfMonth += 1;
          mode_timeout = MODE_TIMEOUT_SET;
          need_date_set = 1;
        } else if (mode == MODE_SET_MONTH) {
          month += 1;
          mode_timeout = MODE_TIMEOUT_SET;
          need_date_set = 1;
        } else if (mode == MODE_SET_YEAR) {
          year += 1;
          mode_timeout = MODE_TIMEOUT_SET;
          need_date_set = 1;
        } else if (mode == MODE_SECOND) {
            second = 0;
            need_date_set = 1;
            mode_timeout = MODE_TIMEOUT_SET;
        }
      } else if ( ! key2_down && key2_press) {
        if (key2_time >= KEY_TIMEOUT) {
        } else {
        }
      } else if (key2_down && key2_press) {
        if (key2_time >= KEY_TIMEOUT) {
          if (mode == MODE_SET_MINUTE) {
            minute += 1;
            mode_timeout = MODE_TIMEOUT_SET;
            need_date_set = 1;
          } else if (mode == MODE_SET_HOUR) {
            hour += 1;
            mode_timeout = MODE_TIMEOUT_SET;
            need_date_set = 1;
          } else if (mode == MODE_SET_DAY) {
            dayOfMonth += 1;
            mode_timeout = MODE_TIMEOUT_SET;
            need_date_set = 1;
          } else if (mode == MODE_SET_MONTH) {
            month += 1;
            mode_timeout = MODE_TIMEOUT_SET;
            need_date_set = 1;
          } else if (mode == MODE_SET_YEAR) {
            year += 1;
            mode_timeout = MODE_TIMEOUT_SET;
            need_date_set = 1;
          }
        } else {
        }
      }
      key1_press = key1_down;
      if ( ! key1_press) {
        key1_time = 0;
      }
      key2_press = key2_down;
      if ( ! key2_press) {
        key2_time = 0;
      }
    }

    if (need_date_set) {
      //  
      //       ds1307    ,
      // ,  ,    
      if (minute > 59) {
        minute = 0;
      }
      if (hour > 23) {
        hour = 0;
      }
      if (dayOfMonth > 31) {
        dayOfMonth = 1;
      }
      if (month > 12) {
        month = 1;
      }
      if (year > 99) {
        year = 0;
      }
      //    ds1307
      setDS3231time(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
    }

    // ,    
    if (need_render) {
      do_render();
    }

    //  
    cli();
    lcd_refresh();
    sei();

    _delay_ms(10);

    cycle_count_10 += 1;
    if (cycle_count_10 >= 10) {
      cycle_count_10 = 0;
    }
  }

  return 0;
}

//    -   
byte decToBcd(byte val)
{
  return( (val/10*16) + (val%10) );
}
byte bcdToDec(byte val)
{
  return( (val/16*10) + (val%16) );
}

//    ds1307
void setDS3231time(byte second, 
                   byte minute, 
                   byte hour, 
                   byte dayOfWeek, 
                   byte dayOfMonth, 
                   byte month, 
                   byte year)
{
  twi_write((uint8_t) DS3231_I2C_ADDRESS, (uint8_t) 0, (uint8_t) decToBcd(second));
  twi_write((uint8_t) DS3231_I2C_ADDRESS, (uint8_t) 1, (uint8_t) decToBcd(minute));
  twi_write((uint8_t) DS3231_I2C_ADDRESS, (uint8_t) 2, (uint8_t) decToBcd(hour));
  twi_write((uint8_t) DS3231_I2C_ADDRESS, (uint8_t) 3, (uint8_t) decToBcd(dayOfWeek));
  twi_write((uint8_t) DS3231_I2C_ADDRESS, (uint8_t) 4, (uint8_t) decToBcd(dayOfMonth));
  twi_write((uint8_t) DS3231_I2C_ADDRESS, (uint8_t) 5, (uint8_t) decToBcd(month));
  twi_write((uint8_t) DS3231_I2C_ADDRESS, (uint8_t) 6, (uint8_t) decToBcd(year));
  //     SQ 1Hz
  //        ,   ds1307    
  //      8kHz
  twi_write((uint8_t) DS3231_I2C_ADDRESS, (uint8_t) 7, (uint8_t) 0b00010000);
}

//    ds1307
byte readDS3231time(byte *second,
                    byte *minute,
                    byte *hour,
                    byte *dayOfWeek,
                    byte *dayOfMonth,
                    byte *month,
                    byte *year)
{
  byte rc = twi_read(DS3231_I2C_ADDRESS, 0, 7);
  if (rc) return 1;
  *second = bcdToDec(twi_receive() & 0x7f);
  *minute = bcdToDec(twi_receive());
  *hour = bcdToDec(twi_receive() & 0x3f);
  *dayOfWeek = bcdToDec(twi_receive());
  *dayOfMonth = bcdToDec(twi_receive());
  *month = bcdToDec(twi_receive());
  *year = bcdToDec(twi_receive());
}

//   ,   ,  ,   
byte readDS3231time_hms(byte *second, byte *minute, byte *hour) {
  byte rc = twi_read(DS3231_I2C_ADDRESS, 0, 3);
  if (rc) return 1;
  *second = bcdToDec(twi_receive() & 0x7f);
  *minute = bcdToDec(twi_receive());
  *hour = bcdToDec(twi_receive() & 0x3f);
}

/*
 *  ,   ,  : http://dsscircuits.com/articles/arduino-i2c-master-library
 *      ,         4k  .
 */
/*
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#define START           0x08
#define REPEATED_START  0x10
#define MT_SLA_ACK  0x18
#define MT_SLA_NACK 0x20
#define MT_DATA_ACK     0x28
#define MT_DATA_NACK    0x30
#define MR_SLA_ACK  0x40
#define MR_SLA_NACK 0x48
#define MR_DATA_ACK     0x50
#define MR_DATA_NACK    0x58
#define LOST_ARBTRTN    0x38
#define TWI_STATUS      (TWSR & 0xF8)
#define SLA_W(address)  (address << 1)
#define SLA_R(address)  ((address << 1) + 0x01)

#define MAX_BUFFER_SIZE 32

uint8_t twi_bytesAvailable = 0;
uint8_t twi_bufferIndex = 0;
uint8_t twi_totalBytes = 0;
uint16_t twi_timeOutDelay = 0;
uint8_t twi_returnStatus;
uint8_t twi_nack;
uint8_t twi_data[MAX_BUFFER_SIZE];

void twi_begin()
{
  sbi(PORTC, 4);
  sbi(PORTC, 5);
  cbi(TWSR, TWPS0);
  cbi(TWSR, TWPS1);
  TWBR = ((F_CPU / 100000) - 16) / 2;
  TWCR = _BV(TWEN) | _BV(TWEA); 
}
uint8_t twi_read(uint8_t address, uint8_t registerAddress, uint8_t numberBytes)
{
  twi_bytesAvailable = 0;
  twi_bufferIndex = 0;
  if(numberBytes == 0){numberBytes++;}
  twi_nack = numberBytes - 1;
  twi_returnStatus = 0;
  twi_returnStatus = twi_start();
  if(twi_returnStatus){return(twi_returnStatus);}
  twi_returnStatus = twi_sendAddress(SLA_W(address));
  if(twi_returnStatus)
  {
    if(twi_returnStatus == 1){return(2);}
    return(twi_returnStatus);
  }
  twi_returnStatus = twi_sendByte(registerAddress);
  if(twi_returnStatus)
  {
    if(twi_returnStatus == 1){return(3);}
    return(twi_returnStatus);
  }
  twi_returnStatus = twi_start();
  if(twi_returnStatus)
  {
    if(twi_returnStatus == 1){return(4);}
    return(twi_returnStatus);
  }
  twi_returnStatus = twi_sendAddress(SLA_R(address));
  if(twi_returnStatus)
  {
    if(twi_returnStatus == 1){return(5);}
    return(twi_returnStatus);
  }
  for(uint8_t i = 0; i < numberBytes; i++)
  {
    if( i == twi_nack )
    {
      twi_returnStatus = twi_receiveByte(0);
      if(twi_returnStatus == 1){return(6);}
      if(twi_returnStatus != MR_DATA_NACK){return(twi_returnStatus);}
    }
    else
    {
      twi_returnStatus = twi_receiveByte(1);
      if(twi_returnStatus == 1){return(6);}
      if(twi_returnStatus != MR_DATA_ACK){return(twi_returnStatus);}
    }
    twi_data[i] = TWDR;
    twi_bytesAvailable = i+1;
    twi_totalBytes = i+1;
  }
  twi_returnStatus = twi_stop();
  if(twi_returnStatus)
  {
    if(twi_returnStatus == 1){return(7);}
    return(twi_returnStatus);
  }
  return(twi_returnStatus);
}
uint8_t twi_write(uint8_t address, uint8_t registerAddress, uint8_t data)
{
  twi_returnStatus = 0;
  twi_returnStatus = twi_start(); 
  if(twi_returnStatus){return(twi_returnStatus);}
  twi_returnStatus = twi_sendAddress(SLA_W(address));
  if(twi_returnStatus)
  {
    if(twi_returnStatus == 1){return(2);}
    return(twi_returnStatus);
  }
  twi_returnStatus = twi_sendByte(registerAddress);
  if(twi_returnStatus)
  {
    if(twi_returnStatus == 1){return(3);}
    return(twi_returnStatus);
  }
  twi_returnStatus = twi_sendByte(data);
  if(twi_returnStatus)
  {
    if(twi_returnStatus == 1){return(3);}
    return(twi_returnStatus);
  }
  twi_returnStatus = twi_stop();
  if(twi_returnStatus)
  {
    if(twi_returnStatus == 1){return(7);}
    return(twi_returnStatus);
  }
  return(twi_returnStatus);
}
uint8_t twi_receive()
{
  twi_bufferIndex = twi_totalBytes - twi_bytesAvailable;
  if(!twi_bytesAvailable)
  {
    twi_bufferIndex = 0;
    return(0);
  }
  twi_bytesAvailable--;
  return(twi_data[twi_bufferIndex]);
}
uint8_t twi_start()
{
  unsigned long startingTime = millis();
  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
  while (!(TWCR & (1<<TWINT)))
  {
    if(!twi_timeOutDelay){continue;}
    if((millis() - startingTime) >= twi_timeOutDelay)
    {
      twi_lockUp();
      return(1);
    }

  }
  if ((TWI_STATUS == START) || (TWI_STATUS == REPEATED_START))
  {
    return(0);
  }
  if (TWI_STATUS == LOST_ARBTRTN)
  {
    uint8_t bufferedStatus = TWI_STATUS;
    twi_lockUp();
    return(bufferedStatus);
  }
  return(TWI_STATUS);
}
uint8_t twi_sendAddress(uint8_t i2cAddress)
{
  TWDR = i2cAddress;
  unsigned long startingTime = millis();
  TWCR = (1<<TWINT) | (1<<TWEN);
  while (!(TWCR & (1<<TWINT)))
  {
    if(!twi_timeOutDelay){continue;}
    if((millis() - startingTime) >= twi_timeOutDelay)
    {
      twi_lockUp();
      return(1);
    }

  }
  if ((TWI_STATUS == MT_SLA_ACK) || (TWI_STATUS == MR_SLA_ACK))
  {
    return(0);
  }
  uint8_t bufferedStatus = TWI_STATUS;
  if ((TWI_STATUS == MT_SLA_NACK) || (TWI_STATUS == MR_SLA_NACK))
  {
    twi_stop();
    return(bufferedStatus);
  }
  else
  {
    twi_lockUp();
    return(bufferedStatus);
  } 
}
uint8_t twi_sendByte(uint8_t i2cData)
{
  TWDR = i2cData;
  unsigned long startingTime = millis();
  TWCR = (1<<TWINT) | (1<<TWEN);
  while (!(TWCR & (1<<TWINT)))
  {
    if(!twi_timeOutDelay){continue;}
    if((millis() - startingTime) >= twi_timeOutDelay)
    {
      twi_lockUp();
      return(1);
    }

  }
  if (TWI_STATUS == MT_DATA_ACK)
  {
    return(0);
  }
  uint8_t bufferedStatus = TWI_STATUS;
  if (TWI_STATUS == MT_DATA_NACK)
  {
    twi_stop();
    return(bufferedStatus);
  }
  else
  {
    twi_lockUp();
    return(bufferedStatus);
  } 
}
uint8_t twi_receiveByte(uint8_t ack)
{
  unsigned long startingTime = millis();
  if(ack)
  {
    TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);

  }
  else
  {
    TWCR = (1<<TWINT) | (1<<TWEN);
  }
  while (!(TWCR & (1<<TWINT)))
  {
    if(!twi_timeOutDelay){continue;}
    if((millis() - startingTime) >= twi_timeOutDelay)
    {
      twi_lockUp();
      return(1);
    }
  }
  if (TWI_STATUS == LOST_ARBTRTN)
  {
    uint8_t bufferedStatus = TWI_STATUS;
    twi_lockUp();
    return(bufferedStatus);
  }
  return(TWI_STATUS); 
}
uint8_t twi_stop()
{
  unsigned long startingTime = millis();
  TWCR = (1<<TWINT)|(1<<TWEN)| (1<<TWSTO);
  while ((TWCR & (1<<TWSTO)))
  {
    if(!twi_timeOutDelay){continue;}
    if((millis() - startingTime) >= twi_timeOutDelay)
    {
      twi_lockUp();
      return(1);
    }

  }
  return(0);
}
void twi_lockUp()
{
  TWCR = 0;
  TWCR = _BV(TWEN) | _BV(TWEA);
}

. , , — . , 1MHz, , 6mA. . , , : USBasp- .


, AVR- " ". ! , 100 . 65ms, , .


, - , , , 7805 , - .


! . , - , , , ? , . STM8/32? MSP430? , -, AVR?




UPD


, , . . , i2c ds1307. , VCC 1.2*VBAT. , i2c. : , +5v - 2.5v, i2c , . VBAT Tiny RTC 3v. .


. , . — , , 595, . , RCLK, , , , . , , . , .


, . - , , , , AVR 65 . , , . , AVR , , , . olartamonov .


, , 6mA , lm7805, (Vout ; Vin ). — 4mA.


, 0.3 1.6 mA. , — , , .


— ! , , 595- 555 , - , 32 595-. - :-)

Source: https://habr.com/ru/post/zh-CN410899/


All Articles