RYMCU

NO15.红外线通信实验-NEBULA-VSCODE

devcui 2 年前
# nebula-vscode

所属作品集

1.什么是红外通信

无线,非接触式数据传输技术,将信息加入红外光波中,利用发射装置发射,接收设备收到红外光后,将信息解码并做出相应操作。

2.NEC

将信息附加到红外光上涉及到红外编码协议
常见的有 Philips,RC-5Protocol,Sharp,NEC
NEC 协议中如何表示 0 或 1 呢

image.png

0: 560us 的连续载波 +560us 的低电平,总时长为 1.125ms
1: 560us 的连续载波 +1680us 的高电平,总时常为 2.25ms

传输一贞 NEC 格式的数据包括以下内容:

image.png

  1. 同步码头: 9ms 载波 +4.5ms 高电平
  2. 用户码: 用户自定义的 8bit 数据
  3. 用户反码: 8bit 用户码按位取反
  4. 数据码: 8bit 数据,也称为 8 位按键数据码
  5. 数据反码: 8bit 数据码按位取反

3.红外接收电路图

image.png

OUT 在 P33 上

4.红外解码

红外解码步骤

    1. 初始化外部中断 1 下降沿触发
    1. 外部中断 1 判断引导码的正确性,判断方法为通过定时器的计数器计算高低电平持续时间,并与引导码做对比
    1. 超出了规定时间范围,不是一贞标准的红外数据,直接跳出中断子程序
    1. 验证符合要求后,判断和接收 4 个字节的数据,将接收的数据放到指定的存储变量中,并置位红外标志位
    1. 在主程序中查询标志位是否收到了红外数据,将变量取出,进行相关联的操作

4.1 回顾 中断和定时器

4.1.1 TMOD 定时器

https://rymcu.com/article/173

image.png

image.png

image.png

4.1.2 中断

https://rymcu.com/article/177

image.png

image.png

image.png

4.1.3 程序

好了,直接写程序

首先目录结构

image.png

1602 从之前的复制过来就好

infrared.h

/*
 * @Author: cuihaonan
 * @Email: devcui@outlook.com
 * @Date: 2021-04-04 22:56:46
 * @LastEditTime: 2021-04-05 14:57:29
 * @LastEditors: cuihaonan
 * @Description: Basic description
 * @FilePath: /sdcc-include/src/ir/include/infrared.h
 * @LICENSE: NONE
 */

#ifndef __IR_H__
#define __IR_H__

// 初始化TR0,外部中断1
extern void InitIR();
// 按键标志位
extern unsigned char Flag_IR;
// 4个自己的数据 [31:0] 数据反码,数据码,用户反码,用户码
extern unsigned long Data_IR;
// 计算时长
extern unsigned int T_Count(unsigned int flag);
// 等待信号输入
extern void WaitRed(void);

#define HIGH_IR 1
#define LOW_IR 0
#define Min_9ms 8000
#define Max_9ms 10000
#define Min_4_5ms 3500
#define Max_4_5ms 5000
#define Min_560us 300
#define Max_560us 700
#define Min_1680us 1300
#define Max_1680us 1800
#define Time_16ms 16000

#endif

infrared.c

/*
 * @Author: cuihaonan
 * @Email: devcui@outlook.com
 * @Date: 2021-04-04 23:09:09
 * @LastEditTime: 2021-04-05 14:56:56
 * @LastEditors: cuihaonan
 * @Description: Basic description
 * @FilePath: /sdcc-include/src/ir/include/infrared.c
 * @LICENSE: NONE
 */

#include "../../../include/STC89xx.h"
#include "./infrared.h"

// LED
SBIT(LED1, _P1, 1);
// 红外接收引脚
SBIT(IR_out, _P3, 3);
// 红外接收标志位
unsigned char Flag_IR = 0;
// 数据位
unsigned long Data_IR;

// 初始化TR0,外部中断1
void InitIR()
{
    // -------IR
    // IR初始化
    IR_out = 1;

    // -------T0
    // 由于是头文件,所以不知道TMOD里面是什么情况,但是后面的M1,M0不变,所以初始化先清除后几位
    TMOD &= 0xF0;
    // timer0 初始化
    // M1=0,M0=1模式,TH0,TL0合并位16位定时器
    // 这里用 |= 也是为了保证前面的不变
    TMOD |= 0x01;
    // 结束中断
    TR0 = 0;
    // 关闭定时器0中断
    ET0 = 0;

    // 装载计数器目标值
    TL0 = 12;
    TH0 = 34;

    // ------INT1
    // 下降沿触发
    IT1 = 1;
    // IT1中断开
    EX1 = 1;
    // 总中断开
    EA = 1;
}

