为什么ATmege 16单片机中的定时器T1中断不起作用?

时间:2022-08-17 05:17:18
    我想用ATmege 16单片机做一个电子钟,用lcd1602显示,结果能显示,就是时间不走,原因就是定时器T1的中断不起作用,因为我用定时器T1计时间,每隔一秒 就进入中断,不知什么原因,请各位高手知道指点!
    源程序如下:

    #include <iom16v.h>
#include <macros.h>
#define uchar unsigned char
#define uint unsigned int    
#include"lcd1602.c"
#include"anjian.c"
uchar x,y,z;
uchar shigao,shidi,fengao,fendi,miaogao,miaodi;

#pragma data:code
const uchar string1[]=" current time:  ";
const uchar string2[]="set new time....";

#pragma data:data
uchar string3[]="0123456789:";

#pragma interrupt_handler miao:9  //定时器T1中断入口
uchar settime;
uchar change_h_m_s;
 
void miao()

   z++;
  if(z==60)
   {
   z=0;
   y+=1; 
    if(y==60)
    {
     y=0;
     x+=1; 
      if(x==24) 
       {
   x=0;y=0;z=0;
   }
     }   
   }   
  TCNT1H=0x85;
  TCNT1L=0Xed; 
}


void set_lcd_pos(uchar p)
{
 lcd_write_com(p|0x80);
 delay(1);
}


void display_string(uchar p, const uchar *s)
{
 uchar i;
 set_lcd_pos(p);
 for(i=0;i<16;i++)
  {
   lcd_write_date(s[i]);
   delay(1); 
  }
}


void fenli()
{
 shigao=x/10; delay(1); 
 shidi=x%10;  delay(1); 
 fengao=y/10; delay(1); 
 fendi=y%10;  delay(1); 
 miaogao=z/10;delay(1); 
 miaodi=z%10; delay(1); 
}



void display_shifenmiao()
{
 fenli();
 lcd_write_com(0xc4);
 lcd_write_date(string3[shigao]);
 
 lcd_write_com(0xc5);
 lcd_write_date(string3[shidi]);
 
 lcd_write_com(0xc7);
 lcd_write_date(string3[fengao]);

 lcd_write_com(0xc8);
 lcd_write_date(string3[fendi]);

 lcd_write_com(0xca);
 lcd_write_date(string3[miaogao]);

 lcd_write_com(0xcb);
 lcd_write_date(string3[miaodi]);

}


void  main()
{
 uchar i;
 x=22;
 y=24;
 z=0;  
  
         TCCR1B=0X04;//256分频
TCNT1H=0x85;
TCNT1L=0XED;//设置定时器初值
TIMSK|=BIT(2);//开启定时器中断
SREG|=BIT(7);//开启总中断TCCR1B=0X04;
   
 DDRD=0X70;//设置PD4,PD5,PD6都为输出
 DDRB=0XFF;//pb口设置为输出      
 lcd_init();//lcd1602初始化 

 display_string(0x00,string1);  // 第一行显示字符串1
 
 lcd_write_com(0xc6);
 lcd_write_date(string3[10]);
 delay(1);
 lcd_write_com(0xc9);
 lcd_write_date(string3[10]);
 delay(1);  //显示“  :   :  ”

while(1)
  {
   //if((TIFR&(BIT(TOV1))))
     //miao();
   display_shifenmiao();
    delay(10); //显示时间"22 44 00"
  }
}
 




8 个解决方案

#1


先给你个例程,你自己对照下,有空再帮你看下程序。
首先是:init.c
//ICC-AVR application builder : 2006-3-26 12:49:14 

// Target : M16
// Crystal: 8.0000Mhz

#include <iom16v.h>
#include <macros.h>
#define uchar unsigned char 

void port_init(void)
{
 PORTA = 0x00;
 DDRA  = 0xC0;
 PORTB = 0x00;
 DDRB  = 0x00;
 PORTC = 0x00; //m103 output only
 DDRC  = 0xFF;
 PORTD = 0x00;
 DDRD  = 0x00;
}

