MSP430F5529学习笔记(3)——实现LED闪烁和呼吸灯;独立按键工作原理
目录
按键扫描
原理图分析
写程序,按下s1点亮LED1
1,首先我们需要告诉单片机,P2.1是输入还是输出
2,配置IO是否允许上下拉
3,配置IO是上拉还是下拉
4,检测当前电平
5,按键消抖
6,实操
写程序——按下s1点亮LED1,按下s2点亮LED2
&,|,~简单介绍
只操作一个bit让其为高电平
只操作一个bit让其为低电平
实操
总结
位操作
PxDIR,PxIN,PxOUT,PxREN
输出
初始化
输出电平
输入
初始化
电平检测
按键扫描
原理图分析
首先我们先查看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);
}
}
总结
位操作
&=~为0,|=为1
如果我们想让某一个引脚为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);