微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 求图中IO口扩展的程序!

求图中IO口扩展的程序!

时间:10-02 整理:3721RD 点击:



最近在做一个项目,发现单片机的IO口不够用,然后得知如上图可以在节省IO口的情况下进行IO口扩展完成矩阵键盘。
在此求大神关于此扩展程序,不甚感激啊!
HELP!

不知道74LS164好不好用·?

云里雾里

代码
解析图片链接
禁用链接识别
禁用表情
禁用编辑器代码
使用个人签名
发送动态

看看看

zhichixia!

看看

谢谢你的点拨,顿时豁然开朗起来!希望有机会能再次获得你的帮助!谢谢

k看看

这个就是先选中第一个74L 在开始扫描  再选中第二个74L  再扫描

这个算是在做4*4键盘中最省的一种方法了,如果你有更好的方法,希望你能共享下哈!

你可以做矩阵键盘啊,以前看到过一个很节约io口的矩阵键盘。

这个程序的目标是每发送一个时钟(P1.0)后,立即检查一次P1.2的状态;
这里要注意两点:
1、由于74LS164不能清零,所以扫描检查之前,必须先发送16个零脉冲,即P1.1保持为0时连发16个时钟信号;
2、扫描过程中,第一个时钟使P1.1为1,然后的15个时钟P1.1应为零,同时CPU内部应该有时钟计数器,该计数值是与按键号相对应的,这样才能知道扫描到的是哪一个键的状态。

/*****************************************************
* 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;
}

坐等大神,万分期盼,不甚感激!

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top