单片机
返回首页

基于msp430G2553的低频方波频率、占空比、峰峰值测量函数

2020-02-12 来源:eefocus

使用的平台是TI公司的launch pad,频率和占空比已经实现,峰峰值还有有待改进


1、主函数部分:

/*********************************************

*                   _ooOoo_                   *

*                  o8888888o                  *

*                  88' . '88                  *

*                  (| -_- |)                  *

*                  O  =  /O                  *

*               ____/`---'____               *

*             .'  \|     |//  `.             *

*            /  \|||  :  |||//              *

*           /  _||||| -:- |||||-             *

*           |   | \  -  /// |   |           *

*           | _|  ''---/''  |   |           *

*             .-__  `-`  ___/-. /           *

*         ___`. .'  /--.--  `. . __          *

*      .'' '<  `.____<|>_/___.'  >'''.       *

*     | | :  `- `.;` _ /`;.`/ - ` : | |     *

*       `-.   _ __ /__ _/   .-` /  /     *

*======`-.____`-.________/___.-`____.-'======*

*                   `=---='                   *

*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*

*                No bug forever               *

*********************************************/



/*

 *  Author: 余裕鑫

 *  function:测量信号的频率和占空比,信号输入管脚为P2.1.串口打印输出信息。

 *          串口:9600,无校验位,8位数据位,1位停止位

 *  Created on: 2018年5月2日

 *注意:测频率和占空比采用分别是测量一个周期和高电平期间的时钟个数,故适合于低频部分的频率和占空比的测量

 *     当频率高于100Hz时,误差逐渐增大,

 *     100Hz时,误差约为1%,1Hz

 *     1000Hz时,误差约为1.5%,15Hz

 *     10000Hz时,误差约为0.37%,37Hz

 *     20000Hz时,误差约为2%,199Hz

 *     30000Hz时,误差约为6.5%,650Hz

 */

#include

#include 'stdio.h'

#include 'pwminput.h'

#include 'uart.h'

#include 'datatype.h'



extern volatile u16 Frequency;

extern volatile u8 Duty;

extern volatile u16 PeakValue;

float PeakValueF;

/**

 * main.c

 */

void main(void)

{

    unsigned char str[20];





    WDTCTL = WDTPW + WDTHOLD;   // stop watchdog timer

    // 将MCLK 和 SMCLK 设置为16MHZ,ACLK默认为32.768KHz

    DCOCTL = CALDCO_16MHZ;

    BCSCTL1 = CALBC1_16MHZ;  //使用高频时钟而减小误差

    _EINT();



    UART_Init();



    sprintf(str,'frequency and duty:n');

    UARTSendString(str);



    while(1)

    {

        Measure_Frequency_Duty();

        sprintf(str,'Frequency : %d n',Frequency);

        UARTSendString(str);

        sprintf(str,'Duty : %d n',Duty);

        UARTSendString(str);



//        Measure_Peak_Value();

//        PeakValueF = PeakValue*3.6/1024;

//        sprintf(str,'Peak Value : %0.2f n',PeakValueF);

//        UARTSendString(str);

        __delay_cycles(50000000);

    }

}

2、C文件部分:

/*

 * pwminput.c

 *

 *  Created on: 2018年4月23日

 *  Author: yyx

 */

#include 'pwminput.h'

#include 'adc.h'



#define T0C1A  P1DIR&=~BIT2;P1SEL|=BIT2;P1SEL2&=~BIT2

#define T1C0A  P2DIR&=~BIT0;P2SEL|=BIT0;P2SEL2&=~BIT0

#define T1C1A  P2DIR&=~BIT1;P2SEL|=BIT1;P2SEL2&=~BIT1

#define SAMPLETIMES  10  //测峰峰值中一个周期采样的次数

#define SAMPLEPERIODS 5   //测一次峰峰值中采样的周期个数



u8 FreqFlag = 0;

u16 PwmStart;//初始时间

u16 PwmHighEnd,PwmLowEnd;//高电平和低电平的结束时间

u16 HighOverFlow,AllOverFlow; //高电平和一个周期的翻转个数

u32 HighClockSteps,AllClockSteps;

u16 PeakIntervalSteps;



volatile u16 Frequency;

volatile u8 Duty;

volatile u16 PeakValue;

extern volatile u16 ADC10_Result;

u8 SampleStatus;



//频率占空比测量函数

void Measure_Frequency_Duty(void)

