SAM4E单片机之旅——5、LED呼吸和PWM
PWM在高频情况下,一个很好的用处就是通过控制占空比来控制输出的功率,比如控制风扇转速、LED灯的亮度等。这次就利用PWM的中断功能,动态改变脉冲的占空比,来实现呼吸灯的效果。
一、实现思路
PWM可以选择让计数器在周期结束产生中断(在周期中央对齐时,可能选择在周期中央也产生中断),并且可以在运行的时候动态地调整占空比、周期、极性等属性。所以可以在中断处理函数中动态地改变占空比以改变LED灯的亮度。
这次也将使用通道0和引脚PA0。
二、PWM设置
这里需要用到较高频率的时钟,所以选择使用主时钟经32分频后的时钟(12.5 kHz)。计数器周期为400,即输出脉冲频率为125000/400 = 312.5 Hz。同时需要使能相应的中断。
PWM的主要配置代码如下:
- #define PERIOD_VALUE 400
- /* 时钟选择 */
- PWM->PWM_CH_NUM[0].PWM_CMR = PWM_CMR_CPRE_MCK_DIV_32;
- /* 启用中断 */
- PWM->PWM_IER1 = PWM_IER1_CHID0;
- /* 周期及占空比 */
- PWM->PWM_CH_NUM[0].PWM_CPRD= PWM_CPRD_CPRD(PERIOD_VALUE);
- PWM->PWM_CH_NUM[0].PWM_CDTY = PWM_CDTY_CDTY(0);
- /* 使能中断 */
- NVIC_ClearPendingIRQ(PWM_IRQn);
- NVIC_SetPriority(PWM_IRQn, 0);
- NVIC_EnableIRQ(PWM_IRQn);
三、PWM中断处理
在每个周期结束后,会产生一个中断。然后在中断处理函数中,改变占空比。需要注意的是,在PWM使能时,需要通过写入PWM占空比修改寄存器(PWM_CDTYUPD)来改变占空比。默认情况下,该修改在下一个周期生效。
为得到更好的效果,可以在两次呼吸之间设置一断间隔。
注意,需要通过读取PWM_ISR1来拉低产生的中断。中断处理函数在后面的完整代码中贴出。
附 完整代码
- #include <sam.h>
- #define PERIOD_VALUE 400
- #define BREATH_INTERVAL_PERIOD 200 /* 两次呼吸间隔的周期 */
- void ConfigPWM(void)
- {
- /* PMC 启用
- * PWM的ID大于31,需要在PMC_PCER1中启用
- */
- PMC->PMC_PCER1 = 1 << (ID_PWM - 32);
- /* 禁用通道0,以进行配置 */
- PWM->PWM_DIS = PWM_DIS_CHID0;
- /* 配置通道0 */
- PWM->PWM_CH_NUM[0].PWM_CMR =
- PWM_CMR_CPRE_MCK_DIV_32 /* 计数器时钟选择为CLKA */
- ; /* 周期左对齐,先输出低电平,不使用死区发生器 */
- /* 启用中断 */
- PWM->PWM_IER1 = PWM_IER1_CHID0;
- PWM->PWM_CH_NUM[0].PWM_CPRD = PWM_CPRD_CPRD(PERIOD_VALUE); /* 周期 */
- PWM->PWM_CH_NUM[0].PWM_CDTY = PWM_CDTY_CDTY(0); /* 占空比,准确来说是阀值 */
- /* 使能中断 */
- NVIC_ClearPendingIRQ(PWM_IRQn);
- NVIC_SetPriority(PWM_IRQn, 0);
- NVIC_EnableIRQ(PWM_IRQn);
- /* 使能 PWM */
- PWM->PWM_ENA = PWM_ENA_CHID0;
- }
- /* PWM 中断处理函数 */
- void PWM_Handler(void)
- {
- static uint32_t ul_duty = 0; /* PWM 占空比*/
- static uint8_t fade_in = 1; /* LED 淡入标志 */
- static uint8_t dark_period = 0; /* LED 完全暗下来的周期 */
- /* 读取PWM_ISR1,同时可以拉低中断 */
- uint32_t events = PWM->PWM_ISR1;
- /* 先确定是否是指定的中断 */
- if ((events & PWM_ISR1_CHID0) != 0)
- {
- if (dark_period != 0)
- {
- dark_period--;
- return;
- }
- /* 淡入 */
- if (fade_in)
- {
- ul_duty++;
- if (ul_duty == PERIOD_VALUE)
- {
- fade_in = 0;
- }
- }
- else
- {
- /* 淡出 */
- ul_duty--;
- if (ul_duty == 0)
- {
- fade_in = 1;
- /* LED暗下来一定的周期再淡入 */
- dark_period = BREATH_INTERVAL_PERIOD;
- }
- }
- /* 设置新的占空比 */
- PWM->PWM_CH_NUM[0].PWM_CDTYUPD = PWM_CDTY_CDTY(ul_duty);
- }
- }
- void ConfigPIO(void)
- {
- /* 引脚由外设控制 */
- PIOA->PIO_PDR = PIO_PA0;
- /* 选择外设 */
- /* PIOA选择外设A(将影响PA所有引脚) */
- PIOA->PIO_ABCDSR[0] = 0;
- PIOA->PIO_ABCDSR[1] = 0;
- }
- int main(void)
- {
- /* Disable WDT */
- WDT->WDT_MR = WDT_MR_WDDIS;
- ConfigPWM();
- ConfigPIO();
- while (1) {
- }
- return 0;
- }
SAM4E单片机之旅——5、LED呼吸和PWM的更多相关文章
- SAM4E单片机之旅——3、LED闪烁之定时器中断
让一个LED灯闪烁不过瘾,我们应该让这块开发板完成一点更高难度的任务:比如让两个LED灯闪烁. …… 当然了,以我们的现在使用的空循环技术,还是可以实现这点的.但是这样显得略为低端.所以我们使用一个高 ...
- SAM4E单片机之旅——2、LED闪烁之轮询定时器
之前我们使用空循环,达到了延迟的目的,但是这样子的延迟比较不精确.现在就使用实时定时器(RTT)来进行更为精确的计时.RTT虽然不是特别通用,在某些单片机上可能没有,但它较为简单. RTT内部有一个计 ...
- SAM4E单片机之旅——1、LED闪烁之空循环
最近因为导师要写一本关于SAME4单片机的书籍,而我也作为一个嵌入式的初学者看了这本书.现在也让我写写几个小的程序,做做示例.既然写了文档之类的,就发到博客上来吧. 目前关于这芯片能参考的书籍大概就只 ...
- SAM4E单片机之旅——7、LED闪烁之TC中断
RTT主要用做一个全局的定时器,而且不太通用.现在尝试使用一个更为通用的定时器进行定时:定时计数器(Timer Counter, TC). TC提供了广泛的功能,主要可以分为对输入的测量,以及波形的输 ...
- SAM4E单片机之旅——6、LED闪烁之按钮控制
现在试试用按钮控制LED灯……让LED在一个按钮按下时亮起:弹起时灭掉. 主要目的是学习GPIO的输入及中断. 一. 电路 图中的J39-n是几个跳线插座,位置在开发板LCD附近,往下进行前要先确保跳 ...
- SAM4E单片机之旅——4、LED闪烁之PWM
两个LED灯虽然可以闪了,但是总是需要CPU的参与.现在尝试使用一种更为自动化的方法:让脉宽调制(PWM)控制器输出具有一定周期和占空比的方波,以此控制LED灯的亮灭. 一.实现思路 依然使用蓝色和琥 ...
- SAM4E单片机之旅——23、在AS6(GCC)中使用FPU
浮点单元(Floating Point Unit,FPU),是用于处理浮点数运算的单元. 为使用FPU,除了需要启用FPU外,还需要对编译器进行设置,以使其针对浮点运算生成特殊的指令.虽然在Atmel ...
- SAM4E单片机之旅——24、使用DSP库求向量数量积
DSP(Digital Signal Processing,数字信号处理)中会使用大量的数学运算.Cortex-M4中,配置了一些强大的部件,以提高DSP能力.同时CMSIS提供了一个DSP库,提供了 ...
- SAM4E单片机之旅——18、通过AFEC(ADC)获取输入的电压
很多时候,一个电压不仅仅需要定性(高电平或者低电平),而且要定量(了解具体电压的数值).这个时候就可以用到模数转换器(ADC)了.这次的内容是测量开发板搭载的滑动变阻器(VR1)的电压,然后把ADC转 ...
随机推荐
- 【Codevs1034】家园(最大流,裂点)
题意:由于人类对自然的疯狂破坏,人们意识到在大约2300年之后,地球不能再居住了,于是在月球上建立了新的绿地,以便在需要时移民.令人意想不到的是,2177年冬由于未知的原因,地球环境发生了连锁崩溃,人 ...
- 诡异的malloc函数和%S的输出
今天测试代码过程中无意间发现,代码如下: #include <stdio.h> #include <string.h> #include <stdlib.h> #d ...
- 微信JSSDK分享功能详解
本文以微信分享到朋友圈,分享给微信好友为例为参考,进行调用测试,想添加其他的功能,自行查看开发人员文档即可 工欲善其事,必先利其器,好好利用下边的帮助工具,都是腾讯给开发人员的工具 1.微信开发者说明 ...
- 十六进制字符串jpg图片互转
十六制字符串jpg图片互转(格式:FFD8FFE000104A******)如:FFD8FFE000104A46494600010100000100010000FFDB0043000806060706 ...
- js-在url后面添加时间戳清除浏览器打开页面的缓存
这个解决办法还是在网上搜出来的,我还没有测试呢: 我有想既然可以添加时间戳,那可以添加随机数吗?我感觉是可以的,尽管没有测试过. 2018-3-13 几天前我就这个问题询问过我们的后台,加时间戳能否真 ...
- 网络入侵检测规避工具fragrouter
网络入侵检测规避工具fragrouter 网络入侵检测系统可以通过拦截数据包,获取内容进而判断是否为恶意数据包.对于传输较大的数据包,通常会采用分片的方式,将大数据包拆分为小数据包进行传输.如果入 ...
- Light oj 1134 - Be Efficient (前缀和)
题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1134 题意: 给你n个数,问你多少个连续的数的和是m的倍数. 思路: 前缀和取 ...
- python装饰器的深度探究
1.讲装饰器一般讲到这种代码就可以了,但这篇博客会介绍更多: def deco(func): def wrapper(): print("start") func() #调用函数 ...
- linux 用户管理命令学习
groupadd www-data 添加组 useradd phpcomposer -g www-data 添加用户并加入组中 passwd phpcomposer 添加密码 usermod -g p ...
- ORACLE MOS 翻译
http://blog.csdn.net/msdnchina/article/details/53174196