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;
}
另外,为了养家糊口,承接工控项目。
我不会无聊地灌水顶贴,请大家有空帮忙顶顶哦。 好东西,我顶! 我拆过电磁炉里面就是用这种方案的。 哦,裤子来了 我纯属灌水来了! 我有空帮忙顶顶 初学者,哈哈~ 顶一下 这样弄的话在扫描按键时是不是要关掉显示?是不是要影响亮度问题?
不过在显示的基础上只用1根线,就弄了8个按键还是很合算的。 回楼上,扫描按键时的确需要关掉显示
// Disable all digits first
PORT_PIN_CLR(DIGIT1);
PORT_PIN_CLR(DIGIT2);
PORT_PIN_CLR(DIGIT3);
PORT_PIN_CLR(DIGIT4);
最近增加了一片74HC138,可以支持到8位显示 非常不错,不过现在大部分电磁炉的面板显示方案已经逐渐被如下方案代替,付上原理图和范例程序,以飨广大需要的朋友
1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_214535.GIF
点击此处打开ourdev_214536.pdf(文件大小:15K)
点击此处打开ourdev_214537.pdf(文件大小:156K) 楼上的大哥,谢谢你的样片。
现在的方案是6位显示,74HC138+74HC164,已经超出了贵公司的芯片方案价格。
早知道客户会由4位改成6位,就直接用你的方案了…… dind ding 呵呵 原来我用中颖69P20C做项目是时也是这么连的 楼主的程序有问题吗?
if( PORT_PIN_VALUE(KEY_FB) == 0 ) 是否改成while( PORT_PIN_VALUE(KEY_FB) == 0 ) M 哈,我家电磁炉三星单片机坏了,我拆开后根据控制板PCB把原理图画出来了,也是用164控制键盘扫描、LED灯、LED数码管,我现在改用AVR16控制,已经可以炒菜了并且能调功率,在软件控制上确实要非常注意,如果谁有兴趣我可以把资料传上来, 【15楼】 xianfen928
哈,我家电磁炉三星单片机坏了,我拆开后根据控制板PCB把原理图画出来了,也是用164控制键盘扫描、LED灯、LED数码管,我现在改用AVR16控制,已经可以炒菜了并且能调功率,在软件控制上确实要非常注意,如果谁有兴趣我可以把资料传上来,
————————————————————
(改后)调温是靠间歇的还是………………? http://cache.amobbs.com/bbs_upload782111/files_19/ourdev_489495.JPG
(原文件名:未命名.JPG)
楼主这个电路和我用的如出一辙,只是我用了两个164,5个口线,驱动4个LED,16个按键 如果两个按键被同时按下呢? 有用 mark http://cache.amobbs.com/bbs_upload782111/files_19/ourdev_489989.jpg
(原文件名:164.jpg)
我都贴一个,1/4 duty+24Key(方便摆放导入PCB再手动连。 支持两个按钮同时按下,
按钮数据是串入的,8个都同时按下,也能检测到。 LS的,问题是在不检测时两个同时按下会影响显示,我图上加4148就是为了解决这个的。 在按下按键是显示会不会闪烁? 顶! 顶啊 顶顶! 发现大家怎么都不把完整的东西发上来,而且发上来的也有很多问题,不明白是否真的能用?,,这程序我试了不行,turn清0都没有,能用吗? mark 标记学习 mark 不错!~ mark MARK mark 回复【楼主位】ghost2
-----------------------------------------------------------------------
不错!顶一下 我们也这样用啊 直接用100o的上拉或者推挽模式,不就解决了吗。stc12c5a32s2才7块一个。 记号 mark mark mark MARK MARK 学习 学习 m 学习! 回复【15楼】xianfen928
-----------------------------------------------------------------------
资料传上来吧 好!!!!!!!!! mark mark 74HC164单行多列键盘扫描并显示 mark mark 留名 可能对我有用,先看看 经典!~ 非常不错, mark mark Stitch 发表于 2009-10-8 20:52 static/image/common/back.gif
【15楼】 xianfen928
哈,我家电磁炉三星单片机坏了,我拆开后根据控制板PCB把原理图画出来了,也是用1 ...
哥们,你还有164控制的资料没,很好奇哦,你居然能够控制了,厉害啊 hkap 发表于 2009-10-8 21:43 static/image/common/back.gif
(原文件名:未命名.JPG)
楼主这个电路和我用的如出一辙,只是我用了两个164,5个口线,驱动4个LED,16个 ...
74hc164这东西好厉害的说,我在研究这个东西,哈哈,我用2个74hc164驱动4个数码管和4个按键,我在按键加减数字时遇到难题了,因为是动态显示,要在按按键的时候,数码管是显示的。好纠结啊 Heavin 发表于 2009-10-10 11:01 static/image/common/back.gif
(原文件名:164.jpg)
我都贴一个,1/4 duty+24Key(方便摆放导入PCB再手动连。
好牛逼啊能把资料给看看么 我的扣扣是326103151,求资料有莫有 很久没来AVR论坛,过来顶一下 记号下,用164扩展IO用的也挺多的 学习,这个对于IO口少的MCU来说,太有用了 我也有过类似的经历,但是不用164了,因他是动态的占用定时器,并且电路又复杂,现在的专用显示IC才两三毛钱,两线通信,发个数给显示寄存器什么都不用管,然后再读一下寄存器看一下有没有键按下,就是那个TM的什么东东。 谁能普及下原理 不错不错。顶一下、{:lol:}
页:
[1]