Портсигар

alexlaw

✩✩✩✩✩✩✩
3 Янв 2020
47
2
Воронеж
Биты конфигурации ATmega328P
Запутался во фьюзах.
При изменении фьюзов через командную строку MK перестает отвечать, через Arduino IDE - ругается (см. выше) и выставляет свои значения.
В конце концов через AVRDUDE_PROG 3.3 установил так - avrdude.exe: safemode: Fuses OK (E: 07, H: DE, L: E2) - как в в читалке Gyvera
Внутренний кварц 8МГц и отключенной проверкой на напряжение питания
В Atmega328 нет фьюза для запрета детектора некачественного питания (BOD). В Atmega328P этот фьюз есть, что позволяет дополнительно уменьшить энергопотребление, если отключить BOD. - E: 07
Пока оставлю так.
##############################################################

atmega328bb.name=ATmega328 on a breadboard (8 MHz internal clock)

atmega328bb.upload.protocol=arduino
atmega328bb.upload.maximum_size=30720
atmega328bb.upload.speed=57600

atmega328bb.bootloader.low_fuses=0xE2
atmega328bb.bootloader.high_fuses=0xDE
atmega328bb.bootloader.extended_fuses=0x07

atmega328bb.bootloader.file=atmega/ATmegaBOOT_168_atmega328_pro_8MHz.hex
atmega328bb.bootloader.unlock_bits=0x3F
atmega328bb.bootloader.lock_bits=0x0F

atmega328bb.build.mcu=atmega328p
atmega328bb.build.f_cpu=8000000L
atmega328bb.build.core=arduino:arduino
atmega328bb.build.variant=arduino:standard


atmega328bb.bootloader.tool=arduino:avrdude
atmega328bb.upload.tool=arduino:avrdude
 
Изменено:

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,265
944
58
Марий-Эл
Почему бы вместо замка не использовать механическую защелку которая открывается только когда на ее подаешь ток. Это бы сократило энергопотребление, а замок сделало бы постоянным и энергонезависимым.
И изменить принцип подачи сигарет. Не доставать через дверцу, а через отверстие в корпусе.
А что, прикольно должно получиться. Типа на выходе шторка, лёгкая. Управляется лёгким, малопотребляющим электромагнитом. На выходе стоит оптодатчик. Когда вытряхиваешь сигарету, после выхода сигареты шторка перекрывается. А знаете где взять маленький, малопотребляющий электромагнит? Из электонномеханического счётчика электроэнергии.
 

alexlaw

✩✩✩✩✩✩✩
3 Янв 2020
47
2
Воронеж
Поставил эксперимент.
Сколько проработает МК на батареи CR2032, без энергосбережения.
IMG_20200119_182033.png
Терминал на ATTINY2313 со своим питанием.
C++:
/*
//-----------------------------------------------------------------------------
                                    ATMEGA328P
                             =========================
                          ATMEGA    ARDUINO      ATMEGA
                            ||              8 - 12 || PB0/ICP1/CLK0/PCINT0
                            ||              9 - 13 || PB1/OC1A/PCINT1
                            ||             10 - 14 || PB2/ss/OC1B/PCINT2
                            ||             11 - 15 || PB3/MOSI/OC2A/PCINT3
                            ||             12 - 16 || PB4/MISO/PCINT4
                            ||             13 - 17 || PB5/SCK/PCINT5
                            ||             20 -  7 || PB6/TOSC1/XTAL1/PCINT6-INTERNAL OSCILLATOR MUST BE ENABLED
                            ||             21 -  8 || PB7/TOSC2/XTAL2/PCINT7-INTERNAL OSCILLATOR MUST BE ENABLED
                            ||                     ||
                            ||          14/A0 - 23 || PC0/ADC0/PCINT8
                            ||          15/A1 - 24 || PC1/ADC1/PCINT9
                            ||          16/A2 - 25 || PC2/ADC2/PCINT10
                            ||          17/A3 - 26 || PC3/ADC3/PCINT11
                            ||          18/A4 - 27 || PC4/ADC4/SDA/PCINT12
                            ||          19/A5 - 28 || PC5/ADC5/SCL/PCINT13
                            ||                 - 1 || PC6/reset/PCINT14                 
                          ATMEGA    ARDUINO      ATMEGA       
                             =========================
                                     ATMEGA328P
//-----------------------------------------------------------------------------
*/
const int data4 = 4;
const int clock3 = 3;
byte tcnt2;
long t;
uint8_t hours1;
uint8_t minutes1;
uint8_t seconds1;
byte dot = 128;//двоеточие на дисплее индикатора
byte b = 0;
unsigned long time = 0; // 86390000;
                  /*0*/ /*1*/ /*2*/ /*3*/ /*4*/ /*5*/ /*6*/ /*7*/ /*8*/ /*9*/
uint8_t digits2[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f };
uint8_t digits1[] = { 0x3f, 0x30, 0x5b, 0x79, 0x74, 0x6d, 0x6F, 0x38, 0x7f, 0x7D };
void setup() {
  Serial.begin(9600);
  Serial.println("Serial.begin(9600)");
  pinMode(data4, OUTPUT);
  pinMode(clock3, OUTPUT);
  start(clock3,data4);
writeValue(clock3,data4,0x8c);
stop(clock3,data4);
// clear display
write(clock3,data4,0x00, 0x00, 0x00, 0x00);
  setupInterrupt();
}

void loop() {
t = (unsigned long)(time/1000); // считываем время
hours1 = (byte)(t / 3600);
minutes1 = (byte)((t / 60) % 60);
seconds1 = (byte)(t % 60);                                                     
     if ((seconds1  % 2)==0){//мигаем двоеточием
                            dot=128;                         
                            } else {
                                   dot=0;
                                   }
    if (hours1>0){
     //если более 1 часа отображ - часы и мин
//    write(clock3,data4,digits1[minutes1 % 10],digits1[minutes1 / 10] | dot,digits1[hours1 % 10],digits1 [hours1 / 10]);
    write(clock3,data4,digits2 [hours1 / 10],digits2[hours1 % 10] | dot,digits2[minutes1 / 10],digits2[minutes1 % 10]);
                 } else {
                        //иначе  отображ - мин  и сек       
//                        write(clock3,data4,digits1[seconds1 % 10],digits1[seconds1 / 10] | dot,digits1[minutes1 % 10],digits1 [minutes1 / 10]);
                        write(clock3,data4,digits2 [minutes1 / 10],digits2[minutes1 % 10] | dot,digits2[seconds1 / 10],digits2[seconds1 % 10]);                   
                        }
b=!b;                   
if (b){
Serial.print(hours1);Serial.print(":");
Serial.print(minutes1);Serial.print(":");
Serial.print(seconds1);Serial.println();
}
delay(500);                               
}
//упраление таймером Timer2
void setupInterrupt()
{
/* First disable the timer overflow interrupt while we're configuring */
TIMSK2 &= ~(1<<TOIE2);
/* Configure timer2 in normal mode (pure counting, no PWM etc.) */
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
/* Select clock source: internal I/O clock */
ASSR &= ~(1<<AS2);
/* Disable Compare Match A interrupt enable (only want overflow) */
TIMSK2 &= ~(1<<OCIE2A);
/* Now configure the prescaler to CPU clock divided by 128 */
TCCR2B |= (1<<CS22)  | (1<<CS20); // Set bits
TCCR2B &= ~(1<<CS21);             // Clear bit
/* We need to calculate a proper value to load the timer counter.
* The following loads the value 131 into the Timer 2 counter register
* The math behind this is:
* (CPU frequency) / (prescaler value) = 62500 Hz = 16us.
* (desired period) / 16us = 62.5 (63)
* MAX(uint8) + 1 - 63 = 193;
*/
/* Save value globally for later reload in ISR */
tcnt2 = 193;
/* Finally load end enable the timer */
TCNT2 = tcnt2;
TIMSK2 |= (1<<TOIE2);
}
/*
* Install the Interrupt Service Routine (ISR) for Timer2 overflow.
* This is normally done by writing the address of the ISR in the
* interrupt vector table but conveniently done by using ISR()  */
ISR(TIMER2_OVF_vect) {
/* Reload the timer */
TCNT2 = tcnt2;
time++;
time = time % 86400000;
}
void write(int clock,int data,uint8_t first, uint8_t second, uint8_t third, uint8_t fourth)
{
start(clock,data);
writeValue(clock,data,0x40);
stop(clock,data);
start(clock,data);
writeValue(clock,data,0xc0);
writeValue(clock,data,first);
writeValue(clock,data,second);
writeValue(clock,data,third);
writeValue(clock,data,fourth);
stop(clock,data);
}

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


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

bool writeValue(int clock,int data,uint8_t value)
{
for(uint8_t i = 0; i < 8; i++)
{
digitalWrite(clock, LOW);
delayMicroseconds(5);
digitalWrite(data, (value & (1 << i)) >> i);
delayMicroseconds(5);
digitalWrite(clock, HIGH);
delayMicroseconds(5);
}
// wait for ACK
digitalWrite(clock,LOW);
delayMicroseconds(5);
pinMode(data,INPUT);
digitalWrite(clock,HIGH);
delayMicroseconds(5);
bool ack = digitalRead(data) == 0;
pinMode(data,OUTPUT);
return ack;
}
Следующий эксперимент будет с дисплеями ssd1306 и hx1230.
PS
Убрал терминал, вносит искажения
Без терминала

TM1637
IMG_20200119_200740.png
Пришел после работы, батарея уже села
расчет работы батареи в зависимости от потребляемого тока
Screenshot_2020-01-21 Онлайн калькулятор расчета времени раб...png
 

Вложения

Изменено:

alexlaw

