Tutorial 6 : SevenSegment Library - sudeshmoreyos/Morey_os-demo-1.0 GitHub Wiki

Home <<Prev 6 Next>>

In this tutorial, we will learn how to use the SevenSegment Library of Morey_os. In the previous tutorial, Tutorial-5, we learned about the Digital Driver.

Before we begin, let us understand the difference between a Driver and a Library. A Driver provides access to hardware functionality and is generally generic in nature. A Library, on the other hand, is usually written for a specific application and may internally use one or more drivers.

For example, a seven-segment display can be controlled using the Digital Driver by manually turning individual segments ON or OFF. The SevenSegment Library simplifies this process by providing functions to directly display digits and characters, without requiring the user to manage individual segments. The implementation of a Driver depends on the underlying controller architecture, whereas the implementation of a Library is generally architecture-independent, provided that the required drivers are available.

1. Introduction to Seven Segment Display

Before we discuss the SevenSegment Library, let us briefly understand what a seven-segment display is. Wikipedia defines a seven-segment display as "a form of electronic display device for displaying decimal numerals that is an alternative to the more complex dot matrix displays." link. A typical seven-segment display looks something like the one shown below:

A seven-segment display consists of seven segments, labeled a, b, c, d, e, f, and g, along with an optional decimal point segment h. By turning different segments ON and OFF, we can display decimal digits and a limited set of characters. Seven-segment displays are available in various sizes and colors. A typical seven-segment display has ten pins: eight pins for segments a to h and two common pins. Electrically, seven-segment displays are available in two types: Common Cathode and Common Anode. These two types differ in the electrical arrangement of their segment LEDs, as shown below:

Seven Segment-2

As shown above, in a Common Cathode seven-segment display, the cathodes (negative terminals) of all segments are connected together and brought out to the common pins. Similarly, in a Common Anode seven-segment display, the anodes (positive terminals) of all segments are connected together and brought out to the common pins.

To illuminate segment A in a Common Cathode seven-segment display, the segment A pin must be connected to the positive supply, while the common pin is connected to ground through a current-limiting resistor. For a Common Anode seven-segment display, the connections are reversed. A typical connection of a Common Cathode seven-segment display with an Arduino Uno board is shown below:

Segments A to H are connected to Pin0 to Pin7, respectively, while the common pin is connected to GND through a series resistor. The resistor value is typically 100 Ω. In the case of a Common Anode seven-segment display, the connections are reversed, as shown below:

The only difference here is that the common pin of the Common Anode seven-segment display is connected to the +5 V supply, whereas the common pin of the Common Cathode seven-segment display is connected to GND.

2. Seven Segment Library

To use the SevenSegment Library in your application, include the following header file in your source code:

#include "lib/SevenSegment.h"

The source code for the SevenSegment Library can be found here: SevenSegment Lib. The SevenSegment Library supports the following initialization functions and APIs:

1. Seven Segment struct initialization

The first step is to initialize a SevenSegment_t structure, which holds the configuration information required by the SevenSegment Library. Initialization is done as follows:

SevenSegment_t seg1={pin0,pin1,pin2,pin3,pin4,pin5,pin6,pin7};

In the above declaration, we create a structure of type SevenSegment_t and assign digital pins corresponding to segments A, B, C, D, E, F, G, and H of the seven-segment display. This structure should be declared above the setup() function. In some applications, it may not be necessary to use all eight segments. For example, if the decimal point (H) is not required, there is no need to connect a digital pin to that segment. In such cases, the structure can be defined as:

SevenSegment_t seg1={pin0,pin1,pin2,pin3,pin4,pin5,pin6,NOT_USED_PIN};

The SevenSegment Library will automatically ignore any segment assigned as NOT_USED_PIN, allowing you to save valuable digital I/O pins. Please note that NOT_USED_PIN can be used for any or all segments of the seven-segment display.

2. SevenSegment_begin

Declaration:

void SevenSegment_begin(struct seven_segment_struct *seven_segment_obj, mos_uint8_t segment_type);

After initializing the SevenSegment_t structure, the first function that must be called is SevenSegment_begin(). This function takes two input parameters:

  1. A pointer to a SevenSegment_t structure.
  2. The segment type, which can be either ANODE for a Common Anode seven-segment display or CATHODE for a Common Cathode seven-segment display.

