ir remote control 加入 repeat/long key

Posted by: 邱小新 at 下午1:47 in

ir remote control NEC protocol 裏只是提到如何處理一個按鍵的處理。在實際應用上,常常會有遇到按著不放時,要重覆處理這個按鍵,或是按住某個按鍵多久才處理。現在我們就來討論這二個應用方法。

下面主要是用來做一個 buffer,免得 mcu 處理來不急,ir_put 都放在 interrupt 內使用,並沒有給一般常式使用;而 ir_get 只有 ir_process 會用到,但是 counter 跟 ir_put 共用到,所以加上中斷排除,免得發生同時修改的慘況。

#define IR_BUFFER_MAX 4 #define IR_BUFFER_MASK 3 static xdata unsigned char ir_buffer[IR_BUFFER_MAX]; static data unsigned char get_index, put_index, counter; static unsigned char ir_debound, ir_key, ir_repeat_key, ir_long_key; static unsigned char code ir_repeat[] = { IR_UP, IR_DOWN, IR_LEFT, IR_RIGHT }; #define IR_REPEAT_MAX (sizeof(ir_repeat)/sizeof(unsigned char)) static void ir_put(unsigned char value) { if (counter < IR_BUFFER_MAX) { ir_buffer[put_index] = value; counter++; put_index++; put_index &= IR_BUFFER_MASK; } } static unsigned char ir_get(void) { unsigned char value; value = ir_buffer[get_index]; ET0 = LOW; counter --; ET0 = HIGH; get_index++; get_index &= IR_BUFFER_MASK; return value; }

下面是在 interrupt 內會用到 ir_put 的片斷,只有二個地方;一個是輸入 repeat 訊號,一個是輸入按鍵訊號。

if (IS_IR_REPEAT(pulse)) { if (ir_pos == 32) ir_put(IR_REPEAT); return; } if(ir_pos >= 32) { ir_mode = 0; stop_timer(); if ((ir_code[0] | ir_code[1]) != 0xef) return; if ((ir_code[2] | ir_code[3]) != 0xff) return; if (ir_code[0] == 0x40) ir_put(ir_code[2]); }

下面是放在 main loop 裏的函數,ir_function 用來處理按鍵事件,而 ir_process 是用來計算處理 normal,repeat,long 按鍵的函數。

