~arcachofo/simulide/1.1.0

« back to all changes in this revision

Viewing changes to resources/examples/Pic/Timer1_Pic16F689/PICTimer.c

  • Committer: arcachofo
  • Date: 2021-01-01 14:23:42 UTC
  • Revision ID: arcachofo@simulide.com-20210101142342-ozfljnll44g5lbl3
Initial Commit 0.5.15-RC3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright (C) 2018 by hovercraft:                                     *
 
3
 *              https://github.com/hovercraft-github                               *
 
4
 *                                                                         *
 
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.                                   *
 
9
 *                                                                         *
 
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.                          *
 
14
 *                                                                         *
 
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
 ***************************************************************************/
 
20
 
 
21
#include <pic16f689.h>
 
22
#include <stdint.h>
 
23
 
 
24
/***************************************************************************
 
25
*                                                                          *
 
26
* This source code is optimized for use with SDCC compiler and piklab IDE  *
 
27
*                                                                          *
 
28
****************************************************************************/
 
29
 
 
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;
 
34
 
 
35
//#define GPSIM
 
36
 
 
37
#define COL_Msd RA1
 
38
#define COL_Lsd RA5
 
39
#define COL_ON 1
 
40
#define COL_OFF 0
 
41
#define COL_IX_Msd 0
 
42
#define COL_IX_Lsd 1
 
43
 
 
44
/*
 
45
#define SEGM_A RC0
 
46
#define SEGM_B RC1
 
47
#define SEGM_C RC2
 
48
#define SEGM_D RC3
 
49
#define SEGM_E RC4
 
50
#define SEGM_F RC5
 
51
#define SEGM_G RC6
 
52
#define SEGM_ON 1
 
53
#define SEGM_OFF 0
 
54
*/
 
55
 
 
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
 
68
 
 
69
#define LOAD1 RB4
 
70
#define LOAD2 RB5
 
71
#define LOAD3 RB6
 
72
#define LOAD_ON 1
 
73
#define LOAD_OFF 0
 
74
 
 
75
#define BUZZER RA0
 
76
#define BUZZER_ON 1
 
77
#define BUZZER_OFF 0
 
78
 
 
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)
 
84
 
 
85
#define EEPROM_IX_FLAG 0
 
86
#define EEPROM_IX_MINUTES 1
 
87
 
 
88
#define clrwdt() \
 
89
    __asm \
 
90
    CLRWDT \
 
91
    __endasm
 
92
 
 
93
typedef enum KeyPressedComb {
 
94
  PRESSED_NONE=0,
 
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,
 
100
};
 
101
 
 
102
typedef enum OpModes {
 
103
  MODE_Idle = 0,
 
104
  MODE_Work,
 
105
  MODE_EditMsd, // edit the most significant digit
 
106
  MODE_EditLsd, // edit the least significant digit
 
107
};
 
108
 
 
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;
 
113
 
 
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) {
 
120
    uint16_t u;
 
121
    while (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. */
 
125
            __asm nop __endasm;
 
126
        }
 
127
    }
 
128
}
 
129
 
 
130
uint8_t ee_write_byte(uint8_t address, uint8_t *_data){
 
131
  uint8_t int_enabled = GIE;
 
132
  EEDATA = *_data;
 
133
  EEADR = address;
 
134
  // start write sequence as described in datasheet, page 91
 
135
  EEPGD = 0;
 
136
  //CFGS = 0;
 
137
  WREN = 1; // enable writes to data EEPROM
 
138
  GIE = 0;  // disable interrupts
 
139
  EECON2 = 0x55;
 
140
  EECON2 = 0x0AA;
 
141
  WR = 1;   // start writing
 
142
  while (WR) {
 
143
      __asm nop __endasm;}
 
144
  if (WRERR) {
 
145
      return 0;
 
146
  }
 
147
  WREN = 0;
 
148
  GIE = int_enabled;  // restore the interrupts enable state
 
149
  return 1;
 
150
}
 
151
 
 
152
void ee_read_byte(uint8_t address, uint8_t *_data){
 
153
  EEADR = address;
 
154
  //CFGS = 0;
 
155
  EEPGD = 0;
 
156
  RD = 1;
 
157
  *_data = EEDATA;
 
158
}
 
159
 
 
160
void store_minutes(void) {
 
161
  uint8_t flag;
 
162
  flag = 'T';
 
163
  ee_write_byte(EEPROM_IX_FLAG, &flag);
 
164
  ee_write_byte(EEPROM_IX_MINUTES, &min_left);
 
165
}
 