This function stores the selected segment type in the structure and configures all assigned digital pins as outputs. Typically, this function is called inside the setup() function, as shown below:

void setup()
{
    SevenSegment_begin(&seg1, CATHODE);
}

3. SevenSegment_print

Declaration:

void SevenSegment_print(struct seven_segment_struct *seven_segment_obj, mos_uint8_t digit);

This function is used to display a digit or character on a seven-segment display. It takes two input parameters:

  1. A pointer to a SevenSegment_t structure.
  2. The digit or character to be displayed.

The following values are supported:

  • DIGIT0 or 0 or 0x00
  • DIGIT1 or 1 or 0x01
  • DIGIT2 or 2 or 0x02
  • DIGIT3 or 3 or 0x03
  • DIGIT4 or 4 or 0x04
  • DIGIT5 or 5 or 0x05
  • DIGIT6 or 6 or 0x06
  • DIGIT7 or 7 or 0x07
  • DIGIT8 or 8 or 0x08
  • DIGIT9 or 9 or 0x09
  • DIGITA or 10 or 0x0A
  • DIGITB or 11 or 0x0B
  • DIGITC or 12 or 0x0C
  • DIGITD or 13 or 0x0D
  • DIGITE or 14 or 0x0E
  • DIGITF or 15 or 0x0F
  • DIGIT_DOT or 16 or 0x10
  • DIGIT_DASH or 17 or 0x11
  • DIGIT_BLANK or 18 or 0x12

For example, to display the digit 2, you can use DIGIT2, 2, or 0x02. All three values produce the same output on the seven-segment display.

4. SevenSegment_printDot

Declaration:

void SevenSegment_printDot(struct seven_segment_struct *seven_segment_obj,
                           mos_uint8_t digit);

This function is similar to SevenSegment_print(), with the only difference being that the decimal point (dot) is displayed along with the digit or hexadecimal character. This function is useful when displaying decimal values on a seven-segment display.

5. SevenSegment_printReverse

Declaration:

void SevenSegment_printReverse(struct seven_segment_struct *seven_segment_obj,
                               mos_uint8_t digit);

This function is similar to SevenSegment_print(), except that the digit or hexadecimal character is displayed in a reversed (upside-down) orientation. One example application is a digital clock implemented using multiple seven-segment displays. To create the ':' separator between hours and minutes, one of the displays may need to be mounted in a reversed orientation. This function simplifies displaying digits on such displays.

6. SevenSegment_printDotReverse

Declaration:

void SevenSegment_printDotReverse(struct seven_segment_struct *seven_segment_obj,
                                  mos_uint8_t digit);

This function is similar to SevenSegment_printReverse(), with the additional feature that the decimal point (dot) is also displayed. It is useful in applications that require both reversed digits and a decimal point, such as certain digital clock designs.

7. SevenSegment_customPrint

Declaration:

void SevenSegment_customPrint(struct seven_segment_struct *seven_segment_obj,
                              mos_uint8_t custom_data_pin_a,
                              mos_uint8_t custom_data_pin_b,
                              mos_uint8_t custom_data_pin_c,
                              mos_uint8_t custom_data_pin_d,
                              mos_uint8_t custom_data_pin_e,
                              mos_uint8_t custom_data_pin_f,
                              mos_uint8_t custom_data_pin_g,
                              mos_uint8_t custom_data_pin_h);

The final function provided by the SevenSegment Library is SevenSegment_customPrint(). If you wish to display symbols other than predefined digits, hexadecimal characters, or special symbols such as dot, dash, and blank, this function can be used to create custom patterns. The function takes nine inputs. The first input is a pointer to a SevenSegment_t structure. The remaining eight inputs specify the ON (1) or OFF (0) state of segments A through H. Please note that values other than 0 or 1 are considered invalid and will be treated as 1.

2. SevenSegment lib Example Code

Let us now check an example code named seven-segment-counter.c that can be found in example folder (examples/board-examples/arduino-uno/seven-segment). It implements two seven segment counters. First seven segment is common cathode while other one is common anode. The code is as follows :

// Declare here all header files used in the code.h , OS related files are included by default
#include "morey_os.h"
#include "lib/sevensegment.h"
SevenSegment_t seg1={D0,D1,D2,D3,D4,D5,D6,D7},seg2={C0,C1,C2,C3,C4,C5,B0,B1};

