按键收集模型代码快速复制
对应勾选底层配置
CMSIS -> CORE
Device->Startup
Device->StdPeriph Drivers->EXTI , Framework, GPIO, RCC, TIM
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