一个很短的PIC16F877A单片机程序

#include<pic.h>__CONFIG(0x3B31);
void initial();
void main()
{
unsigned char count;
initial();
while(1)
{
if(T0IF==1) //T0IF为TMR0的溢出中断申请标志位,T0IF=1时申请中断
{
T0IF=0; //T0IF必须软件清零
TMR0=61;
count++;
if(count==20) //count=20时,一共计数时钟脉冲=256*195*20=998400,4分频后的时钟频率为1MHz,即耗时0.9984s≈1s
{
RD0=!RD0; //控制LED灯亮暗变化
count=0;
}
}
}
}

void initial()
{
TRISD=0;
PORTD=0; //设置RD口为输出,且一开始输出低电平
OPTION=0x07; //设置定时器0定时方式,TMR0分频比为1:256
TMR0=61; //设置TMR0初始值为61,即每次计数195次便发出中断信号
}

上面已经对程序注释了,计算过程也注明了,用proteus仿真时结果并不是1秒亮,1秒灭,大概是1.5秒亮,1.5秒灭,望proteus高手指导!

在使用PIC16F877A单片机时,如果使用定时器0,那么最好不要写TMR0,因为每次的写操作都会导致定时器0的预分频器清零。一般都是定义一个变量,来做定时器0计时值的累计,这样才会将误差降到最小。另外就是仿真的时间不一定准确追问

那应该怎么写?我上面的程序其实是从郭天祥的视频里学的,我记得他的单片机的定时是比较正常,就是不知道为什么一到proteus就出问题了。

追答

如果要用定时器0实现比较精确的定时,如你这个程序
#include__CONFIG(0x3B31);
unsigned long Timer0Count;
void initial();
void main()
{
initial();
while(1)
{
if(T0IF==1) //T0IF为TMR0的溢出中断申请标志位,T0IF=1时申请中断
{
T0IF=0; //T0IF必须软件清零
Timer0Count += 65536;
if(Timer0Count > 1000000)
{
Timer0Count -= 1000000; //每次到达1s后,累积的误差均在该变量中
RD0=!RD0; //控制LED灯亮暗变化
}
}
}
}

void initial()
{
TRISD=0;
PORTD=0; //设置RD口为输出,且一开始输出低电平
OPTION=0x07; //设置定时器0定时方式,TMR0分频比为1:256
TMR0=0; //因为TMR0没有禁止/使能位,所以这里要赋初值,每65536us溢出一次(FOSC = 4MHz)
Timer0Count = 0;
}

追问

谢谢你的程序,其实我已经找到原因了,原因是proteus的时间跟电脑的时间不一致,我在proteus的仿真时间里认真对照过,LED灯确实是1秒亮,一秒灭。上网查过怎么调这个时间变成正常时间,但网上的都说调步长,我怎么调都调不到,你知道怎么调吗?

追答

我第一次回答的时候,就说过仿真的时间不一定准确。我没用过PROTEUS

温馨提示:答案为网友推荐,仅供参考
第1个回答  2012-09-12
这个跟单片机是晶振频率有关,还有就是C语言的目标程序可能会多一些指令所以一般都比汇编要长一些时间!