// Declare all initialization functions of controller peripherals in the setup function below
void setup(void)
{    
	SevenSegment_begin(&seg1, ANODE);
	SevenSegment_begin(&seg2, CATHODE);
}

// Delcare all processes here
PROCESS(SEVEN1,"SEVEN-1");
PROCESS(SEVEN2,"SEVEN-2");

// Delcare autostart  processes here. Atleast one process must be autostarted;
AUTOSTART_PROCESSES(&SEVEN1, &SEVEN2);

PROCESS_THREAD(SEVEN1)
{
  // Declare all variables here, please read documentation to understand 
  // which variables should be declared as static variables            
   static int i=0;
  // Process starts here  
  BEGIN();

  while(1)
  {
	for(i=0; i<16; i++)
	{
		SevenSegment_print(&seg1, i);
		DELAY_SEC_PRECISE(0.5);
	} 
    for(i=0; i<16; i++)
	{
		SevenSegment_printDot(&seg1, i);	
		DELAY_SEC_PRECISE(0.5);
	}
    for(i=0; i<16; i++)
	{
		SevenSegment_printReverse(&seg1, i);
		DELAY_SEC_PRECISE(0.5);
	}
    for(i=0; i<16; i++)
	{
		SevenSegment_printDotReverse(&seg1, i);
		DELAY_SEC_PRECISE(0.5);
	}

	SevenSegment_customPrint(&seg1,1,0,0,0,0,0,0,0);
	DELAY_SEC_PRECISE(0.5);
	
	SevenSegment_customPrint(&seg1,0,1,0,0,0,0,0,0);
	DELAY_SEC_PRECISE(0.5);
	
	SevenSegment_customPrint(&seg1,0,0,1,0,0,0,0,0);
	DELAY_SEC_PRECISE(0.5);
	
	SevenSegment_customPrint(&seg1,0,0,0,1,0,0,0,0);
	DELAY_SEC_PRECISE(0.5);
	
	SevenSegment_customPrint(&seg1,0,0,0,0,1,0,0,0);
	DELAY_SEC_PRECISE(0.5);
	
	SevenSegment_customPrint(&seg1,0,0,0,0,0,1,0,0);
	DELAY_SEC_PRECISE(0.5);
	
	SevenSegment_customPrint(&seg1,0,0,0,0,0,0,1,0);
	DELAY_SEC_PRECISE(0.5);
	
	SevenSegment_customPrint(&seg1,0,0,0,0,0,0,0,1);
	DELAY_SEC_PRECISE(0.5);
	 	
  }
  // process ends here
  END();
}

PROCESS_THREAD(SEVEN2)
{
  // Declare all variables here, please read documentation to understand 
  // which variables should be declared as static variables            
   static int i=0;
  // Process starts here  
  BEGIN();    

  while(1)
  {
	for(i=0; i<16; i++)
	{
		SevenSegment_print(&seg2, i);
		DELAY_SEC_PRECISE(0.5);
	} 
    for(i=0; i<16; i++)
	{
		SevenSegment_printDot(&seg2, i);	
		DELAY_SEC_PRECISE(0.5);
	}
    for(i=0; i<16; i++)
	{
		SevenSegment_printReverse(&seg2, i);
		DELAY_SEC_PRECISE(0.5);
	}
    for(i=0; i<16; i++)
	{
		SevenSegment_printDotReverse(&seg2, i);
		DELAY_SEC_PRECISE(0.5);
	}

	SevenSegment_customPrint(&seg2,1,0,0,0,0,0,0,0);
	DELAY_SEC_PRECISE(0.5);
	
	SevenSegment_customPrint(&seg2,0,1,0,0,0,0,0,0);
	DELAY_SEC_PRECISE(0.5);
	
	SevenSegment_customPrint(&seg2,0,0,1,0,0,0,0,0);
	DELAY_SEC_PRECISE(0.5);
	
	SevenSegment_customPrint(&seg2,0,0,0,1,0,0,0,0);
	DELAY_SEC_PRECISE(0.5);
	
	SevenSegment_customPrint(&seg2,0,0,0,0,1,0,0,0);
	DELAY_SEC_PRECISE(0.5);
	
	SevenSegment_customPrint(&seg2,0,0,0,0,0,1,0,0);
	DELAY_SEC_PRECISE(0.5);
	
	SevenSegment_customPrint(&seg2,0,0,0,0,0,0,1,0);
	DELAY_SEC_PRECISE(0.5);
	
	SevenSegment_customPrint(&seg2,0,0,0,0,0,0,0,1);
	DELAY_SEC_PRECISE(0.5);
	 	
  }
  // process ends here
  END();
}

