按键收集模型代码快速复制

按键收集模型代码快速复制

对应勾选底层配置

CMSIS -> CORE

Device->Startup

Device->StdPeriph Drivers->EXTI , Framework, GPIO, RCC, TIM

image-20240819200919232

image-20240819200947170

User

main.c

#include "stm32f10x.h"                  // Device header
#include "delay.h"
#include "TIM4.h"
#include "key.h"
#include "led.h"

_Bool key_down = 0;	//按键是否按下


uint16_t count;	//定时器计数毫秒数(按键按下时长)
uint8_t button_count = 0; 
uint8_t button_mode = 0;	//按键模式:无-0 , 单击- 1, 双击 - 2, 长按 - 3


int main(void)
{
	Key_Init();
	TIM4_Init();
	Led_Init();
	while(1)
	{
		chose_led();
	}
	
}	

void TIM4_IRQHandler(void)
{
	if(TIM_GetFlagStatus(TIM4,TIM_FLAG_Update))//一毫秒运行一次
	{
		

			//当 button_atom的时候,才能进行读取按键信息
			if(key_down == 1)
			{	
				key_down = 0;
				button_count++;
				count = 1;	//开始计时
			}
			
			if(count > 0)
			{
				count++;
				if(count > 500)
				{
					count = 0;
					if(button_count == 1)
					{
						button_count = 0;
						if(key_scan() == 0)	//短按
							button_mode = 1;
						else if(key_scan() == 1)	//长按
							button_mode = 3; 
					}
					else 
					if(button_count == 2)
					{
						button_count = 0;
						
						button_mode = 2;		
					}
					else
					{
						button_count = 0;//判断完,到时间照样得button_count 清零,为后面做准备
					}
				}
			}		
		
		TIM_ClearFlag(TIM4,TIM_FLAG_Update);
	}
}

led.c

#include "led.h"

extern uint8_t button_mode;

void Led_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟
															//使用各个外设前必须开启时钟,否则对外设的操作无效
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;					//定义结构体变量
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		//GPIO模式,赋值为推挽输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;				//GPIO引脚,赋值为第0号引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		//GPIO速度,赋值为50MHz
	
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将赋值后的构体变量传递给GPIO_Init函数
															//函数内部会自动根据结构体的参数配置相应寄存器
															//实现GPIOA的初始化
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		//GPIO模式,赋值为推挽输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;				//GPIO引脚,赋值为第0号引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		//GPIO速度,赋值为50MHz
	
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将赋值后的构体变量传递给GPIO_Init函数
															//函数内部会自动根据结构体的参数配置相应寄存器
															//实现GPIOA的初始化
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		//GPIO模式,赋值为推挽输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;				//GPIO引脚,赋值为第0号引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		//GPIO速度,赋值为50MHz
	
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将赋值后的构体变量传递给GPIO_Init函数
															//函数内部会自动根据结构体的参数配置相应寄存器

	//引脚初始化
	led_go(0,0);
	led_go(1,0);
	led_go(2,0);		
}	

void led_go(uint8_t led,_Bool go)
{
	if(led == 0)
	{
		if(go == 1)
		{
			GPIO_SetBits(GPIOA, GPIO_Pin_0);	//亮
		}
		else
		{
			GPIO_ResetBits(GPIOA, GPIO_Pin_0); //灭
		}
	}
	else
	if(led == 1)
	{
		if(go == 1)
		{
			GPIO_SetBits(GPIOA, GPIO_Pin_1);	//亮
		}
		else
		{
			GPIO_ResetBits(GPIOA, GPIO_Pin_1); //灭
		}		
	}	
	else
	if(led == 2)
	{
		if(go == 1)
		{
			GPIO_SetBits(GPIOA, GPIO_Pin_2);	//亮
		}
		else
		{
			GPIO_ResetBits(GPIOA, GPIO_Pin_2); //灭
		}		
	}	
}

void chose_led(void)
{
		if(button_mode == 0)
		{
			led_go(0,0);
			led_go(1,0);
			led_go(2,0);
			
		}
		else 
		if(button_mode == 1)
		{
			led_go(0,1);
			led_go(1,0);
			led_go(2,0);
			
		}
		else 
		if(button_mode == 2)
		{
			led_go(0,0);
			led_go(1,1);
			led_go(2,0);
			
		}
		else 
		if(button_mode == 3)
		{
			led_go(0,0);
			led_go(1,0);
			led_go(2,1);
			
		}	
}	


