|
最近在做一个用外部中断测量频率同时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) |
阿莫论坛20周年了!感谢大家的支持与爱护!!
知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)
|