飞利浦 RC-MM 协议


1 2 3 4
| 00 = 0 01 = 1 10 = 2 11 = 3
|
飞利浦RC-5协议
3010红外格式说明
IRReader波形数据

从IRReader波形数据的波形可以看出,3010的相关定义
帧定义
一帧有15位( 2位起始位 + 1位控制位 + 5位地址码 + 6位命令码 + 1位停止位)
位定义
| 逻辑值 |
低电平时长 |
高电平时长 |
总周期 (上升沿到上升沿) |
解码依据 |
| 0 |
880 µs |
880 µs |
1.76 ms |
测量到脉冲间隔较短 |
| 1 |
1.8 ms |
880 µs |
2.68 ms |
测量到脉冲间隔较长 |
数据规则
1.起始位规则:一帧的开头两个位(起始位)是“11”还是“10”,由数据码(D5-D0)的值决定。这是一种将数据码高位信息“隐藏”在起始位中的巧妙设计。
- 规则A:如果
数据码 ≤ 0x3F(即≤63),则起始位固定为 “11”。
- 规则B:如果
数据码 > 0x3F,则:在发送数据码部分时,只发送其低6位(舍弃最高位)。同时,将起始位设置为 “10”。
- 目的:此规则等效于将数据码的最高位“移动”到了起始位中发送,使得6位数据码能表示大于63的数值,扩展了指令容量。
2.奇偶判断位功能:帧中的一个特殊位,用于区分是持续按键还是松开后重新按键(该位在重新按键时会翻转)。它不用于错误校验,而是用于按键状态机判断。
3.地址码:固定部分。每个按键都一样
4.命令码:就是3010格式的数据码,每个按键不一样,只取低6位
5.停止码:固定部分。每个按键都一样
代码编写
在奉加微芯片中
获取红外码值get_ir_key_code函数和红外发送handle函数如下
首先按下按键后会在app_key_press中触发ir_sending_handle
ir_sending_handle在执行判断 if( get_ir_key_code(key_index, temp_infrated_code) != 1)的时候同时将码值通过指针的方式给到临时数组temp_infrated_code中,最后往下执行程序的时候将temp_infrated_code数据传入ir_data_encode中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
| int8 get_ir_key_code( uint8 key_id, uint8* remap_ir_data ) { uint8 index = 0;
if( remap_ir_data == NULL ) { return -1; }
if( (IR_TEST_MODE_SUPPORT == TRUE) && (flag_ir_test_mode == TRUE) ) { for( index = 0; index < sizeof( app_ir_test_keyCode )/ sizeof(app_ir_test_keyCode[0]); index++ ) { if( key_id == app_ir_test_keyCode[ index ].ir_key_index ) { break; } }
if ((index < 0) || (index >= sizeof( app_ir_test_keyCode )/ sizeof(app_ir_test_keyCode[0]))) { LOG("Index out of range: %d\n", index); return -1; } remap_ir_data[0] = IR_TM_USER_CODE; remap_ir_data[1] = IR_TM_USER_CODE_INV; remap_ir_data[2] = app_ir_test_keyCode[ index ].ir_key_value; remap_ir_data[3] = 0XFF - remap_ir_data[2]; return 1; }
else { for( index = 0; index < sizeof( app_ir_keyCode )/ sizeof(app_ir_keyCode[0]); index++ ) { if( key_id == app_ir_keyCode[ index ].ir_key_index ) { break; } } if ( (index < 0) || (index >= sizeof( app_ir_keyCode )/ sizeof(app_ir_keyCode[0]))) { LOG("Index out of range: %d\n", index); return -1; } remap_ir_data[0] = LOCAL_CUSTOMER_CODE; remap_ir_data[1] = 0XFE; remap_ir_data[2] = app_ir_keyCode[ index ].ir_key_value; remap_ir_data[3] = 0XFF - remap_ir_data[2]; return 1; } }
void ir_sending_handle(uint8 key_index) { uint8 temp_infrated_code[4] = { 0x00 }; hal_watchdog_feed(); ir_sending_stop_handle(0);
if( get_ir_learn_mode() == 1 ) { IR_SEND_LOG("ir in learn mode\r\n"); return; }
IR_SEND_LOG("ir sending\n");
if( get_ir_key_code(key_index, temp_infrated_code) != 1) { IR_SEND_LOG("key id error\r\n"); return; }
if( Ir_Send_Parm.ir_ctx_cfg.ir_md == IR_MODE_1 ) { hal_gpio_write(Ir_Send_Parm.ir_ctx_cfg.ir_control_pin, 1); }
ir_data_encode(temp_infrated_code, Ir_Send_Parm.ir_38khz_wave_buff ); Ir_Send_Parm.send_waveform_index = 0; Ir_Send_Parm.switch_flag = 0; Ir_Send_Parm.ir_sending_work = true; Ir_Send_Parm.notify_ir_stop_flag = true; ir_timer_init(); pwm_ch_t ir_pwm_config; hal_pwm_module_init(); ir_pwm_config.pwmN = PWM_CH0; ir_pwm_config.pwmPin = Ir_Send_Parm.ir_ctx_cfg.ir_sending_pin; ir_pwm_config.cmpVal = IR_SENDING_38KHZ_COM_VALUE; ir_pwm_config.cntTopVal = IR_SENDING_38KHZ_TOP_VALUE; ir_pwm_config.pwmMode = PWM_CNT_UP; ir_pwm_config.pwmPolarity = PWM_POLARITY_RISING; ir_pwm_config.pwmDiv = PWM_CLK_DIV_4; hal_pwm_ch_start( ir_pwm_config ); hal_timer_set( IR_SENDING_TIMER_ID, Ir_Send_Parm.ir_38khz_wave_buff[0] ); }
|
我们继续看在得到红外数据并传入编码函数ir_data_encode后,是如何对十六进制的红外数据进行编码位38kHz的波形发送的
下面是ir_data_encoded的函数实现
在上面我们通过将temp_infrated_code数组传入get_ir_key_code,将红外数据存储到temp_infrated_code数组中,并将temp_infrated_code作为get_ir_key_code的参数Origin_Ir_data,需要注意的是这里没有进行数据的复制,而只是将temp_infrated_code的地址传入编码函数当中
所以实际上,我们在app_cfg上写的十六进制的红外用户码和红外数据码,最后是到了ir_data_encode的一个for循环中进行处理
这里for循环处理的目的是将十六进制的数据的每一位进行0和1的编码处理,具体是通过if(Origin_Ir_data[j] & 0x01)这一句位与运算实现0和1的判读和编码的,并且采用低位优先(LSB First)的传输方式,在对最低位进行编码后, Origin_Ir_data[j] >>= 1这句代码会将当前字节右移一位,这样,原来的次低位就变成了新的最低位,等待下一次循环进行判断。这个过程就像我们从左到右阅读一样,程序从字节的最低位开始,逐个比特进行处理
i < 8决定了处理的位数位8位,即一个字节,j < 4决定了处理的一帧的数据为4个字节
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| void ir_data_encode( uint8* Origin_Ir_data, uint32* encode_Ir_data ) { if( Origin_Ir_data == NULL || encode_Ir_data == NULL ) { return; }
uint8 id = 0; encode_Ir_data[id++] = IR_38KHZ_START_CARRIER; encode_Ir_data[id++] = IR_38KHZ_START_NO_CARRIER;
for( uint8 j =0; j < 4; j++ ) { for( uint8 i = 0; i < 8; i++ ) { if( Origin_Ir_data[j] & 0x01 ) { encode_Ir_data[id++] = IR_38KHZ_HIGH_LEVEL_CARRIER; encode_Ir_data[id++] = IR_38KHZ_HIGH_LEVEL_NO_CARRIER; } else { encode_Ir_data[id++] = IR_38KHZ_LOW_LEVEL_CARRIER; encode_Ir_data[id++] = IR_38KHZ_LOW_LEVEL_NO_CARRIER; }
Origin_Ir_data[j] >>= 1; } }
encode_Ir_data[id++] = IR_38KHZ_STOP_CARRIER; encode_Ir_data[id++] = IR_38KHZ_STOP_NO_CARRIER; encode_Ir_data[id++] = IR_38KHZ_REPEATED_CARRIER_1; encode_Ir_data[id++] = IR_38KHZ_REPEATED_NO_CARRIER_1; encode_Ir_data[id++] = IR_38KHZ_REPEATED_CARRIER_2; encode_Ir_data[id++] = IR_38KHZ_REPEATED_NO_CARRIER_2; g_ir_data_count = IR_SENDING_38KHZ_BITS_INDEX + 1; g_ir_is_repeart = 1; return; }
|
接下来我们需要将红外格式由6121格式改为3010格式,我们使用游程编码(Run-Length Encoding)对RC5(3010)红外格式进行编码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
| #define RC5_TOTAL_BITS 14
static uint8_t g_rc5_toggle_bit = 0;
void ir_data_encode( uint8* Origin_Ir_data, uint32* encode_Ir_data ) { if( Origin_Ir_data == NULL || encode_Ir_data == NULL ) { return; }
uint8_t raw_bits[RC5_TOTAL_BITS]; uint8_t half_bits_stream[RC5_TOTAL_BITS * 2]; uint32_t id = 0; int bit_index = 0;
raw_bits[bit_index++] = 1; if (Origin_Ir_data[1] > 0x3F) { raw_bits[bit_index++] = 0;
} else { raw_bits[bit_index++] = 1;
} raw_bits[bit_index++] = g_rc5_toggle_bit & 0x01;
for(int i = 0; i < 5; i++) { int bit_position = (5 -1 - i) % 8; raw_bits[bit_index++] = (Origin_Ir_data[0] >> bit_position) & 0x01; }
for(int i = 0; i < 6; i++) { int bit_position = (5 - i) % 8; raw_bits[bit_index++] = (Origin_Ir_data[1] >> bit_position) & 0x01; }
for(int i = 0; i < RC5_TOTAL_BITS; i++) { if(raw_bits[i] == 1) { half_bits_stream[i*2] = 0; half_bits_stream[i*2 + 1] = 1; } else { half_bits_stream[i*2] = 1; half_bits_stream[i*2 + 1] = 0; } }
uint8_t current_level = half_bits_stream[1]; uint8_t count = 1;
uint8_t change_count = 1;
for(int k = 2; k < RC5_TOTAL_BITS * 2; k++) { if (half_bits_stream[k] == current_level) { count++; } else { change_count++;
if (count == 1) { encode_Ir_data[id++] = IR_38KHZ_Manchester_880; } else { encode_Ir_data[id++] = IR_38KHZ_Manchester_1760; }
current_level = half_bits_stream[k]; count = 1; } }
LOG("RC5 Change Count: %d\n", change_count); if (change_count % 2 == 0) { encode_Ir_data[id++] = 85000 +880 ; } else { if (count == 1) { encode_Ir_data[id++] = IR_38KHZ_Manchester_880; } else { encode_Ir_data[id++] = IR_38KHZ_Manchester_1760; } encode_Ir_data[id++] = 85000 ; }
g_ir_data_count = IR_SENDING_38KHZ_BITS_INDEX + 1; g_ir_is_repeart = 0; return; }
|