//TIMER0 initialize - prescale:64
// WGM: Normal
// desired value: 1mSec
// actual value:  1.000mSec (0.0%)
void timer0_init(void)
{
 TCCR0 = 0x00; //stop
 TCNT0 = 0x83; //set count
 OCR0  = 0x7D;  //set compare
 TCCR0 = 0x03; //start timer
}
////////////////中断服务程序/////////////////////////
extern uchar ShuMa[2];//显示缓冲区
unsigned int count=0;//软件记数
#pragma interrupt_handler timer0_ovf_isr:10
void timer0_ovf_isr(void)
{
 TCNT0 = 0x83; //reload counter value
 if(++count==1000)//1000个1mS等于1秒
 {
  count=0;
  if(++ShuMa[1]==10)//个位
  {
   ShuMa[1]=0;
   if(++ShuMa[0]==6)ShuMa[0]=0;//十位
  }
 }
}
///////////////////////////////////////////////
//call this routine to initialize all peripherals
void init_devices(void)
{
 //stop errant interrupts until set up
 CLI(); //disable all interrupts
 port_init();
 timer0_init();

 MCUCR = 0x00;
 GICR  = 0x00;
 TIMSK = 0x01; //timer interrupt sources
 SEI(); //re-enable interrupts
 //all peripherals are now initialized
}


再是main.c
#include <iom16v.h> 


#define uchar unsigned char 
#define uint  unsigned int
#define Left  0x80
#define Right 0x40
unsigned char const Tab[]={0x14,0x9F,0x38,0x1A,0x93,0x52,0x50,0x1F,
                          0x10,0x12,0x11,0xD0,0x74,0x98,0x70,0x71};
  
void display();//负责把显示缓冲区的数据显示到数码管
void delay(uint ticks);//延时
uchar ShuMa[2];//显示缓冲区

void main()
{
init_devices();
ShuMa[0]=0;
ShuMa[1]=0;
while(1) display();//显示

}


void display()
{
 PORTA=Left|Right;//关显示
 PORTC=Tab[ShuMa[0]];  //输出数据
 PORTA=~Left;   //开左数码管
 delay(10);   //延时
 PORTA=Left|Right;//关显示
 PORTC=Tab[ShuMa[1]];  //输出数据
 PORTA=~Right;   //开右数码管
 delay(10);   //延时
}



void delay(uint ticks)
{
 uchar i;
 while(ticks--)for(i=100;i!=0;i--);//约0.1mS
}


#2


但愿对你有帮助。

#3


   仔细看了一下,你的思路完全正确,但是我的程序改了之后还是老样子,真的不知道哪里出了问题,你帮我看一看,我是新手,刚开始学习AVR单片机,谢谢了!
    #include <iom16v.h>
#include <macros.h>
#define uchar unsigned char
#define uint unsigned int    
#include"lcd1602.c"
#include"anjian.c"
uchar x,y,z,key;
uchar shigao,shidi,fengao,fendi,miaogao,miaodi;

#pragma data:code
const uchar string1[]=" current time:  ";
const uchar string2[]="set new time....";

#pragma data:data
uchar string3[]="0123456789:";

#pragma interrupt_handler miao:9  //定时器T1中断入口
uchar settime;
uchar change_h_m_s;
 
void miao()

CLI();
MCUCR=0X00;  //空闲模式
GICR=0X00;//禁止外部中断请求
   z++;
  if(z==60)
   {
   z=0;
   y+=1; 
    if(y==60)
    {
     y=0;
     x+=1; 
      if(x==24) 
       {
   x=0;y=0;z=0;
   }
     }   
   }   
 TCNT1H=0x85;
 TCNT1L=0Xed; 
 SEI();
}

void set_lcd_pos(uchar p)
{
 lcd_write_com(p|0x80);
 delay(1);
}

void display_string(uchar p, const uchar *s)
{
 uchar i;
 set_lcd_pos(p);
 for(i=0;i<16;i++)
  {
   lcd_write_date(s[i]);
   delay(1); 
  }
}

void beep()
{
  uint i;  uchar j=200;
  for(i=0;i<1145;i++)
  {
   while(--j)
   PORTA=~BIT(6);  
  }
}


