[ZigBee] 13、ZigBee基础阶段性回顾与加深理解——用定时器1产生PWM来控制LED亮度(七色灯)

引言:PWM对于很多软件工程师可能又熟悉又陌生,以PWM调节LED亮度为例,其本质是在每个周期都偷工减料一些,整体表现出LED欠压亮度不同的效果。像大家看到的七色彩灯其原理也类似,只是用3路PWM分别控制红、绿、蓝三种颜色的灯输出亮度,再结合混色原理表现出丰富多彩的炫光效果~

写在前面:前十几篇介绍了CC2530的一些外设的基本用法,接下来几篇拿几个例子回顾并加深一下之前的知识点,上面引言是普及、下面高能预警!

第一个例子:用定时器1产生PWM来控制LED亮度

  我们在《[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)》中讲过定时器1 是一个支持典型的定时/计数功能的独立16 位定时器,支持输入捕获,输出比较和PWM等功能。该工程就是利用定时计数器1产生1毫秒PWM,20%的占空比,用PWM来调节LED的亮度,如果led的亮度比较暗可调整pwm频率和占空比来控制Led灯的亮度。

 1 /****************************************************************************
 2 * 文 件 名: main.c
 3 * 描    述: cc2530 定时计数器1产生1毫秒PWM,20%的占空比,led的亮度比较暗
 4 *           可调整pwm频率和占空比来控制Led灯的亮度
 5 ****************************************************************************/
 6 #include <ioCC2530.h>
 7
 8 typedef unsigned char uchar;
 9 typedef unsigned int  uint;
10
11 #define LED1 P1_0       // P1.0口控制LED1
12
13
14 /****************************************************************************
15 * 名    称: InitLed()
16 * 功    能: 设置LED灯相应的IO口
17 * 入口参数: 无
18 * 出口参数: 无
19 ****************************************************************************/
20 void InitLed(void)
21 {
22     P1DIR |= 0x01;           //P1.0定义为输出
23     LED1 = 1;                //使LED1灯上电默认为熄灭
24 }
25
26 /****************************************************************************
27 * 名    称: InitT1()
28 * 功    能: 定时器初始化,TICKSPD 是16 MHz系统不配置时默认是2分频,即16MHz
29 * 入口参数: 无
30 * 出口参数: 无
31 ****************************************************************************/
32 void InitT1()
33 {
34     CLKCONCMD &= ~0x40;      //设置系统时钟源为32MHZ晶振
35     while(CLKCONSTA & 0x40); //等待晶振稳定为32M
36     CLKCONCMD &= ~0x07;      //设置系统主时钟频率为32MHZ
37     CLKCONCMD |= 0x38;       //时钟速度32 MHz 定时器标记输出设置[5:3]250kHz
38
39     PERCFG |= 0x40;          //定时器1 的IO位置   1:备用位置2
40     P2SEL &= ~0x10;          //定时器1优先
41     P2DIR |= 0xC0;           //第1优先级:定时器1通道2-3
42
43     P1DIR |= 0xff;           //端口1为输出
44     P1SEL |= 0x01;           //timer1 通道2映射口P1_0
45
46     T1CC2H = 0x00;           //20%占空比为200us
47     T1CC2L = 0x32;           //修改T1CC2L可调整led的亮度
48     T1CC0H = 0x00;           //1ms的周期时钟,频率为976.516HZ
49     T1CC0L = 0xff;
50     T1CCTL2 = 0x1c;          // 模式选择 通道2比较模式
51     T1CTL = 0x02;            //250KHz 1分频
52 }
53
54 /****************************************************************************
55 * 程序入口函数
56 ****************************************************************************/
57 void main(void)
58 {
59     InitLed();                 //调用初始化函数
60     InitT1();                //定时器初始化及pwm配置
61     while(1)
62     {
63     }
64 }

可见代码中的核心在于39~51行:

