文章目录
- 前言
- 一、实验相关电路图
- 二、实验相关寄存器
- 三、源码分析
前言
本实验用于学习CC2530芯片GPIO 配置方法,Led 驱动电路及开关 Led 使用按键的原理,实现简单的人机交互。
一、实验相关电路图
由于发光二级管的单向导电性,即只有在正电压(二极管正负负)下才能导致发光。 P1.0、P1.1、P1.4 引脚输出低电平 LED 亮,引脚输出亮电平 LED 熄灭,当 引脚(P0_1 )低电通常表示按钮被按下,高电通常处于提升状态。
二、实验相关寄存器
由于P0、P1.配置方法相同,只列出P1寄存器相关信息:
寄存器 |
|
|
---|---|---|
P1 (0x90) | 端口 1 | 端口 1。通用 I / O 端口。可以从 SFR 位寻址。 |
P1SEL(0xF4) | 端口 1 功能选择 | P1.7 到 P1.0 的功能选择0: 通用 I / O1: 外设功能 |
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 <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语句的原型是while(表达式),当表达式为非0值时,执行while语句中的嵌套语句,while(1)则一直执行嵌套语句,代码不再向下执行。
在单片机中使用while(1),大部分情况是为了防止程序跑飞。因为很多时候执行完某段程序后,单片机的程序指针PC并不会停止,仍然会从ROM中读取指令来执行,从而出现不确定的结果,加个while(1)就能让程序在执行完后在原地循环,防止跑飞。 调试代码时,为了检测一部分代码是否OK,防止后面的代码干扰执行结果,也会在观测点加上while(1);