[color=rgba(0, 0, 0, 0.87)]红外是一种电磁波,可以实现数据的无线传输,由发送和接收两个部分组成。发送端对红外信号进行脉冲编码,接收端完成对红外信号的脉冲解码。红外遥控协议有多种,如 NEC、SIRC、 RC-5 等,这些协议都比较简单,基本都是以脉冲宽度或脉冲间隔来编码。当遥控器按下按键时,遥控器逻辑单元会产生一个完整的脉冲波形,包含遥控指令的信息,即红外传输的基带信号。这个波形被送到遥控器的调制单元,经调制单元调制成高频红外电磁波信号,由发光二极管发射出去,如下图所示。 [color=rgba(0, 0, 0, 0.87)] [color=var(--md-typeset-a-color)][color=rgba(0, 0, 0, 0.87)]红外电磁波信号一般使用一体化接收头接收,同时完成信号的解调和放大,其输出信号就是红外的基带脉冲信号。解调后的信号可直接送入信号处理单元,由处理单元对脉冲波形进行解码,典型红外接收电路如下图所示。 [color=rgba(0, 0, 0, 0.87)] [color=var(--md-typeset-a-color)][color=rgba(0, 0, 0, 0.87)]相对应的,IR RX 模块属于INPUT 输入设备,支持红外遥控器的按键遥控。具体规格如下所示: [color=rgba(0, 0, 0, 0.87)] [color=var(--md-typeset-a-color)][color=rgba(0, 0, 0, 0.87)]整个系统框架流程如上图所示:当用户按下遥控器的时候,会触发一个中断。IR 驱动会进入中断,然后解析遥控器发送的键值,然后对该电压值进行解码,然后将该事件上报给INPUT 子系统。INPUT 子系统找到相应的事件处理程序之后,会将该按键事件上报给用户空间,等待用户程序对该按键信息的读取与处理。 IR TX 发送 (CIR_TX)模块内部调制原理[color=rgba(0, 0, 0, 0.87)]内部调制原理如下图所示。其中 IMS(Internal Modulation Select),为选择使用内部调制或不调制。软件需设置使用IMS。 [color=rgba(0, 0, 0, 0.87)] [color=var(--md-typeset-a-color)] 载波频率设置[color=rgba(0, 0, 0, 0.87)]载波频率计算公式为: code" style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; font-size: inherit; font-family: inherit; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border-width: 0px; border-style: initial; border-color: initial; position: absolute; top: 0.5em; right: 0.5em; z-index: 1; width: 1.5em; height: 1.5em; border-radius: 0.1rem; outline: none; outline-offset: 0.1rem; cursor: pointer; transition: color 0.25s ease 0s;">Fc = Fclk / [(RFMC + 1) * (DRMC + 2)] (公式1)[color=rgba(0, 0, 0, 0.87)]其中 - Fc为载波频率;
- Fclk为Sunxi IR-TX时钟源,目前配置为12MHz;
- RFMC为载波分频系数,由MCR寄存器(0x04)bit[7:0]设定;
- DRMC为载波占空比设置,由GLR寄存器(0x00)bit[6:5]设定,可配置1/2、1/3或1/4。
[color=rgba(0, 0, 0, 0.87)]通常,载波占空比DRMC 和载波频率 Fc 由应用层设定,因此设置载波占空比即转换为设置GLR bit[6:5],设置载波频率即转换成设置MCR bit[7:0],由公式1 变换得计算RFMC 的公式为: code" style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; font-size: inherit; font-family: inherit; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border-width: 0px; border-style: initial; border-color: initial; position: absolute; top: 0.5em; right: 0.5em; z-index: 1; width: 1.5em; height: 1.5em; border-radius: 0.1rem; outline: none; outline-offset: 0.1rem; cursor: pointer; transition: color 0.25s ease 0s;">RFMC = Fclk / [Fc *(DRMC + 2)] - 1 (公式2)数据发送流程[color=rgba(0, 0, 0, 0.87)]CIR-TX 驱动数据发送流程如下图所示: [color=rgba(0, 0, 0, 0.87)] [color=var(--md-typeset-a-color)] 设置载波占空比[color=rgba(0, 0, 0, 0.87)]由于硬件只支持1/4、1/3 和1/2 三挡占空比设置,因此Sunxi IR-TX 驱动设置载波占空比的流 程比较简单:上层传递一个0~100 的数值,如果该数值小于30,则设定占空比为1/4;如果该 数值大于30 且小于40,则设定占空比为1/3;如果该数值大于40,则设定占空比为1/2。最后 更新硬件配置。 设置载波频率[color=rgba(0, 0, 0, 0.87)]IR-TX 驱动设置载波频率流程如下图所示: [color=rgba(0, 0, 0, 0.87)] [color=var(--md-typeset-a-color)] 模块配置介绍[color=rgba(0, 0, 0, 0.87)]IR_TX 在 menuconfig 中配置如下 [color=rgba(0, 0, 0, 0.87)] [color=var(--md-typeset-a-color)] 模块源码结构[color=rgba(0, 0, 0, 0.87)]CIR_TX 模块源码结构如下所示: code" style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; font-size: inherit; font-family: inherit; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border-width: 0px; border-style: initial; border-color: initial; position: absolute; top: 0.5em; right: 0.5em; z-index: 1; width: 1.5em; height: 1.5em; border-radius: 0.1rem; outline: none; outline-offset: 0.1rem; cursor: pointer; transition: color 0.25s ease 0s;">rtos-hal/|--hal/source/cir_tx/hal_cir_tx // hal层接口代码|--include/hal/sunxi_hal_cir_tx.h // 头文件模块接口说明[color=rgba(0, 0, 0, 0.87)]头文件 code" style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; font-size: inherit; font-family: inherit; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border-width: 0px; border-style: initial; border-color: initial; position: absolute; top: 0.5em; right: 0.5em; z-index: 1; width: 1.5em; height: 1.5em; border-radius: 0.1rem; outline: none; outline-offset: 0.1rem; cursor: pointer; transition: color 0.25s ease 0s;">#include <sunxi_hal_cir_tx.h>IRTX 初始化[color=rgba(0, 0, 0, 0.87)]IRTX 模块初始化,主要完成clk 初始化 [color=rgba(0, 0, 0, 0.87)]函数原型: code" style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; font-size: inherit; font-family: inherit; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border-width: 0px; border-style: initial; border-color: initial; position: absolute; top: 0.5em; right: 0.5em; z-index: 1; width: 1.5em; height: 1.5em; border-radius: 0.1rem; outline: none; outline-offset: 0.1rem; cursor: pointer; transition: color 0.25s ease 0s;">cir_tx_status_t hal_cir_tx_init(struct sunxi_cir_tx_t *cir_tx);[color=rgba(0, 0, 0, 0.87)]参数: [color=rgba(0, 0, 0, 0.87)]返回值: IRTX 设置载波占空比[color=rgba(0, 0, 0, 0.87)]配置 IRTX 模块占空比 [color=rgba(0, 0, 0, 0.87)]函数原型: code" style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; font-size: inherit; font-family: inherit; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border-width: 0px; border-style: initial; border-color: initial; position: absolute; top: 0.5em; right: 0.5em; z-index: 1; width: 1.5em; height: 1.5em; border-radius: 0.1rem; outline: none; outline-offset: 0.1rem; cursor: pointer; transition: color 0.25s ease 0s;">void hal_cir_tx_set_duty_cycle(int duty_cycle);[color=rgba(0, 0, 0, 0.87)]参数: [color=rgba(0, 0, 0, 0.87)]返回值: IRTX 设置载波频率[color=rgba(0, 0, 0, 0.87)]设置载波频率 [color=rgba(0, 0, 0, 0.87)]函数原型: code" style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; font-size: inherit; font-family: inherit; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border-width: 0px; border-style: initial; border-color: initial; position: absolute; top: 0.5em; right: 0.5em; z-index: 1; width: 1.5em; height: 1.5em; border-radius: 0.1rem; outline: none; outline-offset: 0.1rem; cursor: pointer; transition: color 0.25s ease 0s;">void hal_cir_tx_set_carrier(int carrier_freq);[color=rgba(0, 0, 0, 0.87)]参数: [color=rgba(0, 0, 0, 0.87)]返回值: IRTX 使能发送[color=rgba(0, 0, 0, 0.87)]发送IRTX 数据 [color=rgba(0, 0, 0, 0.87)]函数原型: code" style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; font-size: inherit; font-family: inherit; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border-width: 0px; border-style: initial; border-color: initial; position: absolute; top: 0.5em; right: 0.5em; z-index: 1; width: 1.5em; height: 1.5em; border-radius: 0.1rem; outline: none; outline-offset: 0.1rem; cursor: pointer; transition: color 0.25s ease 0s;">void hal_cir_tx_xmit(unsigned int *txbuf, unsigned int count);[color=rgba(0, 0, 0, 0.87)]参数: - txbuf: 代表数据 buf
- count: 代表数据长度
[color=rgba(0, 0, 0, 0.87)]返回值: 模块使用范例 code" style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; font-size: inherit; font-family: inherit; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border-width: 0px; border-style: initial; border-color: initial; position: absolute; top: 0.5em; right: 0.5em; z-index: 1; width: 1.5em; height: 1.5em; border-radius: 0.1rem; outline: none; outline-offset: 0.1rem; cursor: pointer; transition: color 0.25s ease 0s;">#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <hal_cmd.h>#include "sunxi_hal_cir_tx.h"#define NS_TO_US(nsec) ((nsec) / 1000)#define NEC_NBITS 32#define NEC_UNIT 562500 /* ns. Logic data bit pulse length */#define NEC_HEADER_PULSE \ (16 * NEC_UNIT) /* 9ms. 16 * Logic data bit pulse length*/#define NEC_HEADER_SPACE (8 * NEC_UNIT) /* 4.5ms */#define NEC_BIT_PULSE (1 * NEC_UNIT)#define NEC_BIT_0_SPACE (1 * NEC_UNIT)#define NEC_BIT_1_SPACE (3 * NEC_UNIT)#define NEC_TRAILER_PULSE (1 * NEC_UNIT)#define NEC_TRAILER_SPACE (10 * NEC_UNIT) /* even longer */#define GPIO_IR_RAW_BUF_SIZE 128#define DEFAULT_DUTY_CYCLE 33#define DEFAULT_CARRIER_FREQ 38000#define LIRC_MODE2_PULSE 0x01000000#define LIRC_MODE2_SPACE 0x00000000#define LIRC_VALUE_MASK 0x00FFFFFF#define LIRC_MODE2_MASK 0xFF000000#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE)#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE)uint32_t tx_raw_buf[GPIO_IR_RAW_BUF_SIZE;static int nec_modulation_byte(uint32_t *buf, uint8_t code) { int i = 0; uint8_t mask = 0x01; while (mask) { if (code & mask) { /* bit 1 */ *(buf + i) = LIRC_PULSE(NS_TO_US(NEC_BIT_PULSE)); *(buf + i + 1) = LIRC_SPACE(NS_TO_US(NEC_BIT_1_SPACE)); } else { /* bit 0 */ *(buf + i) = LIRC_PULSE(NS_TO_US(NEC_BIT_PULSE)); *(buf + i + 1) = LIRC_SPACE(NS_TO_US(NEC_BIT_0_SPACE)); } mask <<= 1; i += 2; } return i;}static int ir_lirc_transmit_ir(uint32_t *raw_buf, size_t n) { int ret, count; count = n / sizeof(unsigned int); if (count > 1024 || count % 2 == 0) { return -1; }}static int nec_ir_encode(uint32_t *raw_buf, uint32_t key_code) { uint8_t address, reverse_address, command, reverse_command; uint32_t *head_p, *data_p, *stop_p; address = (key_code >> 24) & 0xff; reverse_address = (key_code >> 16) & 0xff; command = (key_code >> 8) & 0xff; reverse_command = (key_code >> 0) & 0xff; /* head bit */ head_p = raw_buf; *(head_p) = LIRC_PULSE(NS_TO_US(NEC_HEADER_PULSE)); *(head_p + 1) = LIRC_PULSE(NS_TO_US(NEC_HEADER_SPACE)); /* data bit */ data_p = raw_buf + 2; nec_modulation_byte(data_p, address); data_p += 16; nec_modulation_byte(data_p, reverse_address); data_p += 16; nec_modulation_byte(data_p, command); data_p += 16; nec_modulation_byte(data_p, reverse_command); /* stop bit */ stop_p = data_p + 16; *(stop_p) = LIRC_PULSE(NS_TO_US(NEC_TRAILER_PULSE)); *(stop_p + 1) = LIRC_PULSE(NS_TO_US(NEC_TRAILER_SPACE)); return ((NEC_NBITS + 2) * 2 - 1);}int cmd_test_cir_tx(int argc, char **argv) { int key_code = 0x04fb13ec; int i, size; int count = 67; struct sunxi_cir_tx_t *cir_tx; hal_cir_tx_init(cir_tx); hal_cir_tx_set_duty_cycle(DEFAULT_DUTY_CYCLE); hal_cir_tx_set_carrier(DEFAULT_CARRIER_FREQ); size = nec_ir_encode(tx_raw_buf, key_code); for (i = 0; i < size; i++) { printf("%d ", *(tx_raw_buf + i) & 0x00FFFFFF); if ((i + 1) % 8 == 0) { printf("\n"); } } printf("\n"); for (i = 0; i < size; i++) tx_raw_buf[i = (tx_raw_buf[i & 0x00FFFFFF); hal_cir_tx_xmit(tx_raw_buf, count); printf("end test!\n"); return 0;}IR RX 接收(CIR)模块配置介绍[color=rgba(0, 0, 0, 0.87)]IR 在 menuconfig 中配置如下 [color=rgba(0, 0, 0, 0.87)] [color=var(--md-typeset-a-color)] 模块源码结构[color=rgba(0, 0, 0, 0.87)]CIR 模块源码结构如下所示: code" style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; font-size: inherit; font-family: inherit; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border-width: 0px; border-style: initial; border-color: initial; position: absolute; top: 0.5em; right: 0.5em; z-index: 1; width: 1.5em; height: 1.5em; border-radius: 0.1rem; outline: none; outline-offset: 0.1rem; cursor: pointer; transition: color 0.25s ease 0s;">rtos-hal/|--hal/source/cir/hal_cir.c // hal层接口代码|--include/hal/sunxi_hal_cir.h // 头文件模块返回值定义[color=rgba(0, 0, 0, 0.87)]返回值 枚举 定义
-4CIR_PIN_ERR配置的 CIR 引脚错误
-3CIR_CLK_ERR配置的 CIR 模块时钟错误
-2CIR_IRQ_ERR中断配置错误
-1CIR_PORT_ERR配置 CIR 端口错误
0CIR_OK成功
code" style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; font-size: inherit; font-family: inherit; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border-width: 0px; border-style: initial; border-color: initial; position: absolute; top: 0.5em; right: 0.5em; z-index: 1; width: 1.5em; height: 1.5em; border-radius: 0.1rem; outline: none; outline-offset: 0.1rem; cursor: pointer; transition: color 0.25s ease 0s;">typedef enum { CIR_PIN_ERR = -4, CIR_CLK_ERR = -3, CIR_IRQ_ERR = -2, CIR_PORT_ERR = -1, CIR_OK = 0,} cir_status_t;模块接口说明[color=rgba(0, 0, 0, 0.87)]头文件 code" style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; font-size: inherit; font-family: inherit; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border-width: 0px; border-style: initial; border-color: initial; position: absolute; top: 0.5em; right: 0.5em; z-index: 1; width: 1.5em; height: 1.5em; border-radius: 0.1rem; outline: none; outline-offset: 0.1rem; cursor: pointer; transition: color 0.25s ease 0s;">#include <sunxi_hal_cir.h>IR 初始化接口[color=rgba(0, 0, 0, 0.87)]IR 模块初始化,主要初始化采样率、通道选择及注册中断等 [color=rgba(0, 0, 0, 0.87)]函数原型: code" style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; font-size: inherit; font-family: inherit; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border-width: 0px; border-style: initial; border-color: initial; position: absolute; top: 0.5em; right: 0.5em; z-index: 1; width: 1.5em; height: 1.5em; border-radius: 0.1rem; outline: none; outline-offset: 0.1rem; cursor: pointer; transition: color 0.25s ease 0s;">cir_status_t sunxi_cir_init(cir_port_t port);[color=rgba(0, 0, 0, 0.87)]参数: [color=rgba(0, 0, 0, 0.87)]返回值: IR 注册回调接口[color=rgba(0, 0, 0, 0.87)]向应用层提供注册回调接口的功能 [color=rgba(0, 0, 0, 0.87)]函数原型: code" style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; font-size: inherit; font-family: inherit; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border-width: 0px; border-style: initial; border-color: initial; position: absolute; top: 0.5em; right: 0.5em; z-index: 1; width: 1.5em; height: 1.5em; border-radius: 0.1rem; outline: none; outline-offset: 0.1rem; cursor: pointer; transition: color 0.25s ease 0s;">void sunxi_cir_callback_register(cir_port_t port, cir_callback_t callback);[color=rgba(0, 0, 0, 0.87)]参数: - port :CIR 通道
- callback:应用层回调接口
[color=rgba(0, 0, 0, 0.87)]返回值: IR 去初始化接口[color=rgba(0, 0, 0, 0.87)]函数原型: code" style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; font-size: inherit; font-family: inherit; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border-width: 0px; border-style: initial; border-color: initial; position: absolute; top: 0.5em; right: 0.5em; z-index: 1; width: 1.5em; height: 1.5em; border-radius: 0.1rem; outline: none; outline-offset: 0.1rem; cursor: pointer; transition: color 0.25s ease 0s;">void sunxi_cir_deinit(cir_port_t port);[color=rgba(0, 0, 0, 0.87)]参数: [color=rgba(0, 0, 0, 0.87)]返回值: 模块使用范例 code" style="box-sizing: inherit; -webkit-tap-highlight-color: transparent; font-size: inherit; font-family: inherit; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border-width: 0px; border-style: initial; border-color: initial; position: absolute; top: 0.5em; right: 0.5em; z-index: 1; width: 1.5em; height: 1.5em; border-radius: 0.1rem; outline: none; outline-offset: 0.1rem; cursor: pointer; transition: color 0.25s ease 0s;">#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <hal_cmd.h>#include <hal_log.h>#include "sunxi_hal_cir.h"static cir_callback_t cir_irq_callback(uint32_t data_type, uint32_t data) { printf("reg_val:0x%u\n", data); return 0;}int cmd_test_cir(int argc, char **argv) { cir_port_t port; int ret = -1; int timeout_sec = 15; TickType_t start_ticks, current_ticks; printf("Run ir test\n"); if (argc < 2) { hal_log_err("usage: hal_ir channel\n"); return -1; } port = strtol(argv[1, NULL, 0); ret = sunxi_cir_init(port); if (ret) { hal_log_err("cir init failed!\n"); return -1; } sunxi_cir_callback_register(port, cir_irq_callback); start_ticks = xTaskGetTickCount(); printf("start_ticks: %u\n", start_ticks); while (1) { current_ticks = xTaskGetTickCount(); if ((current_ticks - start_ticks) * portTICK_PERIOD_MS >= timeout_sec * 1000) { printf("current_ticks: %u\n", current_ticks); break; } } sunxi_cir_deinit(port); return 0;}
|