MSP430单片机C语言编程与实践(入门篇)之九----基本时钟模块(2)

9.1观察DCO(MCLK)频率变化的程序

       下述的程序可以用来观察DCO(MCLK)频率的变化。在while(1)循环中,让分别外接于P1.0和P1.6的红、绿LED亮灭,并用延时函数__delay_cycles(1000000)来设定LED亮灭的间隔。当外接于P1.3的按键S2按下时产生I/O口中断,在中断服务程序中进行按键判断,并切换DCO(MCLK)的频率,DCO的频率越高,延时函数__delay_cycles(1000000)产生的延时间隔越短,红、绿LED的闪烁越快。通过多次按下S2,可以观察红、绿LED的闪烁间隔的变化。

9.1观察DCO(MCLK)频率的变化

   

#include<msp430.h>


void main(void)

{

   WDTCTL=WDTPW+WDTHOLD;//关闭看门狗



   BCSCTL2=SELM_0|DIVM_0; //为MCLK选择DCOCLK,不分频



   P1DIR|=BIT6+BIT0;    //P1.0、P1.6被设置为输出方向



   P1OUT|=BIT6+BIT0;     //点亮两个LED


   P1REN|=BIT3;         //P1.3的上/下拉电阻使能

   P1OUT|=BIT3;         //P1.3被上拉,连接于P1.3的按键未按下时,P1.3的输入为高电平



   P1DIR&=~BIT3;        //P1.3被设置为输入方向

   P1IES|=BIT3;         //设置由下降沿引起P1.3中断



   P1IFG=0;             //上述写P1DIR、P1OUT和P1IES,会导致相应的P1IFG被置位,该语句清除这些 
                        //额外产生的中断标志

   P1IE|=BIT3;         //允许P1.3中断



   _EINT();             //总中断允许



while(1)

   {

      P1OUT^=BIT6+BIT0; //亮灭红色和绿色LED

      __delay_cycles(1000000);  //延时函数,延时的长短取决于MCLK的大小,MCLK越高,延时越短, 
                                //红、绿LED的闪烁越快

   }

}


#pragma vector=PORT1_VECTOR      //P1口中断向量,注意:必须严格按此格式书写

__interrupt voidP1_ISR(void)    //声明一个中断服务程序,名为P1_ISR()。

{                                 

  static unsigned int Freq=0;   //静态变量的性质:初始化只有一次,但是可以多次赋值

  unsigned int i=0;

  for(i=0;i<1000;i++);  //延时消抖


  if(P1IN&BIT3)          //若为按键抖动产生的中断,则只进行一个空操作_NOP()

    _NOP();

  else//若为真正的按键按下所产生的中断,则执行下条语句的操作

    Freq++;


  if(Freq>3)  Freq=0;


  switch(Freq)

    {

     case 0: DCOCTL = 0x00; BCSCTL1=CALBC1_1MHZ; DCOCTL=CALDCO_1MHZ;  break;  //MCLK 1MHz

     case 1: DCOCTL = 0x00; BCSCTL1=CALBC1_8MHZ; DCOCTL=CALDCO_8MHZ;  break;  //MCLK 8MHz

     case 2: DCOCTL = 0x00; BCSCTL1=CALBC1_12MHZ; DCOCTL=CALDCO_12MHZ; break; //MCLK 12MHz

     case 3: DCOCTL = 0x00; BCSCTL1=CALBC1_16MHZ; DCOCTL=CALDCO_16MHZ; break; //MCLK 16MHz

     default: break;

    }


   P1IFG=0;//中断标志清零。注意:P1、P2口的中断标志需要人工清除,否则该中断会不停地被执行

}//中断函数(中断服务程序)到此结束

        在CCS中建立工程,将上述的C文件加入工程中。调试无误后,将程序下载到开发板,即可正常运行。重复按下S2,可以观察红、绿LED的闪烁间隔的变化。 

       在上述程序中,对P1.0、P1.6、P1.3三个端口的设置可以打包为一个函数,然后在主函数main( )中调用该函数即可。如下所示:

9.2 在例9.1的基础上,将P1.0、P1.6、P1.3三个端口的设置打包为一个函数,通过函数调用的方法可以实现同样的功能。

#include<msp430.h>


void P1_IO_Init();   //在主函数main()前声明函数,该函数实现对P1.0、P1.6、P1.3的初始化


void main(void)