166
 
 
167
void retrieve_minutes(void) {
 
168
  uint8_t flag;
 
169
  ee_read_byte(EEPROM_IX_FLAG, &flag);
 
170
  if (flag != 'T') {
 
171
    min_left = 10;
 
172
    store_minutes();
 
173
  } else {
 
174
    ee_read_byte(EEPROM_IX_MINUTES, &min_left);
 
175
  }
 
176
}
 
177
 
 
178
  uint8_t scanKeys(void) {
 
179
  uint8_t keys_state;
 
180
  // Switch key pins to input mode
 
181
  TRISC |= KEYS_MASK;
 
182
  delay_ms(1);
 
183
  keys_state = PORTC;
 
184
  TRISC &= ~KEYS_MASK;
 
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))
 
189
    return PRESSED_OK;
 
190
  switch (keys_state) {
 
191
    case PRESSED_TOGGLE:
 
192
      return PRESSED_TOGGLE;
 
193
      break;
 
194
    case PRESSED_CANCEL:
 
195
      return PRESSED_CANCEL;
 
196
      break;
 
197
    case PRESSED_OK:
 
198
      return PRESSED_OK;
 
199
      break;
 
200
    case PRESSED_UP:
 
201
      return PRESSED_UP;
 
202
      break;
 
203
    case PRESSED_DOWN:
 
204
      return PRESSED_DOWN;
 
205
      break;
 
206
    default:
 
207
      return PRESSED_NONE;
 
208
      break;
 
209
  }
 
210
}
 
211
 
 
212
uint8_t bin2decimal(uint8_t n, uint8_t pos) {
 
213
  //n  - binary number
 
214
  //d2...d0 - decimal numbers
 
215
  uint8_t d2 = 0, d1, d0;
 
216
  d1 = n / 10;
 
217
  d2 = d1 / 10;
 
218
  if (d1 > 9) {
 
219
    d1 = d1 % 10;
 
220
  }
 
221
  d0 = n - d2 * 100 - d1 * 10;
 
222
  // d2 always ignored
 
223
  if (pos == COL_IX_Lsd)
 
224
    return d0;
 
225
  return d1;
 
226
}
 
227
 
 
228
void segments_off(void) {
 
229
  COL_Msd = COL_OFF;
 
230
  COL_Lsd = COL_OFF;
 
231
  PORTC = SEGMENTS_OFF;
 
232
}
 
233
 
 
234
void segments_on(char c, uint8_t col_ix) {
 
235
  switch (c) {
 
236
    case '0':
 
237
      PORTC = SEGMENTS_0;
 
238
      break;
 
239
    case '1':
 
240
      PORTC = SEGMENTS_1;
 
241
      break;
 
242
    case '2':
 
243
      PORTC = SEGMENTS_2;
 
244
      break;
 
245
    case '3':
 
246
      PORTC = SEGMENTS_3;
 
247
      break;
 
248
    case '4':
 
249
      PORTC = SEGMENTS_4;
 
250
      break;
 
251
    case '5':
 
252
      PORTC = SEGMENTS_5;
 
253
      break;
 
254
    case '6':
 
255
      PORTC = SEGMENTS_6;
 
256
      break;
 
257
    case '7':
 
258
      PORTC = SEGMENTS_7;
 
259
      break;
 
260
    case '8':
 
261
      PORTC = SEGMENTS_8;
 
262
      break;
 
263
    case '9':
 
264
      PORTC = SEGMENTS_9;
 
265
      break;
 
266
    case 'E':
 
267
      PORTC = SEGMENTS_E;
 
268
      break;
 
269
    default:
 
270
      PORTC = SEGMENTS_OFF;
 
271
      break;
 
272
  }
 
273
  if (col_ix == COL_IX_Msd)
 
274
    COL_Msd = COL_ON;
 
275
  else
 
276
    COL_Lsd = COL_ON;
 
277
}
 
278
 
 
279
volatile uint8_t toggle = 0;
 
280
volatile uint8_t kbstate_prev = PRESSED_NONE;
 
