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

[复制链接]
4607|16
 楼主| shgb2003 发表于 2013-8-6 11:55 | 显示全部楼层 |阅读模式
写了个最简单的定时器 延时函数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的延时,熔丝位的配置问题就不大

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| shgb2003 发表于 2013-8-6 15:44 | 显示全部楼层
我曾经试过,如果把count计数到1000的判断放到中断函数里,问题可以解决。不过写这个程序本来就是为了研究AVR的应用,而写把函数写在中断里也不是好习惯。因此还是想和大家一起探究一下原因的。
netcattle 发表于 2013-8-6 16:56 | 显示全部楼层
马克一下,中断函数里改变的变量最好加入volatile 修饰,不过我觉得这应该不是问题所在。
huangxz 发表于 2013-8-6 17:25 | 显示全部楼层
你在中断函数里面执行浮点运算
netcattle 发表于 2013-8-7 15:15 | 显示全部楼层
huangxz 发表于 2013-8-6 17:25
你在中断函数里面执行浮点运算


我曾经试过,如果把count计数到1000的判断放到中断函数里,问题可以解决。不过写这个程序本来就是为了研究AVR的应用,而写把函数写在中断里也不是好习惯。因此还是想和大家一起探究一下原因的。
这是为什么,这和浮点运算也有关系噢?。
huangxz 发表于 2013-8-7 15:25 | 显示全部楼层
netcattle 发表于 2013-8-7 15:15
我曾经试过,如果把count计数到1000的判断放到中断函数里,问题可以解决。不过写这个程序本来就是为了研 ...

我觉的你的TCNT0这个值根本计算的不对,还有浮点运算在avr里面是要付出很大代价的,最好不要用。
499734424 发表于 2013-8-8 09:10 | 显示全部楼层
浮点运算在avr里面是要付出很大代价,以前还真没注意,学习了
ccbclerk 发表于 2014-3-29 08:18 | 显示全部楼层
用ctc方式会准吧。
qin552011373 发表于 2014-3-29 20:47 | 显示全部楼层
ccbclerk 发表于 2014-3-29 08:18
用ctc方式会准吧。

主要是浮点运算的问题
wolension 发表于 2014-4-2 08:42 | 显示全部楼层
Fosc是宏定义的,这个是在编译阶段计算的吧,不应该在运行时计算。
首先看一下汇编代码,TCNT0的值是否是256-125?
中断用到的变量要加入volatile 修饰。
开定时器中断前最好把TIFR的相应标志位消除。
TIFR |= (1<<TOV0);  //写1清除
TIMSK |= (1<<OCIE0);
yubsh 发表于 2014-4-2 09:17 | 显示全部楼层
这要在微机上写C程序没多大问题,单片机的编译器很烂啊,IAR优化好一些也不敢随便用浮点运算,你得精工细琢。
hnjylijunz 发表于 2015-2-26 23:04 | 显示全部楼层
中断函数里最好是赋值,不要运算
ccxlslr 发表于 2015-2-27 10:38 | 显示全部楼层
本帖最后由 ccxlslr 于 2015-2-27 10:40 编辑
499734424 发表于 2013-8-8 09:10
浮点运算在avr里面是要付出很大代价,以前还真没注意,学习了


有一定道理,但是,那是在有变量的情况下。 只要不是傻子做的编译器, 你几个常量进行计算,都会在编译时已经算好。所以有时候为了可读性,完全可以用常量进行计算,丝毫不会影响单片机的速度。 就如同你算TCNT0一样,完全可以像你那样。不会有影响。而且可读性好。
ZALIN 发表于 2015-3-3 12:43 | 显示全部楼层
因为变量‘count’是unsigned int类型,但是在执行while(count)语句时无法保证对变量‘count’的“原子”访问,
所以有可能被中断函数打断,会出现错误的结果
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

11

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部