1
/***************************************************************************
2
* Copyright (C) 2018 by hovercraft: *
3
* https://github.com/hovercraft-github *
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU General Public License as published by *
7
* the Free Software Foundation; either version 2 of the License, or *
8
* (at your option) any later version. *
10
* This program is distributed in the hope that it will be useful, *
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13
* GNU General Public License for more details. *
15
* You should have received a copy of the GNU General Public License *
16
* along with this program; if not, write to the *
17
* Free Software Foundation, Inc., *
18
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19
***************************************************************************/
21
#include <pic16f689.h>
24
/***************************************************************************
26
* This source code is optimized for use with SDCC compiler and piklab IDE *
28
****************************************************************************/
30
/* ----------------------------------------------------------------------- */
31
/* Configuration bits: adapt to your setup and needs */
32
typedef unsigned int word;
33
word __at 0x2007 CONFIG = _INTRC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOR_OFF & _IESO_ON & _FCMEN_ON;
56
#define SEGMENTS_OFF 0
57
#define SEGMENTS_0 0x3F
58
#define SEGMENTS_1 0x06
59
#define SEGMENTS_2 0x5B
60
#define SEGMENTS_3 0x4F
61
#define SEGMENTS_4 0x66
62
#define SEGMENTS_5 0x6D
63
#define SEGMENTS_6 0x7D
64
#define SEGMENTS_7 0x07
65
#define SEGMENTS_8 0x7F
66
#define SEGMENTS_9 0x6F
67
#define SEGMENTS_E 0x79
79
#define KEY_TOGGLE_MASK 2 // RC1
80
#define KEY_UP_MASK 0x10 // RC4
81
#define KEY_DOWN_MASK 0x20 // RC5
82
#define KEY_OK_MASK 0x40 // RC6
83
#define KEYS_MASK (KEY_TOGGLE_MASK | KEY_UP_MASK | KEY_DOWN_MASK | KEY_OK_MASK)
85
#define EEPROM_IX_FLAG 0
86
#define EEPROM_IX_MINUTES 1
93
typedef enum KeyPressedComb {
95
PRESSED_TOGGLE=KEY_TOGGLE_MASK,
96
PRESSED_UP=KEY_UP_MASK,
97
PRESSED_DOWN=KEY_DOWN_MASK,
98
PRESSED_CANCEL=KEY_UP_MASK | KEY_DOWN_MASK,
99
PRESSED_OK=KEY_OK_MASK,
102
typedef enum OpModes {
105
MODE_EditMsd, // edit the most significant digit
106
MODE_EditLsd, // edit the least significant digit
109
volatile uint8_t clk = 0;
110
volatile uint8_t sec = 0;
111
volatile uint8_t min_left = 10;
112
uint8_t mode = MODE_Work;
114
/* Adjust to your clock frequency (in Hz). */
115
/* Instructions per millisecond. */
116
#define INSNS_PER_MS ((4U*1000U/4000U*1000U))
117
/* Delay loop is about 10 cycles per iteration. */
118
#define LOOPS_PER_MS (INSNS_PER_MS / 10U)
119
void delay_ms(uint16_t ms) {
122
/* Inner loop takes about 10 cycles per iteration + 4 cycles setup. */
123
for (u = 0; u < LOOPS_PER_MS; u++) {
124
/* Prevent this loop from being optimized away. */
130
uint8_t ee_write_byte(uint8_t address, uint8_t *_data){
131
uint8_t int_enabled = GIE;
134
// start write sequence as described in datasheet, page 91
137
WREN = 1; // enable writes to data EEPROM
138
GIE = 0; // disable interrupts
141
WR = 1; // start writing
148
GIE = int_enabled; // restore the interrupts enable state
152
void ee_read_byte(uint8_t address, uint8_t *_data){
160
void store_minutes(void) {
163
ee_write_byte(EEPROM_IX_FLAG, &flag);
164
ee_write_byte(EEPROM_IX_MINUTES, &min_left);
167
void retrieve_minutes(void) {
169
ee_read_byte(EEPROM_IX_FLAG, &flag);
174
ee_read_byte(EEPROM_IX_MINUTES, &min_left);
178
uint8_t scanKeys(void) {
180
// Switch key pins to input mode
185
PORTC = SEGMENTS_OFF;
186
keys_state = (~keys_state) & KEYS_MASK;
187
// Switch key pins to output mode
188
if ((keys_state & KEY_UP_MASK) && (keys_state & KEY_DOWN_MASK))
190
switch (keys_state) {
192
return PRESSED_TOGGLE;
195
return PRESSED_CANCEL;
212
uint8_t bin2decimal(uint8_t n, uint8_t pos) {
214
//d2...d0 - decimal numbers
215
uint8_t d2 = 0, d1, d0;
221
d0 = n - d2 * 100 - d1 * 10;
223
if (pos == COL_IX_Lsd)
228
void segments_off(void) {
231
PORTC = SEGMENTS_OFF;
234
void segments_on(char c, uint8_t col_ix) {
270
PORTC = SEGMENTS_OFF;
273
if (col_ix == COL_IX_Msd)
279
volatile uint8_t toggle = 0;
280
volatile uint8_t kbstate_prev = PRESSED_NONE;
282
void show_digit(void) {
286
kbstate = scanKeys();
287
if ((kbstate != PRESSED_NONE) && (kbstate != kbstate_prev)) {
307
value = bin2decimal(min_left, COL_IX_Lsd) + 1;
310
min_left = bin2decimal(min_left, COL_IX_Msd)*10 + value;
313
value = bin2decimal(min_left, COL_IX_Lsd);
318
min_left = bin2decimal(min_left, COL_IX_Msd)*10 + value;
339
value = bin2decimal(min_left, COL_IX_Msd) + 1;
342
min_left = bin2decimal(min_left, COL_IX_Lsd) + value*10;
345
value = bin2decimal(min_left, COL_IX_Msd);
350
min_left = bin2decimal(min_left, COL_IX_Lsd) + value*10;
356
if (kbstate == PRESSED_OK) {
363
} else if (kbstate == PRESSED_TOGGLE) {
374
if (kbstate == PRESSED_TOGGLE) {
382
kbstate_prev = kbstate;
385
value = bin2decimal(min_left, toggle);
386
segments_on('0' + value, toggle);
387
} else if (toggle == 1) {
389
value = bin2decimal(min_left, toggle);
390
segments_on('0' + value, toggle);
393
if (mode == MODE_EditLsd || mode == MODE_EditMsd) {
394
if (toggle < 100) { // dim the edited position
395
if (mode == MODE_EditLsd) {
396
if (toggle % 2 == COL_IX_Msd)
397
segments_on('0' + bin2decimal(min_left, COL_IX_Msd), COL_IX_Msd); // show only msd
398
} else if (mode == MODE_EditMsd) {
399
if (toggle % 2 == COL_IX_Lsd)
400
segments_on('0' + bin2decimal(min_left, COL_IX_Lsd), COL_IX_Lsd); // show only lsd
402
segments_on('0' + bin2decimal(min_left, toggle % 2), toggle % 2); // show both digits
404
} else if (toggle < 200) { // lit the edited position
405
segments_on('0' + bin2decimal(min_left, toggle % 2), toggle % 2); // show both digits
409
} else if (mode == MODE_Idle) {
410
if (toggle < 100) { // dim both positions
413
} else if (toggle < 200) { // lit both positions
415
segments_on('0' + bin2decimal(min_left, toggle % 2), toggle % 2); // show both digits
423
/* interrupt service routine */
424
void isr() __interrupt 0 {
434
if (mode == MODE_Work) {
441
//BUZZER = BUZZER_ON;
452
volatile uint16_t cnt = 0;
459
// Select 8Mhz internall oscillator with 1/2 prescaler to produce 4MHz clock.
460
// This is the default.
481
TRISA0 = 0; // buzzer
482
TRISA1 = 0; // column 1
483
TRISA5 = 0; // column 2
485
TRISB = 0; // All outputs
486
TRISC = 0x80; // All outputs, except RC7
489
BUZZER = BUZZER_OFF; // buzzer off
498
// setup timer1 interrupt frequency
499
// 4000000/4/2/(2^16-63036) = 200Hz