2024-08-21 02:50 AM
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();
}
}
2024-08-21 03:13 AM
@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;
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 ...
2024-08-21 04:22 AM
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.
2024-08-21 11:07 PM
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
Thanks
2024-08-21 11:40 PM
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.
2024-08-22 12:21 AM
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.
2024-08-22 12:40 AM
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.