void fenli()
{
 shigao=x/10; delay(1); 
 shidi=x%10;  delay(1); 
 fengao=y/10; delay(1); 
 fendi=y%10;  delay(1); 
 miaogao=z/10;delay(1); 
 miaodi=z%10; delay(1); 
}



void display_shifenmiao()
{
 fenli();
 lcd_write_com(0xc4);
 lcd_write_date(string3[shigao]); 
 lcd_write_com(0xc5);
 lcd_write_date(string3[shidi]);
 
 lcd_write_com(0xc7);
 lcd_write_date(string3[fengao]);
 lcd_write_com(0xc8);
 lcd_write_date(string3[fendi]);

 lcd_write_com(0xca);
 lcd_write_date(string3[miaogao]);
 lcd_write_com(0xcb);
 lcd_write_date(string3[miaodi]);

}



/* change_time()
{
 settime=0;
 if(key==1||key==2||key==3)
 {
  display_string(0x00,string2);
  settime=1; 
 }
  while(settime)
  {
   if(key==1)
    {
 beep();
 while(key==1);
   change_h_m_s++;
   if(change_h_m_s==4)
    {change_h_m_s=0;}
}

   else if(key==2)
   {
    beep();
while(key==2);
    if(change_h_m_s==1)
 {if(++x==24) x=0;}
    else if(change_h_m_s==2)  
 {if(++y==60) y=0;} 
else  if(change_h_m_s==3)
 {if(++z==60) z=0;}
   }
  else if(key==3)
  {
   beep();
   while(key==3);
   if(change_h_m_s==1)
 {if(--x==0xff) x=23;}
    else if(change_h_m_s==2)  
 {if(--y==0xff) y=59;} 
else  if(change_h_m_s==3)
 {if(--z==0xff) z=59;} 
  }
  else if(key==4)
  {
   beep();
   while(key==4);
   display_string(0x00,string1);
   settime=0;  
  } 
display_shifenmiao();
delay(5);
 }
} */



void  main()
{
 uchar i;
 x=22;
 y=24;
 z=0; 
 settime=0x00;
 change_h_m_s=0x01;
 DDRA=0X40;//设置接蜂鸣器的端口PA6为输出
 PORTA=BIT(6);
  
    CLI();
    TCCR1B=0X04;//256分频
TCNT1H=0x85;
TCNT1L=0XED;//设置定时器初值
TIMSK|=BIT(2);//开启定时器中断
SEI();//开启总中断TCCR1B=0X04;
   
 DDRD=0X70;//设置PD4,PD5,PD6都为输出
 DDRB=0XFF;//pb口设置为输出      
 lcd_init();//lcd1602初始化 

 display_string(0x00,string1);  // 第一行显示字符串1
 
 lcd_write_com(0xc6);
 lcd_write_date(string3[10]);
 delay(1);
 lcd_write_com(0xc9);
 lcd_write_date(string3[10]);
 delay(1);  //显示“  :   :  ”

while(1)
  {
   display_shifenmiao();
    //delay(10); //显示时间"22 44 00"
  }
}
 


lcd1602的设置
   void delay(uint ms)
 {
   uint a,b;
   for(a=0;a<ms;a++)
    for(b=0;b<1141;b++); 
 }
 
void lcd_write_com(uchar com)
{
  DDRD=0X70;//设置PD4,PD5,PD6都为输出
  PORTD&=~BIT(4);
  PORTD&=~BIT(5);//设置rs和rw为0
  
  PORTD&=~BIT(6);//en为0
  PORTB=com;
  PORTD|=BIT(6);//en为1
  delay(1);
  PORTD&=~BIT(6); //en为0 
}


void lcd_write_date(uchar dat)
{
  DDRD=0X70;//设置PD4,PD5,PD6都为输出
  PORTD|=BIT(4);//设置rs为1
  PORTD&=~BIT(5);//设置rw为0
  
  PORTD&=~BIT(6);//en为0
  PORTB=dat;
  PORTD|=BIT(6);//en为1
  delay(1);
  PORTD&=~BIT(6); //en为0 
}


void lcd_init()  
{
 lcd_write_com(0x38);//设置lcd1602为5*7点阵,2行显示,8位总线
 delay(1);
 lcd_write_com(0x01);//清屏幕
 delay(1);
 lcd_write_com(0x0c);//开显示
 delay(1);
 lcd_write_com(0x06);//地址加1
 delay(1);
}


