打印
[PIC®/AVR®/dsPIC®产品]

【CuriosityNano测评报告】——捕获和跟随未知PWM信号

[复制链接]
6569|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 mxkw0514 于 2023-10-26 09:18 编辑

#每日话题# #申请原创# #有奖活动# #技术资源# #申请开发板#

引言            
       前段时间收到了Microchip寄来的PIC16F17146拇指开发板,PIC17146是Microchip新推出来的8位单片机型号,该单片机是14位指令宽度,是Microchip的中档8位单片机宽度,其主要特色是内部的op-amp和12位ADCC,可惜本次测评并没有用到这两个特色外设。Microchip的8位单片的更新速度还是挺快的,可以是说每个季度都有新型号的8位单片机产品推出,每款新型号的8位单片机的特色功能不完全重样,这也避免了其与同行打价格战的情形出现。比如最近新推出来的PIC18FxxQ84内部竟然还集成了CAN FD模块,确实不可思议,这使得使用Q84单片机的用户不用再额外购买分立的CAN模块了,既节省成本还节省空间,关键是该芯片的QFN封装还只有5x5mm,当然了,这些也是题外话了,今天主要还是针对PIC16F17146单片机进行测评。

      本次测评的话题是“捕获和跟随未知PWM信号”,需要用到该单片机的CCP、Timer、PWM、I/O外设,主要思路是使用一个PWM模块模拟产生未知PWM信号,然后使用CCP外设捕获未知PWM信号,计算出其频率值和占空比,并加载到另一个PWM外设的寄存器中,使其该PWM模块产生一个一个波形来跟随上述未知PWM信号的波形。测评的步骤为开发环境的搭建、项目设计、项目测试和测评心得,具体测评内容如下所示。

一、开发环境搭建
      自从Micrpchip收购了Atmel公司后,PIC单片机和AVR单片机都能在MPLAB X IDE集成环境中进行开发了,可以按照以下几个步骤搭建开发环境:      
    (1)安装MPLAB X IDE软件、XC8编译器和MCC(MPLAB Code Configurate)代码配置器。MPLAB X IDE软件和XC8编译器可以从microchip.com网站上的TOOLS AND RESOURCES菜单栏下的Develop中下载,MCC代码配置器可以从TOOLS AND RESOURCES菜单栏下的Configure中下载,按照图1、2的步骤操作就可以了,考虑到PIC16F17146是最近推出来的器件,所以我都是下载的最新版本,此外,XC8可以安装好几个版本,在新建工程的时候可以选取XC8的版本,这里顺便提一下,PIC16F后面带5位数的型号都是Microchip比较新的产品。


图1


图2

(2)新建项目工程。新建项目工程主要是工程类型、芯片型号、仿真器型号编码类型的选择,以及工程命名和保存路径,这里要指出的是,如果想要中文注释不出现乱码,应当选择GBK,具体操作步骤如图3、4、5、6、7所示。


图3


图4


图5


图6


图7



    (3)MCC的配置。在配置MCC之前,首先需要查阅数据手册和开发板的硬件原理图等信息,这一部分内容无需再去官网搜寻下载了,因为当开发板插上电脑后,就可以在MPLAB软件的Kit Window中下载,当让如果需要例程程序的话,也可以从里面的Github链接中找到;然后设置配置字(在Resource Management[MCC]中的System里面),这是必须要做的,否则程序可能不能正常运行,并继续配置完System里面的Clock、Interrupt;其次是配置外设资源CCP、Timer、PWM、I/O等,主要是根据数据手册的内容配置里面的寄存器;最后是选择芯片的引脚(在Pin Package View中),这里面可以根据PCB的布线灵活将外设输出到想要的引脚,PIC单片机的PPS外设可以实现引脚的重映射。具体步骤按照图8的序号操作即可。