✩✩✩✩✩✩✩
3 Янв 2020
47
2
Воронеж
Следующий дисплей ssd1306 spi
IMG_20200122_032913.png
C++:
int const vin = 6;//20; //+ - PB6
int const clk = 7;//21; //D0,SCL,CLK,SCK - Clock - PB7
int const data = 5;//5;//D1,SDA,MOSI - Data - PD5
int const res = 6;//6,RES - Reset - PD6//можно сразу к +
int const dc = 7;//7;DC - Data/Command - PD7
int const cs = 0;//8;CS - Chip Select - PB0
// Initialisation sequence for OLED module
int const InitLen = 23;
int const BufSize = 32;
uint8_t Buffer[BufSize];
int BufStart = 0, BufEnd = 0;
unsigned char Init[InitLen] = {
  0xAE, // Display off
  0xD5, // Set display clock
  0x80, // Recommended value
  0xA8, // Set multiplex
  0x3F,
  0xD3, // Set display offset
  0x00,
  0x40, // Zero start line
  0x8D, // Charge pump
  0x14,
  0x20, // Memory mode
  0x02, // Page addressing
  0xA1, // 0xA0/0xA1 flip horizontally
  0xC8, // 0xC0/0xC8 flip vertically
  0xDA, // Set comp ins
  0x12,
  0x81, // Set contrast
  0x7F,
  0xD9, // Set pre charge
  0xF1,
  0xDB, // Set vcom detect
  0x40,
  0xA6  // Normal (0xA7=Inverse)
};
// Character set - stored in program memory
const uint8_t CharMap[96][6] PROGMEM = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00 },
{ 0x00, 0x07, 0x00, 0x07, 0x00, 0x00 },
{ 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00 },
{ 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00 },
{ 0x23, 0x13, 0x08, 0x64, 0x62, 0x00 },
{ 0x36, 0x49, 0x56, 0x20, 0x50, 0x00 },
{ 0x00, 0x08, 0x07, 0x03, 0x00, 0x00 },
{ 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00 },
{ 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00 },
{ 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00 },
{ 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00 },
{ 0x00, 0x80, 0x70, 0x30, 0x00, 0x00 },
{ 0x08, 0x08, 0x08, 0x08, 0x08, 0x00 },
{ 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 },
{ 0x20, 0x10, 0x08, 0x04, 0x02, 0x00 },
{ 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00 },
{ 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00 },
{ 0x72, 0x49, 0x49, 0x49, 0x46, 0x00 },
{ 0x21, 0x41, 0x49, 0x4D, 0x33, 0x00 },
{ 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00 },
{ 0x27, 0x45, 0x45, 0x45, 0x39, 0x00 },
{ 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00 },
{ 0x41, 0x21, 0x11, 0x09, 0x07, 0x00 },
{ 0x36, 0x49, 0x49, 0x49, 0x36, 0x00 },
{ 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00 },
{ 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 },
{ 0x00, 0x40, 0x34, 0x00, 0x00, 0x00 },
{ 0x00, 0x08, 0x14, 0x22, 0x41, 0x00 },
{ 0x14, 0x14, 0x14, 0x14, 0x14, 0x00 },
{ 0x00, 0x41, 0x22, 0x14, 0x08, 0x00 },
{ 0x02, 0x01, 0x59, 0x09, 0x06, 0x00 },
{ 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00 },
{ 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00 },
{ 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00 },
{ 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00 },
{ 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00 },
{ 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00 },
{ 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00 },
{ 0x3E, 0x41, 0x41, 0x51, 0x73, 0x00 },
{ 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00 },
{ 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00 },
{ 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00 },
{ 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00 },
{ 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00 },
{ 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00 },
{ 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00 },
{ 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00 },
{ 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00 },
{ 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00 },
{ 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00 },
{ 0x26, 0x49, 0x49, 0x49, 0x32, 0x00 },
{ 0x03, 0x01, 0x7F, 0x01, 0x03, 0x00 },
{ 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00 },
{ 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00 },
{ 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00 },
{ 0x63, 0x14, 0x08, 0x14, 0x63, 0x00 },
{ 0x03, 0x04, 0x78, 0x04, 0x03, 0x00 },
{ 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00 },
{ 0x00, 0x7F, 0x41, 0x41, 0x41, 0x00 },
{ 0x02, 0x04, 0x08, 0x10, 0x20, 0x00 },
{ 0x00, 0x41, 0x41, 0x41, 0x7F, 0x00 },
{ 0x04, 0x02, 0x01, 0x02, 0x04, 0x00 },
{ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00 },
{ 0x00, 0x03, 0x07, 0x08, 0x00, 0x00 },
{ 0x20, 0x54, 0x54, 0x78, 0x40, 0x00 },
{ 0x7F, 0x28, 0x44, 0x44, 0x38, 0x00 },
{ 0x38, 0x44, 0x44, 0x44, 0x28, 0x00 },
{ 0x38, 0x44, 0x44, 0x28, 0x7F, 0x00 },
{ 0x38, 0x54, 0x54, 0x54, 0x18, 0x00 },
{ 0x00, 0x08, 0x7E, 0x09, 0x02, 0x00 },
{ 0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x00 },
{ 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00 },
{ 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00 },
{ 0x20, 0x40, 0x40, 0x3D, 0x00, 0x00 },
{ 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00 },
{ 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00 },
{ 0x7C, 0x04, 0x78, 0x04, 0x78, 0x00 },
{ 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00 },
{ 0x38, 0x44, 0x44, 0x44, 0x38, 0x00 },
{ 0xFC, 0x18, 0x24, 0x24, 0x18, 0x00 },
{ 0x18, 0x24, 0x24, 0x18, 0xFC, 0x00 },
{ 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00 },
{ 0x48, 0x54, 0x54, 0x54, 0x24, 0x00 },
{ 0x04, 0x04, 0x3F, 0x44, 0x24, 0x00 },
{ 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00 },
{ 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00 },
{ 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00 },
{ 0x44, 0x28, 0x10, 0x28, 0x44, 0x00 },
{ 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00 },
{ 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00 },
{ 0x00, 0x08, 0x36, 0x41, 0x00, 0x00 },
{ 0x00, 0x00, 0x77, 0x00, 0x00, 0x00 },
{ 0x00, 0x41, 0x36, 0x08, 0x00, 0x00 },
{ 0x02, 0x01, 0x02, 0x04, 0x02, 0x00 },
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 }
};
int Line, Column, Scroll;
int thisByte = 33;
void setup() {
  // Define pins
//  pinMode(20, OUTPUT); digitalWrite(20,HIGH);//vin
  PORTB |= (1 << vin);/// Set bits - high
  DDRB |= (1 << vin);// Set bits - output
  delay(100);
  pinMode(6, OUTPUT); digitalWrite(6,HIGH);//res
  pinMode(7, OUTPUT); digitalWrite(7,HIGH);//dc
//  pinMode(21, OUTPUT); digitalWrite(21,HIGH);//clk
  PORTB |= (1 << clk);/// Set bits - high
  DDRB |= (1 << clk);// Set bits - output
  pinMode(5, OUTPUT);//data
  pinMode(8, OUTPUT); digitalWrite(8,HIGH);//cs
  InitDisplay();
  ClearDisplay();
  Command(0xAF);  // Display on
}

void loop() {
   //"ASCII Table"
  if (thisByte < 126){
    Print(thisByte);  
    thisByte++;
  } else {
    ClearDisplay();
    thisByte = 33;
  }
delay(1000);
}

// Write a data byte to the display
void Data(uint8_t d) {
  PINB = 1<<cs; // cs low
  for (uint8_t bit = 0x80; bit; bit >>= 1) {
    PINB = 1<<clk; // clk low
    if (d & bit) PORTD = PORTD | (1<<data); else PORTD = PORTD & ~(1<<data);
    PINB = 1<<clk; // clk high
  }
  PINB = 1<<cs; // cs high
}
// Write a command byte to the display
void Command(uint8_t c) {
  PIND = 1<<dc; // dc low
  Data(c);
  PIND = 1<<dc; // dc high
}
void InitDisplay () {
  for (uint8_t c=0; c<InitLen; c++) Command(Init[c]);
}
// Character terminal **********************************************
void Clear256() {
  uint8_t b = 0;
  do {
    PINB = 1<<clk; // clk low
    b++;
    PINB = 1<<clk; // clk high
  } while (b != 0);
}
// Optimised for fast scrolling
void ClearLine (int line) {
  Command(0xB0 + line);
  Command(0x00); // Column start low
  Command(0x00); // Column start high
  PINB = 1<<cs; // cs low
  PORTD = PORTD & ~(1<<data); // data low
  Clear256(); Clear256(); Clear256(); Clear256();
  PINB = 1<<cs; // cs high
}
void ClearDisplay () {
  for (uint8_t p=0; p < 8; p++) ClearLine(p);
  Line = Scroll;
  Column = 0;
}
// Clears the top line, then scrolls the display up by one line
void ScrollDisplay () {
  ClearLine(Scroll);
  Scroll = (Scroll + 1) & 0x07;
  Command(0xD3);
  Command(Scroll << 3);
}
// Plots a character; line = 0 to 7; column = 0 to 20
void PlotChar(char c, int line, int column) {
  column = column*6;
  Command(0xB0 + ((line + Scroll) & 0x07));
  Command(0x00 + (column & 0x0F)); // Column start low
  Command(0x10 + (column >> 4));   // Column start high
  for (uint8_t col = 0 ; col < 6; col++) {
    Data(pgm_read_byte(&CharMap[c-32][col]));
  }
}
// Prints a character, handling control characters
void Print(char c) {
  c = c & 0x7F; // Ignore top bit
  if (c >= 32) {
    PlotChar(c, Line, Column++);
    if (Column > 20) {
      Column = 0;
      if (Line == 7) ScrollDisplay(); else Line++;
    }
  }
  // Return character
  else if (c == 13) {
    Column = 0;
    if (Line == 7) ScrollDisplay(); else Line++;
  }
}

ssd1306 spi

IMG_20200122_033152.png
 
Изменено:

alexlaw

✩✩✩✩✩✩✩
3 Янв 2020
47
2
Воронеж
Поэкспериментировал с кнопками.
Думаю 3-х кнопок достаточно.(раньше обходился одной)
Кнопки повесил на прерывания.
Прерывание вызывается дважды-при нажатии и потом при отпускании кнопки
C++:
void setup() {
initButton();
}

void loop() {
//бесконечный цикл
for(;;) {
}

}
//The External Interrupts are triggered by the INT0 and INT1 pins or any of the PCINT23...0 pins.
//The pin change interrupt PCI1 will trigger if any enabled PCINT[14:8] pin
//toggles.
//This implies that these interrupts can be used for
//waking the part also from sleep modes other than Idle mode.
void initButton() {
//cli(); Запретить прерывания
//pc0 pc1 pc2  кнопки
//pd5 pd6 pd7 светодиод
PORTC |= (1 << 0) | (1 << 1 ) | (1 << 2 );// Set bits - pullup
DDRC &= ~((1 << 0)  | (1 << 1)  | (1 << 2));// Clear bit - input
PORTD &= ~((1 << 5)  |  (1 << 6)  |  (1 << 7));// Clear bit - low
DDRD |= (1 << 5) | (1 << 6) | (1 << 7);// Set bits - output
//PCMSK1 – Pin Change Mask Register 1
//PCMSK1 Определяют условие генерации прерывания PCINT1. Если какойлибо
//бит установлен в 1, то изменение состояния соответствующего вывода
//вызовет генерацию прерывания
PCMSK1 |= (1 << 0) | (1 << 1 ) | (1 << 2 );// Set bits
//PCICR – Pin Change Interrupt Control Register
//прерывание по изменению состояния вывода 0 или 1 или 2
PCICR  |=  (1 << PCIE1);// Set bits - When the PCIE1 bit is set (one) and the I-bit in the Status Register (SREG) is set (one), pin change interrupt 1 is enabled
sei();//Разрешить прерывания
}
ISR(PCINT1_vect) {
PORTD &= ~((1 <<5)  | (1 <<6)  | (1 <<7));// Clear bit - выкл все светодиоды
  switch(PINC & 0x07){
    case 6:{PORTD |= (1 <<5);
    break;}// - high  pd5
    case 5:{PORTD |= (1 <<6);
    break;}// - high  pd6
    case 3:{PORTD |=(1 <<7);
    break;}// - high pd7
  }
}
Схема
atmega328_hx1230.png

Видео из облака
 
Изменено:

alexlaw

✩✩✩✩✩✩✩
3 Янв 2020
47
2
Воронеж
Тестовый скетч для таймера.
Логика.
При вкл на дисплее отображ. время таймера по умолчанию - 1 час.
При наж кн Старт/Стоп - таймер идет /или стоит (отображ. - "pause").
Во время паузы, при одновременном наж кн "H" и "M" таймер обнуляется (отображ "0:0:0")
и переходит в режим уст времени (отображ. - "pause set").
В режим уст времени :
При наж кн "H"(0.5 сек) увеличиваются часы на 1.(0-9).
При наж кн "M"(0.5 сек) увеличиваются минуты на 1. (0-59)
Для пуска таймера наж кн Старт/Стоп.
При достижении 0 - на экране отображ "0:0:0"
В правом нижнем углу отображ. версия скетча "ver-1.01"
C++:
/*
* https://github.com/cbm80amiga/HX1230_SPI
* https://github.com/cbm80amiga/HX1230_FB
* https://github.com/cbm80amiga/PropFonts
  HX1230 96x68 LCD connections (header on bottom, from left):
  #1 RST - any digital
  #2 CE  - any digital
  #3 N/C
  #4 DIN - D11/MOSI
  #5 CLK - D13/SCK
  #6 VCC - 3V3 or any digital
  #7 BL  - 3V3 or any digital
  #8 GND - GND
*/
#define VerProga "ver-1.01"
#define LCD_RST 4
#define LCD_CS  3
#define LCD_BL  8//к VCC (подсветка не подкл)
#define LCD_DIN 11
#define LCD_CLK 13
#include "HX1230_SPI.h"

