【GD32L233C-START评测】第5篇 动态扫描实现直驱4位时钟数码管
[复制链接]
本帖最后由 yang_alex 于 2022-2-21 17:56 编辑
单片机驱动多位数码管时有共阳和共阴两种接法,我们这里使用的是共阳4位时钟数码管。下面是他的外观图、段位图和引脚图:
先来说明一下我们的硬件电路:数码管的位引脚DIG1、DIG2、DIG3、DIG4分别接评估板的PB9、PB6、PB5、PB1,数码管的段引脚A、B、C、D、E、F、G、DP分别接评估板的PB8、PB4、PB12、PB14、PB13、PB7、PB0、PB15。这里没有接限流电阻,主要是考虑到:都是用杜邦线连接的,加电阻不方便(实际做板子的时候最好在每个位引脚和MCU的GPIO之间加个限流电阻),另外就是因为采用了动态扫描以及3.3V电压本来就不高。注意,如果LED的驱动电流比较大的时候就不能直接用MCU的GPIO去驱动数码管的位引脚了,而是需要去驱动一个PNP三极管,通过控制这个PNP三极管的导通与否去控制数码管的位引脚是否接到正电源。
软件方面:驱动方法是评估板上接数码管位引脚的GPIO输出高电平去推数码管中的LED,评估板上接数码管段引脚的GPIO输出低电平去拉数码管中的LED,这样对应的LED就会亮。动态扫描的原理是:评估板上接数码管位引脚的GPIO轮流输出扫描信号,使每一瞬间只有一个数码管被选通(输出高电平,数码管该位共阳极被高电平驱动),然后由评估板上接数码管段引脚的7个GPIO(这个4位时钟数码管上每个数码右下角的点是空的,没有LED,不需要驱动)送入该位要显示的字形码(输出低电平),点亮该位字形段显示字形。这样在的段码驱动和位选线配合控制下,就可以使各数码管轮流点亮显示各自的字符。DP1和DP2另外控制。扫描频率恰当的情况下,由于人眼的暂留效应,4位时钟数码是同时显示的。
工作原理和电路说清楚了,我们来看一下代码:
首先,对用到的GPIO做初始化,这里利用了评估板所带的gd32l233c_start.c程序,所以项目重要添加这个程序,并且在相应的头文件gd32l233c_start.h中增加相应引脚的定义:
- #define LED_A_PIN GPIO_PIN_8
- #define LED_A_GPIO_PORT GPIOB
- #define LED_A_GPIO_CLK RCU_GPIOB
-
- #define LED_B_PIN GPIO_PIN_4
- #define LED_B_GPIO_PORT GPIOB
- #define LED_B_GPIO_CLK RCU_GPIOB
-
- #define LED_C_PIN GPIO_PIN_12
- #define LED_C_GPIO_PORT GPIOB
- #define LED_C_GPIO_CLK RCU_GPIOB
-
- #define LED_D_PIN GPIO_PIN_14
- #define LED_D_GPIO_PORT GPIOB
- #define LED_D_GPIO_CLK RCU_GPIOB
-
- #define LED_E_PIN GPIO_PIN_13
- #define LED_E_GPIO_PORT GPIOB
- #define LED_E_GPIO_CLK RCU_GPIOB
-
- #define LED_F_PIN GPIO_PIN_7
- #define LED_F_GPIO_PORT GPIOB
- #define LED_F_GPIO_CLK RCU_GPIOB
-
- #define LED_G_PIN GPIO_PIN_0
- #define LED_G_GPIO_PORT GPIOB
- #define LED_G_GPIO_CLK RCU_GPIOB
-
- #define LED_1_PIN GPIO_PIN_9
- #define LED_1_GPIO_PORT GPIOB
- #define LED_1_GPIO_CLK RCU_GPIOB
-
- #define LED_2_PIN GPIO_PIN_6
- #define LED_2_GPIO_PORT GPIOB
- #define LED_2_GPIO_CLK RCU_GPIOB
-
- #define LED_3_PIN GPIO_PIN_5
- #define LED_3_GPIO_PORT GPIOB
- #define LED_3_GPIO_CLK RCU_GPIOB
-
- #define LED_4_PIN GPIO_PIN_1
- #define LED_4_GPIO_PORT GPIOB
- #define LED_4_GPIO_CLK RCU_GPIOB
-
- #define LED_DP_PIN GPIO_PIN_15
- #define LED_DP_GPIO_PORT GPIOB
- #define LED_DP_GPIO_CLK RCU_GPIOB
-
-
void gd_eval_led_init(led_typedef_enum lednum)在gd32l233c_start.c程序中有定义,我们直接拿来初始化数码管相关驱动引脚:
- void gpio_config(void)
- {
-
- gd_eval_led_init(LED1);
- gd_eval_led_init(LED_A);
- gd_eval_led_init(LED_B);
- gd_eval_led_init(LED_C);
- gd_eval_led_init(LED_D);
- gd_eval_led_init(LED_E);
- gd_eval_led_init(LED_F);
- gd_eval_led_init(LED_G);
- gd_eval_led_init(LED_1);
- gd_eval_led_init(LED_2);
- gd_eval_led_init(LED_3);
- gd_eval_led_init(LED_4);
- gd_eval_led_init(LED_DP);
- }
我们利用一个定时器实现4位时钟数码管的动态扫描,所以要先配置这个定时器(定时3毫秒):
- void timer_config(void)
- {
- timer_oc_parameter_struct timer_ocinitpara;
- timer_parameter_struct timer_initpara;
-
-
- rcu_periph_clock_enable(RCU_TIMER5);
-
-
- timer_deinit(TIMER5);
-
- timer_struct_para_init(&timer_initpara);
-
- timer_initpara.prescaler = 63;
- timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
- timer_initpara.counterdirection = TIMER_COUNTER_UP;
- timer_initpara.period = 3000;
- timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
- timer_init(TIMER5, &timer_initpara);
-
-
- timer_auto_reload_shadow_enable(TIMER5);
-
- timer_interrupt_flag_clear(TIMER5, TIMER_INT_FLAG_UP);
-
- timer_interrupt_enable(TIMER5, TIMER_INT_UP);
-
-
- timer_enable(TIMER5);
- }
再在定时器的中断程序中更新4位时钟数码管各位要显示的数:
- void TIMER5_IRQHandler(void)
- {
- uint16_t seg6,seg5,seg1,seg3,seg4,seg2 = 0x7191;
- if(SET == timer_interrupt_flag_get(TIMER5, TIMER_INT_FLAG_UP))
- {
-
- timer_interrupt_flag_clear(TIMER5, TIMER_INT_FLAG_UP);
- seg2 = 0x7191;
- if(Times < 4)
- {
- switch(Times)
- {
- case 0: seg4 = display_clock[hour1]|0x8000 ;
- seg3 = 0x0200;
- break;
- case 1: seg4 = display_clock[hour2]|0x8000 ;
- seg3 = 0x0040;
- break;
- case 2: seg4 = display_clock[min1]|0x8000 ;
- seg3 = 0x0020;
- break;
- case 3: seg4 = display_clock[min2]|0x8000 ;
- seg3 = 0x0002;
- break;
- default : break;
- }
- seg1 = gpio_output_port_get(GPIOB);
- seg5 = (seg2 | seg1 )& 0xfd9d;
- gpio_port_write(GPIOB,seg5 );
- seg5 = (seg4 & seg5 )| seg3;
- gpio_port_write(GPIOB,seg5 );
- Times++;
- }
- else
- {
- Times = 0;
- }
- }
- }
接下来就是主程序中给定要时钟数码管要显示的数,已经秒脉冲的显示(500毫秒翻转一次)
- #include "gd32l23x.h"
- #include "gd32l233c_start.h"
- #include "systick.h"
-
- uint16_t hour1,hour2,min1,min2,sec1,sec2;
- uint32_t display_clock[] = {0x8263, 0xE3E3,0x92E2,0xA2E2,0xE362,0xA272,0x8272,0xE081,0x8262,0xA000};
- uint16_t Times = 0,pwm_pulse_value = 20;
-
- void gpio_config(void);
- void nvic_config(void);
- void timer_config(void);
-
- int main(void)
- {
- systick_config();
- gpio_config();
- nvic_config();
- timer_config();
-
- hour1 = 1;
- hour2 = 8;
- min1 = 5;
- min2 = 6;
-
- while(1)
- {
- gd_eval_led_toggle(LED_DP);
- delay_1ms(500);
- }
- }
好了。编译下载,跑起来看看我们的成果吧:
|