Портсигар

#42
А кондёр с каждого вывода на землю паял?
Может не запускаться из за этого.
попробуй корпус кварца соединить с GND
Все же актуально оказалась это - Как запустить неработающий часовой кварц (32768 Гц)
Почистил плату от флюса - заработала, как с конденсаторами так и без, как с землей так и без.
Можно двигаться дальше.
 
#43
Закралась такая мысль.
Будет ли срабатывать прерывание по переполнения счетчика Timer2 в режиме Power Sleep и при этом не пробуждая МК от сна? Т.е. можно ли помигать светодиом, спящим МК?
Проверить это смогу только в субботу, но интересно знать сейчас
 
#44
Скорее нет, чем да. Ядро то спит. А всей периферией управляет ядро. Вот у STM может получится через DMA. Да и то вряд ли. Не задумывался над этим.
 

Wan-Derer

Модератор
Команда форума
31.07.2018
1 269
215
73
Москва
wan-derer.ru
#45
@Эдуард Анисимов, вообще-то, таймеры это отдельные (от вычислительного ядра) блоки, которые вполне могут работать автономно, пробуждая ядро запросом на прерывание. Надо купить доки на тему режимов сна чтобы понять что там да как.
И да, фреймворком Ардуино многие полезные вещи не поддерживаются.
 
#46
@Эдуард Анисимов, вообще-то, таймеры это отдельные (от вычислительного ядра) блоки, которые вполне могут работать автономно, пробуждая ядро запросом на прерывание. Надо купить доки на тему режимов сна чтобы понять что там да как.
И да, фреймворком Ардуино многие полезные вещи не поддерживаются.
У него был вопрос
Т.е. можно ли помигать светодиом, спящим МК?
Я думаю мой ответ верен. Так как Таймер да, работает, но единственное что он может, это разбудить ядро. А вот уже ядро и будет моргать светодиодом.
Скорее даже было бы правильнее ответить - спящим нет, но если таймер его разбудит, то да.
 
#47
Да, ваш ответ верен.
Но как вы понимаете "мигать светодиодом" - это не самоцель.
Цель запустить RTC не зависимо от ядра, Но производитель что то не допилил у себя,
а иначе зачем делать просто 8 битный счетчик на отдельно кристалле, а не полноценный RTC со своими регистрами.
Ну да ладно.
Поставил новую батарейку CR2025, таймер на 9 часов (светодиод для визуализации)-посмотрю, что получится
IMG_20200209_151445.jpg
Код:
/*
* 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 мкФ - на каждую кнопку
 
Последнее редактирование:
#48
Еще чуть модифицировал скетч.
Дисплей после 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
После нажатия любой кнопки - на дисплей подается питание и команда проснуться.
Код:
/*
* 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);

Скорее всего нужно удалить, а то потребление почему то возросло.
 
Последнее редактирование:
#49
Исправил ошибку 9 часов.
Тип данных был неправильным.
В принципе скетч готов.
Код:
/*
 * 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


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

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