HX1230_SPI lcd(LCD_RST, LCD_CS);
#include "term8x14_font.h"
#include "bold13x20digtop_font.h"
byte tcnt2;
volatile long t,t1;
unsigned long time = 0; // 86390000;
//время для отображения таймера
unsigned long sTime;
uint8_t hours1;
uint8_t minutes1;
uint8_t seconds1;
//время для установок  таймера
uint8_t h1=1;
uint8_t m1=0;
uint8_t s1=0;
char buf[40];
int y=2;
int x=2;
String stringVar;
char charVar[9];
volatile boolean StartStopTimer = false;
void setup() {
//  Serial.begin(9600);
//  Serial.print("Serial.begin(9600)");
  pinMode(LCD_BL, OUTPUT);
  digitalWrite(LCD_BL, HIGH);
  lcd.init();
  lcd.clrScr();
  lcd.setDigitMinWd(13);
  setupInterrupt();
  initButton();
  sTime=(unsigned long)(3600*h1+60*m1+s1);
}

void loop() {
if (time!=0){
t = (unsigned long)(time/1000); // считываем время
t1=(long)(sTime-t);
if (t1<0){
t1=0;
}
hours1 = (uint8_t)(t1 / 3600);
minutes1 = (uint8_t)((t1 / 60) % 60);
seconds1 = (uint8_t)(t1 % 60);
stringVar =String(hours1, DEC)+":"+String(minutes1, DEC)+":"+String(seconds1, DEC);
} else {
stringVar =String(h1, DEC)+":"+String(m1, DEC)+":0";
}
stringVar.toCharArray(charVar,sizeof(charVar));
snprintf(buf,sizeof(buf)-1,charVar);
lcd.setFont(Bold13x20);
lcd.printStr(x,y,buf);
lcd.setFont(Term8x14PL);
if (!StartStopTimer)lcd.printStr(0, 0, "pause");
if (time==0)lcd.printStr(0, 0, "pause , set");
lcd.printStr(30, 6, VerProga);
PCICR &= ~(1<<PCIE1);//Clear bit запретить прерывания на кнопки
delay(500);
PCICR  |=  (1 << PCIE1);// Set bits разрешить прерывания на кнопки
lcd.clrScr();

}
//упраление таймером Timer2
void setupInterrupt()
{
/* First disable the timer overflow interrupt while we're configuring */
TIMSK2 &= ~(1<<TOIE2);
/* Configure timer2 in normal mode (pure counting, no PWM etc.) */
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
/* Select clock source: internal I/O clock */
ASSR &= ~(1<<AS2);
/* Disable Compare Match A interrupt enable (only want overflow) */
TIMSK2 &= ~(1<<OCIE2A);
/* Now configure the prescaler to CPU clock divided by 128 */
TCCR2B |= (1<<CS22)  | (1<<CS20); // Set bits
TCCR2B &= ~(1<<CS21);             // Clear bit
/* We need to calculate a proper value to load the timer counter.
* The following loads the value 131 into the Timer 2 counter register
* The math behind this is:
* (CPU frequency) / (prescaler value) = 62500 Hz = 16us.
* (desired period) / 16us = 62.5 (63)
* MAX(uint8) + 1 - 63 = 193;
*/
/* Save value globally for later reload in ISR */
tcnt2 = 193;//mega 8Мгц
//tcnt2 = 131;//nano 16Мгц
/* Finally load end enable the timer */
TCNT2 = tcnt2;
if (!StartStopTimer) return;
TIMSK2 |= (1<<TOIE2);
}
/*
* Install the Interrupt Service Routine (ISR) for Timer2 overflow.
* This is normally done by writing the address of the ISR in the
* interrupt vector table but conveniently done by using ISR()  */
ISR(TIMER2_OVF_vect) {
/* Reload the timer */
TCNT2 = tcnt2;
time++;
time = time % 86400000;
}
//The External Interrupts are triggered by the INT0 and INT1 pins or any of the PCINT23...0 pins.
//The pin change interrupt PCI1 will trigger if any enabled PCINT[14:8] pin
//toggles.
//This implies that these interrupts can be used for
//waking the part also from sleep modes other than Idle mode.
void initButton() {
//pc0 pc1 pc2  кнопки
PORTC |= (1 << 0) | (1 << 1 ) | (1 << 2 );// Set bits - pullup
DDRC &= ~((1 << 0)  | (1 << 1)  | (1 << 2));// Clear bit - input
//PCMSK1 – Pin Change Mask Register 1
//PCMSK1 Определяют условие генерации прерывания PCINT1. Если какойлибо
//бит установлен в 1, то изменение состояния соответствующего вывода
//вызовет генерацию прерывания
PCMSK1 |= (1 << 0) | (1 << 1 ) | (1 << 2 );// Set bits
//PCICR – Pin Change Interrupt Control Register
//прерывание по изменению состояния вывода 0 или 1 или 2
//PCICR  |=  (1 << PCIE1);// Set bits - When the PCIE1 bit is set (one) and the I-bit in the Status Register (SREG) is set (one), pin change interrupt 1 is enabled
}
ISR(PCINT1_vect) {
  switch(PINC & 0x07){
    case 6:{
    if (!StartStopTimer) {//наж кн 0
      StartStopTimer = true;
      TIMSK2 |= (1<<TOIE2);// Set bits - enable the timer - start 
    } else {
      StartStopTimer = false;
      TIMSK2 &= ~(1<<TOIE2);//Clear bit - disable the timer - pause
    }
    break;}
    case 1:{//наж одновременно две кн 1 и 2
      if (!StartStopTimer){           
        h1=0;
        m1=0;
        s1=0;
        time = 0;   
      }
     break;}
     case 5:{//наж кн 1
      if (time == 0){
        h1++;
        if (h1>9){h1=0;}
        s1=0;
        sTime=(unsigned long)(3600*h1+60*m1+s1);   
     }
     break;}
      case 3:{//наж кн 2
       if (time == 0){                 
        m1++;
        if (m1>59){m1=0;}
        s1=0;
        sTime=(unsigned long)(3600*h1+60*m1+s1);     
        }
     break;}
  }
}
PS
Если установить кол-во часов более 9, не корректно работает задуманная логика
 
Изменено:

Кирюша

✩✩✩✩✩✩✩
14 Янв 2020
11
1
Киев
Тестовый скетч для таймера.
Логика.
При вкл на дисплее отображ. время таймера по умолчанию - 1 час.
При наж кн Старт/Стоп - таймер идет /или стоит (отображ. - "pause").
Во время паузы, при одновременном наж кн "H" и "M" таймер обнуляется (отображ "0:0:0")
и переходит в режим уст времени (отображ. - "pause set").
В режим уст времени :
При наж кн "H"(0.5 сек) увеличиваются часы на 1.(0-9).
При наж кн "M"(0.5 сек) увеличиваются минуты на 1. (0-59)
Для пуска таймера наж кн Старт/Стоп.
При достижении 0 - на экране отображ "0:0:0"
В правом нижнем углу отображ. версия скетча "ver-1.01"
C++:
/*
* https://github.com/cbm80amiga/HX1230_SPI
* https://github.com/cbm80amiga/HX1230_FB
* https://github.com/cbm80amiga/PropFonts
  HX1230 96x68 LCD connections (header on bottom, from left):
  #1 RST - any digital
  #2 CE  - any digital
  #3 N/C
  #4 DIN - D11/MOSI
  #5 CLK - D13/SCK
  #6 VCC - 3V3 or any digital
  #7 BL  - 3V3 or any digital
  #8 GND - GND
*/
#define VerProga "ver-1.01"
#define LCD_RST 4
#define LCD_CS  3
#define LCD_BL  8//к VCC (подсветка не подкл)
#define LCD_DIN 11
#define LCD_CLK 13
#include "HX1230_SPI.h"

HX1230_SPI lcd(LCD_RST, LCD_CS);
#include "term8x14_font.h"
#include "bold13x20digtop_font.h"
byte tcnt2;
volatile long t,t1;
unsigned long time = 0; // 86390000;
//время для отображения таймера
unsigned long sTime;
uint8_t hours1;
uint8_t minutes1;
uint8_t seconds1;
//время для установок  таймера
uint8_t h1=1;
uint8_t m1=0;
uint8_t s1=0;
char buf[40];
int y=2;
int x=2;
String stringVar;
char charVar[9];
volatile boolean StartStopTimer = false;
void setup() {
//  Serial.begin(9600);
//  Serial.print("Serial.begin(9600)");
  pinMode(LCD_BL, OUTPUT);
  digitalWrite(LCD_BL, HIGH);
  lcd.init();
  lcd.clrScr();
  lcd.setDigitMinWd(13);
  setupInterrupt();
  initButton();
  sTime=(unsigned long)(3600*h1+60*m1+s1);
}

void loop() {
if (time!=0){
t = (unsigned long)(time/1000); // считываем время
t1=(long)(sTime-t);
if (t1<0){
t1=0;
}
hours1 = (uint8_t)(t1 / 3600);
minutes1 = (uint8_t)((t1 / 60) % 60);
seconds1 = (uint8_t)(t1 % 60);
stringVar =String(hours1, DEC)+":"+String(minutes1, DEC)+":"+String(seconds1, DEC);
} else {
stringVar =String(h1, DEC)+":"+String(m1, DEC)+":0";
}
stringVar.toCharArray(charVar,sizeof(charVar));
snprintf(buf,sizeof(buf)-1,charVar);
lcd.setFont(Bold13x20);
lcd.printStr(x,y,buf);
lcd.setFont(Term8x14PL);
if (!StartStopTimer)lcd.printStr(0, 0, "pause");
if (time==0)lcd.printStr(0, 0, "pause , set");
lcd.printStr(30, 6, VerProga);
PCICR &= ~(1<<PCIE1);//Clear bit запретить прерывания на кнопки
delay(500);
PCICR  |=  (1 << PCIE1);// Set bits разрешить прерывания на кнопки
lcd.clrScr();

}
//упраление таймером Timer2
void setupInterrupt()
{
/* First disable the timer overflow interrupt while we're configuring */
TIMSK2 &= ~(1<<TOIE2);
/* Configure timer2 in normal mode (pure counting, no PWM etc.) */
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
/* Select clock source: internal I/O clock */
ASSR &= ~(1<<AS2);
/* Disable Compare Match A interrupt enable (only want overflow) */
TIMSK2 &= ~(1<<OCIE2A);
/* Now configure the prescaler to CPU clock divided by 128 */
TCCR2B |= (1<<CS22)  | (1<<CS20); // Set bits
TCCR2B &= ~(1<<CS21);             // Clear bit
/* We need to calculate a proper value to load the timer counter.
* The following loads the value 131 into the Timer 2 counter register
* The math behind this is:
* (CPU frequency) / (prescaler value) = 62500 Hz = 16us.
* (desired period) / 16us = 62.5 (63)
* MAX(uint8) + 1 - 63 = 193;
*/
/* Save value globally for later reload in ISR */
tcnt2 = 193;//mega 8Мгц
//tcnt2 = 131;//nano 16Мгц
/* Finally load end enable the timer */
TCNT2 = tcnt2;
if (!StartStopTimer) return;
TIMSK2 |= (1<<TOIE2);
}
/*
* Install the Interrupt Service Routine (ISR) for Timer2 overflow.
* This is normally done by writing the address of the ISR in the
* interrupt vector table but conveniently done by using ISR()  */
ISR(TIMER2_OVF_vect) {
/* Reload the timer */
TCNT2 = tcnt2;
time++;
time = time % 86400000;
}
//The External Interrupts are triggered by the INT0 and INT1 pins or any of the PCINT23...0 pins.
//The pin change interrupt PCI1 will trigger if any enabled PCINT[14:8] pin
//toggles.
//This implies that these interrupts can be used for
//waking the part also from sleep modes other than Idle mode.
void initButton() {
//pc0 pc1 pc2  кнопки
PORTC |= (1 << 0) | (1 << 1 ) | (1 << 2 );// Set bits - pullup
DDRC &= ~((1 << 0)  | (1 << 1)  | (1 << 2));// Clear bit - input
//PCMSK1 – Pin Change Mask Register 1
//PCMSK1 Определяют условие генерации прерывания PCINT1. Если какойлибо
//бит установлен в 1, то изменение состояния соответствующего вывода
//вызовет генерацию прерывания
PCMSK1 |= (1 << 0) | (1 << 1 ) | (1 << 2 );// Set bits
//PCICR – Pin Change Interrupt Control Register
//прерывание по изменению состояния вывода 0 или 1 или 2
//PCICR  |=  (1 << PCIE1);// Set bits - When the PCIE1 bit is set (one) and the I-bit in the Status Register (SREG) is set (one), pin change interrupt 1 is enabled
}
ISR(PCINT1_vect) {
  switch(PINC & 0x07){
    case 6:{
    if (!StartStopTimer) {//наж кн 0
      StartStopTimer = true;
      TIMSK2 |= (1<<TOIE2);// Set bits - enable the timer - start
    } else {
      StartStopTimer = false;
      TIMSK2 &= ~(1<<TOIE2);//Clear bit - disable the timer - pause
    }
    break;}
    case 1:{//наж одновременно две кн 1 и 2
      if (!StartStopTimer){          
        h1=0;
        m1=0;
        s1=0;
        time = 0;  
      }
     break;}
     case 5:{//наж кн 1
      if (time == 0){
        h1++;
        if (h1>9){h1=0;}
        s1=0;
        sTime=(unsigned long)(3600*h1+60*m1+s1);  
     }
     break;}
      case 3:{//наж кн 2
       if (time == 0){                
        m1++;
        if (m1>59){m1=0;}
        s1=0;
        sTime=(unsigned long)(3600*h1+60*m1+s1);    
        }
     break;}
  }
}
PS
Если установить кол-во часов более 9, не корректно работает задуманная логика
То есть покурить реже чем 9 часов не получится.
 

