小兴教你做平衡小车-stm32程序开发(按键扫描)

1 单片机最小系统板按键原理图介绍

从图中看出单片机的PB12引脚接到了按键上。
在这里插入图片描述
根据按键的原理图,可以分析得到,如果不按下按键的时候,引脚输入的是高电平。按下按键的时候,引脚输入的是低电平。
在这里插入图片描述

2 库函数程序设计

main.c文件。

#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "usart.h"
#include "key.h"
#include "stdio.h"

int main(void)
{
	RCC->APB2ENR |= (uint32_t)0x00000010;//打开GPIOC时钟
	GPIOC->CRH   &= (uint32_t)0xFF0FFFFF;//使用前清零
	GPIOC->CRH   |= (uint32_t)0x00300000;//配置PC13为推挽输出,最大速度50MHz
	Delay_Init();
	Usart_Init(115200);
	Key_Init();
	printf("hello world!\r\n");
	while(1)
	{
		GPIOC->BSRR  =  (uint32_t)0x00002000;//PC13引脚输出高电平
		Delay_ms(100);                       //延时100ms
		GPIOC->BRR  =   (uint16_t)0x2000;    //PC13引脚输出低电平
		Delay_ms(100);   		             //延时100ms
		if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0)
		{
			Delay_ms(10);  
			if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0)
				printf("key is pressed!\r\n");
		}
	}
}

key.c文件。

#include "stm32f10x.h"
#include "key.h"	

void Key_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启GPIOB时钟
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;          //PB12
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //频率为50mhz
	GPIO_Init(GPIOB,&GPIO_InitStructure);               //初始化
}

key.h文件。

#ifndef __KEY_H
#define __KEY_H

void Key_Init(void);

#endif

3 寄存器程序设计

因为寄存器操作可以直接在main.c文件中写完,这里只提供给大家main.c文件哈。

#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "usart.h"
#include "key.h"
#include "stdio.h"

int main(void)
{
	RCC->APB2ENR |= (uint32_t)0x00000010;//打开GPIOC时钟
	GPIOC->CRH   &= (uint32_t)0xFF0FFFFF;//使用前清零
	GPIOC->CRH   |= (uint32_t)0x00300000;//配置PC13为推挽输出,最大速度50MHz
	Delay_Init();
	Usart_Init(115200);
	
	//库函数版本
//	//---------------------------------------------------------//
//	Key_Init();
	//---------------------------------------------------------//
	
	//寄存器版本
	//---------------------------------------------------------//
	RCC->APB2ENR |= (uint32_t)0x00000008;//打开GPIOB时钟
	GPIOB->CRH   &= (uint32_t)0xFFF0FFFF;//使用前清零
	GPIOB->CRH   |= (uint32_t)0x00080000;//配置PB12为上/下拉输入
	GPIOB->BSRR   = (uint32_t)0x00001000;//配置PB12为上拉
	//---------------------------------------------------------//
	
	printf("hello world!\r\n");
	while(1)
	{
		GPIOC->BSRR  =  (uint32_t)0x00002000;//PC13引脚输出高电平
		Delay_ms(100);                       //延时100ms
		GPIOC->BRR  =   (uint16_t)0x2000;    //PC13引脚输出低电平
		Delay_ms(100);   		             //延时100ms
		//库函数版本
		//---------------------------------------------------------//
//		if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0)
//		{
//			Delay_ms(10);  
//			if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0)
//				printf("key is pressed!\r\n");
//		}
		//---------------------------------------------------------//
		
		//寄存器版本
		//---------------------------------------------------------//
		if((GPIOB->IDR & (uint16_t)0x1000) == 0)
		{
			Delay_ms(10);
			if((GPIOB->IDR & (uint16_t)0x1000)== 0)
				printf("key is pressed!\r\n");
		}
		//---------------------------------------------------------//
	}
}

4 效果展示

可以看出信息已经打印出来了,但是呢,有时候会出现按下按键后没有打印的情况。因为我们的按键检测是放到主函数中的,再加上之前有小灯闪烁的延时存在,这就导致了检测不是很准的原因。因此,为了更准确的检测按键,可以引入中断。
在这里插入图片描述

5 引脚外部中断

main.c文件。

//按键扫描超准确版本
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "usart.h"
#include "key.h"
#include "stdio.h"

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	RCC->APB2ENR |= (uint32_t)0x00000010;//打开GPIOC时钟
	GPIOC->CRH   &= (uint32_t)0xFF0FFFFF;//使用前清零
	GPIOC->CRH   |= (uint32_t)0x00300000;//配置PC13为推挽输出,最大速度50MHz
	Delay_Init();
	Usart_Init(115200);
	Key_Init();
	printf("hello world!\r\n");
	while(1)
	{
		GPIOC->BSRR  =  (uint32_t)0x00002000;//PC13引脚输出高电平
		Delay_ms(500);                       //延时500ms
		GPIOC->BRR  =   (uint16_t)0x2000;    //PC13引脚输出低电平
		Delay_ms(500);   		             //延时500ms
	}
}

key.c文件。

//按键扫描准确版本
#include "stm32f10x.h"
#include "key.h"
#include "delay.h"
#include "usart.h"
#include "stdio.h"

void Key_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	EXTI_InitTypeDef EXTI_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);//开启GPIOB时钟并开启复用时钟
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;          //PB12
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //频率为50mhz
	GPIO_Init(GPIOB,&GPIO_InitStructure);               //初始化
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource12);   //PB12中断线映射
	EXTI_InitStructure.EXTI_Line = EXTI_Line12; //中断线12
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;   //中断线使能开启
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//外部中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
	EXTI_Init(&EXTI_InitStructure);  //外部中断初始化
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;     //配置外部中断通道
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//设置抢占优先级为0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;       //设置子优先级为1
	NVIC_Init(&NVIC_InitStructure);   //中断优先级初始化
}

key.h文件。

#ifndef __KEY_H
#define __KEY_H

void Key_Init(void);

#endif

stm32f10x_it.c文件。

#include "stm32f10x.h"
#include "delay.h"
#include "stdio.h"

void EXTI15_10_IRQHandler(void)   //按键中断服务函数
{
	if(EXTI_GetITStatus(EXTI_Line12)!=RESET)   //判断是否触发进入中断
	{
		Delay_ms(10);   //按键消抖
		if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0)
		{
			while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0);//等待松开按键
			printf("key is pressed!\r\n");
		}
	}
	EXTI_ClearITPendingBit(EXTI_Line12);   //清除EXTI_Line12上的中断标志位
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值