/*
-----------------------------------------------------------------------------------------
工程:
Test系列工程
环境:
AVR Studio4.17 + WinAVR2010
设备:
Atmega16
作者:
遥远的海
日期:
2015-06-26
说明:
输入捕获之红外解码
-----------------------------------------------------------------------------------------
*/
//---------------------------
//数据类型
//---------------------------
typedef unsigned char U8; //定义8位无符号数
typedef signed char S8; //定义8位有符号数
typedef unsigned int U16; //定义16位无符号数
typedef signed int S16; //定义16位有符号数
typedef unsigned long U32; //定义32位无符号数
typedef signed long S32; //定义32位有符号数
typedef unsigned char * PU8; //定义8位无符号指针
typedef signed char * PS8; //定义8位有符号指针
//---------------------------
//空指令
//---------------------------
#define NOP() __asm("nop") //C 语言中内嵌汇编空指令,起到延时一个指令周期的作用
//---------------------------
//调试用LED 占用PD7(21)脚
//---------------------------
#define LED_BIT 0x80
#define LED_Init() DDRD |= LED_BIT //配置 PD7 口为输出
#define LED_OFF() PORTD&=~LED_BIT //PD7 低电平 LED 灭
#define LED_ON() PORTD|= LED_BIT //PD7 高电平 LED 亮
//---------------------------
//蜂鸣器 占用 PC7 (29) 脚
//---------------------------
#define BEEP_BIT 0x80 //1<
#define BEEP_Init() DDRC |= BEEP_BIT //配置 PD6 口为输出
#define BEEP_OFF() PORTC|= BEEP_BIT //PD6 高电平 蜂鸣器不响
#define BEEP_ON() PORTC&=~BEEP_BIT //PD6 低电平 蜂鸣器响
//---------------------------
//总中断
//---------------------------
#define EN_INT() sei() //开中断
#define DS_INT() cli() //关中断
//------------------------------------------
//红外解码部分
//------------------------------------------
#define NEC_BTN_NONE 0xFF //无按钮被按下
volatile U8 m_ucBtnCode; //控制码
/*
-----------------------------------------------------------------------------------------
红外解码初始化函数
HS0038B OUT脚接M16 PD6(20 ICP1)脚
-----------------------------------------------------------------------------------------
*/
void NEC_Init(void)
{
m_ucBtnCode=NEC_BTN_NONE;
//Bit 7 – ICNC1: 入捕捉噪声抑制器
//Bit 6 – ICES1: 输入捕捉触发沿选择 0下降沿触发,1上升沿触发
//Bit 2:0 – CS1 2:0: 时钟选择
TCCR1B|=0B10000100; //使能输入捕获噪声抑制
//初始设置为下降沿触发
//时钟分频 256 (16M外部时钟下16微秒计数一次)
TIMSK|= 1<
}
/*
-----------------------------------------------------------------------------------------
红外解码输入捕获中断服务函数
定时器1输入捕获中断,计数周期16微秒。
-----------------------------------------------------------------------------------------
*/
SIGNAL(SIG_INPUT_CAPTURE1)
{
static U8 ucStep; //状态机
static U8 ucBitCnt; //记录移位次数
static U8 i,j; //i数组下标,j循环次数
static U8 ucCode[4]; //32位数据
U16 usICR=0; //暂存时间印记
usICR=ICR1; //保存时间印记
switch(ucStep)
{
//同步码:由一个9ms的低电平和一个4.5ms的高电平组成
case 0:
//第一个下降沿到来
TCNT1 = 0; //清零计数器
TCCR1B|=0x40; //上升沿触发
ucStep++;
break;
case 1:
//第一个上升沿到来
TCNT1 = 0; //清零计数器
if(usICR<550 || usICR>570)//测量低电平持续时间(9000us/16us=562.5)是否在误差范围内
goto ERR;
TCCR1B&=~0x40; //下降沿触发
ucStep++;
break;
case 2:
//第二个下降沿到来
TCNT1 = 0; //清零计数器
if(usICR<270 || usICR>290) //测量高电平持续时间(4500us/16us=281.25)是否在误差范围内
goto ERR;
//同步码有效
TCCR1B|=0x40; //上升沿触发
ucBitCnt=0; //移位次数清零
i=0;j=0;
ucStep++;
break;
//接收32位数据:八位地址码、八位地址反码、八位控制码、八位控制反码:
//一个逻辑1传输需要2.25ms(560us低电平+1680us高电平),
//一个逻辑0的传输需要1.125ms(560us低电平+560us高电平)
case 3:
TCNT1 = 0; //清零计数器
TCCR1B&=~0x40; //下降沿触发
if(usICR<30 || usICR>40) //测量低电平持续时间(560us/16us=35)是否在误差范围内
goto ERR;
ucStep++;
break;
case 4:
TCNT1 = 0; //清零计数器
if(usICR>100 && usICR<110) //测量高电平持续时间(1685us/16us=105.3125)是否在误差范围内
{
//有效数据 1
ucCode=(ucCode<<1)+1;
}
else if(usICR>30 && usICR<40//测量高电平持续时间(560us/16us=35)是否在误差范围内
{
//有效数据 0
ucCode<<=1;
}
else //干扰信号
goto ERR;
//接收完8位数据
if(++j==8)
{
//接收完32位数据
if(++i==4)
{
//判断地址码是否正确,注意:(U8)(~ucCode[1])这个写法是必须的
if(ucCode[0]!=(U8)(~ucCode[1]))
goto ERR;
//判断控制码是否正确
if(ucCode[2]!=(U8)(~ucCode[3]))
goto ERR;
//记录控制码
m_ucBtnCode=ucCode[2];
TCCR1B&=~0x40;//下降沿触发
ucStep=0;
break;
}
j=0;
}
TCCR1B|=0x40; //上升沿触发
ucStep=3;
break;
default:
goto ERR;
break;
}
return;
ERR:
m_ucBtnCode=NEC_BTN_NONE;
TCCR1B&=~0x40; //下降沿触发
ucStep=0;
}
/*
-----------------------------------------------------------------------------------------
nec 红外解码按键服务函数
-----------------------------------------------------------------------------------------
*/
void NEC_Service(void)
{
U8 ucBtn=m_ucBtnCode;
//当前无键按下
if(NEC_BTN_NONE==ucBtn)
return;
switch(ucBtn)
{
case 104: //我的遥控器上 “0”键
LED_ON();
break;
case 48: //我的遥控器上 “1”键
LED_OFF();
default:
break;
}
m_ucBtnCode=NEC_BTN_NONE;
}
/*
-----------------------------------------------------------------------------------------
函数:
main
功能:
C 语言主函数
入口:
void
出口:
int
备注:
无
-----------------------------------------------------------------------------------------
*/
int main(void)
{
LED_Init();
NEC_Init();
EN_INT(); //开全局中断
while(1)
{
NEC_Service();
}
return 0;
}
/*
-----------------------------------------------------------------------------------------
end of file
-----------------------------------------------------------------------------------------
*/