概要
STC8G1K08A使用PCA模块红外遥控发射案例,使用PCA模块产生38khz稳定信号,按照NEC协议,控制38khz信号的开关,从而达到红外发送数据的目的。
技术名词解释
- NEC协议
上图已经是解码过的了,控制信号就应像上面这个这样,然后低电平时输出的就是38khz的信号。
所以我们的任务就是产生一个上述控制信号和一个38khz信号接到下面电路的两个三极管(s8550)上就行!
- 电路图
由于pca模块的频率并不是随心所欲设置,所以会在38khz附近,但通过接收头手册可知,这个频率在一定范围内都是可行的(如下图所示)
技术细节
下面我们直接用代码来展示整个过程:
- main.c
#include <STC8G.H>
#include "Timer0.h"
#include "Key.h"
#include "Infr.h"
//注:本案例使用了stc8g1k0a的CCAPM2的P54口作为38khz信号
//通过P54的38khz和P55的开关信号产生NEC协议的相关时序
//所以必须使用相关的电路配合使用,
//如案例的两个pnp型三极管控制红外发射管
unsigned char temp,keynum;//按键变量
//按下四个按键发送不同的数据
void Key_Scan(void)
{
temp=Key();
if(temp)
{
keynum=temp;
switch(keynum)
{
case 1:
Send_Byte(0x00,0x55);
keynum=0;
break;
case 2:
Send_Byte(0x00,0x66);
keynum=0;
break;
case 3:
Send_Byte(0x00,0x77);
keynum=0;
break;
case 4:
Send_Byte(0x00,0x88);
keynum=0;
break;
}
}
}
void main(void)
{
P3M0 = 0x00; // 将P3配置为准双向口
P3M1 = 0x00;
P5M0 = 0xff; // 将P5口配置为推挽输出
P5M1 = 0x00;
/*********配置pca进而产生一个38khz左右信号***************/
CCON=0x00;//停止PCA计数
CMOD=0x04;//PCA计数脉冲设为定时器0的溢出脉冲
CL= 0x00;
CH= 0x00;
CCAPM2=0x42; //PCA模块2为PWM工作模式
PCA_PWM2=0x80; //PCA模块2输出6位PWM
CCAP2L=0x20;//PWM占空比(40H-38H)/40H
CCAP2H=0x20;//溢出时自动填装到CCAP0L里,实现无干扰更新
CR=1;//启动PCA计数
Timer0_Init();//定时器初始化
while(1)
{
Key_Scan();
}
}
void Timer0_Isr(void) interrupt 1
{
//用于PCA模块的频率输入
//0.83333x5=4.17微秒@12.000MHz
//pwm频率为37.5Khz
}
void Timer1_Isr(void) interrupt 3
{
static unsigned int T1Count1;
T1Count1++;//每1ms进行一次++;
if(T1Count1>=15)//20ms调用一次Key_Loop()函数
{
T1Count1=0;
Key_Loop();
}
}
- Infr.c
#include <STC8G.H>
//注:该文件只是输出开关38khz的控制信号,还需另外一个信号源产生38khz信号
//本案例中使用stc8g1k08a的pca模块产生!
/**
* @brief 红外时序延时函数//@12.000MHz
* @param x10us 延时多少个10us
* @retval 无
*/
void Delay_x10us(unsigned int x10us) //@12.000MHz
{
unsigned char data i;
while(x10us)
{
i = 38;
while (--i);
x10us--;
}
}
/**
* @brief 红外发射信号
* @param address 发送的地址
* @param command 发送的命令/数据
* @retval 无
*/
void Send_Byte(unsigned char address,unsigned char command)
{
unsigned char i,j=0x01;
P55=1;
P55=0;
Delay_x10us(845);
P55=1;
Delay_x10us(415);
P55=0;
for(i=0,j=0x01;i<8;i++)
{
if((address & j)==0)
{
Delay_x10us(52);
P55=1;
Delay_x10us(52);
P55=0;
}
else
{
Delay_x10us(52);
P55=1;
Delay_x10us(155);
P55=0;
}
j=j<<1;
}
for(i=0,j=0x01;i<8;i++)
{
if((address & j)==0)
{
Delay_x10us(52);
P55=1;
Delay_x10us(155);
P55=0;
}
else
{
Delay_x10us(52);
P55=1;
Delay_x10us(52);
P55=0;
}
j=j<<1;
}
for(i=0,j=0x01;i<8;i++)
{
if((command & j)==0)
{
Delay_x10us(52);
P55=1;
Delay_x10us(52);
P55=0;
}
else
{
Delay_x10us(52);
P55=1;
Delay_x10us(155);
P55=0;
}
j=j<<1;
}
for(i=0,j=0x01;i<8;i++)
{
if((command & j)==0)
{
Delay_x10us(52);
P55=1;
Delay_x10us(155);
P55=0;
}
else
{
Delay_x10us(52);
P55=1;
Delay_x10us(52);
P55=0;
}
j=j<<1;
}
P55=1;
}
- Timer0.c
#include <STC8G.H>
/**
* @brief 定时器初始化
* @param 无
* @retval 无
*/
void Timer0_Init(void) //313微秒@12.000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL0 = 0xFB; //设置定时初始值
TH0 = 0xFF; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
TL1 = 0x20; //设置定时初始值
TH1 = 0xD1; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1; //使能定时器1中断
EA=1;
PT1=0;
}
- Key.c
#include <STC8G.H>
unsigned char Key_KeyNumber;
/**
* @brief 外部调用主函数
* @param 无
* @retval Temp 传出在loop函数中得到的Key_KeyNumber值;
*/
unsigned char Key(void)
{
unsigned char Temp=0;
Temp=Key_KeyNumber;
Key_KeyNumber=0;//对全局变量清0,防止下次中断进来
//没按键按下仍传出上次按键值
return Temp;
}
/**
* @brief 定时器按周期进来一次则检测四个按键是否有按下的
* @param 无
* @retval keyNumber得到键值在loop中调用并返回值给NowState
*/
unsigned char Key_GetState()
{
unsigned char keyNumber=0;
if(P30==0)keyNumber=1;
if(P31==0)keyNumber=2;
if(P32==0)keyNumber=3;
if(P33==0)keyNumber=4;
return keyNumber;
}
/**
* @brief 定时器周期扫描函数
* @param 无
* @retval 无
*/
void Key_Loop(void)
{
static unsigned char NowState,LastState;//静态变量防止下次进来销毁
LastState=NowState;
NowState=Key_GetState(); //调用按键按下函数,并把按下的值赋给NowState
if(LastState==1 && NowState==0)//如果上次为1按下状态,这次为松开状态0则可以确定1键按下了
{
Key_KeyNumber=1; //把得到的键值从中断中传出,放到全局变量Key_KeyNumber中
}
if(LastState==2 && NowState==0)
{
Key_KeyNumber=2;
}
if(LastState==3 && NowState==0)//如果上次为1按下状态,这次为松开状态0则可以确定1键按下了
{
Key_KeyNumber=3; //把得到的键值从中断中传出,放到全局变量Key_KeyNumber中
}
if(LastState==4 && NowState==0)//如果上次为1按下状态,这次为松开状态0则可以确定1键按下了
{
Key_KeyNumber=4; //把得到的键值从中断中传出,放到全局变量Key_KeyNumber中
}
}
- Infr.h
#ifndef __INFR_H__
#define __INFR_H__
//注:该文件只是输出开关38khz的控制信号,还需另外一个信号源产生38khz信号
//本案例中使用stc8g1k08a的pca模块产生!
void Send_Byte(unsigned char address,unsigned char command);
#endif
- Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0_Init(void);
#endif
- Key.h
#ifndef __KEY_H__
#define __KEY_H__
unsigned char Key(void);
void Key_Loop(void);
#endif
小结
本案例通过软硬件的结合实现了红外遥控信号的发射功能。欢迎大家交流指正!