430学习任务一

430学习任务一之用PWM出两路独立可调频率和相位的正弦波


实验内容

基于MSP430G2553开发板,用PWM处两路正弦波,并且两路波形的频率,相位可以独立改变。为了达到这个目标,需要掌握定时器-比较器的使用,中断函数的使用。

本文分两个阶段来逐步完成实验。第一个阶段不使用外中断,即没有用P1.3按钮,生成两路频率和相位在一定范围内能连续独立地改变。第二个阶段在阶段一的基础上加入外中段控制,利用长按键和短按键来分别控制两路正弦波的频率和相位的改变,按一次按键,频率和相位改变一次。下面分阶段来详细介绍。

阶段一

设计思路

• 生成2路相位,频率和相位可调的正弦波
• 保存了一个正弦波表
• 设定波表的初始读取地址用于设定波形相位
• 设定波表读取地址的增量用于设定频率
• 定义两个静态变量用于存储读取地址的增量的递增和递减值
• 在主函数中循环读取正弦波,当读取地址增量改变时,频率和相位也改变

代码块

/*
 * main.c
 */
#include<msp430g2553.h>

#include "msp430g2553.h"

#define SIN_NUM 120
const unsigned  int sine_table[SIN_NUM] = {60, 63, 66, 69, 72, 75, 78, 81, 84, 86, 89, 92, 94, 97, 99, 102, 104, 106, 108, 109, 111, 112, 114, 115, 116, 117, 118, 118, 119, 119, 119, 119, 119, 118, 118, 117, 116, 115, 114, 112, 111, 109, 108, 106, 104, 102, 99, 97, 94, 92, 89, 86, 84, 81, 78, 75, 72, 69, 66, 63, 60, 57, 54, 51, 48, 45, 42, 39, 36, 34, 31, 28, 26, 23, 21, 18, 16, 14, 12, 11, 9, 8, 6, 5, 4, 3, 2, 2, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 8, 9, 11, 12, 14, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 42, 45, 48, 51, 54, 57};

#define PWM_PERIOD_CYCLE        SIN_NUM      // pwm wave period
#define PWM_DUTY_UPDATE_CYCLE   200          // duty update cycle
#define CH1_INC_PHASE           5            // ch1 sin wave phase increase step
#define CH1_INIT_PHASE          0            // ch1 sin wave initial phase
#define CH2_INC_PHASE           1            // ch2 sin wave phase increase step
#define CH2_INIT_PHASE         (SIN_NUM*1/16) // ch2 sin wave initial phase

void init_clock(){

  WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
  // If calibration constants erased, trap CPU!!
  if (CALBC1_1MHZ  == 0xFF || CALDCO_1MHZ   == 0xFF) { while(1);}
  if (CALBC1_12MHZ == 0xFF || CALDCO_12MHZ  == 0xFF) { while(1);}
  // Configure Basic Clock
  BCSCTL1 = CALBC1_12MHZ;               // Set range
  DCOCTL = CALDCO_12MHZ;                // Set DCO step + modulation
  BCSCTL3 |= LFXT1S_2;                  // Set LFXT1
  IFG1 &= ~OFIFG;                       // Clear OSCFault flag
  BCSCTL2 |= SELM_1 + DIVM_0;       // Set MCLK

}
void inline set_timer_A1_2ch_pwm_period_duty(int val_ta1ccr0, int val_ta1ccr1, int val_ta1ccr2) {
  TA1CCR1  = val_ta1ccr1;
  TA1CCR2  = val_ta1ccr2;
  TA1CCR0  = val_ta1ccr0;  // PWM Period
}

void init_timer_A1_2ch_pwm(int val_ta1ccr0, int val_ta1ccr1, int val_ta1ccr2) {
  P2DIR   |= BIT4+BIT1  ;  // P2.1 and P2.4 output
  P2SEL   |= BIT4+BIT1  ;  // P2.1 and P2.4 TA1 options
  // TA1CCTL0 = CCIE;            // CCR0 interrupt enabled
  TA1CCTL1 = OUTMOD_7   ;  // CCR1 reset/set
  TA1CCTL2 = OUTMOD_7   ;
  TA1CCR1  = val_ta1ccr1;
  TA1CCR2  = val_ta1ccr2;
  TA1CCR0  = val_ta1ccr0;  // PWM Period
  TA1CTL   = TASSEL_2 + MC_1; // SMCLK, up mode

}

