zoukankan      html  css  js  c++  java
  • 【鸿蒙开发】俄罗斯方块 += 遥控器

    目录:

    一、红外遥控器原理(简述)

    二、解析原理

    三、同时也实现了红外编码

    四、源码包

    Hi3861解码红外遥控器

    红外遥控器是个很实用的键盘扩展,即能扩展键盘还能远程操作!

    首先在我的小游戏上试一下!

    先前发布的小游戏:https://harmonyos.51cto.com/posts/1995#kyzg

    先上图:

    视频:因为需要审核稍后再上!

    一、红外遥控器原理(简述)

    红外遥控器是通过940nm-950nm的红外线传输的,载波频率是38K,传输协议也比较简单:

    首先发送一个9ms的引导码,引起接收方注意,我要发送数据了!
    停止4.5ms;
    开始发送数据(发560us停560us代表一个bit 0,发560us停1680us代表发送一个bit 1);
    每次传输发送4个字节 0-15是用户码(一个控制器这个码是固定的)16-23是命令码,24-31是命令码的反码,以上都是低位在前。

    上图左是红外发光二极管

    上图右是红外接收器(HS0038B),会自动过滤掉38K的载波留下数据信息

    我压上了杜邦头可以直接插在开发板的引脚上。

    二、解析原理

    接收器有三个管脚(左:输出,中:电源负,右:电源正)

    配置该管脚为普通输入、启用内部上拉电阻、并注册中断函数;

        IoSetFunc(WIFI_IOT_IO_NAME_GPIO_6, WIFI_IOT_IO_FUNC_GPIO_6_GPIO);
        GpioSetDir(WIFI_IOT_IO_NAME_GPIO_6, WIFI_IOT_GPIO_DIR_IN);
        IoSetPull(WIFI_IOT_IO_NAME_GPIO_6, WIFI_IOT_IO_PULL_UP);
        GpioRegisterIsrFunc(WIFI_IOT_IO_NAME_GPIO_6, WIFI_IOT_INT_TYPE_EDGE, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, rc_decode, NULL);
    

    有输出(下降沿)的时候触发中断,中断里读取us时钟;

    然后判断本次中断与上一次中断的时间间隔;
    如果在13500(9000+4500)左右,说明接收到了一个引导信号,准备接收数据;
    如果在1120(560+560)左右,说明接收到一个 bit 0,接收数据不变,接收序号++;
    如果在2240(560+1680)左右,说明接收到一个 bit 1,接收数据与上接收序号所在的位为1;
    如果接收序号=32说明该次接收结束
    判断第3个字节与第4个字节是否刚好是互补的,成功可执行命令解析执行相关操作。

    static void rc_decode(char *arg)
    {
        (void) arg;
        time_r = hi_get_us();
        // t = 13500
        if(time_r - time_c > 13000 && time_r - time_c < 14000)
        {
            n = 0;
            data.Int = 0;
        }    
        // t = 1120
        if(time_r - time_c > 920 && time_r - time_c < 1320)
        {
            ++n;
        } 
        // t = 2250
        if(time_r - time_c > 2050 && time_r - time_c < 2450)
        {
            data.Int |= 1<<n;
            ++n;
        }
        if(n == 32)
        {
            if ((data.Char[2] ^ data.Char[3]) == 0xff)
            {
    //printf("user_code:%x\tcom_code:%x\n", data.Short[0], data.Char[2]);
                switch_key(data.Char[2]);
            }
            data.Int = 0;
        }
        time_c = time_r;
    }
    

    要获取每个按键的命令码是什么,可以直接打印到串口

    printf("user_code:%x\tcom_code:%x\n", data.Short[0], data.Char[2]);
    

    然后对不同的键码进行一个switch操作就OK了!

    void switch_key(unsigned char key)
    {
        switch(key)
        {
            case 0x99: block_left();break;
            case 0xc1: block_right();break;
            case 0xca: game_stop();break;
            case 0xd2: block_down();break;
            case 0xce: block_turn();break;
        }
    }
    

    三、同时也实现了红外编码

    void rc_encode(unsigned user_code, unsigned com_code)
    {
        PwmInit(PWM);
        PwmStart(PWM, 1404, 4212);
        hi_udelay(9000);
        PwmStop(PWM);
        hi_udelay(4500);
        unsigned int data = user_code | com_code<<16 | ~com_code<<24;
        for(unsigned char i=0;i<32;++i)
        {
            PwmStart(PWM, 1404, 4212);
            hi_udelay(560);
            PwmStop(PWM);
            hi_udelay((data&0x0001)==0x0001?1680:560);
            data >>= 1;
        }  
        PwmStart(PWM, 1404, 4212);
        hi_udelay(560);
        PwmStop(PWM);
        hi_udelay(3000);
        PwmStart(PWM, 1404, 4212);
        hi_udelay(560);
        PwmStop(PWM);
    }
    

    编码就是解码的反操作,相关简单

    函数接收用户码和命令码;
    发送9000us的引导码,停4500us
    将用户码与命令码整理成一个32位的数据,方便发送;
    依次按位进行开关PWM进行发送;38k = (160M/4212), 1/3的占空比(4212/3=1404)
    32位发送完后,再发送一个结束码

    发送间隔本应该用定时器进行操作,但Hi3861的定时器都是ms级的,无法完成us级延时;

    开始我用usleep延时操作,发现误差有一两个数量级,根本无法使用,还好我找到了hi_udelay(),位于hi_time.h可以满足需求!

    以上只是介绍最常见的红外遥控器的解码及编码!有些厂家自己定义了请多非标编码就不一一介绍了!

    最近必须付上代码!!!

    作者:Hallym6

    想了解更多内容,请访问: 51CTO和华为官方战略合作共建的鸿蒙技术社区https://harmonyos.51cto.com

  • 相关阅读:
    imperva_waf导入ssl证书
    博科光纤交换机初始化配置
    xss测试代码
    生成树注意事项
    [转载]Basics of the Unix Philosophy
    [转载]GSview注册码
    [转载]tar命令详解
    [转载]WinEdt 6 注册 试用期30天永不过期
    [转载+修改]计数排序
    [转载]C++ 关于声明,定义,类的定义,头文件作用,防止头文件在同一个编译单元重复引用,不具名空间
  • 原文地址:https://www.cnblogs.com/HarmonyOS/p/14137658.html
Copyright © 2011-2022 走看看