要實現的功能模組有四個:ir訊號解碼,待機訊號重複按鍵判斷,i2c從裝置中斷處理,LED&KEYPAD掃描。其中這四個模組中除了i2c從裝置中斷處理,其他都需要用到定時器。不巧的是,我們用到的單片機是HT46R22,只有一個定時器。我參考了作業系統時間片的概念,最終寫了這個目前還覺得完美的代碼。從測試結果來看,模組之間沒有互相干擾且工作良好。沒採用時間片之前,ir訊號到達時會導致LED閃爍,這樣每次ir訊號到達都會打斷timer,而LED&Keypad的掃描又依賴於timer調度,所以自然會產生閃爍現象)。但用時間片來解碼ir訊號,顯著有一個缺點,就是脈衝寬度計算時誤差取值範圍太大--達到一個時間片的大小。寫完這個代碼後,我還寫了一個應用於單片機的task schedule和message box,簡單的來說就是在這個程式上封裝了一層,實現了insert_task_2_queue()和schedule_task()之類的函數。但是很不巧,模擬器到期要歸還給HT公司,這個代碼雖已大致完成,但還沒調試通過,這裡就暫時保留吧。關於代碼,關於各模組原理,恕我這裡不詳述,因為涉及方面很廣,我想談卻無從談起。如果需要瞭解這份代碼而又有各種困惑的,feel free to contact me by email。另外請不要輕易責怪電子工程師喜歡用全域變數,喜歡用數組而不是指標。我以前也這樣,直到我用了HT-IDE 3000這個開發平台,不支援static變數,不支援指標,沒有malloc和free。何況單片機程式最主要的是穩定,尤其當你面對的是OTP(一次性編程)晶片。
//Ht46r22.c////Body: Ht46r22////Mask option following://SysVolt: 5.0V//SysFreq: 8000KHz//Wake-up PA0-7: All Non-Wake-up//Pull-high PA0-5: All Pull-high//IIC: Enable//Pull-high PB: Pull-high//Pull-high PC: Pull-high//Pull_high PD: Pull-high//the others use the default value#include <Ht46r22.h>/********************************* BASIC TYPE ********************************/#define uint8_t unsigned char#define uint16_t unsigned long/********************************* IR SIGNAL *********************************/#define crystal 8000000 // Crystal frequency#define PSC 16 // Prescaler stage#define nMS 0.25 // Timer interval: 0.25ms#define MS_IR_LEADER 5.44 // Leader code: 5.44ms#define MS_IR_CODE_0 0.76 // Code-0: 0.76ms,=(0.25ms * 3)#define MS_IR_CODE_1 1.73 // Code-1: 1.73ms,=(0.25ms * 7)#define IR_CUSTOM_CODE1 (0x80) // customer-code 1, Need convert BIT7~0 to bit0~7#define IR_CUSTOM_CODE2 (0xff) // customer-code 2#define IR_CUSTOM_CODE3 (0xff) // customer-code 3#define IR_CUSTOM_CODE4 (0x80) // customer-code 4#define IR_KEYVALUE_PWR1 (0x46) // standby-code 1 #define IR_KEYVALUE_PWR2 (0x31) // standby-code 2/********************************* TMR VALUE *********************************/#define TMR_nMS 0x82 // (0xff-((nMS*crystal/1000)/PSC)) Timer value for timing 0.25ms#define TMR_IR_0_nTIMES 3 // Code-0: 0.76ms=0.25ms*3#define TMR_IR_1_nTIMES 7 // Code-1: 1.73ms=0.25ms*7#define TMR_IR_SCALE 1 // Error rangeuint8_t tmr_ir_decode; uint8_t tmr_ir_repeat;uint8_t tmr_led_refresh;/********************************* IR DECODE *********************************/#define IR_FRAME_BITS 48 // Total bits of one frame data #define IR_FRAME_BYTES (IR_FRAME_BITS/8) // Length of one frame datauint8_t ir_bits_cnt; // Counter for data bitsuint8_t ir_data[IR_FRAME_BYTES];// Ir data bufferuint8_t ir_data_ptr;bit ir_data_ready; // 1-Data be ready/********************************** PIN DEF **********************************/#define STANDBY _pc0#define LOCK _pd0/******************************** STANDBY DEF ********************************/uint8_t pwr_repeat_cnt;bit pwr_flag;/********************************** CMD DEF **********************************/#define I2C_CMD_LED 0x80 // Led Refresh Command#define I2C_CMD_LOCK 0x40 // LOCK Refresh Commanduint8_t i2c_cmd; // Commandword: rx_data[0]/********************************** LED DEF **********************************/#define LED_NUM 4 #define LED_SET_DATA(x) do{_pbc = 0x00; _pb = x;}while(0)#define LED_EN_COM(x) do{_pa |= 0x0f; _pa &= ~(1<<(x));}while(0)#define LED_DIS_ALL_COMS() do{_pa |= 0x0f;}while(0) bit lock_status; // LOCK-Led status: rx_data[1]uint8_t led_data[LED_NUM]; // Led display data buffer: rx_data[1:4]uint8_t refresh_timeslice; // Refresh timeslice/********************************** I2C DEF **********************************/#define I2C_SLAVE_ADDR 0x0c#define RX_LEN (LED_NUM+1) // commandword + data[0] + data[1] + data[2] + data[3]uint8_t tx_data; uint8_t rx_data[RX_LEN];uint8_t rx_data_ptr;/***************************** interrupt vector ******************************/#pragma vector isr_ext @ 0x4#pragma vector isr_tmr @ 0x8#pragma vector isr_i2c @ 0x10/******************************* PRIVATE FUNC ********************************/uint8_t byte_reverse(uint8_t dat){ /* Convert bit[7:0] to bit[0:7] */ uint8_t i; uint8_t src, dsn; src = dat; dsn = src & 0x1;; for(i = 0; i < 7; i++) { src >>= 1; dsn <<= 1; dsn |= src & 0x1; } return dsn;}/************************************ ISR ************************************/void isr_ext(){ /* External ISR */ /* Interval between two external interrupt triggered by falling edge of ir-signal. */ uint8_t int_interval; int_interval = tmr_ir_decode; tmr_ir_decode = 0; //decode ir signal if ((int_interval >= (TMR_IR_1_nTIMES-TMR_IR_SCALE)) && (int_interval <= (TMR_IR_1_nTIMES+TMR_IR_SCALE))) { // Code 1 if (ir_data_ptr == IR_FRAME_BYTES) ir_data_ptr = 0; ir_data[ir_data_ptr] = (ir_data[ir_data_ptr]<<1) + 1; ir_bits_cnt++; if ((ir_bits_cnt%8) == 0) ir_data_ptr++; } else if ((int_interval >= (TMR_IR_0_nTIMES-TMR_IR_SCALE)) && (int_interval <= (TMR_IR_0_nTIMES+TMR_IR_SCALE))) { // Code 0 if (ir_data_ptr == IR_FRAME_BYTES) ir_data_ptr = 0; ir_data[ir_data_ptr] = (ir_data[ir_data_ptr]<<1); ir_bits_cnt++; if ((ir_bits_cnt%8) == 0) ir_data_ptr++; } else { // Other, invalid signal, reset ir_data_ptr = 0; ir_bits_cnt = 0; ir_data_ready = 0; } if (ir_bits_cnt == IR_FRAME_BITS) { // Receive over, set ir_data_ready ir_data_ptr = 0; ir_bits_cnt = 0; ir_data_ready = 1; } } void isr_tmr(){ /* Timer ISR, time 0.25ms */ // Check ir repeat. Repeat interval=0.25ms*200*6 tmr_ir_repeat++; if (tmr_ir_repeat > 200) { // time 50ms, 50ms = 200*0.25ms tmr_ir_repeat = 0; if (pwr_flag) { pwr_repeat_cnt++; if( pwr_repeat_cnt >= 6 ) pwr_flag = 0; } } // Timeslice for Led & Keypad refresh tmr_led_refresh++; if (tmr_led_refresh > 8) { // time 2ms, 2ms = 8*0.25ms tmr_led_refresh = 0; refresh_timeslice++; refresh_timeslice %= (LED_NUM+1); } // Interval for ir decoding. When ir signal coming, read it then reset it. tmr_ir_decode++;}void isr_i2c(){ if(_haas == 1) { // Address Match if(_srw == 1) { // Transmit Mode _htx = 1; _hdr = tx_data; } else { // Receive Mode _htx = 0; _txak = 0; rx_data[rx_data_ptr] = _hdr; } } else { // Transfer Completed if(_htx == 1) { // Transmitter. Continue to Transimit or Not if(_rxak == 1) { _htx = 0; // _rxak=1, NO ACK _txak = 0; rx_data[rx_data_ptr] = _hdr; // Dummy read from hdr } else { _hdr = tx_data; // _rxak=0; with ACK } } else { // Receiver ,htx=0 rx_data[rx_data_ptr] = _hdr; rx_data_ptr++; if (rx_data_ptr == RX_LEN) { // Reveive over rx_data_ptr = 0; // rx_data[0]is command word i2c_cmd = rx_data[0]; switch (i2c_cmd) { case I2C_CMD_LED: // Refresh LED command,save display data led_data[0] = rx_data[1]; led_data[1] = rx_data[2]; led_data[2] = rx_data[3]; led_data[3] = rx_data[4]; break; case I2C_CMD_LOCK: // Refresh LOCK command, save lock_status lock_status = rx_data[1]; break; } _txak = 1; // end of receive } else { // Continue to Receive _txak = 0; } } }}/********************************* FUNCTION **********************************/void init_hw(){ /* intc0: +------------------------------------------------------+ |bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | +------------------------------------------------------+ | 0 | ADF | TF | EIF | EADI | ETI | EEI | EMI | +------------------------------------------------------+ */ _intc0 = 0; /* intc1: +------------------------------------------------------+ |bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | +------------------------------------------------------+ | 0 | 0 | 0 | HIF | 0 | 0 | 0 | EHI | +------------------------------------------------------+ */ _intc1 = 0; /* tmrc: +------------------------------------------------------+ |bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | +------------------------------------------------------+ | TM1 | TM0 | 0 | TON | TE | PSC2 | PSC1 | PSC0 | +------------------------------------------------------+ TM[1:0] = 10, timer mode,using internal fsys PSC[2:0]= 100, PSC=16 */ _tmrc = 0x84; _tmr = TMR_nMS; /* hcr: +------------------------------------------------------+ |bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | +------------------------------------------------------+ | HEN | 0 | 0 | HTX | TXAK | 0 | 0 | 0 | +------------------------------------------------------+ */ _hcr = 0; /* _pa[0:3]-->out, LED_COM[1:4] _pa4 -->out, CTRL _pa5 -->1, using for INT_ _pa[6:7]-->11, using for i2c */ _pac = 0x20; /* _pb[0:7]-->out, LED */ _pbc = 0x00; /* _pc0 -->out, STANDBY _pc1 -->out, REQ */ _pcc = 0x00; /* _pd0 -->out, LOCK */ _pdc = 0x00; _hadr = I2C_SLAVE_ADDR; _htx = 0; // Set i2c bus to be receive mode _txak = 0; _hen = 1; // Enable i2c bus _ehi = 1; // Enable i2c interrupt _eti = 1; // Enable timer interrupt _eei = 1; // Enable external interrupt _emi = 1; // Enable global interrupt _ton = 1; // Start timer}void init_sys(){ LOCK = 0; // LOCK-Led off STANDBY = 1; // PWR-Led on ir_data_ptr = 0; ir_data_ready = 0; ir_bits_cnt = 0; tmr_ir_decode = 0; tmr_ir_repeat = 0; tmr_led_refresh = 0; pwr_flag = 0; pwr_repeat_cnt = 0; tx_data = 0xff; rx_data_ptr = 0; // Leds display "boot" when system booting led_data[0] = 0x7c; led_data[1] = 0x5c; led_data[2] = 0x5c; led_data[3] = 0x78; i2c_cmd = 0xff; lock_status = 0; refresh_timeslice = 0;}void main(){ uint8_t ir_custom_code[4]; uint8_t ir_keyvalue_pwr[2]; init_hw(); init_sys(); ir_custom_code[0] = byte_reverse(IR_CUSTOM_CODE1); ir_custom_code[1] = byte_reverse(IR_CUSTOM_CODE2); ir_custom_code[2] = byte_reverse(IR_CUSTOM_CODE3); ir_custom_code[3] = byte_reverse(IR_CUSTOM_CODE4); ir_keyvalue_pwr[0] = byte_reverse(IR_KEYVALUE_PWR1); ir_keyvalue_pwr[1] = byte_reverse(IR_KEYVALUE_PWR2); while (1) { if (refresh_timeslice < LED_NUM) { // Leds's turn, refresh Led display LED_EN_COM(refresh_timeslice); LED_SET_DATA(led_data[refresh_timeslice]); } else { // Keypad's turn, read keypad value LED_DIS_ALL_COMS(); // First disable all Leds _pb = 0xff; // Pull-High port(b) _pbc= 0x7e; // Set port(b) to be input mode tx_data = _pb; // Save status of port(b) to tx_data // Refresh LOCK-Led's status LOCK = lock_status; } if (ir_data_ready) { // Keycode is valid? if ((ir_data[0] == ir_custom_code[0]) && (ir_data[1] == ir_custom_code[1]) &&(ir_data[2] == ir_custom_code[2]) && (ir_data[3] == ir_custom_code[3]) &&(ir_data[4] == ir_keyvalue_pwr[0])&& (ir_data[5] == ir_keyvalue_pwr[1])) { // Check whether Key-PWR is pressed repeatedly. if (pwr_flag == 0) { STANDBY = ~STANDBY; if (STANDBY == 1) { // System on,Leds display "boot" led_data[0] = 0x7c; led_data[1] = 0x5c; led_data[2] = 0x5c; led_data[3] = 0x78; } else { // System off,Leds display "----",LOCK-Led off led_data[0] = led_data[1]= led_data[2] = led_data[3] = 0x40; lock_status = 0; } } pwr_flag = 1; pwr_repeat_cnt = 0; } ir_data_ready = 0; } } }