0%

基于STC8G单片机的红外发射接收程序

基于STC8G单片机的红外发射接收程序

转载自tslids

题外话:因半导体价格涨幅较大和国外形势,开始考虑尽量使用国产芯片(支持国货),先从单片机开始,目前暂定要求不高的场合选择应用较多的STC系列,其中STC8G和STC8H系列为STC主推的型号。
注:程序大部分来源于网络,并做了较大幅度的修改,原因是不是用于红外数据传输,而是作为光电开关来用。
​ 参考NEC编码做了简化,便于延长发射管寿命。
​ 发射管为IR204、接收头为IRM-H638T/TR2、单片机为STC8G1K08A。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#include  "STC8.h"		
#include "intrins.h" //使用nop()函数需引用此文件

#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;

//280us @11.0592MHz
#define T1_START() TL1 = 0xE7; \
TH1 = 0xF3; \
ET1 = 1; \
TR1 = 1
//引脚定义
sbit LED=P5^4; //指示灯
sbit IR_IO=P3^3; //红外发射
//sbit KEY=P5^5; //按键
//数据定义
bit IR_Flag=0; //红外数据接收完成标志位
u8 IR_time=0; //下降沿之间的时间计数值
u8 IR_data[9]; //引导码+8个位数据各自占用的时间
bit IR_TimeFlag; //红外发射延时到标志
unsigned char count; //280us
#define IR_SENDDATA 0X05 //红外发射的数据
static u8 IR_bit; //变量IR_bit用于指示红外数据的位数
//函数声明
void delay(u16 count); //延时函数声明
void Time0_init(void); //定时计数器0初始化函数
void Time1_init(void); //定时计数器1初始化函数
void Int0_init(void); //外部中断0初始化函数
u8 IR_decode(void); //红外解码函数

//-------------------------红外发送高电平----------------------------
void Wait_High(a)//a*280uS
{
unsigned char k;
IR_TimeFlag = 0;
count = a;
T1_START();
while(!IR_TimeFlag) //38khz载波
{
_nop_();
_nop_();
k = 23;
while (--k);
IR_IO = ~IR_IO;
}
IR_IO = 1;
}
//-------------------------红外发送低电平----------------------------
void Wait_Low(a)//a*280uS
{
IR_IO = 1;
IR_TimeFlag = 0;
count = a;
T1_START();
while(!IR_TimeFlag);
}
//-------------------------红外发送单字节数据----------------------------
void Send_IR(u8 dat)
{
unsigned char i,j;
Wait_High(2);//0.56ms
Wait_Low(4);//1.12ms

for(j=0;j<8;j++)
{
Wait_High(1);//0.28ms
if(dat&0x01)
{
Wait_Low(2);// 0.56ms
}
else
{
Wait_Low(1);//0.28ms
}
dat = dat>>1;
}

Wait_High(1);//0.28ms
}
//-------------------------主函数----------------------------
void main(void)
{
u8 num=0;
//STC8G系列单片机除P3.0和P3.1外,所有I/O上电均为高阻输入状态,需先配置再使用
P3M0 |=0x08; //P3.3引脚为推挽输出模式
P3M1 &=0xF7; //P3.3引脚为推挽输出模式
RSTCFG &=0xEF; //复位引脚P5.4当做普通I/O引脚
P5M0 |=0x10; //P5.4引脚为推挽输出模式
P5M1 &=0xEF; //P5.4引脚为推挽输出模式
P5M0 &=0xDF; //P5.5引脚为准双向口模式
P5M1 &=0xDF; //P5.5引脚为准双向口模式

Time0_init(); //定时计数器0初始化函数
Time1_init(); //定时计数器1初始化函数
Int0_init(); //外部中断0初始化函数
EA = 1; //开中断
delay(100); //等待配置稳定

IR_IO = 1; //红外发射置高
while(1)
{
Send_IR(IR_SENDDATA); //红外发送数据
delay(20000);
if(IR_Flag) //红外数据接收完成
{
IR_Flag=0;
if(IR_decode() == IR_SENDDATA) LED = ~LED;//红外接收正确改变指示灯状态
}
}
}
//-------------------------延时函数----------------------------
void delay(u16 count)
{
while(count--)
{
_nop_();
}
}
//-------------------------定时器0初始化----------------------------
void Time0_init(void) //139微秒@11.0592MHz
{
AUXR &= 0x7F; //定时器时钟12T模式,工作方式2
TMOD &= 0xF0;
TMOD |= 0x02;
TL0 = 0x80;
TH0 = 0x80;
TF0 = 0; //清除标志
ET0 = 1; //使能T0中断
TR0 = 1; //启动T0
}
//-------------------------定时器1初始化---------------------------
void Time1_init(void) //278微秒@11.0592MHz
{
AUXR |= 0x40;//模式2 1T
TMOD &= 0x0F;
}
//-------------------------外部中断0初始化-------------------------
void Int0_init(void)
{
IT0 = 1; //触发方式为下降沿触发
EX0 = 1; //使能INT0中断
}
//-------------------------红外接收解码-------------------------
u8 IR_decode(void)
{
u8 j,k;
u8 IR_Value = 0;
k=1; //先让变量k等于1,因为k为0时取出的将会是“引导码的时间间隔”

for(j=0;j<=7;j++) //内层循环8次为了拼合8个数据位为1个字节
{
if(IR_data[k]>5) //若“时间间隔”比5大那肯定是“1码”反之为“0码”
IR_Value|=0x80; //通过按位或运算高位填1
if(j<7) //若数据没有拼合完8次
IR_Value>>=1; //通过右移运算“腾出”位置准备下一位判定
k++; //下标变量自增
}
return IR_Value; //返回红外接收的数据
}
//-------------------------外部中断0服务函数-------------------------
void INT0_ISR() interrupt 0
{
if(IR_time>8) //判断引导码(0.56ms+1.12ms)
IR_bit=0; //清除位数变量,确保当前IR_bit为0,表示引导码
IR_data[IR_bit]=IR_time; //存储相应位时间宽度
IR_time=0; //清零时间宽度计数值
IR_bit++; //位数变量自增
if(IR_bit==9) //如果达到了9位(引导码+8个数据位)
{
IR_Flag=1; //红外数据接收完成标志位置1
IR_bit=0; //位数变量清零
}
}
//-------------------------定时器0中断服务函数-------------------------
void TIMER0_ISR() interrupt 1
{
IR_time++;
}
//-------------------------定时器1中断服务函数-------------------------
void TIMER1_ISR() interrupt 3
{
count--;
if(count == 0)
{
IR_TimeFlag = 1;
ET1 = 1;//
}
}