Humans can visualize things much slower than they can occur. Take for instance the 7 x 10 Click LED display produced by MikroElektronika. What you see in the image isn't multiple LEDs lit at the same time, but a brief instance of an LED being illuminated. Your eyes don't wash away the image fast enough and because of this effect, the display appears to be showing multiples. Magic. Another name is Persistence of Vision.
https://github.com/MikroElektronika/Click_7x10_Led_Matrix
The hardware itself uses a SPI bus to communicate the display pattern to the shift registers. The library itself is written to be easy for the application to use. The entry point to using the display is the initialization function: void s7x10r_init( void ); easy because if you have a SPI bus initialized and you have defined your external dependencies, that is all you need to call to get started.
This is an example of getting the 7x10 ready to work:
sbit SxT_CS at GPIOD_ODR.B13; sbit SxT_RST at GPIOC_ODR.B2; sbit SxT_ROW_RST at GPIOA_ODR.B0; sbit SxT_ROW_CLK at GPIOA_ODR.B4; void system_init() { GPIO_Digital_Output(&GPIOD_ODR, _GPIO_PINMASK_13); // Set CS pin as output GPIO_Digital_Output(&GPIOC_ODR, _GPIO_PINMASK_2); // Set RST pin as output GPIO_Digital_Output(&GPIOA_ODR, _GPIO_PINMASK_0); // Set PWM pin as output GPIO_Digital_Output(&GPIOA_ODR, _GPIO_PINMASK_4); // Set PWM pin as output // Initialize SPI SPI3_Init_Advanced( _SPI_FPCLK_DIV16, _SPI_MASTER | _SPI_8_BIT | _SPI_CLK_IDLE_LOW | _SPI_FIRST_CLK_EDGE_TRANSITION | _SPI_MSB_FIRST | _SPI_SS_DISABLE | _SPI_SSM_ENABLE | _SPI_SSI_1, &_GPIO_MODULE_SPI3_PC10_11_12); s7x10r_init(); }
The required dependencies before calling s7x10r_init() are:
- Pin for Chip Select
- Pin for Reset
- Pin for Row Reset
- Pin for Row Clocking
- SPI bus initialized
Now that the display has all it's dependencies met, the display only works it's magic ( POV ) if s7x10r_display() is called as often as possible. Best place for this function to reside is in the while( 1 ) loop.
void main() { system_init(); s7x10r_clear_display(); while( 1 ) { s7x10r_display(); } }
So what can we do with the display? Best place to reveal this is found in the .h file:
/** * @brief Draws a pixel at specified x, y location * @param row - x * @param col - y * @code * s7x10r_draw_pix( 1, 3 ); // Lights pixel on row 1 column 3 * @endcode * @note min x value is 1 max is 7, min y value is 1 max is 10 */ void s7x10r_draw_pix( uint8_t row, uint8_t col ); /** * @brief Write Text on the display * @param txt */ void s7x10r_draw_txt( char *txt ); /** * @brief Draws numbers on the display * @param num - max number is 99 */ void s7x10r_draw_num( uint8_t num );
According to the header file we can do things like draw individual pixels, draw text, draw numbers. Sounds reasonable.
The display also has the capability to scroll the text across the screen, but to do this it requires a few things. MCUs have no reference to time, and in order to have something related to time we need to use a timer. This will be MCU dependent but the library uses a simple function s7x10r_tick(); that is meant to be called inside an ISR.
/** * @brief Tick called in ISR * * This function is used on the scrolling feature. It is to be called * from the interrupt and does not need to be called is scrolling is not * needed. */ void s7x10r_tick( void );
One example of this is a timer interrupt that is called every 50ms
void timer2_interrupt() iv IVT_INT_TIM2 { TIM2_SR.UIF = 0; s7x10r_tick(); }
Once we have the timer incrementing the timing mechanism of the display, we can enable scrolling. Speed of the scrolling is also adjustable by the enabling of the feature:
/** * @brief Enable scrolling feature * @param speed * @val S7X10R_SLOW * @val S7X10R_MED * @val S7X10R_FAST */ void s7x10r_scroll_enable( s7x10r_speed_t speed );
3 speeds are available. Slow, Med, and Fast.
s7x10r_scroll_enable( S7X10R_FAST );
Now when you draw text or numbers the display will scroll them. The advantage here is that you can display more than just 2 characters, you can display messages, like: "Happy".
Example
Here is a complete example of how to use the various functions. You can download the packed library from Libstock. While this is implemented on the ARM MCU family, it also works with any of the other supported families of MCUs.
/******************************************************************************* * Title : 7x10R click Example * Filename : led7x10_click.c * Author : RBL * Origin Date : 10/11/2015 * Notes : None *******************************************************************************/ /*************** MODULE REVISION LOG ****************************************** * * Date Software Version Initials Description * 10/11/16 .1 RBL Module Created. * *******************************************************************************/ /** * @file led7x10_click.c * @brief Example of multiplexed 7 x 10 led matrix control */ /****************************************************************************** * Includes *******************************************************************************/ #include#include "s7x10r_hw.h" /****************************************************************************** * Module Preprocessor Constants *******************************************************************************/ /****************************************************************************** * Module Preprocessor Macros *******************************************************************************/ /****************************************************************************** * Module Typedefs *******************************************************************************/ enum { TEST_STAGE1, TEST_STAGE2, TEST_STAGE3, TEST_STAGE4 }; /****************************************************************************** * Module Variable Definitions *******************************************************************************/ sbit SxT_CS at GPIOD_ODR.B13; sbit SxT_RST at GPIOC_ODR.B2; sbit SxT_ROW_RST at GPIOA_ODR.B0; sbit SxT_ROW_CLK at GPIOA_ODR.B4; /****************************************************************************** * Function Prototypes *******************************************************************************/ void system_init( void ); void test1_pixels( void ); void test2_text( void ); void test3_scrolling( void ); void test4_numbers( void ); void init_timer2( void ); /****************************************************************************** * Function Definitions *******************************************************************************/ //Timer2 Prescaler :599; Preload = 62499; Actual Interrupt Time = 50 ms void init_timer2() { RCC_APB1ENR.TIM2EN = 1; TIM2_CR1.CEN = 0; TIM2_PSC = 19; TIM2_ARR = 59999; NVIC_IntEnable(IVT_INT_TIM2); TIM2_DIER.UIE = 1; TIM2_CR1.CEN = 1; } void system_init() { GPIO_Digital_Output(&GPIOD_ODR, _GPIO_PINMASK_13); // Set CS pin as output GPIO_Digital_Output(&GPIOC_ODR, _GPIO_PINMASK_2); // Set RST pin as output GPIO_Digital_Output(&GPIOA_ODR, _GPIO_PINMASK_0); // Set PWM pin as output GPIO_Digital_Output(&GPIOA_ODR, _GPIO_PINMASK_4); // Set PWM pin as output // Initialize SPI SPI3_Init_Advanced( _SPI_FPCLK_DIV16, _SPI_MASTER | _SPI_8_BIT | _SPI_CLK_IDLE_LOW | _SPI_FIRST_CLK_EDGE_TRANSITION | _SPI_MSB_FIRST | _SPI_SS_DISABLE | _SPI_SSM_ENABLE | _SPI_SSI_1, &_GPIO_MODULE_SPI3_PC10_11_12); s7x10r_init(); init_timer2(); EnableInterrupts(); } void test1_pixels() { static uint8_t x = 1, y = 0; s7x10r_clear_display(); if( y++ > 10 ) { y = 1; x++; } if( x >= 8 ) x = 1; s7x10r_draw_pix( x, y ); } void test2_text() { s7x10r_draw_txt( "MikroElektronika" ); } void test3_scrolling() { s7x10r_draw_txt( " Mikro Elektronika . Happy" ); s7x10r_scroll_enable( S7X10R_FAST ); } void test4_numbers() { static uint8_t num; s7x10r_clear_display(); s7x10r_draw_num( num ); num++; if( num > 99 ) num = 0; } void main() { uint16_t counter = 0; uint16_t test_counter = 0; int stage = TEST_STAGE1; uint8_t called = 0; system_init(); s7x10r_clear_display(); while( 1 ) { if( !( counter % 20 ) ) { if( test_counter >= 100 ) { stage++; s7x10r_scroll_disable(); if( stage > TEST_STAGE4 ) { stage = TEST_STAGE1; called = 0; } test_counter = 0; } switch( stage ) { case TEST_STAGE1: test1_pixels(); break; case TEST_STAGE2: test2_text(); break; case TEST_STAGE3: if( !called ) { test3_scrolling(); called = 1; } break; case TEST_STAGE4: test4_numbers(); break; } test_counter++; } s7x10r_display(); counter++; } } void timer2_interrupt() iv IVT_INT_TIM2 { TIM2_SR.UIF = 0; s7x10r_tick(); } /*************** END OF FUNCTIONS ***************************************************************************/