Novinka:Univerzální časovač
(Kategorie: Mikroprocesory)
Napsal Kosta
17.01.2013 00:00

Časovač odečítá od nastaveného času k nule. Posledních deset sekund je indikováno zvukovým signálem. Ovládání je třemi tlačítky "+", "-", "Start/Stop". Nastavený čas je zobrazen na dvou sedmi segmentovkách. Až doposud nic zvláštního.

Zajímavý je však rozsah možného nastavení - jedna sekunda až devadesát devět hodin. No není to dost univerzální? Projekt je určen pro Arduino, nic včak nebráni jeho použití samostatně, bez této destičky.

Zdrojový kód

#include <EEPROM.h>void setup() {
  ind_setup();
  kbd_setup();
  out_setup();
  config_setup();
}

void loop() {
  ind_refresh();
  ind_update();
  kbd_update();
  timer_update();
  out_update();
  config_update();
  beep_update();
  delay(10);
}

//Config///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct {
  unsigned long time;
  byte crc;
} config;
#define CONFIG_WRITE_DELAY 500
unsigned int config_timer;
void config_setup() {
  config_read();
  if (config.time > (3600 * 99)) config.time = 1;
}
void config_update() {
  if (config_timer > 0) {
    config_timer--;
    if (config_timer == 0) {
      config_write();
    }
  }
}
void config_read() {
  byte *b = (byte *)&config;
  for (byte i=0; i<sizeof(config); i++)
    *b++ = EEPROM.read(i);
}
void config_write() {
  byte *b = (byte *)&config;
  for (byte i=0; i<sizeof(config); i++)
    EEPROM.write(i, *b++);
}
void config_write_reset() {
  config_timer = CONFIG_WRITE_DELAY;
}

//Timing///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
enum {SEC,MINSEC,MIN,HR}; //time mode
const unsigned int timer_inc[] = {1,10,60,3600};
const unsigned long timer_mode_min[] = {0,60,10*60,60*60};
unsigned long timer = 0;
byte timer_div = 0;
//check if timer is loaded and counting
byte timer_counting() {
  return (timer > 0);
}
//get timer mode (0-seconds, 1-min.sec, 2-min, 3-hr)
byte timer_mode(unsigned long t) {
  if (t < 60) return SEC;
  else if (t < 10 * 60) return MINSEC;
  else if (t < 60 * 60) return MIN;
  else return HR;
}
//get 2-digit value for timer
byte timer_to_byte(unsigned long t) {
  switch (timer_mode(t)) {
    case SEC: return t;
    case MINSEC: return ((t / 60) * 10) + ((t % 60) / 10);
    case MIN: return (t / 60);
    case HR: return (t / 3600);
   }
}
//update timer
void timer_update() {
  if (timer_counting()) {
    if (++timer_div >= 100) {
      timer_div = 0;
      timer--;
      if (timer == 0) {
        //play stop sound
        beep_timer_end();
      } else {
        if (timer <= 10) beep_timer_ending();
      }
    }
  }
}
//set and start timer
void timer_start(unsigned long t) {
  timer = t;
  timer_div = 0;
}

//Indication///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
enum {SEGA=1,SEGB=2,SEGC=4,SEGD=8,SEGE=16,SEGF=32,SEGG=64,SEGH=128}; //segments masks
enum {SEGApin=2,SEGHpin=9}; //segments pins
//HEX 7-seg digits
const byte ind_digits[]={
  SEGA | SEGB | SEGC | SEGD | SEGE | SEGF, //0
  SEGB | SEGC, //1
  SEGA | SEGB | SEGD | SEGE | SEGG, //2
  SEGA | SEGB | SEGC | SEGD | SEGG, //3
  SEGB | SEGC | SEGF | SEGG, //4
  SEGA | SEGC | SEGD | SEGF | SEGG, //5
  SEGA | SEGC | SEGD | SEGE | SEGF | SEGG, //6
  SEGA | SEGB | SEGC, //7
  SEGA | SEGB | SEGC | SEGD | SEGE | SEGF | SEGG, //8
  SEGA | SEGB | SEGC | SEGD | SEGF | SEGG, //9
  SEGA | SEGB | SEGC | SEGE | SEGF | SEGG, //A
  SEGC | SEGD | SEGE | SEGF | SEGG, //b
  SEGA | SEGD | SEGE | SEGF, //C
  SEGB | SEGC | SEGD | SEGE | SEGG, //d
  SEGA | SEGD | SEGE | SEGF | SEGG, //E
  SEGA | SEGE | SEGF | SEGG, //F
};
const byte ind_com[] = {10,A1}; //common anode pins
//number of digits
#define IND_SIZE 2
byte ind_buf[IND_SIZE]; //indication buffer
byte ind_cnt; //current digit counter
//setup indication
void ind_setup() {
  //segment pins
  for (byte pin=SEGApin; pin<=SEGHpin; pin++) {
    pinMode(pin, OUTPUT);
    digitalWrite(pin, HIGH);
  }
  //common anodes pins
  for (byte pin=0; pin<IND_SIZE; pin++) {
    pinMode(ind_com[pin], OUTPUT);
    digitalWrite(ind_com[pin], HIGH);
  }
  //clear buffer
  for (byte i=0; i<IND_SIZE; i++) ind_buf[i] = 0;
}
byte ind_digit(byte digit) {
  return ind_digits[digit];
}
//set segments
void ind_set_segs(byte digit) {
  byte mask = 1;
  for (byte pin=SEGApin; pin<=SEGHpin; pin++) {
    digitalWrite(pin, !(digit & mask));
    mask <<= 1;
  }
}
//select digit (0xFF to deselect all)
void ind_set_com(byte num) {
  if (num == 0xFF) { //all OFF
    for (byte com=0; com<IND_SIZE; com++) digitalWrite(ind_com[com], HIGH);
  } else {
    digitalWrite(ind_com[num], LOW);
  }
}
//convert lower half-byte to 7-segment HEX
byte to_hex(byte data) {
  return ind_digit(data & 0xF);
}
//convert decimal 0..99 to BCD 0..0x99
byte to_bcd(byte data) {
  byte result = data % 10;
  data /= 10;
  result += (data % 10) << 4;
  return result;
}
//write 8-bit HEX to indication buffer
void ind_wr_H8(byte data, byte pos) {
  ind_buf[pos] = to_hex(data >> 4);
  ind_buf[pos + 1] = to_hex(data);
}
//refresh indication
void ind_refresh() {
  ind_set_com(0xFF);
  if (++ind_cnt >= IND_SIZE) ind_cnt = 0;
  ind_set_segs(ind_buf[ind_cnt]);
  ind_set_com(ind_cnt);
}
void ind_update() {
  unsigned long t = (!timer_counting()) ? config.time : timer;
  ind_wr_H8(to_bcd(timer_to_byte(t)), 0);
  if (ind_buf[0] == ind_digits[0]) ind_buf[0] = 0;
  if (timer_div < 50) {
    switch (timer_mode(t)) {
      case SEC: break;
      case MINSEC: ind_buf[0] |= SEGH; break;
      case MIN: ind_buf[1] |= SEGH; break;
      case HR: ind_buf[0] |= SEGH; ind_buf[1] |= SEGH; break;
    }
  }
}

