风筝
发表于: 2018-8-25 17:26:42 | 显示全部楼层

本篇文章主要介绍了使用Atmel的SAM4S Xplained Pro开发板产生脉冲宽度调制PWM信号时需要了解的所有信息。


所需的硬件/软件

●    SAM4S Xplained Pro评估套件

●    Atmel Studio


了解PWM

本文旨在探讨通过低通滤波脉冲宽度调制信号实现数模转换的技术。当遇到以下情况时应该考虑使用PWM DAC:

1.    你不能或者真的不想使用外部DAC或带有集成DAC的微控制器,

2.    PWM硬件提供适合您应用的DAC分辨率,

3.    您的数字电源电压准确且可预测,并且

4.    您可以通过基本的RC低通滤波器实现可接受的输出纹波和建立时间。


我们已经涵盖了这个主题的理论方面,现在是时候将理论付诸实践,然后看看一些现实生活中的结果。为此,我们将使用SAM4S Xplained Pro评估套件。我们还将使用PROTO1和I / O1扩展板,两者都是其中包括SAM4S Xplained Pro入门套件。实际上,对于这个项目,扩展板是方便的,而不是必需的;如果您拥有的是SAM4S板,您可以使用面包板或其他东西安装低通电路。

在我们将PWM信号转换为数字控制模拟电压之前,我们需要生成PWM信号,在我看来,这并不像人们预期的那样简单。在我看来,Atmel软件框架(ASF)的PWM部分有些记录不足,在实际看到预期引脚上的预期PWM波形之前​​,您需要了解各种细节。因此,我们将用本文的其余部分来掌握PWM接口,在下一篇文章中,我们将结合DAC功能。


将信号连接到引脚

SAM4S板上的微控制器支持四个独立的PWM通道;每个通道都有互补输出,因此我们总共有多达8个PWM信号。 SAM4S Xplained Pro用户指南告诉我们其中两个信号包含在标准扩展标头引脚排列中:


在这个项目中,我们不需要互补信号,所以我们只使用引脚7。如果您使用的是PROTO1扩展板,则此引脚方便地标记为“PWM +”;如果没有,您可以轻松找到EXT1标头上的7号针脚。

PWMDAC3_photo1.jpg


PWMDAC3_photo2.jpg


如果我们看看EXT1的引脚排列,我们看到引脚7给出了PWM通道0的正(即非反相)信号,驱动该信号的端口引脚是PA23:

PWMDAC3_datasheet2.jpg


那么我们如何告诉微控制器在引脚PA23上驱动PWM信号?为此,我们需要两件事:一个为引脚分配名称的预处理器定义,以及对pio_configure_pin()的调用。在这一点上,我们有足够的信息用于第一个:

  1. #define PWM_DAC IOPORT_CREATE_PIN(PIOA, 23)
复制代码

IOPORT_CREATE_PIN宏允许我们将名称“PWM_DAC”连接到并行输入/输出控制器A的引脚23.现在我们必须配置PWM_DAC引脚,使其用作外设功能而不是通用I / O,此外,我们需要为正确的外围线配置它。每个引脚最多可连接四个外设信号;这些被称为外围设备A,B,C和D. SAM4S系列数据表的表39-2(第955页)告诉我们我们需要的四个中的哪一个:

PWMDAC3_datasheet3.jpg

现在我们可以正确地调用pio_configure_pin():

  1. pio_configure_pin(PWM_DAC, PIO_TYPE_PIO_PERIPH_B);
复制代码

PWM时钟

接下来我们需要做的是配置驱动PWM硬件的时钟。 PWM模块支持从可编程分频器(称为A和B)得到的两个时钟,但我们只需要一个,因此我们将禁用时钟B.PWM时钟源自微控制器的外设时钟。我们不需要讨论时钟硬件的细节,因为ASF为我们处理低级配置;但是,如果您感兴趣,可以参考SAM4S系列数据表中的第957页。

时钟配置过程的第一步是为PWM硬件启用外设时钟:

  1. pmc_enable_periph_clk(ID_PWM);
复制代码

现在我们使用“pwm_clock_t”结构来设置时钟速度速度;此结构在“pwm.h”头文件中定义如下:

  1. /** Input parameters when initializing PWM */
  2. typedef struct {
  3.         /** Frequency of clock A in Hz (set 0 to turn it off) */
  4.         uint32_t ul_clka;
  5.         /** Frequency of clock B in Hz (set 0 to turn it off) */
  6.         uint32_t ul_clkb;
  7.         /** Frequency of master clock in Hz */
  8.         uint32_t ul_mck;
  9. } pwm_clock_t;
复制代码

这是一个示例配置:      

  1. pwm_clock_t PWMDAC_clock_config =
  2. {
  3.         .ul_clka = 1000000,
  4.         .ul_clkb = 0,
  5.         .ul_mck = sysclk_get_cpu_hz()
  6. };
复制代码

这里我们将时钟A设置为1 MHZ;时钟B被禁用。我们通过调用sysclk_get_cpu_hz()来提供主时钟频率。要应用此配置,我们使用pwm_init()函数:

  1. pwm_init(PWM, &PWMDAC_clock_config);
复制代码

PWM选项

我们快完成了 - 我们只需要配置PWM通道本身然后启用通道。 ASF使PWM配置相当方便:“pwm_channel_t”类型的结构体使我们能够访问各种选项,然后将该结构体的地址传递给pwm_channel_init()函数。

  1. pwm_channel_instance.channel = PWM_CHANNEL_0;
  2. pwm_channel_instance.ul_prescaler = PWM_CMR_CPRE_CLKA;
  3. pwm_channel_instance.polarity = PWM_HIGH;
  4. pwm_channel_instance.alignment = PWM_ALIGN_LEFT;
  5. pwm_channel_instance.ul_period = 20;
  6. pwm_channel_instance.ul_duty = 5;
