10155|12

106

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

只有一个定时器的430,能否输出PWM的同时还能定时中断干其他活? [复制链接]

只有一个定时器的430,能否输出PWM的同时还能定时中断干其他活?
比如系统输出30K的PWM波形,同时还能有0.5秒的定时中断去执行其它任务。
大大能否贴个简单的代码指导一下啊?

最新回复

我没有做过这么复杂的设计,时钟源来回切换的。。。单片机不稳定也不奇怪! 我不知道你有外部32768晶体作为时钟源产生1秒的信号,我做的几个设计都是“单片机+阻容复位”便完成了最小系统的设计,时钟全部使用的内部时钟DCO和VLO,所以我才说用看门狗时钟会不准。 对于你这个设计,完全可以使用看门狗实现1s中断,看门狗内置的参数里有一个就是使用32k时钟设置1000毫秒的中断的,定时器安心的使用DCO,避免时钟源来回切换,会稳定很多。 /* WDT is clocked by fACLK (assumed 32KHz) */ #define WDT_ADLY_1000       (WDTPW+WDTTMSEL+WDTCNTCL+WDTSSEL)                 /* 1000ms  " */ #define WDT_ADLY_250        (WDTPW+WDTTMSEL+WDTCNTCL+WDTSSEL+WDTIS0)          /* 250ms   " */ #define WDT_ADLY_16         (WDTPW+WDTTMSEL+WDTCNTCL+WDTSSEL+WDTIS1)          /* 16ms    " */ #define WDT_ADLY_1_9        (WDTPW+WDTTMSEL+WDTCNTCL+WDTSSEL+WDTIS1+WDTIS0)   /* 1.9ms   " */复制代码 另外,根据CCS的低功耗建议,for循环语句尽量使用递减语句,能提高判断循环条件时的效率。  详情 回复 发表于 2014-8-13 00:25
 
点赞 关注(1)

回复
举报

1193

帖子

0

TA的资源

纯净的硅(高级)

推荐
 
helloxieyu 发表于 2014-8-8 17:17
能否pwm周期与中断函数周期分开,比如PWM波形30K, 中断函数的调用周期是1秒,频繁调用中断函数怕会提高功 ...

不行,PWM波形一个周期计数器产生一次溢出,同时可以产生一个中断,因此中断周期就是PWM波形的周期。
但是,你可以再设置一个变量让N个周期结束后再相应你的中断服务。
估计你没有看懂我的代码,20毫秒产生一次中断,但是中断服务程序是根据条件执行的。只有当count=0时会将单片机唤醒,其他时候单片机只执行--count,然后继续休眠。因此我这里真正的中断服务周期是20ms的整数倍。
至于时间久了定时不准的问题不用担心,中断服务很短,就两句,大概就是十几二十个机器周期。你可能会认为计数多了这个累积误差是不容小觑的,但其实不然,不要忘记单片机工作在Up Mode,定时器会在0-TACCR0之间循环计数,不会因为中断服务程序的执行而停下来,不然PWM波形的周期也就不准了。
30k的周期确实有些紧张,大概33μs就会产生一次中断,如果MCLK设为1M的DCO,也就意味着只能执行6-7句中断服务语句。
如果你使用Value Line系列的430单片机,那么可以考虑使用看门狗中断作为低速的定时中断,同样能够实现大约1s的定时中断,只不过误差可能会大点。选择SMCLK作为看门狗时钟精度会高一些(或者使用32768晶振作为ACLK),一般应用使用VLO作时钟足以应付。

点评

谢谢"qiushenghua [/backcolor] "大大!您说到: “30k的周期确实有些紧张,大概33μs就会产生一次中断,如果MCLK设为1M的DCO,也就意味着只能执行6-7句中断服务语句。 如果你使用Value Line系列的430单片机,那么  详情 回复 发表于 2014-8-12 11:13
 
 

回复

420

帖子

0

TA的资源

一粒金砂(高级)

沙发
 
本帖最后由 armcu 于 2014-8-7 12:29 编辑

