×
单片机 > 单片机程序设计 > 详情

74HC164键扫+显示实例

发布时间:2020-06-05 发布时间:
|

源代码: 

/***************************************************** 
 * main.c 中如此这般: 
 *****************************************************/ 

        kd_init(); 

        // ...... 

        while (1) 
        { 
                if( should_update_kd ) 
                { 
                        kd_update(); 
                } 

                // Other code 
                // ...... 
        } 
         

再看显示、键扫源代码: 

/****************************************************** 
 * key_disp-config.h 
 ******************************************************/ 

#ifndef _KEY_DISP_CFG_H_ 
#define _KEY_DISP_CFG_H_ 

#define DIGIT1        B, 0 
#define DIGIT2        B, 1 
#define DIGIT3        B, 2 
#define DIGIT4        B, 3 

#define KEY_FB        D, 6 

#define KD_CLR        D, 7 
#define KD_CLK        B, 5 
#define KD_DAT        B, 4 


#define KEY_NONE        (uint8_t)(0xFF) 
#define KEY_S1                (uint8_t)(0x01<<0) 
#define KEY_S2                (uint8_t)(0x01<<1) 
#define KEY_S3                (uint8_t)(0x01<<2) 
#define KEY_S4                (uint8_t)(0x01<<3) 
#define KEY_S5                (uint8_t)(0x01<<4) 
#define KEY_S6                (uint8_t)(0x01<<5) 
#define KEY_S7                (uint8_t)(0x01<<6) 
#define KEY_S8                (uint8_t)(0x01<<7) 


#endif /*_KEY_DISP_CFG_H_*/ 



/****************************************************** 
 * key_disp.h 
 ******************************************************/ 

#ifndef _KEY_DISP_H_ 
#define _KEY_DISP_H_ 

#include  

#include "key_disp-config.h" 


#define KD_CODE_NONE                        10 
#define KD_CODE_PAUSED                        11 
#define KD_CODE_CW                                12 
#define KD_CODE_CCW                                13 
#define KD_CODE_SET_RUN                        14 
#define KD_CODE_SET_SLEEP                15 
#define KD_CODE_TIMER_RUN                16 
#define KD_CODE_TIMER_SLEEP                17 
#define KD_CODE_EXTERN_TRIG                18 
#define KD_CODE_EXTERN_CTRL                19 
#define KD_CODE_H                                20 
#define KD_CODE_M                                21 
#define KD_CODE_S                                22 



// Initialize key & display 
void kd_init(); 

// Update key & display, MUST be called periodically, eg., in timer 
void kd_update(); 

// Get key code 
uint8_t kd_get_key(); 

// Set mode to display 
void kd_display_code(uint8_t digit_id, uint8_t code_id); 

// Set display digits, dp_pos=-1 means no dp displayed 
void kd_display(uint16_t value, uint8_t max_digits, const int8_t dp_pos); 


#endif /*_KEY_DISP_H_*/ 



/****************************************************** 
 * key_disp.c 
 ******************************************************/ 

#include "avr/io.h" 

#include "key_disp.h" 
#include "config.h" 

#include "util.h" 

#define NOP() asm volatile ("nop") 


static const uint8_t seg_code[] =  

        0x3F/*0*/, 0x06/*1*/, 0x5B/*2*/, 0x4F/*3*/, 0x66/*4*/, 
        0x6D/*5*/, 0x7D/*6*/, 0x07/*7*/, 0x7F/*8*/, 0x6F/*9*/, 
        0x00/*KD_CODE_NONE*/, 
        0x73/*KD_CODE_PAUSED*/, 
        0x21/*KD_CODE_CW*/, 
        0x03/*KD_CODE_CCW*/, 
        0x50/*KD_CODE_SET_RUN*/, 
        0x6D/*KD_CODE_SET_SLEEP*/, 
        0x09/*KD_CODE_TIMER_RUN*/, 
        0x36/*KD_CODE_TIMER_SLEEP*/, 
        0x79/*KD_CODE_EXTERN_TRIG*/, 
        0x39/*KD_CODE_EXTERN_CTRL*/, 
        0x76/*KD_CODE_H*/, 
        0x20/*KD_CODE_M*/, 
        0x22/*KD_CODE_S*/, 
}; 

#define SEG_DP 0x80 


static volatile uint8_t _key_code = 0xFF; 
static volatile uint8_t _digits[4]; 

void kd_init() 

        PORT_DDR_SET(DIGIT1); 
        PORT_DDR_SET(DIGIT2); 
        PORT_DDR_SET(DIGIT3); 
        PORT_DDR_SET(DIGIT4); 
        PORT_DDR_CLR(KEY_FB);        // Input 
        PORT_DDR_SET(KD_CLR); 

        PORT_PIN_CLR(DIGIT1); 
        PORT_PIN_CLR(DIGIT2); 
        PORT_PIN_CLR(DIGIT3); 
        PORT_PIN_CLR(DIGIT4); 
        PORT_PIN_SET(KEY_FB);        // Internal pull-up 
        PORT_PIN_SET(KD_CLR); 

        _digits[0] = _digits[1] = _digits[2] = _digits[3] = 0; 



