单片机的问题与探讨
单片机C51数字频率计程序
/**************************************************
//头文件部分,文件名:plj.h
/**************************************************
#include<reg52.h>
#include<absacc.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
extern const uchar NoDisp=0;//无显示
extern const uchar NoCur=1;//有显示无光标
extern const uchar CurNoFlash=2;//有光标但不闪烁
extern const uchar CurFlash=3;//有光标且闪烁
extern void LcdPos(uchar,uchar);//确定光标位置
extern void LcdWd(uchar);//写字符
extern void LcdWc(uchar);//送控制字(检测忙信号)
extern void LcdWcn(uchar);//送控制字子程序(不检测忙信号)
extern void mDelay(uchar);//延时,毫秒数由j决定
extern void WaitIdle(void);//正常读写操作之前检测LCD控制器状态
extern void RstLcd(void);//复位LCD控制器
extern void WriteChar(uchar c,uchar xPos,uchar yPos);
//在指定的行与列显示指定的字符,xpos:行,ypos:列,c:待显示字符
extern void WriteString(uchar*s,uchar xPos,uchar yPos);
extern void SetCur(uchar Para);//设置光标
extern void ClrLcd(void);//清屏命令
extern void WaitIdle(void);//正常读写操作之前检测LCD控制器状态
extern void mDelay(uchar j);
/**************************************************
/**************************************************
//液晶1602子程序,文件名:1602.c
/**************************************************
;连线图:
; DB0---DPROT.0 DB4---DPROT.4 RS-------------P3.5
; DB1---DPROT.1 DB5---DPROT.5 RW-------------P3.6
; DB2---DPROT.2 DB6---DPROT.6 E--------------P3.7
; DB3---DPROT.3 DB7---DPROT.7 VLCD接10K可调电阻到GND*
;需要11根单片机口线
;80C51的晶振频率为12MHz
;液晶显示程序
;**************************************************/
#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit RS= P3^5;
sbit RW= P3^6;
sbit EN= P3^7;
#define DPORT P1
void LcdPos(uchar,uchar);//确定光标位置
void LcdWd(uchar);//写字符
void LcdWc(uchar);//送控制字(检测忙信号)
void LcdWcn(uchar);//送控制字子程序(不检测忙信号)
void mDelay(uchar);//延时,毫秒数由j决定
void WaitIdle();//正常读写操作之前检测LCD控制器状态
//在指定的行与列显示指定的字符,xpos:行,ypos:列,c:待显示字符
void WriteChar(uchar c,uchar xPos,uchar yPos)
{
LcdPos(xPos,yPos);
LcdWd(c);
}
void WriteString(uchar*s,uchar xPos,uchar yPos)
{ uchar i;
if(*s==0)//遇到字符串结束
return;
for(i=0;;i++)
{
if(*(s+i)==0)
break;
WriteChar(*(s+i),xPos,yPos);
xPos++;
if(xPos>=15)//如果XPOS中的值未到15(可显示的最多位)
break;
}
}
void SetCur(uchar Para)//设置光标
{ mDelay(2);
switch(Para)
{ case 0:
{ LcdWc(0x08);//关显示
break;
}
case 1:
{ LcdWc(0x0c);//开显示但无光标
break;
}
case 2:
{ LcdWc(0x0e);//开显示有光标但不闪烁
break;
}
case 3:
{ LcdWc(0x0f);//开显示有光标且闪烁
break;
}
default:
break;
}
}
void ClrLcd()//清屏命令
{ LcdWc(0x01);
}
//正常读写操作之前检测LCD控制器状态
void WaitIdle()
{ uchar tmp;
RS=0;
RW=1;
EN=1;
_nop_();
for(;;)
{ tmp=DPORT;
tmp&=0x80;
if( tmp==0)
break;
}
EN=0;
}
void LcdWd(uchar c)//写字符子程序
{ WaitIdle();
RS=1;
RW=0;
DPORT=c;//将待写数据送到数据端口
EN=1;
_nop_();
_nop_();
EN=0;
}
void LcdWc(uchar c)//送控制字子程序(检测忙信号)
{ WaitIdle();
LcdWcn(c);
}
void LcdWcn(uchar c)//送控制字子程序(不检测忙信号)
{ RS=0;
RW=0;
DPORT=c;
EN=1;
_nop_();
EN=0;
}
void LcdPos(uchar xPos,uchar yPos)//设置第(xPos,yPos)个字符的DDRAM地址
{ unsigned char tmp;
xPos&=0x0f;//x位置范围是0~15
yPos&=0x01;//y位置范围是0~1
if(yPos==0)//显示第一行
tmp=xPos;
else
tmp=xPos+0x40;
tmp|=0x80;
LcdWc(tmp);
}
void RstLcd()//复位LCD控制器
{ mDelay(15);//如果使用12M或以下晶振,此数值不必改,如用24M晶振,须用30
LcdWc(0x38);//显示模式设置
LcdWc(0x08);//显示关闭
LcdWc(0x01);//显示清屏
LcdWc(0x06);//显示光标移动位置
LcdWc(0x0c);//显示开及光标设置
}
void mDelay(uchar j)//延时,毫秒数由j决定
{ uint i=0;
for(;j>0;j--)
{ for(i=0;i<124;i++)
{;}
}
}
//主函数:
/*==================================================================================
公司名称:河海大学电气工程学院*
模块名: AT89C52单片机系统,全国电子设计大赛*
创建人:南东亮日期:2007。7。28*
修改人:*
功能描述:利用AT89S51单片机的T0、T1的定时计数器功能,来完成对输入的信号进行
频率计数,计数的频率结果通过8位动态数码管显示出来。要求能够对0-250KHZ
的信号频率进行准确计数,计数误差不超过±hz
程序设计内容:
1)定时/计数器T0和T1的工作方式设置,由图可知,T0是工作在计数状态下,
对输入的频率信号进行计数,当T/C工作在定时器时,计数脉冲来自外部脉冲
输入管脚T0(P3。4)或T1(P3。5),当T0或T1产生负跳变时计数器加1。识别
管脚的负跳变需要两个机器周期,即24个振荡周期。以T0或T1脚输入的
可计数外部脉冲的最高频率为1/24Fosc。但对工作在计数状态下的T0,
最大计数值为fOSC/24,由于fOSC=12MHz因此:T0的最大计数频率为500KHz?
高于此频率将出错。
对于频率的概念就是在一秒只数脉冲的个数,即为频率值
所以T1工作在定时状态下,每定时1秒钟到,就停止T0的计数,
而从T0的计数单元中读取计数的数值,然后进行数据处理。
送到数码管显示出来。
2)T1工作在定时状态下,最大定时时间为65ms,达不到1秒的定时,
所以采用定时50ms,共定时20次,即可完成1秒的定时功能。
*
//;*其他说明:产品为设计阶段*
*/
//;==================================================================================
//;主程序开始
//;==================================================================================
#include"plj.h"
unsigned char code table1[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};//0123456789
//unsigned char code table2[]={0x41,0x42,0x43,0x44,0x45,0x46};//abcdef
uchar*s=" CYMOMETER";
uchar*s1="FREQ: Hz";
uchar T0count;//从T0的计数单元中读取计数的数值
uchar timecount;//
bit flag;//标志位
unsigned long x;
uchar xPos,yPos;
uchar i;
void main(void)
{
RstLcd();//初始化LCD
ClrLcd();//清屏
SetCur(1);//开光标显示、闪烁
WriteString(s,0,0);
WriteString(s1,0,1);
TMOD=0x15;//T0工作为16位计数器(方式1),T1工作方式为16位定时器
TH0=0;//计数为65536
TL0=0;//
TH1=(65536-4000)/256;//定时器采用定时4ms.初值为4000
TL1=(65536-4000)%256;
TR1=1;//TR1=1,控制开关闭合,计数脉冲进入T1计数器,启动定时
TR0=1;//TR0=1,控制开关闭合,计数脉冲进入T1计数器,启动计数
ET0=1;//定时器0开中断
ET1=1;//定时器1开中断
EA=1;//CPU开中断
while(1)
{
if(flag==1)//
{
flag=0;//清标志位
x=T0count*65536+TH0*256+TL0;//取得时间宽度参数
//LCD显示部分代码
//;==================================================================================
LcdPos(15,1);
WriteChar(table1[x%10],11,1);
WriteChar(table1[(x/10)%10],10,1);
WriteChar(table1[(x/100)%10],9,1);
WriteChar(table1[(x/1000)%10],8,1);
WriteChar(table1[(x/10000)%10],7,1);
WriteChar(table1[(x/100000)%10],6,1);
//;==================================================================================
timecount=0;
T0count=0;
TH0=0;
TL0=0;
TR0=1;//TR0=1,控制开关闭合,计数脉冲进入T1计数器,启动计数
}
}
}
//;==================================================================================
void t0() interrupt 1 using 0//T0中断服务
{
T0count++;//对P3。4口的脉冲进行计数
}
//;==================================================================================
void t1(void) interrupt 3 using 0//T1中断服务
{
TH1=(65536-4000)/256;//计数初值重装载
TL1=(65536-4000)%256;
timecount++;
if(timecount==250)
{
TR0=0;
timecount=0;
flag=1;//置标志
}
}<
单片机时钟程序 24小时制怎么设置
C语言的:
#include<reg51.h>
#include<stdio.h>
unsigned char ledbuf[8];
code unsigned char ledmap[]={0xc0, 0xf9, 0xa4, 0xb0, 0x99,
0x92, 0x82, 0xf8, 0x80, 0x90};//8段显示
void delay(unsigned char cnt)
{
unsigned char i;
while(cnt--!=0)
for(i=100;i!=0;i--);
}
#define tick 7554
#define T100us(256-134)
unsigned char hour,minute,second,ankey;
unsigned int c100us;
void sees()
{
ledbuf[0]=ledmap[hour/10];
ledbuf[1]=ledmap[hour%10];
ledbuf[2]=0xbf;
ledbuf[3]=ledmap[minute/10];
ledbuf[4]=ledmap[minute%10];
ledbuf[5]=0xbf;
ledbuf[6]=ledmap[second/10];
ledbuf[7]=ledmap[second%10];
}
void displayled()
{
char i;
unsigned char pos;
pos=0x01;
for(i=7;i>=0;i--)
{
P2=0x255;
P0=ledbuf[i];
P2=~pos;
delay(2);
P2=0x255;
pos<<=1;
}
}
void key()
{
if(P32==0||P33==0||P35==0)
delay(2);
if(P32==0||P33==0||P35==0)
{
if(P32==0)
{
hour++;
if(hour==24)
hour=0;
while(P32==0)
{
sees();
displayled();
}
}
if(P33==0)
{
minute++;
if(minute==60)
minute=0;
while(P33==0)
{
sees();
displayled();
}
}
if(P35==0)
{
second++;
if(second==60)
second=0;
while(P35==0)
{
sees();
displayled();
}
}
}
}
void t0int()interrupt 1
{
c100us--;
if(c100us==0)
{
c100us=tick;
second++;
if(second==60)
{
second=0;
minute++;
if(minute==60)
{
minute=0;
hour++;
if(hour==24)hour=0;
}
}
}
}
void main()
{
TMOD=0x02;
TH0=T100us;
TL0=T100us;
IE=0x82;
hour=0;
minute=0;
second=0;
c100us=tick;
TR0=1;
while(1)
{
sees();
displayled();
key();
}
}
汇编的:
ORG 0000H
AJMP MAIN
ORG 000BH
AJMP TIME
ORG 0300H
MAIN:
MOV P3,#0FFH;
MOV 25H,#00H;
MOV R0,#40H;
MOV 20H,#00H;
MOV 21H,#00H;
MOV 22H,#00H;
MOV 23H,#00H;
MOV P2,#0FFH
MOV IP,#02H;
MOV IE,#82H;
MOV TMOD,#01H;
MOV TL0,#0B0H;
MOV TH0,#3CH;
SETB TR0;
MOV SP,#50H;
NEXT:
LCALL DISP;
LCALL KEY;
JZ NEXT;
LCALL ANKEY;
SJMP NEXT;
NOP
NOP;
NOP;
TIME:
PUSH ACC;
PUSH PSW;
MOV TL0,#0B4H;
MOV TH0,#3CH;
INC 20H;
MOV A,20H;
CJNE A,#20,RETI1;
MOV 20H,#00H;
MOV A,21H;
INC A;
MOV 21H,A;
CJNE A,#3CH,RETI1;
MOV 21H,#00H;
MOV A,22H;
ADD A,#01H;
MOV 22H,A;
CJNE A,#3CH,RETI1;
MOV 22H,#00H;
MOV A,23H;
ADD A,#01H;
MOV 23H,A;
CJNE A,#18H,RETI1;
MOV 23H,#00H;
RETI1:
POP PSW;
POP ACC;
RETI;
NOP
NOP
DISP:
MOV A,21H;
MOV B,#10;
DIV AB;
MOV 41H,A;
MOV 40H,B;
MOV A,22H;
MOV B,#10;
DIV AB;
MOV 43H,A;
MOV 42H,B;
MOV A,23H;
MOV B,#10;
DIV AB;
MOV 45H,A;
MOV 44H,B;
MOV R0,#40H
LCALL DISP2; 1
CLR P2.0;
LCALL DELAY;
SETB P2.0;
INC R0;
LCALL DISP2;
CLR P2.1;
LCALL DELAY;
SETB P2.1;
MOV P0,#0bfh;
CLR P2.2;
LCALL DELAY;
SETB P2.2;
INC R0;
LCALL DISP2;
CLR P2.3;
LCALL DELAY;
SETB P2.3;
INC R0;
LCALL DISP2;
CLR P2.4;
LCALL DELAY;
SETB P2.4;
MOV P0,#0BFH;
CLR P2.5;
LCALL DELAY;
SETB P2.5;
INC R0;
LCALL DISP2;
CLR P2.6;
LCALL DELAY;
SETB P2.6;
INC R0;
LCALL DISP2;
CLR P2.7;
LCALL DELAY;
SETB P2.7;
MOV R0,#40H;
DISP2:
MOV DPTR,#TABLE;
MOV A,@R0;
MOVC A,@A+DPTR;
MOV P0,A;
RET
DELAY:
MOV R6,#255;
D2:DJNZ R6,D2;
RET;
TABLE:DB 0c0h,0f9h,0a4h,0b0h,99h,92h,82h,0f8h,80h,90h
; 0 1 2 3 4 5 6 7 8 9
;按键判断程序
KEY:
MOV A,P3;
CPL A;
ANL A,#3CH;
JZ RETX;无键按下则返回
LCALL DISP;
LCALL DELAY;
MOV A,P3;
CPL A;
ANL A,#3CH;
JZ RETX;无键按下则返回
MOV R6,A;将键值存入R6。
LOOP2: LCALL DISP;
MOV A,P3;
CPL A;
ANL A,#3CH;
JNZ LOOP2;等待键释放
MOV A,R6;
RETX:
MOV P3,#0FFH;
RET;
NOP
NOP
;按键处理子程序
ANKEY: CLR EA;关中断
LX: MOV A,R6;
JB ACC.2,L1;是功能键转L1
JB ACC.3,L2;是确认键转L2
JB ACC.4,L3;是减1键转L3
JNB ACC.5,L12;不是增1键,转L12
JB 2BH.4,L6;判断使哪一位(时、分、秒)的值加1
JB 2DH.4,L8;
JB 2FH.4,L9;
L12: LCALL DISP;
LCALL DISP;
LCALL KEY;判断有无键按下。
JZ L12;
LJMP LX;
L2: MOV 25H,#00H;确认键处理程序
CLR 2BH.4;
CLR 2DH.4;
CLR 2FH.4;
SETB EA;
RET;
L3: JB 2BH.4,L61;减一键处理程序
JB 2DH.4,L81;
JB 2FH.4,L91;
AJMP L12;
L1: MOV A,25H;功能键处理程序
JZ LB1;
JB ACC.0,LB2;
JB ACC.1,LB3;
JNB ACC.2,L12;
LB1: MOV 25H,#01H;25H单元是标志位,(25H)=01H调节时单元的值
SETB 2BH.4;
CLR 2DH.4;
CLR 2FH.4;
AJMP L12;
LB3: MOV 25H,#04H;25H单元是标志位,(25H)=04H调节秒单元的值
SETB 2FH.4;
CLR 2DH.4;
CLR 2BH.4;
AJMP L12;
LB2: MOV 25H,#02H;25H单元是标志位,(25H)=02H调节分单元的值
SETB 2DH.4;
CLR 2BH.4;
CLR 2FH.4;
AJMP L12;
L61: AJMP L611;
L81: AJMP L811;
L91: AJMP L911;
L112:AJMP L12;
L6: MOV A,23H;时加一
INC A;
MOV 23H,A;
CJNE A,#24H,L12;
MOV 23H,#00H;
AJMP L12;
L8: MOV A,22H;分加一
INC A;
MOV 22H,A;
CJNE A,#60H,L12;
MOV 22H,#00H;
AJMP L12;
L9: MOV A,21H;秒加一
INC A;
MOV 21H,A;
CJNE A,#60H,L12;
MOV 21H,#00H;
AJMP L12;
L611: MOV A,23H;时减一
DEC A;
MOV 23H,A;
CJNE A,#00H,L112;
MOV 23H,#23H;
AJMP L12;
L811: MOV A,22H;分减一
DEC A;
MOV 22H,A;
CJNE A,#00H,L112;
MOV 22H,#59H
AJMP L12;
L911: MOV A,21H;秒减一
DEC A;
MOV 21H,A;
CJNE A,#00H,L112;
MOV 21H,#59H;
AJMP L12;
NOP
NOP
END
单片机数字时钟设计
#include<reg51.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit LCD_RS=P2^0;
sbit LCD_RW=P2^1;
sbit LCD_EN=P2^2;
sbit SPK=P3^0;
sbit key1=P1^0;
sbit key2=P1^1;
sbit key3=P1^2;
sbit key4=P1^3;
uchar Display_Buffer[16]="";
uchar Count,hour=12,min=12,sec=12;
bit flag,H_or_M;
uchar display[]="This is colck";
void _delay_ms(uint x)
{
uchar i;
while(x--)
{
for(i=0;i<120;i++);
}
}
/**********************************************************************
*函数名称:LCD_Write_Command
*输入:uchar cmd
*输出:无
*功能:向LCD1602写指令
**********************************************************************/
void LCD_Write_Command(uchar cmd)
{
LCD_RS=0;//根据规定,RS和R/W同时为低电平时,可以写入指令
LCD_RW=0;
LCD_EN=0;//EN置低电平
P0=cmd;//将数据送入P2口,即写入指令或地址
LCD_EN=1;//EN置高电平
_delay_ms(1);//稍延时,给硬件反应时间
LCD_EN=0;//当EN由高电平跳变成低电平时,液晶模块开始执行命令
}
/**********************************************************************
*函数名称:LCD_Write_Data
*输入:uchar dat
*输出:无
*功能:向LCD1602写数据
**********************************************************************/
void LCD_Write_Data(uchar dat)
{
LCD_RS=1;//RS为高电平,RW为低电平时,可以写入数据
LCD_RW=0;
LCD_EN=0;//EN置低电平
P0=dat;//将数据送入P0口,即将数据写入液晶模块
LCD_EN=1;//EN置高电平
_delay_ms(1);//稍延时,给硬件反应时间
LCD_EN=0;//当EN由高电平跳变成低电平时,液晶模块开始执行命令
}
/**********************************************************************
*函数名称:Init_LCD
*输入:无
*输出:无
*功能:初始化LCD1602
**********************************************************************/
void Init_LCD(void)
{
LCD_Write_Command(0x38);//显示模式设置:16×2显示,5×7点阵,8位数据接口
_delay_ms(1);
LCD_Write_Command(0x06);//显示模式设置:光标右移,字符不移
_delay_ms(1);
LCD_Write_Command(0x0c);//显示模式设置:显示开,无光标,光标不闪烁
_delay_ms(1);
LCD_Write_Command(0x01);//清屏幕指令,将以前的显示内容清除
_delay_ms(1);
}
/**********************************************************************
*函数名称:LCD_POS
*输入:uchar pos
*输出:无
*功能:字符显示位置
**********************************************************************/
void LCD_POS(uchar pos)
{
LCD_Write_Command(0x80|pos);//显示位置的确定方法规定为"80H+地址码x"
}
/**********************************************************************
*函数名称:Show_String
*输入:uchar*str
*输出:无
*功能:LCD1602显示字符串处理函数
**********************************************************************/
void Show_String(uchar*str)
{
while(*str!='\0')//只要没有写到结束标志,就继续写
LCD_Write_Data(*str++);//将字符常量写入LCD,并指向下一个字符
}
void song(void)
{
uchar i,j,k;
for(i=0;i<200;i++)
{
SPK=~SPK;
for(k=0;k<50;k++);
for(j=0;j<50;j++);
}
}
/////lcd1602液晶显示//////
void Display_Time(uchar Hour,uchar Min,uchar Sec)
{
Display_Buffer[0]=Hour/10+'0';//小时十位
Display_Buffer[1]=Hour%10+'0';//小时个位
Display_Buffer[2]=':';//显示:号
Display_Buffer[3]=Min/10+'0';//显示分钟十位
Display_Buffer[4]=Min%10+'0';//显示分钟个位
Display_Buffer[5]=':';//显示:号
Display_Buffer[6]=Sec/10+'0';//显示秒十位
Display_Buffer[7]=Sec%10+'0';//显示秒个位
LCD_POS(0x40);//显示在液晶第1行第0列
Show_String(Display_Buffer);
}
/////按键处理//////
void Set_time(void)
{
flag=0;
if(key1==0||key2==0||key3==0)//若key1,key2,key3其中有键按下,则为真
{
TR0=0;//定时器0停止
flag=1;//按键标志位为真
}
while(flag)//判断那一个按键按下
{
if(key1==0)//判断key1是否按下
{
while(!key1);//等待释放
H_or_M=!H_or_M;//选择是修改时还是分钟
}
else if(key2==0)//判断key2是否被按下
{
while(!key2);//等待释放
if(H_or_M)//若H_OR_M为真,则修改小时
{
if(++hour==24)//若小时=24,则小时=0
hour=0;//小时加1
}
else//否则修改分钟
{
if(++min==60)//若分钟等于60,则分钟等于0
min=0;//分钟加1
}
}
else if(key3==0)//判断key3是否被按下
{
while(!key3);//等待释放
if(H_or_M)//若H_OR_M为真,则修改小时
{
if(--hour==0xff)//小时减1,若小时等于-1,则小时等于23
hour=23;
}
else//否则修改分钟
{
if(--min==0xff)//分钟减1,若分钟等于-1,则分钟等于59
min=59;
}
}
else if(key4==0)//判断key4是否被按下
{
while(!key4);//等待释放
flag=0;//按键标志清零
TR0=1;//定时器0启动
}
Display_Time(hour,min,sec);//传H,M,S值显示到液晶
}
}
void timer0_init(void)//定时器0初始化
{
TMOD=0x01;//定时器0,方式1
ET0=1;//
EA=1;//总中断允许
TR0=1;//启动定时器0
TH0=(65535-50000)/256;//装高8位初值
TL0=(65535-50000)%256;//装低8位初值
}
void main(void)//主函数
{
//P0=0xff;
P1=0xff;//端口初始化
P3=0xff;
Init_LCD();//液晶初始化
timer0_init();//定时器0初始化
LCD_POS(0);//显示在液晶第1行第0列
Show_String(display);
while(1)//无限循环
{
Display_Time(hour,min,sec);//液晶显示时间
//_delay_ms(500);//延时
Set_time();//时间调整
}
}
void timer0() interrupt 1//定时器0中断
{
TH0=(65535-50000)/256;//重装定时器0高8位
TL0=(65535-50000)%256;//重装定时器0低8位
Count++;//计数加1
if(Count==20)//如果COUNT等于20
{
Count=0;//计数清零
sec++;//秒加1
if(sec==60)//判断秒是否等于60
{
sec=0;//秒清零
min++;//分钟加1
if(min==60)//判断分钟是否等于60
{
min=0;//若等于60,则清零分钟
hour++;//小时加1
if(hour==24)//判断小时是否等于24
{
hour=0;//若小时等于24,则清零小时,分钟,秒
min=0;
sec=0;
}
song();
}
}
}
}