volatile int ch1_index    = CH1_INIT_PHASE; // channel 1 wave table index
volatile int ch2_index    = CH2_INIT_PHASE; // channel 1 wave table index

volatile int val_ta0ccr0  =   PWM_DUTY_UPDATE_CYCLE ; // pwm duty update counter
volatile int val_ta1ccr0  =   PWM_PERIOD_CYCLE      ; // pwm period counter
volatile int val_ta1ccr1  =   1                     ; // pwm wave 1 duty  counter
volatile int val_ta1ccr2  =   1                     ; // pwm wave 2 duty  counter
static unsigned int ch1_inc=CH1_INC_PHASE,ch2_inc=CH2_INC_PHASE;
int main( void )
{
  init_clock();
  init_timer_A1_2ch_pwm(val_ta1ccr0, val_ta1ccr1, val_ta1ccr2);
  // Configure TimerA
  TA0CTL   = TASSEL_2+MC_1  ;   // Source: SMCLK, UP mode
  TA0CCR0  = val_ta0ccr0    ;   // Timer count
  TA0CCTL0 = CCIE           ;   // CCR0 interrupt enabled

  P1DIR |= BIT6 ;  // P1.6 output dir (green LED)
  P1OUT  = 0    ;  // LED off
  P1DIR |= BIT0 ;  // Set P1.0 to output direction
  P1IES |= BIT3 ;  // P1.3 Hi/lo edge
  P1IFG &= ~BIT3;  // P1.3 IFG cleared
  P1IE  |= BIT3 ;  // P1.3 interrupt enabled


  _EINT(); // global interrupt enable
  while(1){
    __no_operation();               // SET BREAKPOINT HERE
    _delay_cycles(5000000);
      ch1_inc--;
      if(ch1_inc<=1) ch1_inc = 5;
      ch2_inc++;
      if(ch2_inc>=5) ch2_inc =1;

       val_ta1ccr1 = 1;
       val_ta1ccr2 = 1;
     init_timer_A1_2ch_pwm(val_ta1ccr0, val_ta1ccr1, val_ta1ccr2);
    }
  }

// Timer A0 interrupt service routine
#pragma vector= TIMER0_A0_VECTOR
__interrupt void Timer_A0 (void)
{

  set_timer_A1_2ch_pwm_period_duty(val_ta1ccr0, val_ta1ccr1, val_ta1ccr2);
  __no_operation();               // SET BREAKPOINT HERE
  P1OUT ^= BIT6;                // toggle P1.6 output
  // increase duty of channel 1

  val_ta1ccr1 = sine_table[ch1_index];
  val_ta1ccr2 = sine_table[ch2_index];
  ch1_index += ch1_inc; while(ch1_index >= SIN_NUM){ch1_index -= SIN_NUM; }
  ch2_index += ch2_inc; while(ch2_index >= SIN_NUM){ch2_index -= SIN_NUM; }

}

实验结果

时域模式波形照片1
时域模式波形照片
时域模式波形照片2
时域模式波形照片2
XY模式的李萨如图形1
XY模式的李萨如图形
XY模式的李萨如图形2
XY模式的李萨如图形
XY模式的李萨如图形3
XY模式的李萨如图形

阶段二

设计思路

• 基于阶段一的设计进行修改
• 加入PORT1_VECTOR中断,当短按键时改变CH1的频率和相位,长按 键时改变CH2的频率和相位
• 当长按键起作用时会相应地对LED1进行亮灭变换,即按一次长按键,灯亮,再按一次长按键,灯灭,短按键对LED1不起作用,以此来判别此时选中的是CH1还是CH2

代码块

/*
 * main.c
 *
 *  Created on: 2018年4月25日
 *      Author: 1
 */
/*
 * main.c
 */
#include<msp430g2553.h>

#include "msp430g2553.h"