led.h

#ifndef _LED_H_
#define _LED_H_

#include "stm32f10x.h"                  // Device header

void Led_Init(void);

void led_go(uint8_t led,_Bool go);

void chose_led(void);

#endif

Key_model

key.c

//单片机头文件
#include "stm32f10x.h"

//硬件驱动
#include "key.h"
#include "delay.h"

void Key_Init(void)
{

	GPIO_InitTypeDef gpio_initstruct;
	EXTI_InitTypeDef exti_initstruct; 
	NVIC_InitTypeDef nvic_initstruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//打开GPIOB的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);		//打开复用时钟
	
	gpio_initstruct.GPIO_Mode = GPIO_Mode_IPU;				//设置为输出
	gpio_initstruct.GPIO_Pin = GPIO_Pin_1;						//将初始化的Pin脚
	gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;				//可承载的最大频率
	
	GPIO_Init(GPIOB, &gpio_initstruct);							//初始化GPIO
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);
	
	exti_initstruct.EXTI_Line = EXTI_Line1;
	exti_initstruct.EXTI_Mode = EXTI_Mode_Interrupt;
	exti_initstruct.EXTI_Trigger = EXTI_Trigger_Falling;
	exti_initstruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&exti_initstruct);
	
	nvic_initstruct.NVIC_IRQChannel = EXTI1_IRQn;
	nvic_initstruct.NVIC_IRQChannelPreemptionPriority = 2;
	nvic_initstruct.NVIC_IRQChannelSubPriority = 2;
	nvic_initstruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&nvic_initstruct);
	
}


uint8_t key_scan(void)
{
	uint8_t value;
	value = 0;	//默认是不是一直低电平
	//检测是否长按
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)// 判断按键是否仍然在按下
	{
		//这时候还是按下状态, 不一定是真正的按键按下, 有可能是抖动造成的,接下来延时消抖
		//再次判断按键是否按下, 如果按下, 代表真正的按键仍然在按下
		if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
		{
			//那就等抬起了再做事
			value = 1;//这时候才可以判断是 长按下
		}
	}
	return value;
}


extern _Bool key_down;
void EXTI1_IRQHandler(void)
{

	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
	{
		//代表按键按下(按键标志清除--一次时间处理完成)
		key_down = 1;

	}
	EXTI_ClearITPendingBit(EXTI_Line1);
}	

key.h

#ifndef _KEY_H_
#define _KEY_H_


void Key_Init(void);
uint8_t key_scan(void);



#endif

System

delay.c

/**
	************************************************************
	************************************************************
	************************************************************
	*	文件名: 	delay.c
	*
	*	作者: 		张继瑞
	*
	*	日期: 		2016-11-23
	*
	*	版本: 		V1.0
	*
	*	说明: 		利用systick做阻塞式延时
	*
	*	修改记录:	
	************************************************************
	************************************************************
	************************************************************
**/

//单片机头文件
#include "stm32f10x.h"

//delay头文件
#include "delay.h"


//延时系数
unsigned char UsCount = 0;
unsigned short MsCount = 0;


/*
************************************************************
*	函数名称:	Delay_Init
*
*	函数功能:	systick初始化
*
*	入口参数:	无
*
*	返回参数:	无
*
*	说明:		
************************************************************
*/
void Delay_Init(void)
{

	SysTick->CTRL &= ~(1 << 2);		//选择时钟为HCLK(72MHz)/8		103--9MHz
	
	UsCount = 9;					//微秒级延时系数
	
	MsCount = UsCount * 1000;		//毫秒级延时系数

}

/*
************************************************************
*	函数名称:	DelayUs
*
*	函数功能:	微秒级延时
*
*	入口参数:	us:延时的时长
*
*	返回参数:	无
*
*	说明:		此时钟(21MHz)最大延时798915us
************************************************************
*/
void DelayUs(unsigned short us)
{

	unsigned int ctrlResult = 0;
	
	us &= 0x00FFFFFF;											//取低24位
	
	SysTick->LOAD = us * UsCount;								//装载数据
	SysTick->VAL = 0;
	SysTick->CTRL = 1;											//使能倒计数器
	
	do
	{
		ctrlResult = SysTick->CTRL;
	}
	while((ctrlResult & 0x01) && !(ctrlResult & (1 << 16)));	//保证在运行、检查是否倒计数到0
	
	SysTick->CTRL = 0;											//关闭倒计数器
	SysTick->VAL = 0;

}

