基于正点原子STM32F1精英版秒表(库函数版)

一、前期准备

  1. 建立keil5文件,完成基本库函数配置;
  2. 本次需要的文件有:
        #include "led.h"                   //LED灯
        #include "delay.h"                 //延时函数
        #include "key.h"                   //独立按键
        #include "sys.h"                   //系统
        #include "lcd.h"                   //TFTLCD
        #include "timer.h"                 //定时器
        #include "tpad.h"                  //触摸按键
        #include "beep.h"                  //蜂鸣器
  1. 实现功能:
    (1).秒表:按下KEU_UP开始;按下KEY1清零;按下KEY0暂停;
    (2)闹钟(你要说定时炸弹我也没意见):按下触摸按键定时+1秒;

二、代码实现:

1.独立按键与触摸按键

#include "stm32f10x.h"
#include "key.h"
#include "sys.h" 
#include "delay.h"

/*
KEY0  GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)//读取按键0
KEY1  GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)//读取按键1
WK_UP   GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//读取按键3(WK_UP)
*/ 

//按键初始化函数
void KEY_Init(void) //IO初始化
{ 
 	GPIO_InitTypeDef GPIO_InitStructure;
 
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);//使能PORTA,PORTE时钟

	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_4|GPIO_Pin_3;//KEY0-KEY1
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
 	GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE4,3

	//初始化 WK_UP-->GPIOA.0	  下拉输入
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0设置成输入,默认下拉	  
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0

}


//0,没有任何按键按下
//1,KEY0按下
//2,KEY1按下
//3,KEY3按下 WK_UP
//
u8 KEY_Scan()
{	 
	static u8 key_up=1;//按键按松开标志  
	if(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
	{
		delay_ms(10);//去抖动 
		key_up=0;
		if(KEY0==0){return KEY0_PRES;}//KEY0_PRES=1
		else if(KEY1==0){return KEY1_PRES;}//KEY1_PRES=2
		else if(WK_UP==1){return WKUP_PRES;}//WKUP_PRES=3
	}else if(KEY0==1&&KEY1==1&&WK_UP==0){key_up=1;} 	    
 	return 0;// 无按键按下
}
/***********************************以上是独立按键***********************************/
//触摸按键的源程序过于繁琐,在这里就不展示了。其原理我会再出一期


2.TFTLCD

#include "lcd.h"
#include "stdlib.h"
#include "font.h" 	 
#include "delay.h"	

//在LCD上显示数字
//x,y:起点坐标
//num:数值(0~999999999);	 
//len:长度(即要显示的位数)
//size:字体大小
//mode:
//[7]:0,不填充;1,填充0.
//[6:1]:保留
//[0]:0,非叠加显示;1,叠加显示.
void LCD_ShowxNum(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode)
{  
	u8 t,temp;
	u8 enshow=0;						   
	for(t=0;t<len;t++)
	{
		temp=(num/LCD_Pow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				if(mode&0X80)LCD_ShowChar(x+(size/2)*t,y,'0',size,mode&0X01);  
				else LCD_ShowChar(x+(size/2)*t,y,' ',size,mode&0X01);  
 				continue;
			}else enshow=1; 
		 	 
		}
	 	LCD_ShowChar(x+(size/2)*t,y,temp+'0',size,mode&0X01); 
	}
} 
//在LCD上显示字符串(用来显示“ :”)
//x,y:起点坐标
//width,height:区域大小  
//size:字体大小
//*p:字符串起始地址		  
void LCD_ShowString(u16 x,u16 y,u16 width,u16 height,u8 size,u8 *p)
{         
	u8 x0=x;
	width+=x;
	height+=y;
    while((*p<='~')&&(*p>=' '))//判断是不是非法字符!
    {       
        if(x>=width){x=x0;y+=size;}
        if(y>=height)break;//退出
        LCD_ShowChar(x,y,*p,size,0);
        x+=size/2;
        p++;
    }  
}

3.定时器

#include "timer.h"
#include "lcd.h"

u8 hour = 0, minute = 0, second = 0, t = 0;
u16   ms=0;

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通道被使能  ENABLE 1;DISABLE 0;
	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更新中断标志 
		ms++;
			if(ms>99)   //准备定10ms
			{
				ms=0;
				second++;
				if(second>59)
				{
	        second=0;
          minute++;
					if(minute>59)
					{
						minute=0;
						hour++;
					}
				}
			}
		}
	}

4.蜂鸣器与LED灯

#include "led.h"
#include "beep.h"

void LED_Init(void) //这些就没啥好说的了,最基础的LED、蜂鸣器初始化
{
 
 GPIO_InitTypeDef  GPIO_InitStructure;
 	
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);//使能PB,PE端口时钟
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;				 //LED0-->PB.5 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIOB.5
 GPIO_SetBits(GPIOB,GPIO_Pin_5);						 //PB.5 输出高

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;	    		 //LED1-->PE.5 端口配置, 推挽输出
 GPIO_Init(GPIOE, &GPIO_InitStructure);	  				 //推挽输出 ,IO口速度为50MHz
 GPIO_SetBits(GPIOE,GPIO_Pin_5); 						 //PE.5 输出高 
}

void BEEP_Init(void)
{
 
 GPIO_InitTypeDef  GPIO_InitStructure;
 	
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能GPIOB端口时钟
 
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;				 //BEEP-->PB.8 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	 //速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);	 //根据参数初始化GPIOB.8
 
 GPIO_ResetBits(GPIOB,GPIO_Pin_8);//输出0,关闭蜂鸣器输出

}