{

    T1C1A;       //管脚配置p2.1

    FreqFlag=1;  //频率测量中断标志



    TA1CCTL1 = CAP+CM_1+CCIS_0+SCS+CCIE;              // 输入捕捉,上升沿触发(upCM_1,downCM_2,updownCM_3),同步捕捉,CCI0A 中断使能

    TA1CTL = TASSEL_2 + MC_2 + TAIE + TACLR;          // 选择SMCLK为时钟,连续计数模式 ,溢出中断使能

    while(FreqFlag);

    if(PwmHighEnd>PwmStart)

    {

        HighClockSteps=(HighOverFlow-1)*65536+PwmHighEnd-PwmStart;

    }else

    {

        HighClockSteps=(HighOverFlow-1)*65536+PwmHighEnd+65536-PwmStart;

    }

    if(PwmLowEnd>PwmStart)

    {

        AllClockSteps=(AllOverFlow-1)*65536+PwmLowEnd-PwmStart;

    }else

    {

        AllClockSteps=(AllOverFlow-1)*65536+PwmLowEnd+65536-PwmStart;

    }

    if(AllClockSteps)

    {

        PeakIntervalSteps = (u16)AllClockSteps/SAMPLETIMES; //测峰峰值中以10倍频率进行采样

    }

    Frequency = 16000000/AllClockSteps;

    Duty = HighClockSteps*100.0/AllClockSteps;

}

/*

 * 功能:测P1.3管脚信号的峰峰值

 * */

void Measure_Peak_Value(void)

{

   if(PeakIntervalSteps) //如果采样间隔不为0

   {

       //使用TimerA1的计数模式,

       TA1CTL |= TACLR;  //定时器清零

       TA1CTL |= TASSEL_2+ MC_1+ID_0;  //SMCLK(16MHz),1分频,上数模式

       //定时器开始计数从0到CCR0

       TA1CCR0 = PeakIntervalSteps;     //十分之一个周期中断一次

       TA1CCTL0=CCIE;    //使能中断

       ADC10_Init(3);    // 初始化ADC

       SampleStatus = SAMPLEPERIODS;

       while(SampleStatus);



   }

}

#pragma vector = TIMER1_A0_VECTOR

__interrupt void TimerA1_ISR(void)

