1、单纯亮个灯
2、按键点灯
3、中断点灯
一、单纯的亮个灯
首先找到你的zigbee板子的原理图,找到led灯对应的接口。
在这里我想点亮灯D1和D2,可以看到灯D1和D2对应的接口是P1_0和P1_1
我们可以在cc2530的中文手册中找到端口P1的相关设置
首先P0、P1、P2都是可以用作通用IO口也可以用作外设IO口,具体的选择跟上图是一样的。
PxSEL选择IO是通用还是外设
PxDIR选择是输入还是输出
PxINP设置上拉。要注意P1.0和P1.1没有上拉下拉功能,在这里可以不用设置。
#include <ioCC2530.h>
#define LED1 P1_0 //定义P1.0口为LED1控制端
#define LED2 P1_1 //定义P1.1口为LED2控制端
/**LED口初始化**/
void InitLed(void)
{
P1SEL &= ~0x03; //设置为通用IO口
P1DIR |= 0x03; //0000 0011 P1.0,P1.1口定义为输出,
LED1 = 1;
LED2 = 1; //灯的默认状态为熄灭状态
}
void main(void)
{
//初始化
InitLed();
while(1)
{
LED1 = 0;
LED2 = 0;
}
}
之所以设定 P1SEL &= ~0x03; P1DIR |= 0x03; 是为了避免对端口其他位置的改变
&按位或 全1为1
P1SEL & 1111 1100(~0000 0011) 最后两位为0,在或运算下,最后两位的值是不会改变的。如果其他位有改变,也不会有影响。
|按位与 有1为1
同理 P1DIR | 0000 0011 最后两位为1,在与运算下,最后两位的值不会改变。
如果要设置流水灯,那么挨个亮灭就可以了
#include <ioCC2530.h>
#define LED1 P1_0 //定义P1.0口为LED1控制端
#define LED2 P1_1 //定义P1.1口为LED2控制端
/**延时函数**/
void Delayms(int ms)
{
int i,j;
for(i = 0;i < ms;i++){
for(j = 0;j < 535;j++);
}
}
/**LED口初始化**/
void InitLed(void)
{
P1SEL &= ~0x03; //设置为通用IO口
P1DIR |= 0x03; //0000 0011 P1.0,P1.1口定义为输出,
LED1 = 1;
LED2 = 1; //灯的默认状态为熄灭状态
}
void main(void)
{
//初始化
InitLed();
while(1)
{
LED1 = ~LED1;
Delayms(500);
LED1 = ~LED1;
LED2 = ~LED2;
Delayms(500);
LED2 = ~LED2;
}
}
大概最后的效果是D1亮一下灭了然后D2再亮一下灭这样循环。
二、按键点灯
同样是上图
想形成的效果是按一下S1灯开,再按一下灯关。
在这里按键S1的连接端口为P0_1 这个端口有上拉电阻的功能,所以这里要设置P0INP
#include <ioCC2530.h>
#define LED1 P1_0 //定义P1.0口为LED1控制端
#define LED2 P1_1 //定义P1.1口为LED2控制端
#define KEY P0_1 //定义P0.1为按键S1控制端
/**延时函数**/
void Delayms(int ms)
{
int i,j;
for(i = 0;i < ms;i++){
for(j = 0;j < 535;j++);
}
}
/**LED口初始化**/
void InitLed(void)
{
P1SEL &= ~0x03; //设置为通用IO口
P1DIR |= 0x03; //0000 0011 P1.0,P1.1口定义为输出,
LED1 = 1;
LED2 = 1; //灯的默认状态为熄灭状态
}
/**按键初始化**/
void KeyInit(void)
{
P0SEL &= ~0x02; //设置P0.1为普通IO口 0000 0010
P0DIR &= ~0x02; //设置P0.1为输入模式
P0INP &= ~0x02; //打开上拉电阻
}
/**读取按键状态,KEY=0表示按键被按下,KEY=1表示按键抬起**/
int KeyScan(void)
{
if(KEY == 0){
Delayms(10);
if(KEY == 0){
while(!KEY){
return 1;
}
}
}
return 0;
}
void main(void)
{
//初始化
InitLed();
KeyInit();
while(1)
{
if(KeyScan())
{
LED1 = ~LED1;
LED2 = ~LED2;
}
}
}
这个代码IAR单步运行调试的时候是显示是对的,全速运行的时候有的时候按下会亮有的时候不会,不知道是代码逻辑问题还是哪里我没注意到的问题。
三、中断点灯
首先这里关于中断有几个概念。
中断向量:中断服务程序的入口地址。每个中断源都对应一个固定的入口地址。当内核响应中断请求时,就会暂停当前的程序执行,然后跳转到该入口地址执行代码。
中断服务函数: 内核响应中断后执行的相应处理程序。
CPU 有 18 个中断源。每个中断源都有它自己的位于一系列 SFR 寄存器中的中断请求标志。相应标志位请求的每个中断可以分别使能或禁用。
表2-5
大概意思就是,我请求一个中断,这个中断作用在某个端口,在这里,我是按下S1的按键后请求一个中断,这个中断响应在灯的P0口。而在中断源会有设置中断屏蔽,如果P0要响应就得开相应的设置。
注意一定要清楚中断标志,不然就会一直中断。
/******通过按键S1产生外部中断改变LED1状态******/
#include <ioCC2530.h>
#define LED1 P1_0
#define KEY1 P0_1
/**延时函数**/
void Delayms(int ms)
{
for(int i = 0;i < ms;i++){
for(int j = 0;j < 535;j++);
}
}
/**灯初始化**/
void InitLed(void)
{
P1DIR |= 0x01; //定义为输出口
LED1 = 1; //LED1默认熄灭
}
/**按键初始化**/
void InitKey()
{
P0IEN |= 0x2; //P0.1设置为中断方式1
PICTL |= 0x1; //下降沿触发
IEN1 |= 0x20; //允许P0口中断
P0IFG = 0x00; //初始化中断标志位
EA = 1; //打开总中断
}
/**中断函数**/
#pragma vector = P0INT_VECTOR
__interrupt void PA(void)
{
Delayms(10); //消抖
LED1 = ~LED1;
P0IFG = 0; //清理中断标志
P0IF = 0; //要清理中断标志位不然一直一直中断
}
/**主函数**/
void main(void)
{
InitLed();
InitKey();
while(1){
}
}
小声bb一个我容易混乱的点
因为这里大多都是字节运算 八位的顺序是从右往左为0~7
意思就是 76543210 0位是最右边是端口上的0位比如P1_0