欢迎光临~啄木鸟电子科技

软件设计

NEC 红外发射

NEC 红外发射 https://blog.csdn.net/qq_43415898/article/details/107561498




/**********************************************************************
* 作者:杨志强 EWOODPECKER_CHRIS YANG
* 日期:2017.03.04
* 特点: STM8S003F3P6 测试串口;        
* 时钟:内部 16MHz; 

38KHz =>  26.31 us; (高电平 13.2) 
***********************************************************************/
// 头文件 宏定义
#include <iostm8s003f3.h>
#include"stdio.h"

// 声明;常用数据类型定义*************************/
#define u8  uint8_t
#define u16 uint16_t
#define u32 uint32_t

typedef unsigned char    uint8_t;
typedef unsigned int     uint16_t;
typedef unsigned long    uint32_t;

// 位定义, 控制信号口;
#define KEY     	PD_IDR_IDR1   // 按键   KEY 指定到 PA1 ; 输入寄存器;  (上拉输入 )  内部高电平,被动拉低;

#define LED     	PA_ODR_ODR3   // 指示灯 LED 
//#define IR    	PD_ODR_ODR3   // IR红外遥控 发射; 
#define IR   		PD_ODR_ODR2   // IR红外遥控 发射; 

// 数组定义;
unsigned char Table[8];  // 存储 Music 命令码

