cancel
Showing results for 
Search instead for 
Did you mean: 

4 7-Segment Display multiplexing without driver

Omkar23
Associate II

Hello, 
So, I'm trying to display a 4 Digit number on 4 7-segment Display using multiplexing 
The issues are - 1. I'm using different Ports for Segments and Different Ports For common Cathode Pins ( I'll add the code below) 
                          2. I'm Directly using GPIO to segment Pins without having any IC in between 

Flow of the code is as follows :- 

 - Start
 -  for UP/DOWN button press 
 - If UP button is pressed then increment the counter 
 - Display the value of the counter on 7 segment display
 - check if button is still being held 
 - If yes continue incrementing 
 - If no then stop 
 - same for DOWN Button used for decrement 

 - End 

Here my increment and decrement function is working as expected but I'm not getting how can I display that counter values on 4 7-segment 
I wrote a code as follows 

In this code when i press up button only 3rd display is constantly turning on with value all other display just turned on for fraction of sec and then turned off. I want it continuously to display the values which are incrementing and decrementing   

(sorry if the code is confusing i didn't comment or remove some unnecessary part) 

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define SEG_A_PORT GPIOB
#define SEG_A_PIN GPIO_PIN_9
#define SEG_B_PORT GPIOB
#define SEG_B_PIN GPIO_PIN_8
#define SEG_E_PORT GPIOD
#define SEG_E_PIN GPIO_PIN_6

#define SEG_C_PORT GPIOB
#define SEG_C_PIN GPIO_PIN_7
#define SEG_D_PORT GPIOB
#define SEG_D_PIN GPIO_PIN_6
#define SEG_F_PORT GPIOD
#define SEG_F_PIN GPIO_PIN_5
#define SEG_G_PORT GPIOD
#define SEG_G_PIN GPIO_PIN_1
#define SEG_DP_PORT GPIOC
#define SEG_DP_PIN GPIO_PIN_8

#define DIGIT1_PORT GPIOC
#define DIGIT1_PIN GPIO_PIN_10 //CC1
#define DIGIT2_PORT GPIOB
#define DIGIT2_PIN GPIO_PIN_4  //CC2
#define DIGIT3_PORT GPIOB
#define DIGIT3_PIN GPIO_PIN_3  //CC3
#define DIGIT4_PORT GPIOC
#define DIGIT4_PIN GPIO_PIN_9  //CC4

//#define START_BUTTON_GPIO_Port GPIOD
//#define START_BUTTON_Pin GPIO_PIN_9

#define UP_BUTTON_GPIO_Port GPIOD
#define UP_BUTTON_Pin GPIO_PIN_8

#define DOWN_BUTTON_GPIO_Port GPIOA
#define DOWN_BUTTON_Pin GPIO_PIN_15

#define min_down  0
#define max_down  10

#define min_up  -1
#define max_up 9

#define MIN_DIGIT 0
#define MAX_DIGIT 9

#define NUM_DIGITS 4
#define DISPLAY_UPDATE_INTERVAL 2 // Time in milliseconds for display update

uint8_t counter = 0;
const uint8_t max = 9; // Example maximum value
const uint8_t min = 0; // Example minimum value
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */

//volatile uint8_t current_digit_index = 0;
//volatile uint8_t display_digits[4] = {0, 0, 0, 0}; // Array to hold digits to display
//volatile uint8_t multiplexing_active = 1; // Flag to control multiplexing

uint8_t digits[4] = {0, 0, 0, 0};

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void set_segment(GPIO_TypeDef* port, uint16_t pin, uint8_t value) {
    if (value) {
        HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET);
    } else {
        HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET);
    }
}

void TurnOffAllDigits(void) {
    HAL_GPIO_WritePin(DIGIT1_PORT, DIGIT1_PIN, GPIO_PIN_SET);
    HAL_GPIO_WritePin(DIGIT2_PORT, DIGIT2_PIN, GPIO_PIN_SET);
    HAL_GPIO_WritePin(DIGIT3_PORT, DIGIT3_PIN, GPIO_PIN_SET);
    HAL_GPIO_WritePin(DIGIT4_PORT, DIGIT4_PIN, GPIO_PIN_SET);
}

