STM32F0103按键扫描

前言

本次编写的是STM32F103系列,4*4矩阵按键,利用扫描方式获得按键值。编写完成检测是,发了疯一样,给孩子整怕了,还以为代码哪里跑偏了,仔细想一下不至于啊,就我这小技术,不至于发生这样的事,后面发现是烧入线坏了,接口不稳定,一直在重新接入导致串口一直在打印。后面换了根线就ok了。

原理图:本次测试的原理图如下,用到的应交分别为引:P5,PB4,PB3,PD2,PC12,PC11,PC10,PA15


原理:

一下图为参考:将行设置为上拉输入,列设置为推挽输出,扫描按键时,循环依次检测每一行的电频变化。先将第一行设置为低电平,其余均为高电平。再检测每一列的输入输入模式是否被触发。循环读取每一列的电频,当检测到某一列为低电平时则按键被按下。通过循环变量可以得到被按下的按键值。

初始化:

KEY_GROUP_Config函数

#define ROWS 4	//行
#define COLS 4	//列
GPIO_TypeDef * row_ports[ROWS] = {GPIOB, GPIOB, GPIOB, GPIOD};	//这里一一对应好每个引脚
uint16_t row_pins[ROWS] = {GPIO_Pin_5, GPIO_Pin_4, GPIO_Pin_3, GPIO_Pin_2};
GPIO_TypeDef * col_ports[COLS] = {GPIOC, GPIOC, GPIOC, GPIOA};
uint16_t col_pins[COLS] = {GPIO_Pin_12, GPIO_Pin_11, GPIO_Pin_10, GPIO_Pin_15};

void Key_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD, ENABLE);
	GPIO_PinRemapConfig( GPIO_Remap_SWJ_Disable,ENABLE);//失能SWJ引脚,PA15,PB3,PB4
	// 配置行引脚为输入模式,并启用内部上拉电阻
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;	//将每一行设置为上拉输入模式
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;//频率为2MHz
    for (int i = 0; i < ROWS; i++) {	//循环初始化数组
        GPIO_InitStruct.GPIO_Pin = row_pins[i];
        GPIO_Init(row_ports[i], &GPIO_InitStruct);
    }

    // 配置列引脚为输出模式,并设置初始输出值为高电平
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;//配置为推挽输出
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
    for (int i = 0; i < COLS; i++) {
        GPIO_InitStruct.GPIO_Pin = col_pins[i];
        GPIO_Init(col_ports[i], &GPIO_InitStruct);
		GPIO_SetBits(col_ports[i],col_pins[i]);
    }	
	
}

按键扫描

初始化完成后,再主函数中循环扫描按键

uint16_t KEY_Scanf_Config(void),将按下得值返回

uint16_t KEY_Scanf_Config(void)
{
//	unsigned char key_state[4][4] = {0};//获取按下的值
	uint16_t val = 0;
	 for (int i = 0; i < COLS; ++i) {
		 
        // 设置当前列为低电平
       GPIO_ResetBits(col_ports[i], col_pins[i]);
		 
        // 延时一段时间以稳定电平
			   Delay_ms(30);
        // 检测列引脚的电平状态,并根据不同的状态设置按键状态
        for (int j = 0; j <ROWS; ++j) {
			  
            if (GPIO_ReadInputDataBit(row_ports[j], row_pins[j])) {
          //      key_state[i][j] = 0; // 按键释放状态
				
            } else if(!GPIO_ReadInputDataBit(row_ports[j], row_pins[j])){
				//key_state[i][j] = 1;	
				LED_ON;	
				val = (j* ROWS) + i + 1; // 计算按键值	
				
			//	printf("%d\n",val);				
			}        
        // 恢复当前行为高电平
		//GPIO_SetBits(col_ports[i], col_pins[i]);
		}
		GPIO_SetBits(col_ports[i], col_pins[i]);	//恢复高电平,一行为低电平其余行为高电平
	}
		
	if(val != 0){
		printf("%d",val);//打印获得值
		return val;//将只返回出去
	}	
		return 0;		//没有按下按键时候返回0,

}

key头函数:

#ifndef __KEY_GROUP_H
#define __KEY_GROUP_H
#include "stm32f10x.h" 
#include "Delay.h"
#include "stdio.h"
#include "USART.h"
#include "LED.h"

uint16_t KEY_Scanf_Config(void);
void Key_Config(void);