按键部分先暂时不调用,先解决这个问题在说! 在线的各位高手,都来帮忙解决一下这个问题.
  

#4


   还有一个现象就是屏幕1秒钟闪烁一次,但是秒就是不加1,应该是进了中断,但是没有执行中断里面的程序! 这真的是太奇怪了。

#5


1、你要在中断处 设个断点,看看能否进入中断 如果进入不了 检查中断初始化部分代码
2、进入中断后 首先要重新给初值 重新赋值

#6


给你些建议吧!
1.在定时器初始化的时候这个设置
  TCCR1B=0X04;//256分频 
  应该放在把其它寄存器设置好之后,因为一执行完这条语句之后定时器就马上启动了。
2.还有就是把时间刷新的部分直接弄到定时器中断里面,那样就不用整天占用mcu资源
3.调试的时候你可以自己编写一个明显的现实界面放在适当的地方例如屏幕现实一个字符这样你就可以知道程序的运行过程,方便调试

#7


 谢谢各位的回答! 我会费心思在调试一下!

#8


{
 TCCR1B = 0x00; //stop
 TCNT1H = 0xE1; //setup
 TCNT1L = 0x7C;
 OCR1AH = 0x1E;
 OCR1AL = 0x84;
 OCR1BH = 0x1E;
 OCR1BL = 0x84;
 OCR1CH = 0;
 OCR1CL = 0;
 ICR1H  = 0x1E;
 ICR1L  = 0x84;
 TCCR1A = 0x00;
 TCCR1B = 0x05; //start Timer
}
这个是8M晶振,1024分频,1秒的。

#1


先给你个例程,你自己对照下,有空再帮你看下程序。
首先是:init.c
//ICC-AVR application builder : 2006-3-26 12:49:14 

// Target : M16
// Crystal: 8.0000Mhz

#include <iom16v.h>
#include <macros.h>
#define uchar unsigned char 

void port_init(void)
{
 PORTA = 0x00;
 DDRA  = 0xC0;
 PORTB = 0x00;
 DDRB  = 0x00;
 PORTC = 0x00; //m103 output only
 DDRC  = 0xFF;
 PORTD = 0x00;
 DDRD  = 0x00;
}

//TIMER0 initialize - prescale:64
// WGM: Normal
// desired value: 1mSec
// actual value:  1.000mSec (0.0%)
void timer0_init(void)
{
 TCCR0 = 0x00; //stop
 TCNT0 = 0x83; //set count
 OCR0  = 0x7D;  //set compare
 TCCR0 = 0x03; //start timer
}
////////////////中断服务程序/////////////////////////
extern uchar ShuMa[2];//显示缓冲区
unsigned int count=0;//软件记数
#pragma interrupt_handler timer0_ovf_isr:10
void timer0_ovf_isr(void)
{
 TCNT0 = 0x83; //reload counter value
 if(++count==1000)//1000个1mS等于1秒
 {
  count=0;
  if(++ShuMa[1]==10)//个位
  {
   ShuMa[1]=0;
   if(++ShuMa[0]==6)ShuMa[0]=0;//十位
  }
 }
}
///////////////////////////////////////////////
//call this routine to initialize all peripherals
void init_devices(void)
{
 //stop errant interrupts until set up
 CLI(); //disable all interrupts
 port_init();
 timer0_init();

 MCUCR = 0x00;
 GICR  = 0x00;
 TIMSK = 0x01; //timer interrupt sources
 SEI(); //re-enable interrupts
 //all peripherals are now initialized
}


再是main.c
#include <iom16v.h> 


#define uchar unsigned char 
#define uint  unsigned int
#define Left  0x80
#define Right 0x40
unsigned char const Tab[]={0x14,0x9F,0x38,0x1A,0x93,0x52,0x50,0x1F,
                          0x10,0x12,0x11,0xD0,0x74,0x98,0x70,0x71};
  
void display();//负责把显示缓冲区的数据显示到数码管
void delay(uint ticks);//延时
uchar ShuMa[2];//显示缓冲区

