嵌入式实战(一)| GPIO实验 跑马灯效果实现 寄存器及其代码全解析

发布时间:2024年01月04日


硬件图如下
在这里插入图片描述

实际上他们在端口命名的时候进行了分组

如上所示,P和点号之间的我认为他就是代表一个组,用某个寄存器控制,所以有0,1,2组

1 GPIO编程用到的寄存器介绍

1.1 PxSEL寄存器

基本介绍

端口功能选择,用来设置端口为通用I/O还是外设I/O功能

关于这两个功能区别如下

通用I/O功能,可以输出高低电平,在本实验中我们只需要给LED灯高低电平即可,因而设置为通用的

外设I/O功能 一般的外部设备,例如摄像头或者打印机他们具体实现某些功能(拍照或打印文档),单片机要控制这些外部设备,一般的来说单片机的I/O口与这些外设的引脚相连,通过I/O引脚实现对外部设备的控制,让它们完成我们要求的功能

使用方法

PxSEL中的x代表几号端口组

比如上面的按键1KEY1对应的是P0.1 所以就应该控制P0SEL寄存器

那么每一位上面含义呢,对于位位0代表是通用I/O,1代表外设I/O

例如:将P1_0、P1_1、P1_3和P1_4设置成通用I/O,即相应的bit置0

P1SEL &=~0x1B; //0001 1011

注意这里有取反操作,

设0用取反与,设1用或

1.2 PxDIR寄存器

基本介绍

端口方向选择,是输入还是输出

注意这里的输入还是输出都是站在单片机角度的

比如:对于LED灯是单片机输出信号到灯,所以对应端口设置为输出,按键是外部给单片机输入,所以设置为输入

使用方法

PxDIR中的x代表几号端口组

将P1_0、P1_1、P1_3和P1_4设置成输出口,即相应的bit置1

P1DIR |=0x1B; //0001 1101

设置了传输方向为输出后,比如输出给LED灯,然后我们通过在端口设置高电平直接就可以控制灯的亮暗了

例如:

 P1_0=1; P1_1=0;

1.3 PxINP寄存器

基本介绍

当端口设置为输入模式的时候,即上面的PxDIR对应位设置为0的时候,可以进一步设置输入

具体有三种,上拉和下拉和三态

上拉是指单片机的引脚通过一个电阻连接到电源(高电平),当外界没有信号输入到引脚时,引脚被上拉电阻固定在高电平(逻辑值1)。相当于初始给引脚一个高电平

下拉是指单片机的引脚通过一个电阻连接到地(低电平),当外界没有信号输入到引脚时,引脚被下拉电阻固定在低电平(逻辑值0)。相当于初始给引脚一个低电平

三态也称高阻,即I/O引脚既没有上拉到电源,也没有下拉到地,呈现高阻值状态。三态模式一般用于引脚的输出功能,特别当单片机的引脚接在多个设备公用的通信总线上时。当单片机不发送信号时,采用三态工作模式可以保证不干扰其他设备之间的通信。三态模式用于输入引脚时,引脚必须外接其他器件,此时不存在上拉或下拉电阻,还能降低单片机的功耗。

使用方法

P0INP,P1INP寄存器每一位含义如下

在这里插入图片描述

P2INP寄存器每一位含义如下

在这里插入图片描述

可以在输入端口读取电平值

比如

if(P1_2 == 0) //判断按键被按下

2 按键消抖

2.1 软件消抖

最简单的消抖原理,就是当检测到按键状态变化后,先等待一个10ms左右的延时时间,让抖动消失后再进行一次按键状态检测,如果与刚才检测到的状态相同,就可以确认按键已经稳定的动作了。

if(SW1 == 0) //判断按键被按下
{
	DelayMS (10); //为消抖进行延时
	if(SW1 == 0 ) //经过延时后按键仍处在按下状态
	{
	...
	while(!SW1); //等待按键松开
	}
}

3 经典任务代码解析

三个LED灯跑马灯效果,采用软件消抖

注意InitKey的初始化函数

/****************************************************************************
* 文 件 名: main.c
* 描    述: 按下按键KEY1控制LED1.LED2.LED3实现跑马灯效果
****************************************************************************/
#include <ioCC2530.h>

typedef unsigned char uchar;
typedef unsigned int  uint;


#define LED1 P1_0       //定义P1.0口为LED1控制端
#define LED2 P1_1       //定义P1.1口为LED2控制端
#define LED3 P1_4       //定义P1.4口为LED3控制端

#define KEY1 P0_1       // P0.1口控制按键KEY1
#define KEY2 P2_0       // P2.0口控制按键KEY2
#define KEY3 P0_7       // P0.7口控制按键KEY3

#define ON      1    
#define OFF     0


/****************************************************************************
* 名    称: DelayMS()
* 功    能: 以毫秒为单位延时,系统时钟不配置时默认为16M(用示波器测量相当精确)
* 入口参数: msec 延时参数,值越大,延时越久
* 出口参数: 无
****************************************************************************/
void DelayMS(uint msec)
{ 
    uint i,j;
    static int DelayCallCount=0;
    
    for (i=0; i<msec; i++)
        for (j=0; j<535; j++);
    DelayCallCount++;
}