应该是可以的,比如,具有多个比较通道的定时器,其中通道1设置为PWM功能,通道2设置为固定时间的中断功能,。。。。具体可以参考定时器连续计数模式的例程。
 
 
 

回复

1193

帖子

0

TA的资源

纯净的硅(高级)

板凳
 
本帖最后由 qiushenghua 于 2014-8-7 22:34 编辑

当然

#include
#define check1 (0x08&P1IN)                //高电平
#define check2 (!(0x08&P1IN))        //低电平

unsigned char state=0;
unsigned int count=1;
int main(void) {
        //关闭看门狗定时器
        WDTCTL = WDTPW | WDTHOLD;

        //设置DCO频率1MHz
        if(CALBC1_1MHZ!=0xff&&CALDCO_1MHZ!=0xff)
        {
                BCSCTL1 = CALBC1_1MHZ;
                DCOCTL = CALDCO_1MHZ;
        }
        //端口1.2、1.6设置成输出
        //1.2为PWM输出
        //1.6控制舵机电源,高电平电源开
        //P1.3设置成输入
        P1DIR=0xf7;                //1111 0111
        P1OUT&=~0x40;        //1011 1111
        P1OUT|=0x08;        //0000 1000
                                        //上拉1.3,初始化时将1.0拉高
        P1REN|=0x08;        //0000 1000
                                        //为1.3增加上拉电阻
        //不用的端口设置成输出并下拉到GND
        P2DIR=0xff;
        P3DIR=0xff;
        P2OUT&=~0xff;        //0000 0000
        P3OUT&=~0xff;        //0000 0000

        P1SEL|=0x04;        //打开P1.2的PWM输出
        CCR0=20000;                //PWM周期20ms
        CCTL1 = OUTMOD_7;
        CCR1=1000;
        TACTL=TASSEL_2+MC_1;
        TACCTL0 |=CCIE;        //开启CCR0中断,中断周期20ms

        for(;;)
        {

                if(state==0&&check2)        //如果状态0检测到电平变化,跳变到状态10
                {
                        state=10;
                }
                if(state==6&&check1)        //如果状态6检测到电平变化,跳变到状态4
                {
                        state=4;
                }

                        switch (__even_in_range(state,10))
                        {

                        case 10://舵机上电,置于开启位置
                                P1OUT|=0x40;        //0100 0000
                                CCR1=1000;
                                count=20;                //舵机开启花费时间20*20ms
                                state=8;
                                break;

                        case 4://舵机上电,置于关闭位置
                                P1OUT|=0x40;        //0100 0000
                                CCR1=1900;
                                count=20;                //舵机关闭花费时间20*20ms
                                state=2;
                                break;

                        case 8:
                        case 2://断电
                                P1OUT&=~0x40;        //1011 1111
                                count=1;                //断电时间1*20ms
                                state-=2;
                                break;

                        default:
                                count=1;                //检测电平变化周期1*20ms
                        }

                _BIS_SR(LPM0_bits+GIE);//关闭CPU,等待中断唤醒。
        }
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
        if(count>0)--count;
        //每20毫秒进入中断一次,如果count不等于0,不唤醒
        //当count=0时唤醒CPU
        else{
                __bic_SR_register_on_exit(LPM0_bits);
                }
}
 
 
 

回复

1193

帖子

0

TA的资源

纯净的硅(高级)

4
 
这是一个简单的舵机控制器,舵机不动作时关闭舵机电源。
 
 
 

回复

106

帖子

0

TA的资源

一粒金砂(中级)

5
 
谢谢qiushenghua大大细心的回复。
还想请教一下大大,上面的例子pwm周期与中断函数周期都是20ms,能否两者设置成不同的周期呢?
 
 
 

回复

106

帖子

0

TA的资源

一粒金砂(中级)

6
 
能否pwm周期与中断函数周期分开,比如PWM波形30K, 中断函数的调用周期是1秒,频繁调用中断函数怕会提高功耗,还怕长时间计时不准确。

