這篇代碼并未運用到DSC12C887時鐘芯片,而是運用了單片機自帶的定時器0完成,經試驗在清翔開發板上誤差為每小時快4s,且可通過硬體(矩陣鍵盤)更改時間!
目錄
- 前言
- 一、目標
- 二、教學
- 1.矩陣鍵盤
- 2.LCD1602
- 3.定時器0
- 三、例程(各個函式的作用我將在頭檔案為大家說明)
- 1.矩陣鍵盤(我使用的I/O口為P1)
- 2.LCD1602
- 3.延時
- 3.主函式
- 總結
前言
通過寫萬年歷來達到熟練使用定時器、LCD1602(甚至是OLED12864)和矩陣鍵盤的練習,
提示:以下是本篇文章正文內容,下面案例可供參考
一、目標
1.熟練掌握矩陣鍵盤的用法
2.熟練定時器安裝初值
3.熟練1602的使用方法
二、教學
1.矩陣鍵盤
郭天祥老師在《新概念51單片機C語言教程》一書中給了他的例程,但我認為太過于繁瑣,
這里我給出另一個解決方案:
1.先給低四位一個高電平(0x0f),檢測是哪一個I/O口被拉低,確定出某行Y
2.立馬給高四位一個高電平(0xf0),檢測是哪一個I/O口被拉低,確定出某列X
3.得出按鍵坐標(X,Y)
2.LCD1602
想要學會1602就應該掌握它的基本時序操作:
讀狀態 RS=Low,R/W=High,EN=H
讀資料 RS=H,R/W=H,EN=H
寫指令 RS=L,R/W=L,D0~D7=指令碼,EN=高脈沖
寫資料 RS=H,R/W=L,D0~D7=資料,EN=H
其控制器內部的RAM區域有80B的緩沖區可供我們寫顯示資料(00—0F、10—27、40—4F、50—67),其中在00—0F、40—4F中寫入的資料可以直接顯示出來,而另外兩個地址的資料需要通過移動,可以使用“0x18”或者“0x07”,讀者可自己探索,
關于1602將在例程中繼續為大家講解
3.定時器0
一般建立一個函式“void T0_time() interrupt 1”,其中interrupt 1是定時器0的中斷序號,單片機通過它來識別,C51一般用的是11.0592MHz的晶振,裝入初值方式如下:(例如50ms)
TH1=(65536-N)/256 ,TL1=(65536-N)%256
50mS=50 000uS
周期為12*(1/11059200)約等于1.09uS
N=50 000 /1.09 約等于 45872
三、例程(各個函式的作用我將在頭檔案為大家說明)
1.矩陣鍵盤(我使用的I/O口為P1)
Key.h
#ifndef __KEY_H
#define __KEY_H
#include "reg52.h"
/*宏定義*/
#define uchar unsigned char
#define uint unsigned int
#define Keyy P1
void key_scan();//負責掃描矩陣鍵盤
void delay(uint xms);//毫秒級延時
extern uchar Key_C;//列
extern uchar Key_R;//行
extern uint Key_Num;//對按鍵賦予名稱
#endif
Key.c
#include "Key.h"
uchar Key_C;//列
uchar Key_R;//行
uint Key_Num;
void key_scan()
{
Keyy = 0x0f;//檢測低四位某行
if(Keyy != 0x0f)//檢測是否被按下
{
delay(1);//消抖
if(Keyy != 0x0f)//再次檢測是否被按下
{
switch(Keyy)//確定某行
{
case(0x07): Key_R = 0; break;//第一行
case(0x0b): Key_R = 1; break;//第二行
case(0x0d): Key_R = 2; break;//第三行
case(0x0e): Key_R = 3; break;//第四行
}
}
}
Keyy = 0xf0;//檢測高四位某列
if(Keyy != 0xf0)
{
delay(1);
if(Keyy != 0Xf0)
{
switch(Keyy)
{
case(0x70): Key_C = 0; break;//第一列
case(0xb0): Key_C = 1; break;//第二列
case(0xd0): Key_C = 2; break;//第三列
case(0xe0): Key_C = 3; break;//第四列
}
}
}
/*確定出按鍵后為其命名*/
if(Key_R==0&&Key_C==0) Key_Num=16;
else if(Key_R==0&&Key_C==1) Key_Num=15;
else if(Key_R==0&&Key_C==2) Key_Num=14;
else if(Key_R==0&&Key_C==3) Key_Num=13;
else if(Key_R==1&&Key_C==0) Key_Num=12;
else if(Key_R==1&&Key_C==1) Key_Num=11;
else if(Key_R==1&&Key_C==2) Key_Num=10;
else if(Key_R==1&&Key_C==3) Key_Num=9;
else if(Key_R==2&&Key_C==0) Key_Num=8;
else if(Key_R==2&&Key_C==1) Key_Num=7;
else if(Key_R==2&&Key_C==2) Key_Num=6;
else if(Key_R==2&&Key_C==3) Key_Num=5;
else if(Key_R==3&&Key_C==0) Key_Num=4;
else if(Key_R==3&&Key_C==1) Key_Num=3;
else if(Key_R==3&&Key_C==2) Key_Num=2;
else if(Key_R==3&&Key_C==3) Key_Num=1;
}
void delay(uint xms)
{
uint i,j;
for(i=xms ;i>0 ;i--)
for(j=100 ;j>0 ;j--);
}
2.LCD1602
1602.h
#ifndef _1602_H
#define _1602_H
#include "reg52.h"
#define uchar unsigned char
#define uint unsigned int
sbit lcdrs=P3^5;
sbit lcdrw=P3^6;
sbit lcden=P3^4;
sbit dula=P2^6;
sbit wela=P2^7;
void init();//初始化
void Write_Com(uchar com);//寫指令
void Write_Data(uchar date);//寫資料
void Write_Str(uchar addr,uchar length,uchar *pbuf);/*顯示字串,第一個為地址,第二個為
長度,第三個為字符*/
void CGRAM_set();//將自定義字符資料寫入CGRAM ,用戶可以自定義8個字符
void lcd_wdat(uchar addr,int date);//寫4個字符
void lcd_wdat1(uchar addr,int date);//寫2個字符
#endif
1602.c
#include "1602.h"
#include "delay.h"
void init()
{
dula=0;
wela=0;
lcden=0;//關閉數碼管顯示,因為我在開發板上使用,I/O口與數碼管重復
Write_Com(0x38);
Write_Com(0x0c);
Write_Com(0x06);
Write_Com(0x01);
}
void Write_Com(uchar com)
{
lcdrs=0;
lcdrw=0;
P0=com;
Delay_Ms(5);
lcden=1;
Delay_Ms(5);
lcden=0;
}
void Write_Data(uchar date)
{
lcdrs=1;
lcdrw=0;
P0=date;
Delay_Ms(5);
lcden=1;
Delay_Ms(5);
lcden=0;
}
void Write_Str(uchar addr,uchar length,uchar *pbuf)
{
uchar i;
Write_Com(addr);
for(i=0;i<length;i++)
{
Write_Data(pbuf[i]);
}
}
void lcd_wdat(uchar addr,int date)
{
uchar a,b,c,d;
a=date/1000;
b=date%1000/100;
c=date%100/10;
d=date%10;
Write_Com(addr);
Write_Data(0x30+a);//0x30是屬于ASCII碼表,加上它就能顯示數值
Write_Data(0x30+b);
Write_Data(0x30+c);
Write_Data(0x30+d);
}
void lcd_wdat1(uchar addr,int date)
{
uchar a,b;
a=date/10;
b=date%10;
Write_Com(addr);
Write_Data(0x30+a);
Write_Data(0x30+b);
}
3.延時
delay.h
#ifndef _DELAY_H_
#define _DELAY_H_
#include "reg52.h"
#define uchar unsigned char
#define uint unsigned int
void Delay_Ms(uint xms);
void Delay_Us(uint xus);
#endif
delay.c
#include "delay.h"
void Delay_Ms(uint xms)//毫秒級
{
int x,y;
for(x=xms;x>0;x--)
for(y=110;y>0;y--);
}
void Delay_Us(uint xus)//微妙級
{
while(xus--);
}
3.主函式
按鍵:1時2分3秒加 5時6分7秒減
9年10月11日期加 13年14月15日期減
更改日期摁4鍵,先摁4再摁修改,再摁4,再修改
#include "reg52.h"
#include "1602.h"
#include "delay.h"
#include "Key.h"
uchar num;
int s;
void main()
{
int y,m,d;
int h,min;
TMOD=0x01;
TH0=(65535-45872)/256;
TL0=(65535-45872)%256;
EA=1;
ET0=1;
TR0=1;
init();
y=2020;
m=12;
d=12;
h=16;
min=33;
s=0;
/*****************************|
|******日期邏輯設定***********|
|*****************************/
A:/*goto標記位置*/
while(1)
{
/******************************|
|***********掃描鍵盤***********|
|******************************/
key_scan();
if(Key_Num==1)
{
y++;
}
if(Key_Num==2)
{
m++;
}
if(Key_Num==3)
{
d++;
}
if(Key_Num==5)
{
y--;
}
if(Key_Num==6)
{
m--;
}
if(Key_Num==7)
{
d--;
}
if(Key_Num==9)
{
h++;
}
if(Key_Num==10)
{
min++;
}
if(Key_Num==11)
{
s++;
}
if(Key_Num==13)
{
h--;
}
if(Key_Num==14)
{
min--;
}
if(Key_Num==15)
{
s--;
}
goto B;
}
/******************************|
|*************顯示*************|
|******************************/
B:while(1)/*goto標記位置*/
{
key_scan();
lcd_wdat(0x80,y);
Write_Str(0x84,1,"-");
lcd_wdat1(0x85,m);
Write_Str(0x87,1,"-");
lcd_wdat1(0x88,d);
lcd_wdat1(0x80+0x40,h);
Write_Str(0x82+0x40,1,":");
lcd_wdat1(0x83+0x40,min);
Write_Str(0x85+0x40,1,":");
lcd_wdat1(0x86+0x40,s);
/******************************|
|***********判斷進位***********|
|******************************/
if(m>12)
{
m=1;
y++;
}
else if(m<1)
{
m=12;
y--;
}
if(m==1||m==3||m==5||m==7||m==8||m==10||m==12)
{
if(d>31)
{
d=1;
m++;
}
else if(d<1)
{
if(m==5||m==7||m==10||m==12)
{
d=30;
m--;
}
else if(m==2||m==4||m==6||m==8||m==9||m==11||m==1)
{
d=31;
m--;
}
else if(m==3&&(y%4==0)&&(y%100!=0))
{
d=29;
m--;
}
else
{
d=28;
m--;
}
}
}
if(m==4||m==6||m==9||m==11)
{
if(d>30)
{
d=1;
m++;
}
else if(d<1)
{
if(m==5||m==7||m==10||m==12)
{
d=30;
m--;
}
else if(m==2||m==4||m==6||m==8||m==9||m==11||m==1)
{
d=31;
m--;
}
else if(m==3&&(y%4==0)&&(y%100!=0))
{
d=29;
m--;
}
else
{
d=28;
m--;
}
}
}
if(m==2)
{
if((y%4==0)&&(y%100!=0))
{
if(d>29)
{
d=1;
m++;
}
if(d<1)
{
d=31;
m--;
}
}
else
{
if(d>28)
{
d=1;
m++;
}
if(d<1)
{
d=31;
m--;
}
}
}
if(h>23)
{
h=0;
d++;
}
else if(h<0)
{
h=23;
}
if(min>59)
{
min=0;
h++;
}
else if(min<0)
{
min=59;
h--;
}
if(s>59)
{
s=0;
min++;
}
else if(s<0)
{
s=59;
min--;
}
if(Key_Num==4)
goto A;
}
}
void T0_time() interrupt 1
{
TH0=(65535-45872)/256;
TL0=(65535-45872)%256;
num++;
if(num==20)
{
s++;
num=0;
}
}
總結
這里的總結交給goto
雖然不提倡使用goto,因為會使代碼結構不清晰,但是合理的運用goto更能為代碼錦上添花,這里巧妙的使用了goto反而使結構思路清晰,
歡迎加入交流群:1033131250
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/236144.html
標籤:其他
下一篇:基于AMPL建模MATLAB平臺呼叫Gurobi,對HEMs集成的VPP進行優化處理。(第一步-簡單HEMs的優化模型建立)
