PWM

电机控制单电阻采样机制是在一个 PWM 波形内采集两相电流 ADC 数据,但某些扇区边界条件下只能获得一路电流 ADC 数据, 需要对 PWM 波形进行变形用于构造电流采样区域。

背景介绍

根据电机控制拓扑结构,单电阻采样在一个 PWM 控制周期内可以取得两相电流数据:

电机控制单电阻采样 PWM 变形信号产生

电机控制单电阻采样 PWM 变形信号产生

在扇区边沿无法获得两相电流信号。
电机控制单电阻采样 PWM 变形信号产生

波形产生

ST 专利的方法是在波形的中间部分产生变形波形,在变形后的波形上就可以得到两相电流 ADC 数据;

电机控制单电阻采样 PWM 变形信号产生

当然还有目前比较流行的波形移位方法也可以做到相同效果。 波形如下:
电机控制单电阻采样 PWM 变形信号产生

STM32 系列单片机 Timer 有足够的功能,可以产生上面两种波形,机制如下:

PWM 波中间变形

电机控制单电阻采样 PWM 变形信号产生

1. 设定 CCR4 的 DMA 通道,并且设定此时 Timer1 的 preload 为禁止状态;

TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Disable);

2. 在 CCR4 比较值部分产生 DMA 事件;

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(TIM1->CCR1));
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(uint32_t)(hDmaBuff2);
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 2u;
….
TIM_DMACmd(TIM1,TIM_DMA_CC4,ENABLE);

3. 在 1 点上将 CCR1 数据直接修改为周期数据+1;

4. 在 2 点上将 CCR1 数据修改为 CCR1’的数据;

5. 时间计算上按照上面的图示设定,中间凹陷时间为两边补充波形时间之和。

波形移位变形

电机控制单电阻采样 PWM 变形信号产生

1. 设定 Timer1 的 update 事件的 DMA 通道

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(TIM1->CCR1));
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(uint32_t)(hDmaBuff2);
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 2u;
……
TIM_DMACmd(TIM1,TIM_DMA_Update,ENABLE);

2. 在 1 点上更新 CCR1 数据为 CCR1 数据;

3. 在 2 点上更新 CCR1 数据为 CCR1’数据;

4. 保证前后的移位时间相同。

来源:ST意法半导体

围观 6
224

一. TIMER分类:

STM32中一共有11个定时器,其中TIM6、TIM7是基本定时器;TIM2、TIM3、TIM4、TIM5是通用定时器;TIM1和TIM8是高级定时器,以及2个看门狗定时器和1个系统嘀嗒定时器。其中系统嘀嗒定时器是前文中所描述的SysTick。

定时器

计数器分辨率

计数器类型

预分频系数

产生DMA请求

捕获/比较通道

互补输出

TIM1

TIM8

16位

向上,向下,向上/向下

1-65536之间的任意数

可以

4

TIM2

TIM3

TIM4

TIM5

16位

向上,向下,向上/向下

1-65536之间的任意数

可以

4

没有

TIM6

TIM7

16位

向上

1-65536之间的任意数

可以

0

没有

其中TIM1和TIM8是能够产生3对PWM互补输出,常用于三相电机的驱动,时钟由APB2的输出产生。TIM2-TIM5是普通定时器,TIM6和TIM7是基本定时器,其时钟由APB1输出产生。

二、PWM波形产生的原理:

产生波形原理来源:http://www.ndiy.cn/thread-31081-1-1.html
通用定时器可以利用GPIO引脚进行脉冲输出,在配置为比较输出、PWM输出功能时,捕获/比较寄存器TIMx_CCR被用作比较功能,下面把它简称为比较寄存器。
这里直接举例说明定时器的PWM输出工作过程:若配置脉冲计数器TIMx_CNT为向上计数,而重载寄存器TIMx_ARR被配置为N,即TIMx_CNT的当前计数值数值X在TIMxCLK时钟源的驱动下不断累加,当TIMx_CNT的数值X大于N时,会重置TIMx_CNT数值为0重新计数。
而在TIMxCNT计数的同时,TIMxCNT的计数值X会与比较寄存器TIMx_CCR预先存储了的数值A进行比较,当脉冲计数器TIMx_CNT的数值X小于比较寄存器TIMx_CCR的值A时,输出高电平(或低电平),相反地,当脉冲计数器的数值X大于或等于比较寄存器的值A时,输出低电平(或高电平)。
如此循环,得到的输出脉冲周期就为重载寄存器TIMx_ARR存储的数值(N+1)乘以触发脉冲的时钟周期,其脉冲宽度则为比较寄存器TIMx_CCR的值A乘以触发脉冲的时钟周期,即输出PWM的占空比为 A/(N+1) 。

