利用 15 芯片的部分 IO 口实现可调电子时钟,跑秒,电压测量等功能。
以下是原代码,请读者配合着注释阅读。
#include
#include
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define SECOND 100
#define SECOND1 10
uint mvcc=5000;
ulong volt=0;
uchar tab1[16]="
uchar tab2[16]="
uchar tab3[16]="
uchar clock[3]={23,59,55};
uchar seconds[2]={0,0};
ulong vol[2]={0,0};
uchar utime,mtime,f,g,status,resl,res,state=1;
";
";
";
//供电电源为 5000mv 用于 AD 采样数据转换
//初始化为空格
//位定义三个按键(用来调时)
//位定义三个按键(用来切换功能)
/******************************* 12864LCD 引脚定义 **************************/
sbit key1=P2^1;
sbit key2=P2^2;
sbit key3=P2^4;
sbit key4=P2^0;
sbit key5=P2^3;
sbit key6=P2^5;
= P0^0;
sbit CS
sbit SID
= P0^1;
sbit SCLK = P0^2;
sbit PSB
= P0^3;
sbit RESET = P0^4;
//片选 高电平有效 单片 LCD 使用时可固定高电平
//数据
//时钟
//低电平时表示用串口驱动,可固定低电平
//LCD 复位,LCD 模块自带复位电路。可不接
/************************ 毫秒延时函数 ****************************/
void Delayms(){
uchar i, j;
i = 12;
do{
//1ms @12MHz
j = 169;
while (--j);
} while ( --i);
}
/*************************** 延时函数 *****************************/
void Delay(uint t){
while(--t) Delayms();
}
/*************************** 发送单字节函数 ******************************/
void sendbyte(uchar bbyte){
uchar i;
for(i=0;i<8;i++){
SID=bbyte&0x80;
SCLK=1; _nop_(); _nop_();
SCLK=0;
bbyte<<=1;
//左移
//取出最高位
}
}
//写指令
/*************************** 写指令或数据函数 ******************************/
void write(bit start, uchar ddata){
uchar start_data,Hdata,Ldata;
if(start==0)
start_data=0xf8;
else
start_data=0xfa;
Hdata=ddata&0xf0;
Ldata=(ddata<<4)&0xf0;
sendbyte(start_data);
Delay(2);
sendbyte(Hdata);
Delay(2);
sendbyte(Ldata);
Delay(2);
//延时
//发送高四位
//延时
//发送起始信号
//发送低四位
//取低四位
//写数据
//取高四位
//延时
}
//串口驱动模式
//延时等待 LCD 进入工作状态
/******************************* 初始化 LCD 函数 ******************************/
void lcdinit(){
Delay(10);
PSB=0; ;
RESET=0;
Delay(5);
RESET=1;
CS=1;
write(0,0x30);
write(0,0x0c);
write(0,0x01);
//基本指令操作
//显示打开,光标关,反白关
//清屏,将 DDRAM 的地址计数器归零
//复位 LCD
//片选 高电平有效
write(0,0x06);
}
/*****************************AD 写数据***************************/
void writedata(uint mvcc,uchar res,uchar resl)
{
ulong dat;
dat=256*res+resl;
dat= ((dat*mvcc)/1000)+volt;
vol[0] = dat/1000;
vol[1]=dat%1000;
}
/***************************** 光标闪烁****************************/
void shan(void)
{
uchar i;
switch(state) {
case 1:
{
write(0,0x90);
if(f==1)
{{
tab1[4]=' ';
tab1[5]=' '; }
for (i=0;i<=11;i++) {
write(1,tab1[i]); }
goto return1; }
//按键按一下,小时开始闪烁
//按键按二下,分钟开始闪烁
if(f==2)
{ {
tab1[7]=' ';
tab1[8]=' '; }
for (i=0;i<=11;i++)
write(1,tab1[i]); }
goto return1;
{
}
if(f==3)
{
{
//按键按三下,秒开始闪烁
tab1[10]=' ';
tab1[11]=' '; }
for (i=0;i<=11;i++) {
write(1,tab1[i]);
}
goto return1;
}
if(f==4)
{{
//按键按四下,调时完毕,停止闪烁,开始走时
//时间设定完毕,打开定时器
for (i=0;i<=11;i++){
write(1,tab1[i]);
TR0=1;
}
} }
break; }
case 3:
{
write(0,0x90);
if(g==1) { {
//第三种情况
tab3[6]=' ';
tab3[7]=' ';
tab3[8]=' ';
tab3[9]=' ';
tab3[10]=' '; }
for(i=0;i<16;i++)
write(1,tab3[i]); }
goto return1;
}
if(g==2)
{
//按停止闪烁
{{
for (i=0;i<16;i++){
write(1,tab3[i]);} } } } }
return1:Delay(1);
}
/***************************** 定时器初始化函数****************************/
void init_clock()
{
TMOD=0x11;
TH0=0xd8;
TL0=0xf0;
TH1=0xd8;
TL1=0xf0;
IE=0X8a;
TR0=1;
TR1=1;
}
/***********************显示时间 ASCII 码转换函数****************************/
void iscii_change()
{
tab1[4]=clock[0]/10+0x30;
//时间第一位
tab1[5]=clock[0]%10+0x30; //时间第二位
tab1[6]=0x2d;
tab1[7]=clock[1]/10+0x30; //时间第三位
//破折号
//破折号
//秒表前三位
tab1[8]=clock[1]%10+0x30; //时间第四位
tab1[9]=0x2d;
tab1[10]=clock[2]/10+0x30; //时间第五位
tab1[11]=clock[2]%10+0x30; //时间第六位
tab2[5]=seconds[0]/100+0x30;
tab2[6]=(seconds[0]%100)/10+0x30;
tab2[7]=seconds[0]%10+0x30;
tab2[8]=0x2e;
//小数点
tab2[9]=seconds[1]+0x30;
writedata(mvcc,res,resl);
tab3[6]=vol[0]+0x30;
tab3[7] = 0x2e;
tab3[8] = vol[1]/100+0x30;
tab3[9] = (vol[1]%100)/10+0x30;
tab3[10]=vol[1]%10+0x30;
tab3[11] = 0x56;
}
/***************************** 显示函数****************************/
void display()
{
uchar i;
write(0,0x90);
switch(state)
{
case 1:
{
for(i=0;i<16;i++) {
write(1,tab1[i]); }
break;
}
case 2:
{
for(i=0;i<16;i++){
write(1,tab2[i]);}
break;
}
case 3:
{
for(i=0;i<16;i++) write(1,tab3[i]);
break;
}}}
/***************************** 调节函数****************************/
void tkey(void)
{
//调整时间时关闭定时器
int i=0;
switch(state)
{
case 1:
{
/*******移位键*********/
if (key1==0)
{ f++;
TR0=0;
}
if (f==5)
f=1;
/**********加一键*********/
if(key2==0)
{
clock[f-1]++;
}
if (f==1)
{ if (clock[f-1]>=24){
clock[f-1]=0;}
}
else if(f==2)
{
if(clock[f-1]>=60)
clock[f-1]=0;
}
else if(f==3)
{
if(clock[f-1]>=60)
clock[f-1]=0;
}
/******减一键***********/
if(key3==0)
{
clock[f-1]--;
}
else if (f==1)
{ if (clock[f-1]==0xff){
clock[f-1]=23;}
}
else if (f==2)
{ if (clock[f-1]==0xff){
clock[f-1]=59;}
}
else if (f==3)
{ if (clock[f-1]==0xff){
clock[f-1]=59;}
}
break;
}
case 2:
{
//情况二
if(key1==0)
TR1=1;
if(key2==0)
TR1=0;
if(key3==0)
{
seconds[0]=0;
seconds[1]=0;
TR1=0;
}
break;
}
case 3:
{
if (key1==0)
//情况三
{
g++ ;
}
if(g==3)
g=1;
/**********加一键*********/
if(key2==0)
{
volt++;
}
if (g==1)
{ if (volt>=10000){
volt=0;}
}
/******减一键***********/
if(key3==0)
{
volt--;
}
else if (g==1)
{ if (volt==0xff){
volt=9999;}
}
break;
}
}
}
/*****************************采样函数****************************/
void caiyang()
{
P1ASF = 0x10 ;
ADC_CONTR= 0x84;
Delay(200);
CLK_DIV |=0x20;
位放 res
//设置 Pl.4 为模拟量输入功能
//打开 A/D 转换电源,设置输入通道
//设置 A/D 转换结果的储存方式,低 8 位放 resl,高 2
ADC_CONTR=0x8c;
//启动 A/D 转换
_nop_();_nop_();_nop_();_nop_();
status = 0;
while(status==0){
//等待 A/D 转换结束
status=ADC_CONTR&0x10;
}
ADC_CONTR = 0x84;
res = ADC_RES;
resl = ADC_RESL;
}
//清 A/D 转换结束标志位
//保存 A/D 转换结果
/*****************************定时器 0 中断函数****************************/
void timer0()interrupt 1 using 2
{
TH0=0xd8;
TL0=0xf0;
if(++utime ==SECOND)
{
//一秒钟时间到,秒加一
//秒钟加到 60 分钟加一
utime=0;
clock[2]++;
}
else if(clock[2]>=60)
{
clock[2]=0;
clock[1]++;
}
else if(clock[1]>=60)
{
clock[1]=0;
clock[0]++ ;