高产似那啥
哦,细心的同学们可能会发现又没目录了。我承认我懒,用模板都觉得麻烦
这不还是为了跟上更新进度吗?虽然更新了也没人看啊哈哈哈
我们言归正传,为了实现PWM输出,我们总得用点啥来调占空比,频率啥的吧?总不可能改一次就重新刷程序上去吧。可以
所以我们先教大家在32中按键该如何使用当然不是因为我pwm还没调好
按键一般就这两种接线方式,所以我们先介绍上拉和下拉。
一般的,当一个按键按下的时候,对应的引脚输入数据是0或1是不确定的,还要看外部电路的组成是上拉还是下拉,当外部电路时上拉的时候,即外部接正的时候,读入的数据是1;当外部电路是下拉的时候,读入的数据是0.
所以上图中可以理解为当键盘按下后key1和key0是下拉,key_up是上拉。
上拉例子:无键按下的时候是1 ,有键按下时是0
下拉例子:无键按下的时候是0 , 有键按下时是1
所以,为了让键盘按下后,我们的MCU能有所反应,我们就应该设置key0和key1上拉输入,这样当没按键摁下时,引脚读数为1,有按键摁下是,就被GND给带成0了。key_up同理。
我这边用的引脚是GPIOE4,3和GPIOA.0
那么我们按照第一章讲的样子,初始化一下IO口吧:
void KEY_Init(void) //IO初始化
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);//使能PORTA,PORTE时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_3;//KEY0-KEY1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE4,3
//初始化 WK_UP-->GPIOA.0 下拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0设置成输入,默认下拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0
}
我估么着这句话你们没看懂
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);
为什么能直接或上它俩呢?
我们右键到它的定义去看看:
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if (NewState != DISABLE)
{
RCC->APB2ENR |= RCC_APB2Periph;
}
else
{
RCC->APB2ENR &= ~RCC_APB2Periph;
}
}
嗯,好像看不出啥,那我们看看RCC_APB2Periph_GPIOA
是怎么定义的吧
可以看到这一串数转化成二进制后所占的位是互不干扰的,也就是说A占了低一位,那么剩下的BCDEF等等都不会占用A的低一位了,不信你们可以算算。
而每次调用RCC_APB2PeriphClockCmd
这个函数都会执行上图中最下面一行的#define IS_RCC_APB2_PERIPH(PERIPH) ((((PERIPH) & 0xFFC00002) == 0x00) && ((PERIPH) != 0x00))
这是个宏定义,也可以看成一个函数。我把它写成函数形式就是
void IS_RCC_APB2_PERIPH(PERIPH)
{
(((PERIPH) & 0xFFC00002) == 0x00) && ((PERIPH) != 0x00)
}
所以呀,每次调用都会与上0xFFC00002
,而每次调用的数值又互不干扰,那为什么就不能直接或上再调用呢?
10011001&11001100 = 10001000
01100110&11001100 = 01000100
10001000|01000100 = 11001100
而
10011001|01100110 = 11111111
11111111&11001100 = 11001100
10001000|01000100 = 11001100
是不是更明白了?
初始化键盘IO口后,我们就可以写扫描函数了
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1;//按键按松开标志,并不是按键KEY_UP
if(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
{
delay_ms(10);//去抖动
key_up=0;
if(KEY0==0)return 1;
else if(KEY1==0)return 2;
else if(WK_UP==1)return 3;
}else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1;
return 0;// 无按键按下
}
还是很好理解的
(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
这句话是一个简写,写得通俗易懂就是
(key_up&&KEY0==0)|(key_up&&KEY1==0)|(key_up&&KEY_UP==1);
然后就可以直接在主函数调用了
int main(void)
{
unsigned char key=0;
delay_init(); //延时函数初始化
LED_Init(); //初始化与LED连接的硬件接口
BEEP_Init(); //初始化蜂鸣器端口
KEY_Init(); //初始化与按键连接的硬件接口
LED0=0; //先点亮红灯
while(1)
{
key=KEY_Scan(0); //得到键值
if(key)
{
switch(key)
{
case 1: //控制LED0翻转
LED0=!LED0;
break;
case 2: //控制LED1翻转
LED1=!LED1;
break;
case 3: //同时控制LED0,LED1翻转
LED0=!LED0;
LED1=!LED1;
break;
}
}else delay_ms(10);
}
}
好了,赶快把代码写好去试一试吧!