复制代码

●    pwm_channel_instance.channel:我们正在使用频道0。

●    pwm_channel_instance.ul_prescaler:我们需要选择时钟源; PWM_CMR_CPRE_CLKA对应于时钟A.

●    pwm_channel_instance.polarity:如果设置为PWM_HIGH,则“ul_duty”值定义信号的逻辑高部分的宽度(换句话说,逻辑高是活动状态);如果它设置为PWM_LOW,则“ul_duty”值定义信号的逻辑低部分的宽度。

●    pwm_channel_instance.alignment:有关左对齐模式与中心对齐模式的详细信息,请参阅SAM4S系列数据手册中的第960-961页。一般来说,你想要左对齐模式;当您需要两个不重叠的PWM波形时,中心对齐模式非常有用。这些设置之间最明显的区别是从左对齐模式更改为中心对齐模式将导致PWM周期和活动状态脉冲宽度增加2倍。

●    pwm_channel_instance.ul_period:ASF文档将结构的这个成员描述为“周期循环值”,这与您将很容易找到的关于如何处理ul_period的信息一样多。这是一个实际有用的描述:ul_period以时钟周期为单位定义PWM周期的持续时间。在本例中,我们选择时钟A作为PWM通道的时钟源,并将时钟A配置为1 MHz的频率。因此,ul_period的单位是1μs时钟周期。上面给出的示例代码具有pwm_channel_instance.ul_period = 20,这意味着PWM周期为20×1μs=20μs。

●    pwm_channel_instance.ul_duty:不要让成员标识符欺骗你:这不会定义占空比。占空比是有效状态脉冲宽度除以周期,通常表示为百分比。相反,ul_duty是脉冲的持续时间,同样以时钟周期为单位。在上面的例子中,我们有pwm_channel_instance.ul_duty = 5;因此,有源状态脉冲宽度将是5×1μs=5μs,其对应于(5μs)/(20μs)= 25%的占空比。

●    现在我们通过调用pwm_channel_init()来应用配置,之后我们准备使用pwm_channel_enable()启用通道。


结论

让我们看一下不同PWM配置的一些示波器测量。我们将从上面代码摘录中给出的配置开始:时钟源= 1 MHz,极性polarity = PWM_HIGH,对齐alignment = PWM_ALIGN_LEFT,ul_period = 20,ul_duty = 5。请注意,相关的时序特性显示在右侧范围捕获。

PWMDAC3_scope1.jpg

如果我们保持相同的参数,除了切换polarity极性= PWM_LOW,我们得到这个波形:

PWMDAC3_scope2.jpg

如果我们回到PWM_HIGH然后更改为alignment = PWM_ALIGN_CENTER,我们会看到以下波形:

PWMDAC3_scope3.jpg

下一个波是回到左对齐模式,然后将ul_duty增加到10:

PWMDAC3_scope4.jpg

以下是将ul_period增加到30的波形:

PWMDAC3_scope5.jpg

最后,以下波形是相同的参数(ul_duty = 10,ul_period = 30),不同的是将时钟A的频率增加到10 MHz。

PWMDAC3_scope7.jpg


下面列出了“main.c”的所有代码。在下一篇文章中,我们将使用PWM专业知识来探索PWM数模转换。

  1. #include <asf.h>

  2. #define PWM_DAC IOPORT_CREATE_PIN(PIOA, 23)

  3. pwm_channel_t pwm_channel_instance;

  4. int main (void)
  5. {
  6.         //clock configuration and initialization
  7.         sysclk_init();
  8.        
  9.         /*Disable the watchdog timer and configure/initialize
  10.         port pins connected to various components incorporated
  11.         into the SAM4S Xplained development platform, e.g., the
  12.         NAND flash, the OLED interface, the LEDs, the SW0 pushbutton.*/  
  13.         board_init();
  14.        
  15.         //connect peripheral B to pin A23
  16.         pio_configure_pin(PWM_DAC, PIO_TYPE_PIO_PERIPH_B);

  17.         //enable the peripheral clock for the PWM hardware
  18.         pmc_enable_periph_clk(ID_PWM);

  19.         //disable the channel until it is properly configured
  20.         pwm_channel_disable(PWM, PWM_CHANNEL_0);

  21.         //PWM clock configuration
  22.         pwm_clock_t PWMDAC_clock_config =
  23.         {
  24.                 .ul_clka = 1000000,
  25.                 .ul_clkb = 0,
  26.                 .ul_mck = sysclk_get_cpu_hz()
  27.         };
  28.        
  29.         //apply the clock configuration
  30.         pwm_init(PWM, &PWMDAC_clock_config);
  31.        
  32.         //see the article for details
  33.         pwm_channel_instance.channel = PWM_CHANNEL_0;
  34.         pwm_channel_instance.ul_prescaler = PWM_CMR_CPRE_CLKA;
  35.         pwm_channel_instance.polarity = PWM_HIGH;
  36.         pwm_channel_instance.alignment = PWM_ALIGN_LEFT;
  37.         pwm_channel_instance.ul_period = 20;
  38.         pwm_channel_instance.ul_duty = 5;
  39.        
  40.         //apply the channel configuration
  41.         pwm_channel_init(PWM, &pwm_channel_instance);
  42.        
  43.         //configuration is complete, so enable the channel
  44.         pwm_channel_enable(PWM, PWM_CHANNEL_0);
  45.        
  46.         while(1);
  47. }
复制代码

跳转到指定楼层
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 28 | 回复: 31



手机版|

GMT+8, 2024-4-26 07:03 , Processed in 0.056864 second(s), 9 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

快速回复 返回顶部 返回列表