2014-10-07 18:03:52 zqj6893 阅读数 6525
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4001 人正在学习 去看看 朱有鹏

1、ASK调制

        “幅移键控”又称为“振幅键控”,也有称为“开关键控”(通断键控),所以又记作OOK信号。ASK是一种相对简单的调制方式。幅移键控(ASK)相当于模拟信号中的调幅,只不过与载频信号相乘的是二进制数码而已。幅移就是把频率、相位作为常量,而把振幅作为变量,信息比特是通过载波的幅度来传递的。二进制振幅键控(2ASK), 由于调制信号只有0或1两个电平,相乘的结果相当于将载频或者关断,或者接通,它的实际意义是当调制的数字信号为“1”时,传输载波;当调制的数字信号为“0”时,不传输载波。一般载波信号用余弦信号,而调制信号是把数字序列转换成单极性的基带矩形脉冲序列,而这个通断键控的作用就是把这个输出与载波相乘,就可以把频谱搬移到载波频率附近。

2、几个周期

        2.1、时钟周期:也称为振荡周期或晶振周期,定义为时钟频率的倒数,即晶振的振荡频率的倒数,计为:T(时)=1/f(osc)。时钟周期是计算机中最基本的、最小的时间单位。在一个时钟周期内,CPU仅完成一个最基本的动作。对于某种单片机,若采用了1MHZ的时钟频率,则时钟周期为1us。

        2.2、状态周期:状态周期是振荡周期的二倍。振荡周期也称为晶振周期,振荡周期是单片机的基本时间单位。振荡脉冲经二分频成为时钟信号,时钟信号的周期称为状态周期。若时钟晶振的振荡频率为fosc,则时钟信号的状态周期Tosc=(1/fosc)*2。(即为振荡频率的倒数的2倍)。例如:晶振频率为12MHZ,则时钟周期Tosc=(1/12us)*2。

        2.3、机器周期:单片机的基本操作周期。在计算机中,为了便于管理,常把一条指令的执行过程划分为若干个阶段,每一阶段完成一项工作。例如,取指令、存储器读、存储器写等,这每一项工作称为一个基本操作。一个操作周期内,单片机完成一项基本操作。

        2.4、指令周期:执行一条指令所需要的时间,一般由若干个机器周期组成。指令不同,所需的机器周期数也不同。对于一些简单的的单字节指令,在取指令周期中,指令取出到指令寄存器后,立即译码执行,不再需要其它的机器周期。对于一些比较复杂的指令,例如转移指令、乘法指令,则需要两个或者两个以上的机器周期。

        综上所述:一个机器周期 = 6个状态周期 = 12个时钟周期

3、位码

        红外编码波形的基本单位,为分AD(地址码、数据码)位和SYNC(同步码)位,每“位”波形由两个脉冲周期构成,每个脉冲周期含有16个时钟周期。位码使用两个脉冲信号表示一个编码值,其中,两个连续窄脉冲表示编码值“0”;两个连续宽脉冲表示编码值“1”;一个窄脉冲和一个宽脉冲表示“F”,也就是地址码的“悬空”。即每个位码bit用2bit表示:00 或01或10表示0码;11表示1码。

        如下图所示,编码芯片PT2262发出的编码信号经过整形电路之后得到的脉冲波形图。由:地址码、数据码、同步码组成。地址码和数据码都用宽度不同的脉冲来表示,两个窄脉冲表示“0”; 两个宽脉冲表示“1”; 一个窄脉冲和一个宽脉冲表示“F”,也就是地址码的“悬空”;同步码为时间较长的低电平间隔,下图为PT2262编码图: 

 

        如上图,发射端每发送一次信号都会携带多组编码字码,每段编码字码值相同,二进制值为0B010101010101010100001100,对应的十六进制码值为:0x55550C。从图中可以看出,发送码的周期是相等的,只是脉冲宽度不同(宽脉冲与窄脉冲之比为3:1)。而同步码的低电平时间约为这个周期的8倍。

        解码的关键是识别同步码,然后对后面的字码的脉冲宽度进行识别,就可以解出这个编码。PT2262每次发射时至少发射4组字码,每组字码由25个脉冲组成,前24个脉冲为地址和数据,最后一个脉冲和一低电平间隔组成同步码。

 