图8

      接下来谈谈上述(3)中的具体内容:一、说下设置配置字中几个重点(如图9),如果不用外部时钟的话,就将它禁止掉,然后选择内部时钟及其频率,否则原本接外部晶振的那几个引脚不能当作普通IO口使用;禁止低压编程,因为Microchip的下载器基本上使用的是高压编程;不用看门狗的话就将其禁止。二、设置System中的Clock Control(如图10),选择时钟源及其频率、分频,PIC单片机内部的RC振荡器的时钟源可以选择1、2、4、8、16、32MHz,能够通过分频达到想要的System Clock。三、在Interrupt Manager上面设置用到的中断的优先级(如图11),当高优先级的中断发生时,则会先执行高优先级的中断,这个功能在之前老式的PIC16单片机中是没有的。四、设置PWM(图12)、CCP(图13)、Timer(图14)。

图9

图10


图11


图12

图13


图14


二、项目设计
      “捕获和跟随未知PWM信号”项目的硬件框图如图15所示。首先是通过PWM1外设模拟输出一个PWM信号作为被跟随的脉冲1信号,输出引脚设置为RA4,时钟设置为为系统时钟,并设置脉冲1的频率和占空比。然后通过CCP2外设的边沿触发的方式捕获这个信号,在中断里读取不同边沿到来时的时间戳以计算脉冲1的频率和占空比;然后根据计算结果配置PWM2外设输出脉冲2信号的频率和占空比,并同步相位,使脉冲2跟随脉冲1。

图15

      基于此项目绘制的的时序框图如图16所示,首先开启定时器1技术,CCP2模块在捕获未知PWM的边沿后触发中断,并在中断服务函数中连续读取三个边沿到达时的定时器值(锁存到定时器的高八位和低八位),分别将其整合成16位的时间戳,根据数据手册中的相关公式计算此未知PWM波的占空比和频率值,将该值通过形参传输给PWM2模块,控制PWM2模块产生一个信号跟随未知PWM信号,基于此项目绘制的程序流程图如图17所示。

图16

图17

      该项目的程序见附件,项目的主程序如下所示。其中,中断服务函数中读取的是CCPR2H和CCPR2L值,因为在CCP模块捕获到脉冲边沿后,TMR1的值会锁存到CCPR寄存器中(如图18),保证了信号触发后获取时间戳的及时性,其余程序的作用详见注释。
#include "mcc_generated_files/system/system.h"

#define PWM2_Clk_MHz  32
#define Timer1_Period_us  0.125

uint24_t PWM1_PR;
uint24_t PWM1_Duty_Value;//PWM1占空比的传参值

uint16_t CCP2_Capture_High1;//the first capture of rising edge.
uint16_t CCP2_Capture_Low1;
uint16_t CCP2_Capture_High2;//the second capture
uint16_t CCP2_Capture_Low2;
uint16_t CCP2_Capture_High3;//the three capture
uint16_t CCP2_Capture_Low3;

uint8_t CCP2_Capture_Count;//the number of capture

uint16_t Capture_PWM1Value1_Time;//捕获到第一个上升沿,读取到的定时器计数值
uint16_t Capture_PWM1Value2_Time;//捕获到第二个下降沿,读取到的定时器计数值
uint16_t Capture_PWM1Value3_Time;//捕获到第三个上升沿,读取到的定时器计数值

uint24_t Capture_PeriodPWM1_Time;//PWM1周期
uint24_t Capture_DutyPWM1_Time;//PWM1信号高电平的时间

uint24_t Pwm2_Period;//PWM2周期
uint8_t PWM2_Duty;//PWM2占空比
uint16_t PWM2_Duty_Value;//PWM1占空比的传参值
uint16_t PWM2_PR;

uint8_t Print_TimeCount;
uint8_t Capture_Flag;


//PWM1模块信号输出函数, PWM1_Clk_MHz:PWM1时钟源的频率, PWM1_Frequence_KHz:设置PWM1模块输出信号频率
//PWM1_Duty:设置PWM1输出信号占空比
void PWM1_Output(uint8_t PWM1_Clk_MHz, uint8_t PWM1_Frequence_KHz, uint8_t PWM1_Duty)//
{
    PWM1_PR = (uint32_t)PWM1_Clk_MHz  * 1000 / (PWM1_Frequence_KHz ) - 1;
    PWM1_Duty_Value = (uint32_t)(PWM1_PR + 1) * PWM1_Duty  / 100 ;
    PWM1_16BIT_WritePeriodRegister(PWM1_PR);
    PWM1_16BIT_SetSlice1Output1DutyCycleRegister(PWM1_Duty_Value);  
    PWM1CONbits.LD = 1;
}


