求助用atmega88采用外部中断测量频率同时pwm输出时,频率测不准的问题
最近在做一个用外部中断测量频率同时pwm输出的实验时发现了频率老是测量不准确测量频率是用定时器2计时得到频率两个上升沿的时间,pwm采用快速pwm模式
不输出pwm或者将pwm的计数上限值设置为0xffff,频率就准确了
但是pwm计数上限值只要不是最大值0xffff,无论pwm设置成8、9、0位快速pwm模式还是用OCR1A或ICR1记录计数上限值,频率都测不准确,实在不知道是问题出在哪里,恳请大家帮忙分析一下,先谢谢大家
PS:之前通过ICP捕捉测量频率,也有这个问题
下面是源程序
main.c源程序
#include <iom88v.h>
#include <macros.h>
#include "main.h"
#include "serial_ports_drive.c"
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1= 0x0000;
TCCR1A = 0x32;//10位快速PWM模式
ICR1=0xffff;
OCR1B=0;
TCCR1B = 0x19; //start Timer
}
void timer2_init(void)
{
TCCR2B = 0x00; //stop
TCNT2= 0x00;
TCCR2A = 0x00;
}
#pragma interrupt_handler int0_isr:2
void int0_isr(void)
{
if(Pulse_flag==0)
{
TCCR2B = 0x02; //start Timer
Pulse_flag=1;
}
else
{
TCCR2B = 0x00;//停止定时器
Cycle=((((unsigned long)flow_flag)<<8)+TCNT2);
/*
USART_Transmit_str("Freque_value:");
USART_Transmit_num( Freque_value );
USART_Transmit_str(" flow_flag:");
USART_Transmit_num( flow_flag );
USART_Transmit_str("TCNT2:");
USART_Transmit_num( TCNT2 );
USART_Transmit_str("\r\n");
*/
flow_flag=0;
TCNT2= 0x00;
Pulse_flag=0;
}
}
#pragma interrupt_handler timer2_ovf_isr:10
void timer2_ovf_isr(void)
{
flow_flag ++ ;
}
void port_init(void)
{
PORTB = 0b00000001;
DDRB= 0b00000100;
PORTC = 0b00000000; //m103 output only
DDRC= 0b11111111;
PORTD = 0b00000000;
DDRD= 0b00000000;
}
void init_devices(void)
{
CLI();
port_init();
timer2_init();
timer1_init();
MCUCR = 0x00;
EICRA = 0x03; //上升沿触发中断
EIMSK = 0x01;
TIMSK0 = 0x00; //timer 0 interrupt sources
TIMSK1 = 0x00; //timer 1 interrupt sources
TIMSK2 = 0x01; //timer 2 interrupt sources
PCMSK0 = 0x00; //pin change mask 0
PCMSK1 = 0x00; //pin change mask 1
PCMSK2 = 0x00; //pin change mask 2
PCICR = 0x00; //pin change enable
PRR = 0x00; //power controller
SEI();
}
void main(void)
{
usart_init();
init_devices();
USART_Transmit_str("HaHa,Baud Rate is 19200,OK!\r\n");
while(1)
{
Freque_value=((unsigned long)1000000/Cycle); //频率
OCR1B=Freque_value;
USART_Transmit_str("Freque_value:");
USART_Transmit_num( Freque_value );
USART_Transmit_str("\r\n");//*/
}
}
main.h源程序:
unsigned int flow_flag=0; // 用于标记 定时器溢出
unsigned long Cycle,Freque_value;//周期(单位um)
unsigned char Pulse_flag=0;//脉冲标志位
serial_ports_drive.c源程序:
//串口通信初始化(波特率9600,当系统频率为8M时)
void usart_init(void)
{
UCSR0A = 0x02; //使用波特率倍增,不使用多从机模式
UCSR0C = 0x06; //异步串口模式,禁止奇偶校验,1位停止位,8-bit桢模式
UBRR0L = 0x33; //设置波特率,19200(有一定误差)
UBRR0H = 0x00;
UCSR0B = 0x08; //禁止完成中断,禁止发送完成中断,禁止发送寄存器空中断,禁止接收,允许发送
}
//向串口发送一个字节的数据
void USART_Transmit( unsigned char data )
{
while(!(UCSR0A&(1<<UDRE0)));// 等待发送缓冲器为空
UDR0 = data;// 将数据放入缓冲器,发送数据
}
//向串口发送字符串
void USART_Transmit_str( unsigned char *str )
{
while (1)
{
if(*str == '\0')break;
USART_Transmit(*str++);
}
}
//向串口发送ASCII码数字
void USART_Transmit_num( unsigned int data )
{
USART_Transmit(data/10000+48);
USART_Transmit((data%10000)/1000+48);
USART_Transmit((data%1000)/100+48);
USART_Transmit((data%100)/10+48);
USART_Transmit(data%10+48);
}
源程序和proteus仿真ourdev_492175.rar(文件大小:56K) (原文件名:1.rar) 现在又发现,计数上限值就算是设置成0xffff,频率也不是完全准确,还是有不准确的数据,只是出现的概率好像小了点,而且低频时数据不准确的概率大,实在是不知道问题出在哪里,大家有遇到过这样的情况的吗? 再补充一下,频率不准出现的错误数值大约是正确频率的两倍左右,而且错误的数据好像还特别有周期性,而不是随机的,下面是proteus仿真中串口监控的测出的频率值
http://cache.amobbs.com/bbs_upload782111/files_20/ourdev_493379.jpg
(原文件名:1.jpg)
继续在线等大侠解答 不用函数信号发生器产生信号而用DCLOCK产生信号就准确了,真奇怪,难道函数信号发生器和AVR的PWM同时仿真时有冲突??不用PWM时信号发生器很好用,不去管他了,不是程序的事就好,呵呵,纠结了四天的问题终于解决了(好像也没有解决什么,哈哈)! mark 把单片机的 CCP1 模块设置为捕捉模式,先把CCP1设置为捕捉脉冲的上升沿。当脉冲信号上升沿到来时。触发 CCP 中断,并在中断服务程序中记录下此时 TMR1 寄存器中 16位的值T1 :然后把 CCP1 模块设置成捕捉脉冲下降沿,当脉冲信号下降沿到来时,再次触发 CCP中断。并在中断服务程序中记录下此时TMR1 寄存器中 16 位的值 T2 ;最后把 CCP1模块设置成捕捉脉冲上升沿,当脉冲信号上升沿到来时,触发 CCP中断,并在中断服务程序中记录下此时 TMR1 寄存器中 16 位的值T3 ,这样就完成了 PWM信号一个周期的测量。 mark一下,希望审核早日通过
页:
[1]