点评

再次谢谢qiushenghua大大, 我就是在中断服务函数里设置一个变量计数器计到一秒的时候再去执行我要的操作的,但是感觉这样总是进入中断函数,1秒定时的偏差很大。  详情 回复 发表于 2014-8-9 10:13
不行,PWM波形一个周期计数器产生一次溢出,同时可以产生一个中断,因此中断周期就是PWM波形的周期。 但是,你可以再设置一个变量让N个周期结束后再相应你的中断服务。 估计你没有看懂我的代码,20毫秒产生一次中  详情 回复 发表于 2014-8-8 22:38
 
 
 

回复

106

帖子

0

TA的资源

一粒金砂(中级)

8
 
helloxieyu 发表于 2014-8-8 17:17
能否pwm周期与中断函数周期分开,比如PWM波形30K, 中断函数的调用周期是1秒,频繁调用中断函数怕会提高功 ...

再次谢谢qiushenghua大大,
我就是在中断服务函数里设置一个变量计数器计到一秒的时候再去执行我要的操作的,但是感觉这样总是进入中断函数,1秒定时的偏差很大。

 
 
 

回复

106

帖子

0

TA的资源

一粒金砂(中级)

9
 
qiushenghua 发表于 2014-8-8 22:38
不行,PWM波形一个周期计数器产生一次溢出,同时可以产生一个中断,因此中断周期就是PWM波形的周期。
但 ...

谢谢"qiushenghua "大大!您说到:
“30k的周期确实有些紧张,大概33μs就会产生一次中断,如果MCLK设为1M的DCO,也就意味着只能执行6-7句中断服务语句。
如果你使用Value Line系列的430单片机,那么可以考虑使用看门狗中断作为低速的定时中断,同样能够实现大约1s的定时中断,只不过误差可能会大点。选择SMCLK作为看门狗时钟精度会高一些(或者使用32768晶振作为ACLK),一般应用使用VLO作时钟足以应付。”


1. 我试过在中断函数里计数满1秒后去干其它活(大概20ms的时间),那么这个1秒定时函数就延时得很厉害了,是不是我干活的时间必需小于33us,1秒定时函数才不会有很大的误差啊?
2. Value Line系列的430单片机是哪些?手头只有G2系列系列的,算是 Value Line系列么?
3. 用SMCLK作为看门狗时钟做一秒定时中断服务程序的简单例程(同时还要有30K的PWM输出),您能再给出一个么?
再次感谢" qiushenghua "大大!





点评

1.好好看看我的例程,估计你没有使用430低功耗特性。a.把20ms的任务放进main函数里,执行之前进入LPM0低功耗状态。b.定时器中断里只放计数模块和唤醒语句,最多再放几句赋值语句用于设置清除标志位。 c.1s到之后唤  详情 回复 发表于 2014-8-12 11:55
 
 
 

回复

1193

帖子

0

TA的资源

纯净的硅(高级)

10
 
本帖最后由 qiushenghua 于 2014-8-12 11:57 编辑
helloxieyu 发表于 2014-8-12 11:13
谢谢"qiushenghua  "大大!您说到:
“30k的周期确实有些紧张,大概33μs就会产生一次中断 ...

1.好好看看我的例程,估计你没有使用430低功耗特性。
a.把20ms的任务放进main函数里,执行之前进入LPM0低功耗状态。b.定时器中断里只放计数模块和唤醒语句,最多再放几句赋值语句用于设置清除标志位。
c.1s到之后唤醒单片机,然后退出定时中断,于是单片机执行main里的20ms语句(语句开头对计数模块重新赋值)。
d.在这20ms语句执行期间,定时器继续工作,为下一个1s的定时作准备。
e.注意20ms语句执行期间可能会被定时器打断,时序性强的工作可以用定时器辅助完成。

2.Value Line就是MSP430G2xxx。

