找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5923|回复: 0
打印 上一主题 下一主题
收起左侧

应用时间片实现多任务的单片机代码

[复制链接]
跳转到指定楼层
楼主
ID:80436 发表于 2015-5-21 01:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
要实现的功能模块有四个: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(一次性编程)芯片。

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
//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 range  

uint8_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 data  
uint8_t ir_bits_cnt; // Counter for data bits  
uint8_t ir_data[IR_FRAME_BYTES];// Ir data buffer  
uint8_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 Command  
uint8_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;  
        }  

    }  

}  

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表