cancel
Showing results for 
Search instead for 
Did you mean: 

Having a ghosting symbols on 4-digit 7-segment CC indicator

username007
Associate II

Hello, I'm practicing with dynamic indication on multidigit multisegment indicators, and run into the issue when on the screen appear some symbols that are not supposed to be printed. I'm using 3641AS, each segment is connected to PC0...7 via 2K2 resistor, and each digit's pin is connected to PC8...PC11.

The code is:

 

 

/* USER CODE BEGIN PV */

// binary presentation of numbers from 0 till 9
int numbers[10] = { 0b00111111, 0b00000110, 0b01011011, 0b01001111, 0b01100110,
		0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111 };
// the variable to be shown and changed during run of program
int value = 0;
// the decimal place to be depictured at the momen
int current_digit = 0;
// bitmasks of decimals to be depictured (including decimal point)
int digits[4] = { };

#define display_interval 5
#define count_interval 1000

uint32_t last_display_tick;
uint32_t last_count_tick;
uint32_t current_tick;

/* USER CODE END PV */

 

 

 

 

 

/* USER CODE BEGIN 2 */
//turn off all the LEDs
GPIOC->ODR = 0b000000000000;
refresh_digit_values();
/* USER CODE END 2 */

 

 

 

 

 

/* USER CODE BEGIN 3 */
		current_tick = HAL_GetTick();
		if (current_tick - last_count_tick > count_interval) {
			value = (value == 9999) ? 0 : value + 1;
			refresh_digit_values();
			last_count_tick = current_tick;
		};

		if (current_tick - last_display_tick > display_interval) {
			GPIOC->ODR = ((0b1111 ^ (1 << current_digit)) << 8)
					+ digits[current_digit];

			current_digit = current_digit > 3 ? 0 : current_digit + 1;
			last_display_tick = current_tick;
		};

	}
	/* USER CODE END 3 */

 

 

 

 

 

/* USER CODE BEGIN 4 */
void refresh_digit_values(void) {
	digits[3] = numbers[value / 1000];		// by default - integer division
	digits[2] = numbers[value % 1000 / 100];	//
	digits[1] = numbers[value % 100 / 10];		//
	digits[0] = numbers[value % 10];			//

	for (int i = 3; i > 0; i--) {
		if (digits[i] == numbers[0]) {
			digits[i] = 0b00000000;
		} else {
			break;
		};
	}
}
;

/* USER CODE END 4 */

 

 

 

THe expected activity was:

  • increase the value of variable for 1 (and if it hit 9999 reset it)
  • show the value on the screen and remove the leading zeroes ( like if the value is lower than a 1000)

 

Actual output is: 

20240710_184522.jpg

 

20240710_184523.jpg

 

 

20240710_184525.jpg

The counting itself works. But the printing is a problem. Please, advise on the solution.

1 ACCEPTED SOLUTION

Accepted Solutions
unsigned_char_array
Senior III

Display interval is wrong, it's a digit interval, entire display interval is 4 times larger.
You also have an off-by-one error, you divide by 6, not 5.
Assuming hal tick is 1 millisecond, then display is only updated at only 1ms*6*4=24ms=41.7Hz.
This will lead to visible strobing when moving your head and can also lead to interference with camera exposure time.
Better increase it. I would simply leave a timer out entirely. LEDs can switch fast enough (datasheet mentions 10KHz with 10% duty cycle at 200mA, so I assume it can switch at 250Hz 25% duty cycle).

I actually recommend initially increasing the display interval and the counting interval so you can actually see things happening in case you have a bug somewhere that's setting the wrong segments.

 

Edit: another off-by-one bug:

current_digit = current_digit > 3 ? 0 : current_digit + 1;

 current digit can become 4.

Better rewrite as:

current_digit = (current_digit + 1) % 4;
Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.

View solution in original post

3 REPLIES 3
unsigned_char_array
Senior III

Display interval is wrong, it's a digit interval, entire display interval is 4 times larger.
You also have an off-by-one error, you divide by 6, not 5.
Assuming hal tick is 1 millisecond, then display is only updated at only 1ms*6*4=24ms=41.7Hz.
This will lead to visible strobing when moving your head and can also lead to interference with camera exposure time.
Better increase it. I would simply leave a timer out entirely. LEDs can switch fast enough (datasheet mentions 10KHz with 10% duty cycle at 200mA, so I assume it can switch at 250Hz 25% duty cycle).

I actually recommend initially increasing the display interval and the counting interval so you can actually see things happening in case you have a bug somewhere that's setting the wrong segments.

 

Edit: another off-by-one bug:

current_digit = current_digit > 3 ? 0 : current_digit + 1;

 current digit can become 4.

Better rewrite as:

current_digit = (current_digit + 1) % 4;
Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.

The code was functional because the same code, but placed into interrupts on timers was working like a charm:

 

/* USER CODE BEGIN 4 */
void refresh_digit_values(void) {
	digits[3] = numbers[value / 1000];		// by default - integer division
	digits[2] = numbers[value % 1000 / 100];	//
	digits[1] = numbers[value % 100 / 10];		//
	digits[0] = numbers[value % 10];			//

	for (int i = 3; i > 0; i--) {
		if (digits[i] == numbers[0]) {
			digits[i] = 0b00000000;
		} else {
			break;
		};
	}
}
;

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
	if (htim->Instance == TIM2) {
		GPIOC->ODR = ((0b1111 ^ (1 << current_digit)) << 8)
				+ digits[current_digit];
		current_digit = current_digit > 3 ? 0 : current_digit + 1;
	};
	if (htim->Instance == TIM3) {
		refresh_digit_values();
		value = (value == 9999) ? 0 : value + 1;
	};
}
;
/* USER CODE END 4 */

 

And yes, I tried different time intervals (the visual strobing started when `display_interval` is about 9). However, the use of:

 

current_digit = (current_digit + 1) % 4;

 

indeed resolved the problem when used HAL_GetTick. Thank you!

P.S. Also updated the limiter for changed value:

 

value = (value+1) % 10000;

 

 

 

 

Great to hear you got it to work. If my post helped you please mark it as the answer so the topic can be marked as solved.

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.