三、STM32产生PWM的配置方法:

1、配置GPIO口:

配置IO口的时候无非就是开启时钟,然后选择引脚、模式、速率,最后就是用结构体初始化。不过在32上,不是每一个IO引脚都可以直接使用于PWM输出,因为在硬件上已经规定了用某些引脚来连接PWM的输出口。下面是定时器的引脚重映像,其实就是引脚的复用功能选择:

a.定时器1的引脚复用功能映像:

STM32之PWM波形输出配置总结

b.定时器2的引脚复用功能映像:
STM32之PWM波形输出配置总结

c.定时器3的引脚复用功能映像:
STM32之PWM波形输出配置总结

d.定时器4的引脚复用功能映像:
STM32之PWM波形输出配置总结

根据以上重映像表,我们使用定时器3的通道2作为PWM的输出引脚,所以需要对PB5引脚进行配置,对IO口操作代码:

GPIO_InitTypeDef GPIO_InitStructure;//定义结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);//使能GPIO外设和AFIO复用功能模块时钟
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //选择Timer3部分重映像
//选择定时器3的通道2作为PWM的输出引脚TIM3_CH2->PB5 GPIOB.5
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化引脚

2、初始化定时器:

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//定义初始化结构体
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟
//初始化TIM3
TIM_TimeBaseStructure.TIM_Period = arr; //自动重装载寄存器的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //TIMX预分频的值
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //时钟分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据以上功能对定时器进行初始化

3、设置TIM3_CH2的PWM模式,使能TIM3的CH2输出:

TIM_OCInitTypeDef TIM_OCInitStructure;//定义结构体
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;//选择定时器模式,TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;//输出比较极性低
TIM_OC2Init(TIM3, &TIM_OCInitStructure);//根据结构体信息进行初始化
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能定时器TIM2在CCR2上的预装载值

4、使能定时器3:

TIM_Cmd(TIM3, ENABLE); //使能定时器TIM3

经过以上的操作,定时器3的第二通道已经可以正常工作并输出PWM波了,只是其占空比和频率都是固定的,我们可以通过改变TIM3_CCR2,则可以控制它的占空比。修改占空比的函数为:TIM_SetCompare2(TIM3,n); n不同,占空比不同。

5、修改pwm波形的占空比:

编写一个函数:void TIM3_PWM_Init(u16 arr,u16 psc);将以上所有的代码都加进来这个函数中,只要在main函数中调用该函数进行初始化,然后使用TIM_SetCompare2()函数修改PWM的占空比就可以在PB5脚得到需要的PWM波形了。关于频率以及占空比的计算方法有以下例子:

int main(void)
{
  TIM3_PWM_Init(9999,143);//频率为:72*10^6/(9999+1)/(143+1)=50Hz
  TIM_SetCompare2(TIM3,4999);//得到占空比为50%的pwm波形
  while(1);
}

可参考:http://www.cnblogs.com/wangh0802PositiveANDupward/archive/2012/12/29/283...

转自:粥巴坨

围观 11
233

有客户需要用到高精度的DAC模块,MM32L0系列产品内部没有集成DAC模块,考虑到外接DAC芯片会增加成本,所以在本实验中将为大家介绍使用PWM输出,经过简单的变换电路即可实现DAC,这将大量降低电子设备的成本、减少体积,并提高精度。本实验在PWM到DAC转换关系的理论分析基础上,设计出输出为0~5V电压的DAC。

MM32L0系列产品包含1个高级控制定时器、5个通用定时器(1个32 位定时器和5个16 位定时器),以及 2个看门狗定时器和1个系统嘀嗒定时器。

每个定时器都有 PWM 输出或单脉冲模式输出,所以MM32L0系列产品任意一款型号都可以用PWM做DAC输出功能。

PWM波形的分段函数:

MM32 基于PWM做DAC输出设计