alexlaw

✩✩✩✩✩✩✩
3 Янв 2020
47
2
Воронеж
То есть покурить реже чем 9 часов не получится.
Это всего лишь тестовый скетч.
Он нужен для изучения sleep mode.
Я пробовал вогнать МК в спящий режим, но пробудить не получилось.
Не смотря на -
waking the part also from sleep modes other than Idle mode.
Завтра, точнее уже сегодня приеду домой - поразбераюсь.
 

alexlaw

✩✩✩✩✩✩✩
3 Янв 2020
47
2
Воронеж
Я пробовал вогнать МК в спящий режим, но пробудить не получилос
Все работало, просто я неправильно определял пробуждение.
Хотел, чтобы таймер продолжал работать с того же места, а это не так.
Скетч для теста Power-save
C++:
boolean sleep_mode = 0;
void setup() {
for (int i=2;i<20;i++){
pinMode(i, INPUT_PULLUP);
}
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
initButton();
}

void loop() {
digitalWrite(13, LOW);
delay(1000);
if (sleep_mode)sleepNow();
digitalWrite(13, HIGH);
delay(1000);
}
//The External Interrupts are triggered by the INT0 and INT1 pins or any of the PCINT23...0 pins.
//The pin change interrupt PCI1 will trigger if any enabled PCINT[14:8] pin
//toggles.
//This implies that these interrupts can be used for
//waking the part also from sleep modes other than Idle mode.
void initButton() {
//cli(); Запретить прерывания
//pc0 pc1 pc2  кнопки
//pd5 pd6 pd7 светодиод 
PORTC |= (1 << 0) | (1 << 1 ) | (1 << 2 );// Set bits - pullup
DDRC &= ~((1 << 0)  | (1 << 1)  | (1 << 2));// Clear bit - input
PORTD &= ~((1 << 6)  |  (1 << 7));// Clear bit - low
DDRD |= (1 << 6) | (1 << 7);// Set bits - output
//PCMSK1 – Pin Change Mask Register 1
//PCMSK1 Определяют условие генерации прерывания PCINT1. Если какойлибо
//бит установлен в 1, то изменение состояния соответствующего вывода
//вызовет генерацию прерывания
PCMSK1 |= (1 << 0) | (1 << 1 ) | (1 << 2 );// Set bits
//PCICR – Pin Change Interrupt Control Register
//прерывание по изменению состояния вывода 0 или 1 или 2
PCICR  |=  (1 << PCIE1);// Set bits - When the PCIE1 bit is set (one) and the I-bit in the Status Register (SREG) is set (one), pin change interrupt 1 is enabled
sei();//Разрешить прерывания
}
ISR(PCINT1_vect) {
PORTD &= ~((1 <<6)  | (1 <<7));// Clear bit - выкл все светодиоды
  switch(PINC & 0x07){     
    case 6:{PORTD |= (1 <<6);
    break;}// - high  pd6
    case 5:{PORTD |= (1 <<7);
    break;}// - high  pd7
    case 3:{PORTD |=(1 <<6) | (1 << 7 );sleep_mode = 1;
    break;}// - high pd6 pd7 
  }
}
void sleepNow(){
//Помимо режимов пониженного энергопотребления,
//колличество потребляемой энергии микроконтроллера можно уменьшить
//отключением неиспользуемых устройств.
//Для отключения периферии микроконтроллера существует регистр PRR:
/*Аналогоцифровой преобразователь
* Если функционирование АЦП разрешено, то он будет работать во всех
* «спящих»  режимах.  Соответственно,  для  снижения  потребляемого  тока
* модуль АЦП необходимо отключать перед переводом микроконтроллера в
* любой из энергосберегающих режимов.
*/
//Writing this bit to one enables the ADC. By writing it to zero, the ADC is turned off. Turning the ADC off while a
//conversion is in progress, will terminate this conversion.
ADCSRA &= ~(1<<ADEN);//Clear bit
//Timer0 - (1 << PRTIM0) - используется стандартными временными функциями Arduino такими как delay()
//В этом скетче его не оключаем
PRR |= (1 << PRTWI) | (1 << PRTIM1)  | (1 << PRTIM2)  | (1 << PRSPI)  | (1 << PRADC);// Set bits
DIDR1 |= (1 << AIN1D)  | (1 << AIN0D ); // Set bits - отключения  входных  цифровых буферов
//Watchdog Timer Configuration
//WDTCSR – Watchdog Timer Control Register
MCUSR &= ~(1 << WDRF);// Clear bit
//WDE is overridden by WDRF in MCUSR. This means that WDE is always set when WDRF is set. To clear
//WDE, WDRF must be cleared first
WDTCSR &= ~((1 << WDE)  | (1 << WDIE));// Clear bit - Watchdog Timer Stopped
/*3.  Power-down (режим микропотребления) - прекращают работу все устройства микроконтроллера кроме тех,
* которые работают в асинхронном режиме.
* Выход из данного режима может осуществляться при аппаратном сбросе, сбросе от системы BOD,
* внешние прерывания, прерывания от сторожевого таймера,
* и прерывание по совпадению адреса по интерфейсу I2C (TWI).
* 4.  Power-save (экономичный) - полностью повторяет Power-down,
* но в нем еще продолжает свою работу таймер/счетчик 2 в асинхронном режиме.
*/
//Power-save
SMCR &= ~(1 << SM2);// Clear bit
SMCR |= (1 << SM0)  | (1 << SM1 ); // Set bits
SMCR |= (1 << SE);// Set bits -  sleep_enable
asm ("sleep");
SMCR &= ~(1 << SE);// Clear bit - sleep_disable
sleep_mode = 0;
}
IMG_20200201_150212.jpg
Сейчас обдумываю общую концепцию.
Вариант с использованием внешнего RTC - ds1302 или ds3231
Или вариант с асинхронным Timer2.
Сначала попытаю Timer2, только подготовлю часовой кварц для тактирования Timer2.
 
Изменено:

alexlaw

✩✩✩✩✩✩✩
3 Янв 2020
47
2
Воронеж
К сожалению не получается запустить Timer2 в асинхронном режиме.
C++:
const int data4 = 4;
const int clock3 = 3;
long t;
uint8_t hours1;
uint8_t minutes1;
uint8_t seconds1;
byte dot = 128;//двоеточие на дисплее индикатора
unsigned long time = 0;
                  /*0*/ /*1*/ /*2*/ /*3*/ /*4*/ /*5*/ /*6*/ /*7*/ /*8*/ /*9*/
uint8_t digits2[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f };
uint8_t digits1[] = { 0x3f, 0x30, 0x5b, 0x79, 0x74, 0x6d, 0x6F, 0x38, 0x7f, 0x7D };
byte tcnt2;
void setup() {
  pinMode(data4, OUTPUT);
  pinMode(clock3, OUTPUT);
  start(clock3,data4);
writeValue(clock3,data4,0x8c);
stop(clock3,data4);
// clear display
write(clock3,data4,0x00, 0x00, 0x00, 0x00); 

PORTD &= ~(1 << 6);// Clear bit - low
DDRD |= (1 << 6);// Set bits - output
setupInterrupt();
}

void loop() {
t = (unsigned long)(time); // считываем время
hours1 = (byte)(t / 3600); 
minutes1 = (byte)((t / 60) % 60);
seconds1 = (byte)(t % 60);                                                         
     if ((seconds1  % 2)==0){//мигаем двоеточием
                            dot=128;                             
                            } else {
                                   dot=0;
                                   }
    if (hours1>0){
     //если более 1 часа отображ - часы и мин
//    write(clock3,data4,digits1[minutes1 % 10],digits1[minutes1 / 10] | dot,digits1[hours1 % 10],digits1 [hours1 / 10]);
    write(clock3,data4,digits2 [hours1 / 10],digits2[hours1 % 10] | dot,digits2[minutes1 / 10],digits2[minutes1 % 10]);
                 } else {
                        //иначе  отображ - мин  и сек           
//                        write(clock3,data4,digits1[seconds1 % 10],digits1[seconds1 / 10] | dot,digits1[minutes1 % 10],digits1 [minutes1 / 10]);
                        write(clock3,data4,digits2 [minutes1 / 10],digits2[minutes1 % 10] | dot,digits2[seconds1 / 10],digits2[seconds1 % 10]);                       
                        }
delay(900);
}
//упраление таймером Timer2
/*
1.Отключить прерывания Т2 путем сброса бит OCIE2 и TOIE2.
2.Выбрать необходимый тактовый источник с помощью бита AS2
3.Выполнить запись новых значений в TCNT2, OCR2 и TCCR2.
4.При переходе в асинхронный режим тактирования дождаться сброса флагов TCN2UB, OCR2UB и TCR2UB.
5.Сбросить флаги прерывания Т2
6.При необходимости разрешить прерывания
 */

void setupInterrupt()
{
/* First disable the timer overflow interrupt while we're configuring */
TIMSK2 &= ~(1<<TOIE2);
/* Configure timer2 in normal mode (pure counting, no PWM etc.) */
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
/* Select clock source */
ASSR |= (1<<AS2);
/* Disable Compare Match A interrupt enable (only want overflow) */
TIMSK2 &= ~(1<<OCIE2A);
/* Now configure the prescaler to CPU clock divided by 128 */
TCCR2B |= (1<<CS22)  | (1<<CS20); // Set bits
TCCR2B &= ~(1<<CS21);             // Clear bit

tcnt2 = 0;
/* Finally load end enable the timer */
TCNT2 = tcnt2;
//TIFR2 = 0x00;
TIMSK2 |= (1<<TOIE2);
}
ISR(TIMER2_OVF_vect) {
PORTD  ^= (1 << 6);//инвентировать бит
time++;
}
//--------------------------------------------
void write(int clock,int data,uint8_t first, uint8_t second, uint8_t third, uint8_t fourth)
{
start(clock,data);
writeValue(clock,data,0x40);
stop(clock,data);
start(clock,data);
writeValue(clock,data,0xc0);
writeValue(clock,data,first);
writeValue(clock,data,second);
writeValue(clock,data,third);
writeValue(clock,data,fourth);
stop(clock,data);
}
 
void start(int clock,int data)
{
digitalWrite(clock,HIGH);//send start signal to TM1637
digitalWrite(data,HIGH);
delayMicroseconds(5);
digitalWrite(data,LOW);
digitalWrite(clock,LOW);
delayMicroseconds(5);
}
 
 
void stop(int clock,int data)
{
digitalWrite(clock,LOW);
digitalWrite(data,LOW);
delayMicroseconds(5);
digitalWrite(clock,HIGH);
digitalWrite(data,HIGH);
delayMicroseconds(5);
}
 
