Crystalline 发表于 2025-1-9 14:57:46

PWM输入捕获请教

STC8单片机的PWM输入捕获的原理是这样吗:
CNT的计数频率和时钟源频率是一样的(不分频的情况下),检测到上升沿或者下降沿就把CNT的值装载到CCR里面,然后保存CCR的值,用时钟频率÷新的CCR减去旧的CCR再就是信号频率

DebugLab 发表于 2025-1-9 15:11:34

void PWMA_Isr(void) interrupt PWMA_VECTOR
{
        if(PWMA_SR1&0x02)
        {
                PWMA_SR1&=~0x02;
                Cap=Cap;
                Cap=(PWMA_CCR1H<<8)|PWMA_CCR1L;
                Cap=Cap-Cap;
                Flag=1;
        }
}https://www.stcaimcu.com/forum.php?mod=redirect&goto=findpost&ptid=12187&pid=124999


CCR的差乘以时钟频率的倒数是信号的周期,周期的倒数是频率

Crystalline 发表于 2025-1-9 15:29:42

DebugLab 发表于 2025-1-9 15:11
https://www.stcaimcu.com/forum.php?mod=redirect&goto=findpost&ptid=12187&pid=124999




为什么我测低频他一直跳

DebugLab 发表于 2025-1-9 17:00:33

Crystalline 发表于 2025-1-9 15:29
为什么我测低频他一直跳

发原理图和程序

Crystalline 发表于 2025-1-10 11:50:56

DebugLab 发表于 2025-1-9 17:00
发原理图和程序

#include <STC8H.H>
#include <Seg.h>
uchar Seg_Buf[] = {10,10,10};
uchar pos = 0;
uint Seg_Slow_Down = 0;
uint Time_1000ms = 0;
uint Freq = 0;
uchar Time1ms = 0;
uchar led_light = 2;
uchar take_time = 0;   //保存进入中断的次数

#define FILTER_SIZE 10
int filter_buffer;// 存储最新的10个频率值
int filter_index = 0;            // 用于指示当前存储位置
int filtered_freq = 0;         // 存储滤波后的频率值

typedef struct {
        int cap;
        int cap_new;
        int cap_old;
}Freq_Type;
Freq_Type Freq1;
Freq_Type Freq2;
Freq_Type Freq3;

void Timer1_Isr(void) interrupt 3
{
        if(++Seg_Slow_Down == 2000) Seg_Slow_Down = 0;
        if(++Time1ms == 10){
                Time1ms = 0;
                if(++pos ==3) pos = 0;
        }
        if(Time1ms <= led_light)//亮
        {
                Seg_Disp(pos,Seg_Buf);
        }
        else
                Seg_Disp(pos,10);//灭
}

void Timer1_Init(void)                //100微秒@12.000MHz
{
        AUXR &= 0xBF;                        //定时器时钟12T模式
        TMOD &= 0x0F;                        //设置定时器模式
        TL1 = 0x9C;                                //设置定时初始值
        TH1 = 0xFF;                                //设置定时初始值
        TF1 = 0;                                //清除TF1标志
        TR1 = 1;                                //定时器1开始计时
        ET1 = 1;                                //使能定时器1中断
}