void ir_function(unsigned char key) { switch (key) { default: printf_tiny("ir recv: %x,%d,%d,%d\n\r", ir_key, get_index, put_index, counter); } } void ir_process(void) { unsigned char key; if (counter == 0) { return; } key = ir_get(); switch (key) { case IR_REPEAT: if (ir_debound == 0) { ir_debound++; if (ir_key == IR_LONG_KEY) { ir_long_key = IR_LONG_KEY; break; } for (key=0; key<IR_REPEAT_MAX; key++) { if (ir_key == ir_repeat[key]) break; } if (key < IR_REPEAT_MAX) ir_repeat_key = ir_key; } else if (ir_repeat_key != IR_NONE) { if (ir_debound > IR_REPEAT_COUNT) ir_function(ir_repeat_key); else ir_debound++; } else if (ir_long_key != IR_NONE) { if (ir_debound < IR_LONG_COUNT) { ir_debound++; } else if (ir_debound == IR_LONG_COUNT) { ir_function(ir_long_key); ir_debound++; } } break; default: ir_debound = 0; ir_long_key = IR_NONE; ir_repeat_key = IR_NONE; ir_key = key; if (key != IR_LONG_KEY)&#12288;ir_function(key); } }

I2C protocol 時間計算

Posted by: 邱小新 at 上午10:23 in

I2C protocol 原理及應用有提供了一個範例程式碼,裏面的 i2c_wait 在當時是用試誤法來測出需要幾個 nop 指令。最近正好在做新的案子,使用不同的 crystal,就想用時脈來計算出真正需要多少個 nop 指令。

以下推導過程,使用 22.1184MHz 的振盪器,I²C匯流排速度為標準模式(100 Kbit/s)。

  1. 1 clock = 1/22.1184 us
  2. 1 machine cycle = 12 clock = 12/22.1184 us
  3. 1 nop = 1 machine cycle = 12/22.1184 us = 542.534722 ns
  4. 100 kbit/s = 1bit per 1/100000s = 10 us
  5. 1 bit cycle = 10/0.542 = 18.432 machine cycle
  6. 2 * i2c_wait = 1 bit cycle ==> i2c_wait = 9.2 machine cycle = 9 nop

實際上使用的 nop 有 8 個,可以正常 read/write 256 bytes eeprom。但是由於還會呼叫 lcall,ret 等指令,理論上應該少更多才對。不知是 eeprom 不穩,無法達到 100Kbit/s,還是其它原因?

以下推導過程,使用 40MHz 的振盪器,I²C匯流排速度為標準模式(100 Kbit/s)。

  1. 1 clock = 1/40 us
  2. 1 machine cycle = 12 clock = 12/40 us
  3. 1 nop = 1 machine cycle = 12/40 us = 0.3 us
  4. 100 kbit/s = 1bit per 1/100000s = 10 us
  5. 1 bit cycle = 10/0.3 = 33.33 machine cycle
  6. 2 * i2c_wait = 1 bit cycle ==> i2c_wait = 16.67 machine cycle = 16 nop

實際上使用的 nop 有 10 個,只有測試讀寫 1 byte。由於還會呼叫 lcall,ret 等指令,所以少了 6 個 nop 是可以理解的。但是實際上測試需要做讀寫大量的資料,不然像上例的 eeprom,單獨讀寫一個沒問題,大量讀寫時,卻出現很多錯誤。

W77E352 interrupt

Posted by: 邱小新 at 下午1:51 in

W77E352 可以算是 winbond 系列中中斷最多的一個,而像之前我使用的 W79E632 的中斷似乎也是跟 W77E352 系出同門。比如 watchdog timer 的中斷號碼都是 12,而 W79E632 的中斷就少了中間的 7~11,現在終於在 W77E352 看到影子了。但是奇怪的是 6 號中斷不知是那一個?


priority /
interrupt number
sourceflagaddr
0external interrupt 0IE00003h
1timer 0 overflowTF0000bh
2external interrupt 1IE10013h
3timer 1 overflowTF1001bh
4serial portRI+TI0023h
5timer 2 overflowTF2+EXF2002bh
6????0033h
7serial port 1RI_1+TI_1003bh
8external interrupt 2IE20043h
9external interrupt 3IE3004bh
10external interrupt 4IE40053h
11external interrupt 5IE5005bh
12watchdog timerWDIF0063h

  1. INT0,INT1 根據標準的 8051,是可以設定成 edge trigger 或 level trigger,但是由 winbond 提供的 INT2~INT5 卻只能是 edge trigger,而且還各有不同的 edge。
  2. INT2 is raising edge triggered.
  3. INT3 is falling edge triggered.
  4. INT4 is raising edge triggered.
  5. INT5 is falling edge triggered.
  6. INT2~INT5 需手動清除中斷旗標,但可以經由設定 T2MOD 的 HCx,變成自動清除。
  7. INT2~INT5 如果沒有清除中斷旗標,會造成中斷一直重覆,切記。由於 INT0~INT1 會自動清除,所以沒有這個問題。

時間單位

Posted by: 邱小新 at 上午10:56 in
  1. second: 1s = 1000ms
  2. millisecond: 1ms = 1000us
  3. microsecond: 1us = 1000ns
  4. nanosecond: 1ns = 1000ps
  5. picosecond: 1ps = 1000fs
  6. femtosecond: 1fs = 1000as
  7. attosecond: 1as = 10-18 s

SPI (Serial Peripheral Interface)

Posted by: 邱小新 at 上午9:35 in

SPI,Serial Peripheral Interface,顧名思義就是串列周邊介面。是 Motorola 首先在其 MC68HCXX 系列處理器上定義的。SPI 主要應用在轉換器(ADC and DAC),記憶體(EEPROM and FLASH),即時時鐘(RTC),感測器(溫度、壓力)等。SPI 是一種高速串列傳輸匯流排,全雙工通訊協定,主僕控制架構。