本次设计为STM32初学成品,基于STM32F103ZET6的红外遥控电子时钟,采用了战舰开发板配套的TFTLCD显示屏,红外遥控器HS0038等硬件,实现了遥控控制日期时间的更改,闹钟的设置,响铃等功能。
该设计运用到两个定时器,定时器3用于1s定时,定时器4用于捕获遥控器发出的红外信号。通过TFTLCD显示屏显示当前日期、当前时间以及自定义的闹钟时间,纯人工定位画点(后来才发现有现成的RCT)。TFTLCD由FSMC(flexible static memory controller)驱动,颜色编码格式RGB565,遥控器仅设置三个按键有效,ALIENTEK控制模式切换,UP控制加一操作,DOWN控制减一操作。
以下有几个重要的概念:
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"
#include "remote.h"
#include "timer.h"
#include "clock.h"
#include "beep.h"
volatile u32 year=2019;
volatile u32 month=12;
volatile u32 day=12;
volatile u32 hour=23;
volatile u32 minute=59;
volatile u32 second=50;
volatile u32 chour=0;
volatile u32 cminute=0;
volatile u32 csecond=0;
u8 setMode=0;//设置模式
void inc(void)//加1
{
switch(setMode)
{
case 1:
{
year++;
if(year==2100)year=2000;
break;
}
case 2:
{
month++;
if(month==13)month=1;
break;
}
case 3:
{
day++;
if(day==31)day=1;
break;
}
case 4:
{
hour++;
if(hour==24)hour=0;
break;
}
case 5:
{
minute++;
if(minute==60)minute=0;
break;
}
case 6:
{
second++;
if(second==60)second=0;
break;
}
case 7:
{
chour++;
if(chour==24)chour=0;
break;
}
case 8:
{
cminute++;
if(cminute==60)cminute=0;
break;
}
case 9:
{
csecond++;
if(csecond==60)csecond=0;
break;
}
}
}
void dec(void)//减1
{
switch(setMode)
{
case 1:
{
year--;
if(year==1999)year=2100;
break;
}
case 2:
{
month--;
if(month==0)month=12;
break;
}
case 3:
{
day--;
if(day==0)day=30;
break;
}
case 4:
{
hour--;
if(hour<=0)hour=23;
break;
}
case 5:
{
minute--;
if(minute<=0)minute=59;
break;
}
case 6:
{
second--;
if(second<=0)second=59;
break;
}
case 7:
{
chour--;
if(chour<=0)chour=23;
break;
}
case 8:
{
cminute--;
if(cminute<=0)cminute=59;
break;
}
case 9:
{
csecond--;
if(csecond<=0)csecond=59;
break;
}
}
}
int main(void)
{
u8 key;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
//uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
BEEP_Init(); //初始化蜂鸣器端口
LCD_Init();
Remote_Init(); //红外接收初始化
TIM3_Int_Init(9999,7199);//10Khz的计数频率,计数到10000为1s
while(1)
{
CLOCK_Show(year,month,day,hour,minute,second,chour,cminute,csecond);
if(hour==chour&&minute==cminute&&second==csecond) {//闹钟响
BEEP=1;
delay_ms(1000);
BEEP=0;
}
if(Remote_Scan())
{
delay_ms(2800);//2000-3000都可
key=Remote_Scan();
switch(key)
{
case 0://ERROR
break;
case 162://POWER
break;
case 98://UP
{
inc();
break;
}
case 2://PLAY
break;
case 226://ALIENTEK
{
setMode++;
if(setMode==10)setMode=0;
break;
}
case 194://RIGHT
break;
case 34://LEFT
break;
case 224://VOL-
break;
case 168://DOWN
{
dec();
break;
}
case 144://VOL+
break;
case 104://1
break;
case 152://2
break;
case 176://3
break;
case 48://4
break;
case 24://5
break;
case 122://6
break;
case 16://7
break;
case 56://8
break;
case 90://9
break;
case 66://0
break;
case 82://DELETE
break;
}
}
if(setMode)
{
LED1=1;
LED0=0;
} else
{
LED0=1;
LED1=0;
}
}
}
#include "clock.h"
void CLOCK_Show(u32 year,u32 month,u32 day,u32 hour,u32 minute,u32 second,u32 chour,u32 cminute,u32 csecond)//初始化日期时间
{
POINT_COLOR=RED; //设置字体为红色,默认也是红色
LCD_ShowString(30,50,200,24,24,"DATE:");
LCD_ShowString(90,80,1,24,24,"/");//年60 其他30 符号10
LCD_ShowString(140,80,1,24,24,"/");//
LCD_ShowString(30,110,200,24,24,"TIME:");
LCD_ShowString(60,140,1,24,24,":");
LCD_ShowString(110,140,1,24,24,":");
LCD_ShowString(30,170,200,24,24,"CLOCK:");
LCD_ShowString(60,200,1,24,24,":");
LCD_ShowString(110,200,1,24,24,":");
POINT_COLOR=BLUE;
BACK_COLOR=(setMode==1)?GRAY:WHITE;
LCD_ShowNum(30,80,year,4,24);//行距30
BACK_COLOR=(setMode==2)?GRAY:WHITE;
LCD_ShowNum(110,80,month,2,24);
BACK_COLOR=(setMode==3)?GRAY:WHITE;
LCD_ShowNum(160,80,day,2,24);
BACK_COLOR=(setMode==4)?GRAY:WHITE;
LCD_ShowNum(30,140,hour,2,24);
BACK_COLOR=(setMode==5)?GRAY:WHITE;
LCD_ShowNum(80,140,minute,2,24);
BACK_COLOR=(setMode==6)?GRAY:WHITE;
LCD_ShowNum(130,140,second,2,24);
BACK_COLOR=(setMode==7)?GRAY:WHITE;
LCD_ShowNum(30,200,chour,2,24);
BACK_COLOR=(setMode==8)?GRAY:WHITE;
LCD_ShowNum(80,200,cminute,2,24);
BACK_COLOR=(setMode==9)?GRAY:WHITE;
LCD_ShowNum(130,200,csecond,2,24);
BACK_COLOR=WHITE;//字体背景色
}
#ifndef __CLOCK_H
#define __CLOCK_H
#include "sys.h"
#include "lcd.h"
extern u8 setMode;
void CLOCK_Show(u32 year,u32 month,u32 day,u32 hour,u32 minute,u32 second,u32 chour,u32 cminute,u32 csecond);//初始化日期,时间,闹钟
#endif
#include "timer.h"
#include "delay.h"
#include "led.h"
//通用定时器3中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
//定时器TIM3初始化
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_Cmd(TIM3, ENABLE); //使能TIMx
}
//定时器3中断服务程序
void TIM3_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志
if(!setMode)
{
second++;
if(second==60)
{
second=0;
minute++;
if(minute==60)
{
minute=0;
hour++;
if(hour==24)
{
hour=0;
day++;
if(day==31)
{
day=1;
month++;
if(month==13)
{
month=1;
year++;
if(year==3001)
{
year=2000;
}
}
}
}
}
}
}
}
}
#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"
extern volatile u32 day,month,year;
extern volatile u32 second,minute,hour;
extern u8 setMode;
void TIM3_Int_Init(u16 arr,u16 psc);
#endif
图左为正常工作模式(计时模式),图右为设置模式,灰色背景表示当前设置的位置,蓝色数字都可以通过遥控设置。由上往下分别显示当前日期、当前时间、自定义闹钟,按遥控上的ALIENTEK键进入或退出设置模式。
本次课程设计调试过程中,TFTLCD对红外遥控按键的反应是循环检测,支持连按的,一时找不到检测松手的入口,索性直接采用延迟反应的笨办法。2000ms过慢,3000ms又过快,因此选择了2800ms延迟按键反应时间。注意蜂鸣器需要三极管驱动,GPIO口输出高电平放大电流。TFTLCD显示的字体背景颜色改变后要切换回默认状态即白色,以保证设置的时候始终只有一个位置是灰色。LED由GPIO输出低电平点亮,在设置模式下DS0(红灯)亮,正常工作模式下DS1(黄灯)亮 。由于时间关系(一天时间太短了莫得办法),闹钟功能简单的由蜂鸣器响铃一秒完成,可后续扩展成为音乐闹铃。红外遥控键盘部分也可以扩展相应要实现的功能,比如数字键盘设置。