/*
************************************************************
*	函数名称:	DelayXms
*
*	函数功能:	毫秒级延时
*
*	入口参数:	ms:延时的时长
*
*	返回参数:	无
*
*	说明:		
************************************************************
*/
void DelayXms(unsigned short ms)
{

	unsigned int ctrlResult = 0;
	
	if(ms == 0)
		return;
	
	ms &= 0x00FFFFFF;											//取低24位
	
	SysTick->LOAD = ms * MsCount;								//装载数据
	SysTick->VAL = 0;
	SysTick->CTRL = 1;											//使能倒计数器
	
	do
	{
		ctrlResult = SysTick->CTRL;
	}
	while((ctrlResult & 0x01) && !(ctrlResult & (1 << 16)));	//保证在运行、检查是否倒计数到0
	
	SysTick->CTRL = 0;											//关闭倒计数器
	SysTick->VAL = 0;

}

/*
************************************************************
*	函数名称:	DelayMs
*
*	函数功能:	微秒级长延时
*
*	入口参数:	ms:延时的时长
*
*	返回参数:	无
*
*	说明:		多次调用DelayXms,做到长延时
************************************************************
*/
void DelayMs(unsigned short ms)
{

	unsigned char repeat = 0;
	unsigned short remain = 0;
	
	repeat = ms / 500;
	remain = ms % 500;
	
	while(repeat)
	{
		DelayXms(500);
		repeat--;
	}
	
	if(remain)
		DelayXms(remain);

}

void delay(uint32_t t)
{
	while(t--);
}	

void delay_us(u32 us)//微秒
{
	SysTick_Config(72);
	while(us-->0)
	{
		while(!((SysTick->CTRL)&(1<<16)));
	}
	SysTick ->CTRL&=~SysTick_CTRL_ENABLE_Msk;
}

void delay_ms(u32 ms)//毫秒
{
	SysTick_Config(72000);
  while(ms-->0)
	{
		while(!((SysTick->CTRL)&(1<<16)));
	}
	SysTick ->CTRL&=~SysTick_CTRL_ENABLE_Msk;
}

delay.h

#ifndef _DELAY_H_
#define _DELAY_H_

#include "stm32f10x.h"



void Delay_Init(void);

void DelayUs(unsigned short us);

void DelayXms(unsigned short ms);

void DelayMs(unsigned short ms);
void delay(uint32_t t);

void delay_us(u32 us);
void delay_ms(u32 ms);
#endif

sys.h

#ifndef _SYS_H
#define _SYS_H

//操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第5章 92页 在 C 语言中使用位带操作 或<<CM3与M4权威指南>>第6章6.7.4 P216
//addr&0xF0000000取出最高的四位,其实就是用于区别SRAM(0x20000000)还是片上外设(0x40000000)的。
//+0x2000000对于SRAM位带区则得到 0x22000000,对于片上外设位带区则得到0x42000000?
//(addr&0xFFFFF)等效于(addr&0x000FFFFF),就是屏蔽掉高12位,地址范围是0x20000000-0x200FFFFF和0x40000000-0x400FFFFF
//<<5就等效于乘以32 ,同样<<2等效于乘以4 。
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//GPIO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 
 
//GPIO口操作,只对单一的GPIO口!确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

#endif

Time

TIM4.c

#include "stm32f10x.h"

//void (*TIM4_Handler)(void);

void TIM4_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
	
	TIM_DeInit(TIM4);
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_TimeBaseStructure.TIM_Period = 1000-1;
	TIM_TimeBaseStructure.TIM_Prescaler = 72-1;
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	TIM_ClearFlag(TIM4, TIM_FLAG_Update);
	TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE );
	
	TIM_Cmd(TIM4, ENABLE);
}

void TIM4_Cmd(FunctionalState NewState)
{
	TIM_Cmd(TIM4, NewState);
}

void TIM4_SetIRQHandler(void (*Function)(void))
{
//	TIM3_Handler=Function;
}

TIM4.h

#ifndef __TIM4_H
#define __TIM4_H
#include "stm32f10x.h"

void TIM4_Init(void);
void TIM4_Cmd(FunctionalState NewState);
void TIM4_SetIRQHandler(void (*Function)(void));

#endif

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值