• 利用51系列单片机定时器实现脉冲宽度

    STC12C系列增强型单片机片上扩展了基本51单片机的功能,如提供了PCA/PWM接口,定时器能工作在1T模式下(基本51单片机的时钟是Fosc的12分频,1T模式下1分频)。

    PCA可以用于脉宽测量,但是,protues暂不支持该系列单片机的仿真功能,反复烧写也挺麻烦,所以还是先用基本51单片机实现该功能,在后面的博文里在实现PCA测量脉宽。

    实现思路如下:

    TMOD最高位GATEn置位后,Tn启动计数受INTn(Pin3.3)和TRn的共同影响:TRn为1,当INTn引脚输入为高电平时,Tn才允许计数。利用这个功能可测量INTn上正脉冲的宽度。

    先上图(原谅我的制图能力):

    1):1处 在上升沿之前,初始化TMOD,TRn=1;

    2):2处 INTn引脚为高电平,开始计数测量脉宽;

    3):3处 INTn引脚为低电平,测量结束停止计数TRn=0


    再上仿真图:

    1).信号发生器电平选5v方波。注信号发生器的反相端接地,否则正向端只输出2.5v的方波(剩下的2.5v输出反相方波,可以接到示波器上试试),INTn上永远收不到高电平,达不到预期效果。

    2).T0定时器做计数器使用,收到一个负脉冲产生溢出,启动T1;

    3).T0,T1全工作在方式2自动装载计数值模式。

    然后,上代码:

    工作频率12Mhz

    #include <REG52.H> 
    #include <INTRINS.H>
    
    sbit P1_0 = P3^3;
    
    #define MakeByte(target, Hi,Lo) \
    do{ \
    	target |= (((Hi)<<4)|(Lo)); \	
    }while(0); \
    
    #define SetTH(n,val) \
    do{ \
    	TH##n = val; \
    }while(0); \
    
    #define SetTL(n,val)  \
    do{ \
    	TL##n = val; \
    }while(0); \
    
    #define EnableET(n) \
    do{ \
    	ET##n = 0x01; \
    	IE |= 0x80; \
    }while(0); \
    
    unsigned int click;  
    unsigned int oneMs;
    unsigned char getPlusWidth;
    int main()
    {
    	unsigned int totalus=0,maxPlusWidth=0;
    	P3 = 0xFF;
    
    	getPlusWidth = 0;
    	MakeByte(TMOD,0x0A,0x06);
    	SetTH(0,0xff);
    	SetTL(0,0xff);
    	SetTH(1,0x38);
    	SetTL(1,0x38);
    	EnableET(0);
    	EnableET(1); 
    	TR0 = 0x01;
    	while(1)
    	{
    		while(!getPlusWidth);
    		//等待INT1至低
    		while(INT1==0x01);
    		//等待INT1至高电平
    		while(INT1==0x00);
    		//等待INT1至低电平,脉宽结束
    		while(INT1==0x01);
    		TR1 = 0x00;
    
    		totalus = 1000*(oneMs+(click*0.2))+(TL1-TH1);	
    		oneMs = 0;
    	}
    	return 0;
    }
    
    //T0引脚上接受到负跳变
    void IsrT0() interrupt 1
    {
    	TR1 = 0x00;
    	getPlusWidth = 1;		
    	TR1 = 0x01;
    }
    
    void IsrT1() interrupt 3
    {
    	//每次进入中断0.2ms
    	click++;
    	if(click == 5)
    	{
    		oneMs++;
    		click=0;
    	}
    }

    最后 上仿真结果:

    500Hz的方波,脉宽981us

    1kHz的方波,脉宽587us


    2kHz方波,脉宽234us


    展开全文
  • 定时器单片机最重要的一个功能,一开始学的时候遇到了不少的问题,通过不断地学习解决了不少问题,其实学会之后也没有什么。在这里我整理了一下定时器的使用,就用51单片机来举例。像别的STC15等系列的单片机其实...

    如果有朋友对定时器还不太了解,可以看一下这篇文章
    链接: 《单片机定时器总结》—用最简洁的方式学会51单片机定时器。.

    任务要求

    • 😀采用T0定时器方式2在P1.0口输出周期为0.5ms的方波。

    Proteus仿真图

    在这里插入图片描述
    方波的实现
    在这里插入图片描述

    程序代码

    #include"reg51.h"
    void Timer0Init(void);
    unsigned int tt;
    sbit Fangbo=P1^0;
    void main()
    {
    	Timer0Init();
    	while(1);
    	
    }
    
    void Timer0Init(void)		//设置1us定时一次
    {
    
    	TMOD=0x02;		//设置定时器模式
    	TL0 = 0xFF;		//设置定时初值
    	TH0 = 0xFF;		//设置定时重载值
    	TF0 = 0;		//清除TF0标志
    	TR0 = 1;		//定时器0开始计时
    	EA=1;
    	ET0=1;
    }
    void Time0() interrupt 1
    {
    	tt++;
    	if(tt==250)//每当经过250us,P1^0电平翻转一次。
    	{
    		tt=0;
    		Fangbo=~Fangbo;
    	}
    }
    		
    
    展开全文
  • 利用51单片机定时器设计一个时钟 一、功能要求 1602液晶显示时间,且每秒更新,自动计时。 用3个按键实现调节时、分、秒更能,可以定义为功能键、增加键、减小键。 当按键被按下时,蜂鸣器响一声提示。 利用AT24C...

    利用51单片机的定时器设计一个时钟
    一、功能要求

    1. 1602液晶显示时间,且每秒更新,自动计时。
    2. 用3个按键实现调节时、分、秒更能,可以定义为功能键、增加键、减小键。
    3. 当按键被按下时,蜂鸣器响一声提示。
    4. 利用AT24C02实现掉电记忆功能。
      二、 原理图设计
      在这里插入图片描述
      在这里插入图片描述
      三、源程序
    5. 在Keil中的同一个文件夹下新建一个AT24C02.h文件和Clock.c文件
    //*********************** AT24C02.h源程序***************************//
     bit write=0;		//写AT24C02的标志
    sbit SDA=P2^0;		//定义数据串行口,用于单片机通信
    sbit SCL=P2^1;	//定义时钟串行口,用于单片机通信
    
    void delayus()		//定义us级延时函数
    {;;}
    
    void start()	//起始信号
    {
    	SDA=1;
    	delayus();
    	SCL=1;
    	delayus();
    	SDA=0;
    	delayus();
    }
    
    void stop()//终止信号
    {
    	SDA=0;
    	delayus();
    	SCL=1;
    	delayus();
    	SDA=1;
    	delayus();
    }
    
    void ack()//应答信号
    {
    	uchar i;
    	SCL=1;
    	delayus();
    	while((SDA=1)&&i<250)i++;																	
    	SCL=0;
    	delayus();
    }
    
    
    void init_AT24C02()	//初始化
    {
    	SDA=1;
    	delayus();
    	SCL=1;
    	delayus();	
    }
    
    void write_byte(uchar dat)	//定义写1个字节程序
    {
    	uchar i,temp;
    	temp=dat;				//将数据赋值给temp。例如:dat为0x01,则temp=0x01=0000 0001。方便后续移位操作用。
    	for(i=0;i<8;i++)		//1个字节包括8位二进制数
    	{
    		temp=temp<<1;		//将temp左移1位,最低位补0
    		SCL=0;					//将SCL置0允许SDA数据变化
    		delayus();
    		SDA=CY;				//将最高位移出的CY位赋给SDA
    		delayus();
    		SCL=1;					//置1将数据写入
    		delayus();
    	}
    	SCL=0;					//置0允许数据变化,用于SDA置1释放总线。
    	delayus();
    	SDA=1;					//释放总线
    	delayus();			
    }
    
    uchar read_byte()	//读1个带返回值的字节
    {
    	uchar i,k;
    	SCL=0;				//置0允许数据变化
    	delayus();
    	SDA=1;				//假设SDA为1,也可以SDA=0。当SDA=0时,下面for语句会有所差别。
    	delayus();
    	for(i=0;i<8;i++)
    	{
    		SCL=1;					//上升沿时,IIC设备将数据放在sda线上,并在高电平期间数据已经稳定,可以接收啦
    		delayus();
    		k=(k<<1)|SDA;		//将k左移一位跟SDA或运算,再赋给k	
    		SCL=0;					//拉低SCL,使发送端可以把数据放在SDA上  
    		delayus();		
    	}
    	return k;
    }
    
    void write_add(uchar address, uchar dat)			//指定地址写一个字节
    {
    	start();
    	write_byte(0xa0);
    	ack();
    	write_byte(address);
    	ack();
    	write_byte(dat);
    	ack();
    	stop();
    }
    
    char read_add(uchar address)				//随机读取一个字节
    {
    	uchar dat;
    	start();
    	write_byte(0xa0);
    	ack();
    	write_byte(address);
    	ack();
    	start();
    	write_byte(0xa1);
    	ack();
    	dat=read_byte();
    	stop();
    	return dat;
    }
    //****************************Main主程序**************************************//
    #include <reg52.h>
    #define uchar unsigned char
    #define uint unsigned int
    #include"AT24C02.h"		//包含AT24C02头文件
    sbit s1=P3^0;
    sbit s2=P3^1;
    sbit s3=P3^2;
    sbit rd=P3^7;
    sbit lcden=P3^4;
    sbit rs=P3^5;
    sbit dula=P2^6;
    sbit wela=P2^7;
    sbit beep=P2^3;
    char shi,fen,miao;
    uchar s1num,count;
    uchar code table0[]="  2020-6-4 MON";			//字符2020前面3个空格
    uchar code table1[]="00:00:00";
    void delay_us()					//us级延时程序
    {;;}
    void delay_ms(uchar z)	//ms级延时程序
    {
    	uint i,j;
    	for(i=z;i>0;i--)
    		for(j=110;j>0;j--);
    }
    
    void buzzer()				//定义蜂鸣器程序
    {
    	beep=0;
    	delay_ms(100);
    	beep=1;
    
    }
    
    void write_com(uchar com)	//液晶写指令
    {
    	rs=0;
    	lcden=0;
    	P0=com;
    	delay_ms(5);
    	lcden=1;
    	delay_ms(5);
    	lcden=0;
    }
    
    void write_dat(uchar dat)	//液晶写数据
    {
    	rs=1;
    	lcden=0;
    	P0=dat;
    	delay_ms(5);
    	lcden=1;
    	delay_ms(5);
    	lcden=0;
    }
    
    void write_sfm(uchar add,uchar dat)		//写时分秒程序
    {
    	uchar shi,ge;
    	shi=dat/10;				//将时分秒分别分解成一个两位数,以便后续的位操作
    	ge=dat%10;
    	write_com(0x80+0x40+add);			//在液晶第2行写指令
    	write_dat(0x30+shi);						//0x30地址的数据为0
    	write_dat(0x30+ge); 
    }
    void init_1602()							//初始化液晶
    {
    	uchar num;
    	dula=0;
    	wela=0;
    	num=0;
    	s1num=0;
    	count=0;
    	rd=0;
    	lcden=0;
    	shi=0;
    	fen=0;
    	miao=0;
    	init_AT24C02_02();			
    	write_com(0x38);
    	write_com(0x0c);
    	write_com(0x06);
    	write_com(0x08);
    	write_com(0x01);
    	write_com(0x80);
    	for(num=0;num<14;num++)		//显示日期,加空格总共14个字节
    	{
    		write_dat(table0[num]);
    		delay_ms(5);
    	}
    	write_com(0x80+0x40+4);
    	for(num=0;num<8;num++)		//显示时分秒
    	{
    		write_dat(table1[num]);	
    		delay_ms(5);	
    	}
    	miao=read_add(1);	//首次上电从AT24C02中读取出存储器的数据,地址可以随机定义,只要整个程序用的地址相同即可。
    	fen=read_add(2);		
    	shi=read_add(3);
    	write_sfm(10,miao);	//在第十位写秒数据
    	write_sfm(7,fen);
    	write_sfm(4,shi);
    	TMOD=0x01;		//设置T0定时器为工作方式1
    	TH0=(65536-50000)/256;	//装初值
    	TL0=(65536-50000)%256;
    	EA=1;			//开总中断
    	ET0=1;		//开定时器0中断
    	TR0=1;		//启动定时器0
    }
    
    void keyscan()	//按键扫描程序
    {
    	if(s1==0)		//先定义功能键被按下,不然加减键为无效。
    	{
    		delay_ms(5);
    		if(s1==0)		//再次确认被按下,即去抖动
    		{
    			s1num++;	//记录功能键被按下次数
    			while(!s1);	//按键释放
    			buzzer();		//蜂鸣器短鸣提示
    			if(s1num==1)		//功能键按下1次
    			{
    				TR0=0;		//定时器停止计时
    				write_com(0x80+0x40+11);		//光标在11位处,调节11的大小可以进行光标位置设置
    				write_com(0x0f);						//光标闪烁
    			}	
    			if(s1num==2)
    			{
    				write_com(0x80+0x40+8);
    				write_com(0x0f);
    			}
    			if(s1num==3)
    			{
    				write_com(0x80+0x40+5);
    				write_com(0x0f);
    			}
    			if(s1num==4)		//功能键按下4次
    			{
    				s1num=0;		//按键次数清0
    				write_com(0x0c);		//取消光标闪烁
    				TR0=1;			//定时器继续计数
    			}
    		}
    	}
    	if(s1num!=0)		//只有功能键被按下,加减键才有效
    	{
    		if(s2==0)		//增加键被按下
    		{
    			delay_ms(5);
    			if(s2==0)		//再次确认增加键按下,去抖动
    			{
    				while(!s2);		//按键释放,只有按键释放了才可以认为一个完整的按键完成
    				buzzer();
    				if(s1num==1)		//功能键按下一次,此时选择调整秒
    				{
    					miao++;
    					if(miao==60)		//当秒数大于60就清0
    						miao=0;
    					write_sfm(10,miao);	//在第10位写秒,此时写的时一个两位数,调用的write_sfm()函数
    					write_com(0x80+0x40+11);	//光标定位在11位,由于前面已经定义光标闪烁,所以这里不用写write_com(0x0f)
    					write_add(1,miao);		//将变化的值写入AT24C02记忆起来,掉电恢复时可以显示此值
    				}
    				if(s1num==2)
    				{
    					fen++;
    					if(fen==60)
    						fen=0;
    					write_sfm(7,fen);
    					write_com(0x80+0x40+8);
    					write_add(2,fen);
    				}
    				if(s1num==3)
    				{
    					shi++;
    					if(shi==24)
    						shi=0;
    					write_sfm(4,shi);
    					write_com(0x80+0x40+5);
    					write_add(3,shi);
    				}
    			}
    		}
    		if(s3==0);		//减少键被按下
    		{
    			delay_ms(5);
    			if(s3==0)	//再次确认,去抖
    			{
    				while(!s3);
    				buzzer();
    				if(s1num==1)
    				{
    					miao--;	
    					if(miao==-1)//当秒数被减到-1时,秒数清0。
    						miao=59;
    					write_sfm(10,miao);
    					write_com(0x80+0x40+11);
    					write_add(1,miao);
    				}
    				if(s1num==2)
    				{
    					fen--;
    					if(fen==-1)
    						fen=59;
    					write_sfm(7,fen);
    					write_com(0x80+0x40+8);
    					write_add(2,fen);
    				}
    				if(s1num==3)
    				{
    					shi--;
    					if(shi==-1)
    						shi=23;
    					write_sfm(4,shi);
    					write_com(0x80+0x40+5);
    					write_add(3,shi);
    				}
    			}
    		}			
    	}		
    }
    
    void main()		//主程序
    {
    	init_1602();		//初始化1602液晶
    	while(1)	//进入while语句不停的进行按键扫描,来确认是否有按键按下
    	{
    		keyscan();
    	}
    }
    
    void timer0() interrupt 1	//定时器0工作方式1
    {
    	TH0=(65536-50000)/256;	//装初值,因为工作方式1无法自动重装初值,所以这里再次装初值。
    	TL0=(65536-50000)%256;
    	count++;								//将1s拆分成20个50ms,这里对50ms进行计数来累加到1s
    	if(count==20)						//当计数20次时,即为1s
    	{
    		count=0;							//清0重新计数
    		miao++;
    		if(miao==60)					//这里是没有按键被按下时,时钟自动的计数
    		{
    			miao=0;
    			fen++;
    			if(fen==60)
    			{
    				fen=0;
    				shi++;
    				if(shi==24);
    				{
    					shi=0;
    				}
    				write_sfm(4,shi);			//在第4位写小时的数据
    				write_add(3,shi);			//写入AT24C02进行掉电记忆,这里的3为地址,整个程序都要相同。
    			}
    			write_sfm(7,fen);
    			write_add(2,fen);
    		}
    		write_sfm(10,miao);
    		write_add(1,miao);
    	}
    }
    

    1602字符库
    在这里插入图片描述

    展开全文
  • 单片机 定时器/计数器 一、简述  MCS—51系列单片机内部有两个16位定时器/计数器,即定时器T0和定时器T1。它们都具有定时和计数功能,可用于定时或延时控制,对外部事件进行检测、计数等。  定时器/计数器是一...

    单片机 定时器/计数器

    一、简述

        MCS—51系列单片机内部有两个16位定时器/计数器,即定时器T0和定时器T1。它们都具有定时和计数功能,可用于定时或延时控制,对外部事件进行检测、计数等。

        定时器/计数器是一个加“1”计数器,来一脉冲即做加1计数,直至寄存器各位全为1,再来一脉冲,计数器回0且使TF0(定时器T0)TF1(定时器T1)置1表示定时时间到,计数值乘以单片机的机器周期就是定时时间。

         计数器:工作在方式1,可以从0数到65536(2的16次方),超过65535产生中断;如果想要数10000个数,可以设置计数器的初值为55536,这样从初值55535数到65535就是10000个数。

         计数器又叫定时器:晶振产生脉冲信号,一个脉冲信号过来,计数器就数1,频率高,产生脉冲信号就快,计数器数数就快,计数器每数了一个数说明过去了xx秒,那么让计数器数10000个数,对应过去了10000乘以xx秒。这样我们想要在10秒之后做某件事情,设置好计数器初值(设定计数器要数多少个数)、设置好频率(确定产生一个脉冲的时间),计数器数到65535之后,产生溢出信号、引起中断,然后执行中断服务(可以是我们自己编写的中断函数)。

          如:频率是12MHZ,也就是1秒可以产生12000000个脉冲,也就是1秒可以数12000000个数。如果设置计数器的初值为65524(65535-12),也就是数12个数。数12000000个数用时1秒,那么数12个数用时12/12000000=0.000000.1秒=1微秒。(1秒=1000000微秒),想要定时1ms,那么可以让计数器数12000个数,设置计数器的初值为65535-12000=53535。

    二、TMOD控制寄存器

        GATE=1时,“与门”的输出信号K由INTx输入电平和TRx位的状态一起决定(即此时K=TRx·INTx),当且仅当TRx=1,INTx=1(高电平)时,计数启动;否则,计数停止。
        当INT0引脚为高电平时且TR0置位,TR0=1;启动定时器T0;
        当INT1引脚为高电平时且TR1置位,TR1=1;启动定时器T1。
        GATE=0时,“或门”输出恒为1,“与门”的输出信号K由TRx决定(即此时K=TRx),定时器不受INTx输入电平的影响,由TRx直接控制定时器的启动和停止。

    三、TCON控制寄存器

     

    设定好了定时器/计数器的工作方式后,它还不能进入工作状态,必须通过设置控制寄存器TCON中的某些位来启动它工。要使定时器/计数器停止运行,也必须通过设置TCON中的某些位来实现。当定时器/计数器计满溢出,或有外部中断请求时,TCON能标明溢出和中断情况。

      

    设定好了定时器计数器/的工作方式后,它还不能进入工作状态,必须通过设置控制寄存器TCON中的某些位来启动它工。要使定时器/计数器停止运行,也必须通过设置TCON中的某些位来实现。当定时器/计数器计满溢出,或有外部中断请求时,TCON能标明溢出和中断情况。控制寄存器TCON每位的含义: 

     

    TF1:定时器T1溢出标志位。当定时器T1溢出时,由硬件自动使TF1置1,并向CPU申请中断。CPU响应中断后,自动对TF1清零。TF1也可以用软件清零。 
    TR1:定时器T 1运行控制位。可由软件置1(或清零)来启动(或关闭)定时器T1,使定时器T1开始计数。用指令SETB TR1(或CLR TR1)使TR1置1(或清零)。 
    TF0:定时器T0溢出标志位。其功能与TF1相同。 
    TR0:定时器T0运行控制位。其功能与TR1相同。 
    IE1:外部中断1请求标志位。 
    IT1:外部中断1触发方式控制位。 
    IE0:外部中断0请求标志位。 
    IT0:外部中断0触发方式控制位。 
    IE1、IT1、IE0、IT0这4位将在第3节讲述。 
    控制寄存器TCON的位地址是88H,可以对它进行位寻址。

    四、初值计

     

    机器周期:

        时钟周期(振荡周期) = 1秒/晶振频率         (T = 1/f)

        机器周期 = 12*振荡周期

        机器周期 = 12秒/晶振频率 

        如果系统晶振频率为12M,那么机器周期=1us

     

    五、例子

     

    定时函数

    void Delay1ms(unsigned int count)
    {
    	unsigned int i;
    	TMOD=0x01;			   //选用定时器0且工作在方式1
    	TH0=0x3c;			  //设置初值0x3cb0
    	TL0=0xb0;
    	TR0=1;      //开启定时器
    	for(i=0;i<count;i++) //循环count次,每次定时50ms,总共count*50ms
    	{	
    		while(TF0!=1);// 每次定时50ms (溢出时才会跳出循环)
    		TH0=0x3c;	 //重置初值0x3cb0
    		TL0=0xb0;
    		TF0=0;		   //软置溢出位
    	} 
    	TR0=0;      //关闭定时器
    }

    定时1s:Delay1ms(20);

     

     

    展开全文
  • 1.利用实验板和配件,设计一个时钟,时间显示在LCD1602上,并按秒更新,能够在实验板上设计3个按键调整时,分,秒。其功能为:功能选择键,数值增大和数值减小键。利用板上AT24C02设计实现断电保护显示数据的功能。 ...

    1.利用实验板和配件,设计一个时钟,时间显示在LCD1602上,并按秒更新,能够在实验板上设计3个按键调整时,分,秒。其功能为:功能选择键,数值增大和数值减小键。利用板上AT24C02设计实现断电保护显示数据的功能。

    =============Clock.h=============

    #ifndef __CLOCK_H__

    #define __CLOCK_H__

     

     

    //========全局变量区============================================

    unsignedchar T_High_50ms=(65536-45872)/256;

    unsignedint T_Low_50ms=(65536-45872)%256;

    unsignedchar Count,Count_T1,Count_1s;//Count用来记录每50ms的计数,Count_T1用来记

     

    //========全局变量区结束============================================

    #endif

     

    =============I2C.H=============

    #ifndef __I2C_H__

    #define __I2C_H__

    #include<reg51.h>

    sbit sda=P2^0;                        

    sbit scl=P2^1;

    //========函数区============================================

    void nop();

    void initI2C();

    externvoid I2C_start();  //开始信号

    externvoid I2C_stop();   //停止

    externvoid I2C_respons();  //应答

    externvoid I2C_write_byte(unsignedchar date);

    externunsignedchar I2C_read_byte();

    externvoid I2C_write_address(unsignedchar address,unsignedchar date);

    externunsignedchar I2C_read_address(unsignedchar address);

    //========函数区结束============================================

    #endif

     

    =============OrphanKey.h=============

    #ifndef __ORPHANKEY_H__

    #define __ORPHANKEY_H__

     

    sbit FUNCTION_KEY=P3^2;//功能键 --按下暂停,再按开始

    sbit Key_ADD=P3^3;//1

    sbit KEY_MINUS=P3^4;//1

    const bit PRESSED=0;//按下

    bit SUSPEND=0;//0的时候运行,1的时候暂停

     

    #endif

     

    =============I2C.C=============

    #include "head/I2C.h"

    //=========全局变量区============================================

     

    #define uchar unsigned char

    #define uint unsigned int

     

      bit I2C_write=0;           //24C02的标志;

     

     unsignedchar sec,tcnt;

     

    //=========全局变量区结束============================================

    void nop()

    {;;}

     

    /***********************************************************

        I2C的初始化

    ***********************************************************/

    void initI2C(){

        sda=1;

        nop();

        scl=1;

        nop();

     

    }

    void I2C_start()  //开始信号

    {  

        sda=1;

        nop();

        scl=1;

        nop();

        sda=0;

        nop();

    }

    void I2C_stop()   //停止

    {

        sda=0;

        nop();

        scl=1;

        nop();

        sda=1;

        nop();

    }

    void I2C_respons()  //应答

    {

        uchar i;

        scl=1;

        nop();

        while((sda==1)&&(i<250))i++;

        scl=0;

        nop();

    }

     

    void I2C_write_byte(uchar date)

    {

        uchar i,temp;

        temp=date;

        for(i=0;i<8;i++)

        {

           temp=temp<<1;

           scl=0;

            nop();

           sda=CY;

           nop();

           scl=1;

           nop();

        }

        scl=0;

        nop();

        sda=1;

        nop();

    }

    uchar I2C_read_byte()

    {

        uchar i,k;

        scl=0;

        nop();

        sda=1;

        nop();

        for(i=0;i<8;i++)

        {

           scl=1;

           nop();

           k=(k<<1)|sda;

           scl=0;

           nop();

        }

        return k;

    }

    void I2C_write_address(uchar address,uchar date)

    {

        I2C_start();

        I2C_write_byte(0xa0);

        I2C_respons();

        I2C_write_byte(address);

        I2C_respons();

        I2C_write_byte(date);

        I2C_respons();

        I2C_stop();

    }

    uchar I2C_read_address(uchar address)

    {

        uchar date;

        I2C_start();

        I2C_write_byte(0xa0);

        I2C_respons();

        I2C_write_byte(address);

        I2C_respons();

        I2C_start();

        I2C_write_byte(0xa1);

        I2C_respons();

        date=I2C_read_byte();

        I2C_stop();

        return date;

    }

     

    =============lab8_1.c=================

    #include<reg51.h>

    #include "head/Clock.h"

    #include "head/OrphanKey.h"

    #include "head/I2C.H"

    /*

    1.利用实验板和配件,设计一个时钟,时间显示在LCD1602上,并按秒更新,能够在实验板上设计3个按键调整时,分,秒。其功能为:功能选择键,数值增大和数值减小键。利用板上AT24C02设计实现断电保护显示数据的功能。

    */

     

    /*

    步骤:

    1、设计一个中断,用来计时

    2、设计一个字符生成函数,用来生成所需的时间

    3、独立按键监测功能,用来监测按下了什么键

    4、一个外部中断

    5、一个断点保护的功能,其实就是通过I2C写入,读取数值

    */

     

    //=========全局变量区============================================

    #define uchar unsigned char

    #define uint unsigned int

    uchar code table[]="12:23:12";

    uchar code table1[]="I am a boy!";

    sbit lcden=P2^7;  //液晶使能端

    sbit lcdrs=P2^6;  //数据或命令控制(0代表命令,1代表数据)  

    sbit LCDWR=P2^5;  //读写控制(0代表写,1代表读)

    uchar num;

    uchar FIRST_LINE=0x80;

    uchar SECOND_LINE=0xc0;

    uchar Current_Time[9];

    uchar Hour,Minute,Second=0;//时、分、秒

    sbit beer = P1 ^4;      //蜂鸣器

    // sbit led1=P1^3;

     

    //=========全局变量区结束============================================

     

     

    //=========函数区============================================

     

    /***********************************************************

        延时函数

        参数说明:

        z代表要延时z ms

    ***********************************************************/

    void delay(uint z)

    {

        uint x,y;

        for(x=z;x>0;x--)

           for(y=110;y>0;y--);

    }

    /***********************************************************

        写命令或数据

        参数说明:

        isRs=1代表写数据,isRs=0代表写命令

    ***********************************************************/

    void write(uchar mdata, uchar isRs)

    {

        lcdrs=isRs;

        P0=mdata;

        delay(5);

        lcden=1;

        delay(5);

        lcden=0;

    }

    /***********************************************************

        写命令

        参数说明:

        data代表要写的命令

    ***********************************************************/

    void write_command(uchar com)

    {

        write(com,0);

    }

    /***********************************************************

        写数据

        参数说明:

        data代表要写的数据

    ***********************************************************/

    void write_data(uchar mdata)

    {

        write(mdata,1);

    }

     

    /***********************************************************

        初始化时钟

    ***********************************************************/

    void InitTime(){

        // 

        Current_Time[0]=Hour/10+'0';

        Current_Time[1]=Hour%10+'0';

        Current_Time[2]=':';

        Current_Time[3]=Minute/10+'0';

        Current_Time[4]=Minute%10+'0';

        Current_Time[5]=':';

        Current_Time[6]=Second/10+'0';

        Current_Time[7]=Second%10+'0';

        Current_Time[8]='\0';

    }

     

    /***********************************************************

        保存时钟的值

    ***********************************************************/

    void KeepClockValue(){

        I2C_write_address(2,Second); 

        delay(10); 

        I2C_write_address(3,Minute);     

        delay(10);

        I2C_write_address(4,Hour);   

    }

     

    /***********************************************************

        改变时间

    ***********************************************************/

    void changeTime()

    {

        // 

        if(Second>=60){

           Second=0;

           Minute++;

        }else{

           ++Second;

        }

     

        if(Minute==60){

           Hour++;

           Minute=0;

        }

        if(Hour==24){

           Second=0;

           Minute=0;

           Hour=0;

        }

        KeepClockValue();

    }

    /**

        初始化

    **/

    void InitClockInterrupt(){//初始化中断

     

        TMOD=0x11;        // TMOD赋值,以确定T0T1的工作方式。

        TH0=T_High_50ms;// 计算初值,并将其写入TH0TL0TH1TL1

        TL0=T_Low_50ms;

        EA =1;//开启中断总允许

        ET0 =1;  

        IT0 =1;   //开启定时器0,1中断允许

        TR0=1;     // 使TR0TR1置位,启动定时/计数器定时或计数

        Count=Count_T1=Count_1s=0;//计数

    }

    /***********************************************************

        初始化按钮中断

    ***********************************************************/

    void initButtonInterupt(){

        IT0 =0;

        //EA = 1;     //开启中断总允许

        EX0 =1;   //外部中断0允许位

    }

     

     

    void init()

    {

     

        InitTime();

        lcden=0;

        LCDWR=0;

        write_command(0x38);//设置16X2显示,5X7点阵,8位数据接口

        write_command(0x0c);//设置开显示,不显示光标

        write_command(0x06);//写一个字符后地址指针加1

        write_command(0x01);//显示清零,数据指针清零

    }

    void WriteStringToLCD(uchar *dat)

    {

        while(*dat!='\0')

        {  

           write_data(*dat);

           dat++;

           delay(5);

        }

    }

    /***********************************************************

        LCD整体左移动

    ***********************************************************/

    void LCD_MoveToLeft(){

        int num;

        for(num=0;num<16;num++)

        {

               write_command(0x18);

               delay(200);

        }

    }

     

     

    /***********************************************************

        LCD打印字符串

    ***********************************************************/

    void PrintToLCD(){

       

        //write_command(FIRST_LINE);

        //WriteStringToLCD(table);

        write_command(SECOND_LINE);

        WriteStringToLCD(Current_Time);

     

    }

     

    /***********************************************************

        是否加1

    ***********************************************************/

    void IsAdd(){

        if(PRESSED==Key_ADD){       //当加1按键按下

           delay(10);        //去抖动

           if(PRESSED==Key_ADD){    //当加1按键按下

               changeTime();

               InitTime();

               PrintToLCD();

               while(!Key_ADD);

           }

        }

    }

    /***********************************************************

        是否减1

    ***********************************************************/

    void IsMinus(){

        if(PRESSED==KEY_MINUS){     //当减1按键按下

           delay(10);        //去抖动

           if(PRESSED==KEY_MINUS){  //当减1按键按下

               if(Second>0){    //防止按下减1按钮的时候,被减成负数

                  Second--;

                  InitTime();

                  PrintToLCD();

                  while(!KEY_MINUS);

               }

           }

        }

    }

    /***********************************************************

        是否运行

    ***********************************************************/

    void IsRun(){

        if(PRESSED==FUNCTION_KEY){      //当减1按键按下

           delay(10);        //去抖动

              

           if(PRESSED==FUNCTION_KEY){  //当减1按键按下

               SUSPEND=~SUSPEND;

               // led1=SUSPEND;

           while(!KEY_MINUS);

            }

        }

    }

    /***********************************************************

        是否暂停

    ***********************************************************/

    void IsSuspend(){

        IsRun();

        IsMinus();        //监测是否需要减1

        IsAdd();          //监测是否需要加1     

    }

    /***********************************************************

        重新计数

    ***********************************************************/

    void ReCount(){

        Count=0;  //开始下一轮1s的计时

        TH0=T_High_50ms;// 计算初值,并将其写入TH0TL0TH1TL1

        TL0=T_Low_50ms;

    }

    /***********************************************************

        初始化时钟的值

    ***********************************************************/

    void initClockValue(){

        Second=I2C_read_address(2);    //读出保存的数据赋于Second

     

        Minute=I2C_read_address(3);

        Hour=I2C_read_address(4);

    }

    void main()

    {

        init();

        InitClockInterrupt();

        initButtonInterupt();

        initClockValue();

        if(Second>100)        //防止首次读取出错误数据

           Second=0;

     

        while(1){

        IsSuspend();

        if(Count>=20&&(!SUSPEND)){//定时器0 1s时间到

               ReCount();

               changeTime();

               InitTime();

               PrintToLCD();

           }

        }

     

    }

    //=========函数区结束============================================

     

    //=========中断函数区============================================

     

    /**

        初始化按钮外部中断

    **/

    void intButton() interrupt 0//外部中断0

    {

     

    }

     

    /**

        用定时0实现8个发光二极管以1s间隔闪烁

    **/

    void int0() interrupt 1//定时/计数器T0中断

    {

        Count++;

    }

     

     

    //=========中断函数区结束============================================

    本文转自陈哈哈博客园博客,原文链接http://www.cnblogs.com/kissazi2/p/3174473.html如需转载请自行联系原作者


    kissazi2

    展开全文
  • 学习完毕,又顺手利用刚学到定时器的相关知识写了一个“定时器初值计算”控制台程序,能够实现:51定时器三种不同工作方式下的初值计算输出,既实用,又能加深对所学知识的理解。 软件使用VS2012编写,实现效果...
  • 2、用定时器 定时器代码 #include &lt;reg52.h&gt; sbit LED=P1^0; unsigned char numl=0; int flag=0; void main() { TMOD=0x01; //定时器工作模式 TH0=(65536-50000)/256; ...
  • 定时器和计数器是作为定时器还是计数器使用,采用什么工作模式,是否需要利用中断系统参与控制过程,都需要对特殊功能寄存器TMOD和TCON写入相应的方式字和控制字。 方式寄存器: 方式寄存器即...
  •  前面一篇文章讲过如何利用定时器测量信号的频率(见[STM32F10x] 利用定时器测量频率),使用的是定时器的捕获/比较单元(Capture/compare),它也可以测量输入信号的脉冲宽度。  利用定时器测量脉冲宽度有两种方法...
  • 采用汇编语言,实现51单片机内部定时器产生脉冲的功能,附注释,方便自学。
  • 常规方法测量脉冲的频率,利用51单片机的两个定时器来测量,一个定时器来定时,一个定时器作为计数方式;能不能有一个更好的方法,不使用这么多硬件,只使用一个定时器就可以满足需求? 当然可以的,定时器2有输入...
  • 1.本篇博文旨在帮助那些像我一样刚入门51单片机,如果你对定时器有一定了解,但是其中的的工作方式不能理解,那么这篇文章很适合你,如果你是大神的话…直接绕行吧…… 2.我在学习的过程中由于知识上的不足很多的...
  • 实现数字时钟的方式是使用单片机定时器来实现的,让数码管动态显示
  • 我们首先需要了解什么是中断? 中断是指CPU在执行某一过程中由于外界原因必须暂停现在的事情,处理别的事情,处理完了再回去执行暂停的事情。 中断的优点? 1.分时操作。 2.实时响应 3.可靠性高 ... ...
  • 单片机利用定时器中断制作秒表 #include #define LED P0 sbit LA=P2^4; //对应着138译码器C,B,A端口 sbit LB=P2^3; sbit LC=P2^2; sbit start=P3^1;//三个键控制开关和暂停 sbit pulse=P3^0; sbit end=P3^2; char...
  • 任务:利用单片机的中断系统完成程序设计。 实验内容 使用AT89S52单片机的定时器/计数器T0控制实验箱母板上的LED1每隔1秒点亮一次(即亮1秒,灭1秒,如此反复)。LED1的阴极与AT89S52单片机的P1.5引脚连接。(AT89...
  • 51单片机定时器实验

    2008-01-17 16:09:00
    2006-05-11 09:56:09 51单片机定时器实验 一.实验要求由8031内部定时器1,按方式1工作,即作为16位定时器使用每0.05秒钟T1溢出中断一次。P1口的P1.0-P1.7分别接八个发光二极管。要求编写程序模拟一时序...
  • 对于刚接触单片机的同学来说可能会对定时器/计数器的应用很蒙圈,特别是初值的计算和各种定时方式的选择。下面希望能给你带来一个清晰的思路。 定时器:一般用于软件计时,给定时器设置一个时间,时间到了系统停止...
  • 51单片机定时器中断写MIDI音乐(按键可切换)
1 2 3 4 5 ... 20
收藏数 4,472
精华内容 1,788