3.不能,从1看,你对1s定时的精度要求很高,看门狗的精度与之差不多,如果使用ACLK那误差更加是不可预测的,所以不推荐看门狗中断。CCS里有相关的例程,略微改动了一下给你参考:

  1. #include <msp430.h>
  2. unsigned int count;
  3. int main(void)
  4. {
  5.   WDTCTL = WDT_MDLY_32;                     // Set Watchdog Timer interval to ~30ms
  6.   IE1 |= WDTIE;                             // Enable WDT interrupt
  7.   P1DIR |= 0x01;                            // Set P1.0 to output direction
  8. count=31;


  9. /*下面这段自己筛选有用的语句*/
  10.         P1DIR=0xf7;                //1111 0111
  11.         P1OUT&=~0x40;        //1011 1111
  12.         P1OUT|=0x08;        //0000 1000
  13.                                         //上拉1.3,初始化时将1.0拉高
  14.         P1REN|=0x08;        //0000 1000
  15.                                         //为1.3增加上拉电阻
  16.         //不用的端口设置成输出并下拉到GND
  17.         P2DIR=0xff;
  18.         P3DIR=0xff;
  19.         P2OUT&=~0xff;        //0000 0000
  20.         P3OUT&=~0xff;        //0000 0000

  21. /*上面这段自己筛选有用的语句*/

  22.         P1SEL|=0x04;        //打开P1.2的PWM输出
  23.         CCR0=33;                //PWM周期20ms
  24.         CCTL1 = OUTMOD_7;
  25.         CCR1=16;
  26.         TACTL=TASSEL_2+MC_1;
  27.         TACCTL0 |=CCIE;        //开启CCR0中断,中断周期20ms


  28.   _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 w/ interrupt
  29. for(;;)
  30. {
  31. count=31;
  32. {/*20ms周期语句放在这里*/}
  33. LPM0;
  34. }

  35. }

  36. // Watchdog Timer interrupt service routine
  37. #pragma vector=WDT_VECTOR
  38. __interrupt void watchdog_timer(void)
  39. {
  40. if(count>0)count--;
  41. else LPM0_EXIT;
  42. }
复制代码







 
 
 

回复

106

帖子

0

TA的资源

一粒金砂(中级)

11
 
本帖最后由 helloxieyu 于 2014-8-12 21:47 编辑

qiushenghua大大,按照您上面给我的提示,我已经能实现33K PWM与1秒定时中断的任务了。
谢谢您!
我还想再请教您一下,中断函数运行过程中,能否动态切换当前计数器用DCO或是外部32.768晶体?
因为我的应用是这样的:正常状态下用外部32.768晶体计数来产生1秒的中断函数,其他时间处于LPM3模式。
当MCU收到外部指令时跳转到DCO 计数来产生1秒的中断函数同时输出33K PWM波形。我写了下面的代码来测试,单独运行一种时钟的初始化是没问题,但是两个时钟的初始化来回切换就不行了。现象是PWM输出10秒后就没有了(之后的20秒30秒都一直没有出现),或者是1秒定时函数执行几次10秒后就不执行了。


unsigned short SecondCnt;
unsigned short ClkFlipCnt;
unsigned DCOTag;
int main( void )
{
        WDTCTL = WDTPW +WDTHOLD;
        
      BCSCTL1 = CALBC1_8MHZ;
      DCOCTL = CALDCO_8MHZ;


      P1REN|=BIT1;
      P1DIR|=BIT1;

      P1DIR |=BIT2;
      P1SEL |=BIT2;


     ClkFlipCnt=0;
     DCOTag=0;   

     if(DCOTag==1)
     {
                  SetDCO();  
     }
     else
     {
      SetACLK();
     }

    _EINT(); //使能中断,
    while(1)
    {
           OneSecondDo();
           _BIS_SR(LPM0_bits+GIE);//关闭CPU,等待中断唤醒     
     }
  return 0;
}