{

   WDTCTL=WDTPW+WDTHOLD;//关闭看门狗


   BCSCTL2=SELM_0|DIVM_0; //为MCLK选择DCOCLK,不分频


   P1_IO_Init();   //调用P1_IO_Init()函数,初始化相关的I/O口


   _EINT();        //总中断允许


   while(1)

    {

      P1OUT^=BIT6+BIT0; //使LED的亮灭状态取反

      __delay_cycles(1000000);  //延时函数,延时的长短取决于MCLK的大小,MCLK越高,延时越短,红绿LED的闪烁越快

     }

}


#pragma vector=PORT1_VECTOR      //P1口中断向量,注意:必须严格按此格式书写

__interrupt void P1_ISR(void)     //声明一个中断服务程序,名为P1_ISR()

{                        

  static unsigned int Freq=0;   //静态变量的性质:初始化只有一次,但是可以多次赋值

  unsigned int i=0;

  for(i=0;i<1000;i++);   //延时消抖


  if(P1IN&BIT3)          //若为按键抖动产生的中断,则只进行一个空操作_NOP()

      _NOP();

  else//若为真正的按键按下所产生的中断,则执行下条语句的操作

      Freq++;


  if(Freq>3)  Freq=0;


  switch(Freq)

    {

      case 0: DCOCTL = 0x00; BCSCTL1=CALBC1_1MHZ; DCOCTL=CALDCO_1MHZ;  break; //MCLK 1MHz

      case 1: DCOCTL = 0x00; BCSCTL1=CALBC1_8MHZ; DCOCTL=CALDCO_8MHZ;  break; //MCLK 8MHz

      case 2: DCOCTL = 0x00; BCSCTL1=CALBC1_12MHZ; DCOCTL=CALDCO_12MHZ; break; //MCLK 12MHz

      case 3: DCOCTL = 0x00; BCSCTL1=CALBC1_16MHZ; DCOCTL=CALDCO_16MHZ; break; //MCLK 16MHz

      default: break;

    }

    P1IFG=0;    //中断标志清零。注意:P1、P2口的中断标志需要人工清除,否则该中断会不停地执行

}



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

 * 名称:P1_IO_Init()

 * 功能:设定P1.0和P1.6为输出方向。设定P1.3为输入方向,其内部上拉电阻使能,允许P1.3 *的中断。

 * 入口参数:无

 * 出口参数:无

 * 说明:无

 * 范例:无

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

void P1_IO_Init()

{

   P1DIR|=BIT6+BIT0;    //P1.0、P1.6被设置为输出方向

   P1OUT|=BIT6+BIT0;     //点亮两个LED

   P1REN|=BIT3;         //P1.3的上/下拉电阻使能

   P1OUT|=BIT3;         //P1.3被上拉,连接于P1.3的按键未按下时,P1.3的输入为高电平

   P1DIR&=~BIT3;        //P1.3被设置为输入方向

   P1IES|=BIT3;         //设置由下降沿引起P1.3中断


   P1IFG=0;             //上述写P1DIR、P1OUT和P1IES,会导致相应的P1IFG被置位,该语句清除这些额外产生的中断标志

   P1IE|=BIT3;          //允许P1.3中断

}

       再进一步,对上述中断函数中的按键消抖、频率切换功能也可以打包为函数,在中断中直接调用即可,如下所示。

9.3 在例9.2的基础上,将按键消抖、频率切换功能也打包为函数。

#include<msp430.h>

                           //在主函数main()前声明函数

void P1_IO_Init();         //对P1口的初始化函数

void P1_3_Push_Detect();  //对P1.3的按键检测函数

void MCLK_DCO_Change();   //切换MCLK(DCO)频率的函数


void main(void)

{

   WDTCTL=WDTPW+WDTHOLD;//关闭看门狗

   BCSCTL2 = SELM_0 | DIVM_0; //为MCLK选择DCOCLK,不分频

   P1_IO_Init();   //调用P1_IO_Init()函数,初始化相关的I/O口


   _EINT();        //总中断允许


   while(1)

     {

      P1OUT^=BIT6+BIT0;          //使LED的亮灭状态取反

      __delay_cycles(1000000);  //延时函数,延时的长短取决于MCLK的大小,MCLK越高,延时越短,红、绿LED的闪烁越快

     }

}


#pragma vector=PORT1_VECTOR      //P1口中断向量,注意:必须严格按此格式书写