/* Takes about 50 us @ 8MHz */ 
void kd_update() 

        static uint8_t turn = 0; 

        uint8_t i; 

        if( turn++ & 0x01 ) 
                return; 

        // Disable all digits first 
        PORT_PIN_CLR(DIGIT1); 
        PORT_PIN_CLR(DIGIT2); 
        PORT_PIN_CLR(DIGIT3); 
        PORT_PIN_CLR(DIGIT4); 


        if( turn++ & 0x02 ) 
        { 
                // 
                // trun for key scan 
                // 

                uint8_t shift_data; 
                static uint8_t last_scan_code = 0; 
                static uint8_t last_code_count = 0; 

                // 
                // Scan key 

                PORT_PIN_CLR(KD_CLK); 
                PORT_PIN_CLR(KD_CLR); 
                PORT_PIN_SET(KD_CLR); 

                // 
                // All output 1 
                shift_data = 0xFF; 
                PORT_PIN_SET(KD_DAT); 

                while( shift_data ) 
                { 
                        // Pulse out 
                        PORT_PIN_SET(KD_CLK); 
                        PORT_PIN_CLR(KD_CLK); 

                        shift_data >>= 1; 
                } 

                shift_data = 0x01; 

                while( shift_data ) 
                { 
                        if( (~shift_data) & 0x01 ) 
                                PORT_PIN_SET(KD_DAT); 
                        else 
                                PORT_PIN_CLR(KD_DAT); 

                        // Pulse out 
                        PORT_PIN_SET(KD_CLK); 
                        PORT_PIN_CLR(KD_CLK); 

                        // Delay 
                        for( i=0; i<16; i++ ) 
                                NOP(); 

                        // Check feedback 
                        if( PORT_PIN_VALUE(KEY_FB) == 0 ) 
                        { 
                                if( last_scan_code == shift_data ) 
                                { 
                                        // Same as last scan result, that's the key! 
                                        if( last_code_count > 4 ) 
                                                _key_code = shift_data; 

                                        if( last_code_count                                                  last_code_count++; 
                                } 
                                else 
                                { 
                                        last_scan_code = shift_data; 
                                        last_code_count = 1; 
                                        _key_code = KEY_NONE; 
                                } 

                                break; 
                        } 

                        shift_data <<= 1; 
                } 

                if( shift_data == 0 ) 
                { 
                        _key_code = KEY_NONE; 
                        last_scan_code = KEY_NONE; 
                        last_code_count = 1; 
                } 
        } 
        else 
        { 
                // 
                // Turn for display 
                // 
                 
                static uint8_t curr_digit = 0; 
                uint8_t curr_code = 0; 

                // 
                // Display digits 

                PORT_PIN_CLR(KD_CLK); 
                PORT_PIN_CLR(KD_CLR); 
                PORT_PIN_SET(KD_CLR); 

                curr_code = _digits[curr_digit]; 

                for( i=0; i<8; i++ ) 
                { 
                        // MSB first 
                        if( curr_code & 0x80 ) 
                                PORT_PIN_SET(KD_DAT); 
                        else 
                                PORT_PIN_CLR(KD_DAT); 

                        curr_code <<= 1; 
                 
                        // Pulse out 
                        PORT_PIN_SET(KD_CLK); 
                        PORT_PIN_CLR(KD_CLK); 
                } 

                switch( curr_digit ) // 位控制pin可能不连续,所以不能够用移位之类的 
                { 
                case 0: 
                        PORT_PIN_SET(DIGIT4); 
                        break; 

                case 1: 
                        PORT_PIN_SET(DIGIT3); 
                        break; 

                case 2: 
                        PORT_PIN_SET(DIGIT2); 
                        break; 

                case 3: 
                        PORT_PIN_SET(DIGIT1); 
                        break; 
                } 

                // For next trun 
                curr_digit++; 
                curr_digit %= 4; 
        } 



uint8_t kd_get_key() 

        return _key_code; 



void kd_display_code(uint8_t digit_id, uint8_t code_id) 

        _digits[digit_id] = seg_code[code_id]; 



void kd_display(uint16_t value, uint8_t max_digits, const int8_t dp_pos/*=-1*/) 

        // 
        // Prepare seg code for LED 
         
        _digits[0] = seg_code[value % 10]; 
        value /= 10; 

        _digits[1] = seg_code[value % 10]; 

        if(max_digits > 2) 
        { 
                value /= 10; 
                _digits[2] = seg_code[value % 10]; 
         
                if(max_digits > 3) 
                { 
                        value /= 10; 
                        _digits[3] = seg_code[value % 10]; 
                } 
        } 

        if( dp_pos >=0 && dp_pos<3 ) 
                _digits[dp_pos] |= SEG_DP; 
}




『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
51单片机中断源的扩展方法