ghost2 发表于 2008-1-25 10:25:38

74HC164键扫+显示实例,已经过项目验证

点击此处打开Key & Display Board.pdf(文件大小:205K)

源代码:

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

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 = _digits = _digits = _digits = 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;

                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 = seg_code;
}


void kd_display(uint16_t value, uint8_t max_digits, const int8_t dp_pos/*=-1*/)
{
        //
        // Prepare seg code for LED
       
        _digits = seg_code;
        value /= 10;

        _digits = seg_code;

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

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



另外,为了养家糊口,承接工控项目。
我不会无聊地灌水顶贴,请大家有空帮忙顶顶哦。

plc_avr 发表于 2008-1-25 10:41:19

好东西,我顶! 我拆过电磁炉里面就是用这种方案的。

ghost2 发表于 2008-1-25 10:52:26

哦,裤子来了

qxs5264 发表于 2008-2-2 14:03:16

我纯属灌水来了!

mowin 发表于 2008-2-2 14:12:37

我有空帮忙顶顶

ddwl99 发表于 2008-2-2 17:01:20

初学者,哈哈~

asktutu 发表于 2008-2-2 18:25:48

顶一下

xiaobendan 发表于 2008-2-3 08:27:10

这样弄的话在扫描按键时是不是要关掉显示?是不是要影响亮度问题?
不过在显示的基础上只用1根线,就弄了8个按键还是很合算的。

ghost2 发表于 2008-2-3 10:54:48

回楼上,扫描按键时的确需要关掉显示
// Disable all digits first
PORT_PIN_CLR(DIGIT1);
PORT_PIN_CLR(DIGIT2);
PORT_PIN_CLR(DIGIT3);
PORT_PIN_CLR(DIGIT4);

最近增加了一片74HC138,可以支持到8位显示

microcheng 发表于 2008-2-15 17:51:25

非常不错,不过现在大部分电磁炉的面板显示方案已经逐渐被如下方案代替,付上原理图和范例程序,以飨广大需要的朋友
1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_214535.GIF
点击此处打开ourdev_214536.pdf(文件大小:15K)
点击此处打开ourdev_214537.pdf(文件大小:156K)

ghost2 发表于 2008-2-15 19:26:38

楼上的大哥,谢谢你的样片。
现在的方案是6位显示,74HC138+74HC164,已经超出了贵公司的芯片方案价格。
早知道客户会由4位改成6位,就直接用你的方案了……

abcdezh 发表于 2008-3-6 09:58:30

dind ding

vivalite 发表于 2008-3-6 10:05:03

呵呵 原来我用中颖69P20C做项目是时也是这么连的

zengdong 发表于 2008-8-8 16:35:33

楼主的程序有问题吗?
   if( PORT_PIN_VALUE(KEY_FB) == 0 ) 是否改成while( PORT_PIN_VALUE(KEY_FB) == 0 )

Stitch 发表于 2009-10-8 17:15:08

M

xianfen928 发表于 2009-10-8 20:49:02

哈,我家电磁炉三星单片机坏了,我拆开后根据控制板PCB把原理图画出来了,也是用164控制键盘扫描、LED灯、LED数码管,我现在改用AVR16控制,已经可以炒菜了并且能调功率,在软件控制上确实要非常注意,如果谁有兴趣我可以把资料传上来,

Stitch 发表于 2009-10-8 20:52:49

【15楼】 xianfen928
哈,我家电磁炉三星单片机坏了,我拆开后根据控制板PCB把原理图画出来了,也是用164控制键盘扫描、LED灯、LED数码管,我现在改用AVR16控制,已经可以炒菜了并且能调功率,在软件控制上确实要非常注意,如果谁有兴趣我可以把资料传上来,
————————————————————
(改后)调温是靠间歇的还是………………?

hkap 发表于 2009-10-8 21:43:05

http://cache.amobbs.com/bbs_upload782111/files_19/ourdev_489495.JPG
(原文件名:未命名.JPG)

楼主这个电路和我用的如出一辙,只是我用了两个164,5个口线,驱动4个LED,16个按键

guantingwei 发表于 2009-10-8 21:50:48

如果两个按键被同时按下呢?

lv998127 发表于 2009-10-9 09:17:18

有用

gxy508 发表于 2009-10-9 16:22:30

mark

Heavin 发表于 2009-10-10 11:01:00

http://cache.amobbs.com/bbs_upload782111/files_19/ourdev_489989.jpg
(原文件名:164.jpg)

我都贴一个,1/4 duty+24Key(方便摆放导入PCB再手动连。

erxun 发表于 2009-10-10 11:13:58

支持两个按钮同时按下,
按钮数据是串入的,8个都同时按下,也能检测到。

Heavin 发表于 2009-10-10 11:15:59

LS的,问题是在不检测时两个同时按下会影响显示,我图上加4148就是为了解决这个的。

cmgao 发表于 2009-10-10 21:14:02

在按下按键是显示会不会闪烁?

ZGGDYD 发表于 2009-11-6 20:24:00

顶!

bbi3014 发表于 2009-11-10 20:14:32

顶啊

lv998127 发表于 2010-1-7 14:32:59

顶顶!

zhuyi25762 发表于 2010-9-14 10:36:05

发现大家怎么都不把完整的东西发上来,而且发上来的也有很多问题,不明白是否真的能用?,,这程序我试了不行,turn清0都没有,能用吗?

tangwei039 发表于 2010-9-24 11:16:03

mark

bondxie3 发表于 2010-11-4 14:32:43

标记学习

maxuedong 发表于 2011-1-6 16:37:14

mark

ljt8015 发表于 2011-1-6 16:40:37

不错!~

ringan865 发表于 2011-1-6 16:53:33

mark

RENMA 发表于 2011-1-6 17:51:38

MARK

xinxinEC 发表于 2011-2-21 14:30:28

mark

xunke 发表于 2011-2-21 17:56:36

回复【楼主位】ghost2
-----------------------------------------------------------------------

不错!顶一下

823032003 发表于 2011-3-13 22:16:23

我们也这样用啊

hzr0071 发表于 2011-3-13 22:47:17

直接用100o的上拉或者推挽模式,不就解决了吗。stc12c5a32s2才7块一个。

zhangli2020 发表于 2011-3-14 01:55:20

记号

wpnx 发表于 2011-3-14 08:44:51

mark

electricit 发表于 2011-3-14 08:51:01

mark

abc220 发表于 2011-3-14 11:20:40

mark

cuikai12345 发表于 2011-4-6 22:11:38

MARK

myworkmail 发表于 2011-4-25 16:35:00

MARK

hu7215 发表于 2011-4-25 20:30:59

学习

cxbbb 发表于 2011-4-25 21:01:36

学习

gloryzkl 发表于 2011-4-26 12:30:55

m

wukaka 发表于 2011-4-27 22:06:22

学习!

jacky82512 发表于 2011-4-28 16:02:03

回复【15楼】xianfen928
-----------------------------------------------------------------------

资料传上来吧

danfeidie 发表于 2011-4-28 19:00:47

好!!!!!!!!!

suncq 发表于 2011-4-28 19:06:25

mark

CHENXIAOTIAN 发表于 2011-4-28 20:18:00

mark

zyw19987 发表于 2011-5-28 07:10:24

74HC164单行多列键盘扫描并显示

woody1983cn 发表于 2011-5-28 08:24:43

mark

zzh90513 发表于 2011-5-28 11:10:25

mark

xiaowu191 发表于 2011-5-28 12:17:39

留名

hongguoguo 发表于 2011-9-1 11:20:10

可能对我有用,先看看

ljt80158015 发表于 2011-9-1 11:33:52

经典!~

bingshuihuo888 发表于 2011-9-2 08:02:38

非常不错,

walshao 发表于 2011-9-2 09:41:29

mark

wtt_lc 发表于 2011-10-9 17:32:33

mark

a20084666 发表于 2013-8-29 16:33:03

Stitch 发表于 2009-10-8 20:52 static/image/common/back.gif
【15楼】 xianfen928
哈,我家电磁炉三星单片机坏了,我拆开后根据控制板PCB把原理图画出来了,也是用1 ...

哥们,你还有164控制的资料没,很好奇哦,你居然能够控制了,厉害啊

a20084666 发表于 2013-8-29 16:43:16

hkap 发表于 2009-10-8 21:43 static/image/common/back.gif
(原文件名:未命名.JPG)

楼主这个电路和我用的如出一辙,只是我用了两个164,5个口线,驱动4个LED,16个 ...

74hc164这东西好厉害的说,我在研究这个东西,哈哈,我用2个74hc164驱动4个数码管和4个按键,我在按键加减数字时遇到难题了,因为是动态显示,要在按按键的时候,数码管是显示的。好纠结啊

a20084666 发表于 2013-8-29 16:45:10

Heavin 发表于 2009-10-10 11:01 static/image/common/back.gif
(原文件名:164.jpg)

我都贴一个,1/4 duty+24Key(方便摆放导入PCB再手动连。

好牛逼啊能把资料给看看么 我的扣扣是326103151,求资料有莫有

rejoice818 发表于 2013-8-29 22:48:09

很久没来AVR论坛,过来顶一下

wqhzhy5858 发表于 2013-8-29 22:54:29

记号下,用164扩展IO用的也挺多的

漂渺 发表于 2015-6-7 20:27:54

学习,这个对于IO口少的MCU来说,太有用了

zwcled 发表于 2015-6-7 21:14:00

我也有过类似的经历,但是不用164了,因他是动态的占用定时器,并且电路又复杂,现在的专用显示IC才两三毛钱,两线通信,发个数给显示寄存器什么都不用管,然后再读一下寄存器看一下有没有键按下,就是那个TM的什么东东。

s20120907 发表于 2015-8-5 21:52:51

谁能普及下原理

xxzzhy 发表于 2015-8-6 08:52:09

不错不错。顶一下、{:lol:}
页: [1]
查看完整版本: 74HC164键扫+显示实例,已经过项目验证