5.主函数设计

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "timer.h"
#include "tpad.h"
#include "beep.h"
/*这里 u8 为 unsigned char;u16 为 unsigned int */
extern u8 hour, minute, second, t;  //引入外部变量
extern u16 ms;

u8 h_set,m_set,s_set;//设置的时间,仅支持秒开始设置

u16 time_pause[4]={0,0,0,0,};//将四个时间变量存储在数组中,从而达到暂停的目的

void  LCD_miaobiao()//显示
{
        LCD_ShowxNum(30,162,hour,2,16,0x80);   //显示数字
	    LCD_ShowString(47,162,200,2,16,":");   //显示字符串
        LCD_ShowxNum(64,162,minute,2,16,0x80);
	    LCD_ShowString(81,162,200,2,16,":");  
        LCD_ShowxNum(97,162,second,2,16,0x80);
        LCD_ShowString(114,162,200,2,16,":");  	
	    LCD_ShowxNum(140,162,ms,2,16,0x80);

}

void timeset()//闹钟的时间设置
{
	    LCD_ShowxNum(30,100,h_set,2,16,0x80);  
	    LCD_ShowString(47,100,200,2,16,":");  
        LCD_ShowxNum(64,100,m_set,2,16,0x80);
	    LCD_ShowString(81,100,200,2,16,":");  
        LCD_ShowxNum(97,100,s_set,2,16,0x80);
}


 int main(void)
 {	 
 	u8 x=0;              //触摸按键标志位
	u8 key=0;	           //独立键盘标志位
	u8 m=0;              //LED闪烁标志位
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	//NVIC
	delay_init();	    	 //延时函数初始化	  
	BEEP_Init();         //蜂鸣器初始化 	
 	LED_Init();			     //LED端口初始化
	LCD_Init();          //LCD端口初始化
	KEY_Init();          //独立按键初始化
	TPAD_Init(6);			   //触摸按键初始化
	LED_Init();          //LED初始化
	TIM3_Int_Init(100,7199);//定时器初始化

  	while(1) 
	{		 

 		key=KEY_Scan(0);	
		x=TPAD_Scan();//触摸按键
	   	if(key)
		{						   
			switch(key)
			{				 
				case WKUP_PRES:	
					hour=time_pause[0]; //将数组time_pause[]值赋给定时器中的时分秒,完成初始化
					minute=time_pause[1];
				    second=time_pause[2];
				    ms=time_pause[3];
				
					while(1)
				{
					LCD_miaobiao();
					delay_ms(10);     //消抖
					t=KEY_Scan(0);
					if((hour==h_set)&&(minute==m_set)&&(second==s_set)) /*闹钟功能*/
		{
			BEEP=1;
			delay_ms(300);
			BEEP=0; 
			delay_ms(300);
			
			h_set=0;   //原本设置的闹钟时间归零
			m_set=0;
			s_set=0;
			timeset();
			
			hour=0;   //秒表归零
			minute=0;
			second=0;
			ms=0;
			LCD_miaobiao();
		}	
				if(t)
				{
					switch(t)
						{
							case KEY1_PRES:	  //秒表归零
								{   
									second = 0;
								    minute = 0;
									hour = 0;
									ms=0;
									time_pause[0]=0;
								    time_pause[1]=0;
								    time_pause[2]=0;
									time_pause[3]=0;
									LCD_miaobiao();
										}break;
										
					       case KEY0_PRES:	//暂停
							{
								   time_pause[0]=hour; //设置一个数组,并将当前定时器的值(时、分、秒、毫秒)存入数组内
									time_pause[1]=minute;
									time_pause[2]=second;
									time_pause[3]=ms;
								    LCD_ShowxNum(30,162,timeSFM[0],2,16,0x80);
									LCD_ShowString(47,162,200,2,16,":");  
									LCD_ShowxNum(64,162,timeSFM[1],2,16,0x80);
									LCD_ShowString(81,162,200,2,16,":");  
									LCD_ShowxNum(97,162,timeSFM[2],2,16,0x80);
									LCD_ShowString(114,162,200,2,16,":");  	
									LCD_ShowxNum(140,162,timeSFM[3],2,16,0x80);
										if(t==KEY0_PRES)
										{
											m=1;
											if(m)
												{
													m=1;
													LED1=0;
											    delay_ms(100);
											    LED1=1;
											    delay_ms(100);
												}
											
										}else m=0;
									}break;												
									}
									break ;								
								}
							}
							break; 	
			}
		}else delay_ms(10); 
		if(x)    //触摸按键实现设置闹钟功能
		{
			s_set++;
			if(s_set>59)
			{
				s_set=0;
				m_set++;
				if(m_set>59)
				{
					m_set=0;
					h_set++;
					if(h_set>24)
					{
						h_set=0;
					}
				}
			}
				timeset();
				delay_ms(10);
		}
		
	
	} 
}


三、 结束语:

笔者编辑完这篇文章的时候,板子不在身边,无法运行出实际效果来展示。但已经将该程序的压缩包打包上传了,想进一步了解的话可以下载来看看。
笔者刚入坑小白一枚,文中谬误,还请不吝赐教。

  • 15
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

修灯泡的老张

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值