CC2530基础实验:(1)按键控制LED跑马灯


前言

本实验用于学习CC2530芯片GPIO 的配置方法,Led 驱动电路及开关 Led 的原理,按键的使用,实现简单的人机交互。


一、实验相关电路图

在这里插入图片描述
由于发光二级管单向导电性,即只有在正向电压(二极管的正极接正,负极接负)下才能导通发光。所以 P1.0、P1.1、P1.4 引脚输出低电平 LED 亮,引脚输出亮电平 LED 熄灭,当 引脚(P0_1 )为低电平时说明按键被按下,高电平时为抬起状态。

TI官方的开发板是高电平点亮LED,但实验板子是低电平亮,更符合国人习惯。

二、实验相关寄存器

由于P0、P1配置方法相同,所以只列出P1寄存器的相关信息:

寄存器
作用
描述
P1 (0x90)端口 1端口 1。通用 I / O 端口。可以从 SFR 位寻址。
P1SEL(0xF4)端口 1 功能选择P1.7 到 P1.0 的功能选择
0: 通用 I / O
1: 外设功能
P1DIR(0xFE)端口 1 方向P1.7 到 P1.0 的 I/O 方向
0: 输入
1: 输出
P1INP(0xF6)端口 1 输入模式P1.7 到 P1.2 的 I/O 输入模式。由于 P1.0 和 P1.1 没有上拉/下拉功能,,P1INP 暂时不需要配置,了解一下为后面的实验打下基础
0: 上拉/下拉(见 P2INP (0xF7)–端口 2 输入模式)
1: 三态

按照表格寄存器的内容,对 P1.0、P1.1、P1.4 口进行配置,简化配置指令如下:

P1DIR |= 0x13; // P1.0、P1.1、P1.4 定义为输出,只改变最低位的值而不影响其他位

嵌入式中位运算只修改要修改的位,不要影响到其他位,否则在基础实验中功能单一,感觉不出来,如果在协议栈中就有严重问题了。

P1DIR赋值的对应关系:P1DIR(P1 Direction)是P1口方向控制寄存器,给它赋值就是改变P1对应位的状态
P1DIR(P0DIR相同):设置各个I/O口方向,0为输入,1为输出

Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
P1.7方向P1.6方向P1.5方向P1.4方向P1.3方向P1.2方向P1.1方向P1.0方向

举例:P1DIR |= 0x13;转换成二进制为 0001 0011
也就是让bit0、bit1、bit4设置为1,状态为输出。把开发板P1端口上的P1.0、P1.1、P1.4为输出。即改变哪个IO就操作其对应的位。

00010011

按键 S1 配置如下:

P0SEL &= ~0x02; //设置 P0.1 为普通 IO 口
P0DIR &= ~0x02; //按键接在 P0.1 口上,设 P0.1 为输入模式
P0INP &= ~0x02; //打开 P0.1 上拉电阻

三、源码分析

/****************************************************************************
* 文 件 名: main.c
* 描    述: 按下按键S1控制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口为S1控制端
#define ON      0
#define OFF     1

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

//点亮或熄灭所有LED灯:mode为0时LED灯亮  mode为1时LED灯灭
void LedOnOrOff(uchar mode) 
{
    LED1 = mode;
    LED2 = mode;
    LED3 = mode; //由于P1.4与仿真器共用,必须拔掉仿真器的插头才能看到LED3的变化
}

// 设置LED相应的IO口
void InitLed(void)  
{
    P1DIR |= 0x13;  // P1.0、P1.1、P1.4定义为输出
    LedOnOrOff(1);  // 使所有LED灯默认为熄灭状态  
}

//设置按键相应的IO口
void InitKey(void)      
{
    P0SEL &= ~0x02;     //设置P0.1为普通IO口  
    P0DIR &= ~0x02;     //按键接在P0.1口上,设P0.1为输入模式 
    P0INP &= ~0x02;     //打开P0.1上拉电阻
}

//读取按键状态,0为抬起 1为按键按下
uchar KeyScan(void) 
{
    if (KEY1 == 0)
    {
        DelayMS(10);      //延时10MS去抖
        if (KEY1 == 0)
        {
            while(!KEY1); //松手检测
            return 1;     //有按键按下
        }
    }
    return 0;             //无按键按下
}

//程序入口函数
void main(void)           
{
    InitLed();		      //设置LED灯相应的IO口
    InitKey();            //设置按键S1相应的IO口
    while(1)
    {
        DelayMS(2);
        if (KeyScan())    //扫描按键当前状态,按下时执行跑马灯效果
        {
            LED1 = ON;    //点亮LED1      
            DelayMS(500); 
            LED1 = OFF;   //熄灭LED1 
            LED2 = ON;                
            DelayMS(500); 
            LED2 = OFF;            
            LED3 = ON;           
            DelayMS(500); 
            LED3 = OFF; 
        }
    }
}


为什么单片机编程要尽量使用无符号类型的数据?
主要原因:多数情况下不需要用到负数,而单片机内存有限,用无符号类型的数据可以节省内存。

char型可以表示数的范围是-128到127,所占位数是8位
int型可以表示数的范围是-32768到32767,所占位数是16位
假如用有符号的数据类型表示,如果要表示的数是128,那就需要定义int型,用了16位。
unsigned char型可以表示数的范围是0到255,所占位数是8位
int型可以表示数的范围是0到65535,所占位数是16位
假如用无符号的数据类型表示,如果要表示的数是128,那就定义unsigned char型就可以了,只用了8位。

while(1)的作用
while语句的原型是while(表达式),当表达式为非0值时,执行while语句中的嵌套语句,while(1)则一直执行嵌套语句,代码不再向下执行。

在单片机中使用while(1),大部分情况是为了防止程序跑飞。因为很多时候执行完某段程序后,单片机的程序指针PC并不会停止,仍然会从ROM中读取指令来执行,从而出现不确定的结果,加个while(1)就能让程序在执行完后在原地循环,防止跑飞。
调试代码时,为了检测一部分代码是否OK,防止后面的代码干扰执行结果,也会在观测点加上while(1);

  • 12
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值