zoukankan      html  css  js  c++  java
  • 【CC2530入门教程-02】CC2530的通用I/O端口输入和输出控制

    第2课  CC2530的通用I/O端口输入和输出控制

    XMF393 / 广东职业技术学院  欧浩源

    【视频教程】:将寄存器中某些为清0或置1

    【视频教程】:CC2530通用I/O及相关寄存器

    【视频教程】:LED灯闪烁实现的源码分析

    【视频教程】:基于CC2530的跑马灯实现

    【视频教程】:按键的工作原理与程序设计思路

    【视频教程】:按键控制LED灯开关

    【视频教程】:按键控制跑马灯的运行与暂停

    一、CC2530的引脚概述

            CC2530微控制器采用QFN40封装,有40 个引脚。其中,有21个数字I/O端口,其中P0P18 位端口P2仅有5位可以使用。这21个端口均可以通过编程进行配置。实际上,在P2端口的5个引脚中,有2个需要用作仿真,有2个需要用作晶振,你在CC2530的开发中真正能够使用的只有17个引脚

            在微控制器内部,有一些特殊功能的存储单元,这些单元用来存放控制微控制器内部器件的命令、数据或运行过程中的一些状态信息,这些寄存器统称为“特殊功能寄存器(SFR)”。操作微控制器的本质,就是对这些特殊功能寄存器进行读写操作,并且某些特殊功能寄存器可以位寻址

            每一个特殊功能寄存器本质上就是一个内存单元,而标识每个内存单元的是内存地址,不容易记忆。为了便于使用,每个特殊功能寄存器都会起一个名字,在程序设计时,只要引入头文件“ioCC2530.h”,就可以直接使用寄存器的名称访问内存地址了。

            CC2530的通用I/O端口相关的常用寄存器有下面4个:

            <1> PxSEL:端口功能选择,设置端口是通用I/O还是外设功能

            <2> PxDIR:作为通用I/O时,用来设置数据的传输方向。

            <3> PxINP:作为通用输入端口时,选择输入模式是上拉下拉还是三态

            <4> Px:数据端口,用来控制端口的输出或获取端口的输入。

    二、设置寄存器中某些位的方法

            <1> 对寄存器的某些位清0而不影响其他位。

            例如:寄存器P1TM的当前值是0x6c,现需要将该寄存器的第1位、第3 位和第5位设置为0,同时不能影响该寄存器其他位的值,那么,在C语言中应该怎么编写代码呢?

            使用“&=”将寄存器指定位清0,同时不影响其他位的值。

            正确写法:P1TM &= ~0x2A;

            因为:逻辑“与”操作的特点是,该位有0结果就为0,若为1则保存原来值不变。

            首先将字节 0000 0000要操作的位设置为1,即0010 1010,在将该数值取反,即1101 0101,也就是~0x2A。再将该值与寄存器P1TM“相与”,那么有0的位,即1、3、5位将被清0,其余的位会保持原来的值不变。

            所以:P1TM的当前值为0x6c,即0110 1100,

            0110 1100 && 1101 0101 = 0100 0100,即1、3、5位清0,其他位不变。

            <注意>:该方法只能操作多位同时清0,或者某一位清0的情况,如果要将寄存器的位既要清0又要置1,则不能采用这种写法。(其中原因自己思考一下)

            在不少嵌入式应用的源码程序中,对于寄存器的第n位的清0操作也可以写成:寄存器 &= ~(0x01<<(n));其道理是一样的。

            <2> 对寄存器的某些位置1而不影响其他位。

            例如:寄存器P1TM的当前值是0x6c,现需要将该寄存器的第1位、第4位和第5位设置为1,同时不能影响该寄存器其他位的值,那么,在C语言中应该怎么编写代码呢?

            使用“|=”将寄存器指定位置1,同时不影响其他位的值。

            正确写法:P1TM |= 0x32;

            因为:逻辑“或”操作的特点是,该位有1结果就为1,若为0则保存原来值不变。

            首先将字节 0000 0000 要操作的位设置为1,即0011 0010,也就是0x32。 再将该值与寄存器P1TM“相或”,那个有1的位,即1、4、5位将被设置为1,其余的位会保持原来的值不变。

            所以:P1TM的当前值为0x6c,即0110 1100,

            0110 1100 || 0011 0010 = 0111 1110,即1、4、5位置1,其他位不变。

            同样要注意:该方法只能操作多位同时置1,或者某一位置1的情况。

            对于寄存器的第n位的清0操作也可以写成:寄存 |= (0x01<<(n));

    三、实训案例:按键输入控制灯光输出状态

    【1】准备工作。

    引入CC2530必要的头文件“ioCC2530.h”,定义相关变量等。

    【2】端口功能选择。

            微控制器的大部分I/O端口都是功能复用的,在使用的时候需要通过功能选择寄存器来配置端口的功能。

    【3】端口传输方向设置。

    【4】对于输入的端口要设置其输入方式。

            输入方式用来从外界器件获取输入的电信号,当CC2530的引脚为输入端口时,该端口能够提供“上拉”、“下拉”和“三态”三种输入模式,可以通过编程进行设置。在本次实训中,实际上不需要对P0_1和P1_2引脚进行输入方式的设置,因为CC2530复位后,各个I/O端口默认使用的就是上拉模式。

    【5】通用I/O端口寄存器配置的基本思路。

    【6】设计端口初始化函数InitPort()。

            <1>设置P1SEL寄存器,将P1_2、P1_3和P1_4设置为通用I/O端口。

            <2>设置P1DIR寄存器,将P1_3和P1_4设置为输出,将P1_2设置为输入。

            <3>设置P0SEL寄存器,将P0_1设置为通用I/O端口。

            <4>设置P0DIR寄存器,将P0_1设置为输入。

            <5>设置PxINP寄存器,将P0_1和P1_2设置为上拉模式,也可以不设置。

    【7】设计键盘扫描函数ScanKeys()。

            <1>没有按键下时,端口的输入为高电平,当发现该端口有低电平产生时,则有可能会是按键按下,需要经过去抖动处理,如果该端口还是低电平,则确认为按键按下。

            <2>在进行按键处理时,先等待按键松开,然后再将相关的LED进行开关状态的取反控制。

    【8】主函数的实现

    至此,大功搞成,连接仿真器,进行编译调试。

    【附件】:本实训源代码。

    #include "ioCC2530.h"
    
    #define LED5 P1_3
    #define LED6 P1_4
    #define SW1 P1_2
    #define SW2 P0_1
    /*===================延时函数=========================*/
    void Delay(unsigned int t)
    {
      while(t--);
    }
    /*================端口初始化函数======================*/
    void InitPort()
    {
      P1SEL &= ~0x18;         //将P1_3和P1_4设置为通用I/O端口功能
      P1DIR |= 0x18;          //将P1_3和P1_4的端口传输方式设置为输出
      P1SEL &= ~0x04;         //将P1_2设置为通用I/O端口功能
      P1DIR &= ~0x04;         //将P1_2的端口传输方式设置为输入
      P0SEL &= ~0x02;         //将P0_1设置为通用I/O端口功能
      P0DIR &= ~0x02;         //将P0_1的端口传输方式设置为输入
      P0INP &= ~0x02;         //将P0_1的端口输入方式设置为:上拉/下拉
      P1INP &= ~0x04;         //将P1_2的端口输入方式设置为:上拉/下拉
      P2INP &= ~0x60;         //将P0端口和P1端口引脚设置为:上拉
      LED5 = 0;               //上电的时候,LED5不亮
      LED6 = 0;               //上电的时候,LED6不亮
    }
    /*=================按键扫描函数=======================*/
    void ScanKeys()
    {
      if(SW1 == 0)
      {                       //发现SW1有低电平信号
        Delay(100);           //按键去抖动
        if(SW1 == 0)
        {                      //确实是有按键动作
          while(SW1 == 0);    //等待按键1松开
          //将LED5的灯光开关状态取反
          LED5 = ~LED5;
      }
      if(SW2 == 0)
      {                       //发现SW2有低电平信号
        Delay(100);           //按键去抖动
        if(SW2 == 0)
        {                     //确实是有按键动作
          while(SW2 == 0);    //等待按键2松开
          LED6 = ~LED6;
        }
      }
    }
    /*=====================主函数=========================*/
    void main()
    {
      InitPort();
      while(1)
      {
        ScanKeys();
      }
    }

     

  • 相关阅读:
    小Z的袜子
    C#操作XML
    C#中接口的实现方法
    C#邮箱批量注册
    C# 委托的使用
    C# socket
    在C#.net中如何操作XML
    C#接口的基础知识
    C#判断网页中是否含有某字符串
    C#多线程处理多个队列的数据
  • 原文地址:https://www.cnblogs.com/ALittleBee/p/7063814.html
Copyright © 2011-2022 走看看