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的更多相关文章

  1. SAM4E单片机之旅——3、LED闪烁之定时器中断

    让一个LED灯闪烁不过瘾,我们应该让这块开发板完成一点更高难度的任务:比如让两个LED灯闪烁. …… 当然了,以我们的现在使用的空循环技术,还是可以实现这点的.但是这样显得略为低端.所以我们使用一个高 ...

  2. SAM4E单片机之旅——2、LED闪烁之轮询定时器

    之前我们使用空循环,达到了延迟的目的,但是这样子的延迟比较不精确.现在就使用实时定时器(RTT)来进行更为精确的计时.RTT虽然不是特别通用,在某些单片机上可能没有,但它较为简单. RTT内部有一个计 ...

  3. SAM4E单片机之旅——1、LED闪烁之空循环

    最近因为导师要写一本关于SAME4单片机的书籍,而我也作为一个嵌入式的初学者看了这本书.现在也让我写写几个小的程序,做做示例.既然写了文档之类的,就发到博客上来吧. 目前关于这芯片能参考的书籍大概就只 ...

  4. SAM4E单片机之旅——7、LED闪烁之TC中断

    RTT主要用做一个全局的定时器,而且不太通用.现在尝试使用一个更为通用的定时器进行定时:定时计数器(Timer Counter, TC). TC提供了广泛的功能,主要可以分为对输入的测量,以及波形的输 ...

  5. SAM4E单片机之旅——6、LED闪烁之按钮控制

    现在试试用按钮控制LED灯……让LED在一个按钮按下时亮起:弹起时灭掉. 主要目的是学习GPIO的输入及中断. 一. 电路 图中的J39-n是几个跳线插座,位置在开发板LCD附近,往下进行前要先确保跳 ...

  6. SAM4E单片机之旅——4、LED闪烁之PWM

    两个LED灯虽然可以闪了,但是总是需要CPU的参与.现在尝试使用一种更为自动化的方法:让脉宽调制(PWM)控制器输出具有一定周期和占空比的方波,以此控制LED灯的亮灭. 一.实现思路 依然使用蓝色和琥 ...

  7. SAM4E单片机之旅——23、在AS6(GCC)中使用FPU

    浮点单元(Floating Point Unit,FPU),是用于处理浮点数运算的单元. 为使用FPU,除了需要启用FPU外,还需要对编译器进行设置,以使其针对浮点运算生成特殊的指令.虽然在Atmel ...

  8. SAM4E单片机之旅——24、使用DSP库求向量数量积

    DSP(Digital Signal Processing,数字信号处理)中会使用大量的数学运算.Cortex-M4中,配置了一些强大的部件,以提高DSP能力.同时CMSIS提供了一个DSP库,提供了 ...

  9. SAM4E单片机之旅——18、通过AFEC(ADC)获取输入的电压

    很多时候,一个电压不仅仅需要定性(高电平或者低电平),而且要定量(了解具体电压的数值).这个时候就可以用到模数转换器(ADC)了.这次的内容是测量开发板搭载的滑动变阻器(VR1)的电压,然后把ADC转 ...

随机推荐

  1. Activation(hdu 4089)

    题目:仙5的激活序列.有以下4种情况: 1.注册失败,但是不影响队列顺序 ,概率为p1 2.连接失败,队首的人排到队尾,概率为p2 3.注册成功,队首离开队列,概率为p3 4.服务器崩溃,激活停止,概 ...

  2. 使用android ndk编译boost动态库

    由于以往我写过不少使用boost库开发的项目,而最近准备移植一些代码到android上(上层界面以及jni层我不管,也没研究过,现在只完成代码的移植编译,具体如何调用,由其它人负责),所以先要解决的就 ...

  3. Codeforces 597B Restaurant(离散化 + 贪心)

    题目链接 Restaurant 题目意思就是在$n$个区间内选出尽可能多的区间,使得这些区间互不相交. 我们先对这$n$个区间去重. 假如有两个区间$[l1, r1],[l2, r2]$ 若满足$l1 ...

  4. Java爬虫系列二:使用HttpClient抓取页面HTML

    爬虫要想爬取需要的信息,首先第一步就要抓取到页面html内容,然后对html进行分析,获取想要的内容.上一篇随笔<Java爬虫系列一:写在开始前>中提到了HttpClient可以抓取页面内 ...

  5. 服务器SSL/TLS快速检测工具TLLSSLed

    服务器SSL/TLS快速检测工具TLLSSLed   现在SSL和TLS被广泛应用服务器的数据加密中,如网站的HTTPS服务.所以,在渗透测试中如何快速检测服务器的SSL和TLS配置寻找安全漏洞,就显 ...

  6. ApplicationContext介绍

    如果说BeanFactory是Spring的心脏,那么ApplicationContext就是完整的身躯了.ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用 ...

  7. android_浅析canvas的save()和restore()方法

    <span style="font-size:18px;"> </span> <span style="font-size:18px;&qu ...

  8. iOS开发之分段控制器(UISegmentedControl)

    今天我们来说下iOS中的分段选择控制器UISegmentedControl,这一控件有什么作用呢 每个segment都能被点击,相当于集成了多个button 通常我们会点击不同的segment来切换不 ...

  9. 基于cucumber接口测试框架的扩展——测试框架总结之cucumber

    主要功能: 1.通过fiddler抓取请求,导出xml文件. 2.解析xml文件至excel,或者手工填写excel数据. 3.根据excel中的URL中地址生成的接口集合和feature内容模板生成 ...

  10. word中更改图片和标题之间的垂直距离

    word中插入图片后.往往须要给图片加上标题. 你插入图片和给图片插入标题时,word用的是默认的格式给你插入的图片和标题. 假如原来的paragraph是2倍行距.你的图片和标题之间的距离也是2倍行 ...