其中:k为谐波次数,N是PWM波一个周期的计数脉冲个数,T是单片机中计数脉冲的基本周期,即MCU每隔T时间记一次数(计数器的值增加或者减少1),t为时间, n是PWM波一个周期中高电平的计数脉冲个数,VH和VL分别是PWM波中高低电平的电压值。

PWM的高低电平分别为VH和VL,理想的情况VL等于0,但是实际中一般不等于0,所以用户在处理PWM的VL时需注意,出现较大误差一般都是因为这个地方。

将上述函数展开成傅里叶级数得到:

MM32 基于PWM做DAC输出设计

从上式可以看出,上式中第1个方括弧为直流分量,第2项为1次谐波分量,第3项为大于1次的高次谐波分量。上式中的直流分量与n成线性关系,并随着n从0到N,直流分量从VL到VL+VH之间变化,这正是电压输出的DAC所需要的。因此,如果能把式中除直流分量的谐波过滤掉,则可以得到从PWM波到电压输出DAC的转换,即:PWM波可以通过一个低通滤波器进行解调。式中的第2项的幅度和相角与n有关,频率为1/(NT),该频率是设计低通滤波器的依据。如果能把1次谐波很好过滤掉,则高次谐波就应该基本不存在了。

在DAC的应用中,分辨率是一个很重要的参数,傅里叶级数公式中的分辨率计算直接与N和n的可能变化有关:

MM32 基于PWM做DAC输出设计

从上式中可看出:
N越大DAC的分辨率越高,但是NT也越大,即 PWM的周期或者傅里叶级数公式中的1次谐波周期也越大,相当于1次谐波的频率也越低,需要截止频率很低的低通滤波器,DAC输出的滞后也将增加。为了使T减少,即减少单片机的计数脉冲宽度(这往往需要提高单片机的工作频率),达到不降低1次谐波频率的前提下提高精度。

MM32L0系列产品最高工作频率可达 48MHz,TIM2是32位的定时器,PWM频率计算公式:
Fpwm = 48M / ((arr+1)*(psc+1))(单位:Hz)
公式中psc就是分频系数,arr就是计数值。预分频器可以将计数器的时钟频率按 1 到 65536 之间的任意值分频。计数值可以从1-4294967295(2的32次方减1)中任意选取。

本次实验采用两阶RC滤波,使用两个电阻和两个电容组成一个具有DAC功能的引脚,PB10是32位的定时器TIM2_CH3通道,PA3和PA4两个通道分别去采集1阶RC滤波和2阶RC滤波后的电压值。

MM32 基于PWM做DAC输出设计

R29和C10的具体参数可根据傅里叶级数公式的第2部分的一次谐波频率来选择,实际应用中一般选择阻容滤波器的截止频率为傅里叶级数公式的基波频率的1/4左右。

RC滤波器的截止频率计算公式:

f = 1/(2πRC)

滤波器是频率选择电路,只允许输入信号中的某些频率成分通过,而阻止其他频率成分到达输出端。在电路中需要考虑到芯片引脚输出端到RC滤波电路之间的存在阻值等问题,上图中的电阻和电容值需要根据实际情况计算调整。

PB10引脚能将不同占空比的PWM信号转换为不同电压值的模拟信号。为了能更准确的获取DAC转换值,电路中还使用了2个ADC通道用来检测DAC转换值。在转换过程中PWM信号频率越快DAC输出的电压值越稳定,PWM位数越高DAC输出的电压值精度越高,32位PWM比16位PWM精度高。

实验程序:

TIM2定时器配置:
u32 OutCnt;

void InitTIM2_PWM(u16 t1, u16 t2, u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //TIM2_CH3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //TIM2_CH4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_PinAFConfig(GPIOB, GPIO_PinSource10,GPIO_AF_2);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11,GPIO_AF_2);

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Prescaler =psc;
TIM_TimeBaseStructure.TIM_Period = t1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

TIM_OC3Init(TIM2, &TIM_OCInitStructure);
TIM_OC4Init(TIM2, &TIM_OCInitStructure);

TIM_OCInitStructure.TIM_Pulse = t2;
TIM_OC3Init(TIM2, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);

TIM_OCInitStructure.TIM_Pulse = t2;
TIM_OC4Init(TIM2, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);

TIM_ARRPreloadConfig(TIM2, ENABLE);
TIM_Cmd(TIM2, ENABLE);
}

