#include<p18f452.h>
void T0_init();
void main()
{
TRISC=0; // Configure PortB as output Port.
LATC=0x01;
T0CON=0x07; // Prescaler= 1:256, 16-bit mode, Internal Clock
T0_init();
while(1)
{
// Initialize Timer0
LATC=0x00;
T0_init(); //Delay for 1 sec
LATC=0x01;
T0_init(); //Again delay for 1 sec
}
}
void T0_init()
{
int a=0;
//while(a<2) // {
TMR0H=0xF0; // Values calculated for 1 second delay with 4MHz crystal
TMR0L=0xBD; //4/4MHz =1us=1us*prescaler=256us=1sec/256u=0xF42-(FFFF)=F0BD
T0CONbits.TMR0ON=1; // Timer0 On
while(INTCONbits.TMR0IF==0); // Wait until TMR0IF gets flagged
T0CONbits.TMR0ON=0; // Timer0 Off
INTCONbits.TMR0IF=0; // Clear Timer0 interrupt flag
// a++;
// }
}
这是非常准确的延迟,它正在开展工作,但我想要更长的延迟,如小时或分钟。那么,如何处理更长的延误。我尝试使用计数器,每增加一个标记,但它不起作用。
答案 0 :(得分:0)
秒是1000000微秒,小于256 * 256 * 256 = 16777216。因此,256预分频的16位定时器足以计数一秒。但这还不足以算一分钟。
解决方案是添加for
循环来计算秒数。另外一个是分钟,另一个是几个小时,正如@Andrew所建议的那样。
不确定性的来源是在while()
循环中检查定时器溢出一次。因此,如果在该循环中执行长计算,则精度将降低。为了克服这个问题,使用中断是可行的方法。无论发生什么,随着定时器的溢出发生,中断标志被提升,中断功能在几个周期内执行。
由于while(1)
循环中没有任何操作,我想使用SLEEP()
命令来节省一些能量。不幸的是,{0}}命令关闭了timer0。这不是timer1的情况,但是timer1是一个8预分频的16位定时器......所以需要一个for循环来计算一秒钟。
这是由XC8编译并使用MPLAB X的模拟器进行测试的代码......
SLEEP()
“秒”的持续时间会受到警惕......可能需要使用#include <xc.h>
#pragma config WDT=OFF
volatile unsigned char nb;
volatile unsigned char seconds;
volatile unsigned char minutes;
volatile unsigned char hours;
void interrupt high_isr (void)
{
if(PIR1bits.TMR1IF) //interrupt flag of TIMER1
{
if(nb==0){
TMR1H=0; // Values calculated for 1 second delay with 4MHz crystal
TMR1L=0;
nb=1;//4/4MHz =1us=1us*prescaler=8us=1sec/8u=...
}else{
TMR1H=23;
TMR1L=184;
nb=0;
}
if(nb==1){
seconds++;
if(seconds==60){
seconds=0;
minutes++;
if(minutes==60){
minutes=0;
hours++;
}
}
}
PIR1bits.TMR1IF=0; //erase interrupt flag of TIMER1
}
}
void interrupt low_priority low_isr (void)
{
}
void main(void) {
//OSCCON=0x7D;//Internal oscillator, 8Mhz
T1CONbits.RD16=1; //timer1 is a 16-bit timer
T1CONbits.T1CKPS1=1; //prescaler 11 -> 8-prescaled
T1CONbits.T1CKPS0=1;
T1CONbits.TMR1ON=1;// switch on timer1
TMR1H=0x00; //setting timer1 : high bit first
TMR1L=0x00;
// TMR0H=0;
// TMR0L=0;
TRISC=0;
LATC=0x00;
INTCON2bits.TMR0IP=0; // low priority interuption timer0
IPR1bits.TMR1IP=1; // high priority interuption timer1
INTCONbits.TMR0IF=0;//erase interruption flap if set
PIR1bits.TMR1IF=0; //erase interruption flag if set
RCONbits.IPEN=1;// Interruption prioritaires
INTCONbits.TMR0IE=0;// interuption activation on timer0 (0=no active)
PIE1bits.TMR1IE=1;//enable interupt on timer1
nb=1;
seconds=0;
minutes=0;
hours=0;
PORTCbits.RC0=0;
PORTCbits.RC1=0;
PORTCbits.RC2=0;
INTCONbits.GIEH=1;// autorise interuptions
INTCONbits.GIEL=1;
// INTCONbits.GIE=1;
while(1){
//problem with modulo and pic...do not use %
if(seconds-2*(seconds/2)==1){
PORTCbits.RC0=1;
}else{
PORTCbits.RC0=0;
}
if(minutes-2*(minutes/2)==1){
PORTCbits.RC1=1;
}else{
PORTCbits.RC1=0;
}
if(hours-2*(hours/2)==1){
PORTCbits.RC2=1;
}else{
PORTCbits.RC2=0;
}
SLEEP();
}
return;
}
,TMR1H
和TMR1L
。
使用外部时钟源(石英)更好:How to make Timer1 more accurate as a real time clock?
答案 1 :(得分:0)
我不是一个经验丰富的程序员,也不确定你想要使用延迟的确切位置,但我曾尝试用pic18f4550进行长时间的延迟,但它没有工作,即几分钟和几小时。但我考虑使用像CD4060或DS1307这样的IC。你可以点击此链接获取CD4060:http://dmohankumar.wordpress.com/2012/05/13/design-your-circuit-part-ii-cd-4060-timer/。对于DS1307,您可以在studentcompanion网站上查看:http://www.studentcompanion.co.za/post/Digital-Clock-using-PIC-Microcontroller-and-the-DS1307-Real-Time-Clock-XC8-Compiler/。祝你成功,谢谢
答案 2 :(得分:0)
忘记内部计时器并自己做一个繁忙的等待程序:先做一个1秒的延迟程序(非常简单,准确地完成它,处理调用和retf执行时间!),然后做一个1-在第一个上面的分钟延迟例程,然后在1分钟的顶部进行1小时的延迟例程......你明白了。