void main()
{
init_devices();
ShuMa[0]=0;
ShuMa[1]=0;
while(1) display();//显示

}


void display()
{
 PORTA=Left|Right;//关显示
 PORTC=Tab[ShuMa[0]];  //输出数据
 PORTA=~Left;   //开左数码管
 delay(10);   //延时
 PORTA=Left|Right;//关显示
 PORTC=Tab[ShuMa[1]];  //输出数据
 PORTA=~Right;   //开右数码管
 delay(10);   //延时
}



void delay(uint ticks)
{
 uchar i;
 while(ticks--)for(i=100;i!=0;i--);//约0.1mS
}


#2


但愿对你有帮助。

#3


   仔细看了一下,你的思路完全正确,但是我的程序改了之后还是老样子,真的不知道哪里出了问题,你帮我看一看,我是新手,刚开始学习AVR单片机,谢谢了!
    #include <iom16v.h>
#include <macros.h>
#define uchar unsigned char
#define uint unsigned int    
#include"lcd1602.c"
#include"anjian.c"
uchar x,y,z,key;
uchar shigao,shidi,fengao,fendi,miaogao,miaodi;

#pragma data:code
const uchar string1[]=" current time:  ";
const uchar string2[]="set new time....";

#pragma data:data
uchar string3[]="0123456789:";

#pragma interrupt_handler miao:9  //定时器T1中断入口
uchar settime;
uchar change_h_m_s;
 
void miao()

CLI();
MCUCR=0X00;  //空闲模式
GICR=0X00;//禁止外部中断请求
   z++;
  if(z==60)
   {
   z=0;
   y+=1; 
    if(y==60)
    {
     y=0;
     x+=1; 
      if(x==24) 
       {
   x=0;y=0;z=0;
   }
     }   
   }   
 TCNT1H=0x85;
 TCNT1L=0Xed; 
 SEI();
}

void set_lcd_pos(uchar p)
{
 lcd_write_com(p|0x80);
 delay(1);
}

void display_string(uchar p, const uchar *s)
{
 uchar i;
 set_lcd_pos(p);
 for(i=0;i<16;i++)
  {
   lcd_write_date(s[i]);
   delay(1); 
  }
}

void beep()
{
  uint i;  uchar j=200;
  for(i=0;i<1145;i++)
  {
   while(--j)
   PORTA=~BIT(6);  
  }
}


void fenli()
{
 shigao=x/10; delay(1); 
 shidi=x%10;  delay(1); 
 fengao=y/10; delay(1); 
 fendi=y%10;  delay(1); 
 miaogao=z/10;delay(1); 
 miaodi=z%10; delay(1); 
}



void display_shifenmiao()
{
 fenli();
 lcd_write_com(0xc4);
 lcd_write_date(string3[shigao]); 
 lcd_write_com(0xc5);
 lcd_write_date(string3[shidi]);
 
 lcd_write_com(0xc7);
 lcd_write_date(string3[fengao]);
 lcd_write_com(0xc8);
 lcd_write_date(string3[fendi]);

 lcd_write_com(0xca);
 lcd_write_date(string3[miaogao]);
 lcd_write_com(0xcb);
 lcd_write_date(string3[miaodi]);

}



/* change_time()
{
 settime=0;
 if(key==1||key==2||key==3)
 {
  display_string(0x00,string2);
  settime=1; 
 }
  while(settime)
  {
   if(key==1)
    {
 beep();
 while(key==1);
   change_h_m_s++;
   if(change_h_m_s==4)
    {change_h_m_s=0;}
}

   else if(key==2)
   {
    beep();
while(key==2);
    if(change_h_m_s==1)
 {if(++x==24) x=0;}
    else if(change_h_m_s==2)  
 {if(++y==60) y=0;} 
else  if(change_h_m_s==3)
 {if(++z==60) z=0;}
   }
  else if(key==3)
  {
   beep();
   while(key==3);
   if(change_h_m_s==1)
 {if(--x==0xff) x=23;}
    else if(change_h_m_s==2)  
 {if(--y==0xff) y=59;} 
else  if(change_h_m_s==3)
 {if(--z==0xff) z=59;} 
  }
  else if(key==4)
  {
   beep();
   while(key==4);
   display_string(0x00,string1);
   settime=0;  
  } 
display_shifenmiao();
delay(5);
 }
} */