39     PERCFG |= 0x40;          //定时器1 的IO位置   1:备用位置2
40     P2SEL &= ~0x10;          //定时器1优先
41     P2DIR |= 0xC0;           //第1优先级:定时器1通道2-3
42
43     P1DIR |= 0xff;           //端口1为输出
44     P1SEL |= 0x01;           //timer1 通道2映射口P1_0
45
46     T1CC2H = 0x00;           //20%占空比为200us
47     T1CC2L = 0x32;           //修改T1CC2L可调整led的亮度
48     T1CC0H = 0x00;           //1ms的周期时钟,频率为976.516HZ
49     T1CC0L = 0xff;
50     T1CCTL2 = 0x1c;          // 模式选择 通道2比较模式
51     T1CTL = 0x02;            //250KHz 1分频

1.1、第一步:调用外设控制寄存器设置外设所映射IO引脚的方案 

其中第39行令PERCFG |= 0x40,PERCFG是外设控制寄存器,如下图该寄存器用来设置一些外设的I/O的位置。这里操作的是第六位T1CFG,选择定时器1的IO为备用位置2。

这里所说的IO映射位置方案1和方案2需要在表《Peripheral I/O Pin Mapping》中查看,在第七节《[ZigBee] 7、ZigBee之UART剖析(ONLY串口发送)》中我已经用UART的例子详细介绍如何看这个表:

以USART0为例,第一种映射关系是RT-P05\CT-P04\TX-P03\RX-P02;另一种映射关系是TX-P15\RX-P14\RT-P13\CT-P12。

那么在使用过程中,一种模式对应两种映射肯定会出现矛盾!

那么外设控制寄存器就是用来设置选择哪种方案的!这里设置为0x40即选用定时器1的引脚映射方案2:P07对应通道3、P06-通道4、P12-通道0、P11-通道1、P10-通道2~

1.2、第二步:调用Port2功能选择和Port1设备优先级控制寄存器,设置timer1占Port1引脚的外设优先级为高

在第七节《[ZigBee] 7、ZigBee之UART剖析(ONLY串口发送)》中同样有介绍,上面外设控制寄存器仅仅解决了同一个外设多个IO映射方案的冲突问题,但是并没有解决不同外设IO映射冲突问题。P2SEL寄存器就是处理这个问题!

3、4、5、6位用于设置同一个IO上两个设备当PERCFG赋值时的优先级,因此这里设置P2SEL &= ~0x10,将定时器设置为最优先。

1.3、第三步:调用Port2方向选择和Port0设备优先级控制寄存器,设置timer1占Port0引脚的外设优先级为高

在第七节《[ZigBee] 7、ZigBee之UART剖析(ONLY串口发送)》中同样有介绍,由于timer1引脚映射占了Port0和Port1,因此上面P2SEL寄存器用来设置port1部分timer所占引脚的优先级,这里调用P2DIR设置其占Port0引脚的优先级,代码中P2DIR |= 0xC0,即设置7~6位为11使定时器1通道2-3最优先。



规律:不难发现这里timer的用法和第七篇中介绍的uart初始化很类似,前三行做端口映射、优先级选定,一般外设会涉及两个端口,因此需要用P0SEL和P2DIR分别设置。接下来就是针对具体外设的参数设置了!



1.4、第四步:选择PWM通道,并使能

在1.1中介绍定时器1的引脚映射方案选用是备用2方案:P07对应通道3、P06-通道4、P12-通道0、P11-通道1、P10-通道2~

在1.3中设置通道2、3优先级最高

从1.1~1.3为timer1的PWM的的初始化,也设置了通道的优先级,如果想使能通道还需要进一步设置:

43     P1DIR |= 0xff;           //端口1为输出
44     P1SEL |= 0x01;           //timer1 通道2映射口P1_0

其中第43行设置端口1为全部输出,第44行比较关键,用来将IO引脚设置为普通IO引脚还是设置成IO外设引脚,这里将P1_0设置为外设引脚。根据前面的设置,我们知道是将P10设置为了定时器1的通道2输出口。

1.5、定时器1通道2输出比较模式选择&设置周期与占空比

关于输出比较模式在《[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)》里的第9段介绍比较详细:PWM 输出可以通过选择定时器正计数/倒计数模式生成。根据PWM 信号所需的极性选择通道输出比较模式4 或5(由T1CCTLn.CMP 位定义,其中n 是1 或2)。PWM 信号的周期由T1CC0 确定,通道输出的占空比由T1CCn 确定,其中n 是PWM 通道1 或2。某些类型的电机驱动应用程序会需要中心对齐的PWM 模式,一般地这比边沿对齐的PWM 模式产生的噪音更少,因为I/O 引脚传输不集中在同一个时钟边沿上。

