Contiki 2.5
lcd.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008 Swedish Institute of Computer Science
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in
12  * the documentation and/or other materials provided with the
13  * distribution.
14  * * Neither the name of the copyright holders nor the names of
15  * contributors may be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 /**
31  * \file
32  *
33  * \brief
34  * This file provides Raven LCD support.
35  *
36  * \author
37  * Mike Vidales mavida404@gmail.com
38  *
39  */
40 
41 #include "lcd.h"
42 
43 /**
44  * \addtogroup lcd
45  * \{
46 */
47 
48 typedef enum {
49  LCD_DUTY_STATIC = 0,
50  LCD_DUTY_HALF = 1,
51  LCD_DUTY_THIRD = 2,
52  LCD_DUTY_QUART = 3
53 } lcd_duty_t;
54 
55 typedef enum {
56  LCD_PM_0_12 = 0x0,
57  LCD_PM_0_14 = 0x1,
58  LCD_PM_0_16 = 0x2,
59  LCD_PM_0_18 = 0x3,
60  LCD_PM_0_20 = 0x4,
61  LCD_PM_0_22 = 0x5,
62  LCD_PM_0_23 = 0x6,
63  LCD_PM_0_24 = 0x7,
64  LCD_PM_0_26 = 0x8,
65  LCD_PM_0_28 = 0x9,
66  LCD_PM_0_30 = 0xA,
67  LCD_PM_0_32 = 0xB,
68  LCD_PM_0_34 = 0xC,
69  LCD_PM_0_36 = 0xD,
70  LCD_PM_0_38 = 0xE,
71  LCD_PM_0_39 = 0xF
72 } lcd_pm_t;
73 
74 #if defined( DOXYGEN )
75 static const seg_map[];
76 static const LCD_character_table[];
77 static const seg_inf[];
78 static const lcd_symbol_chart[LCD_SYMBOL_COUNT];
79 #else /* !DOXYGEN */
80 /** \name Mapping of segments for different characters */
81 /** \{ */
82 static const unsigned char seg_map[] PROGMEM = {
83  NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F , /* 0 */
84  NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C , /* 1 */
85  NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B| NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E| NUM_LCD_SYMBOL_G, /* 2 */
86  NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D| NUM_LCD_SYMBOL_G, /* 3 */
87  NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C| NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* 4 */
88  NUM_LCD_SYMBOL_A| NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D| NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* 5 */
89  NUM_LCD_SYMBOL_A| NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* 6 */
90  NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C , /* 7 */
91  NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* 8 */
92  NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D| NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* 9 */
93  NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C| NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* A */
94  NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* B */
95  NUM_LCD_SYMBOL_A| NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F , /* C */
96  NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E| NUM_LCD_SYMBOL_G, /* D */
97  NUM_LCD_SYMBOL_A| NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* E */
98  NUM_LCD_SYMBOL_A| NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* F */
99  0, /* ' ' (space) */
100  NUM_LCD_SYMBOL_G /* - (minus) */
101 };
102 /** \} */
103 
104 /* Look-up tables for 14-segment characters */
105 static const unsigned int LCD_character_table[] PROGMEM = /* Character definitions table. */
106 {
107  0x0000, /* '*' (?) */
108  0x2830, /* '+' */
109  0x0000, /* ',' (Not defined) */
110  0x0810, /* '-' */
111  0x0200, /* '.' */
112  0x0240, /* '/' */
113  0x93C5, /* '0' */
114  0x80C0, /* '1' */
115  0x1994, /* '2' */
116  0x9894, /* '3' */
117  0x8891, /* '4' */
118  0x9815, /* '5' */
119  0x9915, /* '6' */
120  0x8084, /* '7' */
121  0x9995, /* '8' */
122  0x9895, /* '9' */
123  0x0000, /* ':' (Not defined) */
124  0x0000, /* ';' (Not defined) */
125  0x0000, /* '<' (Not defined) */
126  0x0000, /* '=' (Not defined) */
127  0x0202, /* '>' */
128  0x0000, /* '?' (Not defined) */
129  0x8E53, /* '@' (redefined as '%') */
130  0x8995, /* 'A' (+ 'a') */
131  0xB8A4, /* 'B' (+ 'b') */
132  0x1105, /* 'C' (+ 'c') */
133  0xB0A4, /* 'D' (+ 'd') */
134  0x1915, /* 'E' (+ 'e') */
135  0x0915, /* 'F' (+ 'f') */
136  0x9905, /* 'G' (+ 'g') */
137  0x8991, /* 'H' (+ 'h') */
138  0x2020, /* 'I' (+ 'i') */
139  0x9180, /* 'J' (+ 'j') */
140  0x0551, /* 'K' (+ 'k') */
141  0x1101, /* 'L' (+ 'l') */
142  0x81C3, /* 'M' (+ 'm') */
143  0x8583, /* 'N' (+ 'n') */
144  0x9185, /* 'O' (+ 'o') */
145  0x0995, /* 'P' (+ 'p') */
146  0x9585, /* 'Q' (+ 'q') */
147  0x0D95, /* 'R' (+ 'r') */
148  0x1406, /* 'S' (+ 's') */
149  0x2024, /* 'T' (+ 't') */
150  0x9181, /* 'U' (+ 'u') */
151  0x0341, /* 'V' (+ 'v') */
152  0x8781, /* 'W' (+ 'w') */
153  0x0642, /* 'X' (+ 'x') */
154  0x2042, /* 'Y' (+ 'y') */
155  0x1244, /* 'Z' (+ 'z') */
156  0x0000, /* '[' (Not defined) */
157  0x0000, /* '\' (Not defined) */
158  0x0000, /* ']' (Not defined) */
159  0x0000, /* '^' (Not defined) */
160  0x0000, /* '_' (Not defined) */
161  0x0004, /* A */
162  0x0080, /* B */
163  0x8000, /* C */
164  0x1000, /* D */
165  0x0100, /* E */
166  0x0001, /* F */
167  0x0002, /* G */
168  0x0020, /* H */
169  0x0040, /* J */
170  0x0800, /* K */
171  0x0400, /* L */
172  0x2000, /* M */
173  0x0200, /* N */
174  0x0010, /* O */
175  0x0000,
176  0x0000,
177  0x0000
178 };
179 
180 /** \brief Seven segment reference guide in flash. */
181 static const unsigned char seg_inf[] PROGMEM = {
182  2<<5|19, /* A */
183  1<<5|19, /* B */
184  1<<5|9, /* C */
185  2<<5|4, /* D */
186  2<<5|9, /* E */
187  2<<5|14, /* F */
188  1<<5|14 /* G */
189 };
190 
191 /** \brief LCD symbol chart located in flash. */
192 static const lcd_symbol_t lcd_symbol_chart[LCD_SYMBOL_COUNT] PROGMEM= {
193  /* Raven */
194  LCD_SYMBOL_RAVEN ,
195 
196  /* Audio */
197  LCD_SYMBOL_BELL ,
198  LCD_SYMBOL_TONE ,
199  LCD_SYMBOL_MIC ,
200  LCD_SYMBOL_SPEAKER ,
201 
202  /* Status */
203  LCD_SYMBOL_KEY ,
204  LCD_SYMBOL_ATT ,
205 
206  /* Time */
207  LCD_SYMBOL_SUN ,
208  LCD_SYMBOL_MOON ,
209  LCD_SYMBOL_AM ,
210  LCD_SYMBOL_PM ,
211 
212  /* Radio comus */
213  LCD_SYMBOL_RX ,
214  LCD_SYMBOL_TX ,
215  LCD_SYMBOL_IP ,
216  LCD_SYMBOL_PAN ,
217  LCD_SYMBOL_ZLINK ,
218  LCD_SYMBOL_ZIGBEE ,
219 
220  /* Antenna status */
221  LCD_SYMBOL_ANT_FOOT,
222  LCD_SYMBOL_ANT_SIG1,
223  LCD_SYMBOL_ANT_SIG2,
224  LCD_SYMBOL_ANT_SIG3,
225  LCD_SYMBOL_ANT_DIS ,
226 
227  /* Battery status */
228  LCD_SYMBOL_BAT_CONT,
229  LCD_SYMBOL_BAT_CAP1,
230  LCD_SYMBOL_BAT_CAP2,
231  LCD_SYMBOL_BAT_CAP3,
232 
233  /* Envelope status */
234  LCD_SYMBOL_ENV_OP ,
235  LCD_SYMBOL_ENV_CL ,
236  LCD_SYMBOL_ENV_MAIN,
237 
238  /* Temperature */
239  LCD_SYMBOL_C ,
240  LCD_SYMBOL_F ,
241 
242  /* Numeric */
243  LCD_SYMBOL_MINUS ,
244  LCD_SYMBOL_DOT ,
245  LCD_SYMBOL_COL
246 };
247 #endif /* !DOXYGEN */
248 
249 /** LCD text buffer */
250 static unsigned char lcd_text[20];
251 
252 /** Textd buffer read pointer for text field in LCD display. When ptr>0 characters in front will be cleared (space) */
253 static int lcd_text_rd_ptr = 0;
254 
255 /** Text pointer for writing new chars to text buffer */
256 static int lcd_text_wr_ptr = 0;
257 
258 static bool lcd_scroll_enable;
259 static int lcd_scroll_prescale;
260 static int lcd_scroll_prescale_value;
261 static int lcd_num_print(uint16_t numb, bool negative, lcd_padding_t padding);
262 static void lcd_nmb_print_dig(uint8_t val, int dig);
263 static int lcd_text_sl(void);
264 static int lcd_text_put(const char* s, int pos);
265 static int lcd_char_put(unsigned char c, int pos);
266 
267 /*---------------------------------------------------------------------------*/
268 
269 /**
270  * \brief This function will initialize the proper settings for the LCD driver.
271  *
272  * This ATmega3290p can directly support an LCD through register mapping.
273  *
274  * \return 0
275 */
276 int
277 lcd_init(void)
278 {
279  /*
280  * Configuring LCD with Extern clock (TOSC, 32.768kHz)
281  * 32786 Hz 32786 Hz
282  * frame_rate = ------------------ = ------------- = 32 Hz
283  * 8 * .prescl * .div 8 * 16 * 8
284  */
285 
286  lcd_config_t lcd_config ;
287  lcd_config.blanking = LCD_BLANKING_OFF;
288  lcd_config.buffer = LCD_BUFFER_ON;
289  lcd_config.wave = LCD_WAVE_LOW_POWER;
290  lcd_config.clock = LCD_CLOCK_EXTERN;
291  lcd_config.bias = LCD_BIAS_HALF;
292  lcd_config.prescl = LCD_PRESCL_16;
293  lcd_config.div = LCD_DIV_8;
294  lcd_config.drive = LCD_DRIVE_450;
295  lcd_config.contrast = LCD_CONTRAST_3_30;
296 
297  /* Enable module */
298  PRR &= ~(1 << PRLCD);
299 
300  /* Configure and enable LCD controller */
301  LCDCRB = lcd_config.lcdcrb|(LCD_PM_0_39<<LCDPM0)|(LCD_DUTY_QUART<<LCDMUX0); /* Add port mask/mux */
302  LCDFRR = lcd_config.lcdfrr;
303  LCDCCR = lcd_config.lcdccr;
304  LCDCRA = lcd_config.lcdcra|(1<<LCDEN)|(1<<LCDIE); /* Add interrupt- and LCD- enable */
305 
306  /* clear screen */
307  lcd_symbol_clr_all();
308 
309  /* Calculate scrolling value */
310  lcd_scroll_prescale_value = LCD_CLCK_FRQ/128;
311  lcd_scroll_prescale_value >>= (lcd_config.prescl == 0) ? 4 : (5+lcd_config.prescl);
312  lcd_scroll_prescale_value /= (lcd_config.div+1);
313  lcd_scroll_prescale_value = (lcd_scroll_prescale_value==0) ? 1 : lcd_scroll_prescale_value;
314  lcd_scroll_prescale = lcd_scroll_prescale_value;
315 
316  return 0;
317 }
318 
319 /*---------------------------------------------------------------------------*/
320 
321 /**
322  * \brief This will disable the LCD operation.
323 */
324 void
326 {
327  while (!(LCDCRA & (1<<LCDIF)))
328  ;
329  /*
330  * Set LCD Blanking and clear interrupt flag
331  * by writing a logical one to the flag.
332  */
333 
334  LCDCRA = (1<<LCDEN)|(1<<LCDIF)|(1<<LCDBL);
335  /* Wait until LCD Blanking is effective. */
336  while ( !(LCDCRA & (1<<LCDIF)) )
337  ;
338 
339  /* Disable LCD */
340  LCDCRA = (0<<LCDEN) | (0<<LCDIE);
341 
342  /* power LCD down */
343  PRR |= (1 << PRLCD);
344 }
345 
346 /*---------------------------------------------------------------------------*/
347 
348 /**
349  * \brief This will convert the incoming decimal number to BCD.
350  *
351  * \param inNumber Decimal number to convert
352  *
353  * \return newByte The converted deicmal number as byte.
354 */
355 uint8_t
356 itobcd(uint8_t inNumber)
357 {
358  int newByte;
359 
360  newByte = 0;
361 
362  while (inNumber >= 10){
363  inNumber -= 10;
364  newByte++;
365  }
366 
367  newByte = newByte << 4;
368  newByte = (newByte | inNumber);
369 
370  return newByte;
371 }
372 
373 /*---------------------------------------------------------------------------*/
374 
375 /**
376  * \brief This will put a HEX value on the LCD that represents the input
377  * parameter.
378  *
379  * \param numb Number to display as HEX.
380  * \param padding This pads the location to place the value on the LCD.
381  *
382  * \return lcd_num_print()
383 */
384 int
385 lcd_num_puthex(uint16_t numb, lcd_padding_t padding)
386 {
387  return lcd_num_print(numb, false, padding);
388 }
389 
390 /*---------------------------------------------------------------------------*/
391 
392 /**
393  * \brief This will put a DEC value on the LCD that represents the input
394  * parameter.
395  *
396  * \param numb Number to display as DEC.
397  * \param padding This pads the location to place the value on the LCD.
398  *
399  * \return lcd_num_print()
400 */
401 int
402 lcd_num_putdec(int numb, lcd_padding_t padding)
403 {
404  uint16_t bcd;
405 
406  /* Check for overflow */
407  if (numb > 9999) {
408  numb = 9999;
409  } else if (numb < -9999) {
410  numb = -9999;
411  }
412 
413  /* Convert to BCD */
414  bcd = itobcd(abs(numb));
415 
416  /* Print */
417  return lcd_num_print(bcd, (bool)(numb<0), padding);
418 }
419 
420 /*---------------------------------------------------------------------------*/
421 
422 /**
423  * \brief This will clear numbers displayed on the LCD.
424  *
425  * \return 0
426 */
427 int
429 {
430  volatile unsigned char* lcd_data = (volatile unsigned char*)0xEC;
431  int i,j;
432 
433  for (i=0;i<4;++i){
434  for (j=0;j<7;++j){
435  lcd_data[pgm_read_byte(&seg_inf[j])&0x1F] &= ~((pgm_read_byte(&seg_inf[j])>>5)<<(i*2));
436  }
437  }
438  return 0;
439 }
440 
441 /*---------------------------------------------------------------------------*/
442 
443 /**
444  * \brief This will put a string of characters out to the LCD.
445  *
446  * \param s First character pointer of string.
447  *
448  * \return 0
449 */
450 int
451 lcd_puts(const char* s)
452 {
453  strcpy((char*)lcd_text, s);
454  lcd_text_wr_ptr = strlen(s);
455  lcd_text_rd_ptr = 0;
456 
457  lcd_text_put((char*)&lcd_text[lcd_text_rd_ptr], 1);
458 
459  lcd_scroll_enable = (lcd_text_wr_ptr > 7) ? true : false;
460 
461  return 0;
462 }
463 
464 /*---------------------------------------------------------------------------*/
465 
466 /**
467  * \brief This will put a string of characters of a certain length out to the LCD.
468  *
469  * \param length Length of string to print.
470  * \param s First character pointer of string.
471  *
472  * \return 0
473 */
474 int
475 lcd_puta(size_t length, const uint8_t *s)
476 {
477  memcpy((void*)lcd_text, (void const*)s, length);
478  lcd_text_wr_ptr = length;
479  lcd_text_rd_ptr = 0;
480 
481  lcd_text_put((char*)&lcd_text[lcd_text_rd_ptr], 1);
482 
483  lcd_scroll_enable = (lcd_text_wr_ptr > 7) ? true : false;
484 
485  return 0;
486 }
487 
488 /*---------------------------------------------------------------------------*/
489 
490 /**
491  * \brief This will put a string out to the LCD from Flash.
492  *
493  * \param s First character pointer of the string located in Flash
494  *
495  * \return 0
496 */
497 int
498 lcd_puts_P(const char *s)
499 {
500  strcpy_P((char*)lcd_text, s);
501  lcd_text_wr_ptr = strlen_P(s);
502  lcd_text_rd_ptr = 0;
503 
504  lcd_text_put((char*)&lcd_text[lcd_text_rd_ptr], 1);
505 
506  lcd_scroll_enable = (lcd_text_wr_ptr > 7) ? true : false;
507 
508  return 0;
509 }
510 
511 /*---------------------------------------------------------------------------*/
512 
513 /**
514  * \brief This will put a single character out to the LCD.
515  *
516  * \param c Character to display on LCD.
517  *
518  * \return 0
519 */
520 int
521 lcd_putchar(unsigned char c)
522 {
523  lcd_text[lcd_text_wr_ptr++] = c;
524  lcd_text[lcd_text_wr_ptr] = 0;
525 
526  lcd_text_put((char*)&lcd_text[lcd_text_rd_ptr], 1);
527 
528  lcd_scroll_enable = (lcd_text_wr_ptr > 7) ? true : false;
529 
530  return 0;
531 }
532 
533 /*---------------------------------------------------------------------------*/
534 
535 /**
536  * \brief This will enable any of the symbols on the Raven LCD.
537  *
538  * \param symbol Specific symbol to enable on the LCD.
539 */
540 void
541 lcd_symbol_set(lcd_symbol_t symbol)
542 {
543  unsigned char mem_offset;
544  unsigned char bit_offset;
545  volatile unsigned char* lcd_data = (volatile unsigned char*)0xEC;
546 
547  /* Symbol format = bbbnnnnn where b is bit and n is offset */
548  bit_offset = (symbol >> 5);
549  mem_offset = (symbol & 0x1F);
550  if ( mem_offset >= 20 ){
551  return; /* Data out of range of the LCD registers */
552  }
553  lcd_data = lcd_data + mem_offset; /* Point to the relevant LCDDR */
554 
555  *lcd_data = *lcd_data | ( 1 << bit_offset);
556 }
557 
558 /*---------------------------------------------------------------------------*/
559 
560 /**
561  * \brief This will clear any symbol on the Raven LCD.
562  *
563  * \param symbol Specific symbol to clear from the LCD.
564 */
565 void
566 lcd_symbol_clr(lcd_symbol_t symbol)
567 {
568  unsigned char offset;
569  unsigned char setbit;
570  volatile unsigned char* lcd_data = (volatile unsigned char*)0xEC;
571 
572  /* symbol format = bbbnnnnn where b is bit and n is offset */
573  setbit = (symbol >> 5);
574  offset = (symbol & 0x1F);
575  if ( offset >= 20 ){
576  return; /* data out of range of the LCD registers */
577  }
578 
579  lcd_data = lcd_data + offset; /* Point to the relevant LCDDR */
580 
581  *lcd_data = *lcd_data & ~( 1 << setbit);
582 }
583 
584 /*---------------------------------------------------------------------------*/
585 
586 /**
587  * \brief This will enable a group of symbols from the lcd_symbol_chart.
588  *
589  * \param start Position of table to start from.
590  * \param count Number of symbols to enable from start position.
591 */
592 void
593 lcd_symbol_set_group(int start, int count)
594 {
595  count = (start + count)>LCD_SYMBOL_COUNT ?
596  LCD_SYMBOL_COUNT - start :
597  count;
598  int i;
599 
600  for(i=start; i<start+count; ++i){
601  lcd_symbol_set(pgm_read_byte(&lcd_symbol_chart[i]));
602  }
603 }
604 
605 /*---------------------------------------------------------------------------*/
606 
607 /**
608  * \brief This will disable a group of symbols from the lcd_symbol_chart.
609  *
610  * \param start Position of table to start from.
611  * \param count Number of symbols to disable from start position.
612 */
613 void
614 lcd_symbol_clr_group(int start, int count)
615 {
616  count = (start + count)>LCD_SYMBOL_COUNT ?
617  LCD_SYMBOL_COUNT - start :
618  count;
619  int i;
620 
621  for(i=start; i<count; ++i){
622  lcd_symbol_clr(pgm_read_byte(&lcd_symbol_chart[i]));
623  }
624 }
625 
626 /*---------------------------------------------------------------------------*/
627 
628 /**
629  * \brief This will print a number to the LCD with the following parameters.
630  *
631  * \param numb Number to display on LCD.
632  * \param negative Display negative sign in the next digit field.
633  * \param padding This pads the location to place the value on the LCD.
634  *
635  * \return 0
636 */
637 static int
638 lcd_num_print(uint16_t numb, bool negative, lcd_padding_t padding)
639 {
640  int i;
641  for (i=0;i<4;/**/) {
642  /* Get segments for this digit and print it */
643  lcd_nmb_print_dig(pgm_read_byte(&seg_map[(numb&(0xF<<4*i))>>4*i]), i);
644 
645  /* If rest of number is zero */
646  if (++i<4) {
647  if (numb >> 4*i == 0) {
648  if (negative == true) { /* print a 'minus' in the next digit field */
649  lcd_nmb_print_dig(pgm_read_byte(&seg_map[(padding == LCD_NUM_PADDING_ZERO) ? LCD_SEV_SEG_INDEX_0 : LCD_SEV_SEG_INDEX_MINUS]), i++);
650  if (padding == LCD_NUM_PADDING_ZERO) {
651  lcd_symbol_set(LCD_SYMBOL_MINUS);
652  }
653  } else {
654  lcd_symbol_clr(LCD_SYMBOL_MINUS);
655  }
656  while (i<4){
657  lcd_nmb_print_dig(pgm_read_byte(&seg_map[(padding == LCD_NUM_PADDING_ZERO) ? LCD_SEV_SEG_INDEX_0 : LCD_SEV_SEG_INDEX_SPACE]), i++);
658  }
659  }
660  } else {
661  if (negative == true) {
662  lcd_symbol_set(LCD_SYMBOL_MINUS);
663  } else {
664  lcd_symbol_clr(LCD_SYMBOL_MINUS);
665  }
666  }
667  }
668  return 0;
669 }
670 
671 /*---------------------------------------------------------------------------*/
672 
673 /**
674  * \brief This will print a number according to the segment map of the LCD.
675  *
676  * \param val Number that is to be matched to appropriate segments.
677  * \param dig Segment to enable
678 */
679 static void
680 lcd_nmb_print_dig(uint8_t val, int dig)
681 {
682  volatile unsigned char* lcd_data = (volatile unsigned char*)0xEC;
683  int j;
684 
685  for (j=0;j<7;++j){
686  if (val & (1<<j)) {
687  lcd_data[pgm_read_byte(&seg_inf[j])&0x1F] |= (pgm_read_byte(&seg_inf[j])>>5)<<(dig*2);
688  }
689  else {
690  lcd_data[pgm_read_byte(&seg_inf[j])&0x1F] &= ~((pgm_read_byte(&seg_inf[j])>>5)<<(dig*2));
691  }
692  }
693 }
694 
695 /*---------------------------------------------------------------------------*/
696 
697 /**
698  * \brief This will scroll the test on the LCD.
699  *
700  * \return 0
701 */
702 static int
703 lcd_text_sl(void)
704 {
705  static int pos = 1;
706  if (lcd_text[lcd_text_rd_ptr] == 0) {
707  lcd_text_rd_ptr = 0;
708  pos = 7;
709  }
710  else {
711  if (pos){
712  pos--;
713  }
714  else {
715  lcd_text_rd_ptr++;
716  }
717  }
718 
719  lcd_text_put((char*)&lcd_text[lcd_text_rd_ptr], pos);
720  return 0;
721 }
722 
723 /*---------------------------------------------------------------------------*/
724 
725 /**
726  * \brief This will put test out to the LCD at a certain location padded with
727  * spaces.
728  *
729  * \param s First character pointer to the string of test to print.
730  * \param pos Count of spaces entered before printing the text.
731  *
732  * \return 0
733 */
734 static int
735 lcd_text_put(const char* s, int pos)
736 {
737  int i;
738 
739  /* Pad with spaces in front if offset > 0 */
740  for (i=1; i<pos; i++) {
741  lcd_char_put(' ', i);
742  }
743 
744  /* Print characters, overwrite with spaces at end if necessary */
745  for ( i=pos; i<=7; ++i) {
746  if (*s == 0) {
747  lcd_char_put(' ', i);
748  }
749  else {
750  lcd_char_put( (unsigned char)*s++, i);
751  }
752  }
753  return 0;
754 }
755 
756 /*---------------------------------------------------------------------------*/
757 
758 /**
759  * \brief This will put a single char out to the LCD by looking up the
760  * proper segments.
761  *
762  * \param c Character to display on the LCD.
763  * \param pos This will add spaces for positioning the text on the LCD.
764  *
765  * \return 0
766 */
767 static int
768 lcd_char_put(unsigned char c, int pos)
769 {
770  unsigned int seg, segMask;
771  unsigned char i;
772  unsigned char mask, nibble, nibbleMask;
773 
774  volatile unsigned char* lcd_data = (volatile unsigned char*)0xEC;
775  unsigned char lcd_reg;
776 
777  if (pos > 7){
778  return EOF;
779  }
780 
781  /* Lookup character table for segmet data */
782  if (((c >= '*') && (c <= 'z')) || (c == ' ')){
783  if (c >= 'a' ){
784  c &= ~0x20; /* c is in character_table. Convert to upper if necessarry. */
785  }
786  if (c == ' ') {
787  c = 0x00;
788  }
789  else {
790  c -= '*';
791  }
792  if ( c > 0x35 ){
793  return EOF; /* c points outside array */
794  }
795  else{
796  seg = pgm_read_dword(&LCD_character_table[c]);
797  }
798  }
799  else {
800  return EOF; /* ASCII code out of range */
801  }
802 
803 
804  /* Adjust mask according to digit */
805  segMask = 0x4008; /* masking out two bits */
806 
807  i = pos-1; /*i used as pointer offset */
808  i >>= 1;
809  lcd_data += i; /* Point to the first relevant LCDDR; i = {0,0,1,1,2,2} */
810 
811  i = 4; /*i used as loop counter */
812  do{
813  nibble = seg & 0x000F;
814  nibbleMask = segMask & 0x000F;
815 
816  seg >>= 4;
817  segMask >>= 4;
818 
819  if (pos & 0x01) {
820  mask = 0xF0 | nibbleMask;
821  }
822  else {
823  nibble <<= 4;
824  mask = 0x0F | ( nibbleMask <<4 );
825  }
826  lcd_reg = *lcd_data;
827  *lcd_data |= (lcd_reg & mask) | nibble; /* Write new bit values */
828 
829  lcd_reg = *lcd_data;
830  *lcd_data &= (lcd_reg & mask) | nibble;
831 
832  lcd_data += 5;
833  } while ( --i );
834 
835  return 0;
836 }
837 
838 /*---------------------------------------------------------------------------*/
839 
840 /**
841  * \brief This is the LCD Start of Frame Interrupt Subroutine.
842  *
843  * This interrupt fires at the beginning of a new frame.
844 */
845 ISR
846 (LCD_vect)
847 {
848  if (lcd_scroll_enable) {
849  if (--lcd_scroll_prescale == 0) {
850  lcd_text_sl();
851  lcd_scroll_prescale = lcd_scroll_prescale_value;
852  }
853  }
854 }
855 
856 /*---------------------------------------------------------------------------*/
857 
858 /**
859  * \brief Turns the Raven nose LED on.
860 */
861 void
862 led_on(void)
863 {
864  DDRB |= 0x80;
865  PORTB &= ~0x80;
866 }
867 
868 /*---------------------------------------------------------------------------*/
869 
870 /**
871  * \brief Turns the Raven nose LED off.
872 */
873 void
874 led_off(void)
875 {
876  DDRB &= ~0x80;
877  PORTB |= 0x80;
878 }
879 
880 /*---------------------------------------------------------------------------*/
881 
882 /**
883  * \brief This will add the passed in number to any of the four locations of
884  * the four digit segment display on the LCD.
885  *
886  * \param numb Number to display.
887  * \param pos Position to display number.
888 */
889 void
890 lcd_single_print_dig(uint8_t numb, uint8_t pos)
891 {
892  lcd_nmb_print_dig(pgm_read_byte(&seg_map[numb]), pos);
893 }
894 
895 /** \} */