获取 SysTick 计数器的值:
u32 GetSysTickCount(void)
{
return SysTick_Count;
}

设置 SysTick 重装载值:
void SysTick_Configuration(void)
{
SysTick_Config(48000);
}

SysTick中断配置:
u32 pwm = 150;
void SysTick_Handler(void)
{
if (SysTick_Count ++ > 500)
{
SysTick_Count = 0;
InitTIM2_PWM(1024, pwm, 1);
}
}

主函数:
int main(void)
{
SystemInit();
SysTick_Count = 0;
SysTick_Configuration();
while(1)
{
}
}

操作方法:按照上述硬件搭建实验环境后,上电接上调试器,进入Debug状态,在IAR的Live watch窗口修改pwm值可以实现占空比可调。

实验结果:

MM32 基于PWM做DAC输出设计MM32 基于PWM做DAC输出设计

根据实验现象:
从PWM到DAC输出的信号处理有许多电路实现方法,上述电路实现方法DAC输出的负载能力比较差,适合具有高输入阻抗的后续电路连接,对精度和负载能力要求较高的场合,建议增加基准电压、负载驱动等电路。在MCU的应用中还可以通过软件的方法进行精度调整和误差的进一步校正。

PWM 外设结合本电路所实现DAC 有非常好的差分非线性(DNL)、线性度(INL),8位分辨率的情况下,PWM 频率为50KHz,实测精度在 0.5LSB 以内,适合于输出低频、高精度的模拟信号。

转自: 灵动微电子

围观 25
431

理解PWM需要知道的知识

(1)脉冲

解释:电子设备中电平状态发生的突变,通常突变时间很短,突变后极短时间后重新变为为原来的电平状态.(突变状态很短,两次突变间的时间相对较长)

(2)脉冲循环

解释:可以理解为一次突变到下一次突变所花的时间如下图:

浅析LED呼吸灯的实现和PWM的关系

(3)*(重点)占空比

解释:一个脉冲循环内通电时间所占的比例.,如下图:

浅析LED呼吸灯的实现和PWM的关系

举个例子:脉冲宽度1μs,信号周期5μs的脉冲序列即t=1,T=5,经过公式-占空比=t/T可以得到占空比为0.2.

(4)滤波器

解释:滤波器的组成为电感,电容,电阻等元器件.虽然PWM能通过通过改变占空比的方法.使电压的平均值达到稳压值,但输出稳定电压是靠PWM之后接的的滤波器来实现的。

(5)平均电压/输出电压

解释:
平均电压电压在一个周期T内积分之后再除以T.
也可以等同于写成:
输出电压 = (接通时间 / 脉冲时间)* 最大电压值

计算方式(平均电压)的示意图如下:

浅析LED呼吸灯的实现和PWM的关系

PWM的定义

PWN(Pulse-width modulation)的中文名是脉冲宽度调制.那么我们来看一下wikipedia对它的定义:

脉冲宽度调制(英语:Pulse Width Modulation,缩写:PWM),简称脉宽调制,是将模拟信号变换为脉冲的一种技术,一般变换后脉冲的周期固定,但脉冲的占空比会依模拟信号的大小而改变.在模拟电路中,模拟信号的值可以连续进行变化,在时间和值的幅度上都几乎没有限制,基本上可以取任何实数值,输入与输出也呈线性变化。所以在模拟电路中,电压和电流可直接用来进行控制对象,例如家用电器设备中的音量开关控制、采用卤素灯泡灯具的亮度控制等等 ...

计算PWN等效电压

PWM的等效电压计算公式为:

(此处我认为因为是方波所以可以将其视作平均电压)
U =(T1*Umax)/(T1+T2)
T1:导通时间
T2:断流时间
T1+T2 脉冲周期
Umax:电压幅值

所以根据公式可知,由于T1/(T1+T2)正是空占比,所以改变空占比就等于改变了等效电压,所以使得灯泡的亮度发生了变化

为什么Analogwrite的值是0-255?

LED亮度通过调节LED驱动器的PWM占空比来对亮度控制,一个PWM周期可以划分成2的控制位的次方个时钟周期而对大部分LED而言,控制位通常是8位,所以8位PWM能够提供256个亮度级的电平,因此PWM周期由256个时钟周期组成.

