打印
[AVR单片机]

AVR Timer0定时器不准,总跑快,快被搞疯了,跪求解答啊

[复制链接]
4020|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
写了个最简单的定时器 延时函数delay_ms(1000), 想测试下1秒闪烁LED灯延时准不准,结果总是跑快。大概5秒闪烁7次。

用porteus仿真和实际烧片测试,发现每两个周期会出现一个延时只有800ms . 各种尝试都不行。
具体程序代码如下:
#include <avr/io.h>
#include <avr/interrupt.h>
#define Fosc 1000000  //系统时钟设置,采用内置1M
unsigned int count=0;
void Timer0_init()//频率:Fosc/8=1M/8=125000,计数周期(计数加1用时)为1/125000=8us
{
    TCCR0 = 0x00;                  //停止定时器0工作
    TCNT0 = 256-(Fosc/8.0)*0.001;  //定时1ms,需计数次数为1000us/8=125次,初值:256-125
    TIMSK |= 0x01;                 //T0中断允许
    SREG  |= 0x80;                 //开总中断
    TCCR0 = 0x02;                  //启动定时器0,8分频
}
void delay_ms1(unsigned int t)
{
   Timer0_init();
   count=t;
   while(count);
   TCCR0=0x00;
}
int main()
{
   PORTB=0xff;
   DDRB=0xff;
   Timer0_init();
   while(1)
   {
      delay_ms1(1000);
      PORTB=~PORTB;
   }
}

ISR(TIMER0_OVF_vect)
{
   TCNT0 = 256-(Fosc/8.0)*0.001;
   count--;
}
porteus 仿真时用测试的波形如下


按照道理说不应该出现这种情况的,程序也是简单到不行,如果时间长点还能理解,但是快了就完全不明白了。
求解答啊。总不会是AVR的单片机定时器不准吧……

相关帖子

沙发
shgb2003|  楼主 | 2013-8-6 13:27 | 只看该作者
另外说一下,用的是Atmel mega16的片子,内置时钟1Mhz

使用特权

评论回复
板凳
qin552011373| | 2013-8-6 15:23 | 只看该作者
定时器还是比较准确的  你的熔丝位怎么配置的

使用特权

评论回复
地板
shgb2003|  楼主 | 2013-8-6 15:38 | 只看该作者
熔丝位配置如下:不过我感觉既然能出现正常1S的延时,熔丝位的配置问题就不大

捕获1.JPG (46.01 KB )

捕获1.JPG

使用特权

评论回复
5
shgb2003|  楼主 | 2013-8-6 15:44 | 只看该作者
我曾经试过,如果把count计数到1000的判断放到中断函数里,问题可以解决。不过写这个程序本来就是为了研究AVR的应用,而写把函数写在中断里也不是好习惯。因此还是想和大家一起探究一下原因的。

使用特权

评论回复
6
netcattle| | 2013-8-6 16:56 | 只看该作者
马克一下,中断函数里改变的变量最好加入volatile 修饰,不过我觉得这应该不是问题所在。

使用特权

评论回复
7
huangxz| | 2013-8-6 17:25 | 只看该作者
你在中断函数里面执行浮点运算

使用特权

评论回复
8
netcattle| | 2013-8-7 15:15 | 只看该作者
huangxz 发表于 2013-8-6 17:25
你在中断函数里面执行浮点运算


我曾经试过,如果把count计数到1000的判断放到中断函数里,问题可以解决。不过写这个程序本来就是为了研究AVR的应用,而写把函数写在中断里也不是好习惯。因此还是想和大家一起探究一下原因的。
这是为什么,这和浮点运算也有关系噢?。

使用特权

评论回复
9
huangxz| | 2013-8-7 15:25 | 只看该作者
netcattle 发表于 2013-8-7 15:15
我曾经试过,如果把count计数到1000的判断放到中断函数里,问题可以解决。不过写这个程序本来就是为了研 ...

我觉的你的TCNT0这个值根本计算的不对,还有浮点运算在avr里面是要付出很大代价的,最好不要用。

使用特权

评论回复
10
499734424| | 2013-8-8 09:10 | 只看该作者
浮点运算在avr里面是要付出很大代价,以前还真没注意,学习了

使用特权

评论回复
11
ccbclerk| | 2014-3-29 08:18 | 只看该作者
用ctc方式会准吧。

使用特权

评论回复
12
qin552011373| | 2014-3-29 20:47 | 只看该作者
ccbclerk 发表于 2014-3-29 08:18
用ctc方式会准吧。

主要是浮点运算的问题

使用特权

评论回复
13
wolension| | 2014-4-2 08:42 | 只看该作者
Fosc是宏定义的,这个是在编译阶段计算的吧,不应该在运行时计算。
首先看一下汇编代码,TCNT0的值是否是256-125?
中断用到的变量要加入volatile 修饰。
开定时器中断前最好把TIFR的相应标志位消除。
TIFR |= (1<<TOV0);  //写1清除
TIMSK |= (1<<OCIE0);

使用特权

评论回复
14
yubsh| | 2014-4-2 09:17 | 只看该作者
这要在微机上写C程序没多大问题,单片机的编译器很烂啊,IAR优化好一些也不敢随便用浮点运算,你得精工细琢。

使用特权

评论回复
15
hnjylijunz| | 2015-2-26 23:04 | 只看该作者
中断函数里最好是赋值,不要运算

使用特权

评论回复
16
ccxlslr| | 2015-2-27 10:38 | 只看该作者
本帖最后由 ccxlslr 于 2015-2-27 10:40 编辑
499734424 发表于 2013-8-8 09:10
浮点运算在avr里面是要付出很大代价,以前还真没注意,学习了


有一定道理,但是,那是在有变量的情况下。 只要不是傻子做的编译器, 你几个常量进行计算,都会在编译时已经算好。所以有时候为了可读性,完全可以用常量进行计算,丝毫不会影响单片机的速度。 就如同你算TCNT0一样,完全可以像你那样。不会有影响。而且可读性好。

使用特权

评论回复
17
ZALIN| | 2015-3-3 12:43 | 只看该作者
因为变量‘count’是unsigned int类型,但是在执行while(count)语句时无法保证对变量‘count’的“原子”访问,
所以有可能被中断函数打断,会出现错误的结果

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

11

帖子

0

粉丝