zoukankan      html  css  js  c++  java
  • SAM4E单片机之旅——4、LED闪烁之PWM

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

    一、实现思路

    image
    依然使用蓝色和琥珀色的LED灯。开发板上能启用四个PWM通道,每个通道能输出两个互补的方波。我们会启用其中的一个通道,然后让这个通道的两个输出分别控制一个LED灯。但是由于这两个引脚上不存在同一通道的输出,所以需要第三个引脚辅助。
    我们将使用PWM的通道0。
    1.    PWMH0输出至引脚PA0(外设A)。
    2.    PWML0输出至引脚PC0(外设B)。
    3.    引脚PD20配置为纯输入引脚。
    4.    将PC0和PD20两个引脚短接起来。
    这样就可以使这两个LED灯交替闪烁了。

    二、PWM设置

    1. 在PMC中启用PWM时钟。

      /* PMC 启用 
      * PWM的ID大于31,需要在PMC_PCER1中启用 
      */ 
      PMC->PMC_PCER1 = 1 << (ID_PWM - 32);
    2. 禁用PWM通道。
      通道在启用时不能进行完整的控制,先禁用通道。

      /* 禁用通道0,以进行配置 */ 
      PWM->PWM_DIS = PWM_DIS_CHID0;
    3. 设置时钟。
      通道选择的时钟直接或间接由主时钟分频得到。由于主时钟频率较高,所以为保证能产生肉眼可见的闪烁,这里会选择尽可能大的分频数。为对PWM的特性有更多的了解,我们将开启它的Clock A。
      通过向PWM时钟控制器的(PWM_CLK)中的PERA字段写入 9,以配置Clock A的输入时钟为MCK / 512;通过向DIVA字段写入125,再将输入时钟进行125分频。配置完成后,CLKA输出的时钟的频率即为MCK / (512 * 125)。初始化时,MCK的频率为4MHz(4000000Hz),所以CLKA输出频率即为62.5 Hz。

      /* clockA */; 
      PWM->PWM_CLK = PWM_CLK_DIVA(125) 
                      | PWM_CLK_PREA(9);
    4. 选择通道的模式。
      为简单起见,将使用默认的属性:周期为左对齐,极性为先输出低电平,不使用中断以及死区发生器。同时,在这里为通道选择时钟CLKA。

      /* 配置通道0 */ 
      PWM->PWM_CH_NUM[0].PWM_CMR = PWM_CMR_CPRE_CLKA;
    5. 配置周期和占空比。
      为观察方便,将输出脉冲方波的周期设置为2秒,占空比50%。因为使用的时钟频率为62.5Hz,所以需要将计数器的周期设置为62.5 * 2 = 125。将比较器阀值设置为63,使占空比大约为50%。

      PWM->PWM_CH_NUM[0].PWM_CPRD = PWM_CPRD_CPRD(125);   /* 周期 */ 
      PWM->PWM_CH_NUM[0].PWM_CDTY = PWM_CDTY_CDTY(63);    /* 占空比,准确来说是阀值 */
    6. 使能PWM通道。

      /* 使能 PWM */    
      PWM->PWM_ENA = PWM_ENA_CHID0;

    三、PIO设置

    在实现思路中已经说明了PIO引脚的配置,而且不是太为复杂,且后面将会给出完整代码,这里就不单独解释了。

    附 完整代码

    #include <sam.h>
    
    void ConfigPWM(void) 
    {
    	/* PMC 启用
    	 * PWM的ID大于31,需要在PMC_PCER1中启用
    	 */
    	PMC->PMC_PCER1 = 1 << (ID_PWM - 32);
    
    	/* 禁用通道0,以进行配置 */
    	PWM->PWM_DIS = PWM_DIS_CHID0;
    	
    	/* clockA */;
    	PWM->PWM_CLK = PWM_CLK_DIVA(125)
    				| PWM_CLK_PREA(9);
    	/* 配置通道0 */
    	PWM->PWM_CH_NUM[0].PWM_CMR = PWM_CMR_CPRE_CLKA	/* 计数器时钟选择为CLKA */
    				;									/* 周期左对齐,先输出低电平,不使用中断及死区发生器 */
    
    	PWM->PWM_CH_NUM[0].PWM_CPRD = PWM_CPRD_CPRD(125);   /* 周期 */
    	PWM->PWM_CH_NUM[0].PWM_CDTY = PWM_CDTY_CDTY(63);    /* 占空比,准确来说是阀值 */
    	
    	/* 使能 PWM */	
    	PWM->PWM_ENA = PWM_ENA_CHID0;
    }
    
    void ConfigPIO(void) 
    {
    	/* 引脚由外设控制 */
    	PIOA->PIO_PDR = PIO_PA0;
    	PIOC->PIO_PDR = PIO_PC0;
    	/* 选择外设 */
    	/* PIOA选择外设A(将影响PA所有引脚) */
    	PIOA->PIO_ABCDSR[0] = 0;
    	PIOA->PIO_ABCDSR[1] = 0;
    	/* PC0选择外设B */
    	PIOC->PIO_ABCDSR[0] = PIO_ABCDSR_P0;
    	PIOC->PIO_ABCDSR[1] = 0;
    	
    	/* 配置PD20为输入 */
    	PIOD->PIO_PER = PIO_PD20;
    	PIOD->PIO_ODR = PIO_PD20;
    }
    
    int main(void)
    {
    	/* Disable WDT */
    	WDT->WDT_MR = WDT_MR_WDDIS;
    	
    	ConfigPWM();
    	ConfigPIO();
    
    	while (1) {
    	}
    	return 0;
    }
  • 相关阅读:
    log4j不生成日志文件的问题
    前端得到或者改变组件的值
    取list的值
    idea Library XXXXXXXX has broken classes paths
    session.save()返回值问题
    Intellij Error:Cannot build Artifact 'XXX:war exploded' because it is included into a circular dependency
    shell小结
    python操作rabbitMQ小结
    python+rabbitMQ实现生产者和消费者模式
    Python操作rabbitmq消息队列持久化
  • 原文地址:https://www.cnblogs.com/h46incon/p/3408600.html
Copyright © 2011-2022 走看看