参考文章: PIC单片机捕捉模块的设计思路-EDA365
#include <ny8.h>
#include "ny8_constant.h"
#define UPDATE_REG(x) __asm__("MOVR _" #x ",F")
#define C_TIMER_VALUE 0xFFFF
unsigned char R_COUNT;
unsigned char signal_period;
unsigned char signal_width;
// unsigned int signal_duty;
// unsigned int signal_freq;
// 存储定时器值
unsigned char H1;
unsigned char L1;
unsigned char H2;
unsigned char L2;
unsigned char H3;
unsigned char L3;
unsigned char H4;
unsigned char L4;
unsigned char time_array[5];
unsigned char time_index;
void main(void)
{
DISI();
// Initialize GPIO
IOSTB = C_PB2_Input; // Set PB2 as input pin
PORTB = 0xFF; // PortB Data Register = 0xFF
BPHCONbits.PHPB2 = 0; // Set PB2 with Pull-High
// Step1: Set Timer5 operating mode
T5CR1 = C_TMR5_Reload;
// Step2: Set Timer4 clock source, prescaler
T4CR2 = C_PS4_Dis;
// Step3: Set 16-bit-timer reload value
TMR4 = C_TIMER_VALUE&0x00FF;
TMR5 = (C_TIMER_VALUE&0xFF00)>>8;
// Step4: Set capture mode
CCPCON = C_CCP_Capt_RiseEdge;
R_COUNT = 0;
INTE3 = C_INT_CCP; // Enable CCP interrupt
INTF3 = 0; // Clear CCP interrupt
ENI();
time_index = 0;
signal_period = 0;
signal_width = 0;
// signal_duty = 0;
// signal_freq = 0;
// 存储定时器值
H1 = 0; L1 = 0; H2 = 0; L2 = 0; H3 = 0; L3 = 0; H4 = 0; L4 = 0;
while(1)
{
CLRWDT(); // Clear WatchDog
}
}
void isr(void) __interrupt(0)
{
if(INTF3)
{
if(R_COUNT == 0) // 第一次上升沿
{
H1 = PWM5DUTY;
L1 = PWM4DUTY;
R_COUNT = 1;
}
else if(R_COUNT == 1) // 第二次上升沿
{
H2 = PWM5DUTY;
L2 = PWM4DUTY;
R_COUNT = 2;
}
else if(R_COUNT == 2) // 第三次上升沿
{
H3 = PWM5DUTY;
L3 = PWM4DUTY;
CCPCON = C_CCP_Capt_FallEdge; // CCP模式改为下降沿触发
R_COUNT = 3;
}
else if(R_COUNT == 3) // 第四次下降沿
{
H4 = PWM5DUTY;
L4 = PWM4DUTY;
unsigned int time1 = (0xFF - H1) * 0x100 + 0xFF - L1;
unsigned int time2 = (0xFF - H2) * 0x100 + 0xFF - L2;
unsigned int time3 = (0xFF - H3) * 0x100 + 0xFF - L3;
unsigned int time4 = (0xFF - H4) * 0x100 + 0xFF - L4;
if(time4 > time3 && time3 > time2 && time2 > time1) // 略过定时器下溢
{
signal_period = (time3 - time1) / 2;
signal_width = time4 - time3;
if(signal_width > signal_period) // 切换下降沿,可能会多出1个周期才读到下降沿,需要减去
{
if(signal_width > signal_period + signal_period / 100)
signal_width -= signal_period;
else
signal_width = signal_period;
}
time_array[time_index++] = signal_width;
// 筛掉异常的数值,取平均值
if(time_index == 5)
{
unsigned char pwm_num = 0;
unsigned char avg = (time_array[0] + time_array[1] + time_array[2] + time_array[3] + time_array[4]) / 5;
for(char i = 0; i < 5; i++)
{
if(time_array[i] < (avg + avg / 10) && time_array[i] > (avg - avg / 10))
{
if(pwm_num == 0)
pwm_num = time_array[i];
else
pwm_num = (pwm_num + time_array[i]) / 2;
}
}
signal_width = pwm_num;
time_index = 0;
}
/*
signal_freq = 1 / signal_period;
signal_duty = signal_width / signal_period;
*/
}
CCPCON = C_CCP_Capt_RiseEdge; // 恢复上升沿触发
R_COUNT = 0;
ccp_heart = 100;
}
INTF3 = 0; // Clear CCP interrupt
}
}