#define SIN_NUM 120
const unsigned  int sine_table[SIN_NUM] = {60, 63, 66, 69, 72, 75, 78, 81, 84, 86, 89, 92, 94, 97, 99, 102, 104, 106, 108, 109, 111, 112, 114, 115, 116, 117, 118, 118, 119, 119, 119, 119, 119, 118, 118, 117, 116, 115, 114, 112, 111, 109, 108, 106, 104, 102, 99, 97, 94, 92, 89, 86, 84, 81, 78, 75, 72, 69, 66, 63, 60, 57, 54, 51, 48, 45, 42, 39, 36, 34, 31, 28, 26, 23, 21, 18, 16, 14, 12, 11, 9, 8, 6, 5, 4, 3, 2, 2, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 8, 9, 11, 12, 14, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 42, 45, 48, 51, 54, 57};

#define PWM_PERIOD_CYCLE        SIN_NUM      // pwm wave period
#define PWM_DUTY_UPDATE_CYCLE   200          // duty update cycle
#define CH1_INC_PHASE           5            // ch1 sin wave phase increase step
#define CH1_INIT_PHASE          0            // ch1 sin wave initial phase
#define CH2_INC_PHASE           1            // ch2 sin wave phase increase step
#define CH2_INIT_PHASE         (SIN_NUM*1/16) // ch2 sin wave initial phase



void init_clock(){

  WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
  // If calibration constants erased, trap CPU!!
  if (CALBC1_1MHZ  == 0xFF || CALDCO_1MHZ   == 0xFF) { while(1);}
  if (CALBC1_12MHZ == 0xFF || CALDCO_12MHZ  == 0xFF) { while(1);}
  // Configure Basic Clock
  BCSCTL1 = CALBC1_12MHZ;               // Set range
  DCOCTL = CALDCO_12MHZ;                // Set DCO step + modulation
  BCSCTL3 |= LFXT1S_2;                  // Set LFXT1
  IFG1 &= ~OFIFG;                       // Clear OSCFault flag
  BCSCTL2 |= SELM_1 + DIVM_0;       // Set MCLK

}
void inline set_timer_A1_2ch_pwm_period_duty(int val_ta1ccr0, int val_ta1ccr1, int val_ta1ccr2) {
  TA1CCR1  = val_ta1ccr1;
  TA1CCR2  = val_ta1ccr2;
  TA1CCR0  = val_ta1ccr0;  // PWM Period
}

void init_timer_A1_2ch_pwm(int val_ta1ccr0, int val_ta1ccr1, int val_ta1ccr2) {
  P2DIR   |= BIT4+BIT1  ;  // P2.1 and P2.4 output
  P2SEL   |= BIT4+BIT1  ;  // P2.1 and P2.4 TA1 options
  // TA1CCTL0 = CCIE;            // CCR0 interrupt enabled
  TA1CCTL1 = OUTMOD_7   ;  // CCR1 reset/set
  TA1CCTL2 = OUTMOD_7   ;
  TA1CCR1  = val_ta1ccr1;
  TA1CCR2  = val_ta1ccr2;
  TA1CCR0  = val_ta1ccr0;  // PWM Period
  TA1CTL   = TASSEL_2 + MC_1; // SMCLK, up mode

}

volatile int ch1_index    = CH1_INIT_PHASE; // channel 1 wave table index
volatile int ch2_index    = CH2_INIT_PHASE; // channel 1 wave table index

volatile int val_ta0ccr0  =   PWM_DUTY_UPDATE_CYCLE ; // pwm duty update counter
volatile int val_ta1ccr0  =   PWM_PERIOD_CYCLE      ; // pwm period counter
volatile int val_ta1ccr1  =   1                     ; // pwm wave 1 duty  counter
volatile int val_ta1ccr2  =   1                     ; // pwm wave 2 duty  counter
static unsigned int ch1_inc=CH1_INC_PHASE,ch2_inc=CH2_INC_PHASE;



void P13_OnShortRelease()     //P1.3的事件处理函数
{
     ch1_inc--;
          if(ch1_inc<=1) ch1_inc = 5;
 //             ch1_index += ch1_inc; if(ch2_index >= SIN_NUM){ch2_index -= SIN_NUM; }
          //    P1OUT ^= BIT0;                         // P1.0 = toggle
              P1IFG &= ~BIT3;                        // P1.3 IFG cleared


}