void DisplayDigits(uint8_t digit1, uint8_t digit2, uint8_t digit3, uint8_t digit4) {
    // Segment representation for digits 0-9
    const uint8_t segments[] = {
        0b00111111, // 0
        0b00000110, // 1
        0b01011011, // 2
        0b01001111, // 3
        0b01100110, // 4
        0b01101101, // 5
        0b01111101, // 6
        0b00000111, // 7
        0b01111111, // 8
        0b01101111  // 9
    };

    // Array to hold digit values for the display
    uint8_t segment_bits[4];
    segment_bits[0] = segments[digit1];
    segment_bits[1] = segments[digit2];
    segment_bits[2] = segments[digit3];
    segment_bits[3] = segments[digit4];

    // Time to display each digit
    const uint32_t digit_delay = 2; // Time in milliseconds for displaying each digit
    const uint32_t total_display_time = digit_delay * NUM_DIGITS;

    uint32_t start_time = HAL_GetTick();
    uint8_t current_digit = 0;

    while (HAL_GetTick() - start_time < total_display_time) {
        // Turn off all digits
        TurnOffAllDigits();

        // Turn on the current digit
        switch (current_digit) {
            case 0: HAL_GPIO_WritePin(DIGIT1_PORT, DIGIT1_PIN, GPIO_PIN_RESET); break;
            case 1: HAL_GPIO_WritePin(DIGIT2_PORT, DIGIT2_PIN, GPIO_PIN_RESET); break;
            case 2: HAL_GPIO_WritePin(DIGIT3_PORT, DIGIT3_PIN, GPIO_PIN_RESET); break;
            case 3: HAL_GPIO_WritePin(DIGIT4_PORT, DIGIT4_PIN, GPIO_PIN_RESET); break;
        }

        // Set segment values based on current digit
        uint8_t bits = segment_bits[current_digit];
        set_segment(SEG_A_PORT, SEG_A_PIN, !(bits & 0x01));
        set_segment(SEG_B_PORT, SEG_B_PIN, !(bits & 0x02));
        set_segment(SEG_C_PORT, SEG_C_PIN, !(bits & 0x04));
        set_segment(SEG_D_PORT, SEG_D_PIN, !(bits & 0x08));
        set_segment(SEG_E_PORT, SEG_E_PIN, !(bits & 0x10));
        set_segment(SEG_F_PORT, SEG_F_PIN, !(bits & 0x20));
        set_segment(SEG_G_PORT, SEG_G_PIN, !(bits & 0x40));

        // Small delay to allow digit display to be visible
        HAL_Delay(digit_delay);

        // Move to the next digit
        current_digit = (current_digit + 1) % NUM_DIGITS;
    }
}


void MultiplexDisplay(uint8_t* digits) {
    static uint8_t current_digit = 0;

    TurnOffAllDigits(); // Turn off all digits

    // Display the current digit
    switch (current_digit) {
        case 0: HAL_GPIO_WritePin(DIGIT1_PORT, DIGIT1_PIN, GPIO_PIN_RESET); break;
        case 1: HAL_GPIO_WritePin(DIGIT2_PORT, DIGIT2_PIN, GPIO_PIN_RESET); break;
        case 2: HAL_GPIO_WritePin(DIGIT3_PORT, DIGIT3_PIN, GPIO_PIN_RESET); break;
        case 3: HAL_GPIO_WritePin(DIGIT4_PORT, DIGIT4_PIN, GPIO_PIN_RESET); break;
    }

    // Set segment values based on current digit
    uint8_t digit_value = digits[current_digit];
    const uint8_t segments[] = {
        0b00111111, // 0
        0b00000110, // 1
        0b01011011, // 2
        0b01001111, // 3
        0b01100110, // 4
        0b01101101, // 5
        0b01111101, // 6
        0b00000111, // 7
        0b01111111, // 8
        0b01101111  // 9
    };

    uint8_t bits = segments[digit_value];
    set_segment(SEG_A_PORT, SEG_A_PIN, !(bits & 0x01));
    set_segment(SEG_B_PORT, SEG_B_PIN, !(bits & 0x02));
    set_segment(SEG_C_PORT, SEG_C_PIN, !(bits & 0x04));
    set_segment(SEG_D_PORT, SEG_D_PIN, !(bits & 0x08));
    set_segment(SEG_E_PORT, SEG_E_PIN, !(bits & 0x10));
    set_segment(SEG_F_PORT, SEG_F_PIN, !(bits & 0x20));
    set_segment(SEG_G_PORT, SEG_G_PIN, !(bits & 0x40));

    // Move to the next digit
    current_digit = (current_digit + 1) % 4;
}

