Простые часы

Материал из LicrymWiki
Перейти к: навигация, поиск

Даже наверное не просто простые, а супер простые. Данный проект на микроконтроллере можно назвать проектом выходного дня, так как на разработку и создание этих часов с нуля ушло 1,25 дня, а учитывая, что у вас будет под рукой готовый код, то вы управитесь быстрее.

Нам понадобятся: Кварцевый резонатор на 16 МГц, микроконтроллер ATTINY2313, 2 кнопки, 2 конденсатора на 22 пф, конденсатор на 220 нф, линейный стабилизатор питания 7805, 4 транзистора КТ817Б, ну и четыре семисегментных светодиодных индикатора, у меня это SA15–11GWA (высота цифр 38 мм) и горстка резисторов. Приведенный список соответствует той конструкции, что на фотографиях. Вы можете использовать иные комплектующие (более крупные индикаторы, другой микроконтроллер и т.д.), и тогда придется пересчитать некоторые сопротивления. В общем простор для творчества большой. Отечественные транзисторы пришлось использовать, поскольку под рукой ничего другого не было, если бы была возможность выбирать, то я бы поставил полевые транзисторы.

Итак, имеющиеся компоненты:

Prostie chasy components.jpg

Микроконтроллер обошелся в 41 руб, индикаторы по 52,8 руб за штуку. Всего получается 252,2 руб. Остальное было извлечено из запасов, но в любом случае бюджет бы не превысил бы 300 рублей. Исходя из имеющихся компонентов была изготовлена печатная плата, по лазерно-утюжной технологии, которая уже описывалась на портале.

Вид печатной платы:

Prostie chasy printed cir board.jpg

Далее следует сборка и прошивка программного обеспечения. На заднем плане знакомый уже вам блок питания

Вид часов в сборе:

Prostie chasy assembled.jpg

Вид часов в полумраке:

Prostie chasy in dark.jpg

А теперь рассмотрим схему и разберемся как это всё работает.

Схема (Пользователь Иван подписал на схеме названия сегментов, спасибо):

Prostie chasy scheme2.jpg

Микроконтроллер тактируется кварцем с частотой 16 МГц. В качестве счетчика времени, внутри микроконтроллера запущен 16 битный таймер с предделителем 256 (т.е. частота отсчетов таймера 62500 Гц), настроенный на создание прерывания по достижении счетчиком значения 625. Таким образом, мы получаем прерывания ровно 100 раз в секунду. Значение времени хранится в глобальных переменных, и каждое прерывание мы увеличиваем значение миллисекунд на 1. Если количество миллисекунд достигает 100, то мы увеличиваем на 1 значение секунд, а значением миллисекунд сбрасываем. И так далее вплоть до десятков часов, которые сбрасываются по достижении 24 без увеличения следующего разряда. Часы предельно простые, поэтому не считают ни дату, ни перевод на зимнее/летнее время и т.д. Данные функции можно реализовать программно, без изменения аппаратной части, поэтому остаются для реализации желающим.

Разобравшись с таймером и прерываниями мы получаем значение текущего времени в глобальных переменных. Теперь займемся выводом этих значений. Так как количество портов микроконтроллера ограничено, то будем эксплуатировать инерционность зрения. Катоды всех 4 индикаторов соединены параллельно, а аноды коммутируются отдельно, что позволяет нам в любой момент времени вывести любую цифру на любой индикатор. Быстро переключая порт B, к которому подключены катоды и быстро переключая аноды мы можем создать видимость, что у нас работают все 4 цифры, хотя единовременно работает только одна. Иными словами, если текущее время 12:51, то мы выводим цифру 1 на первый индикатор, спустя малый промежуток времени (у меня 1 мс) выводим цифру 2 на второй индикатор, спустя 1 мс выводим 5 на 3 индикатор, спустя 1 мс выводим 1 на 4 индикатор и так далее по кругу.

Кнопки опрашиваются после каждого цикла отображения (примерно 40 раз в сек), обработка нажатия снабжена антидребезгом и «защелкой» в виде флага, что позволяет считать именно нажатия не отвлекаясь на удержание.

Программа:

/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.7 beta 5 Professional
Automatic Program Generator
© Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project : Simple AVR Clock
Version : 
Date    : 01.05.2008
Author  : Spiritus Sancti                     
Company : licrym.org                
Comments: 


Chip type           : ATtiny2313
Clock frequency     : 16,000000 MHz
Memory model        : Tiny
External SRAM size  : 0
Data Stack size     : 32
*****************************************************/

#include <tiny2313.h>
#include <delay.h>  
#define digit_display_time 1

unsigned char milliseconds, seconds, ten_seconds, minutes, ten_minutes, hours, ten_hours;
bit button_pressed1, button_pressed2;


// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)    //Прерывание происходит 100 раз в сек, 
сохраняем в глобальные переменные текущее время
{ milliseconds++;
  TCNT1H=0x00;
  TCNT1L=0x00;

  if (milliseconds >= 100 )
  {
  milliseconds = 0;
  seconds++;
  };
   
  if (seconds >= 10)
  {
  seconds = 0;
  ten_seconds++;
  }; 
  
  if (ten_seconds >= 6)
  {
  ten_seconds = 0;
  minutes++;
  };
   
  if (minutes >= 10)
  {
  minutes = 0;
  ten_minutes++;
  };  
  
  if (ten_minutes >= 6)
  {
  ten_minutes = 0;
  hours++;
  };

  if (hours >= 10)
  {
  hours = 0;
  ten_hours++;
  };

  if (ten_hours >= 2 && hours == 4)
  {
  ten_hours = 0;
  hours=0;
  };   
  

}



void main(void)
{
unsigned char digits[10] = {18, 159, 56, 28, 149, 84, 80, 31, 16, 20};     //массив для генерации 
цифр. Какой элемент массива будет отправлен в порт, такая цифра и загорится.


// Crystal Oscillator division factor: 1

CLKPR=0x80;
CLKPR=0x00;


// Input/Output Ports initialization
// Port A initialization
// Func2=In Func1=In Func0=In 
// State2=T State1=T State0=T 
PORTA=0x00;
DDRA=0x00;

// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out 
// State7=1 State6=1 State5=1 State4=1 State3=1 State2=1 State1=1 State0=1 
PORTB=0xFF;
DDRB=0xFF;

// Port D initialization
// Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=In Func0=In 
// State6=0 State5=0 State4=0 State3=0 State2=0 State1=P State0=P 
PORTD=0x03;
DDRD=0x7C;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 62,500 kHz
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x04;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x02;
OCR1AL=0x70;
OCR1BH=0x00;
OCR1BL=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
GIMSK=0x00;
MCUCR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x40;

// Universal Serial Interface initialization
// Mode: Disabled
// Clock source: Register & Counter=no clk.
// USI Counter Overflow Interrupt: Off
USICR=0x00;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;

// Global enable interrupts
#asm("sei")

while (1)
      {
      PORTD |=1<<5;                              //включаем первый индикатор 
      PORTB = digits[ten_hours];                 //выводим на него десятки часов
      delay_ms(digit_display_time);              //ждем, время индикации одного разряда задается в заголовке программы
      PORTD &=~(1<<5);                           //выключаем первый индикатор и переходим дальше и так в цикле для каждого из 4 разрядов
      PORTD |=1<<4;
      PORTB = digits[hours]; 
      if (milliseconds >= 50) PORTB &=~(1<<4); else PORTB|=1<<4;  //моргание точки
      delay_ms(digit_display_time);
      PORTD &=~(1<<4); 
      PORTD |=1<<3;
      PORTB = digits[ten_minutes];
      delay_ms(digit_display_time);
      PORTD &=~(1<<3); 
      PORTD |=1<<6;
      PORTB = digits[minutes];
      delay_ms(digit_display_time);
      PORTD &=~(1<<6);         
      
      //а вот теперь проверим кнопочки в стиле часов Электроника 13
      
      if ((PIND & 1<<0) == 0 && button_pressed1 == 0)                     //Если нажата кнопка 1
      { 
      delay_ms(1);
      hours++; 
      button_pressed1 = 1;
      };   
      
      if ((PIND & 1<<0) == 1) button_pressed1=0;                          //Если отпущена то
 сбрасываем флаг
      

      
      if ((PIND & 1<<1) == 0 && button_pressed2 == 0)                     //Если нажата  кнопка 2
      { 
      delay_ms(1);
      minutes++; 
      button_pressed2 = 1;
      };   
      
      if (PIND & 1<<1) button_pressed2=0;
     
           
                    

      };
}



Автор проекта: Spiritus
За основу взят: -
Лицензия распространения: Creative Commons BY-NC-SA

[править] Собрано читателями

[править] windcool

My simple clock 001.jpg

My simple clock 002.jpg

My simple clock 003.jpg

My simple clock 004.jpg

My simple clock 005.jpg

Часы были собраны по схеме, аналогичной схеме автора портала. Не были установлены токоограничивающие резисторы в цепях сегментов индикаторов. Конструкция, как видно из фотографий содержит макетку с установленными на ней индикаторами и транзисторами управления разрядами, а также макетку с Мк и обвязкой. Плата с МК жестко закреплена на обратной стороне платы индикаторов, что способствует уменьшению габаритов готовых часов.



Автор проекта: windcool, 39 region, Slavsk (windcool[псина]rambler.ru)
За основу взят: Эта страничка
Лицензия распространения: Creative Commons BY-NC-SA

Отдельное спасибо автору портала за помощь в осуществлении данного проекта


[править] Urboss

Suc54060.jpg

Suc54063.jpg

Suc54065.jpg

Suc54066.jpg



Автор проекта: Urboss
За основу взят: Эта страничка
Лицензия распространения: Creative Commons BY-NC-SA