任务要求
新建IAR工程文件,完成按键控制Zigbee黑色板子上的灯及外接风扇,实现以下任务要求:
【1】程序开始运行时,板上的D4、D3、D6、D5灯亮3秒后全灭,外接的风扇停止。
【2】按键SW1单击,切换D5灯的开关状态。
【3】按键SW1双击,切换D6灯的开关状态。
【4】按键SW1三连击,切换D3灯的开关状态。
【5】按键SW1四连击,切换D4灯的开关状态。
【6】当LED灯的状态为1101时,即D5灯亮,D6灯亮,D3灯灭,D4灯亮,打开外接的风扇,否则停止风扇。
【7】按下SW2按键后,数据及风扇重置到初始上电状态。
【8】能重复实现以上步骤。
【9】需在代码中使用定时器实现以上LED灯及外接风扇的功能。
参考源码
#include "ioCC2530.h"
#define D4 P1_1
#define D3 P1_0
#define D5 P1_3
#define D6 P1_4
#define SW1 P1_2
#define SW2 P0_1
#define FS P2_0
unsigned char count_t = 0; //0.1秒间隔定时累计
unsigned char K_Num = 0; //按键连击状态记录
unsigned char LED_dat = 0; //灯光工作状态标志
unsigned char F_Start = 0; //系统工作状态标志
/*=======================简单的延时函数========================*/
void Delay(unsigned int t)
{
while(t--);
}
/*======================端口初始化函数========================*/
void Init_Port()
{
P1SEL &= ~0x1b; //P1_0、P1_1、P1_3和P1_4作为通用I/O端口
P1DIR |= 0x1b; //P1_0、P1_1、P1_3和P1_4端口输出
P1 &= ~0x1b; //关闭所有的LED灯
P1SEL &= ~0x04; //P1_2作为通用I/O端口
P1DIR &= ~0x04; //P1_2端口输入
P1INP &= ~0x04; //P1_2设置为上拉/下拉模式
P2INP &= ~0x40; //P1_2设置为上拉
P0SEL &= ~0x02; //P0_1作为通用I/O端口
P0DIR &= ~0x02; //P0_1端口输入
P0INP &= ~0x02; //P0_1设置为上拉/下拉模式
P2INP &= ~0x20; //P0_1设置为上拉
P2SEL &= ~0x01; //P2_0作为通用I/O端口
P2DIR |= 0x01; //P2_0端口输出
FS = 0;
}
/*=======================定时器1初始化========================*/
void Init_Timer1()
{
T1CC0L = 0xd4;
T1CC0H = 0x30; //16MHz时钟,128分频,定时0.1秒
T1CCTL0 |= 0x04; //开启通道0的输出比较模式
T1IE = 1; //开启定时器中断
EA = 1; //开启总中断
T1CTL = 0x0e; //分频系数是128,模模式
}
/*====================定时器1服务函数========================*/
#pragma vector = T1_VECTOR
__interrupt void Timer1_int()
{
T1STAT &= ~0x20; //清除定时器1的溢出中断标志位
if(F_Start == 1)
{
if(K_Num != 0 && SW1 != 0)
{
count_t++; //计算按键的生命周期
}
}
else
{
count_t++; //间隔定时3秒钟
if(count_t == 30)
{
count_t = 0;
F_Start = 1;
}
}
}
/*====================按键扫描处理函数========================*/
void Scan_Keys()
{
if(SW1 == 0)
{
Delay(100); //去抖动处理
if(SW1 == 0) //确认按键SW1按下
{
while(SW1 == 0); //等待按键松开
count_t = 0; //重新计算按键生命周期
K_Num++; //按键按下次数记录
}
}
if(SW2 == 0)
{
Delay(100); //去抖动处理
if(SW2 == 0) //确认按键SW2按下
{
while(SW2 == 0);
count_t = 0;
K_Num = 0;
LED_dat = 0;
D5 = 0;
D6 = 0;
D4 = 0;
D3 = 0;
}
}
if(count_t > 5) //按键生命周期结束
{
switch(K_Num)
{
case 1: //按键单击
if((LED_dat & 0x01) == 0x01)
{
D4 = 0;
LED_dat &= ~0x01;
}
else
{
D4 = 1;
LED_dat |= 0x01;
}
break;
case 2: //按键双击
if((LED_dat & 0x02) == 0x02)
{
D3 = 0;
LED_dat &= ~0x02;
}
else
{
D3 = 1;
LED_dat |= 0x02;
}
break;
case 3: //按键三连击
if((LED_dat & 0x04) == 0x04)
{
D6 = 0;
LED_dat &= ~0x04;
}
else
{
D6 = 1;
LED_dat |= 0x04;
}
break;
case 4: //按键四连击
if((LED_dat & 0x08) == 0x08)
{
D5 = 0;
LED_dat &= ~0x08;
}
else
{
D5 = 1;
LED_dat |= 0x08;
}
break;
}
K_Num = 0; //清除按键按下记录
count_t = 0; //按键生命周期清零
}
}
/*==========================主函数============================*/
void main()
{
Init_Port(); //初始化端口
Init_Timer1(); //初始化定时器1
D5 = 1;
D6 = 1;
D4 = 1;
D3 = 1;
while(F_Start == 0); //等待间隔定时3秒
D5 = 0;
D6 = 0;
D4 = 0;
D3 = 0;
while(1)
{
Scan_Keys(); //扫描按键
if(LED_dat == 0x0d) //0000 1101
{
FS = 1; //打开风扇
}
else
{
FS = 0; //停止风扇
}
}
}
该程序存在一定问题,即第一次满足上述的二进制要求时,若第二次触发该二进制涉及的LED时也会触发继电器模块。
举个例子:第一次触发0000 1101后,第二次双击按键(改变第1位后)板子上的LED灯的状态为0000 0011,继电器还会被触发。
建议:通过判断P1口输出状态可以有效防止该问题的发生!