int _write(int file, char *ptr, int len){
	HAL_UART_Transmit(&huart2, (uint8_t*)ptr, len, HAL_MAX_DELAY);
	return len;
}

void update_counter(int *counter, int direction) {
    int tens = *counter / 10;
    int units = *counter % 10;

    units += direction;

    // Check for units digit wrapping
    if (units > MAX_DIGIT) {
        units = MIN_DIGIT;
        tens += 1;
    } else if (units < MIN_DIGIT) {
        units = MAX_DIGIT;
        tens -= 1;
    }

    // Check for tens digit wrapping
    if (tens > MAX_DIGIT) {
        tens = MIN_DIGIT;
    } else if (tens < MIN_DIGIT) {
        tens = MAX_DIGIT;
    }

    *counter = tens * 10 + units;
}


void handle_buttons() {
    static int counter = 44;

    if (HAL_GPIO_ReadPin(DOWN_BUTTON_GPIO_Port, DOWN_BUTTON_Pin) == GPIO_PIN_RESET) {
        HAL_Delay(250);
        if (HAL_GPIO_ReadPin(DOWN_BUTTON_GPIO_Port, DOWN_BUTTON_Pin) == GPIO_PIN_RESET) {
            update_counter(&counter, -1); // Decrement
            printf("%d\r\n", counter);
            int tens = counter / 10;
            int units = counter % 10;
//
//            // Update display with the new counter value
//
//            uint8_t digits[4] = {0, tens, units, 0};
//            MultiplexDisplay(digits);
            DisplayDigits(0,tens,units,0);



            while (HAL_GPIO_ReadPin(DOWN_BUTTON_GPIO_Port, DOWN_BUTTON_Pin) == GPIO_PIN_SET) {
                HAL_Delay(500);
            }
        }
    } else if (HAL_GPIO_ReadPin(UP_BUTTON_GPIO_Port, UP_BUTTON_Pin) == GPIO_PIN_RESET) {
        HAL_Delay(250);
        if (HAL_GPIO_ReadPin(UP_BUTTON_GPIO_Port, UP_BUTTON_Pin) == GPIO_PIN_RESET) {
            update_counter(&counter, 1); // Increment
            printf("%d\r\n", counter);
            int tens = counter / 10;
            int units = counter % 10;
//
//            uint8_t digits[4] = {0, tens, units, 0};
//            MultiplexDisplay(digits);
            DisplayDigits(0,tens,units ,0);


//            uint8_t digits[4] = {0, counter / 10, counter % 10, 0};

            while (HAL_GPIO_ReadPin(UP_BUTTON_GPIO_Port, UP_BUTTON_Pin) == GPIO_PIN_SET) {
                HAL_Delay(500);

            }
        }
    }
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
// uint8_t digit = 0 ;
// uint8_t value = 0;

 //static uint32_t counter = 0;
 // DisplayDigits(1,2,3,4);

  //uint8_t digits[4] = {0, 0, 0, 0};
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

	  handle_buttons();


  }
}

 

6 REPLIES 6
Andrew Neil
Evangelist III

@Omkar23 wrote:

I'm not getting how can I display that counter values on 4 7-segment 


As always, the way to approach this is to get one part working at a time - don't try to do everything all at once!

So start with some code which just displays a 4-digit number - get rid of all the other complications of buttons, counters, etc.

It needs to;

  1. Select the first digit (ie, activate its common cathode)
  2. Write the segments for the first digit
  3. Pause while the digit is displayed
  4. Deselect the first digit (ie, deactivate its common cathode)
  5. Repeat for the other digits

Use the debugger to step your code and see that it's working.

You could also use the debugger to change the number being displayed ...

SofLit
ST Employee
 1. I'm using different Ports for Segments and Different Ports For common Cathode Pins ( I'll add the code below) 
  2. I'm Directly using GPIO to segment Pins without having any IC in between 


This is not the right way to drive the 7-segment display. You need to take care about the currents source/sink as you can break the IOs of your MCU. So you need at least a current booster on GPIOs using transistors or similar on common Cathode pins to drive the display.

You can find many schematics on the net on how to do this.

 

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

Hello,
Thanks for your reply 
I have 4 PNP-Transistor which i connect to the 7 segment in order to drive it. I created one schematic which I connected here.
You can check 
Thanks7-SEG.PNG

 

Hello ,
Thank you for this detailed steps. 
I already implemented it with various codes, let me share it with you. 