unsigned int T_Count(unsigned int flag)
{
    // 清除TH0,TL0
    TH0 = 0;
    TL0 = 0;
    // 开定时器0中断
    TR0 = 1;
    // 判断IR引脚是否等同于flag
    // 如果等同于flag
    while (IR_out == flag)
    {
        // 比较计时器高8位和16ms高8位
        // 如果超过了16ms跳出循环
        if (TH0 > (Time_16ms >> 8))
        {
            break;
        }
    }
    // 关闭定时器0
    TR0 = 0;
    // 返回结果
    // TH0 高8位 * 256 + TL0 低八位
    return (TH0 * 256 + TL0);
}

void WaitRed()
{
    unsigned int i;
    unsigned int T_Low;
    unsigned int T_High;
    // 用户码 头 9ms载波 + 4.5ms 高电平
    // 9ms引导码的低电平
    T_Low = T_Count(LOW_IR);
    // 4.5ms引导码的高电平
    T_High = T_Count(HIGH_IR);

    // 判断引导码是否正确
    // 比较1.09us的次数,推算出时常
    if (T_Low < Min_9ms || T_Low > Max_9ms || T_High < Min_4_5ms || T_High > Max_4_5ms)
    {
        // I重置INT1 中断
        IE1 = 0;
        return;
    }
    // 接收4个字节数据,共计32位
    // 第一个字节 用户码
    // 第二个字节 用户反码
    // 第三个字节 数据码
    // 第四个字节 数据反码
    for (i = 0; i < 32; i++)
    {
        // 560us 低电平
        T_Low = T_Count(LOW_IR);
        // 560us/1680us高电平
        T_High = T_Count(HIGH_IR);
        // 判断位电平正确性
        if (T_Low < Min_560us || T_Low > Max_560us || T_High < Min_560us || T_High > Max_1680us)
        {
            // 重置IINT1中断
            IE1 = 0;
            return;
        }
        // 高位补0
        Data_IR >>= 1;
        if (T_High > Min_1680us)
        {
            // 取数据
            Data_IR |= 0x80000000;
        }
    }
    // 接收完毕,置位(存一个值)
    Flag_IR = 1;
    // 重置INT1中断
    IE1 = 0;
}

main.c

/*
 * @Author: cuihaonan
 * @Email: devcui@outlook.com
 * @Date: 2021-04-05 00:49:37
 * @LastEditTime: 2021-04-05 15:03:23
 * @LastEditors: cuihaonan
 * @Description: Basic description
 * @FilePath: /sdcc-include/src/ir/main.c
 * @LICENSE: NONE
 */
#include "./include/1602.h"
#include "./include/infrared.h"
#include "../../include/STC89xx.h"
#include "../../include/mcs51/lint.h"

unsigned char *Key_Str = 0;

void main()
{
    P10 = 1;
    unsigned char Key;
    Init_1602();
    InitIR();
    Disp_1602_str(1, 2, "Nebula-Pi IR");
    Disp_1602_str(2, 1, "KEY: ");
    while (1)
    {
        // 如果接收到32位被验证过的值了
        if (Flag_IR)
        {
            // 先置0
            Flag_IR = 0;
            // 首先,低位先存,所以数据码和反码在最前面16位
            // 32位 右移16,获取到数据码和数据反码
            Key = (unsigned char)(Data_IR >> 16);
            switch (Key)
            {
            case 69:
                Key_Str = "CH-";
                break;
            case 70:
                Key_Str = "CH";
                break;
            case 71:
                Key_Str = "CH+";
                break;
            case 68:
                Key_Str = "PREV";
                break;
            case 64:
                Key_Str = "NEXT";
                break;
            case 67:
                Key_Str = "PLAY/PAUSE";
                break;
            case 7:
                Key_Str = "-";
                break;
            case 21:
                Key_Str = "+";
                break;
            case 9:
                Key_Str = "EQ";
                break;
            case 22:
                Key_Str = "0";
                break;
            case 25:
                Key_Str = "100+";
                break;
            case 13:
                Key_Str = "200+";
                break;
            case 12:
                Key_Str = "1";
                break;
            case 24:
                Key_Str = "2";
                break;
            case 94:
                Key_Str = "3";
                break;
            case 8:
                Key_Str = "4";
                break;
            case 28:
                Key_Str = "5";
                break;
            case 90:
                Key_Str = "6";
                break;
            case 66:
                Key_Str = "7";
                break;
            case 82:
                Key_Str = "8";
                break;
            case 74:
                Key_Str = "9";
                break;
            default:
                Key_Str = "error!";
            }
            Disp_1602_str(2,5,"             ");
            Disp_1602_str(2, 5, Key_Str);
        }
    }
}

void wait2() __interrupt(2)
{
    if (P10 == 0)
    {
        P10 = 1;
    }
    else
    {
        P10 = 0;
    }
    WaitRed();
}

所属作品集

后发布评论
devcui 回复了 社区风纪委员会

闪回?

哈哈哈哈哈哈哈哈 失而复得