#endif

串口部分

串口也放进来吧,毕竟需要打印出按键

#include "USART.h"
extern uint8_t flag;

void USART_Config_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	USART_InitTypeDef  USART_InitStruct;
	NVIC_InitTypeDef  NVIC_InitStruct;
	//初始化GPIOA_PIN9|10号引脚,USART1,AFIO复用功能
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO, ENABLE);

	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 ;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;

	//初始化GPIO引脚
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
	
	GPIO_Init(GPIOA,&GPIO_InitStruct);

	USART_InitStruct.USART_BaudRate = 115200;	//波特率
	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;	//硬件流控制
	USART_InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; //发送接收模式
	USART_InitStruct.USART_StopBits = USART_StopBits_1;//停止位
	USART_InitStruct.USART_Parity = USART_Parity_No;//奇偶校验
	USART_InitStruct.USART_WordLength = USART_WordLength_8b;	//数据位
	//初始化串口
	USART_Init(USART1, &USART_InitStruct);
	
	//配置接受中断源:USART_IT_RXNE
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

	//配置中断优先级NVIC
	NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;	
	NVIC_Init(&NVIC_InitStruct);
	
	USART_ClearFlag(USART1,USART_FLAG_TC|USART_FLAG_TXE);
	//打开串口1
	USART_Cmd(USART1, ENABLE );
	
	
}

void Send_Msg(uint8_t data)
{
	USART_SendData(USART1,data);//发送信息
	while(SET != USART_GetFlagStatus(USART1,USART_FLAG_TC));//发送标志位获取,知道发送全
}

void Rev_Msg(void)
{	
	if(SET==USART_GetFlagStatus(USART1,USART_FLAG_RXNE)){//接受数据
		USART_ClearFlag(USART1,USART_FLAG_RXNE);//清除标志位置
		USART_SendData(USART1,USART_ReceiveData(USART1));//发送信息到串口助手
	}
}
extern uint8_t flag;//判断是否接受完全的标志位
extern char ptr[10];  //接受数据数组
volatile uint8_t recv_data;
volatile uint32_t strIndex = 0;
void USART1_IRQHandler(void)
{
	
	//中断服务函数
	if(SET == USART_GetFlagStatus(USART1,USART_IT_RXNE))
	{
		//清除标志位
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);//
		recv_data = USART_ReceiveData(USART1);//把接受到的数据放到变量中
		//USART_SendData(USART1,recv_data);//发送信息到串口助手
		
	//	while(SET != USART_GetFlagStatus(USART1,USART_FLAG_TC));				
		if(recv_data =='\n'){
			ptr[strIndex] = '\0'; 
			flag = 1; 
			strIndex = 0;			
		}else {
			ptr[strIndex] = recv_data;
			strIndex++;			
		}
		
	}
				
}





int fputc(int ch,FILE *f)
{
	USART1->DR=(uint8_t)ch;   //将其强转为char类型数据放入数据寄存器中
	
	while(0==(USART1->SR&(1<<6)));  //循环发送
	USART1->SR &=~(1<<6);
	return ch;
	
}

USART的头文件

#ifndef __USART_H
#define __USART_H

#include "stm32f10x.h"                  // Device header

void Send_Msg(uint8_t data);
void Rev_Msg(void);
void USART_Config_Init(void);
#include "stdio.h"
#include "string.h"
int fputc(int ch,FILE*f);
#endif

main()函数:

#include "stm32f10x.h"                  // Device header
#include "USART.h"
#include "LED.h"
#include "stdio.h"
#include "KEY_GROUP.h"
uint8_t flag;
char ptr[20];

uint16_t val;
int main()
{	
	
	LED_Init();	
	//中断管理方式
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	USART_Config_Init();
	Key_Config();
	//Key_Group_Config();
	printf("进入while循环\n");
	
	while(1){
		
		val = KEY_Scanf_Config();
		if(val){
			
			//LED_ON;
			
		printf("s %d 被按下\n",val);

			val = 0;
		}
		
	
}
			
}

结果:


总体来说,干啥事情都要小心点,总是马马虎虎的这样不行的啊,干啥事情都要思考清楚呀,慎重做事,从心而为。细致,细心,细微。从小事做起。加油冲。

猜你喜欢

转载自blog.csdn.net/apple_71040140/article/details/132973783