#include <p33fxxxx.h>
/*
功能说明:本代码将演示利用RD0/OC1输出PWM波形驱动,由RD11/INT4进行高电平时间的测量。
运行环境:外接8M,FOSC 80MHZ,FCY 40MHZ,TCY 25ns
版本说明:V1.1
修改人 :**南 www.PIC591.com
*/
unsigned int ADCVal;
unsigned int HIGHVal; //OC输出的高电平时间,us
unsigned int INTVal; //中断测量结果,us
unsigned int i,j;
unsigned char INTType ; //中断沿类型,含义与INTXEP一致
int main(void)
{
_PLLPRE = 0 ; //N1 = 2
_PLLDIV = 38 ; //M = 38+2 = 40
_PLLPOST = 0 ; //N2 = 2
//FOSC = (8/2) * 40 / 2 = 80M
while(OSCCONbits.LOCK == 0) ; //等待PLL稳定
_DISI = 1 ; //使能DISI指令,部分内建函数需要,建议开启
_TRISB9 = 1 ; //RB9/AN9为输入口
_PCFG9 = 0 ; //RB9/AN9设置为模拟口
/*
根据勘误,只能配置为300KBPS,带A的型号没这些问题
则一次转换至少要3.3us,按采样保持3TAD,转换14TAD算,至少17TAD。
3.3us/17 ~= 200ns,即,TAD至少为8TCY,200ns。
带A的流行后,建议大家换带A的,改下配置位重新编译后,目前看来几乎是全兼容的。
*/
AD1CON1 = 0x04E4 ; //暂不使能AD,12位AD模式,自动采样模式自动转换
AD1CON2 = 0x0000 ; //AVDD,AVSS做看靠,不扫描通道,每次采样完毕中断
AD1CON3 = 0x0307 ; //TAD根据PBCLK为基准,TAD = (7+1)*Tcy = 200ns ,
//TSAMP = 3TAD
//经过以上配置,AD转换时间约为17TAD = 3.4us,略低于300KBPS
AD1CON4 = 0 ; //非DMA模式未用到此寄存器
AD1CHS123 = 0 ; //12BIT模式未用到
AD1CHS0 = 0x0009 ; //设置采样通道为AN9/RB9
AD1CSSL = 0 ; //不扫描轮询,可设置为0
_AD1IF = 0 ; //清中断标志位
_AD1IE = 0 ; //不启用中断
_AD1IP = 0 ; //中断主优先级别设置为0
_ADON = 1 ; //AD使能
//设置OC1/RD1
_TRISD0 = 0 ; //
T2CON = 0x0020 ; //暂不使能T2,1:64分频,内部定时器模式
TMR2 = 0 ; //
PR2 = 12499 ; //PWM周期 = (PR2+1)*64*(1/40)us = 20ms,50HZ
OC1CON = 0X0006 ; //暂不使能模块,选择T2做时钟,16位模式,PWM模式
OC1RS = 0 ; //
OC1R = 0 ; //
//设置INT4/RD11
_TRISD11 = 1 ; //IO置输入
_INT4EP = 0 ; //INT4为上升沿中断,注意,级性定义与PIC32是相反的
_INT4IF = 0 ; //
_INT4IP = 7 ; //中断优先级别为7
_INT4IE = 1 ; //中断使能
INTType = 1 ; //初使化类型必须与INT4EP相反
TMR4 = 0 ; //利用T4+INT4,测量OC1的高电平时间
T4CON = 0X0020 ; //暂不使能T4,1:64分频,内部定时器模式,即1个计数单为1.6us。
T2CONbits.TON = 1 ; //
T4CONbits.TON = 1 ; //
while(1)
{
while(_AD1IF == 0) ; //等待第一次AD转换结果
_AD1IF = 0 ; //
ADCVal = ADC1BUF0 ; //
AD1CON1bits.ASAM = 0 ; //停止AD
if(ADCVal >= 4000) //填入占空比
{
PR2 = 12499 ; //最大周期为20ms
}
else if(ADCVal <= 400) //
{
PR2 = 1249 ; //最小周期为2ms
}
else
{
PR2 = ADCVal * 3 + ADCVal / 8 - 1 ; //
}
OC1RS = (PR2 + 1)/2 ; //占空比固定为一半
HIGHVal = OC1RS ; //记录
for(j = 0 ; j < 10 ; j++ )
{
for(i = 0 ; i < 0xffff; i++ ) ; //延时
}
AD1CON1bits.ASAM = 1 ; //时间到再次启动
}
}
void __attribute__((__interrupt__,no_auto_psv)) _INT4Interrupt(void)
{
_INT4IF = 0 ;
if(_INT4EP == 0) //如本次为上升沿中断
{
if((INTType == 1) && (_RD11 == 1)) //如果上一次中断类型为下降沿
{
TMR4 = 0 ;
}
_INT4EP = 1 ; //下次下降沿进中断
INTType = 0 ; //记录本次中断类型
}
else //本次为下降沿
{
if((_RD11 == 0) && (INTType == 0)) //低电平,且上一次中断类型为高电平
{
INTVal = TMR4 ; //下降沿来,取走高电平值,随后在低电平期间就让TMR4其自由计数,
}
_INT4EP = 0 ; //下次上升沿进中断
INTType = 1 ; //记录本次中断类型
}
}
|