/************************************************************
FileName: main.c
Author:
Version: v0.0
Date: 2016/4/26
Description: 扫描检测按键,读取键值,通过曼彻斯特编码将键值发送给X5钥匙主板
History:
<author> <time> <version > <desc>
***********************************************************/
#include <SI_EFM8UB1_Defs.h>
#include <main.h>
uint8_t gBufNum = 0; //曼码buf的具体哪个位
uint8_t gBitPart = FIRST_PART; //判断是发送的bit位的第一部分,还是第二部分
uint8_t idata gManBuf[64]; //曼码buf,包括9个同步头,一共64个位
//例如设置为如下值
//{1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1,
// 1,1,1,0,0,0,1,1,0,1,1,1,0,0,1,0,1,0,0,0,0,0,1,1,0,1,1,0,1,1,0,0};
/************************************************************
Function: main
Description: 检测按键,填充曼码发送buf(同步头+键值+校验等),出错处理等
Input: null
Output: null
Return: null
Others:
************************************************************/
void main(void)
{
uint8_t FinalBtnVal[2] = {0,0}; //最终的按键值,是循环5次读值的稳定结果
uint8_t LastFinalBtnVal[2] = {0,0}; //上次的最终按键值
uint8_t tmp_btn_val[2] = {0,0}; //记录按键值,用于确定钥匙已经拔出
uint8_t flag = 0;
uint8_t tmp_btn_flg = TRUE; //按键标记,用于循环20次检查钥匙是否拔出。如果为ERR,则说明钥匙不是真的拔出,只是抖动而已
uint8_t SendFlag = FAULSE; //当按键检测到正确不为0的按键时,发送曼码,此标记置位。当钥匙拔出,关闭曼码发送,此标记设为FAULSE
uint8_t i = 0;
uint8_t j = 0;
//初始化
InitHardWare();
while(1)
{
//喂狗
WDTCN = 0xA5;
//检测按键
LastFinalBtnVal[0] = FinalBtnVal[0];
LastFinalBtnVal[1] = FinalBtnVal[1];
flag = DetectBtn(FinalBtnVal);
if(RIGHT_VALUE == flag)
{
//如果按键值变化,需要重新设置曼码的buf,如果值不变,就一直用timer中断发送之前的值
if((LastFinalBtnVal[0] != FinalBtnVal[0]) || (LastFinalBtnVal[1] != FinalBtnVal[1]))
{
//关中断,停定时器
IE_ET1 = 0;
IE_EA = 0;
TCON_TR1 = 0;
//设置曼码的buf
SetManBuf(FinalBtnVal,gManBuf);
//延时一会,让timer上次发的那一帧作废
DelayNms(4);
//设置参数让timer从头开始发送
gBufNum = 0;
gBitPart = FIRST_PART;
TL1 = TIM_RLL_VAL & 0x00FF;
TH1 = TIM_RLL_VAL >> 0x80;
//开timer中断,开定时器,开始发送曼码
IE_ET1 = 1;
IE_EA = 1;
TCON_TR1 = 1;
SendFlag = TRUE;
}
}
else if(NO_BTN == flag) //没有按键按下
{
if(SendFlag == TRUE)
{
tmp_btn_flg = TRUE;
for(i=0;i<20;i++)
{
ReadBtn(tmp_btn_val);
//判断是否都为0
if((0xb0 == tmp_btn_val[0])&&(0xb0 == tmp_btn_val[1]))
{
DelayNms(10); //延时10ms,继续下次扫描,直到20次扫描完成
}
else
{
tmp_btn_flg = FAULSE; //键值抖动了,说明钥匙不是真的拔出了
break;
}
}
if(tmp_btn_flg == TRUE) //钥匙确定已经拔出,关闭中断,停止发送曼码,如果不为true,说明只是抖动,继续发送之前的曼码
{
//关timer中断
IE_ET1 = 0;
IE_EA = 0;
TCON_TR1 = 0;
//清曼码的buf
for(i=0;i<64;i++)
{
gManBuf[i] = 0;
}
FinalBtnVal[0] = 0; //把值清零
FinalBtnVal[1] = 0;
SendFlag = FAULSE;
}
}
}
else //ERR == flag,检测到抖动的按键值,丢弃这些值,还是继续发送之前的正确值。
{
}
}
}
/************************************************************
Function: InitWdt
Description: 看门狗的设置
************************************************************/
void InitWdt(void)
{
//设置LFOSC0的频率,DIV=8,所以 频率为80KHz/8 = 10KHz,使能LFOSC0
LFO0CN = 0x80;
//等待LFOSC0时钟稳定
while((LFO0CN & 0x40) == 0);
//设置WDT的时间间隔为4^8/10000 = 6.5536s,并使能WDT
WDTCN = 0x05;
WDTCN = 0xA5;
/*
//Disable Watchdog with key sequence
WDTCN = 0xDE; //First key
WDTCN = 0xAD; //Second key
*/
}
/************************************************************
Function: InitClk
Description: 时钟初始化
************************************************************/
void InitClk(void)
{
//设置时钟分频为DIV_4,时钟源为HFOSC1,预分频为1.5,则SYSCLK = 48/1.5/4=8MHz
CLKSEL = 0x27;
CLKSEL = 0x27; //写两次
while((CLKSEL&0x80) == 0); //等待时钟稳定
}
/************************************************************
Function: InitGpio
Description: io口初始化
************************************************************/
void InitGpio(void)
{
XBR0 = 0;
XBR1 = 0;
XBR2 = 0X40;
P0MDIN = 0xFF; //GPIO0 设为数字输入口
P0MDOUT = 0x00; //GPIO0 设为开集电极输出
P0SKIP = 0XFF;
P1MDOUT = 0x3; //GPIO1 设为push-pull
P1MDIN = 0xFF;
/*
//测试pin脚使用
P0MDOUT = 0xFF;
P1MDOUT = 0x0; //GPIO1 设为push-pull
//P1MDIN = 0xFF;
P0 = 0x55;
P1 = 0x00;
P0 = 0xaa;
P1 = 0x07;
*/
}
/************************************************************
Function: InitTimer1
Description: 定时器1初始化
************************************************************/
void InitTimer1(void)
{
CKCON0 = 0xFF; //设置timer1的时钟源为 sysclk
TCON = 0x00; //关闭timer
TMOD = 0x11; //16BIT工作模式
TL1 = TIM_RLL_VAL & 0x00FF;
TH1 = TIM_RLL_VAL >> 8;
IE = 0;
}
/************************************************************
Function: InitHardWare
Description: 硬件初始化
************************************************************/
void InitHardWare(void)
{
InitWdt();
InitClk();
InitGpio();
InitTimer1();
}
/************************************************************
Function: DetectBtn
Description: 检测按键
Input: null
Output: *pBtnVal:确认按键无误后,将按键的键值处理后赋值给 *pBtnVal
Return: BtnFlag: 按键检测的标记,指示是否正确检测到按键
Others:
************************************************************/
uint8_t DetectBtn(uint8_t *pBtnVal)
{
uint8_t CurBtnVal[2] = {0,0};
static uint8_t sLastBtnVal[2] = {0xb0,0xb0};
uint8_t BtnFlag = NO_BTN; //BtnFlag检测有按键且无错误,返回RIGHT_VALUE,
//无按键无错误,返回NO_BTN,有按键有错误,返回ERR
uint8_t i = 0;
uint8_t tmp = 0;
//读取按键
ReadBtn(CurBtnVal);
if((0xb0 != CurBtnVal[0]) || (0xb0 != CurBtnVal[1])) //有按键输入
{
//BtnFlag = NO_ERR; //清错误标记位
//循环5次读取键值,如果都一致,说明按键稳定
for(i=0;i<25;i++)
{
sLastBtnVal[0] = CurBtnVal[0];
sLastBtnVal[1] = CurBtnVal[1];
ReadBtn(CurBtnVal);
//判断是否和上次读到的值一样,
if((sLastBtnVal[0] == CurBtnVal[0])&&(sLastBtnVal[1] == CurBtnVal[1]))
{
DelayNms(10); //延时10ms,继续下次扫描,直到20次扫描完成