void Variable_Printf()
{
    if ( PIR0bits.TMR0IF == 1)
    {
       Print_TimeCount++;
       if(Print_TimeCount == 100 )//每隔5秒打印一次
       {
            printf("PWM2_PR=%d\r\n",PWM2_PR );
            printf("PWM2_Duty=%d\r\n",PWM2_Duty );
            printf("Capture_PeriodPWM1_Time=%d\r\n",Capture_PeriodPWM1_Time);
            Print_TimeCount = 0;
       }
    }
}


void DutyandPerridtoPWM2_Math()
{
  
    if (Capture_Flag ==1)
    {
        Capture_PWM1Value1_Time = (uint16_t)(CCP2_Capture_High1<<8) | CCP2_Capture_Low1;//计算上升沿到来时的时间戳
        Capture_PWM1Value2_Time = (uint16_t)(CCP2_Capture_High2<<8) | CCP2_Capture_Low2;//计算下降沿到来时的时间戳
        Capture_PWM1Value3_Time = (uint16_t)(CCP2_Capture_High3<<8) | CCP2_Capture_Low3;//计算第二次上升沿到来时的时间戳
        
        Capture_DutyPWM1_Time = (uint24_t)(Capture_PWM1Value2_Time - Capture_PWM1Value1_Time) * Timer1_Period_us  ; //计算PWM1信号高电平占用的时间
        Capture_PeriodPWM1_Time = (uint24_t)(Capture_PWM1Value3_Time - Capture_PWM1Value1_Time) * Timer1_Period_us ; //计算PWM1信号的周期
        PWM2_Duty = (uint24_t)Capture_DutyPWM1_Time * 100 / Capture_PeriodPWM1_Time;//计算PWM1信号的占空比  
        
        PWM2_Duty = (uint8_t)PWM2_Duty;
        PWM2_PR = (uint24_t)PWM2_Clk_MHz * Capture_PeriodPWM1_Time  - 1;
        PWM2_PR = (uint16_t)PWM2_PR;//0xc7f
        PWM2_Duty_Value = (uint24_t)PWM2_Duty * (PWM2_PR + 1) / 100;
        PWM2_Duty_Value = (uint16_t)PWM2_Duty_Value;//0x640

        PWM2_16BIT_WritePeriodRegister(PWM2_PR);//根据计算结果,设置PWM2的周期
        PWM2_16BIT_SetSlice1Output1DutyCycleRegister(PWM2_Duty_Value);//根据计算结果,设置PWM2的占空比
        
        Variable_Printf();//打印要计算的变量值
               
        Capture_Flag = 0;//清零捕获标志位
    }
}

//每个边沿捕获
void Capture2_PWM1_Edge()
{   
    if (Capture_Flag == 0)//当捕获标志位为0时,开始读取捕获值
    {
      //  CCP2CON = 0x3;//关闭捕获
        if ((IO_RC3_GetValue() == 1) && (CCP2_Capture_Count == 0))
        {
            PWM2CONbits.LD=1;//加载PWM2,相位同步
            CCP2_Capture_Count++;
            CCP2_Capture_High1 = CCPR2H;
            CCP2_Capture_Low1 = CCPR2L;
        }

        else if ((IO_RC3_GetValue() == 0) &&(CCP2_Capture_Count == 1))
        {
            CCP2_Capture_Count++;
            CCP2_Capture_High2 = CCPR2H;
            CCP2_Capture_Low2 = CCPR2L;
        }

        else if ((IO_RC3_GetValue() == 1) &&(CCP2_Capture_Count == 2))
        {
            CCP2_Capture_High3 = CCPR2H;
            CCP2_Capture_Low3 = CCPR2L;
            CCP2_Capture_Count = 0;

            TMR1H = 0;//Timer1 Reset
            TMR1L = 0;
            Capture_Flag = 1;//置位捕获标志位
        }
        
      
        CCP2CON = 0x83;//开启捕获
    }
}