脉冲周期/频率和人眼的关系

LED的典型时钟频率是32kHz,那么根据公式PWM周期为256/32kHz=8ms.那么这样对于人眼而言这个闪烁频率很安全的避免了人眼能够觉察的闪烁.

在ARDUINO中使用PWM控制LED灯模拟呼吸灯的实验

实验准备:

实验主设备: Arduino UNO R3(图片来自NRIOBOT)

浅析LED呼吸灯的实现和PWM的关系

其他:
LED灯(若干)
面包板(一块)
杜邦线(双头公若干)
电阻(若干)(可选择/非必需)

连接图示意(通过Fritzing软件制作的简易电路图)

浅析LED呼吸灯的实现和PWM的关系

实验代码:

/*先要介绍一下analogwrite的用法
将模拟值(PWM波)输出到管脚。可用于在不同的光线亮度调节发光二极管亮度或以不同的速度驱动马达。调用analogWrite()后,该引脚将产生一个指定占空比的稳定方波,直到下一次调用analogWrite()(或在同一引脚调用digitalRead()或digitalWrite())

这种方法也叫快速PWM方式*/

需要上传到ARDUINO中的代码:

//设定使用9号口
void setup (){
pinMode(9,OUTPUT);
}
void loop(){
//由于上文中提到的所以为256种亮度
for (int a=0; a<=255;a++) //控制PWM亮度的增加
{
analogWrite(9,a);
delay(8);
}
for (int a=255; a>=0;a--) //控制PWM亮度减小
{
analogWrite(9,a);
delay(8);
}
delay(300); //完成一个循环
}

Analogwrite和占空比的关系

analogwrite(x,y)

X是管脚,而y(value)就是亮度级(在LED中)

占空比的计算方法就是: 占空比=y/256

对于Analogwrite占空比的一个特殊之处的解释

对于快速PWM模式,如果我们代码用了analogWrite(9, 0)即Y(value)=0,实际上应该有1/256的占空比,然而实际输出的电平为0.这是因为在Arduino的强制设定,当检测到AnalogWrite的value为0,那么就等于关闭了PWM.所以带来的问题是,如果我们设置analogWrite(9, 1),那么占空比2/256,所以在0到1之间产生了一个跳跃,丢弃了占空比为1/256的情况.

总结

这次的python实验中,让我们尝试了怎么使用Arduino和LED灯做出呼吸灯的效果,因为对于机器是怎么输出高电平(5v)和低电平(0v)之间的电压好奇,所以探究了一下原理,总结来说就是机器通过pwm在管脚产生了一定占空比的方波,改变空占比就等同于改变了等效电压,所以使得灯泡的亮度发生了变化.

转自: xlxw

围观 19
571

89C51芯片没有自带PWM发生器,如果要用51来产生PWM波就必须要用软件编程的方法来模拟。方法大概可以分为软件延时和定时器产生两种方法。下面将逐一介绍。

1 软件延时法

利用软件延时函数,控制电平持续的时间,达到模拟pwm的效果。

程序如下:

#include<reg52.h>
sbit pwm=P1^0;
main()
{
while(1)
{
 
pwm=1;
delayus(60);//置高电平后延时60us,占空比60%
pwm=0;
delayus(40);
}
}
void delayus(uint x)
{
while(x--);
}

proteus软件仿真结果如下:

51单片机产生PWM方法

可见,用这种延时函数的方法就能简单地模拟出pwm输出。但是这种方法的缺点也相当明显。当程序除了要输出pwm波还要执行其他操作比如键盘扫描、显示等操作时,需要占用CPU一定的机器周期,这样就会影响pwm的准确度。现在很少会用到这种方法,接下来要介绍的是比较常用的方法。

2 定时器产生pwm

这种方法利用了定时器溢出中断,在中断服务程序改变电平的高低,在程序较复杂、多操作时仍能输出较准确的pwm波形。

2.1 注意事项

2.2.1中断服务程序的内容。

一般来说中断服务程序只完成改变标志位、转换高低电平的功能,如果中断服务程序中有太多的操作会影响pwm波的输出,尤其是除法、取余、浮点数运算会占用大量的机器周期,应在中断外完成运算。
2.2.2定时器装入初值的问题。

