标题:
51单片机学习:4*4矩阵键盘与可对时电子钟
[打印本页]
作者:
51黑电子迷
时间:
2017-2-9 22:19
标题:
51单片机学习:4*4矩阵键盘与可对时电子钟
今天学习了下矩阵键盘,
4*4, 分别代表0~F这16个数字
我们按了哪个键就显示到数码管上
看完郭老师讲解原理后就自己动手写了,郁闷的是
在keil软件中,我在switch-case语句中 少了个冒号,竟然编译通过!
结果当然不正确了,然后我再keil中调试代码,那更郁闷了,P3口在扫描到第2行键盘时就
会复位成0xff,怎么赋值都没用,其实是没写冒号啊!
调了半天都不行,最后不得不将STC89C52RC换上仿真芯片SST89E516,在线调试后才发现的错误,
然后参考书上的代码才调试成功的,表示无语~~~
mark下
#include <reg52.h>
#include "MY51.H"
void showKey(uint8 num); //静态显示
void keyScan();
void main()
{
showKey(18); //初始显示的是6个负号
while(1)
{ //循环检测
keyScan();
}
}
void showKey(uint8 num)
{
P0=0xc0; //11000000 打开6个数码管
wela=open;
wela=lock;
P0=table[num];
dula=1;
dula=0;
}
void keyScan()
{
uint8 num=0; //定义显示的数字
uint8 temp=0; //P3口回读信息
uint8 i=0; //定义矩阵键盘行号索引
for(i=0; i<4;i++) //共4行
{
P3=_crol_(0xfe,i); //扫描的行索引号,从第0行到第3行
temp=P3; //读取P3口
temp=temp&0xf0; //提取高4位
if(temp!=0xf0) //按键了
{
delayms(5); //消抖
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0) //真的按键了
{
switch(temp)
{
case 0xe0: //1110 0000
{
num=0+4*i;
break;
}
case 0xd0: //1101 0000
{
num=1+4*i;
break;
}
case 0xb0: //1011 0000
{
num=2+4*i;
break;
}
case 0x70: //0111 0000
{
num=3+4*i;
break;
}
default:
{
num=18; //18号索引是负号
led7=0; // 按了不该按的指示灯
break;
}
}
while(1) //松开按键检测
{
temp=P3; //读取P3口
temp=temp&0xf0; //提取高4位
if(temp==0xf0) //松开按键了
{
delayms(5);
temp=P3;
temp=temp&0xf0;
if(temp==0xf0) //真的松开键盘了
{
break;
}
}
}
showKey(num); //静态显示按键
}
}
}
}
void T0_Work() //T0定时器调用的工作函数
{
}
复制代码
#ifndef _MY51_H_
#define _MY51_H_
#include <math.h>
#include <intrins.h>
typedef int int16 ;
typedef int INT16 ;
typedef unsigned int uint16 ;
typedef unsigned int UINT16 ;
typedef unsigned short uint ;
typedef unsigned short UINT ;
typedef unsigned short word ;
typedef unsigned short WORD ;
typedef unsigned long uint32 ;
typedef unsigned long UINT32 ;
typedef unsigned long DWORD ;
typedef unsigned long dword ;
typedef signed long int32 ;
typedef signed long INT32 ;
typedef float float32 ;
typedef double double64 ;
typedef signed char int8 ;
typedef signed char INT8 ;
typedef unsigned char byte ;
typedef unsigned char BYTE ; //WINDOWS的windef.h里面是这么定义的
typedef unsigned char uchar ;
typedef unsigned char UCHAR ;
typedef unsigned char UINT8 ;
typedef unsigned char uint8 ;
typedef unsigned char BOOL ; //windows中定义BOOL为int
typedef unsigned char bool ; //bool是c++的内置类型
#define TRUE 1
#define true 1
#define FALSE 0
#define false 0
#define open 1 //open和close用于 标志打开和关闭状态
#define OPEN 1
#define close 0
#define CLOSE 0
#define lock 0
#define start 1
#define START 1
#define stop 0
#define STOP 0
#define keyDown 0
#define keyUp 1
sbit dula =P2^6; //段选锁存器控制 控制笔段
sbit wela =P2^7; //位选锁存器控制 控制位置
#define led P1 //灯总线控制
sbit led0=P1^0; //8个led灯,阴极送低电平点亮
sbit led1=P1^1;
sbit led2=P1^2;
sbit led3=P1^3;
sbit led4=P1^4;
sbit led5=P1^5;
sbit led6=P1^6;
sbit led7=P1^7;
sbit keyS2=P3^4; //4个独立按键
sbit keyS3=P3^5;
sbit keyS4=P3^6;
sbit keyS5=P3^7;
void displaySMG(uint8 one,uint8 two,uint8 three,uint8 four,uint8 five,uint8 six,uint8 dot);
void delayms(uint16 ms);
void T0_Work();
void delayms(uint16 ms) //软延时函数
{
uint16 i,j;
for(i=ms;i>0;i--)
{
for(j=113;j>0;j--)
{}
}
}
///////////////////////////////////////////////////////////////////////////
#define dark 0x11 //在段中,0x11是第17号元素,为0是低电平,数码管不亮
#define dotDark 0xff //小数点全暗时
uint8 code table[]= { //0~F外加小数点和空输出的数码管编码
0x3f , 0x06 , 0x5b , 0x4f , // 0 1 2 3
0x66 , 0x6d , 0x7d , 0x07 , // 4 5 6 7
0x7f , 0x6f , 0x77 , 0x7c , // 8 9 A B
0x39 , 0x5e , 0x79 , 0x71 , // C D E F
0x80 , 0x00 ,0x40 // . 空 负号 空时是第0x11号也就是第17号元素
};
/////////////////////////////////////////////////////////////////////////////
uint8 TH0Cout=0 ; //初值
uint8 TL0Cout=0 ;
uint16 T0IntCout=0; //中断计数
uint16 T0IntCountAll=0; //(N-1)/65536+1; //总中断次数
bool bT0Delay=false; //使用延时函数标志,初始未用
bool bT0Over=false; //中断处理函数执行结果之一
void startT0(uint32 ms) //开启定时器
{
float32 t=ms/1000.0; //定时时间
double64 fox =11.0592*(pow(10,6)); //晶振频率
uint32 N=(t*fox)/12 ; //定时器总计数值
TH0Cout =(65536-N%65536)/256; //装入计时值零头计数初值
TL0Cout =(65536-N%65536)%256;
T0IntCountAll=(N-1)/65536+1; //总中断次数
TMOD=TMOD | 0x01; //设置定时器0的工作方式为1
EA =open; //打开总中断
ET0=open; //打开定时器中断
TH0=TH0Cout; //定时器装入初值
TL0=TL0Cout;
TR0=start; //启动定时器
}
void delayT0(uint32 ms) //硬延时函数,自己乱写的不好用,求指点
{
startT0(ms); //启动定时器
bT0Delay=true; //告诉T0定时器,起用延时模式
while(bT0Over==false); //时间没到的话继续检测
bT0Over=false; //时间到了,让标志复位
}
void T0_times() interrupt 1 //T0定时器中断函数
{
T0IntCout++;
if(T0IntCout==T0IntCountAll) //达到总中断次数值
{
T0IntCout=0; //中断次数清零,重新计时
bT0Over=true; //时间真的到了
if(bT0Delay) //本次中断是用来延时的吗
{
TR0=stop; //如果是由延时函数开启T0的话,关闭T0
return;
}
TH0=TH0Cout; //循环定时的话要重装初值,每次定时1秒,重装一次
TL0=TL0Cout;
T0_Work(); //工作函数
}
}
////////////////////////////////////////////////////////////////////////////////
void displaySMG(uint8 oneWela,uint8 twoWela,uint8 threeWela,uint8 fourWela,uint8 fiveWela,uint8 sixWela,uint8 dot)
{ //控制6位数码管显示函数,不显示的位用参数 dark
P0=0;
dula=1;
dula=0; //段选数据清空并锁定
//////////////////////////
P0=0xff; //送位数据前关闭所有显示
wela=1;
P0=0xfe;
wela=0;
P0=0; //低电平输到数码管阳极,避免数码管吴亮
dula=1;
P0=table[oneWela]|((0x01&dot)?0x00:0x80); //送段数据,使用小数点显示标志
dula=0;
delayms(2);
/////////////////////////
P0=0xff;
wela=1;
P0=0xfd;
wela=0;
P0=0;
dula=1;
P0=table[twoWela]|((0x02&dot)?0x00:0x80);
dula=0;
delayms(2);
/////////////////////////
P0=0xff;
wela=1;
P0=0xfb;
wela=0;
P0=0;
dula=1;
P0=table[threeWela]|((0x04&dot)?0x00:0x80);
dula=0;
delayms(2);
/////////////////////////
P0=0xff;
wela=1;
P0=0xf7;
wela=0;
P0=0;
dula=1;
P0=table[fourWela]|((0x08&dot)?0x00:0x80);
dula=0;
delayms(2);
/////////////////////////
P0=0xff;
wela=1;
P0=0xef;
wela=0;
P0=0;
dula=1;
P0=table[fiveWela]|((0x10&dot)?0x00:0x80);
dula=0;
delayms(2);
/////////////////////////
P0=0xff;
wela=1;
P0=0xdf;
wela=0;
P0=0;
dula=1;
P0=table[sixWela]|((0x20&dot)?0x00:0x80);
dula=0;
delayms(2);
}
#endif
复制代码
作者:
51黑电子迷
时间:
2017-2-9 22:21
51单片机学习笔记:可对时电子钟
本篇是对上一篇的改进,昨天学习了第4章 中的独立键盘的使用
独立键盘拥有自己独有的IO口,所以比较简单,我上一篇写的电子钟程序只能烧程序对时,
不能手动按键对时,这肯定是最差劲的做法,所以学习了按键之后,就立马动手改进我的电子钟了
同时改进了数码管小数点的显示,消除了叠影
使用芯片STC89C52RC, 2个锁存器
6个带小数点共阴极数码管显示一个24时制时钟
没有时钟芯片,所以掉电后时间会复位
原理图为TX-1C开发板
==============================
最终显示的<时.分.秒>是 16.31.37 形式
使用3个按键, S2 S3 S5
其中S2和S3是加减数值,S5是切换对时状态,
#include <reg52.h>
#include "MY51.H"
void show();
int8 shi=22; //初识时间22:45:00 按S5键进入对时模式
int8 fen=45;
int8 miao=0;
uint8 timeFlag=0;//0计时模式,1校对时钟,2校对分钟,3校对秒钟
void main()
{
startT0(1000); //开始定时器
while(1)
{
show(); //送入数码管显示
if(keyS5==keyDown) //按下S5键
{
delayms(5);//消抖处理
if(keyS5==keyDown)
{
while(1)
{
show();
if(keyS5==keyUp)//放开按钮
{
delayms(5); //消抖处理
if(keyS5==keyUp)
{
break;
}
}
}
timeFlag=(++timeFlag)%4; //按S5键进行状态切换
while(timeFlag)
{
if(timeFlag==1)
{
led=0xff;
led7=0; //进入对时钟模式,且打开7号指示灯
}
else if(timeFlag==2)
{
led=0xff;
led5=0; //进入校对分钟模式,且打开5号指示灯
}
else if(timeFlag==3)
{
led=0xff;
led3=0; //进入校对秒钟模式,且打开3号指示灯
}
show(); //刷新数码管
if(keyS2==keyDown)//S2和S3用于调整数值,加减运算
{
delayms(5);//消抖处理
if(keyS2==keyDown)
{
if(timeFlag==1)
{
shi--;
if(shi<0)
{
shi=23;
}
}
else if(timeFlag==2)
{
fen--;
if(fen<0)
{
fen=59;
}
}
else if(timeFlag==3)
{
miao--;
if(miao<0)
{
miao=59;
}
}
while(1)
{
show(); //就算S2键被按着,也要刷新数码管
if(keyS2==keyUp)
{
delayms(10);
if(keyS2==keyUp)
{
break;
}
}
}
}
}
if(keyS3==keyDown)
{
delayms(5);//消抖处理
if(keyS3==keyDown)
{
if(timeFlag==1)
{
shi++;
if(shi>23)
{
shi=0;
}
}
else if(timeFlag==2)
{
fen++;
if(fen>59)
{
fen=0;
}
}
else if(timeFlag==3)
{
miao++;
if(miao>59)
{
miao=0;
}
}
while(1)
{
show();
if(keyS3==keyUp)
{
delayms(5);
if(keyS3==keyUp)
{
break;
}
}
}
}
}
if(keyS5==keyDown)
{
delayms(5);//消抖处理
if(keyS5==keyDown)
{
timeFlag=(++timeFlag)%4;//按S5键切换状态
while(1)
{
show();
if(keyS5==keyUp)
{
delayms(5);
if(keyS5==keyUp)
{
break;
}
}
}
}
}
}
led=0xff; //对时结束,指示灯灭
}
}
}
}
void show() //显示时钟
{
uint8 oneWela,twoWela,threeWela,foreWela,fiveWela,sixWela; //oneWela是最左边的数码管
sixWela =miao%10;
fiveWela=miao/10;
foreWela=fen%10;
threeWela=fen/10;
twoWela=shi%10;
oneWela=shi/10;
displaySMG(oneWela,twoWela,threeWela,foreWela,fiveWela,sixWela,0xf5); //0xf5是小数点的位置
}
void T0_Work() //T0定时器调用的工作函数
{
miao++;
if(miao>59)
{
miao=0;
fen++;
}
if(fen>59)
{
fen=0;
shi++;
}
if(shi>23)
{
shi=0;
}
}
复制代码
#ifndef _MY51_H_
#define _MY51_H_
#include <math.h>
#include <intrins.h>
typedef int int16 ;
typedef int INT16 ;
typedef unsigned int uint16 ;
typedef unsigned int UINT16 ;
typedef unsigned short uint ;
typedef unsigned short UINT ;
typedef unsigned short word ;
typedef unsigned short WORD ;
typedef unsigned long uint32 ;
typedef unsigned long UINT32 ;
typedef unsigned long DWORD ;
typedef unsigned long dword ;
typedef signed long int32 ;
typedef signed long INT32 ;
typedef float float32 ;
typedef double double64 ;
typedef signed char int8 ;
typedef signed char INT8 ;
typedef unsigned char byte ;
typedef unsigned char BYTE ; //WINDOWS的windef.h里面是这么定义的
typedef unsigned char uchar ;
typedef unsigned char UCHAR ;
typedef unsigned char UINT8 ;
typedef unsigned char uint8 ;
typedef unsigned char BOOL ; //windows中定义BOOL为int
typedef unsigned char bool ; //bool是c++的内置类型
#define TRUE 1
#define true 1
#define FALSE 0
#define false 0
#define open 1 //open和close用于 标志打开和关闭状态
#define OPEN 1
#define close 0
#define CLOSE 0
#define lock 0
#define start 1
#define START 1
#define stop 0
#define STOP 0
#define keyDown 0
#define keyUp 1
sbit dula =P2^6; //段选锁存器控制 控制笔段
sbit wela =P2^7; //位选锁存器控制 控制位置
#define led P1 //灯总线控制
sbit led0=P1^0; //8个led灯,阴极送低电平点亮
sbit led1=P1^1;
sbit led2=P1^2;
sbit led3=P1^3;
sbit led4=P1^4;
sbit led5=P1^5;
sbit led6=P1^6;
sbit led7=P1^7;
sbit keyS2=P3^4; //4个独立按键
sbit keyS3=P3^5;
sbit keyS4=P3^6;
sbit keyS5=P3^7;
void displaySMG(uint8 one,uint8 two,uint8 three,uint8 four,uint8 five,uint8 six,uint8 dot);
void delayms(uint16 ms);
void T0_Work();
void delayms(uint16 ms) //软延时函数
{
uint16 i,j;
for(i=ms;i>0;i--)
{
for(j=113;j>0;j--)
{}
}
}
///////////////////////////////////////////////////////////////////////////
#define dark 0x11 //在段中,0x11是第17号元素,为0是低电平,数码管不亮
#define dotDark 0xff //小数点全暗时
uint8 code table[]= { //0~F外加小数点和空输出的数码管编码
0x3f , 0x06 , 0x5b , 0x4f , // 0 1 2 3
0x66 , 0x6d , 0x7d , 0x07 , // 4 5 6 7
0x7f , 0x6f , 0x77 , 0x7c , // 8 9 A B
0x39 , 0x5e , 0x79 , 0x71 , // C D E F
0x80 , 0x00 // . 空 空时是第0x11号也就是第17号元素
};
/////////////////////////////////////////////////////////////////////////////
uint8 TH0Cout=0 ; //初值
uint8 TL0Cout=0 ;
uint16 T0IntCout=0; //中断计数
uint16 T0IntCountAll=0; //(N-1)/65536+1; //总中断次数
bool bT0Delay=false; //使用延时函数标志,初始未用
bool bT0Over=false; //中断处理函数执行结果之一
void startT0(uint32 ms) //开启定时器
{
float32 t=ms/1000.0; //定时时间
double64 fox =11.0592*(pow(10,6)); //晶振频率
uint32 N=(t*fox)/12 ; //定时器总计数值
TH0Cout =(65536-N%65536)/256; //装入计时值零头计数初值
TL0Cout =(65536-N%65536)%256;
T0IntCountAll=(N-1)/65536+1; //总中断次数
TMOD=TMOD | 0x01; //设置定时器0的工作方式为1
EA =open; //打开总中断
ET0=open; //打开定时器中断
TH0=TH0Cout; //定时器装入初值
TL0=TL0Cout;
TR0=start; //启动定时器
}
void delayT0(uint32 ms) //硬延时函数,自己乱写的不好用,求指点
{
startT0(ms); //启动定时器
bT0Delay=true; //告诉T0定时器,起用延时模式
while(bT0Over==false); //时间没到的话继续检测
bT0Over=false; //时间到了,让标志复位
}
void T0_times() interrupt 1 //T0定时器中断函数
{
T0IntCout++;
if(T0IntCout==T0IntCountAll) //达到总中断次数值
{
T0IntCout=0; //中断次数清零,重新计时
bT0Over=true; //时间真的到了
if(bT0Delay) //本次中断是用来延时的吗
{
TR0=stop; //如果是由延时函数开启T0的话,关闭T0
return;
}
TH0=TH0Cout; //循环定时的话要重装初值,每次定时1秒,重装一次
TL0=TL0Cout;
T0_Work(); //工作函数
}
}
////////////////////////////////////////////////////////////////////////////////
void displaySMG(uint8 oneWela,uint8 twoWela,uint8 threeWela,uint8 fourWela,uint8 fiveWela,uint8 sixWela,uint8 dot)
{ //控制6位数码管显示函数,不显示的位用参数 dark
P0=0;
dula=1;
dula=0; //段选数据清空并锁定
//////////////////////////
P0=0xff; //送位数据前关闭所有显示
wela=1;
P0=0xfe;
wela=0;
P0=0; //低电平输到数码管阳极,避免数码管吴亮
dula=1;
P0=table[oneWela]|((0x01&dot)?0x00:0x80); //送段数据,小数点可选显示 dula=0;
delayms(2);
/////////////////////////
P0=0xff;
wela=1;
P0=0xfd;
wela=0;
P0=0;
dula=1;
P0=table[twoWela]|((0x02&dot)?0x00:0x80);
dula=0;
delayms(2);
/////////////////////////
P0=0xff;
wela=1;
P0=0xfb;
wela=0;
P0=0;
dula=1;
P0=table[threeWela]|((0x04&dot)?0x00:0x80);
dula=0;
delayms(2);
/////////////////////////
P0=0xff;
wela=1;
P0=0xf7;
wela=0;
P0=0;
dula=1;
P0=table[fourWela]|((0x08&dot)?0x00:0x80);
dula=0;
delayms(2);
/////////////////////////
P0=0xff;
wela=1;
P0=0xef;
wela=0;
P0=0;
dula=1;
P0=table[fiveWela]|((0x10&dot)?0x00:0x80);
dula=0;
delayms(2);
/////////////////////////
P0=0xff;
wela=1;
P0=0xdf;
wela=0;
P0=0;
dula=1;
P0=table[sixWela]|((0x20&dot)?0x00:0x80);
dula=0;
delayms(2);
}
#endif
复制代码
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1