4、单片机解码思路:

        下面我们来说说如何用51单片机对其进行解码。由于程序结构不复杂,就不再画程序流程图了。

        红外线经一体化接收模块解码后送到单片机的外部中断0,单片机设置外部中断下降沿触发(即外部中断0为跳变沿触发方式,从高到低的负跳变触发进入中断处理函数进行解码操作);

        首先我们把T0设置为16位定时器模式,工作在定时状态,初始化值为0,在晶振的工作频率为11.0592MHz时计满最大值计数值的时间为:71111us。由于同步码周期与地址数据周期都远小于定时器0的定时时间,所在定时器0正常工作时,是不会溢出的;

        T1用作延时,设置其定时为1ms(本示例中没有用到T1功能);

        在EX0=1(外部中断0启动)并且EA=1(使能所有中断)后,当下降沿到来时进入到中断处理函数,T0在TR0的控制下启动与停止计时;

        当接收到下降沿后,先判断当前的电平状态,检测到是低电平时则把T0计时器归零开始计数低电平的时间宽度,电平状态发生变化时停止计数。取TH0和TL0之和即可根据该低电平的时间宽度值来识别是否为同步码。只有先识别出同步码,才开始接收后续脉冲数据进行24位解码操作。

 

        判断电平宽度,检测是否为同步码时,事实上超过10ms即有可能为同步码。初步找出同步码后,根据同步码低电平宽度取得宽脉冲低电平宽度值,根据同步码低电平宽度取得窄脉冲低电平宽度值,由上面的PT2262编码格式图可以看出,同步码低电平持续时间是宽脉冲低电平持续时间的32倍,是窄脉冲低电平持续时间的10(或11)倍,后续的24位数据的宽、窄脉冲低电平持续时间宽度进行比较,满足一定的范围时,即可解析出发射端送出的编码。

        注意:因为生产接收模块的厂家不同,标准不一,我遇到过有的模块把接收信号反向了,这时就需要找寻时间宽度较长的高电平来初步识别同步码了。

        以下为示例代码说明部分:

 

/********************************************************************************************************************************************************************************

文件名:Decode.c  (zqjun@HK 2014-05)

*  描  述:用一个外部中断IO脚配合定时器0实现对2262系列编码信号进行软解码, PT2262的输出信号经LM358整形放大后由单片机P3.2口输入,作为单片机的外部中断源。

编  码:A0 -- A11 中的每bit用2bit表示:0码:00 ;1码:11

硬  件:PT2262发射模块、LM358+R25.接收模块、STC89C52RC单片机

晶  振:11.0592MHz

说  明:

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时间没有脉冲变化就有可能是同步码。

**********************************************************************************************************************************************************************************/