void System_Init()
{
        P_SW2 |= 0x80; //扩展外部XFR
        PWMB_PS = 0x54; //01 01 01 00 选用P54\P33\P34作为输入捕获引脚
        PWMB_PSCRH = 0x2E; //预分频寄存器
        PWMB_PSCRL = 0xDF;
        /*必须先关闭CCER才能设置CC1*/
        PWMB_CCER1 = 0x00;PWMB_CCER2 = 0x00 ;
        PWMB_CCMR2 = 0x01;PWMB_CCMR3 = 0x01;        PWMB_CCMR4 = 0x01;                     //通道6、7、8设为输入
        //PWMB_CCMR2 |= 0xC0; PWMB_CCMR3 |= 0xC0; PWMB_CCMR4 |= 0xC0;//8个事件触发一次
        PWMB_CCER1 = 0x10; PWMB_CCER2 = 0x11; //使能通道6、7、8

        PWMB_IER = 0x1C;
        PWMB_CR1 |= 0x01; //使能计数器
        IP |= 0x0f; //拉低定时器1的优先级

        P1M0 = 0xff; P1M1 = 0x00;
        P5M0 = 0x00; P5M1 = 0x00;
P3M0 = 0xe0; P3M1 = 0x00;
       
        Timer1_Init();

        EA = 1;
}
void Seg_Proc()
{
        if(Seg_Slow_Down) return;
        Seg_Slow_Down = 1;
        //Freq = Freq1.cap + Freq2.cap + Freq3.cap;
//        if(Freq <= 999){
//                Seg_Buf = (Freq/100)?Freq/100:10;
//                Seg_Buf = (Freq/10)?Freq/10%10:10;
//                Seg_Buf = Freq%10;       
//        }
//        else
//                Seg_Buf = Seg_Buf = Seg_Buf = 9;
       
        filtered_freq = 1000 / filtered_freq;
Seg_Buf = (filtered_freq/100)?filtered_freq/100:10;
        Seg_Buf = (filtered_freq/10)?filtered_freq/10%10:10;
        Seg_Buf = filtered_freq%10;       
       
}
void main()
{
        System_Init();
        while(1)
        {
                Seg_Proc();
        }
}

void PWMB_ISR() interrupt 27
{
        long sum;
        uchar i;
        if(PWMB_SR1 & 0x04) //是CC6的中断
        {
                Freq1.cap_old = Freq1.cap_new;
                Freq1.cap_new = PWMB_CCR6;
                Freq1.cap = Freq1.cap_new - Freq1.cap_old;       
               
                filter_buffer = (Freq1.cap >= 0) ? Freq1.cap : -Freq1.cap;
                filter_index = (filter_index + 1) % FILTER_SIZE;
                for(i = 0;i<FILTER_SIZE;i++)
                        sum += filter_buffer;
                filtered_freq = sum / FILTER_SIZE;
               
                PWMB_SR1 &= ~0x04;
               
        }
//        if(PWMB_SR1 & 0x08) //是CC7的中断
//        {
//                Freq2.cap_old = Freq2.cap_new;
//                Freq2.cap_new = PWMB_CCR7;
//                Freq2.cap = Freq2.cap_new - Freq2.cap_old;
//                PWMB_SR1 &= ~0x08;               
//        }
//        if(PWMB_SR1 & 0x10) //是CC8的中断
//        {
//                Freq3.cap_old = Freq3.cap_new;
//                Freq3.cap_new = PWMB_CCR8;
//                Freq3.cap = Freq3.cap_new - Freq3.cap_old;
//                PWMB_SR1 &= ~0x10;               
//        }
}

DebugLab 发表于 2025-1-10 12:50:57

Crystalline 发表于 2025-1-10 11:50


被测信号频率范围是多少
被测信号周期不能大于PWM计数器溢出时间,溢出前后被测信号处于同一个周期,结果就会乱跳

梁工 发表于 2025-1-10 14:23:58

Crystalline 发表于 2025-1-9 15:29
为什么我测低频他一直跳

被测信号频率多少?是否稳定?可以使用晶振做时钟发出频率来测试。

Crystalline 发表于 2025-1-10 14:42:24

梁工 发表于 2025-1-10 14:23
被测信号频率多少?是否稳定?可以使用晶振做时钟发出频率来测试。

这样的

Crystalline 发表于 2025-1-10 14:48:23

我还有个疑问就是PWMB_CNTR和PWMB_CCR1不是16位的吗为什么要用int类型?int类型不是-32768-32767吗,要是计数值达到了32767以上,那这里面的捕获值不是有问题了吗

梁工 发表于 2025-1-10 16:56:37

Crystalline 发表于 2025-1-10 14:48
我还有个疑问就是PWMB_CNTR和PWMB_CCR1不是16位的吗为什么要用int类型?int类型不是-32768-32767吗,要是计 ...
应该用unsigned int型,已通知修改手册。
页: [1] 2
查看完整版本: PWM输入捕获请教