/************************************************************************************************************************
******* 文件名:Decode.c
******* 描 述:用一个外部中断IO脚配合定时器0实现对2262系列编码信号进行软解码, PT2262的输出信号经LM358整形放大后
由单片机P3.2口输入,作为单片机的外部中断源。
******* 编 码:A0 -- A11 中的每bit用2bit表示:0码:00 ;1码:11
******* 硬 件:PT2262发射模块、LM358+R25.接收模块、STC89C52RC单片机
******* 晶 振:11.0592MHz
******* 日 期:2014-05-21 (zqjun@HK)
******* 说 明:
1、PT2262输出编码包括8位地址码、4位数据码、1位同步码,共13位,
顺序:A0 A1 -- A10 A11 + 同步码 + A0 A1 -- A10 A11 + 同步码,连续发四次。
2、四个振荡周期为1个编码计时单位,记作T,除同步码外,编码中只有2种类别的组合脉冲取名长脉冲和短脉冲,
其中:长脉冲由3T高电平、1T低电平组成;短脉冲由1T高电平、3T低电平组成。
3、同步码,由1T高电平31T低电平组合(实际测试同步码低电平宽度基本在10ms以上)。
4、只需测量低电平或者高电平长短,即可知是长还是短脉冲,超过12T时间没有脉冲变化就有可能是同步码。
************************************************************************************************************************/
#include <reg52.h> //8051系列单片机头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Decode.h" //各种宏定义、全局变量、全局结构体声明
/**************************************************
********* 功能:利用定时器1实现1ms延时 ************
**************************************************/
void T1_timer(void) interrupt 3 using 1
{
TH1 = (65536 - DELAY)/256;
TL1 = (65536 - DELAY)%256; //922:1ms 450:1us
count++;
//LED1 = ~LED1;//改变P1.1状态
}
/**************************************************
***************** 功能:xms延时 *******************
**************************************************/
void delayms(uint xms)
{
uint i, j;
for(i = xms; i > 0; i--) //延时xms
{
for(j = 110; j > 0; j--);
}
}
#if 0
/*****************************************************
*********** 功能:数码管显示0 ~ F之间的值 ************
*****************************************************/
/*
void display(uint arry_index)
{
dula = 1; //开段选
P0 = table[ arry_index ]; //送段选数据
dula = 0; //关段选
P0 = 0xFF; //消影
delayms(Display_DELAY); //延时
}
*/
/****************************************************************
************ 功能: 把十六进制数据转换为十进制数据 *************
************ 返回值:转换之后结果,即十进制数据 *************
***************************************************************/
/*
uint Hex2Decimal(unsigned long num)
{
uint ret = 0;
if( (0 <= num) && (num <= 15) ) //0 ~ F
{
ret = ( (num & 0x8) * 8 ) +
( (num & 0x4) * 4 ) +
( (num & 0x2) * 2 ) +
( (num & 0x1) * 1 );
return ret;
}
return 0;
}
*/
/********************************************************************
****** 功能:解析接收到的解码后的数据,送8段数码管显示解码结果 ******
********************************************************************/
/*
void Parse_DecData(unsigned long decdata)
{
unsigned long temp = 0;
temp = decdata & 0xF00000; //编码最高4位
wela = 1;
P0 = 0xFE; //第1位数码管
wela = 0;
//display( Hex2Decimal(temp >> 20) );
display( temp >> 20 );
temp = decdata & 0x0F0000;
wela = 1;
P0 = 0xFD; //第2位数码管
wela = 0;
//display( Hex2Decimal(temp >> 16) );
display( temp >> 16 );
temp = decdata & 0x00F000;
wela = 1;
P0 = 0xFB; //第3位数码管
wela = 0;
//display( Hex2Decimal(temp >> 12) );
display( temp >> 12 );
temp = decdata & 0x000F00;
wela = 1;
P0 = 0xF7; //第4位数码管
wela = 0;
//display( Hex2Decimal(temp >> 8) );
display( temp >> 8 );
temp = decdata & 0x0000F0;
wela = 1;
P0 = 0xEF; //第5位数码管
wela = 0;
//display( Hex2Decimal(temp >> 4) );
display( temp >> 4 );
temp = decdata & 0x00000F; //编码最低4位
wela = 1;
P0 = 0xDF; //第6位数码管
wela = 0;
//display( Hex2Decimal(temp) );
display( temp );
return;
}
*/
#endif
/*************************************************
********** 功能:十六进制数据比较大小 ************
*************************************************/
/*
int HexDataCompare(unsigned long data_recv, unsigned long data_base)
{
if( (data_recv == 0) || (data_base == 0) )
{
return -1;
}
unsigned int i;
unsigned long temp = data_recv;
for (i = 0; i < 4; i++)
{
temp = data_recv & 0xFF;
}
return 0;
}
*/
/**********************************************
************ 功能:全局变量预初始化 *************
**********************************************/
int PrevInitial(M433_Service *p433_srv)
{
//g_Display = 0; //数码管显示全局控制标志
uchar i;
for (i = 0; i < NODE_MAX; i++)
{
memset( &p433_srv->m433CodeTable[i], 0, sizeof(p433_srv->m433CodeTable[i]) );
}
p433_srv->m433WorkMode = MODE_NORMAL; //1, 初始化为正常工作模式
p433_srv->m433_DecData_Learn = 0x0; //新对码值
p433_srv->m433_DecData_Curr = 0x0; //当前接收到的编码信号值
//p433_srv->m433_DecData_Prev = 0x0; //以前接收到的编码信号值
p433_srv->m433_DevCount = 0; //已经对码的设备计数器
p433_srv->m433_LearnStart = 0; //学习对码开始
p433_srv->m433_LearnOK = 0; //学习对码成功
p433_srv->m433_Enable = 1; //使能433模块
count = 0;
g_Receive = 0x0; //数据接收buffer
g_DecData = 0x0; //待解码buffer,数据接收buffer的备份
g_RecvOK = 0; //接收完成标志
g_DecOK = 1; //解码完成标志,第一次进来置1以获取接收后的数据
g_Running = 1; //循环检测开启
return 0;
}
/***************************************************************
******************** 功能:单片机中断系统初始化 **********************
***************************************************************/
void MCU_Int_Initial( void )
{
TMOD = 0x11; //设置定时器0和1的工作方式1:16位定时器
TH1 = (65536 - DELAY)/256;
TL1 = (65536 - DELAY)%256; //1ms
ET1 = 1; //使能定时器1
TR1 = 1; //启动定时器1
TH0 = 0; //定时器0装初值
TL0 = 0; //11.0592MHz 计满最大值计数值的时间为:71111us
ET0 = 1; //使能定时器0
IT0 = 1; //设置外部中断0为跳变沿触发方式,从高到低的负跳变触发
EX0 = 1; //开启外部中断0
EA = 1; //开启所有中断
}
/*********************************************************************
************** 功能: 外部中断0服务函数,实现对2262解码 ***************
************** 中断功能开启后,下降沿触发中断进入此函数 **************
*********************************************************************/
void INT0_ISR(void) interrupt 0 using 1
{
unsigned char i = 0;
unsigned char j = 0;
unsigned int Low_Level_Count = 0; //低电平状态持续时间计数器
unsigned int Wide_Low = 0; //宽脉冲低电平持续时间
unsigned int Narrow_Low = 0; //窄脉冲低电平持续时间
EX0 = 0; //先关闭外部中断0
while( WAVE_RECV ); //如果当前为高电平,则等待低电平的到来
TH0 = 0;
TL0 = 0; //11.0592MHz:71111us
TR0 = 1; //启动定时器0,开始测量低电平的宽度,检测同步码
while( ! WAVE_RECV ) //中断进入时当前为低电平状态
{
if( TF0 == 1 ) //如果定时器溢出,TF0位由硬件置1
{
goto DecExit; //定时器超时溢出则退出
}
}
TR0 = 0; //电平状态发生变化,停止timer0计数,取得当前计数值
Low_Level_Count = TH0;
Low_Level_Count = Low_Level_Count << 8;
Low_Level_Count = Low_Level_Count + TL0; //根据定时器计数值取得低电平的宽度
//if( ((TIME_SYNC - TIME_SYNC_RANDOM) < Low_Level_Count) && (!g_RecvOK) ) //判断电平宽度,检测是否为同步码,事实上超过10ms即有可能为同步头
if( ((TIME_SYNC_COMMON - TIME_SYNC_RANDOM) < Low_Level_Count) && (!g_RecvOK) ) //判断电平宽度,检测是否为同步码,超过8.5ms即有可能为同步头
{
//LED0 = ~LED0;
Wide_Low = Low_Level_Count / 32; //根据同步码低电平宽度取得宽脉冲低电平宽度值
Narrow_Low = Low_Level_Count / 11; //根据同步码低电平宽度取得窄脉冲低电平宽度值
g_Receive = 0x0;
for( i = 0; i < 24; i++ ) //循环24次解码
{
while( WAVE_RECV ); //如果当前高电平状态,则等待低电平到来
TH0 = 0;
TL0 = 0; //定时器重装初值
TR0 = 1; //电平变化,开启定时器0 ,测量低电平的宽度
while( ! WAVE_RECV )
{
if( TF0 == 1 )
{
goto DecExit; //如果定时0溢出则退出
}
}
TR0 = 0; //电平状态发生变化,停止计数
Low_Level_Count = TH0;
Low_Level_Count = Low_Level_Count << 8;
Low_Level_Count = Low_Level_Count + TL0; //根据定时器0计数值取得低电平的宽度
//if( ((TIME_BIT1 - TIME_BIT_RANDOM) < Low_Level_Count) && (Low_Level_Count < (TIME_BIT1 + TIME_BIT_RANDOM)) )//宽脉冲的低电平宽度:1表示
if( ((Wide_Low - TIME_BIT_RANDOM) < Low_Level_Count) && (Low_Level_Count < (Wide_Low + TIME_BIT_RANDOM)) ) //宽脉冲的低电平宽度:1表示
{
g_Receive = g_Receive << 1;
g_Receive = g_Receive + 0x01; //存入1
}
//else if( ((TIME_BIT0 - TIME_BIT_RANDOM) < Low_Level_Count) && (Low_Level_Count < (TIME_BIT0 + TIME_BIT_RANDOM)) ) //判断窄脉冲低电平宽度:0表示
else if( ((Narrow_Low - TIME_BIT_RANDOM) < Low_Level_Count) && (Low_Level_Count < (Narrow_Low + TIME_BIT_RANDOM)) ) //窄脉冲低电平宽度:0表示
{
g_Receive = g_Receive << 1;
//g_Receive = g_Receive + 0x00; //存入0
}
else
{
goto DecExit; //在24个脉冲周期上,有一个在时间上匹配,则表明收到的为干扰波,丢弃掉
}
if( g_DecOK == 1 ) //如果接收到的数据已经解码处理完成,再重新获取新的数据
{
//LED1 = ~LED1;
g_DecData = g_Receive;
}
}
//g_Display = 0;//禁止向数码管送数据
g_RecvOK = 1; //数据接收完毕,等待解析
g_DecOK = 0; //数据等待解析,重置解码标志
Low_Level_Count = 0; //电平状态持续时间计数器归0
return;
}
else
{
goto DecExit;
}
DecExit:
{
//LED3 = ~LED3; //改变P1.2状态
TR0 = 0;
EA = 1; //使能所有中断
EX0 = 1; //开外部中断0
TF0 = 0; //溢出标志位软件清0
return;
}
}
/************************************************
********** 功能:433模块退出,释放资源 **********
************************************************/
int m433_Exit(M433_Service *p433_srv)
{
EA = 0; //关闭所有中断
EX0 = 0; //关闭外部中断0
TR0 = 0; //关闭定时器0
TF0 = 0; //溢出标志位软件清0
TH1 = 0;
TL1 = 0;
ET1 = 0;
TR1 = 0; //关闭定时器1
count = 0;
g_Receive = 0x0; //数据接收buffer
g_DecData = 0x0; //待解码buffer,数据接收buffer的备份
g_RecvOK = 0; //接收完成标志
g_DecOK = 0; //解码完成标志,第一次进来置1以获取接收后的数据
p433_srv->m433_Enable = 0;
p433_srv->m433_LearnStart = 0;
p433_srv->m433_LearnOK = 0;
p433_srv->m433WorkMode = MODE_NORMAL; //1, 初始化为正常工作模式
p433_srv->m433_DecData_Learn = 0x0; //新对码值
p433_srv->m433_DecData_Curr = 0x0; //当前值
//p433_srv->m433_DecData_Prev = 0x0; //以前接收到的编码信号值
p433_srv->m433_DevCount = 0;
g_Running = 0; //停止循环检测
return 0;
}
/*********************************************************************
************************** main function *****************************
*********************************************************************/
int main(void)
{
unsigned char i = 0;
unsigned long dec_Data = 0x0; //解码后的24位编码
M433_Service m433Serv; //struct.
if( PrevInitial( &m433Serv ) ) //初始化全局变量
{
m433_Exit( &m433Serv );
return -1;
}
MCU_Int_Initial(); //中断、定时器/计数器初始化
/**解析接收到的码值**/
while( g_Running )
{
if( g_RecvOK ) //数据接收完成,等待解码
{
g_DecOK = 0; //置位0,表示数据解析还未完成
#if 0
P1 = g_DecData & 0xFF;
P1 = (g_DecData >> 8) & 0xFF;
P1 = (g_DecData >> 16) & 0xFF; //此处可以通过点亮led来验证解码的结果,我的单片机板上只有8个led灯。
#else
m433Serv.m433_DecData_Curr = g_DecData;
//if( 1 == m433Serv.m433_LearnStart ) //是否开始学习对码
//{
// //m433Serv.m433_DecData_Prev = g_DecData; //开始对码,首先更新的之前保存的对码信号值
// //m433Serv.m433_DecData_Learn = g_DecData; //新的编码信号值
//}
if( m433Serv.m433_DecData_Curr == CTRL_KEY_ENABLE ) //======> 按键A:布防 <======
{
m433Serv.m433WorkMode = MODE_NORMAL; //1, 初始化为正常工作模式
m433Serv.m433_Enable = 1; //使能433报警探测功能
//LED0 = ~LED0;
}
else if( m433Serv.m433_DecData_Curr == CTRL_KEY_DISABLE ) //======> 按键B:撤防 <======
{
m433Serv.m433WorkMode = MODE_SLEEP; //睡眠模式,不输出报警信息
m433Serv.m433_Enable = 0; //关闭433报警探测功能
//LED1 = ~LED1;
}
else if( m433Serv.m433_DecData_Curr == CTRL_KEY_LEARNING ) //======> 按键C:学习对码 <======
{
m433Serv.m433WorkMode = MODE_LEARNING;//学习对码模式,把接下来收到的新编码存入码表
//LED2 = ~LED2;
}
else if( m433Serv.m433_DecData_Curr == CTRL_KEY_TEST ) //======> 按键D:测试对码是否生效 <======
{
if( 1 == m433Serv.m433_LearnOK ) //学习对码成功,才可以测试新加入的设备是否生效
{
m433Serv.m433WorkMode = MODE_TEST; //测试模式,匹配新报警设备的报警信号
}
else
{
m433Serv.m433WorkMode = MODE_NORMAL; //对码不成功则依旧进入正常工作模式继续探测
}
//LED3 = ~LED3;
}
else //=============>四按键钥匙以外的编码信号到来<=============
{
if( (1 == m433Serv.m433_LearnStart) && (0 == m433Serv.m433_LearnOK) )
{
m433Serv.m433WorkMode = MODE_LEARNING; //如果对码模式已经开启,则进入对码模式开始学习新的编码信号值
}
else
{
m433Serv.m433WorkMode = MODE_NORMAL; //非对码模式则默认为正常工作模式
}
LED4 = ~LED4;
}
if( 0 == m433Serv.m433_Enable ) //如果未开启433布防功能
{
LED5 = ~LED5;
}
#if 0
if( m433_TaskSchedule( &m433Serv ) ) //433任务调度
{
printf("433 module task schedule error,exit!\n");
m433_Exit( &m433Serv );
}
#endif
#endif
TF0 = 0; //定时器0溢出标志位清0
EA = 1; //开所有中断
EX0 = 1; //重开外部中断0
g_DecOK = 1; //数据解码已经完成,可以接收新的数据了
//g_Display = 1; //解析后的数据可以送数码管显示了
g_RecvOK = 0; //解析完成,开始接收新的数据
}
#if 0
if (g_Display)
{
g_Display = 0;
//Show_Data = 0x5555C0;
Parse_DecData( Show_Data ); //解析编码数据,分位送8段数码管显示
}
//if (count == 250)//250ms间隔闪烁
//{
// count = 0;
// LED0 = ~LED0;//改变P1.0状态
//}
#endif
}
m433_Exit( &m433Serv );
return 0;
}
单片机实现PT2262解码示例代码
最新推荐文章于 2024-08-02 01:20:10 发布