[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灯的亮度。
/****************************************************************************
* 文 件 名: main.c
* 描 述: cc2530 定时计数器1产生1毫秒PWM,20%的占空比,led的亮度比较暗
* 可调整pwm频率和占空比来控制Led灯的亮度
****************************************************************************/
#include <ioCC2530.h> typedef unsigned char uchar;
typedef unsigned int uint; #define LED1 P1_0 // P1.0口控制LED1 /****************************************************************************
* 名 称: InitLed()
* 功 能: 设置LED灯相应的IO口
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitLed(void)
{
P1DIR |= 0x01; //P1.0定义为输出
LED1 = ; //使LED1灯上电默认为熄灭
} /****************************************************************************
* 名 称: InitT1()
* 功 能: 定时器初始化,TICKSPD 是16 MHz系统不配置时默认是2分频,即16MHz
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitT1()
{
CLKCONCMD &= ~0x40; //设置系统时钟源为32MHZ晶振
while(CLKCONSTA & 0x40); //等待晶振稳定为32M
CLKCONCMD &= ~0x07; //设置系统主时钟频率为32MHZ
CLKCONCMD |= 0x38; //时钟速度32 MHz 定时器标记输出设置[5:3]250kHz PERCFG |= 0x40; //定时器1 的IO位置 1:备用位置2
P2SEL &= ~0x10; //定时器1优先
P2DIR |= 0xC0; //第1优先级:定时器1通道2-3 P1DIR |= 0xff; //端口1为输出
P1SEL |= 0x01; //timer1 通道2映射口P1_0 T1CC2H = 0x00; //20%占空比为200us
T1CC2L = 0x32; //修改T1CC2L可调整led的亮度
T1CC0H = 0x00; //1ms的周期时钟,频率为976.516HZ
T1CC0L = 0xff;
T1CCTL2 = 0x1c; // 模式选择 通道2比较模式
T1CTL = 0x02; //250KHz 1分频
} /****************************************************************************
* 程序入口函数
****************************************************************************/
void main(void)
{
InitLed(); //调用初始化函数
InitT1(); //定时器初始化及pwm配置
while()
{
}
}
可见代码中的核心在于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] 3、ZigBee基础实验——GPIO输出控制实验-控制Led亮灭
[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] 12、ZigBee之看门狗定时器——饿了就咬人的GOOD DOG
PS:如果您觉得还不错,点个赞,让更多人受益~
@beautifulzzzz 2016-07-22 continue~
e-mail:beautifulzzzz@qq.com
sina:http://weibo.com/beautifulzzzz?is_all=1
[ZigBee] 13、ZigBee基础阶段性回顾与加深理解——用定时器1产生PWM来控制LED亮度(七色灯)的更多相关文章
- 18-ESP8266 SDK开发基础入门篇--TCP 服务器 RTOS版,串口透传,TCP客户端控制LED
https://www.cnblogs.com/yangfengwu/p/11112015.html 先规定一下协议 aa 55 02 01 F1 4C 控制LED点亮 F1 4C为CRC高位和低位 ...
- [ZigBee] 16、Zigbee协议栈应用(二)——基于OSAL的无线控制LED闪烁分析(下)
说在前面:上一篇介绍了无线LED闪烁实现的OSAL部分,本篇介绍如何实现无线数据收发及数据处理: 上一篇是用SI跟着流程查看源码,我个人认为以架构的思维去了解代码能让人更清晰 ::ZMain.c程序入 ...
- C#基础知识回顾-- 反射(3)
C#基础知识回顾-- 反射(3) 获取Type对象的构造函数: 前一篇因为篇幅问题因为篇幅太短被移除首页,反射这一块还有一篇“怎样在程序集中使用反射”, 其他没有什么可以写的了,前两篇主要是铺垫, ...
- JavaWeb开发技术基础概念回顾篇
JavaWeb开发技术基础概念回顾篇 第一章 动态网页开发技术概述 1.JSP技术:JSP是Java Server Page的缩写,指的是基于Java服务器端动态网页. 2.JSP的运行原理:当用户第 ...
- Linux基础命令回顾
前言 说到linux基础命令,网上一搜一箩筐,想学也有很多教程,如果你不幸看到此篇文章,想看就认真看完,毕竟你点进来了不是嘛? 我每次写的文章都是为了分享自己的学习成果或重要知识点,希望能帮助更多的人 ...
- java基础知识回顾之---java String final类普通方法
辞职了,最近一段时间在找工作,把在大二的时候学习java基础知识回顾下,拿出来跟大家分享,如果有问题,欢迎大家的指正. /* * 按照面向对象的思想对字符串进行功能分类. * ...
- C#基础知识回顾-- 反射(1)
C#基础知识回顾-- 反射(1) 反射(reflection)是一种允许用户获得类型信息的C#特性.术语“反射”源自于它的工作方式: Type对象映射它所代表的底层对象.对Type对象进行查询可以 ...
- C#基础知识回顾--线程传参
C#基础知识回顾--线程传参 在不传递参数情况下,一般大家都使用ThreadStart代理来连接执行函数,ThreadStart委托接收的函数不能有参数, 也不能有返回值.如果希望传递参数给执行函数, ...
- python爬虫主要就是五个模块:爬虫启动入口模块,URL管理器存放已经爬虫的URL和待爬虫URL列表,html下载器,html解析器,html输出器 同时可以掌握到urllib2的使用、bs4(BeautifulSoup)页面解析器、re正则表达式、urlparse、python基础知识回顾(set集合操作)等相关内容。
本次python爬虫百步百科,里面详细分析了爬虫的步骤,对每一步代码都有详细的注释说明,可通过本案例掌握python爬虫的特点: 1.爬虫调度入口(crawler_main.py) # coding: ...
随机推荐
- C#中的using和yield return混合使用
最近写代码为了为了省事儿用了几个yield return,因为我不想New一个List<T>或者T[]对象再往里放元素,就直接返回IEnumerable<T>了.我的代码里还有 ...
- gitlab安装过程总结
gitlab总算搭建好了,今天下午完成了第一个工程的导入. 梳理下搭建的过程: 1.下载bitnami的一键安装包,并安装 注意设置权限为777,以免出现某文件写入错误的问题 2.配置邮件服务 分别修 ...
- 子进程 已安装 pre-removal 脚本 返回了错误号 1或2 与 子进程 已安装 post-installation 脚本 返回了错误号 1或2
今天在ubuntu kylin上安装了virtualbox, 后来我想删除了再装个新一点的,结果正常的情况下删除不了,我就把找到的virtualbox的目录全部都删除了, 再通过apt-get rem ...
- jsp_内置对象_request
request内置对象是使用最多的一个对象,其主要作用是接收客户端发送来的请求信息.如请求的参数.发送的头信息等都属于客户端发送来的信息.request是javax.servlet.http.Http ...
- Android volley 当用fiddler2 抓包时隔一段时间不操作,会出现 http 408错误
出现原因是由于fiddler2导致,关闭fiddler2即可...
- hdu 5543 Pick The Sticks(动态规划)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5543 题意:给你一根长为m的长木板和一些小木棒,每一根小木棒有它的长度和价值,这些小木棒要放在长木板上 ...
- js多种切换图片
分享通过js实现多种图片切换特效,这里只有手动切换哦,自动效果需自写,效果地址:http://dwz.cn/1drD5u. 下载地址:http://***/download/index/52209 适 ...
- Linq学习工具及Lamada表达式
好东西.转载一个.以备学习 Linq学习工具: http://www.linqpad.net/ Lamada表达式: Func<int, int, int> IntPow = (x ...
- 使用getopt()处理命令行参数
假设有一程序 testopt,其命令行选项参数有: -i 选项 -l 选项 -r 选项 -n <值> 带关联值的选项 则处理 ...
- 【Java】深深跪了,OJ题目Java与C运行效率对比(附带清华北大OJ内存计算的对比)
看了园友的评论之后,我也好奇清橙OJ是怎么计算内存占用的.重新测试的情况附在原文后边. -------------------------------------- 这是切割线 ----------- ...