(本实验中的蜂鸣声 用LED10闪烁来表示,该实验中 STC15-IV版试验箱 上运行)
建一个文件夹,里面建两个子文件夹,一个叫仿真,一个叫真机
用keil C 创建工程,创建文件,粘贴代码:
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
uint bdata key;//声明变量,键状态
uint bdata edgk;//声明变量,键变化前沿
uchar data kcode;//声明变量,键编号
uchar data ktmr;//定义变量,消抖计时器
uchar data beeftmr;//定义变量,蜂鸣计时器
sbit BEEF=P3^0;//定义变量,蜂鸣器控制I/O
sbit K17=P3^3; //定义按键接口
sbit K0=key^8;//定义变量,开关型键位。大端方式:低字节存高地址,第8位始
sbit K1=key^9;
sbit K2=key^10;
sbit K3=key^11;
sbit K4=key^12;
sbit K5=key^13;
sbit K6=key^14;
sbit K7=key^15;
sbit K8=key^0;
sbit K9=key^1;
sbit KA=key^2;
sbit KB=key^3;
sbit KC=key^4;
sbit KD=key^5;
sbit KE=key^6;
sbit KF=key^7;
sbit EK0=edgk^8;//定义变量,触发型键位
sbit EK1=edgk^9;
sbit EK2=edgk^10;
sbit EK3=edgk^11;
sbit EK4=edgk^12;
sbit EK5=edgk^13;
sbit EK6=edgk^14;
sbit EK7=edgk^15;
sbit EK8=edgk^0;
sbit EK9=edgk^1;
sbit EKA=edgk^2;
sbit EKB=edgk^3;
sbit EKC=edgk^4;
sbit EKD=edgk^5;
sbit EKE=edgk^6;
sbit EKF=edgk^7;
/*sbit P_595_SER=P4^0; //定义 74HC595 的串行数据接口
sbit P_595_SRCLK=P4^3; //定义 74HC595 的移位脉冲接口
sbit P_595_RCLK=P5^4; //定义 74HC595 的输出寄存器锁存信号接口 */
uchar code seg7[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; //七段码表 0~9
uchar code scand_com[4]={0xfe,0xfd,0xfb,0xf7}; //4 种位选线信号数据
uchar data dis_buf[4]; //定义显示缓冲区
uchar data scand_num; //定义当前扫描位
/*void delay2ms5() //延时 2.5ms
{
unsigned int j;
for(j=0;j<429;j++);
} */
/*void send_595(uchar x) //从 STC 单片机移位输出 1 字节数据
{ uchar i;
for(i=0;i<8;i++) //循环移位,共 8 位
{
x=x<<1; //左移 1 位,最高位移出到 CY
P_595_SER=CY; //CY 从串行数据口输出
P_595_SRCLK=1; //输出移位脉冲
P_595_SRCLK=0;
}
}*/
void Timer0Int()//T0初始化,2.5ms定时@12MHz
{TMOD=0x01;//T0方式1,16位定时,初值不能重载
TL0=(65536-2500)%256;//T0定时器初值设置
TH0=(65536-2500)/256;
TF0=0;//清定时器溢出标志
TR0=1;//启动定时器
}
void readkey()//扫描键盘、存键状态
{uchar i;
P0=0x7f;//扫描第3列,列线输出为0
for(i=0;i<20;i++);//延时约10uS待列信号稳定,若键盘引线较长应延长
edgk=(~P0<<4)&0xf0;//读KC~KF键,有键按下读行线为0,求反转正逻辑
P0=0xbf;//扫描第2列
for(i=0;i<20;i++);
edgk|=(~P0)&0x0f;//读K8~KB键
edgk<<=8;
P0=0xdf;//扫描第1列
for(i=0;i<20;i++);
edgk|=(~P0<<4)&0xf0;//读K4~K7键
P0=0xef;//扫描第0列
for(i=0;i<20;i++);
edgk|=(~P0)&0x0f;//读K0~K3键
}
void keytrim()//消抖动,沿检出,求键号
{uint temp;//本行以下为:消抖动
if(edgk==0)ktmr=0;//无键,消抖计时器清零
else
{if(ktmr<255)ktmr++;//有键,消抖计时器+1(防溢出)
if(ktmr<8)edgk=0;//消抖20mS未到丢弃不稳定键
}
temp=edgk;//本行及以下为:键变化前沿提取。edgk保存本次键状态
edgk=(key^edgk)&edgk;//此时key还保存着上次循环键状态
key=temp;//暂存的本次循环键状态移至key
if(edgk!=0)//本行及以下为:求键号
{temp=edgk;//从低到高逐位查键,未查出kcode+1
for(kcode=0;(temp&0x1)==0;kcode++)temp>>=1;
}
else kcode=0x10;//无键,kcode=0x10
}
void keysound()//按键发出"嘀"声响
{if(edgk!=0)beeftmr=40;//有键变化沿,蜂鸣倒计时器100mS初值
if(beeftmr!=0){beeftmr--;BEEF=1;}//蜂鸣时间未到,走时、蜂鸣开
else BEEF=0;//蜂鸣时间已到,蜂鸣关
}
void display(void) //显示驱动函数
{
P2=0xff; //关闭所有位
P1=seg7[dis_buf[scand_num&3]]; //将当前扫描位七段码送 P1 口
P2=scand_com[scand_num&3]; //将当前扫描位选线信号送 P2 口
scand_num=(scand_num+1)%4; //调整扫描位的值,指向下一位
}
void main(void)
{
Timer0Int();
dis_buf[0]=0x0; dis_buf[1]=0x1; //显示"0123"
dis_buf[2]=0x2; dis_buf[3]=0x3;
while(1)
{
//delay2ms5();
//P1M1=0;
//P1M0=0;
while(!TF0);//2.5mS定时未到则等待
TF0=0;//清定时器溢出标志
TL0=(65536-2500)%256;//定时器初值恢复
TH0=(65536-2500)/256;
readkey();
display();
keytrim();//调用键状态消抖等处理函数
keysound();
K17=1; //准双向口,读之前先写 1
if(kcode<16)
{
dis_buf[0]=dis_buf[1]; dis_buf[1]=dis_buf[2];//键号从右边滚入
dis_buf[2]=dis_buf[3]; dis_buf[3]=kcode;
}
}
}
编译运行,并保存为.c的文件,添加在本工程的Group下面。
点击"project"下的"options for target1 'target1'",找到output选项,勾选"create hex file"
再次编译运行,就能在该文件夹中找到 相应的.hex文件
用Proteus画出仿真电路图

双击电路图中单片机,添加刚刚的.hex文件,点击运行按钮,就开始模拟了。
你能看到显示的是0123(你想改成什么就是什么了)
.用keil C创建工程(保存在真机的文件夹下面),创建文件,粘贴代码
#include<stc15.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
uint bdata key;//声明变量,键状态
uint bdata edgk;//声明变量,键变化前沿
uchar data kcode;//声明变量,键编号
uchar data ktmr;//定义变量,消抖计时器
uchar data beeftmr;
//sbit BEEF=P3^0;//定义变量,蜂鸣计时器
sbit K17=P3^3; //定义按键接口
sbit P_595_SER=P4^0; //定义 74HC595 的串行数据接口
sbit P_595_SRCLK=P4^3; //定义 74HC595 的移位脉冲接口
sbit P_595_RCLK=P5^4; //定义 74HC595 的输出寄存器锁存信号接口
sbit K0=key^8;//定义变量,开关型键位。大端方式:低字节存高地址,第8位始
sbit K1=key^9;
sbit K2=key^10;
sbit K3=key^11;
sbit K4=key^12;
sbit K5=key^13;
sbit K6=key^14;
sbit K7=key^15;
sbit K8=key^0;
sbit K9=key^1;
sbit KA=key^2;
sbit KB=key^3;
sbit KC=key^4;
sbit KD=key^5;
sbit KE=key^6;
sbit KF=key^7;
sbit EK0=edgk^8;//定义变量,触发型键位
sbit EK1=edgk^9;
sbit EK2=edgk^10;
sbit EK3=edgk^11;
sbit EK4=edgk^12;
sbit EK5=edgk^13;
sbit EK6=edgk^14;
sbit EK7=edgk^15;
sbit EK8=edgk^0;
sbit EK9=edgk^1;
sbit EKA=edgk^2;
sbit EKB=edgk^3;
sbit EKC=edgk^4;
sbit EKD=edgk^5;
sbit EKE=edgk^6;
sbit EKF=edgk^7;
uchar code seg7[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //七段码表 0~9 a-f
uchar code scand_com[4]={0xfe,0xfd,0xfb,0xf7}; //4 种位选线信号数据
uchar data dis_buf[4]; //定义显示缓冲区
uchar data scand_num; //定义当前扫描位
void Timer0Int()//T0初始化,2.5ms定时@12MHz
{
TMOD=0x01;//T0方式1,16位定时,初值不能重载
TL0=(65536-2500)%256;//T0定时器初值设置
TH0=(65536-2500)/256;
TF0=0;//清定时器溢出标志
TR0=1;//启动定时器
}
void send_595(uchar x) //从 STC 单片机移位输出 1 字节数据
{
uchar i;
for(i=0;i<8;i++) //循环移位,共 8 位
{
x=x<<1; //左移 1 位,最高位移出到 CY
P_595_SER=CY; //CY 从串行数据口输出
P_595_SRCLK=1; //输出移位脉冲
P_595_SRCLK=0;
}
}
void readkey()//扫描键盘、存键状态
{
uchar i;
P0=0x7f;//扫描第3列,列线输出为0
for(i=0;i<20;i++);//延时约10uS待列信号稳定,若键盘引线较长应延长
edgk=(~P0<<4)&0xf0;//读KC~KF键,有键按下读行线为0,求反转正逻辑
P0=0xbf;//扫描第2列
for(i=0;i<20;i++);
edgk|=(~P0)&0x0f;//读K8~KB键
edgk<<=8;
P0=0xdf;//扫描第1列
for(i=0;i<20;i++);
edgk|=(~P0<<4)&0xf0;//读K4~K7键
P0=0xef;//扫描第0列
for(i=0;i<20;i++);
edgk|=(~P0)&0x0f;//读K0~K3键
}
void keytrim()//消抖动,沿检出,求键号
{uint temp;//本行以下为:消抖动
if(edgk==0)ktmr=0;//无键,消抖计时器清零
else
{
if(ktmr<255)ktmr++;//有键,消抖计时器+1(防溢出)
if(ktmr<8)edgk=0;//消抖20mS未到丢弃不稳定键
}
temp=edgk;//本行及以下为:键变化前沿提取。edgk保存本次键状态
edgk=(key^edgk)&edgk;//此时key还保存着上次循环键状态
key=temp;//暂存的本次循环键状态移至key
if(edgk!=0)//本行及以下为:求键号
{
temp=edgk;//从低到高逐位查键,未查出kcode+1
for(kcode=0;(temp&0x1)==0;kcode++)temp>>=1;
}
else kcode=0x10;//无键,kcode=0x10
}
void keysound()//按键发出"嘀"声响
{
if(edgk!=0)beeftmr=40;//有键变化沿,蜂鸣倒计时器100mS初值
if(beeftmr!=0){beeftmr--;P46=0;}//蜂鸣时间未到,走时、蜂鸣开 ,0表示亮
else P46=1;//蜂鸣时间已到,蜂鸣关
}
void display(void) //显示驱动函数
{
send_595(scand_com[scand_num&3]);//将当前扫描位选线信号发送
send_595(seg7[dis_buf[scand_num&3]]);//将当前扫描位七段数据发送
P_595_RCLK=1;//16位数据移位后锁入输出寄存器中
P_595_RCLK=0;
scand_num=(scand_num+1)%4; //调整扫描位的值,指向下一位
}
void main(void)
{
P0M1=0;
P0M0=0;
Timer0Int();
dis_buf[0]=0x0; dis_buf[1]=0x1; //显示"0106"
dis_buf[2]=0x0; dis_buf[3]=0x6;
while(1)
{
while(!TF0);//2.5mS定时未到则等待
TF0=0;//清定时器溢出标志
TL0=(65536-2500)%256;//定时器初值恢复
TH0=(65536-2500)/256;
readkey();
display();
keytrim();//调用键状态消抖等处理函数
keysound();
K17=1; //准双向口,读之前先写 1
if(kcode<16)
{
dis_buf[0]=dis_buf[1]; dis_buf[1]=dis_buf[2];//键号从右边滚入
dis_buf[2]=dis_buf[3]; dis_buf[3]=kcode;
}
}
}
重复步骤2的类似操作。
5.最后连接上真正的单片机实验板,载入程序即可
你可以在SW16键盘上面按键,从而LED10灯会闪烁