STM32F0103 key scan

Preface

What I wrote this time is the STM32F103 series, 4*4 matrix keys, and the key values ​​are obtained by scanning. When I finished writing the test, I felt like I was going crazy. I was so scared that I thought the code had gone astray. I thought about it carefully. With my little skills, such a thing would not happen. Later I found out that the line was burned into the code. It's broken, the interface is unstable, and the serial port keeps printing when it is reconnected. After changing the wire, it was ok.

Schematic diagram: The schematic diagram of this test is as follows. The components used are: P5, PB4, PB3, PD2, PC12, PC11, PC10, PA15


principle:

The picture below is for reference: Set the row as pull-up input and the column as push-pull output. When scanning the keys, the frequency changes of each row will be detected in a loop. First set the first line to low level, and the rest to high level. Then check whether the input input mode of each column is triggered. The electric frequency of each column is read cyclically. When a low level in a certain column is detected, the button is pressed. The value of the pressed key can be obtained by looping the variable.

initialization:

KEY_GROUP_Config function

#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]);
    }	
	
}

Key scan

After the initialization is completed, scan the keys in a loop in the main function

uint16_t KEY_Scanf_Config(void), returns the pressed value

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 header function:

#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

Serial port part

Let’s put the serial port in too. After all, we need to print out the buttons.

#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 header file

#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() function:

#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;
		}
		
	
}
			
}

result:


Generally speaking, you have to be careful in everything you do. It's not okay to be careless all the time. You have to think clearly about everything you do. Do things carefully and act from your heart. Meticulous, attentive, subtle. From the little things. Come on.

Guess you like

Origin blog.csdn.net/apple_71040140/article/details/132973783