From: lottaviano Date: Wed, 16 Mar 2011 13:26:11 +0000 (+0000) Subject: Add seven segment LED driver. X-Git-Tag: 2.7.0~187 X-Git-Url: https://codewiz.org/gitweb?a=commitdiff_plain;ds=sidebyside;h=abdd9dd68114e8e1df56825615258ae1ce2fe14c;p=bertos.git Add seven segment LED driver. Signed-off-by: Fabio Bizzi git-svn-id: https://src.develer.com/svnoss/bertos/trunk@4779 38d2e660-2303-0410-9eaa-f027e97ec537 --- diff --git a/bertos/drv/led_7seg.c b/bertos/drv/led_7seg.c new file mode 100644 index 00000000..d89ef377 --- /dev/null +++ b/bertos/drv/led_7seg.c @@ -0,0 +1,527 @@ +/** + * \file led_7seg.c + * + * + * \brief 7 segments LED displays (impl) + * + * \author Fabio Bizzi + * + * \addtogroup SevenSegDisplay 7 Segments LED Displays Driver + * \{ + * + */ + +#include "drv/led_7seg.h" +#include "hw/hw_led_7seg.h" +#include "cfg/cfg_arch.h" +#include +#include + +/* + * Define the timer for the refreshing + */ +static Timer sseg_trefresh; + +/* + * FUNCTION: sseg_refresh + * + * This is the procedure that prints the seven_seg structure'string to the display. + * It prints a single digit at time and does all the checks to a proper display. + * It is called by the wrapper function fired by the timer set in the init procedure. + * + * param SS The void pointer that holds the pointer to the data structure + * + */ +static void sseg_refresh(SevenSeg *SS) +{ + /* First Check if the structure is being edited we do a silent exit*/ + if (SS->busyedit == true) + return; + + /* If we have displayed all the digits */ + if (SS->curdigit == CONFIG_LED_7SEG_DIGIT) + { + sseg_off(); + /* And if we have to display again all the digit */ + if (SS->curspeed > 0) + { + SS->curspeed--; + SS->curdigit = 0; + SS->curpos -= CONFIG_LED_7SEG_DIGIT; + } + /* Else is time to scroll the text */ + else + { + /* If we aren't at the end of the string */ + if (SS->curpos < SS->string_len) + { + SS->curpos -= CONFIG_LED_7SEG_DIGIT; + SS->curpos++; + SS->curdigit = 0; + SS->curspeed = SS->speed; + } + /* Else we are at the end of the string */ + else + { + /* Set that the string was displayed at least one time and we can accept a new text*/ + SS->firstrun = false; + /* If the string has to be displayed only one time we set an empty string + * to display till next print request*/ + if (SS->runonce == true) + sevenseg_clear(SS); + /* Else we reset the text to it's first character ad do again the display */ + else + { + SS->curdigit = 0; + SS->curpos = 0; + SS->curspeed = SS->speed; + } + } + } + } + /* Else We have to do a print*/ + else + { + /* If the text doesn't have to blink we write the character to the proper disply's digit */ + if (SS->blink == false) + sseg_on(SS->string[SS->curpos], SS->curdigit); + /* Else we do the blinking */ + else + { + /* If bdigit == 0 we have to blink all the digits */ + if (SS->bdigit == 0) + { + if (SS->curspeed >= (SS->speed/2)) + sseg_on(SS->string[SS->curpos], SS->curdigit); + else + sseg_off(); + } + /* else we have to blink only one digit (bdigit -1) */ + else + /* is this the digit to blink? */ + if (SS->curdigit == ((unsigned int)SS->bdigit-1)) + { + if (SS->curspeed >= (SS->speed/2)) + sseg_on(SS->string[SS->curpos], SS->curdigit); + else + sseg_off(); + } + /* no, so let do a normal print */ + else + sseg_on(SS->string[SS->curpos], SS->curdigit); + } + /* Ok, next time next char.... ;) */ + SS->curdigit++; + SS->curpos++; + } +} + +/* + * FUNCTION: sseg_refresh_wrapper + * + * This is a "wrapper" procedure that is called by the timer_setSoftint() + * with the unique purpose to call the real sseg_refresh procedure without + * the cast of the structure from void to SevenSeg. + * + * param VSS The void pointer that holds the pointer to the data structure + * + */ +static void sseg_refresh_wrapper(void *VSS) +{ + /* Here we cast the Structure from void to proper type */ + SevenSeg *SS; + SS = (SevenSeg *)VSS; + /* now we call the right refresh routine */ + sseg_refresh(SS); + /* ReStart the timer */ + timer_add(&sseg_trefresh); +} + +/* + * FUNCTION: sseg_tabcheck + * + * This function return the position of the ascii character in the hex + * segstable. + * + * param source The ascii char to be positioned + */ +INLINE uint8_t sseg_tabcheck(char source) +{ + uint8_t hexchar=38; + + /* Numbers */ + if ((((int)source) > 47) && (((int)source) < 58)) + hexchar = source-48; + else + /* Capital Letters */ + if ((((int)source) > 64) && (((int)source) < 91)) + hexchar = source-53; + else + /* Letters */ + if ((((int)source) > 96) && (((int)source) < 123)) + hexchar = source-85; + else + /* Minus */ + if (((int)source) == 45) + hexchar = 11; + else + /* Space */ + if (((int)source) == 32) + hexchar = 38; + else + /* Dot */ + if (((int)source) == 46) + hexchar = 10; + return hexchar; +} + +/** + * \brief Print a string on the display + * + * This is the procedure that fills the seven_seg structure with the translated + * string to display. It swaps also the structures to display the new text when + * all the data is ready to display. + * + * \param SS Pointer to the SevenSeg structure + * \param sstring String to be displayed + * + * \return 0 if all went well, -1 if the display is locked, -2 if the string too long. + */ +int sevenseg_print(SevenSeg *SS, const char *sstring) +{ + size_t string_lenght; + unsigned int x,y,dotnumber; + bool dotjump = false; + uint8_t hexchar; + + /* Check if the display is unlocked */ + if (SS->busyedit == false) + return -1; + + /* Check if the string is too big */ + if (sizeof(&sstring) > (CONFIG_LED_7SEG_STRLEN-(2*CONFIG_LED_7SEG_DIGIT))) + return -2; + + /* get the string length and set the number of dots in the string to 0 */ + string_lenght = strlen(sstring); + dotnumber = 0; + + /* check if there are some dots in the string and report the number in dotnumber */ + for (x=0;x<(unsigned int)string_lenght;x++) + { + if (((int)sstring[x]) == 46) + dotnumber++; + } + + /* If the *REAL* lenght of the string is less or equal than the number of digits */ + if (((int)string_lenght-dotnumber) <= CONFIG_LED_7SEG_DIGIT) + { + /* If the *REAL* lenght of the string is less than number of digits */ + if (((int)string_lenght-dotnumber) < CONFIG_LED_7SEG_DIGIT) + { + /* Fill the left side of the string with blanks */ + for (x=0; x<(CONFIG_LED_7SEG_DIGIT-((int)string_lenght-dotnumber)); x++) + SS->string[x] = segstable[38]; + y = x; + } + else + { + /* Else we have the exact string length of the display */ + y = 0; + } + } + else + { + /* Else we have the string length bigger than the display and we need to fill + * the entire left side of the string with blanks to begin the scroll from the + * rigthest side of the display */ + for (x=0; xstring[x] = segstable[38]; + y = CONFIG_LED_7SEG_DIGIT; + } + /* Here we start to fill the string with the Hex 7seg characters values */ + hexchar = 0; + for (x=0; x<(unsigned int)string_lenght; x++) + { + hexchar = sseg_tabcheck(sstring[x]); + /* do we have a dot? */ + if (hexchar == 10) + { + /* If we are at the first character of the string it has to be forced + * as "lonly" dot ;) */ + if (x > 0) + { +#if CONFIG_LED_7SEG_CCAT + SS->string[y-1] = SS->string[y-1] | segstable[(int)hexchar]; +#else + SS->string[y-1] = SS->string[y-1] & segstable[(int)hexchar]; +#endif + dotjump = true; + } + } + /* If the last character was a dot and we aren't at the first character of the string + * we have just inserted it */ + if (dotjump) + dotjump = false; + /* Let's put the character in the structure's string */ + else + { + SS->string[y] = segstable[(int)hexchar]; + y++; + } + } + /* If we have the string length bigger than the display we need to fill + * the entire right side of the string with blanks to end the scroll + * to the rigthest side of the display */ + if (((int)string_lenght-dotnumber) > CONFIG_LED_7SEG_DIGIT) + { + for (x=0; xstring[y] = segstable[38]; + y++; + } + } + /* Let's put the total string length to the structure */ + SS->string_len = y; + + return 0; +} + +/** + * \brief initialize the structure and the timer for the display + * + * This is the procedure that inits all the structures that rules the 7 segments + * display and set the timer for the proper print/refresh of the text. + * + * \param SS Pointer to the SevenSeg structure + */ +void sevenseg_init(SevenSeg *SS) +{ + /* + * Init the 7segments string structure + */ + SS->busyedit = true; + sevenseg_clear(SS); + SS->busyedit = false; + + /* + * Init the I/O ports and set the display OFF + */ + sseg_init(); + + /* + * Define the timer for the refresh of the display + * The timer calls the sevenseg_refresh function + * every "CONFIG_LED_7SEG_RTIME" milliseconds for + * an acceptable persistance of a single 7 segments + * display. + */ + // set the callback + timer_setSoftint(&sseg_trefresh, sseg_refresh_wrapper, (void *)SS); + // expire time: 1s + timer_setDelay(&sseg_trefresh, ms_to_ticks(CONFIG_LED_7SEG_RTIME)); + // start the timer + timer_add(&sseg_trefresh); +} + +/** + * \brief check if is possible to do a new print + * + * This is the procedure that check if the print of the current text is run + * almost one time and we're ready to print a new text. + * + * \param SS Pointer to the SevenSeg structure + * + * \return true if we can print a new text, false if we're still printing the previous text for the first time and we have to wait. + */ +bool sevenseg_isReady(SevenSeg *SS) +{ + return !SS->firstrun; +} + +/** + * \brief unlock the SevenSeg structure and stops the print + * + * This is the procedure that check if the print of the current text is run + * almost one time and then set the status of the display to "unlocked". + * + * \param SS Pointer to the SevenSeg structure + * + * \return true if the display is unlocked, false if the dispaly is still locked. + */ +bool sevenseg_unlock(SevenSeg *SS) +{ + if (SS->firstrun == false) + { + SS->busyedit = true; + SS->firstrun = true; + SS->curdigit = 0; + SS->curpos = 0; + } + else + return false; + return true; +} + +/** + * \brief lock the SeveSeg structure and starts a new print + * + * This is the procedure that lock the display and permit + * the print of the text. + * + * \param SS Pointer to the SevenSeg structure + * + * \return true if the display is now locked, false if the display was already locked. + */ +bool sevenseg_lock(SevenSeg *SS) +{ + if (SS->busyedit == true) + { + /* If the string is longer than the number of the digit of the display we + * reset the single digit blink to zero to be sure that the display of + * the text is clean from previous single digit blinking settings */ + if (SS->string_len > CONFIG_LED_7SEG_DIGIT) + SS->bdigit = 0; + SS->busyedit = false; + } + else + return false; + return true; +} + +/** + * \brief set the blinking of the digits of the display + * + * This is the procedure that set the blinking of the display. + * You can choose to blink all the display or only a single + * digit. + * + * \param SS Pointer to the SevenSeg structure + * \param blink if true the display will blink + * \param digit if 0 all the digits have to blink, else the digit that has to blink + * + * \return true if the set was succesfull, false if the set was not succesfull. + */ +bool sevenseg_setBlink(SevenSeg *SS, bool blink, uint8_t digit) +{ + if (SS->busyedit == true) + { + if (blink == true) + { + if (digit == 0) + SS->bdigit = digit; + else + if ((digit-1) <= CONFIG_LED_7SEG_DIGIT) + SS->bdigit = digit; + else + return false; + } + SS->blink = blink; + } + else + return false; + return true; +} + +/** + * \brief set if the text has to be displayed just one time + * + * This is the procedure that set if the text has to be displayed + * just one time + * + * \param SS Pointer to the SevenSeg structure + * \param runonce true if the text has to be displayed only one time, false if the text has to be displayed till next print + * + * \return true if the set was succesfull, false if the set was not succesfull. + */ +bool sevenseg_setRunonce(SevenSeg *SS, bool runonce) +{ + if (SS->busyedit == true) + SS->runonce = runonce; + else + return false; + return true; +} + +/** + * \brief set the scrolling speed of the text + * + * This is the procedure that set the scrolling speed of the text + * if the text is longer than the display digits or the + * duration of the display if the text is smaller or equal the + * length of display digits. + * + * \param SS Pointer to the SevenSeg structure + * \param r_speed the Scrolling speed or display time + * + * \return true if the set was succesfull, false if the set was not succesfull. + */ +bool sevenseg_setRunspeed(SevenSeg *SS, unsigned int r_speed) +{ + if (SS->busyedit == true) + { + SS->speed = r_speed; + SS->curspeed = r_speed; + } + else + return false; + return true; +} + +/** + * \brief clear the display + * + * This is the procedure that blanks the text to be displayed + * and so on clear the display. + * + * \param SS Pointer to the SevenSeg structure + * + * \return true if the clear was succesfull, false if the clear was not succesfull. + */ +bool sevenseg_clear(SevenSeg *SS) +{ + if (SS->busyedit == true) + { + memset(((void *)&SS->string),segstable[38],sizeof(SS->string)); + SS->string_len = CONFIG_LED_7SEG_DIGIT; + SS->blink = false; + SS->bdigit = 0; + SS->runonce = false; + SS->curdigit = 0; + SS->curpos = 0; + SS->speed = CONFIG_LED_7SEG_SSPEED; + SS->curspeed = CONFIG_LED_7SEG_SSPEED; + SS->firstrun = false; + } + else + return false; + return true; +} + /** \} */ //defgroup drivers diff --git a/bertos/drv/led_7seg.h b/bertos/drv/led_7seg.h new file mode 100644 index 00000000..ee359ec2 --- /dev/null +++ b/bertos/drv/led_7seg.h @@ -0,0 +1,230 @@ +/** + * \file led_7seg.h + * + * + * \author Fabio Bizzi + * + * \defgroup SevenSegDisplay 7 Segments LED Displays Driver + * \ingroup drivers + * \{ + * + * \brief 7 segments LED displays (headers) + * + * Here you find the prototypes and the data structures that + * format and holds the text that has to be displayed by the + * 7 segments display. + * + * The main function is the sevenseg_print() + * that is called by your software to display the text, also + * important is the sevenseg_init() that initialize the data + * structures and set the refresh timer, you need to call + * this procedure just one time in the init procedure of + * your software before any use of the sevenseg_print(). + * + * Usage: + * + * To use succesfully the display you have to follow these steps: + * + * \li Create the structure and init the display + * \li Check if the display is ready to accept a new print with + * the function sevenseg_isReady() + * \li Unlock the display with the function sevenseg_unlock() + * NOTE: when the display is unlocked the displaying of any + * text is stopped but the data (text and attributes like text + * position, blinking etc etc) are not erased. + * \li Set the wanted text attributes with sevenseg_set* functions + * \li Print the wanted text with sevenseg_print() + * \li Lock the display with sevenseg_lock() + * + * When the display is locked the displaying of the text starts. + * + * + * \code + * static Seven_Seg display; + * // ... + * sevenseg_init(&display); + * while (!sevenseg_isReady(&display)) + * ; + * sevenseg_unlock(&display); + * sevenseg_setBlink(&display,false,0); + * sevenseg_setRunonce(&display,false); + * sevenseg_setRunspeed(&display,10); + * if ((sevenseg_print(&display, "made with bertos.")) != 0) + * return -1; + * sevenseg_lock(&display); + * \endcode + * + * $WIZ$ module_name = "led_7seg" + * $WIZ$ module_depends = "timer" + * $WIZ$ module_configuration = "bertos/cfg/cfg_led_7seg.h" + * $WIZ$ module_hw = "bertos/hw/hw_led_7seg.h" + */ + +#ifndef DRV_LED_7SEG_H +#define DRV_LED_7SEG_H + +#include "cfg/cfg_led_7seg.h" +#include +#include + +/** + * \name Numbers and Letters Table. + * \note These tables contain all the printable + * characters on a 7 segment digit encoded + * for common cathode and common anode + * display type. + * + * 0, 1, 2, 3, 4, 5, 6, 7, 8, + * 9, ., -, A, B, C, D, E, F, + * G, H, I, J, K, L, M, N, O, + * P, Q, R, S, T, U, V, W, X, + * Y, Z, SPACE + * + * \{ + */ +#if CONFIG_LED_7SEG_CCAT + static const uint8_t segstable[] = + { + 0x3f, 0x6, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x7, 0x7f, + 0x6f, 0x80, 0x40, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, + 0x3d, 0x74, 0x30, 0x1e, 0x75, 0x38, 0x15, 0x37, 0x3f, + 0x73, 0x67, 0x50, 0x6d, 0x78, 0x3e, 0x2a, 0x6a, 0x76, + 0x6e, 0x5b, 0x0 + }; +#else + static const uint8_t segstable[] = + { + 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, + 0x90, 0x7f, 0xbf, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e, + 0xc2, 0x8b, 0xcf, 0xe1, 0x8a, 0xc7, 0xea, 0xc8, 0xc0, + 0x8c, 0x98, 0xaf, 0x92, 0x87, 0xc1, 0xd5, 0x95, 0x89, + 0x91, 0xa4, 0xff + }; +#endif +/**\} */ + +/** + * Context data for Display functions + * + */ +typedef struct SevenSeg +{ + /** The String to be displayed */ + uint8_t string[CONFIG_LED_7SEG_STRLEN]; + /** The length of the string to be displayed */ + unsigned int string_len; + /** Has to blink? */ + bool blink; + /** Has to blink only one digit? */ + uint8_t bdigit; + /** Has to be displayed only one time? */ + bool runonce; + /** Scrolling speed */ + unsigned int speed; + /** Working scrolling speed */ + unsigned int curspeed; + /** Is it printed at least one time? */ + bool firstrun; + /** Working current position */ + unsigned int curpos; + /** Working current digit */ + unsigned int curdigit; + /** Is the structure in edit? */ + bool busyedit; +} SevenSeg; + +/* Functions prototypes */ + +/* + * This is the procedure that fills the seven_seg structure with the translated + * string to display. It swaps also the structures to display the new text when + * all the data is ready to display. + */ +int sevenseg_print(SevenSeg *SS, const char *sstring); + +/* + * This is the procedure that inits all the structures that rules the 7 segments + * display and set the timer for the proper print/refresh of the text. + */ +void sevenseg_init(SevenSeg *SS); + +/* + * This is the procedure that does a short print of all segments of all + * digits of the display. + */ +void sevenseg_test(SevenSeg *SS); + +/* + * This is the procedure that check if the print of the current text is run + * almost one time and we're ready to print a new text. + */ +bool sevenseg_isReady(SevenSeg *SS); + +/* + * This is the procedure that check if the print of the current text is run + * almost one time and then set the status of the display to "unlocked". + */ +bool sevenseg_unlock(SevenSeg *SS); + +/* + * This is the procedure that lock the display and permit + * the print of the text. + */ +bool sevenseg_lock(SevenSeg *SS); + +/* + * This is the procedure that set the blinking of the display. + * You can choose to blink all the display or only a single + * digit. + */ +bool sevenseg_setBlink(SevenSeg *SS, bool blink, uint8_t digit); + +/* + * This is the procedure that set if the text has to be displayed + * just one time + */ +bool sevenseg_setRunonce(SevenSeg *SS, bool runonce); + +/* + * This is the procedure that set the scrolling speed of the text + * if the text is longer than the display digits or the + * duration of the display if the text is smaller or equal the + * length of display digits. + */ +bool sevenseg_setRunspeed(SevenSeg *SS, unsigned int r_speed); + +/* + * This is the procedure that blanks the text to be displayed + * and so on clear the display. + */ +bool sevenseg_clear(SevenSeg *SS); + +#endif /* DRV_LED_7SEG_H */ + /** \} */ //defgroup drivers