求图中IO口扩展的程序!

2019-07-16 04:11发布

本帖最后由 herochenzhao 于 2012-10-25 19:37 编辑

55.png
最近在做一个项目,发现单片机的IO口不够用,然后得知如上图可以在节省IO口的情况下进行IO口扩展完成矩阵键盘。
在此求大神关于此扩展程序,不甚感激啊!
HELP!!!
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
19条回答
lstcspring
2019-07-18 20:17
/*****************************************************
* 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 <inttypes.h>

#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 < 255 )
                                                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;
}

一周热门 更多>