void DisplayDigits(uint8_t digit1, uint8_t digit2, uint8_t digit3, uint8_t digit4) {
    // Segment representation for digits 0-9
    const uint8_t segments[] = {
        0b00111111, // 0
        0b00000110, // 1
        0b01011011, // 2
        0b01001111, // 3
        0b01100110, // 4
        0b01101101, // 5
        0b01111101, // 6
        0b00000111, // 7
        0b01111111, // 8
        0b01101111  // 9
    };

    // Array to hold digit values for the display
    uint8_t segment_bits[4];
    segment_bits[0] = segments[digit1];
    segment_bits[1] = segments[digit2];
    segment_bits[2] = segments[digit3];
    segment_bits[3] = segments[digit4];

    // Time to display each digit
    const uint32_t digit_delay = 2; // Time in milliseconds for displaying each digit
    const uint32_t total_display_time = digit_delay * NUM_DIGITS;

    uint32_t start_time = HAL_GetTick();
    uint8_t current_digit = 0;

    while (HAL_GetTick() - start_time < total_display_time) {
        // Turn off all digits
        TurnOffAllDigits();

        // Turn on the current digit
        switch (current_digit) {
            case 0: HAL_GPIO_WritePin(DIGIT1_PORT, DIGIT1_PIN, GPIO_PIN_RESET); break;
            case 1: HAL_GPIO_WritePin(DIGIT2_PORT, DIGIT2_PIN, GPIO_PIN_RESET); break;
            case 2: HAL_GPIO_WritePin(DIGIT3_PORT, DIGIT3_PIN, GPIO_PIN_RESET); break;
            case 3: HAL_GPIO_WritePin(DIGIT4_PORT, DIGIT4_PIN, GPIO_PIN_RESET); break;
        }

        // Set segment values based on current digit
        uint8_t bits = segment_bits[current_digit];
        set_segment(SEG_A_PORT, SEG_A_PIN, !(bits & 0x01));
        set_segment(SEG_B_PORT, SEG_B_PIN, !(bits & 0x02));
        set_segment(SEG_C_PORT, SEG_C_PIN, !(bits & 0x04));
        set_segment(SEG_D_PORT, SEG_D_PIN, !(bits & 0x08));
        set_segment(SEG_E_PORT, SEG_E_PIN, !(bits & 0x10));
        set_segment(SEG_F_PORT, SEG_F_PIN, !(bits & 0x20));
        set_segment(SEG_G_PORT, SEG_G_PIN, !(bits & 0x40));

        // Small delay to allow digit display to be visible
        HAL_Delay(digit_delay);

        // Move to the next digit
        current_digit = (current_digit + 1) % NUM_DIGITS;
    }
}

  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
// uint8_t digit = 0 ;
// uint8_t value = 0;

  uint8_t digit1, digit2, digit3, digit4;
 //static uint32_t counter = 0;
//  DisplayDigits(1,2,3,4);

  //uint8_t digits[4] = {0, 0, 0, 0};
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

	  for(int displayValue = 0 ; displayValue < 999 ; displayValue++){

		    digit1 = (displayValue / 1000) % 10; // Thousands place
		    digit2 = (displayValue / 100) % 10;  // Hundreds place
		    digit3 = (displayValue / 10) % 10;   // Tens place
		    digit4 = displayValue %10;          // Units place


		    DisplayDigits(digit1 , digit2 ,digit3 , digit4);
		    


	  }


The above code is latest one in which I take four values and parameters and used in the function. The issue with this code is that in main as you can see in while(1) I split te values and pass it through the DisplayDigits in which I didnt add the delay so it's working smoothly. I attached the video for reference but when I add some delay it start flickering. The issue is with the display function and its timing and may be its a silly mistake but I can't see it I don't know why. can you please check it. 

There are numerous big and small problems with your code:

1. Display refresh must be done in a timer interrupt; otherwise you cannot display anything continuously (actually, with a proper connection, display refresh on STM32 can be done in hardware using DMA, without interrupts).

2. Your refresh routine results in ghosting - a faint shade of a neighboring digit visible on the display. The sequence in a refresh routine should be: turn of all digits, set the segments for the next digit, activate the next digit.

3. const declaration inside of a function without static attribute results in dynamic creation of digit decoder array on every function call.

4. You could avoid switch statements by keeping the port and bit data in an array of structures.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

Thank You for the inputs this will help me a lot in the development. I'm pretty new to firmware Dev. I'll keep this things in mind and make the necessary changes.
I'll try it implementing your suggestions.