void Capture_PWM1_Init()//变量初始化置零
{
    PWM1_PR = 0;

    CCP2_Capture_High1 = 0;//第1次上升沿捕获后的高8位值
    CCP2_Capture_Low1 = 0;//第1次上升沿捕获后的低8位值
    CCP2_Capture_High2 = 0;//第2次下降沿捕获后的高8位值
    CCP2_Capture_Low2 = 0;//第2次下降沿捕获后的低8位值
    CCP2_Capture_High3 = 0;//第3次上升沿捕获后的高8位值
    CCP2_Capture_Low3 = 0;//第3次下降沿捕获后的高8位值

    CCP2_Capture_Count = 0;//捕获次数的计数器

    Capture_PWM1Value1_Time = 0;//第1次捕获记录的时间戳
    Capture_PWM1Value2_Time = 0;//第2次捕获记录的时间戳
    Capture_PWM1Value3_Time = 0;//第3次捕获记录的时间戳

    Capture_PeriodPWM1_Time = 0;//捕获PWM1信号的周期
    Capture_DutyPWM1_Time = 0;//捕获PWM1信号的占空比

    Pwm2_Period = 0;//PWM2的周期
    PWM2_Duty = 0;//PWM2的占空比
    PWM2_PR = 0;//PWM2的PR值

    Print_TimeCount = 0;//打印时间计数器
}


int main(void)
{
   
    SYSTEM_Initialize();//系统初始化

    INTERRUPT_GlobalInterruptEnable(); //开启全局中断

    INTERRUPT_PeripheralInterruptEnable(); //开启外设中断

    Capture_PWM1_Init();
   
    PWM1_Output(32, 10 ,20);//PWM1时钟源的频率为32MHz, PWM1频率为10KHz,占空比为50%
   
    CCP2_SetCallBack(Capture2_PWM1_Edge);
            
    while(1)
    {
        DutyandPerridtoPWM2_Math();//计算PWM1的周期和占空比,设置PWM2的周期和占空比
    }   
}

图18

三、项目测试      
      将PIC16F17142拇指板插在地板上,使用杜邦线连接好相关引脚(如图19所示),并将拇指板通过USB线与电脑连接,使用示波器的探头分别连接PWM1模块输出引脚和PWM2模块输出引脚,观察未知信号和跟随信号的波形,结果如图20所示(未知信号频率为10KHz,占空比为20%),由该图可以看到,两个信号之间存在一定的相位差,这是软件跟随无法消除的问题,究其原因,PIC单片机进入中断服务函数之前还执行了很多条程序,这就带来了软件延时,如图21所示。


图19



图20

图21

四、测评心得
      在本次项目中,跟随100us周期、20%占空比的PWM信号产生了25us的相位差,虽然软件跟随比硬件跟随的相位差大,但是使用软件跟随的工程中,计算出了占空比和频率,这些参数在实际工程项目中应该也能够用得到。PIC16F17146的数据手册写的非常详细,如果熟悉PIC单片机底层寄存器,那么使用MCC工具辅助工具还是能大大增加编程速度的。通过本次测评以及额外的学习,发现CIPs(Core Independent Peripherals是PIC单片机的一大特色,包括了CLC、OP、AC等不占用CPU的资源,这是非常实用的。其实,在32位单片机飞速发展的今天,8位单片机作为家电主控制器或者复杂领域的协处理器,仍然有着广泛的应用,可以说32位单片机的发展也在带动着8位单片机的发展。   
         
      在此,感谢Microchip提供了测评PIC16F17146单片机的机会,期盼以后能有更多这样的活动。


















PIC16F17126-46-Microcontrollers-Data-Sheet-DS40002343.pdf

8.61 MB

Capture_PWM_17146.X.zip

1.75 MB

使用特权

评论回复
沙发
xixi2017| | 2023-9-28 08:53 | 只看该作者
写的很详细。是不是没写完啊,没看到代码部分呢。

使用特权

评论回复
板凳
mxkw0514|  楼主 | 2023-10-7 11:49 | 只看该作者
xixi2017 发表于 2023-9-28 08:53
写的很详细。是不是没写完啊,没看到代码部分呢。

现在已经写完了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

32

主题

549

帖子

5

粉丝