锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

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

时间:2023-11-15 20:07:02 s1m通用二极管

文章目录

  • 前言
  • 一、实验相关电路图
  • 二、实验相关寄存器
  • 三、源码分析


前言

本实验用于学习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为输出

Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
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操作相应的位置。

0 0 0 1 0 0 1 1

按键 S1 配置如下:

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

三、源码分析

/**************************************************************************** * 文 件 名: main.c * 描 述: 按下按键S1控制LED1.LED2.LED3实现跑马灯效果 ****************************************************************************/ #include  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);

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章