通常我们都是固定的PWM设定然后直接输出。我这里问的是关于根据采样反馈的电压值来调节相应的PWM波形。CCR0为PWM的周期。CCR1是PWM的高电平时间,当采样电压过大,减小CCR1的值。反之,则增大CCR1的值。但是,问题出现在:采样电压大,所以要减小CCR1的值,但当CCR1当减小到0时,再减小就会返回到FFFFH,成为很大的数,超过了之前设定的CCR0的值。同样,当CCR1增加时,也会超过CCR0的值。
问题是:(1)高电平的值CCR1竟然比 周期的值CCR0都大,这样会出现什么情况?
(2)我一直以为PWM设置后就自己能进行产生,哪怕是没有在程序中的死循环。但是今天没成功。我在main中先设置PWM。但是for(;;)后面的死循环没有PWM,我在示波器上没看到PWM。难道说PWM的相关设置也必须都循环才能产生么?我很诧异()
(3)如何能动态调节PWM?
谢谢!困惑很久,作为学生,希望各位不吝赐教!!(程序在后面)
#include<msp430g2553.h>
//占空比是CCR0=256,CCR1=81;
#define step 20 //调节精度每次20
#define upline 590
#define downline 562
void main()
{
unsigned int FLAG ;//判断是否在误差范围内,若在允许范围内,则置1;否则置0;
unsigned int WIDE_OLD , WIDE_NEW ;
/*************时钟初始化设置**************************************************************************************/
WDTCTL = WDTPW + WDTHOLD; //关闭看门狗
//将PWM要50Khz左右,DCO大约是7.8MHZ,对应可选择SMCLK为DCO振荡器,DCOx=3,MODx=0,RSELx=13
DCOCTL = DCO0+DCO1 ; //可以不用设置因为是默认值,DCOX=3,MODX=0
BCSCTL1 = RSEL3+RSEL1 ; //RSELx=13,
BCSCTL2 = DIVS_0 + SELM_0 ; //可以不用设置因为是默认值,SMCLK的来源是DCO,分频比是1,MCLK选择是DCO,
//SMCLK=MCLK=DCO=7.8Mhz, 周期是应该是3.424Mhz左右
// 计数时间=1/6.8Mhz=1.47e-7 s T=2.94e-7 s
//检测:SMCLK的频率可以通过P1.4端口设置,根据P1.4原理图。
P1DIR=BIT4;
P1SEL=BIT4;
/**************定时器A1初始化******** ****************************************************************************/
//TA1CCR1 可选择端口:P2.1
//TA1CCR2 可选择端口:P2.4
//50Khz频率,T周期为=1/50Khz=2e-5 s 因为定时器只输出PWM一般情况不用进入中断
// TA0CTL = TACLR ; //当TACLR置位时,清除计数器的数据,注意:分频比也同时reset。
TA1CTL |= TASSEL_2 + MC_1 ; //SMCLK,分频比是1,UP-mode,定时器内容清除,不允许中断.
TA1CCTL1 = OUTMOD_7 ; //reset/set, 不允许中断,
TA1CCTL2 = OUTMOD_7 ; //reset/set, 不允许中断,
TA1CCR0 = 256-1 ; // 计数周期: 256/29200000=0.07us
TA1CCR1 =170-1; //占空比是 81/256=31.6%
TA1CCR2 =170-1 ; //占空比是 81/256=31.6%
P2DIR = BIT1 + BIT4 ; //PWM输出端口 13.36KHZ
P2SEL = BIT1 + BIT4 ; //PWM输出端口 13.36KHZ
/************************************以上的PWM输出正确***************************************************************************
ADC10CTL0 = SREF_1 + ADC10SHT_2 + REF2_5V + REFON + ADC10ON ; // VREF+ /AVSS, ts=16*ADC10CLK ,2.5v, ADC10ON,IE中断使能
ADC10CTL1 = INCH_2 + CONSEQ_0 + SHS_0 ; //Channel 2, 单通道单次, ADC10SC触发
ADC10AE0 =BIT2 ; //通道A2使能
//for(;;) //调节电压
//{
WIDE_OLD = TA1CCR1 ;
ADC10CTL0 &= ~ADC10IFG ; //标志位清零
ADC10CTL0 |= ENC + ADC10SC ; // 开始转换信号,和等待trigger,(默认的ADC10SC)此处设置成PWM来触发,| 只改变该位
while(!( ADC10CTL0 & ADC10IFG) );//判断采样是否完成
ADC10CTL0 &= ~ADC10IFG ; //标志位清零
if( ADC10MEM < upline && ADC10MEM > downline ) FLAG = 1 ; //合理值
else FLAG = 0 ; //调节
if( FLAG == 0 )
{
if( ADC10MEM > upline )//不能用减法,unsigned int 类型,减完会变大
{
if( WIDE_OLD > step )
{WIDE_NEW = WIDE_OLD – step ; WIDE_NEW = WIDE_OLD – step ;}//够减继续减
else WIDE_NEW = 0 ; //不够减就直接清零
}
else { WIDE_NEW = WIDE_OLD + step ;WIDE_NEW = WIDE_OLD + step ;}
}
if( WIDE_NEW > 255)
{ WIDE_NEW = 255 ; }//超过最大值则只能是最大值255
TA1CCR1 = WIDE_NEW ;
TA1CCR2 = WIDE_NEW ;
}
//}
//
//
//
*/}
zhikai kuang:
注释有些没有及时改过来。请大家见谅。。尤其是数值方面的。。不过看的具体是思路和原理吧。。谢谢~!
Xutong Han2:
PWM是配置好后就会输出,下面测试程序,单片机进入了低功耗模式,但是PWM是输出的,
当改变PWM的占空比时需要动态的修改CCR1的值,
//———————————————————Timer0/1 A3 配置函数——————————————————–//================================================================// 函数名称 :Timer0A3PWM()// 函数功能 : 定时器Timer0_A的比较输出引脚即可做PWM输出的引脚为:// 入口参数 :无// 出口参数 :无// 备注:// out0(比较值为CCR0)P1.1,P1.5 对应芯片手册TA0.0// out1(比较值为CCR1)P1.2,P1.6 对应芯片手册TA0.1// ACLK时钟选择内部VLO大约12KHz 二分频后为6KHz左右 // T=120*(1/6K) f=1/T=50Hz(实际测试为52Hz) // 时钟选择SMLK f大约为9.4KHz//================================================================void Timer0A3PWM(){ P1DIR |=0x66 ; // 0110 0110 P1SEL |=0x66 ; // 0110 0110 // TACTL |= TASSEL_2 + MC_1 ; // TACTL=TA0CTL 时钟源选择SMCLK MCLK=SMCLK=TACLK=default DCO 增计数模式 TACTL |= TASSEL_1 + MC_1; // 时钟源选择ACLK时钟源 增计数模式 TACCTL0 |= OUTMOD_4; //模式4是toggle翻转模式 计数达到TACCR0输出翻转 占空比50% TACCTL1 |= OUTMOD_7; //模式7是reset/set模式 计数达到TACCR1输出0 TACCR0输出1 TACCR0 = 120-1; //模式4周期的一半 模式7的整周期PWM的周期是120 26Hz TACCR1 = 60; //模式7的占空比 PWM的初值为60 此时的占空比为50% 52Hz}
//================================================================// 函数名称 :InitializeClocks()// 函数功能 : 初始化ACLK时钟// 入口参数 :无// 出口参数 :无// ACLK时钟选择内部VLO大约12KHz 二分频后为6KHz左右 //================================================================void InitializeClocks(void){ BCSCTL1 |= DIVA_1; // ACLK/2 BCSCTL3 |= LFXT1S_2; // ACLK = VLO 内部12K的振荡器}
void main(void){ WDTCTL = WDTPW + WDTHOLD; // Stop WDT InitializeClocks(); // 初始化辅助时钟源配置
Timer0A3PWM(); __bis_SR_register(LPM3_bits); // 不使能中断P1.1 正常 while (1);}
Hardy Zhou:
如果CCR1比CCR0大,会优先执行CCR0的动作。比如设定达到CCR1是拉高PWM输出,达到CCR0时拉低,那么此时输出就会一直低。