装入初值不能太接近于定时器的溢出值。如我们使用定时器方式1,最多能计65536个数,假设我们转入的初值为65534,那么定时器计两个数就会进入中断,这样会使程序紊乱而其他功能无法正常地执行,所以一般要留50-100个数的裕量。

2.2 定时器工作方式

在定时器工作方式的选择上,可以选择定时器的工作方式0、1、2都可以,本文采用的是工作方式1,即16位定时器,这样可以获得较宽的调频范围。

2.3 定时器初值的计算

设占空比为α,频率为f

产生高电平时装入定时器高8位的值应为

产生高电平时装入定时器低8位的值应为

显然,产生低电平时的公式只要把α换成(1-α)就行了。

然而在51单片机中,浮点数运算需要消耗cpu很长的时间,为了提高程序效率,通常用100倍的占空比来计算。同时,要注意数据类型,避免超出范围,影响计算结果。关于C51的乘除法问题,可以看以下这篇文章: http://blog.163.com/ssou_1985/blog/static/295320362010311102232210/

修改后的公式如下:
a为100倍占空比,fr为0.01倍频率
TH0 = (65535-a*100/fr)/256; //高位初值
TL0 = (65535-a*100/fr)%256;
同样,低电平的公式只需把a换成(100-a)即可。

2.4 例程

本例程采用定时器T0在工作方式1下产生一路PWM,用独立键盘控制频率、占空比的加减,频率可调范围100Hz-10kHz,占空比0-100%(均为理论值,实际值略低)
部分代码如下:

51单片机产生PWM方法

注:T0_H , T0_L , T1_H , T1_L 均用于暂时存储初值,进入中断服务程序后直接给寄存器TH0、TL0赋值,避免了在中断中计算。
51单片机产生PWM方法

注:flag为pwm输出标志,flag=1输出高电平,flag=0输出低电平

2.5 软件仿真结果

2.5.1 频率为100Hz

a.占空比约15%

51单片机产生PWM方法

b.占空比95%

51单片机产生PWM方法

2.5.2 频率为10KHz

a.占空比15%

51单片机产生PWM方法

b.占空比90%

51单片机产生PWM方法

转自: 玩转单片机

围观 17
412

脉宽调制(PWM:(Pulse Width Modulation)是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。PWM是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。PWM信号仍然是数字的,因为在给定的任何时刻,满幅值的直流供电要么完全有(ON),要么完全无(OFF)。只要带宽足够,任何模拟值都可以使用PWM进行编码。本文提出AVR单片机ATmega128的PWM的设计方法。

1.定时/计数器PWM设计要点

根据PWM的特点,在使用ATmega128的定时/计数器设计输出PWM时应注意以下几点:

1)首先应根据实际的情况,确定需要输出的PWM频率范围,这个频率与控制的对象有关。如输出PWM波用于控制灯的亮度,由于人眼不能分辨42Hz以上的频率,所以PWM的频率应高于42Hz,否则人眼会察觉到灯的闪烁。

2)然后根据需要PWM的频率范围确定ATmega128定时/计数器的PWM工作方式。AVR定时/计数器的PWM模式可以分成快速PWM和频率(或相位)调整PWM两大类。

3)快速PWM可以的到比较高频率的PWM输出,但占空比的调节精度稍微差一些。此时计数器仅工作在单程正向计数方式,计数器的上限值决定PWM的频率,而比较匹配寄存器的值决定了占空比的大小。PWM频率的计算公式为:

PWM频率 = 系统时钟频率/(分频系数*(1+计数器上限值))

4)快速PWM模式适合要求输出PWM频率较高,但频率固定,占空比调节精度要求不高的应用。

5)频率(相位)调整PWM模式的占空比调节精度高,但输出频率比较低,因为此时计数器仅工作在双向计数方式。同样计数器的上限值决定了PWM的频率,比较匹配寄存器的值决定了占空比的大小。PWM频率的计算公式为:

PWM频率 = 系统时钟频率/(分频系数*2*计数器上限值))

6)相位调整PWM模式适合要求输出PWM频率较低,但频率固定,占空比调节精度要求高的应用。当调整占空比时,PWM的相位也相应的跟着变化(Phase
Correct)。

