admin 管理员组

文章数量: 1086866

51单片机定时器计时并数码管显示计时实验,精度不精确原因记录

开篇说明:开发板平台是普中的A7开发板,实验代码及相关注意事项以及精度不精确原因在下面代码注释中有说明。

/********************************************************************************实验现象:通过串转并及138译码器控制动态数码管秒表计时*接    线:P0.0 -> RC, P0.1 -> SC, P0.2 -> SE; P1.0 -> A_138, P1.1 -> B_138,P1.2 -> C_138; J27 -> J6;*注意事项:需要注意数码管数字显示前消影,数码管显示时不能用for循环来显示,因为*			for循环显示刷新太快了,而数码管显示最起码要保持1ms。所以在中断函数*          刷新显示数码管的时候用的是switch而不是for循环。*特别注意:做秒数定时实验的时候,使用了封装函数或者代码量太多后反而计时不准确,*          走时会变快,如果使用代码量小的测试代码计时基本正常,具体可以查看最下*          面的那段测试代码;******************************************************************************/
#include <reg52.h>#define DELAY_1_MS
//#define DELAY_500_US#define BIT_16_LOAD		0X01
#define AUTOLOAD		0X02
#define ON				0x01
#define OFF				0x00sbit RC = P0^0;
sbit SC = P0^1;
sbit SE = P0^2;sbit A_138 = P1^0;
sbit B_138 = P1^1;
sbit C_138 = P1^2;/* 数码管字模 */
unsigned char code byte_buff[] = {0xFC, 0x60, 0xDA, 0xF2, 0x66, 0xB6, 0xBE, 0xE0, 0xFE, 0xF6};
/* 138译码器真值表 */
unsigned char code ctl_138[] = {0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0};
/* 用来保存时间计算得出的数字 */
unsigned char tmp_buf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char pos = 1;		/* 记录需要显示多少个数码管 */
unsigned long sec = 0;		/* 记录走了多少个秒数 */
unsigned int cnt = 0;		/* 记录中断次数 */
unsigned char x_pos = 1;	/* 记录当前显示第几个数码管 */void Timer0Init();
void SetDelay();
void SentByte(unsigned char byte);
void SelectDisplay(unsigned char num);void main()
{unsigned char i;Timer0Init();while(1){if(cnt >= 1000)			/* 计时为1s的时候做下面的运算 */{cnt = 0;sec++;/* 用设置的ms计数计算tmp_buf[]的值 */tmp_buf[0] = byte_buff[sec%10];tmp_buf[1] = byte_buff[(sec/10)%10];tmp_buf[2] = byte_buff[(sec/100)%10];tmp_buf[3] = byte_buff[(sec/1000)%10];tmp_buf[4] = byte_buff[(sec/10000)%10];tmp_buf[5] = byte_buff[(sec/100000)%10];tmp_buf[6] = byte_buff[(sec/1000000)%10];tmp_buf[7] = byte_buff[(sec/10000000)%10];/* 计算有几个数码管需要显示 */for(i=1; i<8; i++){if(tmp_buf[8-i] != 0xFC) {pos = 8 - i + 1;break;		/* 如果不加break就会导致显示的数码管数量有时候是错误的 */}}}				}return;
} /* 定时器中断初始化 */
void Timer0Init()
{TMOD = BIT_16_LOAD;SetDelay();TR0 = ON;ET0 = ON;EA = ON;	return;
} /* 设置延迟并计算秒数 */
void InterruptTimer0() interrupt 1
{	SetDelay();cnt++;	SentByte(0x00);/* 让需要显示的数码管正确显示数字 */if(x_pos > pos){x_pos = 1;}switch(x_pos){case 1:SelectDisplay(0); x_pos++; break;case 2:SelectDisplay(1); x_pos++; break;case 3:SelectDisplay(2); x_pos++; break;case 4:SelectDisplay(3); x_pos++; break;		case 5:SelectDisplay(4); x_pos++; break;		case 6:SelectDisplay(5); x_pos++; break;	case 7:SelectDisplay(6); x_pos++; break;case 8:SelectDisplay(7); x_pos++; break;default:break;		}
}/* 选择显示数码管并发送显示数据到数码管 */
void SelectDisplay(unsigned char num)
{A_138 = (ctl_138[num] >> 0) & 0x1;B_138 = (ctl_138[num] >> 1) & 0x1;C_138 = (ctl_138[num] >> 2) & 0x1;SentByte(tmp_buf[num]);
}void SentByte(unsigned char byte)
{unsigned char i;RC = 0;for(i=0; i<8; i++){SC = 0;SE = (byte >> i) & 0x1;SC = 1;}RC = 1;return;
}/* 延迟设置 */
#ifdef DELAY_1_MS
void SetDelay()
{TH0 = 0xFC;TL0 = 0x18;return;
}
#elif define DELAY_500_US
void SetDelay()
{TH0 = 0xFE;TL0 = 0x0C;return;
}
#endif/*********************************************************************** * 测试51单片机定时器计时是否准确代码,只摘录了main函数和interrupt函数,* 其他的函数都是跟上面的一模一样.**********************************************************************/
#if 0
void main()
{Timer0Init();while(1){if(cnt >= 1000)			/* 计时为1s的时候做下面的运算 */{cnt = 0;sec++;/* 用设置的ms计数计算tmp_buf[]的值 */tmp_buf[0] = byte_buff[sec%10];SentByte(0x00);A_138 = (ctl_138[0] >> 0) & 0x1;B_138 = (ctl_138[0] >> 1) & 0x1;C_138 = (ctl_138[0] >> 2) & 0x1;SentByte(tmp_buf[0]);		}				}return;
} /* 设置延迟并计算秒数 */
void InterruptTimer0() interrupt 1
{	TH0 = 0xFC;TL0 = 0x18;cnt++;	
}
#endif

本文标签: 51单片机定时器计时并数码管显示计时实验,精度不精确原因记录