應用時間片實現多任務的單片機代碼

來源:互聯網
上載者:User
要實現的功能模組有四個: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;        }            }    }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.