proteus实现矩阵按键(stm32)
·
一、新建工程

1、工程命名
2、选择工程存储位置

3、默认下一步

4、默认下一步

5、选择没有固件项目,下一步
二、器件放置并连线
1、点击左边工具栏中运放的形状的符号
2、再点击‘P’,搜索器件

3、搜索器件并放置连线

按键控制LED需要的器件有,按键、电容、LED、电阻、主控,LCD1602显示屏,主控选择的是stm32f103r6。
4、器件连线,如下图所示:

图中使用了网络标签,网络标签是在电源、GND的那个工具栏中的DEFAULT。
三、网络配置
1、想要仿真成功运行,首先配置主控参数,双击主控,选择Program File,即代码的hex文件路径,以及Crystal Frequency,即晶振的频率8M,具体如下图所示:

2、仿真供电网络的配置,点击工具栏中的“design”,再点击配置供电网络(点击design后的第四个选项),将"VDDA"增加到"VCC/VDD"中,将"VSSA"增加到"GND"中,如下图所示:


四、代码分享
1、LCD.c代码
#include "stm32f10x.h" // Device header
#include "LCD1602.h"
void LCD1602_PORT_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx,ENABLE); //使能PC端口时钟
GPIO_InitStructure.GPIO_Pin = GPIOx_Pin; //端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; //IO口速度为10MHz
GPIO_Init(GPIOx, &GPIO_InitStructure); //根据设定参数初始化
}
void delay_nus(uint16_t n)//微妙级延时,通常情况此函数可以不用更改
{
uint16_t i;
while(n--)
{
i=20;
while(i--);
}
}
void delay_nms(uint16_t n) //毫秒级延时,保通常情况此函数可以不用更改
{
while(n--)
delay_nus(1100);
}
void LCD_init(void) //初始化,通常情况此函数可以不用更改
{
LCD1602_PORT_Init(); //LCD 1602使用的PC口初始化
LCD_RS_0;
LCD_RW_0;
LCD_EN_0;
delay_nms(5);
LCD_cmd(0x38);//16*2显示,5*7点阵,8数据
delay_nms(1);
LCD_cmd(0x38);//16*2显示,5*7点阵,8数据
delay_nms(1);
LCD_cmd(0x38);//16*2显示,5*7点阵,8数据
delay_nms(1);
LCD_cmd(0x08);//先关显示,后开显示
delay_nms(1);
LCD_cmd(0x01);//清屏
delay_nms(1);
LCD_cmd(0x06);//写命令,注意
delay_nms(1);
LCD_cmd(0x0c);//显示开,关光标
delay_nms(1);
}
void LCD_clr(void) //清屏
{
LCD_cmd(0x01);
}
void LCD_cmd(uint16_t cmd)//写命令
{
LCD_RS_0;
delay_nus(1);
LCD_RW_0;
delay_nus(1);
LCD_EN_0;
delay_nus(1);
GPIO_SetBits(LCDPORT, LCD_DATA_PORT & cmd);
GPIO_ResetBits(LCDPORT, LCD_DATA_PORT &(~cmd));
LCD_EN_1;
delay_nus(1);
LCD_EN_0;
}
void LCD_dat(uint8_t dat)//写数据
{
delay_nms(1);
LCD_RS_1;
delay_nus(1);
LCD_RW_0;
delay_nus(1);
LCD_EN_0;
delay_nus(1);
GPIO_SetBits(LCDPORT, LCD_DATA_PORT & dat);
GPIO_ResetBits(LCDPORT, LCD_DATA_PORT &(~dat));
LCD_EN_1;
delay_nus(1);
LCD_EN_0;
}
//写字符串
void LCD_Write_String(uint8_t x,uint8_t y,uint8_t *s)
{
if (y == 0)
{
LCD_cmd(0x80 + x); //第一行
}
else
{
LCD_cmd(0xC0 + x); //第二行
}
while (*s)
{
LCD_dat( *s);
s ++;
}
}
//写字符
void LCD_Write_Char(uint8_t x,uint8_t y,uint8_t Data)
{
if (y == 0)
{
LCD_cmd(0x80 + x);
}
else
{
LCD_cmd(0xC0 + x);
}
LCD_dat( Data);
}
void LCD_pos(uint16_t x,uint16_t y)//显示位置,不需要修改
{
if(y)
LCD_cmd(x | 0xc0);
else
LCD_cmd(x | 0x80);
}
void LCD_printc(uint16_t x,uint16_t y,uint8_t c)//显示字符,不需要修改
{
LCD_pos(x,y);
LCD_dat(c);
}
void LCD_prints(uint16_t x,uint16_t y,uint8_t *s)//显示字符串,不需要修改
{
LCD_pos(x,y);
while(*s!='\0')
{
LCD_dat(*s);
s++;
//delay_nms(1);
}
}
2、LCD.h代码
#ifndef __LCD1602_H
#define __LCD1602_H
/***********端口定义**********************************************************/
/*#define rs GPIOSetValue(PORT2,0,rs)
#define rw GPIOSetValue(PORT2,1,rw)
#define e GPIOSetValue(PORT2,2,e)
*/
#define LCDPORT GPIOC
#define RS_PIN GPIO_Pin_8
#define RW_PIN GPIO_Pin_9
#define EN_PIN GPIO_Pin_10
#define GPIOx GPIOC
#define RCC_APB2Periph_GPIOx RCC_APB2Periph_GPIOC
#define GPIOx_Pin GPIO_Pin_All
#define LCD_DATA_PORT 0xff
#define LCD_RS_1 GPIO_SetBits(LCDPORT, RS_PIN)
#define LCD_RS_0 GPIO_ResetBits(LCDPORT, RS_PIN)
#define LCD_RW_1 GPIO_SetBits(LCDPORT, RW_PIN)
#define LCD_RW_0 GPIO_ResetBits(LCDPORT, RW_PIN)
#define LCD_EN_1 GPIO_SetBits(LCDPORT, EN_PIN)
#define LCD_EN_0 GPIO_ResetBits(LCDPORT, EN_PIN)
void LCD1602_PORT_Init(void);
void LCD_init(void);
void LCD_clr(void);
void LCD_cmd(uint16_t cmd);
void LCD_dat(uint8_t dat);
void LCD_pos(uint16_t x,uint16_t y);
void LCD_Write_Char(uint8_t x,uint8_t y,uint8_t Data) ;
void LCD_printc(uint16_t x,uint16_t y,uint8_t c);
void LCD_prints(uint16_t x,uint16_t y,uint8_t *s);
extern void delay_nus(uint16_t us);
extern void delay_nms(uint16_t ms);
void LCD_Write_String(uint8_t x,uint8_t y,uint8_t *s) ;
#endif
3、按键代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
uint8_t KeyNum = 0; //定义变量,默认键码值为0
/**
* 函 数:按键初始化
* 参 数:无
* 返 回 值:无
*/
void Key_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
/*矩阵键盘的列GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 |GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//将PB0、PB1、PB2、PB3 引脚初始化为推挽输出
/*矩阵键盘的行GPIO初始化*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB4、PB5、PB6、PB7引脚初始化为推挽输出
GPIO_SetBits(GPIOB,GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
}
/**
* 函 数:矩阵按键扫描获取键码
* 参 数:无
* 返 回 值:按下按键的键码值,范围:0~16,返回0代表没有按键按下
* 注意事项:此函数是阻塞式操作,当按键按住不放时,函数会卡住,直到按键松手
*/
uint8_t Key_Scan(void)
{
// uint8_t KeyNum = 0; // 初始化按键值为0,表示无按键按下
uint8_t row, col;
uint16_t rowPins[4] = {GPIO_Pin_4, GPIO_Pin_5, GPIO_Pin_6, GPIO_Pin_7};
uint16_t colPins[4] = {GPIO_Pin_0, GPIO_Pin_1, GPIO_Pin_2, GPIO_Pin_3};
// 扫描每一行
for (row = 0; row < 4; row++) {
// 选中当前行(拉低)
GPIO_ResetBits(GPIOB, rowPins[row]);
// 检测列是否有按键按下
if ((GPIO_ReadInputDataBit(GPIOB, colPins[0]) == 0) ||
(GPIO_ReadInputDataBit(GPIOB, colPins[1]) == 0) ||
(GPIO_ReadInputDataBit(GPIOB, colPins[2]) == 0) ||
(GPIO_ReadInputDataBit(GPIOB, colPins[3]) == 0)) {
Delay_ms(10); // 消抖延时
// 确认按键按下,查找具体按下的列
for (col = 0; col < 4; col++) {
if (GPIO_ReadInputDataBit(GPIOB, colPins[col]) == 0) {
// 计算键值 (1-16)
KeyNum = row * 4 + col + 1;
// 等待按键释放
while (GPIO_ReadInputDataBit(GPIOB, colPins[col]) == 0);
// 清除当前行选择
GPIO_SetBits(GPIOB, rowPins[row]);
return KeyNum; // 找到按键后立即返回
}
}
}
// 清除当前行选择
GPIO_SetBits(GPIOB, rowPins[row]);
}
return KeyNum; // 无按键按下,返回0
}
4、main函数代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"
#include "LCD1602.h"
#include "stdint.h"
#include "stdio.h"
#include "stm32f10x_conf.h"
/****全局变量******************************************/
uint8_t lcd_dat1[20];//液晶第一行
uint8_t lcd_dat2[20];//液晶第二行
uint8_t Key_Num=0;
int main(void)
{
Key_Init();
LCD_init(); //LCD1602初始化
LCD_clr();//LCD清屏幕
LCD_Write_Char(0,1,1);
while (1)
{
Key_Num=Key_Scan();
sprintf(lcd_dat1,"%d",Key_Num);
LCD_prints(0,0,lcd_dat1);//液晶显示第一行
}
}
main函数实现了点击矩阵按键,LCD显示矩阵按键的编号。
五、仿真与实物不同之处
1、仿真的按键引脚需要外部电路上拉
2、仿真不需要晶振电路
更多推荐
所有评论(0)