/****************************************************************************
* 名    称: LedOnOrOff()
* 功    能: 点亮或熄灭所有LED灯    
* 入口参数: mode为0时LED灯亮  mode为1时LED灯灭
* 出口参数: 无
****************************************************************************/
void LedOnOrOff(uchar mode)
{
    LED1 = mode;
    LED2 = mode;
    LED3 = mode; 
}

/****************************************************************************
* 名    称: InitLed()
* 功    能: 设置LED相应的IO口
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitLed(void)
{

  P1DIR |= 0x01;               //P1.0定义为输出口  
  P1DIR |= 0x02;               //P1.1定义为输出口 
  P1DIR |= 0x10;               //P1.4定义为输出口 
  asm("NOP");
  
  LedOnOrOff(0);  // 使所有LED灯默认为熄灭状态  
}

/****************************************************************************
* 名    称: InitKey()
* 功    能: 设置按键相应的IO口
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitKey(void)
{
  
    P0SEL &= ~0x02;     //设置P0.1为普通IO口  
    P0DIR &= ~0x02;     //按键接在P0.1口上,设P0.1为输入模式 
    P0INP &= ~0x02;     //打开P0.1上拉电阻
    
    P2SEL &= ~0x01;     //设置P2.0为普通IO口
    P2DIR &= ~0x01;     //按键接在P2.0口上,设P2.0为输入模式 
    P2INP &= ~0x01;     //打开P2.0上拉电阻
    
    P0SEL &= ~0x80;     //设置P0.7为普通IO口  
    P0DIR &= ~0x80;     //按键接在P0.7口上,设P0.7为输入模式 
    P0INP &= ~0x80;     //打开P0.7上拉电阻
  
}

/****************************************************************************
* 名    称: KeyScan()
* 功    能: 读取按键状态
* 入口参数: 无
* 出口参数: 0为抬起   1为按键按下
****************************************************************************/
uchar KeyScan_1(void)   //检测按键key1
{
    if (KEY1 == 0)
    {
        DelayMS(10);      //延时10MS去抖
        if (KEY1 == 0)
        {
            while(!KEY1); //松手检测
            return 1;     //有按键按下
        }
    }
    
    return 0;             //无按键按下
}

uchar KeyScan_2(void)   //检测按键key2
{
    if (KEY2 == 0)
    {
        DelayMS(10);      //延时10MS去抖
        if (KEY2 == 0)
        {
            while(!KEY2); //松手检测
            return 1;     //有按键按下
        }
    }
    
    return 0;             //无按键按下
}


uchar KeyScan_3(void)   //检测按键key3
{
    if (KEY3 == 0)
    {
        DelayMS(10);      //延时10MS去抖
        if (KEY3 == 0)
        {
            while(!KEY3); //松手检测
            return 1;     //有按键按下
        }
    }
    
    return 0;             //无按键按下
}

/****************************************************************************
* 程序入口函数
****************************************************************************/
void main(void)
{
    InitLed();		      //设置LED灯相应的IO口
    InitKey();                //设置按键KEY1相应的IO口
    int flow_1=1;             //初始设置
    int flow_2=0;
    int flow_3=0;
    while(1)
    {
        DelayMS(2);
        if(KeyScan_1())
        {
          flow_1=!flow_1;  
          if(flow_1==1)  //判断如果此时flow1按下,则把其余按键置零,防止干扰
            flow_2=0;
            flow_3=0;
        }
        if(KeyScan_2())  
        {
          flow_2=!flow_2; 
          if(flow_2==1)  //判断如果此时flow2按下,则把其余按键置零,防止干扰
            flow_1=0;
            flow_3=0;
        }
        if(KeyScan_3())
        {
          flow_3=!flow_3;  //判断如果此时flow2按下,则把其余按键置零,防止干扰
          if(flow_3==1)  
            flow_1=0;
            flow_2=0;
        }
        //扫描按键当前状态,按下抬起一次改变LED显示效果,在跑马灯效果从左到右,从右到左,与LED2灯闪烁效果间切换
        if (flow_1)    //依次点亮 LED1  LED2 LED3 实现跑马灯效果
        {   LED1 = ON;    //点亮LED1      
            DelayMS(500); 
            LED1 = OFF;   //熄灭LED1 
            LED2 = ON;                
            DelayMS(500); 
            LED2 = OFF;            
            LED3 = ON;           
            DelayMS(500); 
            LED3 = OFF;
        }
        if (flow_2)     //依次点亮 LED3  LED2 LED1 实现跑马灯效果  
        {   LED3 = ON;    //点亮LED1      
            DelayMS(500); 
            LED3 = OFF;   //熄灭LED1 
            LED2 = ON;                
            DelayMS(500); 
            LED2 = OFF;            
            LED1 = ON;           
            DelayMS(500); 
            LED1 = OFF;
        }               
        if (flow_3)     //依次点亮 LED2 实现亮灯是灭灯时长的2倍效果 
        {   LED2 = ON;    //点亮LED1      
            DelayMS(1000); 
            LED2 = OFF;   //熄灭LED1 
            DelayMS(500); 
        }
        
    }
}
文章来源:https://blog.csdn.net/Q52099999/article/details/135394630
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。