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

Posted 芯青年0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于msp430G2553的低频方波频率占空比峰峰值测量函数相关的知识,希望对你有一定的参考价值。

使用的平台是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 <msp430g2553.h>
#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]<MinValue[SampleStatus])MinValue[SampleStatus]=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  <msp430g2553.h>
#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  <msp430g2553.h>


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_ */


以上是关于基于msp430G2553的低频方波频率占空比峰峰值测量函数的主要内容,如果未能解决你的问题,请参考以下文章

matlab实现可调节占空比的方波

MSP430G2553 模拟交通灯

MSP430G2553单片机——利用蜂鸣器播放一首歌

MSP430G2553 4x4矩阵键盘

Arduino利用TimerOne库产生固定频率和占空比的方波

什么是pwm占空比