void  main()
{
 uchar i;
 x=22;
 y=24;
 z=0; 
 settime=0x00;
 change_h_m_s=0x01;
 DDRA=0X40;//设置接蜂鸣器的端口PA6为输出
 PORTA=BIT(6);
  
    CLI();
    TCCR1B=0X04;//256分频
TCNT1H=0x85;
TCNT1L=0XED;//设置定时器初值
TIMSK|=BIT(2);//开启定时器中断
SEI();//开启总中断TCCR1B=0X04;
   
 DDRD=0X70;//设置PD4,PD5,PD6都为输出
 DDRB=0XFF;//pb口设置为输出      
 lcd_init();//lcd1602初始化 

 display_string(0x00,string1);  // 第一行显示字符串1
 
 lcd_write_com(0xc6);
 lcd_write_date(string3[10]);
 delay(1);
 lcd_write_com(0xc9);
 lcd_write_date(string3[10]);
 delay(1);  //显示“  :   :  ”

while(1)
  {
   display_shifenmiao();
    //delay(10); //显示时间"22 44 00"
  }
}
 


lcd1602的设置
   void delay(uint ms)
 {
   uint a,b;
   for(a=0;a<ms;a++)
    for(b=0;b<1141;b++); 
 }
 
void lcd_write_com(uchar com)
{
  DDRD=0X70;//设置PD4,PD5,PD6都为输出
  PORTD&=~BIT(4);
  PORTD&=~BIT(5);//设置rs和rw为0
  
  PORTD&=~BIT(6);//en为0
  PORTB=com;
  PORTD|=BIT(6);//en为1
  delay(1);
  PORTD&=~BIT(6); //en为0 
}


void lcd_write_date(uchar dat)
{
  DDRD=0X70;//设置PD4,PD5,PD6都为输出
  PORTD|=BIT(4);//设置rs为1
  PORTD&=~BIT(5);//设置rw为0
  
  PORTD&=~BIT(6);//en为0
  PORTB=dat;
  PORTD|=BIT(6);//en为1
  delay(1);
  PORTD&=~BIT(6); //en为0 
}


void lcd_init()  
{
 lcd_write_com(0x38);//设置lcd1602为5*7点阵,2行显示,8位总线
 delay(1);
 lcd_write_com(0x01);//清屏幕
 delay(1);
 lcd_write_com(0x0c);//开显示
 delay(1);
 lcd_write_com(0x06);//地址加1
 delay(1);
}


按键部分先暂时不调用,先解决这个问题在说! 在线的各位高手,都来帮忙解决一下这个问题.
  

#4


   还有一个现象就是屏幕1秒钟闪烁一次,但是秒就是不加1,应该是进了中断,但是没有执行中断里面的程序! 这真的是太奇怪了。

#5


1、你要在中断处 设个断点,看看能否进入中断 如果进入不了 检查中断初始化部分代码
2、进入中断后 首先要重新给初值 重新赋值

#6


给你些建议吧!
1.在定时器初始化的时候这个设置
  TCCR1B=0X04;//256分频 
  应该放在把其它寄存器设置好之后,因为一执行完这条语句之后定时器就马上启动了。
2.还有就是把时间刷新的部分直接弄到定时器中断里面,那样就不用整天占用mcu资源
3.调试的时候你可以自己编写一个明显的现实界面放在适当的地方例如屏幕现实一个字符这样你就可以知道程序的运行过程,方便调试

#7


 谢谢各位的回答! 我会费心思在调试一下!

#8


{
 TCCR1B = 0x00; //stop
 TCNT1H = 0xE1; //setup
 TCNT1L = 0x7C;
 OCR1AH = 0x1E;
 OCR1AL = 0x84;
 OCR1BH = 0x1E;
 OCR1BL = 0x84;
 OCR1CH = 0;
 OCR1CL = 0;
 ICR1H  = 0x1E;
 ICR1L  = 0x84;
 TCCR1A = 0x00;
 TCCR1B = 0x05; //start Timer
}
这个是8M晶振,1024分频,1秒的。