专家
公告
财富商城
电子网
旗下网站
首页
问题库
专栏
标签库
话题
专家
NEW
门户
发布
提问题
发文章
51单片机
求图中IO口扩展的程序!
2019-07-16 04:11
发布
×
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
站内问答
/
51单片机
9009
19
1119
本帖最后由 herochenzhao 于 2012-10-25 19:37 编辑
最近在做一个项目,发现
单片机
的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;
}
加载中...
查看其它19个回答
一周热门
更多
>
相关问题
【东软载波ESF0654 PDS开发板活动】开箱
1 个回答
东软载波ESF0654 PDS开发板外部中断
1 个回答
东软载波ESF0654 PDS开发板高级控制定时器AD16C4T
1 个回答
用串口调试助手为什么只能在hex模式接收发送而在文本模式不行
9 个回答
触摸芯片SC02B/SC04B在地砖灯的设计方案
1 个回答
相关文章
51单片机与蓝牙模块连接
0个评论
51单片机的硬件结构
0个评论
基于51单片机的无线遥控器制作
0个评论
51单片机 AD转换
0个评论
51单片机数码管递增显示
0个评论
如何实现对单片机寄存器的访问
0个评论
基于51单片机的指纹密码锁
0个评论
×
关闭
采纳回答
向帮助了您的知道网友说句感谢的话吧!
非常感谢!
确 认
×
关闭
编辑标签
最多设置5个标签!
51单片机
保存
关闭
×
关闭
举报内容
检举类型
检举内容
检举用户
检举原因
广告推广
恶意灌水
回答内容与提问无关
抄袭答案
其他
检举说明(必填)
提交
关闭
×
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
×
付费偷看金额在0.1-10元之间
确定
×
关闭
您已邀请
0
人回答
查看邀请
擅长该话题的人
回答过该话题的人
我关注的人
* 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;
}
一周热门 更多>