2014-10-07 19:31:57 zqj6893 阅读数 4442
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4001 人正在学习 去看看 朱有鹏
/************************************************************************************************************************
******* 文件名: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;
}

2010-09-25 13:07:00 jh_zzz 阅读数 3568
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4001 人正在学习 去看看 朱有鹏

一个写的不错的 PT2262 精确解码程序,实际硬件测试通过,分享一下:

 

2005-10-20 17:33:00 nesert 阅读数 1204
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4001 人正在学习 去看看 朱有鹏
目前正在写一个51系列单片机的模拟器,会陆续写一些开发过程及进展情况。。。
2010-11-30 03:56:00 boliu218 阅读数 3266
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4001 人正在学习 去看看 朱有鹏

    这几天研究了市场上常见的无线遥控开关,它们的无线部分大都是用2262-2272编码实现,在网上找了些2262-2272软解码的资料,发现少的可怜,即使有实用性也不高,于是乎就有了这篇博客。

    22262频率计算公式为F=32000/Ros(KΩ)KHz,其中Ros为震荡电阻,发送一位占用32个时钟周期,其中起始位占用128时钟周期。2262编码格式如下图:

image

     ‘F’只有地址为才有,数据位只有‘0’‘1’。

cc1101与stc单片机连接如下:

SI-P1.5;

SO-P1.6;

CLK-P1.7;

CS-P3.4;

GDO0-P4.2(CCP0);

GDO2-P4.3(CCP1);

cc1101配置如下:
    0x08,//0x0B,   // FSCTRL1   Frequency synthesizer control.
    0x00,   // FSCTRL0   Frequency synthesizer control.
    0x0c,   // FREQ2     Frequency control word, high byte.
    0x1d,//0xAA,//,   // FREQ1     Frequency control word, middle byte.
    0x89,//0x55,//   // FREQ0     Frequency control word, low byte.
    0xc6,//0x8A,   //2d MDMCFG4   Modem configuration.
    0x45,//0x01,   //3B MDMCFG3   Modem configuration.
    0xb2,//0x73,   // MDMCFG2   Modem configuration.
    0x02,//0xA2,   // 22  MDMCFG1   Modem configuration.
    0xF8,   // MDMCFG0   Modem configuration.

    0x00,   // CHANNR    Channel number.
    0x40,//0x00,   // DEVIATN   Modem deviation setting (when FSK modulation is enabled).
    0x56,//0xB6,   // FREND1    Front end RX configuration.
    0x11,   //10 FREND0    Front end RX configuration.
    0x18,   // MCSM0     Main Radio Control State Machine configuration.
        0x00,
    //0x0f,        //MCSM1
    //0x30,
    0x16,//0x1D,   // FOCCFG    Frequency Offset Compensation Configuration.
    0x6c,//0x1C,   // BSCFG     Bit synchronization Configuration.
    0x43,//0xC7,   // AGCCTRL2  AGC control.
    0x40,//0x00,   // AGCCTRL1  AGC control.
    0x93,//0xB2,   // AGCCTRL0  AGC control.

    0xe9,//0xEA,   // FSCAL3    Frequency synthesizer calibration.
    0x2A,//0x0A,   // FSCAL2    Frequency synthesizer calibration.
    0x00,   // FSCAL1    Frequency synthesizer calibration.
    0x1f,   // FSCAL0    Frequency synthesizer calibration.
    0x59,   // FSTEST    Frequency synthesizer calibration.
    0x81,//0x88,   // TEST2     Various test settings.
    0x35,//0x31,   // TEST1     Various test settings.
    0x09,   // TEST0     Various test settings.
    0x09,   // IOCFG2    GDO2 output pin configuration.
    0x4d,   // IOCFG0D   GDO0 output pin configuration. Refer to SmartRF?Studio User Manual for detailed pseudo register explanation.

    0x00,   // PKTCTRL1  Packet automation control.
    0x30,   // 05   PKTCTRL0  Packet automation control.
    0x00,   // ADDR      Device address.
    0x2e,   // PKTLEN    Packet length.

这里配置异步接收速度大约为2.1K,根据CC1101手册说明,异步接收时,其发送频率的误差应在设定接收频率的1/8内,经测试表明,此设置完全可以接受震荡电阻为475的2262编码。

这里要说明一个问题,我也没有找出原因,cc1101在接收2262编码时,第一个起始位和第一个数据电平接收不到,大概会丢失132-140个震荡周期,这个可以用一个cc1101和一个超再生接收模块接收相同的数据在示波器上看出,但并不影响数据接收,因为一般2262编码至少会发送4次以上。

GDO0在接收时为数据输出,在发送时自动配置为数据输入,将STC的ccp0上升沿和下降沿捕获打开,并将ccp0跳转至P4.2。

2262软解码的关键在于找到正确的起始位。使用定时器0资源,配置成16位向上计数器,初始值为0x0000。过程如下:ccp0第一次捕获到上升沿时,启动定时器计数,捕获到下降沿时停止定时器并记录下此时TH0和TL0的计数并重新启动定时器,再一次捕获到上升沿时停止定时器并记录下TH0和TL0的值重启定时器,此时已读取到一个高电平和低电平的宽度了,然后比较,看低电平宽度是否为高电平宽度的30-33倍,如果是则可以认为是2262编码的起始位,如果不是,则如此循环直到找到比例合适的。

找到起始位后,循环捕获,至少捕获两个2262编码周期,因为OOK/ASK方式太不稳定了,取两次解码比较如果相同才能认为是正确的。

假定捕获完毕,到解码过程了,注意到2262编码规则,每位需要四个电平宽度来表示,其实可以不管是否为高电平或低电平,只需注意四个电平的比例规则:

‘0’1:3,1:3

‘1’3:1,3:1

‘F’1:3,3:1

还要注意一点,2262编码中‘F’只能出现在地址码中,如果在数据码中出现了‘F’,则可认为解码错误。

单片机模拟spi通信

阅读数 766

没有更多推荐了,返回首页