//Keyboard/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
byte kbd_buf[2]; //current/previous keyboard states
byte kbd_cnt; //keypress counter
enum {KBD_UP=1, KBD_DOWN=2, KBD_SET=3}; //key codes
enum {KBD_CNT_SHORT=5, KBD_CNT_LONG=100, KBD_CNT_START=250, KBD_REPEAT=10}; //key press counter values
#define KBD_CNT_REPEAT (KBD_CNT_LONG - KBD_REPEAT)
void kbd_setup() {
  pinMode(12, INPUT_PULLUP);
  digitalWrite(12, HIGH);
  pinMode(13, INPUT_PULLUP);
  digitalWrite(13, HIGH);
}
byte kbd_read() {
  return (!digitalRead(12) << 1) | !digitalRead(13);
}
byte kbd_press(byte code, byte cnt) {
    return (kbd_buf[1] == code) && (kbd_cnt == cnt);
}
byte kbd_press2(byte code, byte cnt1, byte cnt2) {
    return (kbd_buf[1] == code) && ((kbd_cnt == cnt1) || (kbd_cnt == cnt2));
}
void kbd_update(void) {
  kbd_buf[0] = kbd_read();
  if (kbd_buf[1] != kbd_buf[0]) {
    kbd_cnt = 0;
    kbd_buf[1] = kbd_buf[0];
  } else {
    if (kbd_cnt < 255) kbd_cnt++;
    if (!timer_counting()) {
      if (kbd_press2(KBD_UP, KBD_CNT_SHORT, KBD_CNT_LONG)) {
        if (kbd_cnt == KBD_CNT_LONG) kbd_cnt = KBD_CNT_REPEAT;
        else beep_key_press();
        config.time += timer_inc[timer_mode(config.time)];
        if (config.time > (3600UL * 99)) config.time = (3600UL * 99);
        config_write_reset();
        beep_stop();
      }
      else if (kbd_press2(KBD_DOWN, KBD_CNT_SHORT, KBD_CNT_LONG)) {
        if (kbd_cnt == KBD_CNT_LONG) kbd_cnt = KBD_CNT_REPEAT;
        else beep_key_press();
        if (config.time > 1) {
          byte m = timer_mode(config.time);
          if ((m > 0)&&(config.time == timer_mode_min[m])) m--;
          config.time -= timer_inc[m];
          config_write_reset();
        }
        beep_stop();
      }
      //start timer
      else if (kbd_press(KBD_SET, KBD_CNT_SHORT)) {
        timer_start(config.time);
        beep_stop();
        beep_timer_start();
      }
    } else {
      //stop timer
      if (kbd_press(KBD_SET, KBD_CNT_SHORT)) {
        timer = 0;
        beep_timer_stop();
      }
    }
  }
}

//Out/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define OUT_PIN A0
void out_setup() {
  pinMode(OUT_PIN, OUTPUT);
  digitalWrite(OUT_PIN, LOW);
}
void out_update() {
  if (timer_counting()) digitalWrite(OUT_PIN, HIGH);
  else digitalWrite(OUT_PIN, LOW);
}

//Beeper//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define BEEP_FREQ 2500
unsigned int beep_cnt;
void beep(byte len) {
  if (len == 0) noTone(11);
  else if (len == 1) tone(11, BEEP_FREQ);
  else tone(11, BEEP_FREQ, len);
}
void beep_stop() {
  beep_cnt = 0;
  beep(0);
}
void beep_update() {
  if (beep_cnt > 0) {
    beep_cnt--;
    if (beep_cnt == 0) beep(0);
    else {
//      beep((beep_cnt & 0x20) && (beep_cnt & 0x4) && (beep_cnt & 0x02));
      beep((beep_cnt & 0x40) && (beep_cnt & 0x08));
    }
  }
}
void beep_timer_end() {
  beep_cnt = 1000;
}
void beep_timer_start() {
  beep(100);
}
void beep_timer_stop() {
  beep(100);
}
void beep_timer_ending() {
  beep(50);
}
void beep_key_press() {
  beep(30);
}


Zdroj



Tato novinka je z -MCU-mikroelektronika
( http://mcu.cz/news.php?extend.3286 )