{

    _DINT();

    static u16 PeriodValue[2*SAMPLETIMES],MaxValue[SAMPLEPERIODS+1],MinValue[SAMPLEPERIODS+1];

    u32 MaxSum,MinSum;

    static u8 i;

    u8 j;

    if(SampleStatus)

    {

        if(i<2*SAMPLETIMES)

       {

           ADC10_Start_Convey();

           PeriodValue[i++] = ADC10_Result;

       }

       if(i==2*SAMPLETIMES)

       {

           i=0;

           MaxValue[SampleStatus]=MinValue[SampleStatus]=PeriodValue[0];//初始化最值

           for(j=0;j<2*SAMPLETIMES;j++)

           {

               if(PeriodValue[j]>MaxValue[SampleStatus])MaxValue[SampleStatus]=PeriodValue[j];

               if(PeriodValue[j]           }

           SampleStatus--;  //测量的周期次数减1

           if(SampleStatus==0)//如果采样完成

           {

               for(j=1;j<=SAMPLEPERIODS;j++)

               {

                   MaxSum+=MaxValue[j];

                   MinSum+=MinValue[j];

               }

               PeakValue=(u16)(MaxSum-MinSum)/SAMPLEPERIODS;

               MaxSum=MinSum=0;

           }

       }

    }

    _EINT();

}

#pragma vector = TIMER1_A1_VECTOR

__interrupt void TimerA1_Capture_ISR(void)

{

    _DINT(); //关闭中断,

    switch(TA1IV)//向量查询

    {

        case 2: //捕获中断,CCR1

            if(FreqFlag)

            {

                static u8 index;

                if((TA1CCTL1&CM0)&&(index==0)) //第一次上升沿

                {

                    TA1CCTL1|=CM_2;//更变为下降沿触发

                    PwmStart=TA1R;//记录初始时间

                    HighOverFlow = AllOverFlow = 0;    //溢出计数变量复位

                    PwmHighEnd=PwmLowEnd=0;

                    index=(index+1)%3;

                }

                else if((TA1CCTL1&CM1)&&(index==1))//下降沿

                {

                    TA1CCTL1|=CM_1;//更改设置为上升沿触发

                    HighOverFlow = AllOverFlow;

                    PwmHighEnd = TA1R; //记录高电平结束时间

                    index=(index+1)%3;

                }else if((TA1CCTL1&CM0)&&(index==2)) //第二次上升沿

                {

                    //测完一个周期,等待下一个上升沿

                    PwmLowEnd = TA1R;

                    FreqFlag = 0;

                    index=(index+1)%3;

                }

            }



        break;

        case 4:break;//CCR2

        case 10:

        {

            if(FreqFlag)

            {

                AllOverFlow++;

                TA1CTL &= ~TAIFG;

            }

            break;

        }

        default: break;

    }

    _EINT();  //打开中断

}





3、头文件部分:

/*

 * pwminput.h

 *

 *  Created on: 2018年4月23日

 *      Author: yyx

 */



#ifndef PWMINPUT_H_

#define PWMINPUT_H_





#include 

#include 'datatype.h'



void Measure_Frequency_Duty(void);

void Measure_Peak_Value(void);



#endif /* SRC_PWMINPUT_H_ */

4、其中涉及的相关辅助型文件

①、ADC

/*  * adc.c  *  *  Created on: 2018年5月2日  *      Author: yyx  */ #include 'adc.h' volatile u16 ADC10_Result; /**  * 功能:ADC10初始化函数  * 参数:  * pin:选择模拟输入的管脚,取值为0-7,对应P1.0到P1.7  * */ void ADC10_Init(u8 pin) {     ADC10CTL0 |= ADC10SHT_2 + ADC10ON;  //打开ADC10,并设置为16个ADC时钟     ADC10CTL0 |=  ADC10IE;     ADC10CTL1 |= ADC10SSEL_3;     switch(pin)     {     case 3:         ADC10CTL1 |= INCH_3;         ADC10AE0 |= BIT3;         P1DIR &= ~BIT3;         break;      default:break;     } } /*  * adc.h  *  *  Created on: 2018年5月2日  *      Author: yyx  */ #ifndef SRC_ADC_H_ #define SRC_ADC_H_ #include 'msp430g2553.h' #include 'datatype.h' void ADC10_Init(u8 pin); void ADC10_Start_Convey(void); #endif /* ADC_H_ */ void ADC10_Start_Convey(void) {     ADC10CTL0 |=ENC + ADC10SC; //开始转换 } #pragma vector = ADC10_VECTOR __interrupt void ADC10_ISR(void) {     _DINT(); //关总中断     ADC10_Result = ADC10MEM;     ADC10CTL0 &= ~ADC10SC; //结束转换     _EINT(); //开总中断 }


②、uart


/*

 * uart.c

 *

 *  Created on: 2018年4月22日

 *      Author: yyx

 */

#include 'uart.h'



void UART_Init()

{

    P1SEL |= BIT1 + BIT2;

    P1SEL2 |= BIT1 + BIT2;  //将p1.1和p1.2选为UART模式

    P1DIR &= ~BIT1;

    P1DIR |= BIT2;





    UCA0CTL1 |= UCSSEL_2;   //SMCLK

    UCA0BR1 = 1666/256;         //高8位

    UCA0BR0 = 1666%256;

    UCA0MCTL |= UCBRS_6 + UCBRF_0; //设置波特率为9600

    UCA0CTL1 &= ~UCSWRST;          //开始运行

   // IE2 |= UCA0RXIE+UCA0TXIE;      //使能中断

}

/********************************************************************

 *

*******************************************************************/



void UARTSendChar(char ch)

{

    if(ch == 'n')

    {

        while(UCA0STAT & UCBUSY);

        UCA0TXBUF = 'r';

    }

    while(UCA0STAT & UCBUSY);

          UCA0TXBUF = ch;

}



/********************************************************************

 *

 *******************************************************************/



void UARTSendString(char *pt)

{

     UART_Init();

     while(UCA0STAT & UCBUSY);

     while(*pt)

     {

        UARTSendChar(*pt++);

     }



}



/*

 * uart.h

 *

 *  Created on: 2018年4月22日

 *      Author: yyx

 */



#ifndef SRC_UART_H_

#define SRC_UART_H_



#include 



void UART_Init(void);

void UARTSendChar(char ch);

void UARTSendString(char *pt);



#endif /* SRC_UART_H_ */


③、数据类型的重定义


/*

 * datatype.h

 *

 *  Created on: 2018年5月1日

 *      Author: yyx

 */


#ifndef SRC_DATATYPE_H_

#define SRC_DATATYPE_H_


typedef unsigned char u8;

typedef unsigned int u16;

typedef unsigned long u32;


#endif /* DATATYPE_H_ */

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • PIC单片机控制的遥控防盗报警器电路

  • 用数字电路CD4069制作的万能遥控轻触开关

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 开关电源的基本组成及工作原理

  • 如何构建一个触摸传感器电路

  • 基于ICL296的大电流开关稳压器电源电路

    相关电子头条文章