46     T1CC2H = 0x00;           //20%占空比为200us
47     T1CC2L = 0x32;           //修改T1CC2L可调整led的亮度
48     T1CC0H = 0x00;           //1ms的周期时钟,频率为976.516HZ
49     T1CC0L = 0xff;
50     T1CCTL2 = 0x1c;          // 模式选择 通道2比较模式
51     T1CTL = 0x02;            //250KHz 1分频

其中第50行用来设置定时器1通道2捕获/比较控制寄存器为0x1C,[5:3]=011则选择了输出比较模式4,其PWM信号周期由T1CC0决定,占空比由T1CCn确定(正计数到计数模式生成PWM比边沿模式生成PWM更适合这里,如果你听不懂这句话请看第5篇)!因此,46~49行就是设置PWM的周期和占空比~

  



注意:这里0x0032/0x00ff不等于20%,为什么注释中说占空比为20%呢?我们用一个简单的例子解释这个问题的特殊性(绘制定时器counter的值变化线如下):左边的一个设T1CC0=4,T1CC2=2,显然占空比不是2/4,也不是3/9,因为最后一个绿色框内的时期属于下一个周期了,一个完整周期应该为0~4~1,因此占空比为3/8;同理右边的占空比为3/6。这里T1CC2设置为0x0032,则低段有:0~0x0032,0x0032~1,总共(0x0032-0+1)+(0x0032-1+1)=0x0032*2+1=0x0065=101;总周期为0x00FF*2=0x01FE=510,占空比为0x65/0x01FE约等于5



其中最后一行T1CTL = 0x02,用来设置自由运行模式(关于模式也在第七篇介绍),采用1分频,250KHz~

总结:这样就能用PWM输出通道2直接关联到P10来控制LED的亮度,简单有效~

Zigbee系列文章:

[ZigBee] 1、 ZigBee简介

[ZigBee] 2、 ZigBee开发环境搭建

[ZigBee] 3、ZigBee基础实验——GPIO输出控制实验-控制Led亮灭

[ZigBee] 4、ZigBee基础实验——中断

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

[ZigBee] 6、ZigBee基础实验——定时器3和定时器4(8 位定时器)

[ZigBee] 7、ZigBee之UART剖析(ONLY串口发送)

[ZigBee] 8、ZigBee之UART剖析·二(串口收发)

[ZigBee] 9、ZigBee之AD剖析——AD采集CC2530温度串口显示

[ZigBee] 10、ZigBee之睡眠定时器

[ZigBee] 11、ZigBee之睡眠定时器二

[ZigBee] 12、ZigBee之看门狗定时器——饿了就咬人的GOOD DOG

PS:如果您觉得还不错,点个赞,让更多人受益~

@beautifulzzzz 2016-07-22 continue~  
e-mail:[email protected] 
sina:http://weibo.com/beautifulzzzz?is_all=1

时间: 2024-10-12 03:53:23

[ZigBee] 13、ZigBee基础阶段性回顾与加深理解——用定时器1产生PWM来控制LED亮度(七色灯)的相关文章

[ZigBee] 16、Zigbee协议栈应用(二)——基于OSAL的无线控制LED闪烁分析(下)