281
 
 
282
void show_digit(void) {
 
283
  uint8_t value;
 
284
  uint8_t kbstate;
 
285
  segments_off();
 
286
  kbstate = scanKeys();
 
287
  if ((kbstate != PRESSED_NONE) && (kbstate != kbstate_prev)) {
 
288
    BUZZER = BUZZER_OFF;
 
289
    switch (mode) {
 
290
      case MODE_EditLsd:
 
291
        if (toggle < 2)
 
292
          toggle = 2;
 
293
        switch (kbstate) {
 
294
          case PRESSED_CANCEL:
 
295
            mode = MODE_Idle;
 
296
            toggle = 2;
 
297
            break;
 
298
          case PRESSED_OK:
 
299
            store_minutes();
 
300
            mode = MODE_Idle;
 
301
            toggle = 2;
 
302
            break;
 
303
          case PRESSED_TOGGLE:
 
304
            mode = MODE_EditMsd;
 
305
            break;
 
306
          case PRESSED_UP:
 
307
            value = bin2decimal(min_left, COL_IX_Lsd) + 1;
 
308
            if (value > 9)
 
309
              value = 0;
 
310
            min_left = bin2decimal(min_left, COL_IX_Msd)*10 + value;
 
311
            break;
 
312
          case PRESSED_DOWN:
 
313
            value = bin2decimal(min_left, COL_IX_Lsd);
 
314
            if (value > 0)
 
315
              value -= 1;
 
316
            else
 
317
              value = 9;
 
318
            min_left = bin2decimal(min_left, COL_IX_Msd)*10 + value;
 
319
            break;
 
320
        };
 
321
        break;
 
322
      case MODE_EditMsd:
 
323
        if (toggle < 2)
 
324
          toggle = 2;
 
325
        switch (kbstate) {
 
326
          case PRESSED_CANCEL:
 
327
            mode = MODE_Idle;
 
328
            toggle = 2;
 
329
            break;
 
330
          case PRESSED_OK:
 
331
            store_minutes();
 
332
            mode = MODE_Idle;
 
333
            toggle = 2;
 
334
            break;
 
335
          case PRESSED_TOGGLE:
 
336
            mode = MODE_EditLsd;
 
337
            break;
 
338
          case PRESSED_UP:
 
339
            value = bin2decimal(min_left, COL_IX_Msd) + 1;
 
340
            if (value > 9)
 
341
              value = 0;
 
342
            min_left = bin2decimal(min_left, COL_IX_Lsd) + value*10;
 
343
            break;
 
344
          case PRESSED_DOWN:
 
345
            value = bin2decimal(min_left, COL_IX_Msd);
 
346
            if (value > 0)
 
347
              value -= 1;
 
348
            else
 
349
              value = 9;
 
350
            min_left = bin2decimal(min_left, COL_IX_Lsd) + value*10;
 
351
            break;
 
352
        };
 
353
        break;
 
354
      case MODE_Idle:
 
355
        retrieve_minutes();
 
356
        if (kbstate == PRESSED_OK) {
 
357
            mode = MODE_Work;
 
358
            toggle = 0;
 
359
            LOAD1 = LOAD_ON;
 
360
            LOAD2 = LOAD_ON;
 
361
            LOAD3 = LOAD_ON;
 
362
            sec = 0;
 
363
        } else if (kbstate == PRESSED_TOGGLE) {
 
364
            mode = MODE_EditLsd;
 
365
            toggle = 2;
 
366
        }
 
367
        break;
 
368
      case MODE_Work:
 
369
      default:
 
370
        LOAD1 = LOAD_OFF;
 
371
        LOAD2 = LOAD_OFF;
 
372
        LOAD3 = LOAD_OFF;
 
373
        toggle = 2;
 
374
        if (kbstate == PRESSED_TOGGLE) {
 
375
          mode = MODE_EditLsd;
 
376
        }
 
377
        else
 
378
          mode = MODE_Idle;
 
379
        break;
 
380
    };
 
381
  }
 
382
  kbstate_prev = kbstate;
 
383
  if (toggle == 0) {
 
384
    toggle = 1;
 
385
    value = bin2decimal(min_left, toggle);
 
386
    segments_on('0' + value, toggle);
 
387
  } else if (toggle == 1) {
 
388
    toggle = 0;
 
389
    value = bin2decimal(min_left, toggle);
 
390
    segments_on('0' + value, toggle);
 
391
  } else {
 
392
    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
 
401
        } else {
 
402
          segments_on('0' + bin2decimal(min_left, toggle % 2), toggle % 2); // show both digits
 
403
        }
 
404
      } else if (toggle < 200) { // lit the edited position
 
405
          segments_on('0' + bin2decimal(min_left, toggle % 2), toggle % 2); // show both digits
 
406
      } else {
 
407
        toggle = 2;
 
408
      }
 