bool writeValue(int clock,int data,uint8_t value)
{
for(uint8_t i = 0; i < 8; i++)
{
digitalWrite(clock, LOW);
delayMicroseconds(5);
digitalWrite(data, (value & (1 << i)) >> i);
delayMicroseconds(5);
digitalWrite(clock, HIGH);
delayMicroseconds(5);
}
// wait for ACK
digitalWrite(clock,LOW);
delayMicroseconds(5);
pinMode(data,INPUT);
digitalWrite(clock,HIGH);
delayMicroseconds(5);
bool ack = digitalRead(data) == 0;
pinMode(data,OUTPUT);
return ack;
}
Причем в Протеусе работает, а в железе нет.
Прерывание срабатывает 1 раз и все.
Светодиод загорается и на индикаторе - 00:01.
Кто то пробовал запустить Timer2 в асинхронном режиме?
Кристалл брал от модуля RTC ds1302.

TM1637.png
PS
Пока писал пост сработало прерывание - прошло минут 5
Надо понять почему?
 

Вложения

alexlaw

✩✩✩✩✩✩✩
3 Янв 2020
47
2
Воронеж
Как оказалось - запустить Timer в асинхронном режиме, на часовом кварце 32.768 кГц - большой геморрой.
Кварц очень капризный, ни как не хочет запускаться.
У меня запустился всего лишь пару раз, когда я его воткнул в панельку прямо на ноги MK.
Я обрадовался и даже припаял кварц прямо на ноги. Но рано радовался, как обрезало - больше не запустился ни разу.
Код, который работал.
C++:
//Как запустить неработающий часовой кварц (32768 Гц)
//http://www.getchip.net/posts/052-kak-zapustit-nerabotayushhijj-chasovojj-kvarc-32768-gc/
//часы реального времени
//http://microsin.net/programming/avr/avr134-real-time-clock-with-asynchronous-timer.html
//32.768 кГц
const int data4 = 4;
const int clock3 = 3;
long t;
uint8_t hours1;
uint8_t minutes1;
uint8_t seconds1;
byte dot = 128;//двоеточие на дисплее индикатора
unsigned long time = 0;
                  /*0*/ /*1*/ /*2*/ /*3*/ /*4*/ /*5*/ /*6*/ /*7*/ /*8*/ /*9*/
uint8_t digits2[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f };
uint8_t digits1[] = { 0x3f, 0x30, 0x5b, 0x79, 0x74, 0x6d, 0x6F, 0x38, 0x7f, 0x7D };
byte tcnt2;
void setup() {
  pinMode(data4, OUTPUT);
  pinMode(clock3, OUTPUT);
  start(clock3,data4);
writeValue(clock3,data4,0x8c);
stop(clock3,data4);
// clear display
write(clock3,data4,0x00, 0x00, 0x00, 0x00);

PORTD &= ~(1 << 6);// Clear bit - low
DDRD |= (1 << 6);// Set bits - output
setupInterrupt();
}

void loop() {
t = (unsigned long)(time); // считываем время
hours1 = (byte)(t / 3600);
minutes1 = (byte)((t / 60) % 60);
seconds1 = (byte)(t % 60);                                                         
     if ((seconds1  % 2)==0){//мигаем двоеточием
                            dot=128;                             
                            } else {
                                   dot=0;
                                   }
    if (hours1>0){
     //если более 1 часа отображ - часы и мин
//    write(clock3,data4,digits1[minutes1 % 10],digits1[minutes1 / 10] | dot,digits1[hours1 % 10],digits1 [hours1 / 10]);
      write(clock3,data4,digits2 [hours1 / 10],digits2[hours1 % 10] | dot,digits2[minutes1 / 10],digits2[minutes1 % 10]);
                 } else {
                        //иначе  отображ - мин  и сек           
//                        write(clock3,data4,digits1[seconds1 % 10],digits1[seconds1 / 10] | dot,digits1[minutes1 % 10],digits1 [minutes1 / 10]);
                        write(clock3,data4,digits2 [minutes1 / 10],digits2[minutes1 % 10] | dot,digits2[seconds1 / 10],digits2[seconds1 % 10]);                       
                        }
delay(900);
}
//упраление таймером Timer2
/*
1.Отключить прерывания Т2 путем сброса бит OCIE2 и TOIE2.
2.Выбрать необходимый тактовый источник с помощью бита AS2
3.Выполнить запись новых значений в TCNT2, OCR2 и TCCR2.
4.При переходе в асинхронный режим тактирования дождаться сброса флагов TCN2UB, OCR2UB и TCR2UB.
5.Сбросить флаги прерывания Т2
6.При необходимости разрешить прерывания
 */

void setupInterrupt()
{
   //Ожидание завершения стабилизации внешнего
   // кварцевого генератора часов RTC:
   for (uint8_t i=0; i < 0x40; i++)
   {
      for (int j=0; j < 0xFFFF; j++);
   } 
     /* запрещаем прерывания */
  cli(); 
/* Запрещаем прерывания Timer/Counter2 обнуляя OCIE2х и TOIE2. */
TIMSK2 &= ~((1<<OCIE2A)|(1<<OCIE2B)|(1<<TOIE2));
/* Select clock source */
ASSR |= (1<<AS2);
delay(300);
/* Configure timer2 in normal mode (pure counting, no PWM etc.) */
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
/* Now configure the prescaler to CPU clock divided by 128 */
TCCR2B |= (1<<CS22)  | (1<<CS20); // Set bits
TCCR2B &= ~(1<<CS21);             // Clear bit
tcnt2 = 0;
/* Finally load end enable the timer */
TCNT2 = tcnt2;
while(ASSR & 0x1F);
/*  Обнуляем флаги прерываний Timer/Counter2. */
TIFR2 |= ((1<<OCF2A)|(1<<OCF2B)|(1<<TOV2));

TIMSK2 |= (1<<TOIE2);
     /* разрешаем прерывания */
  sei();
}
ISR(TIMER2_OVF_vect) {
TCNT2 = tcnt2; 
PORTD  ^= (1 << 6);//инвентировать бит
time++;
}
//--------------------------------------------
void write(int clock,int data,uint8_t first, uint8_t second, uint8_t third, uint8_t fourth)
{
start(clock,data);
writeValue(clock,data,0x40);
stop(clock,data);
start(clock,data);
writeValue(clock,data,0xc0);
writeValue(clock,data,first);
writeValue(clock,data,second);
writeValue(clock,data,third);
writeValue(clock,data,fourth);
stop(clock,data);
}
 
void start(int clock,int data)
{
digitalWrite(clock,HIGH);//send start signal to TM1637
digitalWrite(data,HIGH);
delayMicroseconds(5);
digitalWrite(data,LOW);
digitalWrite(clock,LOW);
delayMicroseconds(5);
}
 
 
void stop(int clock,int data)
{
digitalWrite(clock,LOW);
digitalWrite(data,LOW);
delayMicroseconds(5);
digitalWrite(clock,HIGH);
digitalWrite(data,HIGH);
delayMicroseconds(5);
}
 
bool writeValue(int clock,int data,uint8_t value)
{
for(uint8_t i = 0; i < 8; i++)
{
digitalWrite(clock, LOW);
delayMicroseconds(5);
digitalWrite(data, (value & (1 << i)) >> i);
delayMicroseconds(5);
digitalWrite(clock, HIGH);
delayMicroseconds(5);
}
// wait for ACK
digitalWrite(clock,LOW);
delayMicroseconds(5);
pinMode(data,INPUT);
digitalWrite(clock,HIGH);
delayMicroseconds(5);
bool ack = digitalRead(data) == 0;
pinMode(data,OUTPUT);
return ack;
}
 

alexlaw

✩✩✩✩✩✩✩
3 Янв 2020
47
2
Воронеж
А кондёр с каждого вывода на землю паял?
Может не запускаться из за этого.
попробуй корпус кварца соединить с GND
Все же актуально оказалась это - Как запустить неработающий часовой кварц (32768 Гц)
Почистил плату от флюса - заработала, как с конденсаторами так и без, как с землей так и без.
Можно двигаться дальше.
 

alexlaw

✩✩✩✩✩✩✩
3 Янв 2020
47
2
Воронеж
Закралась такая мысль.
Будет ли срабатывать прерывание по переполнения счетчика Timer2 в режиме Power Sleep и при этом не пробуждая МК от сна? Т.е. можно ли помигать светодиом, спящим МК?
Проверить это смогу только в субботу, но интересно знать сейчас
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,265
944
58
Марий-Эл
Скорее нет, чем да. Ядро то спит. А всей периферией управляет ядро. Вот у STM может получится через DMA. Да и то вряд ли. Не задумывался над этим.
 

Wan-Derer

★★★★★✩✩
Команда форума
31 Июл 2018
2,003
406
Москва
wan-derer.ru
@Эдуард Анисимов, вообще-то, таймеры это отдельные (от вычислительного ядра) блоки, которые вполне могут работать автономно, пробуждая ядро запросом на прерывание. Надо купить доки на тему режимов сна чтобы понять что там да как.
И да, фреймворком Ардуино многие полезные вещи не поддерживаются.
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,265
944
58
Марий-Эл
@Эдуард Анисимов, вообще-то, таймеры это отдельные (от вычислительного ядра) блоки, которые вполне могут работать автономно, пробуждая ядро запросом на прерывание. Надо купить доки на тему режимов сна чтобы понять что там да как.
И да, фреймворком Ардуино многие полезные вещи не поддерживаются.
У него был вопрос
Т.е. можно ли помигать светодиом, спящим МК?
Я думаю мой ответ верен. Так как Таймер да, работает, но единственное что он может, это разбудить ядро. А вот уже ядро и будет моргать светодиодом.
Скорее даже было бы правильнее ответить - спящим нет, но если таймер его разбудит, то да.
 

alexlaw

✩✩✩✩✩✩✩
3 Янв 2020
47
2
Воронеж
Я думаю мой ответ верен
Да, ваш ответ верен.
Но как вы понимаете "мигать светодиодом" - это не самоцель.
Цель запустить RTC не зависимо от ядра, Но производитель что то не допилил у себя,
а иначе зачем делать просто 8 битный счетчик на отдельно кристалле, а не полноценный RTC со своими регистрами.
Ну да ладно.
Поставил новую батарейку CR2025, таймер на 9 часов (светодиод для визуализации)-посмотрю, что получится
IMG_20200209_151445.jpg
C++:
/*
* https://github.com/cbm80amiga/HX1230_SPI
* https://github.com/cbm80amiga/HX1230_FB
* https://github.com/cbm80amiga/PropFonts
  HX1230 96x68 LCD connections (header on bottom, from left):
  #1 RST - any digital
  #2 CE  - any digital
  #3 N/C
  #4 DIN - D11/MOSI
  #5 CLK - D13/SCK
  #6 VCC - 3V3 or any digital
  #7 BL  - 3V3 or any digital
  #8 GND - GND
*/
#define VerProga "ver-1.02"
#define LCD_RST 4
#define LCD_CS  3
#define LCD_BL  8
#define LCD_DIN 11
#define LCD_CLK 13

#include "HX1230_SPI.h"

HX1230_SPI lcd(LCD_RST, LCD_CS);
#include "term8x14_font.h"
#include "bold13x20digtop_font.h"
byte tcnt2;
volatile long t,t1;
unsigned long time = 0; // 86390000;
//время для отображения таймера
unsigned long sTime;
uint8_t hours1;
uint8_t minutes1;
uint8_t seconds1;
//время для установок  таймера
uint8_t h1=1;
uint8_t m1=0;
uint8_t s1=0;
char buf[40];
int y=2;
int x=2;
String stringVar;
char charVar[9];
volatile boolean StartStopTimer = false;
volatile boolean sleep_mode = false;
void setup() {
//  Serial.begin(9600);
//  Serial.print("Serial.begin(9600)");
PowerLow();
  pinMode(LCD_BL, OUTPUT);
  digitalWrite(LCD_BL, HIGH);
  //светодиод для теста
PORTD &= ~(1 << 6);// Clear bit - low
DDRD |= (1 << 6);// Set bits - output
  lcd.init();
  lcd.clrScr();
  lcd.setDigitMinWd(13);
  setupInterrupt();
  initButton();
  sTime=(unsigned long)(3600*h1+60*m1+s1);
}