7)频率和相位调整PWM模式适合要求输出PWM频率较低,输出频率需要变化,占空比调节精度要求高的应用。此时应注意:不仅调整占空比时,PWM的相位会相应的跟着变化;而一但改变计数器上限值,即改变PWM的输出频率时,会使PWM的占空比和相位都相应的跟着变化(Phase
and Frequency Correct)。

8)在PWM方式中,计数器的上限值有固定的0xFF(8位T/C);0xFF、0x1FF、0x3FF(16位T/C)。或由用户设定的0x0000-0xFFFF,设定值在16位T/C的ICP或OCRA寄存器中。而比较匹配寄存器的值与计数器上限值之比即为占空比。

2.PWM应用设计参考

下面给出一个设计示例,在示例中使用PWM方式来产生一个1KHz左右的正弦波,幅度为0-Vcc/2。

首先按照下面的公式建立一个正弦波样本表,样本表将一个正弦波周期分为128个点,每点按7位量化(127对应最高幅值Vcc/2):

f(x) = 64 + 63 * sin(2πx/180) x∈[0…127]

如果在一个正弦波周期中采用128个样点,那么对应1KHz的正弦波PWM的频率为128KHz。实际上,按照采样频率至少为信号频率的2倍的取样定理来计算,PWM的频率的理论值为2KHz即可。考虑尽量提高PWM的输出精度,实际设计使用PWM的频率为16KHz,即一个正弦波周期(1KHz)中输出16个正弦波样本值。这意味着在128点的正弦波样本表中,每隔8点取出一点作为PWM的输出。

程序中使用ATmega128的8位T/C0,工作模式为相位调整PWM模式输出,系统时钟为8MHz,分频系数为1,其可以产生最高PWM频率为:

8000000Hz / 510 =15686Hz。

每16次输出构成一个周期正弦波,正弦波的频率为980.4Hz。PWM由OC0(PB4)引脚输出。参考程序如下(ICCAVR)。

//ICC-AVR application builder : 2004-08

// Target : M128

// Crystal: 8.0000Mhz

#include

#include

#pragma data:code

// 128点正弦波样本表

const unsigned char auc_SinParam[128] = {

64,67,70,73,76,79,82,85,88,91,94,96,99,102,104,106,109,111,113,115,117,

118,120,121,123,124,125,126,126,127,127,127,127,127,127,127,126,126,125,

124,123,121,120,118,117,115,113,111,109,106,104,102,99,96,94,91,88,85,82,

79,76,73,70,67,64,60,57,54,51,48,45,42,39,36,33,31,28,25,23,21,18,16,14,12,

10,9,7,6,4,3,2,1,1,0,0,0,0,0,0,0,1,1,2,3,4,6,7,9,10,12,14,16,18,21,23,25,28,31,33,

36,39,42,45,48,51,54,57,60};

#pragma data:data

unsigned char x_SW = 8,X_LUT = 0;

#pragma interrupt_handler timer0_ovf_isr:17

void timer0_ovf_isr(void)

{

X_LUT += x_SW; // 新样点指针

if (X_LUT > 127) X_LUT -= 128; // 样点指针调整

OCR0 = auc_SinParam[X_LUT]; // 取样点指针到比较匹配寄存器

}

void main(void)

{

DDRB |= 0x10; // PB4(OC0)输出

TCCR0 = 0x71; // 相位调整PWM模式,分频系数=1,正向控制OC0

TIMSK = 0x01; // T/C0溢出中断允许

SEI(); // 使能全局中断

while(1)

{……};

}

每次计数器溢出中断的服务中取出一个正弦波的样点值到比较匹配寄存器中,用于调整下一个PWM的脉冲宽度,这样在PB4引脚上输出了按正弦波调制的PWM方波。当PB4的输出通过一个低通滤波器后,便得到一个980.4Hz的正弦波了。如要得到更精确的1KHz的正弦波,可使用定时/计数器T/C1,选择工作模式10,设置ICR1=250为计数器的上限值。

结束语:

本文以ATmega128为例介绍了AVR单片机的PWM设计方法。随着电力电子技术,微电子技术和自动控制技术的发展PWM技术获得了空前的发展,被广泛应用在测量、通信到功率控制与变换的许多领域中。

来源: eechina.com

围观 13
349

页面

订阅 RSS - PWM