#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0_ISR(void)   
{
            if(DCOTag==1) //用内部DCO  
            {
                    if(SecondCnt==32240)  //32.24K
                    {                             
                            SecondCnt=0;            
                            __bic_SR_register_on_exit(LPM0_bits); //唤醒MCU,  
                    }
                    else  //不唤醒MCU
                    {
                            SecondCnt++;  
                    }
            }
            else  //用外部32.768晶体
            {
                    __bic_SR_register_on_exit(LPM0_bits); //唤醒MCU,
            }

}   

void OneSecondDo()
{
            Delay(1000);//就是n个循环,模拟MCU在处理事情                  
            P1OUT=(~P1OUT);  

            if(ClkFlipCnt==20) //每10秒切换一次时钟选择
            {
                    SetACLK();
                    ClkFlipCnt=0;
            }
            if(ClkFlipCnt==10) //每10秒切换一次时钟选择
            {
                    SetDCO();
             }
            ClkFlipCnt++;               
}

void SetACLK() //用内部DCO  
{
   CCR0 =32768;
   TACTL = TASSEL0+MC0+ TACLR;
   TACCTL0 |=CCIE;
}

void SetDCO()  //用外部32.768晶体
{
        CCR0=240;    //PWM周期
        CCTL1 = OUTMOD_7;
        CCR1=120;    //占空比
        TACTL=TASSEL1+MC0+ TACLR;  
        TACCTL0 |=CCIE;        
}


 
 
 

回复

1193

帖子

0

TA的资源

纯净的硅(高级)

12
 
我没有做过这么复杂的设计,时钟源来回切换的。。。单片机不稳定也不奇怪!
我不知道你有外部32768晶体作为时钟源产生1秒的信号,我做的几个设计都是“单片机+阻容复位”便完成了最小系统的设计,时钟全部使用的内部时钟DCO和VLO,所以我才说用看门狗时钟会不准。
对于你这个设计,完全可以使用看门狗实现1s中断,看门狗内置的参数里有一个就是使用32k时钟设置1000毫秒的中断的,定时器安心的使用DCO,避免时钟源来回切换,会稳定很多。
  1. /* WDT is clocked by fACLK (assumed 32KHz) */
  2. #define WDT_ADLY_1000       (WDTPW+WDTTMSEL+WDTCNTCL+WDTSSEL)                 /* 1000ms  " */
  3. #define WDT_ADLY_250        (WDTPW+WDTTMSEL+WDTCNTCL+WDTSSEL+WDTIS0)          /* 250ms   " */
  4. #define WDT_ADLY_16         (WDTPW+WDTTMSEL+WDTCNTCL+WDTSSEL+WDTIS1)          /* 16ms    " */
  5. #define WDT_ADLY_1_9        (WDTPW+WDTTMSEL+WDTCNTCL+WDTSSEL+WDTIS1+WDTIS0)   /* 1.9ms   " */
复制代码

另外,根据CCS的低功耗建议,for循环语句尽量使用递减语句,能提高判断循环条件时的效率。
 
 
 

回复

106

帖子

0

TA的资源

一粒金砂(中级)

13
 
本帖最后由 helloxieyu 于 2014-8-13 16:06 编辑

  qiushenghua大大,跟您说一下我这个应用吧:
1. 我这个系统是超低功耗的,用纽扣电池供电,在用户完全不使用的情况下需要纽扣电池需要能待机2年时间。
2. 待机情况下430需进入LPM3模式,这就要用到外部32.768晶体或内部VLO,但是每个430的VLO的频率都相差很大(4k-20K都有可能),因此不敢用。
3. 这个系统是运行在140C温度下的,430内部的VLO温飘大得吓人,更不敢用。而外部的32.768晶体只能到125C,超过了125C就不起振,这样子我在120C时就必须切换到内部DCO时钟让1秒定时器能继续工作,这样子430就无法工作在LPM3模式下而只能工作在LPM1模式下,功耗将大大增加(是 LPM3功耗的几十倍)。待温度降到120C以下后,为了降低功耗,我又需要跳转到外部32.768晶体的LPM3模式下。
4. 就因为买不到125C以上的32.768晶体,为了低功耗,我头都想爆了。
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表