按键扫描
原理图分析
首先我们先查看LED的原理图,按ctrl+f查找——>输入LED1,即可找到LED部分的原理图。User LEDs是LED的电路图,User Buttons是按键的电路图。
首先LED之前说过(MSP430F5529学习笔记(2)——点亮LED),LED高电平灯亮,低电平灯灭。
现在我们来看按键的,我们明显看到,P2.1是连接GND的。表明如果当我按下s1,P2.1会变成低电平。于是我们可以将P2.1设置为上拉输入,空闲状态为高点平。按下P2.1之后,IO为低电平。
写程序,按下s1点亮LED1
现在我们要做的是,按下s1,P2.1为低电平。我们检测P2.1脚,如果P2.1脚为低电平,LED1亮。P2.1为高电平,LED1灭
1,首先我们需要告诉单片机,P2.1是输入还是输出
我们看数据手册,前几张博客也说了。如果P2DIR为高电平表示输入,P2DIR为低电平表示输出。
2,配置IO是否允许上下拉
我们看数据手册可以知道,他需要配置一个PxREN的寄存器,来确认IO是否可以上下拉。很明显我们需要将IO进行上拉
3,配置IO是上拉还是下拉
因为此处是输入,所以我们只需要看下面的IO输入部分。我们知道,bit=1为上拉输入。所以我们要将PxOUT的bit设置为1。
4,检测当前电平
因为我们知道P2.1为低电平表示按键被按下,所以我们需要一个检测电平的寄存器。PxIN就是用于检测高低电平的。需要注意的一点是 ,PxIN只能用于读,不能写入。
5,按键消抖
独立按键工作原理
我们都知道按键按下是会有抖动的,而这个抖动时间一般位5~20ms,而且我们人手按下按键一般都是零点几秒,甚至几秒,不可能做到20ms按下再松开。所以我们就可以延时20ms跳过抖动时间重新电平是否为0,如果电平为0,则按键被按下。同时加一个while等待松开按键。
if((P2IN &(0x01<<1))==0x00) //如果P2.1为低电平 { delay_ms(20); P1OUT=0x01<<0; while((P2IN &(0x01<<1))==0x00); }
6,实操
#define CPU_F ((double)1000000) #define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0)) #define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0)) /** * main.c */ void main() { WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer /****配置LED****/ //P1.0为输出 P1DIR = 0x01<<0; /****配置按键****/ //P2.1为输入 P2DIR = 0x00; //开启P2.1的上下拉 P2REN = 0x02; //P2.1都为上拉输入 P2OUT = 0x02; while(1) { if((P2IN &(0x01<<1))==0x00) //如果P2.1为低电平 { delay_ms(20); P1OUT = 0x01; while((P2IN &(0x01<<1))==0x00); } else P1OUT =0x00; } }
写程序——按下s1点亮LED1,按下s2点亮LED2
让按下s1点亮LED1很简单,因为他们s1是P2.1口,LED1是P1.0口。但是我们看板子上面,s2是P1.1口,与LED1有所冲突,他们都是P1口。写程序肯定麻烦一点。
这个时候我们就要又&和|的概念了。
&,|,~简单介绍
&,就是有0出0。比如说,0010&0110,结果为0010。
|,就是有1出1(如果记不住,可以记着|长得像1,所以是有1出1)。比如说,0010|0110,结果为0110。
~,就说有1出0,有0出1。~0101,结果为1010。
只操作一个bit让其为高电平
既然我们知道了&和|的作用之后。我们想让P1.0为输出可以这样写。
这样写我们就只会改变P1.0引脚,其他引脚没有变化 P1DIR |= (0x01<<0);
如果那么无法理解,那我就先假设P1DIR=0x40; 0100 0000,如果我们需要在这里将P1.0为输出。不能写成P1DIR=0x01;那样P1.6会从输出变为输入。
0100 0000|(0x01<<0),那么就是0100 0000 | 0000 0001。结果为0100 00001。
只操作一个bit让其为低电平
假如我现在想让P1.0为低电平。还是假设P1DIR=0x40; 0100 0000
P1DIR &= ~(0x01<<0); 0100 0000 & 1111 1110 ——>0100 0000
现在我们就能够将P1.0随意变成输出或者输入,其他引脚也不会受到改变。
很多时候我们都知道这个原理,但是写出来可能就忘了。想要记住也简单,就是&1,|0。
实操
我们知道&和|之后,就可以实操了。具体自己看,我懒得啰嗦了。
记住&=~,表示让指定引脚为低电平, |=表示让指定引脚为高电平。
#define CPU_F ((double)1000000) #define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0)) #define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0)) /** * main.c */ void main() { WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer /****配置LED****/ //P1.0和P4.7为输出 P1DIR |= (0x01<<0); P4DIR |= (0x01<<7); /****配置按键****/ //P2.1和P1.1为输入 P2DIR &= ~(0x01<<1); P1DIR &= ~(0x01<<1); //开启P2.1和P1.1的上下拉 P2REN |= (0x01<<1); P1REN |= (0x01<<1); //P2.1和P1.1都为上拉输入 P2OUT |= (0x01<<1); P1OUT |= (0x01<<1); while(1) { if((P2IN &(0x01<<1))==0x00) //如果P2.1为低电平 { delay_ms(20); P1OUT|=(0x01<<0); while((P2IN &(0x01<<1))==0x00); } else P1OUT&=~(0x01<<0); if((P1IN &(0x01<<1))==0x00) //如果P1.1为低电平 { delay_ms(20); P4OUT|=(0x01<<7); while((P1IN &(0x01<<1))==0x00); } else P4OUT&=~(0x01<<7); } }
总结
位操作
&=~为1,|=为0
如果我们想让某一个引脚为1,就使用&=~。如果想让他为0就使用|=。
P1OUT|=(0x01<<0); //P1.0输出高电平 P1OUT&=~(0x01<<0); //P1.0输出低电平
PxDIR,PxIN,PxOUT,PxREN
输出
初始化
输出的初始化,只需要配置一个PxDIR即可。
P1DIR |= (0x01<<0); //P1.0为输出
输出电平
利用 PxOUT输出高电平还是低电平
P1OUT|=(0x01<<0); //P1.0输出高电平 P1OUT&=~(0x01<<0); //P1.0输出低电平
输入
初始化
输入需要匹配PxDIR,PxREN,PxOUT。
(1)先配置PxDIR
P2DIR &= ~(0x01<<1); //P2.1为输入
(2)再配置PxREN
P2REN |= (0x01<<1); //开启P2.1的上下拉
(3)先配置PxOUT
P2OUT |= (0x01<<1); //P2.1为上拉输入
电平检测
PxIN,只可读取,不能修改。如果bit为0表示检测到低电平,bit为1,表示检测到高电平。
if((P2IN &(0x01<<1))==0x00) //如果P2.1为低电平 P1OUT|=(0x01<<0); else //如果P2.1为高电平 P1OUT&=~(0x01<<0);