查看: 6307|回复: 9

Arduino Leonardo 可调频高速PWM的实现

[复制链接]
  • TA的每日心情
    奋斗
    2019-3-20 18:16
  • 签到天数: 141 天

    [LV.7]常住居民III

    发表于 2016-11-9 23:41 | 显示全部楼层 |阅读模式
    本帖最后由 希岩 于 2016-11-10 23:58 编辑

        Leonardo是一款很好用的开发板。用到了ATmel公司的ATMEGA32U4芯片,具有USB功能和高速PWM功能。
        查看网上讲的实现PWM过程也比较简单,可以说非常简单,如下所示:
    #include "Arduino.h"
    char pin1 = 9; // 3,5,6,9,10,11,13 均为PWM口
    char pin2 = 5; //5


    void setup()
    {
        pinMode(pin1, OUTPUT);  
        pinMode(pin2, OUTPUT);  
        //tone(pin2,100000);  
        analogWrite(pin1, 50);      //占空比20/255  频率500HZ
        analogWrite(pin2, 90);      //占空比90/255  频率500HZ

    }   

    void loop()
    {
      //none

    }

    图1 标准PWM

    图1 标准PWM

    其效果如图1所示,频率竟然只有500HZ,非常慢,可以调节占空比。但是觉得功能太差,用在我的Leonardo上 。看到参考中有tone这个函数,非常好,我就试了一下,程序如下,也非常简单;#include "Arduino.h"
    char pin1 = 9; // 3,5,6,9,10,11,13 均为PWM口
    char pin2 = 5; //5端口


    void setup()
    {
        pinMode(pin1, OUTPUT);  
        pinMode(pin2, OUTPUT);  
        tone(pin2,100000);            //频率100kHz
        analogWrite(pin1, 50);      //占空比20/255  频率500HZ
        //analogWrite(pin2, 90);      //占空比90/255  频率500HZ

    }   

    void loop()
    {

      //none

    }

    图2 调频PWM

    图2 调频PWM

    调试结果如图2所示。1通道用的是数字9 ,2通道用的是数字5,可以看出,2通道频率到了10kHz。

    图3 调频PWM

    图3 调频PWM

    但是再往上就有问题了,如图3所示,最高只能到34.33kHz,你在逗我吗?这是Leonardo的高速PWM吗?显然不是,因此我决定自己写一个函数来初始化高速的PWM通道。

    图4 高速PWM流程

    图4 高速PWM流程

    根据图4所示数据手册给出的初始化PWM流程,对Atmega32u4 高速PWM进行初始化。本例采用初始化数字5端口和数字13引脚,这两个相位相反。我就给出了我的程序,对初学者来讲,不用管程序内容,只需要学会调用和给合适的参数。
    程序完全给出,也非常简单:

    kittenblock中小学创客名师推荐的图形化编程软件

    /*================================================================
     * 晶振16Mhz
     * 平台:Leonardo(ATMEGA32U4)
     * 编译器:Arduino IDE1.6.8
     *                                    ——设计:ChenYannan 2016/11/10
     ================================================================*/
    
    
    #include "Arduino.h"
    char pin2 = 5; //5端口
    unsigned char u08temp;
    
    /******************************************************************************
     * 说明:Leonardo 已经打开了PLL,PLLCSR=19;CLKPR=74LL锁频到96MHZ,2分频后送到USB
     * 此时我们需要打开PLL到定时器4
     * 参数:Period 周期 
     * Duty 占空比,0-100
     * 注意:周期是10位的数,0-1024.
     ******************************************************************************/
    void Fast_PWM(unsigned short Period,unsigned char Duty,unsigned int upFrequency)
    {   unsigned char temp;
        unsigned  short  PeriodHigh;
        SREG&=~0x80;                                                      //全局中断关
        Period&=0x3FF;                                                    //仅保留10位
        Duty&=0x7F;                                                       //保留7位
        PeriodHigh=(unsigned  short)((unsigned  long)Period*Duty/50);     //计算高电平时间
        switch(upFrequency)
        {
          case 64000:temp=1;break;                                        //64MHz  PWM
          case 32000:temp=2;break;
          case 16000:temp=3;break;
          case 8000: temp=4;break;
          case 4000: temp=5;break;
          case 2000: temp=6;break;
          case 1000: temp=7;break;                                        //1MHz  PWM
          case 500:  temp=8;break; 
          case 250:  temp=9;break; 
          case 125:  temp=10;break; 
          case 62:   temp=11;break; 
          case 31:   temp=12;break;
          case 15:   temp=13;break;
          case 8:    temp=14;break;             
          case 4:    temp=15;break;                                       //3.90625kHz 
          default:   temp=7;                                              //默认1MHz
         }
        u08temp=temp;
        while (PLLCSR != 19);                    //等待PLL锁定
        PLLFRQ|=(1<<LLTM1);                     //将PLL送到TIMER4,1.5分频,速度最高64MHZ
        TCCR4A=0;
        TCCR4A=(1<<COM4A0)|(1<<WM4A);           //清除输出比较,OC4A PWM使能
        TCCR4B=(1<<WM4X)|(1<<CS40)|(1<<SR4);   //PWM反转,异步时钟1分频
        TCCR4B|=temp&0x0F;
        TCCR4D=0;                                //保护中断不开
        TCCR4E=(1<<ENHC4);                       //增强比较 10位模式
    
      
       
        TC4H = (Period>>8)&0x03;                 //高两位
        OCR4C  = Period&0xFF;                    //低8位
        TC4H = (PeriodHigh>>8)&0x03;             //高两位
        OCR4A = PeriodHigh&0xFF;                 //低8位
    
        SREG|=0x80;                              //中断开
      }
      
    void setup()
    {
    
        pinMode(pin2, OUTPUT);  
        Fast_PWM(100,50,1000);        //10kHz,50%占空比
    
       
    }   
    
    void loop()
    {
      //none
       
    }


        本设计程序根据Atmega32u4的数据手册,根据图4所示初始化流程进行初始化。注意,由于定时器4用到了异步时钟,即PLL时钟,这个时钟是给USB用的,不要轻易动,否则串口通信该出问题了。
        由于Leonardo本已初始化了PLL锁相环,因此我只需将锁相环时钟给路由到我的Timer4即可。另外设置定时器4的运行模式,这里重要的是OCR4C寄存器和OCR4A 寄存器。前者定义了占空比,后者定义了频率。两个都配置成了10位的,也就是说,可以有0-1024个步长,PWM的分辨率大大改善。
        同时,通过函数的第三个参数进行PWM模块的频率设置,也就是设置了计数器的单次计数时间。该高速PWM计数时钟最高可达64MHz真的非常高了,技术手册中告诉我们,这个计数器4是用来驱动BLDC(直流无刷电机)的。设置PWM默认计数频率为1MHz。

    图5 高速PWM

    图5 高速PWM

      
           图5 显示了调试结果,设置了10kHz PWM频率,50%占空比,1通道显示的为5引脚的电平变化,可以看出,频率为10kHz,占空比为50%。13引脚为5引脚的反相。通过调整第一个参数用来调频,调整第二个参数用来调整占空比,调整第三个参数也用来调频,不过这调频就不是连续的了。结论就是改程序是验证正确的
         美中不足的是未设置其余几个高速PWM。另外,本程序思路完全可以应用在Arduino Uno上,自己写一个可调度高的PWM,Uno可是有三个定时器,6个pWM通道的。






  • TA的每日心情
    擦汗
    2017-8-16 16:44
  • 签到天数: 229 天

    [LV.7]常住居民III

    发表于 2016-11-10 09:40 | 显示全部楼层
    赞赞赞                 
  • TA的每日心情
    开心
    2019-2-13 00:00
  • 签到天数: 379 天

    [LV.9]以坛为家II

    发表于 2016-11-10 13:11 | 显示全部楼层
    楼主,我觉得你要把你的代码贴在代码编辑框里面,不然有些会变成表情,不方便阅读
    要和我PY吗?
  • TA的每日心情
    奋斗
    2019-3-20 18:16
  • 签到天数: 141 天

    [LV.7]常住居民III

     楼主| 发表于 2016-11-10 23:03 | 显示全部楼层
    本帖最后由 希岩 于 2016-11-10 23:59 编辑
    jianwei569 发表于 2016-11-10 13:11
    楼主,我觉得你要把你的代码贴在代码编辑框里面,不然有些会变成表情,不方便阅读 ...

    是啊,才发现里面有表情。已修改,谢谢
  • TA的每日心情

    2016-12-19 11:30
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    发表于 2016-12-1 11:04 | 显示全部楼层

    回帖奖励 +1 金币

    很强很强很强很强
  • TA的每日心情
    奋斗
    2019-3-20 18:16
  • 签到天数: 141 天

    [LV.7]常住居民III

     楼主| 发表于 2016-12-6 18:18 | 显示全部楼层
    Tcwxc 发表于 2016-12-1 11:04
    很强很强很强很强

    lalala ==  
  • TA的每日心情
    开心
    2019-4-25 11:17
  • 签到天数: 649 天

    [LV.9]以坛为家II

    发表于 2016-12-15 08:38 | 显示全部楼层

    回帖奖励 +1 金币

    可以可以  谢谢分享
    打赏作者鼓励一下!
  • TA的每日心情

    2019-1-23 15:24
  • 签到天数: 23 天

    [LV.4]偶尔看看III

    发表于 2019-1-12 19:56 | 显示全部楼层
       TCCR4B
       CS43
       TCCR4D
       TC4H
    这些都是什么呀
  • TA的每日心情
    奋斗
    2019-3-20 18:16
  • 签到天数: 141 天

    [LV.7]常住居民III

     楼主| 发表于 2019-1-13 15:59 | 显示全部楼层
    作业小斗士 发表于 2019-1-12 19:56
    TCCR4B
       CS43
       TCCR4D

    AVR的寄存器
    您需要登录后才可以回帖 登录 | 立即注册  

    本版积分规则

    热门推荐

    学习记录2,Blinker读取温湿度
    学习记录2,Blinker读取温
    开关现在是使用得很6了,准备进行下一步,读取数据。 找了下官方的例程,发现用的是w
    学生智能打卡系统(接入blinker)
    学生智能打卡系统(接入bl
    【项目名称】学生智能打卡系统(接入blinker) 一.感谢各位大佬 首先感谢社区的管理员
    关于红外控制空调的模块选型
    关于红外控制空调的模块选
    想问问这中模块能支持arduino吗
    LCD1602只亮 不显示
    LCD1602只亮 不显示
    #include // initialize the library by associating any needed LCD interface pin
    18脚的8x8LED点阵如何使用??
    18脚的8x8LED点阵如何使用
    本帖最后由 Creeper666 于 2018-8-14 12:24 编辑 这个点阵模块上面一排有12个脚,
    Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   ( 蜀ICP备14017632号-3 )
    快速回复 返回顶部 返回列表