__interrupt void P1_ISR(void)     //声明一个中断服务程序,名为P1_ISR()

{                                 

    P1_3_Push_Detect();   //调用对P1.3的按键检测函数,并在该函数中调用MCLK频率切换函数


    P1IFG=0;    //中断标志清零。注意:P1、P2口的中断标志需要人工清除,否则该中断会不停地被执行

}



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

 * 名称:P1_IO_Init()

 * 功能:设定P1.0和P1.6为输出方向。设定P1.3为输入方向,其内部上拉电阻使能,允许P1.3 的中断。

 * 入口参数:无

 * 出口参数:无

 * 说明:无

 * 范例:无

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

void P1_IO_Init()

{

   P1DIR|=BIT6+BIT0;    //P1.0、P1.6被设置为输出方向



   P1OUT|=BIT6+BIT0;     //点亮两个LED



   P1REN|=BIT3;         //P1.3的上/下拉电阻使能

   P1OUT|=BIT3;         //P1.3被上拉,连接于P1.3的按键未按下时,P1.3的输入为高电平



   P1DIR&=~BIT3;        //P1.3被设置为输入方向

   P1IES|=BIT3;         //设置由下降沿引起P1.3中断


   P1IFG=0;             //上述写P1DIR、P1OUT和P1IES,会导致相应的P1IFG被置位,该语句清除这些额外产生的中断标志

   P1IE|=BIT3;          //允许P1.3中断

}



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

 * 名称:P1_3_Push_Detect()

 * 功能:对外接于P1.3的按键S2进行按键按下的消抖及识别

 * 入口参数:无

 * 出口参数:无

 * 说明:无

 * 范例:无

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

void P1_3_Push_Detect()

{

   unsigned int i=0;

   unsigned char PushKey;

   PushKey=P1IFG&BIT3;


   for(i=0;i<1000;i++);   //延时消抖


   if(P1IN&PushKey==PushKey)     //若为按键抖动产生的中断,则清除中断标志并返回

     {

       P1IFG=0;

       return;

     }



   if(PushKey&BIT3)     //若为真正的按键按下所产生的中断,则执行下述语句的操作

     {

        MCLK_DCO_Change();  //调用切换MCLK频率的函数

     }

    return;

}



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

 * 名称:MCLK_DCO_Change()

 * 功能:根据P1.3中断产生的次数,切换MCLK(DCO)的频率为1MHz、8MHz、12MHz或16MHz

 * 入口参数:无

 * 出口参数:无

 * 说明:无

 * 范例:无 ****************************************************************************/

void MCLK_DCO_Change()

{

   static unsigned int Freq=0;   //静态变量的性质:初始化只有一次,但是可以多次赋值

   Freq++;

   if(Freq>3)  Freq=0;


   switch(Freq)

     {

        case 0: DCOCTL = 0x00; BCSCTL1=CALBC1_1MHZ; DCOCTL=CALDCO_1MHZ;  break;  //MCLK 1MHz

        case 1: DCOCTL = 0x00; BCSCTL1=CALBC1_8MHZ; DCOCTL=CALDCO_8MHZ;  break;  //MCLK 8MHz

        case 2: DCOCTL = 0x00; BCSCTL1=CALBC1_12MHZ; DCOCTL=CALDCO_12MHZ; break; //MCLK 12MHz

        case 3: DCOCTL = 0x00; BCSCTL1=CALBC1_16MHZ; DCOCTL=CALDCO_16MHZ; break; //MCLK 16MHz

        default: break;

    }

}

       上述例子都可以在CCS中建立工程,在C文件中添加、编辑程序,然后建立、编译、下载到LaunchPad实验板中运行,观察实验结果。

        采用定义函数和调用函数的方法可以增强程序的可移植性和可读性,便于实现结构化和模块化编程的思想。而且许多函数可以直接用于或稍加修改用于其它程序中,可大大提高编程效率。

       单片机的学习要注重实践环节,无论是软件还是硬件,都需要亲自动手调试,在实践中发现问题、排查问题、解决问题。比如:在CCS中调试软件,会碰到各种各样的出错信息,需要返回到程序中去排查错误。当搭建外围电路时,也会出现各种各样的错误。软、硬件方面的这些bug(错误)都是难免的,消灭这些bug也是学习的一部分,我们的能力也在消灭这些bug的过程中一天天的提升。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

The East Sea

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值