题目
新建 IAR 工程文件,完成按键控制 Zigbee 单片机上的 LED 的亮灭功能,模拟酒店楼道灯的控制效果,考核选手 ZigBee 单片机基础知识的掌握。具体任务要求如下:
- 程序开始运行; D4 灯闪烁,D3、D5、D6 灯灭;
- 按下模块上的“SW1”键松开后,实现 D5、D6 灯亮 2 秒后自动熄灭(期间再次按下后,顺延亮);
- 重复上述第二个步骤。
补充说明: - 在这块 ZigBee 板的小辣椒上贴上题号(如:任务三第 1 题则写题 1), 将这块ZigBee 板 装在答题区上 ,接上电源,待裁判评判。
- 参赛选手打开“竞赛资料\任务 3\ ZigBee 模块板硬件原理图.pdf 文档”进行参考。
- ZigBee 模块板所采用的芯片为 TI CC2530F256 芯片,头文件为 “ioCC2530.h”
- 寄存器描述 如下表所示。
寄存器 | 功能 | 位 | 描述 |
---|---|---|---|
P1SEL (0XF4) | 功能选择 | 7:0 | P1.7到P1.0功能选择 0:通用I/O 1:外设功能 |
P1DIR (0XFE) | 端口方向 | 7:0 | P1.7 到 P1.0 的 I/O 口方向 0:输入 1:输出 |
解题思路
IAR新建工程并配置。
好多同学不明白顺延亮是什么意思,我的理解是类比电梯门:
- 进入电梯之后没人去按开门键2秒后电梯门就会自动关闭。
- 如果突然有人要上电梯里面的人需要按一下开门键让电梯门顺延关闭,也就是电梯门打开重新计时2秒后关闭。
- 如果你在电梯里等人,需要一直按下开门键让电梯门一直开着,直到你等的那个人上电梯之后松开电梯开门键,松开按键之后电梯门才会计时2秒后关闭。
代码
//-------------------------------------------------------------------
// 库文件
//-------------------------------------------------------------------
#include "ioCC2530.h"
//-------------------------------------------------------------------
// 常 量
//-------------------------------------------------------------------
#define D4 (P1_1)
#define D3 (P1_0)
#define D6 (P1_4)
#define D5 (P1_3)
#define SW1 (P1_2)
//-------------------------------------------------------------------
// 变 量
//-------------------------------------------------------------------
unsigned char flag200ms = 0; // 定时200ms标志位 用于D4闪烁
unsigned char flag2s = 0; // 定时2s标志位 用于D5、D6熄灭
unsigned char keySta = 1; // 按键状态
unsigned char lightPeriod = 0; // 亮灯期间
unsigned char putoffPeriod = 0; // 顺延期间
//-------------------------------------------------------------------
// 函 数
//-------------------------------------------------------------------
void halTimer1Config(unsigned int ms);
void halKeyScan();
void halKeyDirver();
void LeD56Light();
void putoffLight();
//-------------------------------------------------------------------
// 函数名 halTimer1Config
//
// 简 述 定时器1设置周期
//
// 参 数 ms(1~500ms)
//
// 返回值 无
//-------------------------------------------------------------------
void halTimer1Config(unsigned int ms)
{
unsigned long compare_up; // 临时变量 向上比较
compare_up = 16000000 / 128; // 时钟频率 16MHZ / 128分频
// s(定时时间) / T(时钟周期) = k(最大计数值)
// 1 / f(时钟频率) = T(时钟周期)
// s(定时时间) * f(时钟频率) / = k(最大计数值)
compare_up = (compare_up * ms) / 1000; // ms / 1000 * f = k
// cmpare_up = 65536 - cmpare_up; // 51单片机算法
T1CC0L = (unsigned char)(compare_up); // 定时器1通道0捕获/比较值低位
T1CC0H = (unsigned char)(compare_up >> 8); // 定时器1通道0捕获/比较值高位
T1CCTL0 |= 0X04; // 定时器1通道0比较模式
T1CTL |= (0X0C)|(0X02); // 定时器1 128分频 模模式
T1IE = 1; // IEN1.1/T1IE 定时器1中断使能
}
//-------------------------------------------------------------------
// 函数名 halKeyScan
//
// 简 述 按键SW1扫描消抖 8次扫描
//
// 参 数 无
//
// 返回值 无
//-------------------------------------------------------------------
void halKeyScan()
{
static unsigned char keybuf = 0xff; // 缓存
keybuf = (keybuf << 1) | SW1;
if(keybuf == 0x00)
keySta = 0;
else if( keybuf == 0xff )
keySta = 1;
else
{}
}
//-------------------------------------------------------------------
// 函数名 halKeyDriver
//
// 简 述 按键驱动函数 分配按键动作
//
// 参 数 无
//
// 返回值 无
//-------------------------------------------------------------------
void halKeyDriver()
{
static unsigned char backup = 1; // 按键上次状态
if( lightPeriod == 1 )
{
if( keySta == 0 )
{
putoffLight(); // 亮灯期间按下按键 顺延亮
}
else
{
putoffPeriod = 0; // 按键弹起顺延期间结束 计时2s后熄灭LED
}
}
else
{
if( backup != keySta )
{
if( keySta == 1 )
{
LeD56Light(); // 没有亮灯时按下点亮LeD56 进入亮灯期间
}
backup = keySta; // 保存按键状态
}
}
}
//-------------------------------------------------------------------
// 函数名 Led56Light
//
// 简 述 按键动作点亮LeD56进入亮灯期间
//
// 参 数 无
//
// 返回值 无
//-------------------------------------------------------------------
void LeD56Light()
{
D5 = 1;
D6 = 1;
lightPeriod = 1; // 亮灯期间ing..
}
//-------------------------------------------------------------------
// 函数名 putoffLight
//
// 简 述 按键动作 顺延亮 进入顺延期间
//
// 参 数 无
//
// 返回值 无
//-------------------------------------------------------------------
void putoffLight()
{
D5 = 1;
D6 = 1;
putoffPeriod = 1; // 顺延期间ing..
}
//-------------------------------------------------------------------
// 函数名 main
//
// 简 述 主函数
//
// 参 数 无
//
// 返回值 无
//-------------------------------------------------------------------
void main(void)
{
// LED与引脚对应关系
// LED1 == D4 == P1_1
// LED2 == D3 == P1_0
// LED3 == D6 == P1_4
// LED4 == D5 == P1_3
// P1SEL复位值0x00 默认为通用I/O口所以省略
// 设置D4、D5、D6 通用输出 D3没用到
P1DIR |= (1<<1)|(1<<4)|(1<<3);
//程序开始运行:D4灯闪烁 D6、D5灯灭,D3没有设置不会亮
D6 = 0;D5 = 0;
halTimer1Config(10); // 设置定时器1定时10ms
EA = 1; // 开启总中断
while(1)
{
halKeyDriver(); // 按键驱动函数
// 满足题意 运行时D4灯闪烁 间隔200ms(自定义)
if( flag200ms == 1 )
{
flag200ms = 0;
D4 = ~D4;
}
// 亮灯期间 2s时间到 关灯
if( lightPeriod == 1 && flag2s == 1 )
{
flag2s = 0;
D6 = 0;
D5 = 0;
lightPeriod = 0;
}
}
}
#pragma vector = T1_VECTOR
__interrupt void T1_ISR(void)
{
static unsigned char tmr200ms = 0;
static unsigned char tmr2s = 0;
tmr200ms++;
if( tmr200ms >= 20 )
{
tmr200ms = 0;
flag200ms = 1;
if( lightPeriod == 1 && putoffPeriod == 0 ) // 在亮灯期间 并且 没有在顺延期间开始2s计时
{
tmr2s++;
if(tmr2s >= 10)
{
tmr2s = 0;
flag2s = 1;
}
}
else
{
tmr2s = 0;
}
}
halKeyScan(); // 按键扫描
}
//-------------------------------------------------------------------
// 作 者 : MCU-51王
// 修改日期 : 2019年9月4日 10:43:05
//-------------------------------------------------------------------
顺延流程图
画的不是很好大概是这个意思 ?