// 变量定义;
u8 wy[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; // 0000 0001 / 0000 0010 / 0000 0100 / 0000 10000 
u16  end_count = 0;

u8 count     = 0;
u8 count0    = 0;
u8 user; 
//u16 system = 0x00ff;
u16 system = 0x00;

u16 time_cnt = 0;
	
u8 hc;

/**********************************************************************
* 函数: CLK_Init(void)
* 功能: 时钟设置;配置成 16MHz; 
* 输入: 无;
* 输出: 无;
***********************************************************************/
void CLK_Init(void)
{
	CLK_CKDIVR = 0x00; // 配置成 16MHz; 
}

/**********************************************************************
* 函数: eeprom_write(u8 addr, u8 dat)
* 功能: EEPROM指定地址写入一个数据
* 输入: 无;
* 输出: 无
***********************************************************************/
void eeprom_write(u8 addr, u8 dat)
{
  u8 *p;
  p = (u8 *)(0x4000+addr);
  *p = dat;
  while(!(FLASH_IAPSR & 0x04)); //等待写操作成功
}

/**********************************************************************
* 函数: TIM1_Init(unsigned int psc,unsigned int arr)  //psc  分频系数  arr  计数值
* 功能: 时钟定义 初始化;
* 输入: 无
* 输出: 无
***********************************************************************/
void Init_TIM1(u16 psc,u16 arr)  //psc  分频系数  arr  计数值
{	
  //1. 配置定时器 工作模式 和系统时钟;
	TIM1_CR1 = 0x00;
	/*
	ARPE_7 = 0;	// ( )
	CMS_6 = 0;	// ( )
	CMS_5 = 0; 	// ( )
	DIR_4 = 0;	// ( 0:计数器向上计数; 1:计数器向下计数?)
	OPM_3 = 0;	// ( 0:发生更新事件时,计数器不停止;1: 发生下一次更新事件时(清除 CEN 位,计数器停止; )
	URS_2 = 0;	// ( ) 
	UDIS_1 = 0;	// ( )
	CEN_0 = 0; 	// ( 0: 禁止计数; 关闭计数器, 使用时,再开启;)
	*/
	
  	//2. 配置定时器 中断;
 	TIM1_IER = 0x01;  // 0000 0001(中断使能寄存器 )允许更行中断
	/*
	UIE_0 = 1; // (0: 禁止更新中断; 1: 允许更新中断;)	
	*/
	
	//3. 进行时钟分频;
  	TIM1_PSCRH = (psc-1)/256;  //进行分频值
	TIM1_PSCRL = (psc-1)%256;
	
  	//4. 设定计数值上限;
  	TIM1_ARRH = arr/256;   // 溢出值 高位;
	TIM1_ARRL = arr%256;   // 溢出值 低位;
        
  	//5. 开始计数;
	//TIM1_CR1 |=0x01;     //开始计数
} 

/**********************************************************************
* 函数: TIM1 中断函数;
* 功能: 时钟计时 中断标志位 清 0 ;
* 输入:  无;
* 输出:  无

打开 时钟 计时,让他一直不停 的 计数;
计数,根据不同 阶段 来设定 不同的参数,以示 区分; 
***********************************************************************/
#pragma vector=13
__interrupt void Inter_Timer1_Over(void)
{	 
    //TIM1_SR1 = 0x00; 				// 中断标志位 清 0 
	TIM1_SR1_UIF = 0; 				// 无更新事件 产生;
	TIM1_CR1_CEN = 0;  				// 停止记数;			
					
}

// D 端口 外部 中断函数;
/*********************************
1120us = 0; 
2250us = 1; 
13500us = start; 
< 1050 X
在  1700 为分界点;
1050 < 1120 < 1700 < 2250


#pragma vector = 8
__interrupt void Inter_EXTI3_IR_Handle(void)
{
   uchar IR_Time_H;
   uchar IR_Time_L;
   uint  IR_Time; // 记录脉冲的周期长度;
	
	//读数据之前先停止计数器
  TIM2_CR1_CEN=0;                      
    
	//读计数器的值 TIMx_CNTRH/TIMx_CNTRL
	IR_Time_H=TIM2_CNTRH;
  IR_Time_L=TIM2_CNTRL;                
	
	//数据转换 每计 1 次数 用时 1us; 
  IR_Time=IR_Time_H*256+IR_Time_L; 
	
  //清零计数器,以计算两次进入中断的时间   
  TIM2_CNTRH=0;                  
  TIM2_CNTRL=0;
	
  //启动计数器
	TIM2_CR1_CEN=1;
	
  //如果时间间隔大于11ms,说明接收到启动码 (引导码 9000us 高电平)
  if(IR_Time>11000)                    
  {
     IR_Start=1;   // 启动标志置一
     IR_Num=0;     // 清零IR_Num,保证数据的准确性,该语句可以保证不会因为接收到部分数据而
  }                // 导致数据不准确,原理是启动后必须接收到全部数据,数据才有效
		
		//数据时间间隔大余1.05ms,故不在这个范围则说明不是数据,则返回
  if(IR_Time<1050)                     
	{
		return;  // 退出操作,不再往下执行语句;
	}

	//如果已经收到启动代码,且数据在有效范围内
  if((IR_Start==1) && (IR_Time<2600))     
  {  
		//因为先发地址高位,所以要向右移动
    IR_data<<=1; // 0000 0100 -> 0000 1000 -> 0001 0000 注意:左移,补 0 ;
		
		//如果数据间隔大于数据0和数据1中间数值,则认为收到数据1
    if(IR_Time>1700)                 
		{
			IR_data|=1;  // 例:0000 1000 | 0000 0001  -> 0000 1001  让最低位 置 1;
		}
		
		//收到一位后IR_Num加1
		IR_Num++;                        
		
		//如果IR_Num>31,即等于32,33,34....(为保证可靠,用大于)时,说明数据已经收完
    if(IR_Num>31)                    
    { 
      //数据收完后接收结束标志置位 
			Sign_Data_Ok=1;
			
			//启动标志清零    
       IR_Start=0;
			
			//收到全部数据后关闭定时器,可节能,也避免出错
       TIM2_CR1_CEN=0;               
    }
  }
	
	IR_Data();// 对数据进行转换;
}

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

// 初始化:TIME2;
void  Init_TIME2(void)
{ 
	// 自动分频器 TIMx_PSCR
  	//TIM2_PSCR_PSC=1;         //0000 0001: 1MHz,计数器为1时定时时间约1us  (默认上电时,16MHz,8分频; 再 2 预分频成 1MHz; 
  	TIM2_PSCR_PSC=4; // 主时钟 16MHz, TIM2 采用 16 分频 = 1MHZ(1us); 
	
	//自动重装为10000保证正常接收过程中不会溢出	
	TIM2_ARRH=0xff;
  	TIM2_ARRL=0xff;         
	// ARRH/ARRL: 当自动装载的值为 0 时,计数器不工作;
  	TIM2_EGR_UG=1;          //重新初始化寄存器
	// UG 产生更新事件 0:无动作; 1 重新初始化计数器,并产生一个更新事件
	// 注意,预分频器的计数器也被清 0;
}


/**********************************************************************
* 函数: TIM2 初始化 
* 功能:  
* 输入:  
* 输出:  
16位 向上计数 和 自动装载计数器;
4位可编程;分频系数:1-32768 之间的 2 的幂; 

分频,向上计数,自动重装载
***********************************************************************/
void Init_TIME2_2(void)
{
	TIM2_ARRH = (u8)(1000 >> 8);
	TIM2_ARRL = (u8)(1000);
	
	TIM2_PSCR = 0x04; 		// 16M/(2^4) = 1M
	
	TIM2_EGR = 0x01; 		// 产生更新事件 
	TIM2_SR1 = (~0x01); 	// 清除更新中断标志;
	TIM2_CR1 |= 0x01; 		// 使能 计数器
	TIM2_IER |= 0x01;  		// 更新中断使能; 
 } 
 
 #pragma vector = 15
__interrupt void Inter_Timer2_Over(void)
{	 
    //TIM1_SR1 = 0x00; 			// 中断标志位 清 0 
	TIM2_SR1  = (~0x01); 		// 清除无更新 中断 标志; 
	time_cnt++;
	if(time_cnt > 999)
	{
		time_cnt = 0;
		LED = !LED;
	}
//	TIM1_CR1_CEN = 0;  		// 停止记数;			
					
}

/**********************************************************************
* 函数: Uart1_Init(void)
* 功能: Uart1 串口初始化环境设置;
* 输入:  无;
* 输出:  无
***********************************************************************/
void Init_UART1(void)
{
    UART1_CR1  = 0x00;   // 0000 0000 (5:使能)(4: 1个起始位,8个数据位);一位起始位,八位数据,不校验
    //UART1_CR2  = 0x2c; // 0010 1100 (开打接收中断,发送中断可以不设置,发送是我们主动发送的)(开启 发送使能,接收使能)()允许接收中断  发送接收使能
    //UART1_CR2  = 0x08;   // 0000 1000  发送使能 1开启;不要发送中断 ,不要接收中断;
    UART1_CR3  = 0x00;   // 0000 0000 一位停止位
    
    // UART1_BRR2 = 0x0b;   // 波特率 115200@ 16Mhz // BRR2 要先写于 BRR1; 
    // UART1_BRR1 = 0x08;	
    
    UART1_BRR2 = 0x03;   // 波特率 9600 @ 16Mhz(16 000 000 /9600) = 1667;
    UART1_BRR1 = 0x68;   // 1667 的 16进制:(1667 = 0x0683 )  UART_DIV = 0x0683; UART1_BRR2 =0X03;  UART1_BRR1 = 0X68;
   
		//4.使能发送和接收功能	
		UART1_CR2  = 0x2C;   // 0010 1100  开启: ( 发送 + 接收 使能 ) +( 接收 中断)
		//UART1_CR2  = 0x0C;   // 0000 1100  开启: ( 发送 + 接收 使能 )  
		/*
		7-TIEN 	发送 中断使能;
		6-TCIEN 发送 完成 中断 使能;
		4-ILIEN IDLE 中断 使能;
	
		2-REN 	接收使能;
		3-TEN 	发送使能;
		5-RIEN	接收  中断使能;		
		*/
		//UART1_CR2  = 0x08;   // 0000 1000  开启: 发送使能;  关闭:接收使能; 不要发送中断 ,不要接收中断?}
}

/**********************************************************************
* 函数: eeprom_read( u8  addr){
* 功能: EEPROM 指定地址读出一个数据
* 输入: 无;
* 输出: 有
***********************************************************************/
u16 eeprom_read( u8 addr)
{
  u8 *p;
  p=( u8 *)(0x4000+addr); 
  return *p; 
}

/**********************************************************************
* 函数: Delay_Nms(u16 x)
* 功能: 延时Nms;
* 输入: int x; 
* 输出: 无
***********************************************************************/
void Delay_Nms(u16 x)
{
  	u16 a,b;
  	while(x--)
  	{
    	for(a=0; a<18; a++)
    	{
      		for(b=0; b<176; b++);  // 175->998us;  176->1.00425ms; 
    	}    
  	}
}

/**********************************************************************
* 函数: Delay_1ms(int i)
* 功能: 1ms 延时
* 输入:  无
* 输出:	 无																				   
***********************************************************************/
void Delay_50us(u16 i)
{
	u8 j;
 	while(i--)
 	{
 		for(j=0; j<154; j++)	  //50us基准延时程序 
 		{	
			;
 		}  
 	}
}

/**********************************************************************
* 函数: Delay_1ms(int i)
* 功能: 38 KHz 
* 输入:  无
* 输出:	 无																				   
***********************************************************************/
void Delay_13us_duli(u16 i)
{
 	while(i--)
 	{
 		for(u8 j=0; j<30; j++)	  //38KHz 基准延时程序 高电平 13us.= 26us;  
 		{	
			;
 		}  
 	}
}

/**********************************************************************
* 函数: Delay_1ms(int i)
* 功能: 38 KHz 
* 输入:  无
* 输出:	 无
35 -> (37.7-38 KHz);																				   
***********************************************************************/
void Delay_13us(u16 i)
{
 	while(i--)
 	{
 		for(u8 j=0; j<35; j++)	  //38KHz 基准延时程序 高电平 13us.= 26us;  
 		{	
			;
 		}  
 	}
}

//发射 38KHz 的程序;  1000 000 us / 38 000 Hz = 26.315789 us
void khz_38()
{
	IR = 1;
//	LED = 1;
	Delay_13us(1); 	
	IR = 0;
//	LED = 0;
	Delay_13us(1); 
	
	// khz(116);		// 3.028 ms 
	// khz(64);			// 2.006 ms 
	// khz(40);			// 1.052 ms 
	// delayms(125); 	// 2.012 ms
	// delayms(65);  	// 1.054 ms
	// delayms(93); 	// 1.5 ms	
}

/**********************************************************************
* 函数: Delay100us(void)
* 功能: 100us 延时 精准;  误差 0us
* 输入:  无;
* 输出:  无
***********************************************************************/
void Delay_100us(void)
{
	Delay_50us(2); 	
}

/**********************************************************************
* 函数: LED_Flash()
* 功能: 指示灯
* 输入: 无
* 输出: 无
***********************************************************************/
void LED_Flash(u8 x)
{
	u8 i; 
	for (i = 0; i<= x; i++)
	{
		LED = 0;
		Delay_Nms(3);
		LED = 1; 
		Delay_Nms(3);	
	}
	LED = 1;	
}

/**********************************************************************
* 函数: GPIO_Init_Time()
* 功能: IO 端口初始化配置;
* 输入:  无;
* 输出:  无
***********************************************************************/
void GPIO_Init()
{

	PA_DDR |= 0x08;  // 0000 1000;  1:输出;0:输入 ( PA1_KEY 按键 上拉输入;)
 	PA_CR1 |= 0x08;  // 0000 1000;  1:推挽;0:开漏;
  	PA_CR2  = 0x00;  // 0000 0000;   

  	PB_DDR |= 0x10;  // 0001 0000;  1:输出;0:输入  (PB4_LED指示灯 推挽输出 110) 
  	PB_CR1 |= 0x30;  // 0011 0000;  1:推挽;0:开漏;
  	PB_CR2  = 0x00;  // 0000 0000;   

  	PC_DDR |= 0xF0;  // 0000 0000;  1:输出;0:输入  PA1 按键上拉输入;
  	PC_CR1 |= 0xF0;  // 1111 0000;  1:推挽;0:开漏;
  	PC_CR2  = 0x00;  // 0000 0100
  	
  	PD_DDR |= 0x0C;  // 0000 1100;  1:输出;0:输入 ( PA1_KEY 按键 上拉输入;)
 	PD_CR1 |= 0x0E;  // 0000 1110;  1:推挽;0:开漏;
  	PD_CR2  = 0x00;  // 0000 0000; 
	
	// 端口初始化设置;-----------------------------------------------------------------------------  
  	PA_ODR |= 0xFF;  // 0x3F: 1111 1111;  |= 将 PA端口全部置 1 (高电平 )
  	PB_ODR |= 0xFF;
  	PC_ODR |= 0xFF; 
	PD_ODR |= 0xFF;  	
}

void send_1(void)
{
	/////////////////////////////////////////////////////	
	u8 end_count 	= 3;		//发送 公共的 0.56ms 高电平
	IR  			= 1;
	u8 count   		= 0;
	u8 count0   	= 0;
	do
	{ 		
		IR = 1;
		Delay_13us(1); 	
		IR = 0;
		Delay_13us(1); 
		count++;
		if(count >= 8)
		{
			count = 0;
			count0 ++;	
		}	
	}
	while(count0 < end_count);
		
	/////////////////////////////////////////////////////
		
	end_count = 7;		//发送 底电平 0.56ms 1.125 ms 
	IR  = 0;
	count0    = 0;
	count0    = 0;
	do
	{
		count++;
		if(count >= 100)
		{
			count = 0;
			count0 ++;	
			}	
	}
	while(count0 < end_count);
}

//		send_1();  // 数据 0; 1.125
//		send_0();  // 数据 0; 2.25
void send_0(void)
{
	/////////////////////////////////////////////////////	
	u8 end_count = 3;		//发送 公共的 0.56ms 高电平
	IR  		 = 1;
	u8 count   	 = 0;
	u8 count0    = 0;
	do
	{ 		
		IR = 1;
		Delay_13us(1); 	
		IR = 0;
		Delay_13us(1); 
		count++;
		if(count >= 7)
		{
			count = 0;
			count0 ++;	
		}	
	}
	while(count0 < end_count);
		
	/////////////////////////////////////////////////////
		
	end_count = 21;		//发送 底电平 0.56ms 1.125 ms 
	IR  = 0;
	count0    = 0;
	count0    = 0;
	do
	{
		count++;
		if(count >= 100)
		{
			count = 0;
			count0 ++;	
		}	
	}
	while(count0 < end_count);
}

void send(u8 dat)
{
	u8 s = 0, user = 0, shu_ju = 0, hc = 0;
	u8 count0 = 0;
	
	/**********发送引导码**********************/
	end_count = 8;		// 发送 9ms 起始码的高电平
	IR  = 1;
	count     = 0;;
	do
	{ 		
		IR = 1;
		Delay_13us(1); 	
		IR = 0;
		Delay_13us(1); 
		count++;
		if(count >= 42)
		{
			count = 0;
			count0 ++;	
		}	
	}
	while(count0 < end_count);
	
	end_count = 53;		// 发送 4.5ms 结束码的低电平
	IR  = 0;
	count0    = 0;
	do
	{
		count++;
		if(count >= 100)
		{
			count = 0;
			count0 ++;	
		}	
	}
	while(count0 < end_count);
	
	/**********发送 系统 码***********************/
	user = system;
	for(u8 s = 0; s < 8; s++)
	{		
		hc = user & wy[s];		// 发送 脉冲 间距			
		if(hc == 0)
		{
			send_1();  			// 数据; 2.25
		}
		else
		{
			send_0();  			// 数据; 1.125 
		}
	}
	
	/********** 发送 系统 反码 ***********************/
	for(u8 s = 0; s < 8; s++)
	{	
		hc = user & wy[s];		//发送脉冲间距			
		if(hc == 0)
		{
			send_0();  // 数据; 1.125
		}
		else
		{
			send_1();  // 数据; 2.25
		}
	}

	/**********发送 客户 码 ***********************/
	user = 0x0C;
	for(u8 s = 0; s < 8; s++)
	{	
		hc = user & wy[s];	// 发送 脉冲 间距			
		if(hc == 0)
		{
			send_1();  		// 数据; 2.25
		}
		else
		{
			send_0();  		// 数据; 1.125
		}
	}

	/**********发送 客户 反码 ***********************/
	for(u8 s = 0; s < 8; s++)
	{	
		hc = user & wy[s];	// 发送 脉冲 间距			
		if(hc == 0)
		{
			send_0();  		// 数据; 1.125
		}
		else
		{
			send_1();  		// 数据; 2.25
		}
	}
	
	send_1();  				// 数据; 2.25

 } 
 
 

/**********************************************************************
* 函数: main()
* 功能: 主函数;
* 输入:  无;
* 输出:  无
***********************************************************************/
void main()
{
	
	asm("sim");      // disable all interrupt  EA=0;  // 关闭 中断;
	CLK_Init();             // 时钟初始化| 没有打开时钟计时,在需要时,才开启;
	// TIM1_Init(16000,1000);  // 定时器初始化| f=16M/16000=1kHz   time=1ms*1000=1s  
	GPIO_Init(); //
	asm("rim");    //enable all interrupt    EA=1; // 打开 中断;
	
//  	TIM1_CR1 |= 0x01;     //开始计数	      

	while(1)
	{
//		IR = 1;
////	LED = 1;
//		Delay_13us(1); 	
//		IR = 0;
////	LED = 0;
//		Delay_13us(1); 
//		khz_38();
		if(!KEY)
		{
			Delay_Nms(10);
			if(!KEY)
			{
				LED_Flash(1);
				send(0xFF);  // 发送 红外 编码; 
			}
		}		
	} 
}


联系我们

联系人:客服在线

手机:全工:13903011251

电话:李R:13530006400

邮箱:729986191@qq.com

地址: GUANGDONG PROVINCE

用手机扫描二维码关闭
二维码