Contiki 2.6
|
00001 /* 00002 * Copyright (c) 2008 Swedish Institute of Computer Science 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in 00012 * the documentation and/or other materials provided with the 00013 * distribution. 00014 * * Neither the name of the copyright holders nor the names of 00015 * contributors may be used to endorse or promote products derived 00016 * from this software without specific prior written permission. 00017 * 00018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00028 * POSSIBILITY OF SUCH DAMAGE. 00029 */ 00030 /** 00031 * \file 00032 * 00033 * \brief 00034 * This file provides Raven LCD support. 00035 * 00036 * \author 00037 * Mike Vidales mavida404@gmail.com 00038 * 00039 */ 00040 00041 #include "lcd.h" 00042 00043 /** 00044 * \addtogroup lcd 00045 * \{ 00046 */ 00047 00048 typedef enum { 00049 LCD_DUTY_STATIC = 0, 00050 LCD_DUTY_HALF = 1, 00051 LCD_DUTY_THIRD = 2, 00052 LCD_DUTY_QUART = 3 00053 } lcd_duty_t; 00054 00055 typedef enum { 00056 LCD_PM_0_12 = 0x0, 00057 LCD_PM_0_14 = 0x1, 00058 LCD_PM_0_16 = 0x2, 00059 LCD_PM_0_18 = 0x3, 00060 LCD_PM_0_20 = 0x4, 00061 LCD_PM_0_22 = 0x5, 00062 LCD_PM_0_23 = 0x6, 00063 LCD_PM_0_24 = 0x7, 00064 LCD_PM_0_26 = 0x8, 00065 LCD_PM_0_28 = 0x9, 00066 LCD_PM_0_30 = 0xA, 00067 LCD_PM_0_32 = 0xB, 00068 LCD_PM_0_34 = 0xC, 00069 LCD_PM_0_36 = 0xD, 00070 LCD_PM_0_38 = 0xE, 00071 LCD_PM_0_39 = 0xF 00072 } lcd_pm_t; 00073 00074 #if defined( DOXYGEN ) 00075 static const seg_map[]; 00076 static const LCD_character_table[]; 00077 static const seg_inf[]; 00078 static const lcd_symbol_chart[LCD_SYMBOL_COUNT]; 00079 #else /* !DOXYGEN */ 00080 /** \name Mapping of segments for different characters */ 00081 /** \{ */ 00082 static const unsigned char seg_map[] PROGMEM = { 00083 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 */ 00084 NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C , /* 1 */ 00085 NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B| NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E| NUM_LCD_SYMBOL_G, /* 2 */ 00086 NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D| NUM_LCD_SYMBOL_G, /* 3 */ 00087 NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C| NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* 4 */ 00088 NUM_LCD_SYMBOL_A| NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D| NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* 5 */ 00089 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 */ 00090 NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C , /* 7 */ 00091 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 */ 00092 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 */ 00093 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 */ 00094 NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* B */ 00095 NUM_LCD_SYMBOL_A| NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F , /* C */ 00096 NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E| NUM_LCD_SYMBOL_G, /* D */ 00097 NUM_LCD_SYMBOL_A| NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* E */ 00098 NUM_LCD_SYMBOL_A| NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* F */ 00099 0, /* ' ' (space) */ 00100 NUM_LCD_SYMBOL_G /* - (minus) */ 00101 }; 00102 /** \} */ 00103 00104 /* Look-up tables for 14-segment characters */ 00105 static const unsigned int LCD_character_table[] PROGMEM = /* Character definitions table. */ 00106 { 00107 0x0000, /* '*' (?) */ 00108 0x2830, /* '+' */ 00109 0x0000, /* ',' (Not defined) */ 00110 0x0810, /* '-' */ 00111 0x0200, /* '.' */ 00112 0x0240, /* '/' */ 00113 0x93C5, /* '0' */ 00114 0x80C0, /* '1' */ 00115 0x1994, /* '2' */ 00116 0x9894, /* '3' */ 00117 0x8891, /* '4' */ 00118 0x9815, /* '5' */ 00119 0x9915, /* '6' */ 00120 0x8084, /* '7' */ 00121 0x9995, /* '8' */ 00122 0x9895, /* '9' */ 00123 0x0000, /* ':' (Not defined) */ 00124 0x0000, /* ';' (Not defined) */ 00125 0x0000, /* '<' (Not defined) */ 00126 0x0000, /* '=' (Not defined) */ 00127 0x0202, /* '>' */ 00128 0x0000, /* '?' (Not defined) */ 00129 0x8E53, /* '@' (redefined as '%') */ 00130 0x8995, /* 'A' (+ 'a') */ 00131 0xB8A4, /* 'B' (+ 'b') */ 00132 0x1105, /* 'C' (+ 'c') */ 00133 0xB0A4, /* 'D' (+ 'd') */ 00134 0x1915, /* 'E' (+ 'e') */ 00135 0x0915, /* 'F' (+ 'f') */ 00136 0x9905, /* 'G' (+ 'g') */ 00137 0x8991, /* 'H' (+ 'h') */ 00138 0x2020, /* 'I' (+ 'i') */ 00139 0x9180, /* 'J' (+ 'j') */ 00140 0x0551, /* 'K' (+ 'k') */ 00141 0x1101, /* 'L' (+ 'l') */ 00142 0x81C3, /* 'M' (+ 'm') */ 00143 0x8583, /* 'N' (+ 'n') */ 00144 0x9185, /* 'O' (+ 'o') */ 00145 0x0995, /* 'P' (+ 'p') */ 00146 0x9585, /* 'Q' (+ 'q') */ 00147 0x0D95, /* 'R' (+ 'r') */ 00148 0x1406, /* 'S' (+ 's') */ 00149 0x2024, /* 'T' (+ 't') */ 00150 0x9181, /* 'U' (+ 'u') */ 00151 0x0341, /* 'V' (+ 'v') */ 00152 0x8781, /* 'W' (+ 'w') */ 00153 0x0642, /* 'X' (+ 'x') */ 00154 0x2042, /* 'Y' (+ 'y') */ 00155 0x1244, /* 'Z' (+ 'z') */ 00156 0x0000, /* '[' (Not defined) */ 00157 0x0000, /* '\' (Not defined) */ 00158 0x0000, /* ']' (Not defined) */ 00159 0x0000, /* '^' (Not defined) */ 00160 0x0000, /* '_' (Not defined) */ 00161 0x0004, /* A */ 00162 0x0080, /* B */ 00163 0x8000, /* C */ 00164 0x1000, /* D */ 00165 0x0100, /* E */ 00166 0x0001, /* F */ 00167 0x0002, /* G */ 00168 0x0020, /* H */ 00169 0x0040, /* J */ 00170 0x0800, /* K */ 00171 0x0400, /* L */ 00172 0x2000, /* M */ 00173 0x0200, /* N */ 00174 0x0010, /* O */ 00175 0x0000, 00176 0x0000, 00177 0x0000 00178 }; 00179 00180 /** \brief Seven segment reference guide in flash. */ 00181 static const unsigned char seg_inf[] PROGMEM = { 00182 2<<5|19, /* A */ 00183 1<<5|19, /* B */ 00184 1<<5|9, /* C */ 00185 2<<5|4, /* D */ 00186 2<<5|9, /* E */ 00187 2<<5|14, /* F */ 00188 1<<5|14 /* G */ 00189 }; 00190 00191 /** \brief LCD symbol chart located in flash. */ 00192 static const lcd_symbol_t lcd_symbol_chart[LCD_SYMBOL_COUNT] PROGMEM= { 00193 /* Raven */ 00194 LCD_SYMBOL_RAVEN , 00195 00196 /* Audio */ 00197 LCD_SYMBOL_BELL , 00198 LCD_SYMBOL_TONE , 00199 LCD_SYMBOL_MIC , 00200 LCD_SYMBOL_SPEAKER , 00201 00202 /* Status */ 00203 LCD_SYMBOL_KEY , 00204 LCD_SYMBOL_ATT , 00205 00206 /* Time */ 00207 LCD_SYMBOL_SUN , 00208 LCD_SYMBOL_MOON , 00209 LCD_SYMBOL_AM , 00210 LCD_SYMBOL_PM , 00211 00212 /* Radio comus */ 00213 LCD_SYMBOL_RX , 00214 LCD_SYMBOL_TX , 00215 LCD_SYMBOL_IP , 00216 LCD_SYMBOL_PAN , 00217 LCD_SYMBOL_ZLINK , 00218 LCD_SYMBOL_ZIGBEE , 00219 00220 /* Antenna status */ 00221 LCD_SYMBOL_ANT_FOOT, 00222 LCD_SYMBOL_ANT_SIG1, 00223 LCD_SYMBOL_ANT_SIG2, 00224 LCD_SYMBOL_ANT_SIG3, 00225 LCD_SYMBOL_ANT_DIS , 00226 00227 /* Battery status */ 00228 LCD_SYMBOL_BAT_CONT, 00229 LCD_SYMBOL_BAT_CAP1, 00230 LCD_SYMBOL_BAT_CAP2, 00231 LCD_SYMBOL_BAT_CAP3, 00232 00233 /* Envelope status */ 00234 LCD_SYMBOL_ENV_OP , 00235 LCD_SYMBOL_ENV_CL , 00236 LCD_SYMBOL_ENV_MAIN, 00237 00238 /* Temperature */ 00239 LCD_SYMBOL_C , 00240 LCD_SYMBOL_F , 00241 00242 /* Numeric */ 00243 LCD_SYMBOL_MINUS , 00244 LCD_SYMBOL_DOT , 00245 LCD_SYMBOL_COL 00246 }; 00247 #endif /* !DOXYGEN */ 00248 00249 /** LCD text buffer */ 00250 static unsigned char lcd_text[20]; 00251 00252 /** Textd buffer read pointer for text field in LCD display. When ptr>0 characters in front will be cleared (space) */ 00253 static int lcd_text_rd_ptr = 0; 00254 00255 /** Text pointer for writing new chars to text buffer */ 00256 static int lcd_text_wr_ptr = 0; 00257 00258 static bool lcd_scroll_enable; 00259 static int lcd_scroll_prescale; 00260 static int lcd_scroll_prescale_value; 00261 static int lcd_num_print(uint16_t numb, bool negative, lcd_padding_t padding); 00262 static void lcd_nmb_print_dig(uint8_t val, int dig); 00263 static int lcd_text_sl(void); 00264 static int lcd_text_put(const char* s, int pos); 00265 static int lcd_char_put(unsigned char c, int pos); 00266 00267 /*---------------------------------------------------------------------------*/ 00268 00269 /** 00270 * \brief This function will initialize the proper settings for the LCD driver. 00271 * 00272 * This ATmega3290p can directly support an LCD through register mapping. 00273 * 00274 * \return 0 00275 */ 00276 int 00277 lcd_init(void) 00278 { 00279 /* 00280 * Configuring LCD with Extern clock (TOSC, 32.768kHz) 00281 * 32786 Hz 32786 Hz 00282 * frame_rate = ------------------ = ------------- = 32 Hz 00283 * 8 * .prescl * .div 8 * 16 * 8 00284 */ 00285 00286 lcd_config_t lcd_config ; 00287 lcd_config.blanking = LCD_BLANKING_OFF; 00288 lcd_config.buffer = LCD_BUFFER_ON; 00289 lcd_config.wave = LCD_WAVE_LOW_POWER; 00290 lcd_config.clock = LCD_CLOCK_EXTERN; 00291 lcd_config.bias = LCD_BIAS_HALF; 00292 lcd_config.prescl = LCD_PRESCL_16; 00293 lcd_config.div = LCD_DIV_8; 00294 lcd_config.drive = LCD_DRIVE_450; 00295 lcd_config.contrast = LCD_CONTRAST_3_30; 00296 00297 /* Enable module */ 00298 PRR &= ~(1 << PRLCD); 00299 00300 /* Configure and enable LCD controller */ 00301 LCDCRB = lcd_config.lcdcrb|(LCD_PM_0_39<<LCDPM0)|(LCD_DUTY_QUART<<LCDMUX0); /* Add port mask/mux */ 00302 LCDFRR = lcd_config.lcdfrr; 00303 LCDCCR = lcd_config.lcdccr; 00304 LCDCRA = lcd_config.lcdcra|(1<<LCDEN)|(1<<LCDIE); /* Add interrupt- and LCD- enable */ 00305 00306 /* clear screen */ 00307 lcd_symbol_clr_all(); 00308 00309 /* Calculate scrolling value */ 00310 lcd_scroll_prescale_value = LCD_CLCK_FRQ/128; 00311 lcd_scroll_prescale_value >>= (lcd_config.prescl == 0) ? 4 : (5+lcd_config.prescl); 00312 lcd_scroll_prescale_value /= (lcd_config.div+1); 00313 lcd_scroll_prescale_value = (lcd_scroll_prescale_value==0) ? 1 : lcd_scroll_prescale_value; 00314 lcd_scroll_prescale = lcd_scroll_prescale_value; 00315 00316 return 0; 00317 } 00318 00319 /*---------------------------------------------------------------------------*/ 00320 00321 /** 00322 * \brief This will disable the LCD operation. 00323 */ 00324 void 00325 lcd_deinit(void) 00326 { 00327 while (!(LCDCRA & (1<<LCDIF))) 00328 ; 00329 /* 00330 * Set LCD Blanking and clear interrupt flag 00331 * by writing a logical one to the flag. 00332 */ 00333 00334 LCDCRA = (1<<LCDEN)|(1<<LCDIF)|(1<<LCDBL); 00335 /* Wait until LCD Blanking is effective. */ 00336 while ( !(LCDCRA & (1<<LCDIF)) ) 00337 ; 00338 00339 /* Disable LCD */ 00340 LCDCRA = (0<<LCDEN) | (0<<LCDIE); 00341 00342 /* power LCD down */ 00343 PRR |= (1 << PRLCD); 00344 } 00345 00346 /*---------------------------------------------------------------------------*/ 00347 00348 /** 00349 * \brief This will convert the incoming decimal number to BCD. 00350 * 00351 * \param inNumber Decimal number to convert 00352 * 00353 * \return newByte The converted deicmal number as byte. 00354 */ 00355 uint8_t 00356 itobcd(uint8_t inNumber) 00357 { 00358 int newByte; 00359 00360 newByte = 0; 00361 00362 while (inNumber >= 10){ 00363 inNumber -= 10; 00364 newByte++; 00365 } 00366 00367 newByte = newByte << 4; 00368 newByte = (newByte | inNumber); 00369 00370 return newByte; 00371 } 00372 00373 /*---------------------------------------------------------------------------*/ 00374 00375 /** 00376 * \brief This will put a HEX value on the LCD that represents the input 00377 * parameter. 00378 * 00379 * \param numb Number to display as HEX. 00380 * \param padding This pads the location to place the value on the LCD. 00381 * 00382 * \return lcd_num_print() 00383 */ 00384 int 00385 lcd_num_puthex(uint16_t numb, lcd_padding_t padding) 00386 { 00387 return lcd_num_print(numb, false, padding); 00388 } 00389 00390 /*---------------------------------------------------------------------------*/ 00391 00392 /** 00393 * \brief This will put a DEC value on the LCD that represents the input 00394 * parameter. 00395 * 00396 * \param numb Number to display as DEC. 00397 * \param padding This pads the location to place the value on the LCD. 00398 * 00399 * \return lcd_num_print() 00400 */ 00401 int 00402 lcd_num_putdec(int numb, lcd_padding_t padding) 00403 { 00404 uint16_t bcd; 00405 00406 /* Check for overflow */ 00407 if (numb > 9999) { 00408 numb = 9999; 00409 } else if (numb < -9999) { 00410 numb = -9999; 00411 } 00412 00413 /* Convert to BCD */ 00414 bcd = itobcd(abs(numb)); 00415 00416 /* Print */ 00417 return lcd_num_print(bcd, (bool)(numb<0), padding); 00418 } 00419 00420 /*---------------------------------------------------------------------------*/ 00421 00422 /** 00423 * \brief This will clear numbers displayed on the LCD. 00424 * 00425 * \return 0 00426 */ 00427 int 00428 lcd_num_clr(void) 00429 { 00430 volatile unsigned char* lcd_data = (volatile unsigned char*)0xEC; 00431 int i,j; 00432 00433 for (i=0;i<4;++i){ 00434 for (j=0;j<7;++j){ 00435 lcd_data[pgm_read_byte(&seg_inf[j])&0x1F] &= ~((pgm_read_byte(&seg_inf[j])>>5)<<(i*2)); 00436 } 00437 } 00438 return 0; 00439 } 00440 00441 /*---------------------------------------------------------------------------*/ 00442 00443 /** 00444 * \brief This will put a string of characters out to the LCD. 00445 * 00446 * \param s First character pointer of string. 00447 * 00448 * \return 0 00449 */ 00450 int 00451 lcd_puts(const char* s) 00452 { 00453 strcpy((char*)lcd_text, s); 00454 lcd_text_wr_ptr = strlen(s); 00455 lcd_text_rd_ptr = 0; 00456 00457 lcd_text_put((char*)&lcd_text[lcd_text_rd_ptr], 1); 00458 00459 lcd_scroll_enable = (lcd_text_wr_ptr > 7) ? true : false; 00460 00461 return 0; 00462 } 00463 00464 /*---------------------------------------------------------------------------*/ 00465 00466 /** 00467 * \brief This will put a string of characters of a certain length out to the LCD. 00468 * 00469 * \param length Length of string to print. 00470 * \param s First character pointer of string. 00471 * 00472 * \return 0 00473 */ 00474 int 00475 lcd_puta(size_t length, const uint8_t *s) 00476 { 00477 memcpy((void*)lcd_text, (void const*)s, length); 00478 lcd_text_wr_ptr = length; 00479 lcd_text_rd_ptr = 0; 00480 00481 lcd_text_put((char*)&lcd_text[lcd_text_rd_ptr], 1); 00482 00483 lcd_scroll_enable = (lcd_text_wr_ptr > 7) ? true : false; 00484 00485 return 0; 00486 } 00487 00488 /*---------------------------------------------------------------------------*/ 00489 00490 /** 00491 * \brief This will put a string out to the LCD from Flash. 00492 * 00493 * \param s First character pointer of the string located in Flash 00494 * 00495 * \return 0 00496 */ 00497 int 00498 lcd_puts_P(const char *s) 00499 { 00500 strcpy_P((char*)lcd_text, s); 00501 lcd_text_wr_ptr = strlen_P(s); 00502 lcd_text_rd_ptr = 0; 00503 00504 lcd_text_put((char*)&lcd_text[lcd_text_rd_ptr], 1); 00505 00506 lcd_scroll_enable = (lcd_text_wr_ptr > 7) ? true : false; 00507 00508 return 0; 00509 } 00510 00511 /*---------------------------------------------------------------------------*/ 00512 00513 /** 00514 * \brief This will put a single character out to the LCD. 00515 * 00516 * \param c Character to display on LCD. 00517 * 00518 * \return 0 00519 */ 00520 int 00521 lcd_putchar(unsigned char c) 00522 { 00523 lcd_text[lcd_text_wr_ptr++] = c; 00524 lcd_text[lcd_text_wr_ptr] = 0; 00525 00526 lcd_text_put((char*)&lcd_text[lcd_text_rd_ptr], 1); 00527 00528 lcd_scroll_enable = (lcd_text_wr_ptr > 7) ? true : false; 00529 00530 return 0; 00531 } 00532 00533 /*---------------------------------------------------------------------------*/ 00534 00535 /** 00536 * \brief This will enable any of the symbols on the Raven LCD. 00537 * 00538 * \param symbol Specific symbol to enable on the LCD. 00539 */ 00540 void 00541 lcd_symbol_set(lcd_symbol_t symbol) 00542 { 00543 unsigned char mem_offset; 00544 unsigned char bit_offset; 00545 volatile unsigned char* lcd_data = (volatile unsigned char*)0xEC; 00546 00547 /* Symbol format = bbbnnnnn where b is bit and n is offset */ 00548 bit_offset = (symbol >> 5); 00549 mem_offset = (symbol & 0x1F); 00550 if ( mem_offset >= 20 ){ 00551 return; /* Data out of range of the LCD registers */ 00552 } 00553 lcd_data = lcd_data + mem_offset; /* Point to the relevant LCDDR */ 00554 00555 *lcd_data = *lcd_data | ( 1 << bit_offset); 00556 } 00557 00558 /*---------------------------------------------------------------------------*/ 00559 00560 /** 00561 * \brief This will clear any symbol on the Raven LCD. 00562 * 00563 * \param symbol Specific symbol to clear from the LCD. 00564 */ 00565 void 00566 lcd_symbol_clr(lcd_symbol_t symbol) 00567 { 00568 unsigned char offset; 00569 unsigned char setbit; 00570 volatile unsigned char* lcd_data = (volatile unsigned char*)0xEC; 00571 00572 /* symbol format = bbbnnnnn where b is bit and n is offset */ 00573 setbit = (symbol >> 5); 00574 offset = (symbol & 0x1F); 00575 if ( offset >= 20 ){ 00576 return; /* data out of range of the LCD registers */ 00577 } 00578 00579 lcd_data = lcd_data + offset; /* Point to the relevant LCDDR */ 00580 00581 *lcd_data = *lcd_data & ~( 1 << setbit); 00582 } 00583 00584 /*---------------------------------------------------------------------------*/ 00585 00586 /** 00587 * \brief This will enable a group of symbols from the lcd_symbol_chart. 00588 * 00589 * \param start Position of table to start from. 00590 * \param count Number of symbols to enable from start position. 00591 */ 00592 void 00593 lcd_symbol_set_group(int start, int count) 00594 { 00595 count = (start + count)>LCD_SYMBOL_COUNT ? 00596 LCD_SYMBOL_COUNT - start : 00597 count; 00598 int i; 00599 00600 for(i=start; i<start+count; ++i){ 00601 lcd_symbol_set(pgm_read_byte(&lcd_symbol_chart[i])); 00602 } 00603 } 00604 00605 /*---------------------------------------------------------------------------*/ 00606 00607 /** 00608 * \brief This will disable a group of symbols from the lcd_symbol_chart. 00609 * 00610 * \param start Position of table to start from. 00611 * \param count Number of symbols to disable from start position. 00612 */ 00613 void 00614 lcd_symbol_clr_group(int start, int count) 00615 { 00616 count = (start + count)>LCD_SYMBOL_COUNT ? 00617 LCD_SYMBOL_COUNT - start : 00618 count; 00619 int i; 00620 00621 for(i=start; i<count; ++i){ 00622 lcd_symbol_clr(pgm_read_byte(&lcd_symbol_chart[i])); 00623 } 00624 } 00625 00626 /*---------------------------------------------------------------------------*/ 00627 00628 /** 00629 * \brief This will print a number to the LCD with the following parameters. 00630 * 00631 * \param numb Number to display on LCD. 00632 * \param negative Display negative sign in the next digit field. 00633 * \param padding This pads the location to place the value on the LCD. 00634 * 00635 * \return 0 00636 */ 00637 static int 00638 lcd_num_print(uint16_t numb, bool negative, lcd_padding_t padding) 00639 { 00640 int i; 00641 for (i=0;i<4;/**/) { 00642 /* Get segments for this digit and print it */ 00643 lcd_nmb_print_dig(pgm_read_byte(&seg_map[(numb&(0xF<<4*i))>>4*i]), i); 00644 00645 /* If rest of number is zero */ 00646 if (++i<4) { 00647 if (numb >> 4*i == 0) { 00648 if (negative == true) { /* print a 'minus' in the next digit field */ 00649 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++); 00650 if (padding == LCD_NUM_PADDING_ZERO) { 00651 lcd_symbol_set(LCD_SYMBOL_MINUS); 00652 } 00653 } else { 00654 lcd_symbol_clr(LCD_SYMBOL_MINUS); 00655 } 00656 while (i<4){ 00657 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++); 00658 } 00659 } 00660 } else { 00661 if (negative == true) { 00662 lcd_symbol_set(LCD_SYMBOL_MINUS); 00663 } else { 00664 lcd_symbol_clr(LCD_SYMBOL_MINUS); 00665 } 00666 } 00667 } 00668 return 0; 00669 } 00670 00671 /*---------------------------------------------------------------------------*/ 00672 00673 /** 00674 * \brief This will print a number according to the segment map of the LCD. 00675 * 00676 * \param val Number that is to be matched to appropriate segments. 00677 * \param dig Segment to enable 00678 */ 00679 static void 00680 lcd_nmb_print_dig(uint8_t val, int dig) 00681 { 00682 volatile unsigned char* lcd_data = (volatile unsigned char*)0xEC; 00683 int j; 00684 00685 for (j=0;j<7;++j){ 00686 if (val & (1<<j)) { 00687 lcd_data[pgm_read_byte(&seg_inf[j])&0x1F] |= (pgm_read_byte(&seg_inf[j])>>5)<<(dig*2); 00688 } 00689 else { 00690 lcd_data[pgm_read_byte(&seg_inf[j])&0x1F] &= ~((pgm_read_byte(&seg_inf[j])>>5)<<(dig*2)); 00691 } 00692 } 00693 } 00694 00695 /*---------------------------------------------------------------------------*/ 00696 00697 /** 00698 * \brief This will scroll the test on the LCD. 00699 * 00700 * \return 0 00701 */ 00702 static int 00703 lcd_text_sl(void) 00704 { 00705 static int pos = 1; 00706 if (lcd_text[lcd_text_rd_ptr] == 0) { 00707 lcd_text_rd_ptr = 0; 00708 pos = 7; 00709 } 00710 else { 00711 if (pos){ 00712 pos--; 00713 } 00714 else { 00715 lcd_text_rd_ptr++; 00716 } 00717 } 00718 00719 lcd_text_put((char*)&lcd_text[lcd_text_rd_ptr], pos); 00720 return 0; 00721 } 00722 00723 /*---------------------------------------------------------------------------*/ 00724 00725 /** 00726 * \brief This will put test out to the LCD at a certain location padded with 00727 * spaces. 00728 * 00729 * \param s First character pointer to the string of test to print. 00730 * \param pos Count of spaces entered before printing the text. 00731 * 00732 * \return 0 00733 */ 00734 static int 00735 lcd_text_put(const char* s, int pos) 00736 { 00737 int i; 00738 00739 /* Pad with spaces in front if offset > 0 */ 00740 for (i=1; i<pos; i++) { 00741 lcd_char_put(' ', i); 00742 } 00743 00744 /* Print characters, overwrite with spaces at end if necessary */ 00745 for ( i=pos; i<=7; ++i) { 00746 if (*s == 0) { 00747 lcd_char_put(' ', i); 00748 } 00749 else { 00750 lcd_char_put( (unsigned char)*s++, i); 00751 } 00752 } 00753 return 0; 00754 } 00755 00756 /*---------------------------------------------------------------------------*/ 00757 00758 /** 00759 * \brief This will put a single char out to the LCD by looking up the 00760 * proper segments. 00761 * 00762 * \param c Character to display on the LCD. 00763 * \param pos This will add spaces for positioning the text on the LCD. 00764 * 00765 * \return 0 00766 */ 00767 static int 00768 lcd_char_put(unsigned char c, int pos) 00769 { 00770 unsigned int seg, segMask; 00771 unsigned char i; 00772 unsigned char mask, nibble, nibbleMask; 00773 00774 volatile unsigned char* lcd_data = (volatile unsigned char*)0xEC; 00775 unsigned char lcd_reg; 00776 00777 if (pos > 7){ 00778 return EOF; 00779 } 00780 00781 /* Lookup character table for segmet data */ 00782 if (((c >= '*') && (c <= 'z')) || (c == ' ')){ 00783 if (c >= 'a' ){ 00784 c &= ~0x20; /* c is in character_table. Convert to upper if necessarry. */ 00785 } 00786 if (c == ' ') { 00787 c = 0x00; 00788 } 00789 else { 00790 c -= '*'; 00791 } 00792 if ( c > 0x35 ){ 00793 return EOF; /* c points outside array */ 00794 } 00795 else{ 00796 seg = pgm_read_dword(&LCD_character_table[c]); 00797 } 00798 } 00799 else { 00800 return EOF; /* ASCII code out of range */ 00801 } 00802 00803 00804 /* Adjust mask according to digit */ 00805 segMask = 0x4008; /* masking out two bits */ 00806 00807 i = pos-1; /*i used as pointer offset */ 00808 i >>= 1; 00809 lcd_data += i; /* Point to the first relevant LCDDR; i = {0,0,1,1,2,2} */ 00810 00811 i = 4; /*i used as loop counter */ 00812 do{ 00813 nibble = seg & 0x000F; 00814 nibbleMask = segMask & 0x000F; 00815 00816 seg >>= 4; 00817 segMask >>= 4; 00818 00819 if (pos & 0x01) { 00820 mask = 0xF0 | nibbleMask; 00821 } 00822 else { 00823 nibble <<= 4; 00824 mask = 0x0F | ( nibbleMask <<4 ); 00825 } 00826 lcd_reg = *lcd_data; 00827 *lcd_data |= (lcd_reg & mask) | nibble; /* Write new bit values */ 00828 00829 lcd_reg = *lcd_data; 00830 *lcd_data &= (lcd_reg & mask) | nibble; 00831 00832 lcd_data += 5; 00833 } while ( --i ); 00834 00835 return 0; 00836 } 00837 00838 /*---------------------------------------------------------------------------*/ 00839 00840 /** 00841 * \brief This is the LCD Start of Frame Interrupt Subroutine. 00842 * 00843 * This interrupt fires at the beginning of a new frame. 00844 */ 00845 ISR 00846 (LCD_vect) 00847 { 00848 if (lcd_scroll_enable) { 00849 if (--lcd_scroll_prescale == 0) { 00850 lcd_text_sl(); 00851 lcd_scroll_prescale = lcd_scroll_prescale_value; 00852 } 00853 } 00854 } 00855 00856 /*---------------------------------------------------------------------------*/ 00857 00858 /** 00859 * \brief Turns the Raven nose LED on. 00860 */ 00861 void 00862 led_on(void) 00863 { 00864 DDRB |= 0x80; 00865 PORTB &= ~0x80; 00866 } 00867 00868 /*---------------------------------------------------------------------------*/ 00869 00870 /** 00871 * \brief Turns the Raven nose LED off. 00872 */ 00873 void 00874 led_off(void) 00875 { 00876 DDRB &= ~0x80; 00877 PORTB |= 0x80; 00878 } 00879 00880 /*---------------------------------------------------------------------------*/ 00881 00882 /** 00883 * \brief This will add the passed in number to any of the four locations of 00884 * the four digit segment display on the LCD. 00885 * 00886 * \param numb Number to display. 00887 * \param pos Position to display number. 00888 */ 00889 void 00890 lcd_single_print_dig(uint8_t numb, uint8_t pos) 00891 { 00892 lcd_nmb_print_dig(pgm_read_byte(&seg_map[numb]), pos); 00893 } 00894 00895 /** \} */