void loop() {
if (time!=0){
t1=(long)(sTime-time);
if (t1<0){
t1=0;
}
hours1 = (uint8_t)(t1 / 3600);
minutes1 = (uint8_t)((t1 / 60) % 60);
seconds1 = (uint8_t)(t1 % 60);
stringVar =String(hours1, DEC)+":"+String(minutes1, DEC)+":"+String(seconds1, DEC);
} else {
stringVar =String(h1, DEC)+":"+String(m1, DEC)+":0";
}
stringVar.toCharArray(charVar,sizeof(charVar));
snprintf(buf,sizeof(buf)-1,charVar);
lcd.setFont(Bold13x20);
lcd.printStr(x,y,buf);
lcd.setFont(Term8x14PL);
if (!StartStopTimer)lcd.printStr(0, 0, "pause");
if (time==0)lcd.printStr(0, 0, "pause , set");
lcd.printStr(30, 6, VerProga);
while(ASSR & 0x1F);
if (sleep_mode)sleepNow();
delay(250);
lcd.clrScr();

}
//упраление таймером Timer2
void setupInterrupt()
{
   //Ожидание завершения стабилизации внешнего
   // кварцевого генератора часов RTC:
   for (uint8_t i=0; i < 0x40; i++)
   {
      for (int j=0; j < 0xFFFF; j++);
   }
     /* запрещаем прерывания */
  cli();
/* Запрещаем прерывания Timer/Counter2 обнуляя OCIE2х и TOIE2. */
TIMSK2 &= ~((1<<OCIE2A)|(1<<OCIE2B)|(1<<TOIE2));
//Бит EXCLK (6) регистра ASSR разрешает использование внешнего тактового сигнала от кварцевого резонатора 32 кГц
//при записи в него 1
//ASSR |= (1<<EXCLK);
//delay(100);
/* Select clock source */
ASSR |= (1<<AS2);
delay(300);
/* Configure timer2 in normal mode (pure counting, no PWM etc.) */
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
/* Now configure the prescaler to CPU clock divided by 128 */
TCCR2B |= (1<<CS22)  | (1<<CS20); // Set bits
TCCR2B &= ~(1<<CS21);             // Clear bit
tcnt2 = 0;
/* Finally load end enable the timer */
TCNT2 = tcnt2;
while(ASSR & 0x1F);
/*  Обнуляем флаги прерываний Timer/Counter2. */
TIFR2 |= ((1<<OCF2A)|(1<<OCF2B)|(1<<TOV2));
PORTD  |= (1<<6);//заж светодиод
//TIMSK2 |= (1<<TOIE2);
     /* разрешаем прерывания */
  sei();
}
/*
* Install the Interrupt Service Routine (ISR) for Timer2 overflow.
* This is normally done by writing the address of the ISR in the
* interrupt vector table but conveniently done by using ISR()  */
ISR(TIMER2_OVF_vect) {
/* Reload the timer */
TCNT2 = tcnt2;
PORTD  ^= (1 << 6);//инвентировать бит
time++;
sleep_mode=1;
}
//The External Interrupts are triggered by the INT0 and INT1 pins or any of the PCINT23...0 pins.
//The pin change interrupt PCI1 will trigger if any enabled PCINT[14:8] pin
//toggles.
//This implies that these interrupts can be used for
//waking the part also from sleep modes other than Idle mode.
void initButton() {
//pc0 pc1 pc2  кнопки
PORTC |= (1 << 0) | (1 << 1 ) | (1 << 2 );// Set bits - pullup
DDRC &= ~((1 << 0)  | (1 << 1)  | (1 << 2));// Clear bit - input
//PCMSK1 – Pin Change Mask Register 1
//PCMSK1 Определяют условие генерации прерывания PCINT1. Если какойлибо
//бит установлен в 1, то изменение состояния соответствующего вывода
//вызовет генерацию прерывания
PCMSK1 |= (1 << 0) | (1 << 1 ) | (1 << 2 );// Set bits
//PCICR – Pin Change Interrupt Control Register
//прерывание по изменению состояния вывода 0 или 1 или 2
PCICR  |=  (1 << PCIE1);// Set bits - When the PCIE1 bit is set (one) and the I-bit in the Status Register (SREG) is set (one), pin change interrupt 1 is enabled
}
//т.к. тактирование идет от кварца 32.768 кГц - событие должно иметь место вплоть до срабатывания прерывания
ISR(PCINT1_vect) {
  switch(PINC & 0x07){
    case 6:{
    if (!StartStopTimer) {//наж кн 0
      StartStopTimer = true;
      TIMSK2 |= (1<<TOIE2);// Set bits - enable the timer - start
    } else {
      StartStopTimer = false;
      TIMSK2 &= ~(1<<TOIE2);//Clear bit - disable the timer - pause
    }
    break;}
    case 1:{//наж одновременно две кн 1 и 2
      if (!StartStopTimer){          
        h1=0;
        m1=0;
        s1=0;
        time = 0;  
      }
     break;}
     case 5:{//наж кн 1
      if (time == 0){
        h1++;
        if (h1>9){h1=0;}
        s1=0;
        sTime=(unsigned long)(3600*h1+60*m1+s1);  
     }
     break;}
      case 3:{//наж кн 2
       if (time == 0){                
        m1++;
        if (m1>59){m1=0;}
        s1=0;
        sTime=(unsigned long)(3600*h1+60*m1+s1);    
        }
     break;}
  }
}
void PowerLow(){
//Помимо режимов пониженного энергопотребления,
//колличество потребляемой энергии микроконтроллера можно уменьшить
//отключением неиспользуемых устройств.
//Для отключения периферии микроконтроллера существует регистр PRR:
/*Аналогоцифровой преобразователь
* Если функционирование АЦП разрешено, то он будет работать во всех
* «спящих»  режимах.  Соответственно,  для  снижения  потребляемого  тока
* модуль АЦП необходимо отключать перед переводом микроконтроллера в
* любой из энергосберегающих режимов.
*/
//Writing this bit to one enables the ADC. By writing it to zero, the ADC is turned off. Turning the ADC off while a
//conversion is in progress, will terminate this conversion.
ADCSRA &= ~(1<<ADEN);//Clear bit
//PRR |= (1 << PRTWI) | (1 << PRTIM0)  | (1 << PRTIM1)  | (1 << PRSPI)  | (1 << PRUSART0)  | (1 << PRADC)
PRR |= (1 << PRTWI) | (1 << PRTIM1)  | (1 << PRUSART0)  | (1 << PRADC);// Set bits
DIDR1 |= (1 << AIN1D)  | (1 << AIN0D ); // Set bits - отключения  входных  цифровых буферов
//DIDR1 – Digital Input Disable Register 1
//When this bit is written logic one, the digital input buffer on the AIN1/0 pin is disabled. The corresponding PIN
//Register bit will always read as zero when this bit is set. When an analog signal is applied to the AIN1/0 pin and
//the digital input from this pin is not needed, this bit should be written logic one to reduce power consumption in
//the digital input buffer.

//Watchdog Timer Configuration
//WDTCSR – Watchdog Timer Control Register
MCUSR &= ~(1 << WDRF);// Clear bit
//WDE is overridden by WDRF in MCUSR. This means that WDE is always set when WDRF is set. To clear
//WDE, WDRF must be cleared first
WDTCSR &= ~((1 << WDE)  | (1 << WDIE));// Clear bit - Watchdog Timer Stopped
//IVCE (Interrupt Vector Change Enable): бит разрешения изменения вектора прерывания. Данный бит должен быть установлен, чтобы разрешить изменение бита IVSEL.
//IVCE очищается аппаратно через четыре цикла после его установки или при установке бита IVSEL
MCUCR |= (1 << IVCE);
//IVSEL (Interrupt Vector Select): выбор вектора прерываний.
//Если установлен данный бит, то векторы прерываний перемещаются в начало загрузочного сектора флэш-памяти
//  Установить бит разрешения изменения вектора прерывания (IVCE).
//  В течение четырех машинных циклов внести изменение (записать 1 или 0) в IVSEL, при этом записывая лог.0 в IVCE.
MCUCR |= (1 << IVSEL);
}
void sleepNow(){
/*3.  Power-down (режим микропотребления) - прекращают работу все устройства микроконтроллера кроме тех,
* которые работают в асинхронном режиме.
* Выход из данного режима может осуществляться при аппаратном сбросе, сбросе от системы BOD,
* внешние прерывания, прерывания от сторожевого таймера,
* и прерывание по совпадению адреса по интерфейсу I2C (TWI).
* 4.  Power-save (экономичный) - полностью повторяет Power-down,
* но в нем еще продолжает свою работу таймер/счетчик 2 в асинхронном режиме.
*/
//Power-save
SMCR &= ~(1 << SM2);// Clear bit
SMCR |= (1 << SM0)  | (1 << SM1 ); // Set bits
SMCR |= (1 << SE);// Set bits -  sleep_enable
asm ("sleep");
SMCR &= ~(1 << SE);// Clear bit - sleep_disable
sleep_mode=0;
}
Цифровой амперметр показывает 0.15мА-в режиме сна, 3.3мА-в бодр.режиме (LED убран, но пин работает, как в скетче)
Дребезг уберу аппаратно - потом.
pullup.png
Это нормальная Схема или нет?

А может сделаю - Устранение дребезга контактов на основе вертикальных счетчиков
PS: Сделал аппаратно. R - 510 ом, С - 0.1 мкФ - на каждую кнопку
 
Изменено:

alexlaw

✩✩✩✩✩✩✩
3 Янв 2020
47
2
Воронеж
Еще чуть модифицировал скетч.
Дисплей после 30 сек простоя (не нажата ни одна кнопка),
переходит в энергосберегающий режим.
После этого даташит гласит, что можно выключить питание дисплея.
In power save mode, LCD outputs are fixed to VSS and all analog outputs are discharged. The power can be turned OFF after ST7567 is in the power save mode
После нажатия любой кнопки - на дисплей подается питание и команда проснуться.
C++:
/*
* https://github.com/cbm80amiga/HX1230_SPI
* https://github.com/cbm80amiga/HX1230_FB
* https://github.com/cbm80amiga/PropFonts
  HX1230 96x68 LCD connections (header on bottom, from left):
  #1 RST - any digital
  #2 CE  - any digital
  #3 N/C
  #4 DIN - D11/MOSI
  #5 CLK - D13/SCK
  #6 VCC - 3V3 or any digital
  #7 BL  - 3V3 or any digital
  #8 GND - GND
*/
#define VerProga "ver-1.02b"
#define LCD_RST 4
#define LCD_CS  3
#define LCD_BL  8
#define LCD_DIN 11
#define LCD_CLK 13
#define DISP_SLEEP 30

#include "HX1230_SPI.h"

HX1230_SPI lcd(LCD_RST, LCD_CS);
#include "term8x14_font.h"
#include "bold13x20digtop_font.h"
byte tcnt2;
volatile long t,t1;
unsigned long time = 0; // 86390000;
volatile uint8_t time_sleep;
//время для отображения таймера
unsigned long sTime;
uint8_t hours1;
uint8_t minutes1;
uint8_t seconds1;
//время для установок  таймера
uint8_t h1=1;
uint8_t m1=0;
uint8_t s1=0;
char buf[40];
int y=2;
int x=2;
String stringVar;
char charVar[9];
volatile boolean StartStopTimer = false;
volatile boolean sleep_mode = false;
void setup() {
//  Serial.begin(9600);
//  Serial.print("Serial.begin(9600)");
for (int i=2;i<20;i++){
pinMode(i, INPUT_PULLUP);
}
PowerLow();
  pinMode(LCD_BL, OUTPUT);
  digitalWrite(LCD_BL, HIGH);
  //светодиод для теста
PORTD &= ~(1 << 6);// Clear bit - low
DDRD |= (1 << 6);// Set bits - output
  lcd.init();
  lcd.clrScr();
  lcd.setDigitMinWd(13);
  setupInterrupt();
  initButton();
  sTime=(unsigned long)(3600*h1+60*m1+s1);
  time_sleep=0;
}

