这一篇选择解析 以 button 输入的程式练习。
内容很简单,就是
- 设定 key/button 的输入寄存器
- 掃描检查 哪一个 key/button 被触发并传回一个讯号
- 取得讯号,依照讯号指示执行特定功能。
所以,main() 主程式可以看到三部分, 启动各种设定,key_scan 和 switch…case…
以下是 MAIN.c 的内容:
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "beep.h"
/************************************************
int main(void)
{
vu8 key=0;
Stm32_Clock_Init(9);//
delay_init(72); //
LED_Init(); //
KEY_Init(); //
BEEP_Init(); //
LED0=0; //
while(1)
{
key = KEY_Scan(0);//
switch(key)
{
case KEY0_PRES://KEY0
LED0=!LED0;
break;
case KEY1_PRES://KEY1
LED1=!LED1;
break;
case KEY2_PRES:// BEEP
BEEP=!BEEP;
break;
case WKUP_PRES://KEY_UP
LED0=!LED0;
LED1=!LED1;
break;
default:
delay_ms(10);
}
}
}
线路图
图上可以看到 4 个 key
- PA0 – wake_up,需要 下拉
- PC8 – Key0, 需要 上拉
- PC9 – Key1, 需要 上拉
- PD2 – Key2, 需要 上拉
key.h 档 和 key.c 档
// key.h
#ifndef __KEY_H
#define __KEY_H
#include "sys.h"
//
#define KEY0 PCin(8)
#define KEY1 PCin(9)
#define KEY2 PDin(2)
#define WK_UP PAin(0)
#define KEY0_PRES 1 //KEY0 这个数字是 return 后的控制码
#define KEY1_PRES 2 //KEY1 这个数字是 return 后的控制码
#define KEY2_PRES 3 //KEY2 这个数字是 return 后的控制码
#define WKUP_PRES 4 //WK_UP 这个数字是 return 后的控制码
void KEY_Init(void); //
u8 KEY_Scan(u8 mode); //
#endif
以下是 key.c 档,请看注解
#include "key.h"
#include "delay.h"
//
void KEY_Init(void)
{
RCC->APB2ENR|=1<<2; //PORTA
RCC->APB2ENR|=1<<4; //PORTC
RCC->APB2ENR|=1<<5; //PORTD
GPIOA->CRL&=0XFFFFFFF0; //PA0
GPIOA->CRL|=0X00000008; // 8 ==》 二进制 1000
GPIOC->CRH&=0XFFFFFF00; //PC8 、9
GPIOC->CRH|=0X00000088;
GPIOC->ODR|=1<<8; //PC8
GPIOC->ODR|=1<<9; //PC9
GPIOD->CRL&=0XFFFFF0FF; //PD2
GPIOD->CRL|=0X00000800;
GPIOD->ODR|=1<<2; //PD2
}
//mode:0,;1,;
// KEY0>KEY1>KEY2>WK_UP!!
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1;//
if(mode) key_up=1; // 这个 mode 被当成一个“使能” 的旗标,表示是这个程式在跑
if(key_up&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1))
{
delay_ms(10);//
key_up=0; // 清除 “使能” 的旗标
if(KEY0==0)return KEY0_PRES;
else if(KEY1==0)return KEY1_PRES;
else if(KEY2==0)return KEY2_PRES;
else if(WK_UP==1)return WKUP_PRES;
}else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0) key_up=1;
return 0;//
}
这里再复习一次 GPIOx 的 CRL 和 CRH
GPIOA->CRL|=0X00000008; 是 CNFy= 10, MODEy = 00
**“输入模式(复位后的状态),上拉下拉输入模式”**
再查表
GPIOD->ODR|=1<<2; //PD2 =1 是 上拉输入, 见下一张图表
以下是部分 sys.h 的内容,(参考用)
#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //
#define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
执行后的结果:
- PA0 – wake_up,pc0 和 pc1 的 LED 呈现与当下相反的亮或灭 灯
- PC8 – Key0, pc0 的 LED 亮或灭
- PC9 – Key1, pc1 的 LED 亮或灭
- PD2 – Key2, beep 打开或关闭
有兴趣的人,也可以把亮灯改到 7 节显示器上试试!