Escaneo de claves STM32F0103

Prefacio

Lo que escribí esta vez es la serie STM32F103, claves matriciales de 4 * 4 y los valores de las claves se obtienen mediante escaneo. Cuando terminé de escribir la prueba, sentí que me estaba volviendo loco. Tenía tanto miedo que pensé que el código se había desviado. Lo pensé detenidamente. Con mis pequeñas habilidades, tal cosa no sucedería. Más tarde lo descubrí. que la línea fue grabada en el código. Está rota, la interfaz es inestable y el puerto serie sigue imprimiendo cuando se vuelve a conectar. Después de cambiar el cable, todo estaba bien.

Diagrama esquemático: El diagrama esquemático de esta prueba es el siguiente, los componentes utilizados son: P5, PB4, PB3, PD2, PC12, PC11, PC10, PA15.


principio:

La siguiente imagen es como referencia: configure la fila como entrada pull-up y la columna como salida push-pull. Al escanear las teclas, los cambios de frecuencia de cada fila se detectarán en un bucle. Primero configure la primera línea en nivel bajo y el resto en nivel alto. Luego verifique si se activa el modo de entrada de entrada de cada columna. La frecuencia eléctrica de cada columna se lee cíclicamente, cuando se detecta un nivel bajo en una determinada columna se presiona el botón. El valor de la tecla presionada se puede obtener haciendo un bucle con la variable.

inicialización:

Función 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]);
    }	
	
}

Escaneo de claves

Una vez completada la inicialización, escanee las claves en un bucle en la función principal

uint16_t KEY_Scanf_Config(void), devuelve el valor presionado

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,

}

función de encabezado clave:

#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

Parte del puerto serie

Pongamos también el puerto serie, después de todo, necesitamos imprimir los botones.

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

Archivo de encabezado 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

función principal:

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

resultado:


En general hay que tener cuidado en todo lo que se hace, no está bien ser descuidado todo el tiempo, hay que pensar con claridad en todo lo que se hace, hacer las cosas con cuidado y actuar desde el corazón. Meticuloso, atento, sutil. De las pequeñas cosas. Vamos.

Supongo que te gusta

Origin blog.csdn.net/apple_71040140/article/details/132973783
Recomendado
Clasificación