首先,确定TIMx的时钟,除非APB1的时钟分频数设置为1,否则通用定时器TIMx的时钟是APB1时钟的2倍,这时的TIMx时钟为72MHz,用这个TIMx时钟72MHz除以(PSC+1),得到定时器每隔多少秒涨一次,这里给PSC赋7199,计算得定时器每隔00001秒涨一次,即此时频率为10KHz,再把这个值乘以(ARR+1)得出PWM频率。
假如ARR值为0,即00001(0+1),则输出PWM频率为10KHz,再假如输出频率为100Hz的PWM,则将ARR寄存器设置为99即可。如果想调整PWM占空比精度,则只需降低PSC寄存器的值即可。
如果你的预装载值TIM_TimeBaseStructureTIM_Period设为100TIM_SetCompare2(20),就是20%占空比了。
我写的一个 多路PWM模拟 很简单的 希望对有用
#include<reg52h>
unsigned char count;
sbit pwm1=P0^0;
sbit pwm2=P0^1;
sbit pwm3=P0^2;
unsigned char jd1,jd2,m1,m2;
unsigned int x,y,z,xx,yy,zz;
void delay1(unsigned int ms);
//延时程序
void delay(unsigned int x)
{
unsigned char i,j;
for(i=x;i>0;i--)
for(j=125;j>0;j--);
}
//定时01ms,
void Timer0_Init()
{
TMOD |=0x01;
//IE=0x82;
EA=1; //总中断打开
ET0=1; //定时器中断打开
TR0=1; //定时器开关打开
TH0=0xff;//10uS
TL0=0xf6;//
TR0=1;
}
void Timer0_Int() interrupt 1//中断程序
{
TH0=0xff; //10uS
TL0=0xf6;
x++;
y++;
z++;
if(x<3) //30%
{
pwm1=1;
}
else
pwm1=0;
if(x>=6 {
x=0;
}
if(y<=2) //20%
{
pwm2=1;
}
else
pwm2=0;
if(y>=10)
{
y=0;
}
if(z<=2) //50%
{
pwm3=1;
}
else
pwm3=0;
if(z>=4)
{
z=0;
}
}
哥,占空比的范围是0~1,PWM波还有精度要求的,以下以8为PWM波为例:
8位的PWM波,一个周期有256个时间段,单片机定时器的中断频率为60256=15360 Hz
T=0651ms
以下为伪代码:
ISR_Time();定时器中断服务程序
{ if(i==255)
i=0;
else
i++;
if (i<k) // k=占空比256
PORT=1; //端口输出高电平
else
PORT=0;
定时器计数载入();
}
以标准8051为例(晶振12M),计数脉冲为1us,需计651个脉冲,我们用定时器0,用Keil C编译
#include "reg52h"
unsigned char k=255;//k等于占空比乘以255,可以动态调整
unsigned char i=0;
sbit PORT = P1^0;//P10口输出
void main(void )
{
EA=0;//关总中断
ET0=1; //开定时器中断
TMOD=0x01;//设置定时器为16为定时模式
TH0=0x02; //定时651个周期,0x028B=651
TL0=0x8B;
EA=1;//开中断
TR0=1; //开始定时
while(1);
}
void timer0 (void) interrupt 1 using 0//定时器中断服务程序
{ if(i==255)
i=0;
else
i++;
if (i<k) // k=占空比256
PORT=1; //端口输出高电平
else
PORT=0;
TH0=0x02;
TL0=0x8B;
TR0=1;
}
脉冲输出控制
(JOG控制: 带通道指定)
概述
程序示例
*** 作数
描述
根据参数表的设置,从指定的输出通道(ch0或ch2)输出脉冲。
10
11
ST R 10
F172 (PLSH)
DT 10
K 0
触发器
n
参数表存储区的起始地址 S
指定用于输出脉冲的输出通道Yn(n: K0或K2)
数据寄存器
WX WY WR SV EV DT K H
S N/A N/A N/A N/A N/A A N/A N/A A
n N/A N/A N/A N/A N/A N/A A A N/A
N/A
N/A
*** 作数 索引变址 继电器 定时器/计数器 索引寄存器 常数
I
当相关控制标志为OFF并且执行条件(触发器)变成ON时, 从指定的通道(ch0或者ch2)输出脉冲
在执行条件为ON的状态下持续输出脉冲
CW PLS
CCW SIGN
CW PLS
CCW SIGN
Y3
通道号 输出 输出方式
ch0
ch2
Y0
Y1
Y4
3-443
A: 可以使用
N/A: 不可使用
通过在控制代码中指定加计数或者减计数,可将该指令作为JOG *** 作指令
可以在每个扫描周期内改变脉冲频率, 也可以在不同时间修改目标值 但是在指令执行的过程中, 不能
改变控制代码
如果频率被设置成50kHz或者更高, 应指定占空比为1/4(25%)
数据表设置
(1) 由H常数(16进制)指定控制代码
0: 固定
目标值设置
0: 无目标值模式
1: 到达目标值停止模式
占空比(ON脉冲宽度)
0: 占空比1/2 (50%)
1: 占空比1/4 (25%)
频率范围
0: 15Hz~98kHz
1: 48Hz~100kHz
2: 191Hz~100kHz
动作模式及输出逻辑关系
00: 无计数 CW
01: 无计数 CCW
10: 增计数 CW
12: 增计数 方向输出OFF
13: 增计数 方向输出ON
21: 减计数 CCW
22: 减计数 方向输出OFF
23: 减计数 方向输出ON
(2) 频率范围(Hz) ”K值表示”,
15Hz到98kHz [K1到K9800(单位:Hz)] (最大误差在98kHz时约-09 kHz)
设定”K1”对应15Hz
48Hz到100kHz [K48到K100000(单位: Hz)] (最大误差在100kHz时约-3 kHz)
191Hz到100kHz [K191到K100000(单位: Hz)] (最大误差在100kHz时约-08 kHz)
(3) 目标值(绝对值) (版本20以后)
用于到达目标值停止模式(只使用绝对值)
目标值设置的范围如下表所示 如果指定的数值超出范围, 则实际的输出脉冲数可能
与设定值不同 在无计数模式下, 忽略目标值
控制码H □□□□□□□□
S
S+1
控制代码 (1)
S+2
S+3
频率(Hz) (2)
S+4
S+5
目标值 (3)
S
S+1
控制代码 (1)
S+2
S+3
频率(Hz) (2)
无目标值模式 达到目标值停止模式
增计数
减计数
输出模式 允许指定的目标值。
以上我是在手册查到的,如果需要我可以发给你看看,就非常明白的,望采纳,谢谢!
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
//TIM3设置
TIM_DeInit(TIM3);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //clock
//定时器pwm模式
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); //其它默认值
TIM_TimeBaseStructureTIM_Period = 20000-1; //重载定时器周期,ARPE=1时更新事件时//
TIM_TimeBaseStructureTIM_Prescaler = 0; //定时器时钟分频数,下次更新事件时采用//
TIM_TimeBaseStructureTIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割//
TIM_TimeBaseStructureTIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_OCStructInit(&TIM_OCInitStructure); //其它默认值
TIM_OCInitStructureTIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructureTIM_OutputState =TIM_OutputState_Enable; //输出禁止
TIM_OCInitStructureTIM_Pulse = 11000; //延时时间
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
//TIM_OC1FastConfig(TIM3, TIM_OCFast_Enable);
//TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable); //通道预装载使能
TIM_Cmd(TIM3, ENABLE);
时钟频率72M,pwm频率=72M/20000=36K
55%=11000/20000
// P2^0和P2^1;接2个按钮,
//P2^0控制频率10HZ到50HZ, 按压改变
//P2^1控制占比10%到90%,按压改变
//假设晶振为12MHz
#include<reg52h>
#define uint unsigned int
#define uchar unsigned char
uint t=0,f=100,w=50;
sbit P10=P1^0; // 输出端
sbit KF=P2^0; // 改变频率按钮
sbit KW=P2^1; // 改变占宽按钮
void init()
{
TMOD=0x21;
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
ET0=1;
TR0=1;
EA=1;
}
void time0() interrupt 1
{
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
t++; //t为1ms
if(t>=f) t=0;
}
void main()
{
init();
while(1)
{
if(KF==0) //改变频率
{f=f-10;
if(f<=10) f=100;
while(KF==0);
w=f/10;
}
if(KW==0) //改变占比
{w=w+f/10;
if(w>=f) w=f/10;
while(KW==0);
}
if(t<w)P10=1; //单个周期
else P10=0;
}
}
如果看不清,请先“查看大图”,此时另存到你的电脑里,再查看更大的。
后补充:根据你的“问题补充”,需要增加一个AD转换器,常用的并口有ADC0809,串口有ADC0834,单片机扫描AD转换输出的数据,送到上述的频率f和占比w两个变量。就可以改变。幅度改变很简单,用电位器的分压直接输出就可以了。要把整个写出来,需要一定的篇幅,上面给你提供思路,望你自己多动手电脑,得到满意的结果。
第一,你什么电机?第二,步进电机你是几线几向的?你这都没说清楚让人咋写?
其实思想很简单,比如你是用PWM写的,就是控制脉冲占空比。
思想都说了,你要代码?
给你个例子你看看就行了,估计直接用是不可能的,接口不同。
// 左轮驱动
void __leftMotorContr (void)
{
static int8 cStep = 0; / ±£Žæµç»úµ±Ç°Î»Öà /
switch (__GmLeftcDir) {
case __MOTORGOAHEAD: / ÏòÇ°²œœø /
cStep = (cStep + 1) % 8;
break;
case __MOTORGOBACK: / Ïòºó²œœø /
cStep = (cStep + 7) % 8;
break;
default:
break;
}
switch (cStep) {
case 0: / A2B2 /
GPIOPinWrite(GPIO_PORTD_BASE,
__PHLA1 | __PHLA2 | __PHLB1 | __PHLB2,
__PHLA1 | __PHLA2 | __PHLB1 | __PHLB2);
break;
case 1: / B2 /
GPIOPinWrite(GPIO_PORTD_BASE,
__PHLA1 | __PHLA2 | __PHLB1 | __PHLB2,
__PHLB1 | __PHLB2);
break;
case 2: / A1B2 /
GPIOPinWrite(GPIO_PORTD_BASE,
__PHLA1 | __PHLA2 | __PHLB1 | __PHLB2,
__PHLA2 | __PHLB1 | __PHLB2);
break;
case 3: / A1 /
GPIOPinWrite(GPIO_PORTD_BASE,
__PHLA1 | __PHLA2 | __PHLB1 | __PHLB2,
__PHLA2);
break;
case 4: / A1B1 /
GPIOPinWrite(GPIO_PORTD_BASE,
__PHLA1 | __PHLA2 | __PHLB1 | __PHLB2,
__PHLA2 | __PHLB2);
break;
case 5: / B1 /
GPIOPinWrite(GPIO_PORTD_BASE,
__PHLA1 | __PHLA2 | __PHLB1 | __PHLB2,
__PHLB2);
break;
case 6: / A2B1 /
GPIOPinWrite(GPIO_PORTD_BASE,
__PHLA1 | __PHLA2 | __PHLB1 | __PHLB2,
__PHLA1 | __PHLA2 | __PHLB2);
break;
case 7: / A2 /
GPIOPinWrite(GPIO_PORTD_BASE,
__PHLA1 | __PHLA2 | __PHLB1 | __PHLB2,
__PHLA1 | __PHLA2);
break;
default:
break;
}
}
// 右轮驱动同理
首先89C52内部没有硬件PWM发生器,只能通过定时器模拟!你可以通过两个定时器,T0控制周期,T1控制占空比。
例如:实现周期为1000us,占空比为20%的PWM,用P10实现
首先你设置T0为65536-1000 (12M晶振)
T1为65536-200
首先初始化P10=1,两个定时器同时打开,在定时器T1中断时拉低P10,在定时器T0中断时在拉高P10,同时将两定时器初始值初始化T0为65536-1000 ,T1为65536-200
希望对你有用,呵呵!!!
用1个定时器的话也是可以的,但是这就要用一个变量count1 来控制周期和占空比了,比如说你设置1周期为10ms,占空比还是为20%的PWM,你可以设置定时器为每10us产生一次中断,没中断一次使count加1,一开始设置P10为高电平,当count1加到200的时候拉低P10,等count1到1000了在拉高P10,同时复位count1=0,不过这样做的缺点是精度不高,要是PWM所需周期段,精度高的话我还是建议用两个定时器来实现 ,我在这里没有给你具体的代码,我觉得把原理讲清楚猜是最重要的,什么都是才来就上代码,这个对你学习不利,希望对你有用,呵呵!!!!
如果两路同时输出的话只要你设置两个变量,同时进行判断就行了,和一路的原理是一样的。
以上就是关于stm32中pwm的占空比全部的内容,包括:stm32中pwm的占空比、求教单片机PWM发生器,如何实现以下功能:产生2路PWM波,频率10KHz,一路30%占空比,另一路20%占空比、如何让单片机产生 频率为60Hz 占空比在0.5-2.5之间的PWM波等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)