基于STC89C52实现红外遥控功能_stc89c52rc单片机能实现红外遥控吗-程序员宅基地

技术标签: 51单片机  单片机  

实现一个红外遥控系统的基本要素包括红外发射器、红外接收器、解码器和单片机。
其中,红外发射器负责发送红外信号,红外接收器用来接收红外信号,解码器将红外信号解码成数字信号,而单片机则是用来处理数字信号并控制外设的。

本文章主要是实现红外遥控功能与红外遥控控制电机调速。

红外发射信号

首先,红外发射器发送的红外信号,是以38KHz的频率发送,用于区分外界自然持续发出的红外光。根据发送的数据内容不同,进行区分按下的按钮。
发送的红外信号遵循NEC红外协议编码

NEC红外编码协议具体来说,一个NEC遥控信号包含了以下内容:

  1.  帧头: 9ms的空闲时间,后面跟着4.5ms的载波信号,表示信号开始。
  2. 地址码: 由8位组成,表示接收设备的地址。可以用来区分不同的设备。
  3. 地址码的反码: 地址码的每一位都取反,用于校验
  4. 命令码: 由8位组成,表示具体的操作命令。比如开关机、音量调节等。
  5. 命令码的反码: 命令码的每一位都取反,用于校验。
  6. 结束位: 一个1.5ms的高电平,表示信号传输结束。

红外信号接收与解调

发送的红外信号被HS0038接收与解调。HS0038是一种常用的红外接收器芯片,它具有以下特点:

  • 1. 工作频率为38kHz,在NEC红外协议中得到广泛应用。
  • 2. 强抗干扰能力,能够滤除大部分的杂波干扰。
  • 3. 高灵敏度,能够接收到较远距离的红外信号。
  • 4. 具有内置解调器,能够自动将解调后的数字信号输出到引脚上,方便后续处理。
  • 5. 与常用的微控制器(如8051、AVR、PIC等)兼容。

 被HS0038解调后的数据被放在P32线上,发送给单片机,所以我们要通过编写程序分析在P32线上的数据,进行对遥控信号的处理,进而转为其他程序的驱动指令。

因为解调后的数据遵循NEC红外协议,所以我们只需要对信号的时间长短进行分析,则可以区分不同的信号内容。对信号时间长短进行分析,就需要使用到定时器与外部中断,定时器是记录中断前的信号时间长短,外部中断主要是在发完了一段信号后进行中断
(外部中断触发方式分为下降沿触发与低电平触发,在此处设为下降沿触发,因为在发完一段信号时,都伴随着一段下降沿,则可以在该下降沿进行中断,进而对中断前的一段信号发送的总时间进行记时,达到分析不同信号内容的目的)。
通过定时器与外部中断,就可以实现对不同段信号内容的读取。

代码实现(STC89C52)

所以我们先要分别对定时器与外部中断进行设置,以下是代码实现

定时器对一段时间的记录

#include <REGX52.H>

//定时器初始化
void Timer0Init(void)		
{
	TMOD &= 0xF0;		
	TMOD |= 0x01;		
	TL0 = 0;		
	TH0 = 0;		
	TF0 = 0;
	TR0 = 0;
}

//设置定时器初值函数
void Timer0_SetCounter(unsigned int Value)
{
	TH0 = Value/256;
	TL0 = Value%256;
}

//取得在该点处的记录的时间
unsigned int Timer0_GetCounter(void)
{
	return (TH0 << 8) | TL0;
}

//启动定时器
void Timer0_Run(unsigned char Flag)
{
	TR0 = Flag;
}

外部中断

#include <REGX52.H>

//外部中断0初始化
void Int0_Init(void)
{
	IT0 = 1;  //1为下降沿驱动,0为低电平驱动
	IE0 = 0;
	EX0 = 1;
	EA = 1;
	PX0 = 1;
}

//中断函数
/*
void Int0_Routine(void)  interrupt 0
{
	
}
*/


接下来就是在中断后对前段的信号内容进行处理,将定时器与外部中断集成在一个模块中

#include <REGX52.H>
#include "Int0.h"
#include "Timer0.h"

unsigned int IR_Time;					//计时
unsigned char IR_State;					//状态位

unsigned char IR_Data[4];				//零时存放32位Data数据

unsigned char IR_pData;					//指向32位数据的哪个位置

unsigned char IR_DataFlag;			//数据标志位
unsigned char IR_RepeatFlag; 		//结束标志位
unsigned char IR_Address;  			//存放数据
unsigned char IR_Command;  			//存放指令

//初始化
void IR_Init(void)
{
	Timer0Init();
	Int0_Init();
}

//用于判断是否取得数据
unsigned char IR_GetDataFlag(void)
{
	if(IR_DataFlag)
	{
		IR_DataFlag = 0;
		return 1;
	}
	return 0;
}

//判断是否结束
unsigned char IR_GetRepeat(void)
{
	if(IR_RepeatFlag)
	{
		IR_RepeatFlag = 0;
		return 1;
	}
	return 0;
}

//返回取得的数据
unsigned char IR_GetAddress(void)
{
	return IR_Address;
}

//返回取得的指令
unsigned char IR_GetCommand(void)
{
	return IR_Command;
}

void Int0_Routine(void) interrupt 0
{
	if(IR_State == 0)  //空闲时开始计数
	{
		Timer0_SetCounter(0);
		Timer0_Run(1);
		IR_State = 1;
	}
	else if(IR_State == 1)  //计数完成后开始分析
	{
		
		IR_Time = Timer0_GetCounter();
		Timer0_SetCounter(0);
		if(IR_Time > 13500 - 600 && IR_Time < 13500 + 600) //检测到Start
		{
			//转为对Data记录处理
			IR_State = 2;
		}
		else if(IR_Time > 11250 - 600 && IR_Time < 11250 + 600)  //检测到Repeat
		{
			IR_RepeatFlag = 1;
			Timer0_Run(0);
			IR_State = 0;
		}
		else
		{
			IR_State = 1;
		}
	}
	else if(IR_State == 2)
	{
		IR_Time = Timer0_GetCounter();
		Timer0_SetCounter(0);
		
		if(IR_Time > 1120 - 600 && IR_Time < 1120 + 600)  //检测到0
		{
			//IR_Data[4]将原本的32位数据用四个八位存放,
                        所以要精确的找到对应数组元素的对应位数进行改变
			//因为IR_pData最大只能到达32,所以IR_pData/8的范围只有0~4,,IR_pData%8的范围为0~7
			IR_Data[IR_pData/8] &= ~(0x01 << (IR_pData%8));  //对应位清零
			IR_pData++;
		}
		else if(IR_Time > 2250 - 600 && IR_Time < 2250 + 600)  //检测到1
		{
			IR_Data[IR_pData/8] |= (0x01 << (IR_pData%8));  //对应位清零
			IR_pData++;
		}
		else
		{
			IR_pData = 0;
			IR_State = 1;
		}
		if(IR_pData >= 32)
		{
			IR_pData = 0;
			if((IR_Data[0] == ~IR_Data[1]) && (IR_Data[2] == ~IR_Data[3]))  
                //如果满足NEC红外协议中的Data格式
			{
				IR_Address = IR_Data[0];
				IR_Command = IR_Data[2];
				IR_DataFlag = 1;
			}
			Timer0_Run(0);
			IR_State = 0;
		}
	}
}

 综上就实现了最简单的红外遥控功能


下面是通过红外遥控控制电机速度(前置知识PWM)

//定时器1初始化
#include <REGX52.H>


void Timer1Init(void)		
{
	TMOD &= 0x0F;		
	TMOD |= 0x10;		
	TL1 = 0xF4;		//设置定时初值
	TH1 = 0xFF;		//设置定时初值
	TF1 = 0;		
	TR1 = 1;		
	
	ET1 = 1;
	EA = 1;
	PT1 = 0;
}

//

//main.c

#include <REGX52.H>
#include "IR.h"
#include "Timer1.h"


unsigned char Counter,Compare;
unsigned char Command;



void main()
{
	P1 = 0;
		
	IR_Init();
	Timer1Init();
	
	while(1)
	{
		if(IR_GetDataFlag())
		{
            //通过接收不同的指令去执行不同的速度
			Command = IR_GetCommand();
			
			if(Command == 0x16)
			{
				Compare = 0;
			}
			if(Command == 0x0C)
			{
				Compare = 50;
			}
			if(Command == 0x18)
			{
				Compare = 75;
			}
			if(Command == 0x5E)
			{
				Compare = 100;
			}
		}
		
	}
}


void Timer1_Rountine(void) interrupt 3
{
	TL1 = 0xF4;		//设置定时初值
	TH1 = 0xFF;		//设置定时初值

	Counter++;
	Counter %= 100;
	if(Counter >= Compare)
	{
		P1_0 = 0;
	}
	if(Counter < Compare)
	{
		P1_0 = 1;
	}

}

遥控器键码

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yoyoyoyoy6/article/details/131706946

智能推荐

while循环&CPU占用率高问题深入分析与解决方案_main函数使用while(1)循环cpu占用99-程序员宅基地

文章浏览阅读3.8k次,点赞9次,收藏28次。直接上一个工作中碰到的问题,另外一个系统开启多线程调用我这边的接口,然后我这边会开启多线程批量查询第三方接口并且返回给调用方。使用的是两三年前别人遗留下来的方法,放到线上后发现确实是可以正常取到结果,但是一旦调用,CPU占用就直接100%(部署环境是win server服务器)。因此查看了下相关的老代码并使用JProfiler查看发现是在某个while循环的时候有问题。具体项目代码就不贴了,类似于下面这段代码。​​​​​​while(flag) {//your code;}这里的flag._main函数使用while(1)循环cpu占用99

【无标题】jetbrains idea shift f6不生效_idea shift +f6快捷键不生效-程序员宅基地

文章浏览阅读347次。idea shift f6 快捷键无效_idea shift +f6快捷键不生效

node.js学习笔记之Node中的核心模块_node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是-程序员宅基地

文章浏览阅读135次。Ecmacript 中没有DOM 和 BOM核心模块Node为JavaScript提供了很多服务器级别,这些API绝大多数都被包装到了一个具名和核心模块中了,例如文件操作的 fs 核心模块 ,http服务构建的http 模块 path 路径操作模块 os 操作系统信息模块// 用来获取机器信息的var os = require('os')// 用来操作路径的var path = require('path')// 获取当前机器的 CPU 信息console.log(os.cpus._node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是

数学建模【SPSS 下载-安装、方差分析与回归分析的SPSS实现(软件概述、方差分析、回归分析)】_化工数学模型数据回归软件-程序员宅基地

文章浏览阅读10w+次,点赞435次,收藏3.4k次。SPSS 22 下载安装过程7.6 方差分析与回归分析的SPSS实现7.6.1 SPSS软件概述1 SPSS版本与安装2 SPSS界面3 SPSS特点4 SPSS数据7.6.2 SPSS与方差分析1 单因素方差分析2 双因素方差分析7.6.3 SPSS与回归分析SPSS回归分析过程牙膏价格问题的回归分析_化工数学模型数据回归软件

利用hutool实现邮件发送功能_hutool发送邮件-程序员宅基地

文章浏览阅读7.5k次。如何利用hutool工具包实现邮件发送功能呢?1、首先引入hutool依赖<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version></dependency>2、编写邮件发送工具类package com.pc.c..._hutool发送邮件

docker安装elasticsearch,elasticsearch-head,kibana,ik分词器_docker安装kibana连接elasticsearch并且elasticsearch有密码-程序员宅基地

文章浏览阅读867次,点赞2次,收藏2次。docker安装elasticsearch,elasticsearch-head,kibana,ik分词器安装方式基本有两种,一种是pull的方式,一种是Dockerfile的方式,由于pull的方式pull下来后还需配置许多东西且不便于复用,个人比较喜欢使用Dockerfile的方式所有docker支持的镜像基本都在https://hub.docker.com/docker的官网上能找到合..._docker安装kibana连接elasticsearch并且elasticsearch有密码

随便推点

Python 攻克移动开发失败!_beeware-程序员宅基地

文章浏览阅读1.3w次,点赞57次,收藏92次。整理 | 郑丽媛出品 | CSDN(ID:CSDNnews)近年来,随着机器学习的兴起,有一门编程语言逐渐变得火热——Python。得益于其针对机器学习提供了大量开源框架和第三方模块,内置..._beeware

Swift4.0_Timer 的基本使用_swift timer 暂停-程序员宅基地

文章浏览阅读7.9k次。//// ViewController.swift// Day_10_Timer//// Created by dongqiangfei on 2018/10/15.// Copyright 2018年 飞飞. All rights reserved.//import UIKitclass ViewController: UIViewController { ..._swift timer 暂停

元素三大等待-程序员宅基地

文章浏览阅读986次,点赞2次,收藏2次。1.硬性等待让当前线程暂停执行,应用场景:代码执行速度太快了,但是UI元素没有立马加载出来,造成两者不同步,这时候就可以让代码等待一下,再去执行找元素的动作线程休眠,强制等待 Thread.sleep(long mills)package com.example.demo;import org.junit.jupiter.api.Test;import org.openqa.selenium.By;import org.openqa.selenium.firefox.Firefox.._元素三大等待

Java软件工程师职位分析_java岗位分析-程序员宅基地

文章浏览阅读3k次,点赞4次,收藏14次。Java软件工程师职位分析_java岗位分析

Java:Unreachable code的解决方法_java unreachable code-程序员宅基地

文章浏览阅读2k次。Java:Unreachable code的解决方法_java unreachable code

标签data-*自定义属性值和根据data属性值查找对应标签_如何根据data-*属性获取对应的标签对象-程序员宅基地

文章浏览阅读1w次。1、html中设置标签data-*的值 标题 11111 222222、点击获取当前标签的data-url的值$('dd').on('click', function() { var urlVal = $(this).data('ur_如何根据data-*属性获取对应的标签对象

推荐文章

热门文章

相关标签