说在前面:上一篇介绍了无线LED闪烁实现的OSAL部分,本篇介绍如何实现无线数据收发及数据处理: 上一篇是用SI跟着流程查看源码,我个人认为以架构的思维去了解代码能让人更清晰 ::ZMain.c程序入口文件 这里chipcon_cstartup.s51是汇编的启动文件,ZMain.c相当于main文件,里面有main函数: 1 int main( void ) 2 { 3 osal_int_disable( INTS_ALL );// Turn off interrupts 关中断 4 HAL_

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

1.定时器1概述 定时器1 是一个支持典型的定时/计数功能的独立16 位定时器,支持输入捕获,输出比较和PWM等功能.定时器有五个独立的捕获/比较通道.每个通道定时器要使用一个I/O 引脚.定时器用于范围广泛的控制和测量应用,可用的五个通道的正计数/倒计数模式将允许诸如电机控制应用的实现. 定时器1 的功能如下: • 五个捕获/比较通道• 上升沿.下降沿或任何边沿的输入捕获• 设置.清除或切换输出比较• 自由运行.模或正计数/倒计数操作• 可被1,8,32 或128 整除的时钟分频器• 在每个捕

[ZigBee] 3、ZigBee基础实验——GPIO输出控制实验-控制Led亮灭

1.CC2530的IO口概述 CC2530芯片有21 个数字输入/输出引脚,可以配置为通用数字I/O 或外设I/O 信号,配置为连接到ADC.定时器或USART外设.这些I/O 口的用途可以通过一系列寄存器配置,由用户软件加以实现. I/O 端口具备如下重要特性:    ?? 21 个数字I/O 引脚 ?? 可以配置为通用I/O 或外部设备I/O ?? 输入口具备上拉或下拉能力 ?? 具有外部中断能力. 21 个I/O 引脚都可以用作于外部中断源输入口.因此如果需要外部设备可以产生中断.外部中断

ZigBee入门之基础概念3

第三讲: zigbee术语 射频收发器:如cc2420 一个节点可以对应多个设备 一个设备包含多个端点 每个端点又有很多群集(输出群集.输入群集) 每个群集有一个或多个属性 属性 Attribute 是一个反映物理数量或状态的数据值,比如开关值(On/Off) ,温度值.百 分比等. 群集(簇) Cluster 是包含一个或多个属性(attribute)的群组.简单的说,群集就是属性的集合. 每个群集都被分配一个唯一的群集 ID 且每个群集最多有 65536 个属性 设备描述 Device De

「ZigBee模块」基础实验(5)串口通讯

一.补充基础知识 在CC2530 中,USART0 和USART1 是串行通信接口,它们能够分别运行于异步USART 模式或者同步SPI 模式.两个USART 的功能是一样的,并且各自有单独的IO 引脚.USART里面的A指的就是asynchronous(异步),S指的是synchronous(同步).这里我们使用异步通信方式. UART模式特征: ·一次传8或9个比特的数据 ·奇校验.偶校验或者无校验位 ·配置起始位和停止位点平 ·配置LSB或者MSB首先传送 ·独立收发中断 ·独立收发DMA

java基础知识回顾之java Thread类学习(六)--java多线程同步函数用的锁

1.验证同步函数使用的锁----普通方法使用的锁 思路:创建两个线程,同时操作同一个资源,还是用卖票的例子来验证.创建好两个线程t1,t2,t1线程走同步代码块操作tickets,t2,线程走同步函数封装的代码操作tickets,同步代码块中的锁我们可以指定.假设我们事先不知道同步函数用的是什么锁:如果在同步代码块中指定的某个锁(测试)和同步函数用的锁相同,就不会出现线程安全问题,如果锁不相同,就会发生线程安全问题. 看下面的代码:t1线程用的同步锁是obj,t2线程在操作同步函数的资源,假设不

java基础知识回顾之关键字

其实java中的常用关键字并不多,总共加起来也没有多少个,具体见如下这张表: private,protect,public 在java中,在类,类的属性和累的方法前面加上一个修饰符来对其进行访问权限上的控制.除了使用private,protect,public之外, 还有一种是default情况,即使不加任何权限修饰符.关于这四中情况的权限差别见下表: 注意:default不是修饰符,他表示一种不加任何修饰符的情况. 这里,主要看一看static,instanceof,final关键字的含义和如

JS基础知识回顾:引用类型(二)

ECMAScript中的Date类型是在早期Java中的java.util.Date类基础上构建的. 因此,Date类型使用自UTC(Coordinated Universal Time,国际协调时间)1970年1月1日午夜零点开始经过的毫秒数来保存日期. 在使用这种数据存储格式的条件下,Date类型保存的日期能够精确到1970年1月1日或之后的285616年. 要创建一个日期对象,使用new操作符和Date构造函数即可:var now=new Date(); 在调用Date构造函数而不传递参数

java基础知识回顾之java集合类-Properties集合

/** java.lang.Object   |--java.util.Dictionary<K,V>      |--java.util.Hashtable<Object,Object>          |--java.util.Properties * @author Administrator *Properties集合:         * 特点:         * 1,该集合中的键和值都是字符串类型.         * 2,集合中的数据可以保存到流中,或者从流加载