本帖最后由 希岩 于 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所示,频率竟然只有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所示。1通道用的是数字9 ,2通道用的是数字5,可以看出,2通道频率到了10kHz。
图3 调频PWM
但是再往上就有问题了,如图3所示,最高只能到34.33kHz,你在逗我吗?这是Leonardo的高速PWM吗?显然不是,因此我决定自己写一个函数来初始化高速的PWM通道。
图4 高速PWM流程
根据图4所示数据手册给出的初始化PWM流程,对Atmega32u4 高速PWM进行初始化。本例采用初始化数字5端口和数字13引脚,这两个相位相反。我就给出了我的程序,对初学者来讲,不用管程序内容,只需要学会调用和给合适的参数。
程序完全给出,也非常简单:
[mw_shl_code=cpp,true]/*================================================================
* 晶振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
}[/mw_shl_code]
本设计程序根据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 显示了调试结果,设置了10kHz PWM频率,50%占空比,1通道显示的为5引脚的电平变化,可以看出,频率为10kHz,占空比为50%。13引脚为5引脚的反相。通过调整第一个参数用来调频,调整第二个参数用来调整占空比,调整第三个参数也用来调频,不过这调频就不是连续的了。结论就是改程序是验证正确的。
美中不足的是未设置其余几个高速PWM。另外,本程序思路完全可以应用在Arduino Uno上,自己写一个可调度高的PWM,Uno可是有三个定时器,6个pWM通道的。
|