Code Explanation

  1. Header Files

The morey_os.h header file must be included in all applications. Since this example uses the SevenSegment Library, we also include lib/SevenSegment.h.

#include "morey_os.h"
#include "lib/SevenSegment.h"
  1. Seven-Segment Structure Initialization

Two structures of type SevenSegment_t, named seg1 and seg2, are initialized. The corresponding digital pins of the board are assigned to these structures. seg1 is connected to pin0 through pin7, while seg2 is connected to pinA0 through pinA5, along with pin8 and pin9.

SevenSegment_t seg1={pin0,pin1,pin2,pin3,pin4,pin5,pin6,pin7},
               seg2={pinA0,pinA1,pinA2,pinA3,pinA4,pinA5,pin8,pin9};
  1. Seven-Segment Initialization

seg1 is configured as a Common Anode seven-segment display, while seg2 is configured as a Common Cathode seven-segment display.

void setup(void)
{
    SevenSegment_begin(&seg1, ANODE);
    SevenSegment_begin(&seg2, CATHODE);
}
  1. Task Creation

Two tasks, SEVEN1 and SEVEN2, are created using the TASK_CREATE macro. Please note that TASK_CREATE takes two inputs. The first input is the task name, while the second input is a descriptive string used during debugging. We will discuss debugging in more detail in subsequent tutorials.

TASK_CREATE(SEVEN1,"SEVEN1");
TASK_CREATE(SEVEN2,"SEVEN2");
  1. Task Autostart

Both tasks are configured to start automatically when the controller boots. Tasks can also be started manually from within other tasks. Task creation, startup, and termination will be discussed in later tutorials. For now, both tasks are started automatically using:

TASK_AUTOSTART(&SEVEN1, &SEVEN2);
  1. Task Implementation

The TASK_RUN(SEVEN1) task demonstrates all five functions provided by the SevenSegment Library:

  • SevenSegment_print()
  • SevenSegment_printDot()
  • SevenSegment_printReverse()
  • SevenSegment_printDotReverse()
  • SevenSegment_customPrint()

A static integer variable i is used to iterate through all supported display values. Please note that all variables in Morey_os must be declared as static. The reason for this requirement will be explained in subsequent tutorials. The loop runs until i = 18 (i < 19) so that all supported symbols can be displayed:

  • 0–9
  • A–F
  • Dot (16)
  • Dash (17)
  • Blank (18)

The functions behave as follows:

  • SevenSegment_print() displays digits, hexadecimal characters, dot, dash, and blank.
  • SevenSegment_printDot() displays the same symbols along with the decimal point.
  • SevenSegment_printReverse() displays the symbols in an upside-down orientation.
  • SevenSegment_printDotReverse() displays upside-down symbols along with the decimal point.
  • SevenSegment_customPrint() demonstrates custom segment control by illuminating individual segments one at a time.

Each display update occurs after a delay of 0.5 seconds. To create delays in Morey_os, we can use the DELAY_SEC() or DELAY_SEC_PRECISE() macros. A detailed discussion of these macros is available in Tutorial 8 : DELAY_SEC Macros Demystified.

Finally, note that both tasks contain an infinite while(1) loop. Since Morey_os uses cooperative threading, every infinite loop must contain at least one DELAY_SEC() or DELAY_SEC_PRECISE() macro to allow other tasks to execute. In this example, DELAY_SEC_PRECISE(0.5) satisfies this requirement.

SEVEN2 task implements exact operations for seg2.

  1. Content of Makefile is as follows :
PROJECT = seven-segment-counter
MOREY_OS_PATH = ../../../..
BOARD = ARDUINO_UNO
include $(MOREY_OS_PATH)/Makefile.include

PROJECT Macro will hold name of the project file name. MOREY_OS_PATH holds the location of Morey_os root directory. BOARD Macro should hold ARDUINO_UNO since we are programming for Arduino_uno board. And last line should remain the same as mentioned above.

  1. This code is simple and requires no special configurations. Hence config.h file content will remain same as below :
#ifndef CONFIG_H
#define CONFIG_H
#define COMPILER AVR_GCC
#endif

Home <<Prev 6 Next>>