void loop() {
if (time_sleep>=DISP_SLEEP){
lcd.sleep(true);
time_sleep=DISP_SLEEP;
delay(250);
digitalWrite(LCD_BL, LOW);
}
if (time!=0){
t1=(long)(sTime-time);
if (t1<0){
TIMSK2 &= ~(1<<TOIE2);//Clear bit - disable the timer - pause
t1=0;
sleep_mode=1;
StartStopTimer = false;
}
hours1 = (uint8_t)(t1 / 3600);
minutes1 = (uint8_t)((t1 / 60) % 60);
seconds1 = (uint8_t)(t1 % 60);
stringVar =String(hours1, DEC)+":"+String(minutes1, DEC)+":"+String(seconds1, DEC);
} else {
stringVar =String(h1, DEC)+":"+String(m1, DEC)+":0";
}
stringVar.toCharArray(charVar,sizeof(charVar));
snprintf(buf,sizeof(buf)-1,charVar);
lcd.setFont(Bold13x20);
lcd.printStr(x,y,buf);
lcd.setFont(Term8x14PL);
if (!StartStopTimer)lcd.printStr(0, 0, "pause");
if (time==0)lcd.printStr(0, 0, "pause , set");
lcd.printStr(30, 6, VerProga);
while(ASSR & 0x1F);
if (sleep_mode)sleepNow();
delay(250);
lcd.clrScr();

}
//упраление таймером Timer2
void setupInterrupt()
{
   //Ожидание завершения стабилизации внешнего
   // кварцевого генератора часов RTC:
   for (uint8_t i=0; i < 0x40; i++)
   {
      for (int j=0; j < 0xFFFF; j++);
   }
     /* запрещаем прерывания */
  cli();
/* Запрещаем прерывания Timer/Counter2 обнуляя OCIE2х и TOIE2. */
TIMSK2 &= ~((1<<OCIE2A)|(1<<OCIE2B)|(1<<TOIE2));
//Бит EXCLK (6) регистра ASSR разрешает использование внешнего тактового сигнала от кварцевого резонатора 32 кГц
//при записи в него 1
//ASSR |= (1<<EXCLK);
//delay(100);
/* Select clock source */
ASSR |= (1<<AS2);
delay(300);
/* Configure timer2 in normal mode (pure counting, no PWM etc.) */
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
/* Now configure the prescaler to CPU clock divided by 128 */
TCCR2B |= (1<<CS22)  | (1<<CS20); // Set bits
TCCR2B &= ~(1<<CS21);             // Clear bit
tcnt2 = 0;
/* Finally load end enable the timer */
TCNT2 = tcnt2;
while(ASSR & 0x1F);
/*  Обнуляем флаги прерываний Timer/Counter2. */
TIFR2 |= ((1<<OCF2A)|(1<<OCF2B)|(1<<TOV2));
PORTD  |= (1<<6);//заж светодиод
//TIMSK2 |= (1<<TOIE2);
     /* разрешаем прерывания */
  sei();
}
/*
* Install the Interrupt Service Routine (ISR) for Timer2 overflow.
* This is normally done by writing the address of the ISR in the
* interrupt vector table but conveniently done by using ISR()  */
ISR(TIMER2_OVF_vect) {
/* Reload the timer */
TCNT2 = tcnt2;
PORTD  ^= (1 << 6);//инвентировать бит
time++;
time_sleep++;
sleep_mode=1;
}
//The External Interrupts are triggered by the INT0 and INT1 pins or any of the PCINT23...0 pins.
//The pin change interrupt PCI1 will trigger if any enabled PCINT[14:8] pin
//toggles.
//This implies that these interrupts can be used for
//waking the part also from sleep modes other than Idle mode.
void initButton() {
//pc0 pc1 pc2  кнопки
PORTC |= (1 << 0) | (1 << 1 ) | (1 << 2 );// Set bits - pullup
DDRC &= ~((1 << 0)  | (1 << 1)  | (1 << 2));// Clear bit - input
//PCMSK1 – Pin Change Mask Register 1
//PCMSK1 Определяют условие генерации прерывания PCINT1. Если какойлибо
//бит установлен в 1, то изменение состояния соответствующего вывода
//вызовет генерацию прерывания
PCMSK1 |= (1 << 0) | (1 << 1 ) | (1 << 2 );// Set bits
//PCICR – Pin Change Interrupt Control Register
//прерывание по изменению состояния вывода 0 или 1 или 2
PCICR  |=  (1 << PCIE1);// Set bits - When the PCIE1 bit is set (one) and the I-bit in the Status Register (SREG) is set (one), pin change interrupt 1 is enabled
}
//т.к. тактирование идет от кварца 32.768 кГц - событие должно иметь место вплоть до срабатывания прерывания
ISR(PCINT1_vect) {
  digitalWrite(LCD_BL, HIGH);
  time_sleep=0;
  lcd.sleep(false);    
  switch(PINC & 0x07){  
    case 6:{
    if (!StartStopTimer) {//наж кн 0
      StartStopTimer = true;
      TIMSK2 |= (1<<TOIE2);// Set bits - enable the timer - start    
    } else {
      StartStopTimer = false;
      TIMSK2 &= ~(1<<TOIE2);//Clear bit - disable the timer - pause
    }  
    break;}
    case 1:{//наж одновременно две кн 1 и 2
      if (!StartStopTimer){              
        h1=0;
        m1=0;
        s1=0;
        time = 0;      
      }  
     break;}
     case 5:{//наж кн 1
      if (time == 0){
        h1++;
        if (h1>9){h1=0;}
        s1=0;
        sTime=(unsigned long)(3600*h1+60*m1+s1);      
     }
     break;}
      case 3:{//наж кн 2
       if (time == 0){                    
        m1++;
        if (m1>59){m1=0;}
        s1=0;
        sTime=(unsigned long)(3600*h1+60*m1+s1);        
        }
     break;}
  }
}
void PowerLow(){
//Помимо режимов пониженного энергопотребления,
//колличество потребляемой энергии микроконтроллера можно уменьшить
//отключением неиспользуемых устройств.
//Для отключения периферии микроконтроллера существует регистр PRR:
/*Аналогоцифровой преобразователь
* Если функционирование АЦП разрешено, то он будет работать во всех
* «спящих»  режимах.  Соответственно,  для  снижения  потребляемого  тока
* модуль АЦП необходимо отключать перед переводом микроконтроллера в
* любой из энергосберегающих режимов.
*/
//Writing this bit to one enables the ADC. By writing it to zero, the ADC is turned off. Turning the ADC off while a
//conversion is in progress, will terminate this conversion.
ADCSRA &= ~(1<<ADEN);//Clear bit
//PRR |= (1 << PRTWI) | (1 << PRTIM0)  | (1 << PRTIM1)  | (1 << PRSPI)  | (1 << PRUSART0)  | (1 << PRADC)
PRR |= (1 << PRTWI) | (1 << PRTIM1)  | (1 << PRUSART0)  | (1 << PRADC);// Set bits
DIDR1 |= (1 << AIN1D)  | (1 << AIN0D ); // Set bits - отключения  входных  цифровых буферов
//DIDR1 – Digital Input Disable Register 1
//When this bit is written logic one, the digital input buffer on the AIN1/0 pin is disabled. The corresponding PIN
//Register bit will always read as zero when this bit is set. When an analog signal is applied to the AIN1/0 pin and
//the digital input from this pin is not needed, this bit should be written logic one to reduce power consumption in
//the digital input buffer.

//Watchdog Timer Configuration
//WDTCSR – Watchdog Timer Control Register
MCUSR &= ~(1 << WDRF);// Clear bit
//WDE is overridden by WDRF in MCUSR. This means that WDE is always set when WDRF is set. To clear
//WDE, WDRF must be cleared first
WDTCSR &= ~((1 << WDE)  | (1 << WDIE));// Clear bit - Watchdog Timer Stopped
//IVCE (Interrupt Vector Change Enable): бит разрешения изменения вектора прерывания. Данный бит должен быть установлен, чтобы разрешить изменение бита IVSEL.
//IVCE очищается аппаратно через четыре цикла после его установки или при установке бита IVSEL
MCUCR |= (1 << IVCE);
//IVSEL (Interrupt Vector Select): выбор вектора прерываний.
//Если установлен данный бит, то векторы прерываний перемещаются в начало загрузочного сектора флэш-памяти
//  Установить бит разрешения изменения вектора прерывания (IVCE).
//  В течение четырех машинных циклов внести изменение (записать 1 или 0) в IVSEL, при этом записывая лог.0 в IVCE.
MCUCR |= (1 << IVSEL);
}
void sleepNow(){
/*3.  Power-down (режим микропотребления) - прекращают работу все устройства микроконтроллера кроме тех,
* которые работают в асинхронном режиме.
* Выход из данного режима может осуществляться при аппаратном сбросе, сбросе от системы BOD,
* внешние прерывания, прерывания от сторожевого таймера,
* и прерывание по совпадению адреса по интерфейсу I2C (TWI).
* 4.  Power-save (экономичный) - полностью повторяет Power-down,
* но в нем еще продолжает свою работу таймер/счетчик 2 в асинхронном режиме.
*/
//Power-save
SMCR &= ~(1 << SM2);// Clear bit
SMCR |= (1 << SM0)  | (1 << SM1 ); // Set bits
SMCR |= (1 << SE);// Set bits -  sleep_enable
asm ("sleep");
SMCR &= ~(1 << SE);// Clear bit - sleep_disable
sleep_mode=0;
}
PS
Будет время, нужно разобраться, где напортачил с временем таймера.
Если более 9 часов, то выводится какая то фигня.
PSS
эти строки
delay(250);
digitalWrite(LCD_BL, LOW);

