【GD32L233C-START评测】八、综合应用之厨用倒计时器
[复制链接]
本帖最后由 lising 于 2022-4-11 10:21 编辑
本次的综合实验是利用GD32L233C-START开发板制作的计时范围1(min)~99(max)分钟厨用倒计时器。“倒计时器”使用了一片4位段式LCD显示屏用于显示倒计时时间;利用EC11旋转编码器设置、调整倒计时时间;计时时间到蜂鸣器鸣响报警。下面是本次实验的具体过程。
一、简介
GD32L233系列以低功耗见长,利用LCD显示配合锂电池供电应该有不错的功耗表现。遗憾的是只有LQFP64封装才具备LCD驱动功能,如果能在LQFP48上增加LCD驱动功能就好了,在一些小的有LCD驱动需求的应用中还是不错的选择。
本次综合实验算是对GD32L233C-START评测的一个阶段性小结。用到的片上资源包括利用LPTIMER(低功耗定时器)的正交编码器模式0来驱动EC11型旋转编码器设置、调整倒计时时间数据;TIMER2(通用定时器L0)产生倒计时秒信号;其它就是用于驱动TM1722(LCD)、LED、蜂鸣器等驱动的GPIO了。实验总体上比较简单,算是凑个热闹。
二、硬件、软件及功能实现
1、EC11旋转编码器
GD32L233C的定时器资源非常丰富,这里使用的是LPTIMER(低功耗定时器),利用其正交编码模式0对EC11旋转编码器的旋转脉冲进行计数。
下面是EC11旋转编码器产生脉冲的特征,是不是很搭?
实物就是这种了,带按键。
LPTIMER的“LPTIMER_IN0”及“LPTIMER_IN1”与EC11的“A”、“B”端口的连接可以有多种引脚映射可供选择,实验使用了官方例程,没有调整:
static void ec11_gpio_config(void)
{
rcu_periph_clock_enable(RCU_SYSCFG);
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOB);
/*PA6(LPTIMER_IN0) EC11_A_KEY*/
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
gpio_af_set(GPIOA, GPIO_AF_2, GPIO_PIN_6);
/*PB3(LPTIMER_IN1) EC11_B_KEY*/
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
gpio_af_set(GPIOB, GPIO_AF_2, GPIO_PIN_3);
/*PB1 EC11_SW_KEY*/
gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN_1);//上拉输入
syscfg_exti_line_config(EXTI_SOURCE_GPIOB, EXTI_SOURCE_PIN1);
exti_init(EXTI_1, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_interrupt_flag_clear(EXTI_1);
nvic_irq_enable(EXTI1_IRQn, 2U);
}
根据EC11的旋转状态及旋转的步数,用于增加或减少倒计时时间数据。当倒计时时间数据调整结束后,即可按下EC11的按键开始倒计时工作。下面是按键(PB1)中断程序:
void EXTI1_IRQHandler(void)//EC11按键中断
{
static uint8_t A=0;
if(RESET != exti_interrupt_flag_get(EXTI_1))
{
exti_interrupt_flag_clear(EXTI_1);
if(A==0)
{
timer_enable(TIMER2); //启动TIMER2
lptimer_stop(); //停止LPTIMER
A = 1;
RED_LED_OFF();
GREEN_LED_ON();
BEEP(1);
}
else if(A)
{
timer_disable(TIMER2); //启动TIMER2
lptimer_countinue_start(1U, 1U); //启动LPTIMER
A = 0;
RED_LED_ON();
GREEN_LED_OFF();
BEEP(1);
}
}
}
从上面的程序中可以看出,进入中断后启动了TIMER2、并关闭了LPTIMER,意味着开始倒计时后EC11的旋转变得没有意义,如想在中途改变倒计时时间数据只能再次按下按键。避免了误操作。红色LED亮时表明此时为可调整状态;绿色LED亮时表明此时为倒计时工作状态,倒计时时间数据不可调整,EC11旋转动作无效。
之前用软件方式操作过EC11旋转编码器,但是快速旋转有时会产生误码,这次利用LPTIMER(低功耗定时器)的正交编码器模式实现的EC11解码效果非常好,快速旋转也没出现误码。除了LPTIMER另外的TIMER1和TIMER2也可以干这个活儿。
2、LCD及TM1722(LCD)驱动
这两样都是拆机的,LCD显示屏有4个“COM”、8个“SEG”,能显示4位“8”及“秒”符号,就是尺寸有点小;TM1722就不用说了,LCD专用驱动,不过SOP24体积有点大。现在手上又有了一些LQFP48的VK1621B,积相对要小巧的多,用来驱动这个LCD也是不错的选择。程序实现见附件,LCD全段点亮如下:
3、LED及蜂鸣器
选用了一颗RGB三色LED,红色LED用于电源开机或计时结束指示;当开始计时时绿色LED被点亮、红色LED熄灭,计时结束绿色LED熄灭、红色LED常亮并且蜂鸣器响提示倒计时时间“到”的状态。蓝色LED用于锂电池充电状态指示,实验中没有实现。程序实现见附件。
4、TIMER2
TIMER2在这里被用作定时器,为倒计时器提供计数脉冲,配置如下:
定时器时钟计数频率 = 64MHz/(prescaler+1) = 64MHz/(639+1)=100KHz
定时时间 = 定时器时钟计数频率/(period+1) = 100KHz/(9999+1) = 10Hz = 0.1s = 100ms
void TIMER_Config(void)
{
timer_oc_parameter_struct timer_ocintpara;
timer_parameter_struct timer_initpara;
rcu_periph_clock_enable(RCU_TIMER2);
timer_deinit(TIMER2);
timer_struct_para_init(&timer_initpara);
timer_initpara.prescaler = 639; //时钟预分频系数
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;//边缘对齐
timer_initpara.counterdirection = TIMER_COUNTER_UP; //向上计数
timer_initpara.period = 9999; //重载计数值
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_init(TIMER2, &timer_initpara);
timer_auto_reload_shadow_enable(TIMER2); //使能TIMER2重装载
timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_UP);//清除TIMER2向上计数中断标志位
timer_interrupt_enable(TIMER2, TIMER_INT_UP); //使能TIMER2向上计数中断
nvic_irq_enable(TIMER2_IRQn, 0); //配置TIMER2中断
//timer_enable(TIMER2);//使能TIMER2 由EC11按键中断控制
}
TIMER2中断产生“分”信号:
void TIMER2_IRQHandler(void)
{
static uint16_t num=0;
if(SET == timer_interrupt_flag_get(TIMER2, TIMER_INT_FLAG_UP))
{
timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_UP);//清除向上计数中断标志位
num++;
if(num==600)//60s
{
num=0;
timer_60s_flag = 1; //计数60s(1分钟)标志
}
}
}
再来看看主程序:
int main(void)
{
static int8_t EC11_COUNTER;
static int8_t Count_Down_Timer = 0;
systick_config();
EC11_Config();
TM1722_Init();
//TM1722_Clear(1);
TIMER_Config();
//USART_Config();
LED_Config();
BEEP_Config();
RED_LED_ON();
BEEP(1);
//printf("ec11 test");
TM1722_Display_Count(Count_Down_Timer);
while(1)
{
if(timer_60s_flag)
{
timer_60s_flag = 0;
Count_Down_Timer--;
if(Count_Down_Timer == 0)
timer_disable(TIMER2);
BEEP(6);
RED_LED_ON();
GREEN_LED_OFF();
TM1722_Display_Count(Count_Down_Timer);
}
if(ec11_flag)
{
ec11_flag=0;
EC11_COUNTER = lptimer_counter_read();
if(EC11_COUNTER)
{
Count_Down_Timer++;
if(Count_Down_Timer > 99)
Count_Down_Timer = 0;
}
else
{
Count_Down_Timer--;
if(Count_Down_Timer < 0)
Count_Down_Timer = 99;
}
//printf(" %d",Count_Down_Timer);
TM1722_Display_Count(Count_Down_Timer);
}
}
}
三、实验过程中的几张照片
四、改进计划
1、对于主控MCU有两种想法,其一选用LQFP64引脚芯片,使用SLCD模块直接驱动LCD;其二使用更低引脚芯片,LCD改用体积比较小巧的VK1621B;
2、LCD选用一款尺寸稍大的日光型LCD,取消背光产生的功耗;
3、利用“RTC”模块增加时钟功能;
4、利用“ADC”模块监测锂电池电压,电压低时提示充电;
5、增加空气检测,最重要的是增加煤气泄漏检测。
五、总结
通过这一段时间的学习,对GD32L233系列微控制器有了更多直接的认识和使用体验,为今后的学习奠定了基础。借此机会再次向兆易创新及EEWORLD表示感谢!
六、附件
本次实验的完整工程文件:
编辑原因:增补“二、硬件、软件及功能实现”中的“4、TIMER2”描述。
|