void P13_OnLongClick()       //P1.3的事件处理函数
{
    ch2_inc++;
          if(ch2_inc>=5) ch2_inc =1;

 //          ch2_index += ch2_inc; if(ch2_index >= SIN_NUM){ch2_index -= SIN_NUM; }
           P1OUT ^= BIT0;                         // P1.0 = toggle
           P1IFG &= ~BIT3;                        // P1.3 IFG cleared


}

int main( void )
{
  init_clock();
  init_timer_A1_2ch_pwm(val_ta1ccr0, val_ta1ccr1, val_ta1ccr2);
  // Configure TimerA
  TA0CTL   = TASSEL_2+MC_1  ;   // Source: SMCLK, UP mode
  TA0CCR0  = val_ta0ccr0    ;   // Timer count
  TA0CCTL0 = CCIE           ;   // CCR0 interrupt enabled

  P1DIR |= BIT6 ;  // P1.6 output dir (green LED)
  P1OUT  = 0    ;  // LED off
  P1DIR |= BIT0 ;  // Set P1.0 to output direction
  P1IES |= BIT3 ;  // P1.3 Hi/lo edge
  P1IFG &= ~BIT3;  // P1.3 IFG cleared
  P1IE  |= BIT3 ;  // P1.3 interrupt enabled


  _EINT(); // global interrupt enable
  while(1){
    __no_operation();               // SET BREAKPOINT HERE

    _delay_cycles(5000000);

//           val_ta1ccr1 = 1;
//           val_ta1ccr2 = 1;
    init_timer_A1_2ch_pwm(val_ta1ccr0, val_ta1ccr1, val_ta1ccr2);
        if(!(P1IN & BIT3)){ // if key is push, its val is 0
            ch1_index += ch1_inc; while(ch1_index >= SIN_NUM){ch1_index -= SIN_NUM; }
          ch2_index += CH2_INC_PHASE; while(ch2_index >= SIN_NUM){ch2_index -= SIN_NUM; }
    }
  }
}
// Timer A0 interrupt service routine
#pragma vector= TIMER0_A0_VECTOR
__interrupt void Timer_A0 (void)
{

  set_timer_A1_2ch_pwm_period_duty(val_ta1ccr0, val_ta1ccr1, val_ta1ccr2);
  __no_operation();               // SET BREAKPOINT HERE
  P1OUT ^= BIT6;                // toggle P1.6 output
  // increase duty of channel 1

  val_ta1ccr1 = sine_table[ch1_index];
  val_ta1ccr2 = sine_table[ch2_index];
  ch1_index += ch1_inc; while(ch1_index >= SIN_NUM){ch1_index -= SIN_NUM; }
  ch2_index += ch2_inc; while(ch2_index >= SIN_NUM){ch2_index -= SIN_NUM; }

}

 //Port 1 interrupt service routine
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
    unsigned int Push_Key=0;
    //-----排除输出IO的干扰后,锁定唯一被触发的中断标志位-----
    Push_Key=P1IFG&(~P1DIR);
    //-----延时一段时间,避开机械抖动区域-----
    __delay_cycles(10000);
    //----判断按键状态是否与延时前一致-----
    if((P1IN&Push_Key)==0)              //如果该次按键确实有效
        {
            _delay_cycles(5000000);
            if((P1IN&Push_Key)==0)//判断是否是长按键
            {
               P13_OnLongClick();//若是长按键,跳到该函数

            }
            else
            {

                P13_OnShortRelease();//若是短按键,跳到该函数
            }


        }

实验结果

时域模式下的波形图
这里写图片描述

与时域波形相对应的XY模式图形
这里写图片描述

时域模式下的波形图2

这里写图片描述

与时域波形2相对应的XY模式图形
这里写图片描述

总结

由于本人对于用CCS8软件中自带的仿真波形功能不能熟练掌握,故在此只给出用示波器显示的结果,相较于仿真图形应该更为准确。同时,该代码全部放在main.c文件中,所以代码整体看起来可能有点费劲,之后会加以注意改正。通过这次实验,发现自己对定时器、比较器的掌握还不够熟练,以后要多看书多练习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值