и эту
ISR(PCINT1_vect) {
digitalWrite(LCD_BL, HIGH);

Скорее всего нужно удалить, а то потребление почему то возросло.
 
Изменено:

alexlaw

✩✩✩✩✩✩✩
3 Янв 2020
47
2
Воронеж
Исправил ошибку 9 часов.
Тип данных был неправильным.
В принципе скетч готов.
C++:
/*
 * https://github.com/cbm80amiga/HX1230_SPI
 * https://github.com/cbm80amiga/HX1230_FB
 * https://github.com/cbm80amiga/PropFonts
  HX1230 96x68 LCD connections (header on bottom, from left):
  #1 RST - any digital
  #2 CE  - any digital
  #3 N/C
  #4 DIN - D11/MOSI
  #5 CLK - D13/SCK
  #6 VCC - 3V3 or any digital
  #7 BL  - 3V3 or any digital - не подключен
  #8 GND - GND
*/
#define VerProga "ver-1.02d"
#define LCD_RST 4
#define LCD_CS  3
#define LCD_VCC  8
#define LCD_DIN 11
#define LCD_CLK 13
#define DISP_SLEEP 30

#include "HX1230_SPI.h"

HX1230_SPI lcd(LCD_RST, LCD_CS);
#include "term8x14_font.h"
#include "bold13x20digtop_font.h"
byte tcnt2;
volatile long t,t1;
unsigned long time = 0; // 86390000;
volatile uint8_t time_sleep;
//время для отображения таймера
unsigned long sTime;
uint8_t hours1;
uint8_t minutes1;
uint8_t seconds1;
//время для установок  таймера
long h1=23;
long m1=59;
long s1=0;
char buf[40];
int y=2;
int x=2;
String stringVar;
char charVar[9];
volatile boolean StartStopTimer = false;
volatile boolean sleep_mode = false;
void setup() {
//  Serial.begin(9600);
//  Serial.print("Serial.begin(9600)");
for (int i=2;i<20;i++){
pinMode(i, INPUT_PULLUP);
}
PowerLow();
  pinMode(LCD_VCC, OUTPUT);
  digitalWrite(LCD_VCC, HIGH);
  //светодиод для теста
  //Светодиод PD6 - при срабатывании прерывания по переполнению счетчика меняет свое состояние
  //Светодиод PD5 - при наж люб кнопки и сраб прерывания PCINT1, меняет свое состояние
  //Светодиод PD5 - выкл перед переходом в сон
PORTD &= ~((1 << 5) | (1 << 6));// Clear bit - low
DDRD |= (1 << 5) | (1 << 6);// Set bits - output
  lcd.init();
  lcd.clrScr(); 
  lcd.setDigitMinWd(13);
  setupInterrupt();
  initButton();
  sTime=3600*h1+60*m1+s1;
  time_sleep=0;
}

void loop() {
if (time_sleep>=DISP_SLEEP){
lcd.sleep(true);
time_sleep=DISP_SLEEP;
}
if (time!=0){
t1=(long)(sTime-time);
if (t1<0){
PORTD &= ~(1<<6);//выкл светодиод 
lcd.sleep(false); 
StartStopTimer = false;
TIMSK2 &= ~(1<<TOIE2);//Clear bit - disable the timer - pause 
t1=0;
sleep_mode=1;
}
hours1 = (uint8_t)(t1 / 3600); 
minutes1 = (uint8_t)((t1 / 60) % 60);
seconds1 = (uint8_t)(t1 % 60);
stringVar =String(hours1, DEC)+":"+String(minutes1, DEC)+":"+String(seconds1, DEC);
} else {
stringVar =String(h1, DEC)+":"+String(m1, DEC)+":0"; 
}
stringVar.toCharArray(charVar,sizeof(charVar));
 snprintf(buf,sizeof(buf)-1,charVar);
 lcd.setFont(Bold13x20);
 lcd.printStr(x,y,buf);
 lcd.setFont(Term8x14PL);
 if (!StartStopTimer){lcd.printStr(0, 0, "pause");
 if (time==0)lcd.printStr(0, 0, "pause , set");
 }
 lcd.printStr(25, 6, VerProga);
 while(ASSR & 0x1F); 
 if (sleep_mode)sleepNow();
 delay(250);
 lcd.clrScr();
 
}
//упраление таймером Timer2
void setupInterrupt()
{
   //Ожидание завершения стабилизации внешнего
   // кварцевого генератора часов RTC:
   for (uint8_t i=0; i < 0x40; i++)
   {
      for (int j=0; j < 0xFFFF; j++);
   } 
     /* запрещаем прерывания */
  cli(); 
/* Запрещаем прерывания Timer/Counter2 обнуляя OCIE2х и TOIE2. */
TIMSK2 &= ~((1<<OCIE2A)|(1<<OCIE2B)|(1<<TOIE2));
//Бит EXCLK (6) регистра ASSR разрешает использование внешнего тактового сигнала от кварцевого резонатора 32 кГц
//при записи в него 1
//ASSR |= (1<<EXCLK);
//delay(100);
/* Select clock source */
ASSR |= (1<<AS2);
delay(300);
/* Configure timer2 in normal mode (pure counting, no PWM etc.) */
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
/* Now configure the prescaler to CPU clock divided by 128 */
TCCR2B |= (1<<CS22)  | (1<<CS20); // Set bits
TCCR2B &= ~(1<<CS21);             // Clear bit
tcnt2 = 0;
/* Finally load end enable the timer */
TCNT2 = tcnt2;
while(ASSR & 0x1F);
/*  Обнуляем флаги прерываний Timer/Counter2. */
TIFR2 |= ((1<<OCF2A)|(1<<OCF2B)|(1<<TOV2));
PORTD  |= (1<<6);//заж светодиод
//TIMSK2 |= (1<<TOIE2);
     /* разрешаем прерывания */
  sei();
}
/*
* Install the Interrupt Service Routine (ISR) for Timer2 overflow.
* This is normally done by writing the address of the ISR in the
* interrupt vector table but conveniently done by using ISR()  */
ISR(TIMER2_OVF_vect) {
// Как запустить неработающий часовой кварц (32768 Гц)
//http://www.getchip.net/posts/052-kak-zapustit-nerabotayushhijj-chasovojj-kvarc-32768-gc/
/* Reload the timer */
TCNT2 = tcnt2;
PORTD  ^= (1 << 6);//инвентировать бит
time++;
time_sleep++;
sleep_mode=1;
}
//The External Interrupts are triggered by the INT0 and INT1 pins or any of the PCINT23...0 pins.
//The pin change interrupt PCI1 will trigger if any enabled PCINT[14:8] pin
//toggles.
//This implies that these interrupts can be used for
//waking the part also from sleep modes other than Idle mode.
void initButton() {
//pc0 pc1 pc2  кнопки
PORTC |= (1 << 0) | (1 << 1 ) | (1 << 2 );// Set bits - pullup
DDRC &= ~((1 << 0)  | (1 << 1)  | (1 << 2));// Clear bit - input
//PCMSK1 – Pin Change Mask Register 1
//PCMSK1 Определяют условие генерации прерывания PCINT1. Если какойлибо
//бит установлен в 1, то изменение состояния соответствующего вывода
//вызовет генерацию прерывания
PCMSK1 |= (1 << 0) | (1 << 1 ) | (1 << 2 );// Set bits
//PCICR – Pin Change Interrupt Control Register
//прерывание по изменению состояния вывода 0 или 1 или 2
PCICR  |=  (1 << PCIE1);// Set bits - When the PCIE1 bit is set (one) and the I-bit in the Status Register (SREG) is set (one), pin change interrupt 1 is enabled
}
//т.к. тактирование идет от кварца 32.768 кГц - событие должно иметь место вплоть до срабатывания прерывания
ISR(PCINT1_vect) {
  time_sleep=0;
  lcd.sleep(false);     
  switch(PINC & 0x07){   
    case 6:{
    if (!StartStopTimer) {//наж кн 0
      StartStopTimer = true;
      TIMSK2 |= (1<<TOIE2);// Set bits - enable the timer - start     
    } else {
      StartStopTimer = false;
      TIMSK2 &= ~(1<<TOIE2);//Clear bit - disable the timer - pause
    }   
    break;}
    case 1:{//наж одновременно две кн 1 и 2
      if (!StartStopTimer){               
        h1=0;
        m1=0;
        s1=0;
        time = 0;       
      }   
     break;}
     case 5:{//наж кн 1
      if (!StartStopTimer){
      if (time == 0){
        h1++;
        if (h1>23){h1=0;}
        s1=0;
        sTime=3600*h1+60*m1+s1;       
     }
      }
     break;}
      case 3:{//наж кн 2
       if (!StartStopTimer){
       if (time == 0){                     
        m1++;
        if (m1>59){m1=0;}
        s1=0;
        sTime=3600*h1+60*m1+s1;         
        }
       }
     break;}
  }
PORTD  ^= (1 << 5);//инвентировать бит 
}
void PowerLow(){
//Помимо режимов пониженного энергопотребления,
//колличество потребляемой энергии микроконтроллера можно уменьшить
//отключением неиспользуемых устройств.
//Для отключения периферии микроконтроллера существует регистр PRR:
/*Аналогоцифровой преобразователь
* Если функционирование АЦП разрешено, то он будет работать во всех
* «спящих»  режимах.  Соответственно,  для  снижения  потребляемого  тока
* модуль АЦП необходимо отключать перед переводом микроконтроллера в
* любой из энергосберегающих режимов.
*/
//Writing this bit to one enables the ADC. By writing it to zero, the ADC is turned off. Turning the ADC off while a
//conversion is in progress, will terminate this conversion.
ADCSRA &= ~(1<<ADEN);//Clear bit
//PRR |= (1 << PRTWI) | (1 << PRTIM0)  | (1 << PRTIM1)  | (1 << PRSPI)  | (1 << PRUSART0)  | (1 << PRADC)
PRR |= (1 << PRTWI) | (1 << PRTIM1)  | (1 << PRUSART0)  | (1 << PRADC);// Set bits
DIDR1 |= (1 << AIN1D)  | (1 << AIN0D ); // Set bits - отключения  входных  цифровых буферов
//DIDR1 – Digital Input Disable Register 1 
//When this bit is written logic one, the digital input buffer on the AIN1/0 pin is disabled. The corresponding PIN
//Register bit will always read as zero when this bit is set. When an analog signal is applied to the AIN1/0 pin and
//the digital input from this pin is not needed, this bit should be written logic one to reduce power consumption in
//the digital input buffer.

//Watchdog Timer Configuration
//WDTCSR – Watchdog Timer Control Register
MCUSR &= ~(1 << WDRF);// Clear bit
//WDE is overridden by WDRF in MCUSR. This means that WDE is always set when WDRF is set. To clear
//WDE, WDRF must be cleared first
WDTCSR &= ~((1 << WDE)  | (1 << WDIE));// Clear bit - Watchdog Timer Stopped
//IVCE (Interrupt Vector Change Enable): бит разрешения изменения вектора прерывания. Данный бит должен быть установлен, чтобы разрешить изменение бита IVSEL.
//IVCE очищается аппаратно через четыре цикла после его установки или при установке бита IVSEL
MCUCR |= (1 << IVCE);
//IVSEL (Interrupt Vector Select): выбор вектора прерываний.
//Если установлен данный бит, то векторы прерываний перемещаются в начало загрузочного сектора флэш-памяти
//  Установить бит разрешения изменения вектора прерывания (IVCE).
//  В течение четырех машинных циклов внести изменение (записать 1 или 0) в IVSEL, при этом записывая лог.0 в IVCE.
MCUCR |= (1 << IVSEL);
}
void sleepNow(){
 /*3.  Power-down (режим микропотребления) - прекращают работу все устройства микроконтроллера кроме тех,
* которые работают в асинхронном режиме.
* Выход из данного режима может осуществляться при аппаратном сбросе, сбросе от системы BOD,
* внешние прерывания, прерывания от сторожевого таймера,
* и прерывание по совпадению адреса по интерфейсу I2C (TWI).
* 4.  Power-save (экономичный) - полностью повторяет Power-down,
* но в нем еще продолжает свою работу таймер/счетчик 2 в асинхронном режиме.
*/
//Power-save
SMCR &= ~(1 << SM2);// Clear bit
SMCR |= (1 << SM0)  | (1 << SM1 ); // Set bits
PORTD &= ~(1<<5);//выкл светодиод
SMCR |= (1 << SE);// Set bits -  sleep_enable
asm ("sleep");
SMCR &= ~(1 << SE);// Clear bit - sleep_disable
sleep_mode=0;
}
Схема
Mega328_HX1230_lib_Timer2_v102d.png


Познавательная статья, в т.ч. о конденсаторах на резонаторе - RTC без RTC


Возвращаюсь к конструкции защелки.
 
Изменено:

alexlaw

✩✩✩✩✩✩✩
3 Янв 2020
47
2
Воронеж
Хочу поделиться следующими экспериментом, может кому будет полезно.
Т.к. кварц перестал запускаться, я подумал, что это следствие пайки его прямо на ноги МК.
Поэтому решил подать внешний тактовый сигнал, чобы проверить Мегу (не спалил ли я порты)
Самое простое, что пришло в голову - это таймер555.
Нашел калькулятор, там же схема с расчетом частоты
555-1.png
На что хотел обратить внимание, у меня заработало, только, когда я подал сигнал на XTAL2(PB7).
IMG_20200217_182100.jpg

Частота получилась ниже, но это может из за питания таймера555 - 3.3в (отдельное)
Нашел другую схему потом переделаю
555-2.png
PS
Схема простого генератора на двух транзисторах подойдет для проверки частоты низкочастотных «часовых» кварцевых резонаторов
Сверхэкономичный кварцевый генератор запускается при напряжении 2.4 В
 
Изменено: