实现一个红外遥控系统的基本要素包括红外发射器、红外接收器、解码器和单片机。
其中,红外发射器负责发送红外信号,红外接收器用来接收红外信号,解码器将红外信号解码成数字信号,而单片机则是用来处理数字信号并控制外设的。
本文章主要是实现红外遥控功能与红外遥控控制电机调速。
首先,红外发射器发送的红外信号,是以38KHz的频率发送,用于区分外界自然持续发出的红外光。根据发送的数据内容不同,进行区分按下的按钮。
发送的红外信号遵循NEC红外协议编码
NEC红外编码协议具体来说,一个NEC遥控信号包含了以下内容:
发送的红外信号被HS0038接收与解调。HS0038是一种常用的红外接收器芯片,它具有以下特点:
被HS0038解调后的数据被放在P32线上,发送给单片机,所以我们要通过编写程序分析在P32线上的数据,进行对遥控信号的处理,进而转为其他程序的驱动指令。
因为解调后的数据遵循NEC红外协议,所以我们只需要对信号的时间长短进行分析,则可以区分不同的信号内容。对信号时间长短进行分析,就需要使用到定时器与外部中断,定时器是记录中断前的信号时间长短,外部中断主要是在发完了一段信号后进行中断
(外部中断触发方式分为下降沿触发与低电平触发,在此处设为下降沿触发,因为在发完一段信号时,都伴随着一段下降沿,则可以在该下降沿进行中断,进而对中断前的一段信号发送的总时间进行记时,达到分析不同信号内容的目的)。
通过定时器与外部中断,就可以实现对不同段信号内容的读取。
所以我们先要分别对定时器与外部中断进行设置,以下是代码实现
定时器对一段时间的记录
#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;
}
}
遥控器键码
文章浏览阅读3.8k次,点赞9次,收藏28次。直接上一个工作中碰到的问题,另外一个系统开启多线程调用我这边的接口,然后我这边会开启多线程批量查询第三方接口并且返回给调用方。使用的是两三年前别人遗留下来的方法,放到线上后发现确实是可以正常取到结果,但是一旦调用,CPU占用就直接100%(部署环境是win server服务器)。因此查看了下相关的老代码并使用JProfiler查看发现是在某个while循环的时候有问题。具体项目代码就不贴了,类似于下面这段代码。while(flag) {//your code;}这里的flag._main函数使用while(1)循环cpu占用99
文章浏览阅读347次。idea shift f6 快捷键无效_idea shift +f6快捷键不生效
文章浏览阅读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模块中有很多核心模块,以下不属于核心模块,使用时需下载的是
文章浏览阅读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回归分析过程牙膏价格问题的回归分析_化工数学模型数据回归软件
文章浏览阅读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发送邮件
文章浏览阅读867次,点赞2次,收藏2次。docker安装elasticsearch,elasticsearch-head,kibana,ik分词器安装方式基本有两种,一种是pull的方式,一种是Dockerfile的方式,由于pull的方式pull下来后还需配置许多东西且不便于复用,个人比较喜欢使用Dockerfile的方式所有docker支持的镜像基本都在https://hub.docker.com/docker的官网上能找到合..._docker安装kibana连接elasticsearch并且elasticsearch有密码
文章浏览阅读1.3w次,点赞57次,收藏92次。整理 | 郑丽媛出品 | CSDN(ID:CSDNnews)近年来,随着机器学习的兴起,有一门编程语言逐渐变得火热——Python。得益于其针对机器学习提供了大量开源框架和第三方模块,内置..._beeware
文章浏览阅读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.._元素三大等待
文章浏览阅读3k次,点赞4次,收藏14次。Java软件工程师职位分析_java岗位分析
文章浏览阅读2k次。Java:Unreachable code的解决方法_java unreachable code
文章浏览阅读1w次。1、html中设置标签data-*的值 标题 11111 222222、点击获取当前标签的data-url的值$('dd').on('click', function() { var urlVal = $(this).data('ur_如何根据data-*属性获取对应的标签对象