409
    } else if (mode == MODE_Idle) {
 
410
      if (toggle < 100) { // dim both positions
 
411
        if (!min_left)
 
412
          BUZZER = BUZZER_ON;
 
413
      } else if (toggle < 200) { // lit both positions
 
414
          BUZZER = BUZZER_OFF;
 
415
          segments_on('0' + bin2decimal(min_left, toggle % 2), toggle % 2); // show both digits
 
416
      } else {
 
417
        toggle = 2;
 
418
      }
 
419
    }
 
420
  };
 
421
}
 
422
 
 
423
/* interrupt service routine */
 
424
void isr() __interrupt 0 {
 
425
  clrwdt();
 
426
  TMR1H = 0xF6;
 
427
  TMR1L = 0x3C;
 
428
  clk++;
 
429
  if (clk == 200) {
 
430
    clk = 0;
 
431
    sec++;
 
432
    if (sec == 60) {
 
433
      sec = 0;
 
434
      if (mode == MODE_Work) {
 
435
        if (min_left)
 
436
          --min_left;
 
437
        if (!min_left) {
 
438
          LOAD1 = LOAD_OFF;
 
439
          LOAD2 = LOAD_OFF;
 
440
          LOAD3 = LOAD_OFF;
 
441
          //BUZZER = BUZZER_ON;
 
442
          toggle = 2;
 
443
          mode = MODE_Idle;
 
444
        }
 
445
      }
 
446
    }
 
447
  }
 
448
  show_digit();
 
449
  TMR1IF = 0;
 
450
}
 
451
 
 
452
volatile uint16_t cnt = 0;
 
453
 
 
454
void main() {
 
455
  GIE = 0;
 
456
  WDTPS0 = 1;
 
457
  WDTPS1 = 1;
 
458
  WDTPS2 = 1;
 
459
  // Select 8Mhz internall oscillator with 1/2 prescaler to produce 4MHz clock.
 
460
  // This is the default.
 
461
  /*
 
462
  IRCF0 = 0;
 
463
  IRCF1 = 1;
 
464
  IRCF2 = 1;
 
465
  SCS = 1;
 
466
  //SCS = OSTS;
 
467
  */
 
468
  
 
469
  SSPEN = 0;
 
470
  INTE = 0;
 
471
  T0IE = 0;
 
472
  IOCA = 0;
 
473
  IOCB = 0;
 
474
  RABIE = 0;
 
475
  RABIF = 0;
 
476
  
 
477
  ADIE = 0;
 
478
  ANSEL = 0;
 
479
  ANSELH = 0;
 
480
  TRISA = 0x3F;
 
481
  TRISA0 = 0;   // buzzer
 
482
  TRISA1 = 0;   // column 1
 
483
  TRISA5 = 0;   // column 2
 
484
 
 
485
  TRISB = 0;    // All outputs
 
486
  TRISC = 0x80; // All outputs, except RC7
 
487
  segments_off();
 
488
 
 
489
  BUZZER = BUZZER_OFF;  // buzzer off
 
490
 
 
491
  T1CON = 0;
 
492
  T1CKPS0 = 1;
 
493
  T1CKPS1 = 0;
 
494
  
 
495
  PIE1 = 0;
 
496
  INTCON = 0;
 
497
  
 
498
  // setup timer1 interrupt frequency
 
499
  // 4000000/4/2/(2^16-63036) = 200Hz
 
500
  //TMR1 = 63036L;
 
501
  TMR1H = 0xF6;
 
502
  TMR1L = 0x3C;
 
503
  TMR1IE = 1;
 
504
  TMR1CS = 0;
 
505
  TMR1GE = 0;
 
506
  T1OSCEN = 0;
 
507
  //T1SYNC = 1;
 
508
  TMR1ON = 1;
 
509
  PEIE = 1;
 
510
  retrieve_minutes();
 
511
  TMR1IF = 0;
 
512
  GIE = 1;
 
513
  LOAD1 = LOAD_ON;
 
514
  LOAD2 = LOAD_ON;
 
515
  LOAD3 = LOAD_ON;
 
516
  while (1) {
 
517
    cnt++;
 
518
#ifdef GPSIM
 
519
  if (cnt > 512) {
 
520
    cnt = 0;
 
521
    isr();
 
522
  }
 
523
#endif
 
524
  };
 
525
}