请问使用 CC2540/CC2541 定时器1 输出的 PWM 波的频率是如何设定的?公式是什么?
RT,使用的是 Modulo 模式。
频率由T1CC0决定的,频率大小为Timer1的时钟输入频率/T1CC0的值。
rtos 你好,
CLKCONCMD &= ~0x40; // 设置系统时钟源为 32MHZ晶振
while(CLKCONSTA & 0x40); // 等待晶振稳定
CLKCONCMD &= ~0x47; // 设置系统主时钟频率为 32MHZ
PERCFG = (PERCFG & ~0x40) | 0x03; // Select Timer 1 Alternative 0 location, set U1CFG and U0CFG to Alternative 1
P2DIR |= 0xC0; // Give priority to Timer 1
P0SEL |= 0x78; // Set P0.4, P0.5 and P0.6 to peripheral
T1CNTH = 0xff;
T1CNTL = 0xff;
T1CTL = 0x0e; /* mode: modulo bit[1:0]=10, div: tick/128 bit[3:2]=11 */
T1CCTL0 = 0x3c;
T1CCTL1 = 0x24;
T1CCTL2 = 0x24;
T1CCTL3 = 0x24;
T1CCTL4 = 0x24;
T1CC0L = 2500%256;
T1CC0H = 2500/256;
T1CC1L = 625%256;
T1CC1H = 625/256; /* white */
T1CC2L = 625%256;
T1CC2H = 625/256; /* green */
T1CC3L = 625%256;
T1CC3H = 625/256; /* blue */
T1CC4L = 625%256;
T1CC4H = 625/256; /* red */
按照你所说的公式,此输出的 PWM 频率应该是 32000000/128/2500=100HZ
实际值却是50HZ,请问这是如何引起了?
我的初始化如下,生成频率125K,你可以参考一下,看看有没有区别
P1DIR|= BV(0)|BV(1);
P0DIR|= BV(7);
P1SEL|= BV(0)|BV(1);
P0SEL|= BV(7);
PERCFG |= 0x40;
T1CTL = 0x00;
T1CCTL1 = 0x34;
T1CCTL2 = 0x34;
T1CCTL3 = 0x34;
T1CNTL = 0; // Reset timer to 0;
T1CC0L = 0x00; // 125K 32M/256 = 125K
T1CC0H = 0x01; //
T1CC1L = 0x80;
T1CC1H = 0x00; //
T1CC2L = 0x80;
T1CC2H = 0x00; //
T1CC3L = 0x80;
T1CC3H = 0x00;
有设定系统时钟吗?
默认的,没有设置
ok,谢谢!
如果要输出2M的PWM,你们试过么,我怎么配置都不成功,最大频率是240K左右
您好,我现在也在用cc2540产生pwm波。但是我定时器1的3和4通道都无法正常产生。无法改变占空比。而1和2通道可以正常输出。四个通道的设置是一样的。想请教一下是为什么?谢谢
CC2540系统时钟默认2分频,即16M
关掉PWM系统分频功能
CC2541定时器1有5个捕获/比较通道,首先介绍什么是捕获和比较功能。
捕获通道:
设置的捕获开始的时候,CPU 会将计数寄存器的值复制到捕获比较寄存器中并开始计数,当再次捕捉到电平变化时,这时
计数寄存器中的值减去刚才复制的值就是这段电平的持续时间,你可以设置上升沿捕获、下降沿捕获、或者上升沿下降沿
都捕获。 捕获通道可以用来测量信号的频率周期或者波形的宽度,捕获通道类似于秒表的功能。
比较通道:
这里有两个单元:一个计数器单元和一个比较单元,比较单元就是个双缓冲寄存器,比较单元的值是可以根据不同的模式
设置的,与此同时,计数器在不停的计数,并不停的与比较寄存器中的值进行比较,当计数器的值与比较寄存器的值相等
的时候一个比较匹配就发生了,根据设置,可以 产生不同的波形。对于定时器1,计数器单元就是2个8位的SFR:T1CNTH
和T1CNTL,比较单元就是2个8位的寄存器T1CCxH和T1CCxL(x:0~4)。而对于定时器3(4),计数器单元是寄存器
T3CNT(T4CNT),比较单元是寄存器T3CC0和T3CC1(T4CC0和T4CC1)。比较通道可以用来产生特定的波形,输
出 PWM波,比较通道类似于闹钟的功能。
CC2541的输入捕获功能
输入捕获功能一般用的比较少,当定时器1的某一个通道被配置为输入捕获通道,那么对应的I/O引脚则自动配置为输入, 不
需要再通过配置寄存器PxDIR设定为输入 ,在定时器开始计数后, 在外部输入信号的上升沿或者下降沿异或两个沿到来时触
发16位的计数器T1CNT的计数值装入对应通道的捕获/比较寄存器T1CCxH:T1CCxL 。注意根据沿到来的时间间隔选择合
理的定时器时 钟,假如外部信号每隔几us沿发生变化,但是定时器的时钟周期是几ms,显然捕获不到外部的沿变化。具体
应用时,可以在 中 断服务程序里把通道的捕获值T1CCxH:T1CCxL读到一个变量里,如果要测量一个信号的频率,可以将
第二次捕获的变量 减去第一次捕获的变量,得到的是信号的周期,倒数就是频率。但是有一个问题,假如说两次捕获的上升
沿(或下降沿)的时 间间隔大于时钟的周期,定时器溢出又从0x0000开始计数,那么这两次的计数值之差肯定就不对了,
所以在应用之前还得估 计一下外部信号的周期以选择合适的时钟周期,所以一般来说我们不用它来测量脉宽或者信号周期频
率。这个输入捕获功能当 做触发用特别合适,当检测到外部信号的沿变化时,在中断服务程序里完成相应的功能,比如触发
采集。
另外注意:输入捕获功能,在读取T1CCxH:T1CCxL时,必须先读取T1CCxL,再读取T1CCxH
下面重点讲解定时器 1的通道输出比较功能。
CC2541的输出比较功能:
在输出比较模式时,I/O引脚被配置为输出功能, 不 需要再通过配置寄存器PxDIR设定为输出引脚 , 在定时器开始工作后,计数
值和对应通道的捕获/比较寄存器T1CCxH:T1CCxL比较,如果两者相等,那么输出引脚就会根据T1CCTLn.CMP的配置发生
置1、清0、翻转等变化 。T1CCTLn.CMP的定义根据通道的不同也不一样,比如通道0寄存器T1CCTL1定义如下:
T1CCTL1.MODE是选择定时器1通道的模式,1:输出比较模式,0:输入捕获模式
T1CCTL1.IM是通道的中断使能标志,1:开通道中断,0:关通道中断
T1CCTL1.CAP用来选择输入捕获沿的选择, 当通道处于输出比较模式时,T1CCTL1.CAP配置为00
- 01:上升沿捕获
- 10:下降沿捕获
- 11:上升沿和下降沿都捕获
T1CCTL1.CMP是输出比较模式的选择,对于通道1来说有7种模式 ,分别为
- 000:当计数值等于T1CCxH:T1CCxL时,输出引脚置1
- 001:当计数值等于T1CCxH:T1CCxL时,输出引脚清0
- 010:当计数值等于T1CCxH:T1CCxL时,输出引脚电平翻转
- 011:在正计数/倒计数模式下,在计数增加阶段,当计数值等于T1CCxH:T1CCxL时,输出引脚置1,在计数递减阶段,当计数值等于T1CCxH:T1CCxL时,输出引脚清0
- 在其他模式下,当计数值等于T1CCxH:T1CCxL时,输出引脚置1,当计数值等于0x0000时,输出引脚清0
- 100:在正计数/倒计数模式下,在计数增加阶段,当计数值等于T1CCxH:T1CCxL时,输出引脚清0,在计数递减阶段,当计数值等于T1CCxH:T1CCxL时,输出引脚置1
- 在其他模式下,当计数值等于T1CCxH:T1CCxL时,输出引脚清0,当计数值等于0x0000时,输出引脚置1
- 101:当计数值等于T1CCxH:T1CCxL时,输出引脚置1;当计数值等于T1CC0H:T1CC0L时,输出引脚清0
- 110:当计数值等于T1CCxH:T1CCxL时,输出引脚清0;当计数值等于T1CC0H:T1CC0L时,输出引脚置1
- 111:初始化输出比较引脚
通道0的输出比较功能比较少,如下图所示,这是因为T1CC0H:T1CC0L在模式6和模式7下有特殊的功能,这就意味着这两种模式对于通道0不可用
所以要生成较复杂的波形,一般都不用通道0。
比较输出引脚会在下面两种情况下被初始化
- 往定时器计数器低字节T1CNTL 写入任何值,并且会导致计数器被清除为0x0000
- T1CCTLn.CMP设置为111
初始化值如下表,在不同模式下,初始值不同
接下来看下,定时器1在自由运行模式、模模式、正计数/倒计数模式下的输出波形
自由运行模式
我们可出,除了模式000、001、010,其他的模式输出的波形周期都是0xffff个计数时间,所以周期和定时器1的计时频率有关,也就是和T1CTL.div及CLKONCMD寄存器有关。
周期:0xffff
占空比:T1CCn/T1CC0或者1-T1CCn/T1CC0
模模式
我们可出,除了模式000、001、010,在定时器时钟频率一定的情况下,其他的模式输出的波形周期和寄存器T1CC0有关
周期:T1CC0
占空比:T1CCn/T1CC0或者1-T1CCn/T1CC0
正计数/倒计数模式
周期:2*T1CC0
占空比:010和100——T1CCn/T1CC0;011——1-T1CCn/T1CC0;101和110——(T1CC0-T1CCn)/2*T1CC0
程序编写
端口引脚初始化: 配置引脚功能为外设I/O,外设位置选择,位置优先级选择,注:无需配置引脚方向PxDIR
例子中用到引脚P1.0,定时器1的位置2位引脚P1.0为通道2
1 /****************************************************************************** 2 *函 数 名:InitPWM 3 *功 能:PWM输出口P1.0初始化 4 *入口参数:无 5 *出口参数:无 6 ******************************************************************************/ 7 void InitPWM(void) 8 { 9 P1SEL |= 0x01; //P1.0设置为外设I/O口:定时器1通道2 10 PERCFG |= (1<<6); //定时器1为外设位置2 11 P2SEL &= ~(1<<4); //优先级控制:定时器1优先 12 }
定时器初始化配置:
- 定时器1分频值,工作模式配置,寄存器T1CTL
- 定时器1通道n输入捕获/输出比较模式选择,如果用到中断,开通道n中断,寄存器T1CCTLn
- 通道1捕获/比较寄存器值配置,先低位后高位,T1CC0L和T1CC0H
- 通道n捕获/比较寄存器值配置,先低位后高位,T1CCnL和T1CCnH
- 开定时器1溢出中断,TIMIF
- 定时器1中断使能,IEN1
- 开总中断,EA
1 /****************************************************************************** 2 *函 数 名:InitT1 3 *功 能:定时器1初始化,使用通道2 4 *入口参数:无 5 *出口参数:无 6 ******************************************************************************/ 7 void InitT1(void) 8 { 9 T1CTL = 0x0f; //定时器1设置为128分频,正计数/倒计数模式 10 T1CCTL2 = 0x6c; //定时器1通道2配置为比较输出,模式101,开通道2中断 11 T1CC0L = 0x00; //定时器1通道0捕获/比较值低位 12 T1CC0H = 0x88; //定时器1通道0捕获/比较值高位 13 T1CC2L = 0x00; //定时器2通道0捕获/比较值低位 14 T1CC2H = 0x44; //定时器1通道2捕获/比较值高位 15 TIMIF &= ~(1<<6); //定时器1溢出中断使能 16 IEN1 |= (1<<1); //定时器1中断使能 17 EA = 1; //开总中断 18 }
这样就可以输出PWM波形了,对于只输出PWM波,中断是可以不用管的,不开中断什么的都可以
本例使用的定时器主时钟是32MHz,128分频,周期是2*T1CC0H:T1CC0L(2*0x8800)计时时间,为278.528ms,频率为3.59Hz,占空比为
(T1CC0-T1CCn)/2*T1CC0=25%
波形用示波器看得
另外,通过实验发现,当输出频率较高的波形时,波形失真较明显,下图是输出8MHz的波形
http://www.deyisupport.com/question_answer/wireless_connectivity/bluetooth/f/103/t/47906.aspx
http://www.cnblogs.com/chenzhao207/p/4498842.html
参考这两个帖子或文章。
这个资料也很适合楼主,可以参考下
http://www.tuicool.com/articles/y6JfAve
频率即周期的倒数。
根据定时器捕获比较值来计算的。
计算两个上升沿的时间间隔即1个周期。
假设定时器计数+1=1ms,第一次捕获时间轴为55,第二次捕获时间轴为77,则周期=(77-55)*1ms=22ms
频率f=1/22ms~=45Hz。
频率由T1CC0决定的,频率大小为Timer1的时钟输入频率/T1CC0的值。
T1CC0 决定PWM的周期, T1CC1 决定PWM的占空比
官方的程序,可以参考和移植!
3377.t4_pwm.c
参考附件的程序
编译的时候记得power saving关掉,因为需要32M晶振提供时钟
当PWM频率较高时,用PWM的硬件翻转模式输出波形,而不是在ISR中手工翻转IO
T1CC0 决定PWM的周期, T1CC1 决定PWM的占空比,T1CC1 /T1CC0 就等于占空比
频率由T1CC0决定的,频率大小为Timer1的时钟输入频率/T1CC0的值。
-
void PWM_init()
{
//设置pwm端口为输出
P0DIR|= BV(3)|BV(4)|BV(5);
//设置pwm端口为外设端口,非gpio
P0SEL|= BV(3)|BV(4)|BV(5);
//由于uart等会占用我们当前使用的pwm端口,因此需要将uart等重映射到别的端口去。
PERCFG |= 0x33; // Move USART1&2 to alternate2 location so that T1 is visible
T1CTL = 0x0e; // Div = 128, CLR, MODE = module
T1CCTL1 = 0x1c; // IM = 0; CMP = Clear output on compare; Mode = Compare
T1CCTL2 = 0x1c; // IM = 0; CMP = Clear output on compare; Mode = Compare
T1CCTL3 = 0x1c; // IM = 0, CMP = Clear output on compare; Mode = Compare
T1CNTL = 0; // Reset timer to 0;
T1CNTH = 0; // Reset timer to 0;//必须设置,否则定时器不工作
T1CCTL0 = 0x4C; // IM = 1, CMP = Clear output on compare; Mode = Compare
T1CC0H = 0x07; // Ticks = 375 (2.4ms)
T1CC0L = 0XF8; // Ticks = 375 (2.4ms)
T1CC1H = 0x03; // Ticks = 375 (1,5ms initial duty cycle)
T1CC1L = 0Xc0;
T1CC2H = 0x03; // Ticks = 375 (1,5ms initial duty cycle)
T1CC2L = 0Xc0;
T1CC3H = 0x03; // Ticks = 375 (1,5ms initial duty cycle)
T1CC3L = 0Xc0;
EA=1;
IEN1 |= 0x02; // Enable T1 cpu interrupt
}
不是很了解,前来学习的,从网上找到了步骤,不知道是不是这样的
定时器初始化配置:
- 定时器1分频值,工作模式配置,寄存器T1CTL
- 定时器1通道n输入捕获/输出比较模式选择,如果用到中断,开通道n中断,寄存器T1CCTLn
- 通道1捕获/比较寄存器值配置,先低位后高位,T1CC0L和T1CC0H
- 通道n捕获/比较寄存器值配置,先低位后高位,T1CCnL和T1CCnH
- 开定时器1溢出中断,TIMIF
- 定时器1中断使能,IEN1
- 开总中断,EA
这样就可以输出PWM波形了,对于只输出PWM波,中断是可以不用管的,不开中断什么的都可以
本例使用的定时器主时钟是32MHz,128分频,周期是2*T1CC0H:T1CC0L(2*0x8800)计时时间,为278.528ms,频率为3.59Hz,占空比为
(T1CC0-T1CCn)/2*T1CC0=25%
CC2530内部定时器有硬件PWM生成器,也就是说,你设置好相应的寄存器以后他就会自动产生,不占用内核资源。
频率由T1CC0决定的,频率大小为Timer1的时钟输入频率/T1CC0的值。
请问硬件PWM生成器和哪些寄存器有关系? 都可以通过设置寄存器修改哪些变量?
楼上都会的很详细了。PWM设置不外乎频率以及占空比。频率当然首先需要知道系统时候以及分频倍数 .了解这个简单的方法就是跑一下例程,然后修改参数后用示波器测试!
当输出频率较高的波形时,波形失真较明显,所以cc2541不适合输出高频率的波形。
是的,出来的波形如下