关于STC15单片机定时器产生PWM的问题。官方例程如下。

#include <reg52.h>
#define MAIN_Fosc 24000000UL //定义主时钟
#define PWM_DUTY 6000 //定义PWM的周期,数值为时钟周期数,假如使用24.576MHZ的主频,则PWM频率为6000HZ。
#define PWM_HIGH_MIN 32 //限制PWM输出的最小占空比。用户请勿修改。
#define PWM_HIGH_MAX (PWM_DUTY-PWM_HIGH_MIN) //限制PWM输出的最大占空比。用户请勿修改。

typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;

sfr P3M1 = 0xB1; //P3M1.n,P3M0.n =00--->Standard, 01--->push-pull
sfr P3M0 = 0xB2; // =10--->pure input, 11--->open drain
sfr AUXR = 0x8E;
sfr INT_CLKO = 0x8F;

sbit P_PWM = P3^5; //定义PWM输出引脚。
//sbit P_PWM = P1^4; //定义PWM输出引脚。STC15W204S

u16 pwm; //定义PWM输出高电平的时间的变量。用户操作PWM的变量。

u16 PWM_high,PWM_low; //中间变量,用户请勿修改。

void delay_ms(unsigned char ms);
void LoadPWM(u16 i);

/******************** 主函数**************************/
void main(void)
{
P_PWM = 0;
P3M1 &= ~(1 << 5); //P3.5 设置为推挽输出
P3M0 |= (1 << 5);

// P1M1 &= ~(1 << 4); //P1.4 设置为推挽输出 STC15W204S
// P1M0 |= (1 << 4);

TR0 = 0; //停止计数
ET0 = 1; //允许中断
PT0 = 1; //高优先级中断
TMOD &= ~0x03; //工作模式,0: 16位自动重装
AUXR |= 0x80; //1T
TMOD &= ~0x04; //定时
INT_CLKO |= 0x01; //输出时钟

TH0 = 0;
TL0 = 0;
TR0 = 1; //开始运行

EA = 1;

pwm = PWM_DUTY / 10; //给PWM一个初值,这里为10%占空比
LoadPWM(pwm); //计算PWM重装值

while (1)
{
while(pwm < (PWM_HIGH_MAX-8))
{
pwm += 8; //PWM逐渐加到最大
LoadPWM(pwm);
delay_ms(8);
}
while(pwm > (PWM_HIGH_MIN+8))
{
pwm -= 8; //PWM逐渐减到最小
LoadPWM(pwm);
delay_ms(8);
}
}
}

//========================================================================
// 函数: void delay_ms(unsigned char ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void delay_ms(unsigned char ms)
{
unsigned int i;
do{
i = MAIN_Fosc / 13000;
while(--i) ;
}while(--ms);
}

/**************** 计算PWM重装值函数 *******************/
void LoadPWM(u16 i)
{
u16 j;

if(i > PWM_HIGH_MAX) i = PWM_HIGH_MAX; //如果写入大于最大占空比数据,则强制为最大占空比。
if(i < PWM_HIGH_MIN) i = PWM_HIGH_MIN; //如果写入小于最小占空比数据,则强制为最小占空比。
j = 65536UL - PWM_DUTY + i; //计算PWM低电平时间
i = 65536UL - i; //计算PWM高电平时间
EA = 0;
PWM_high = i; //装载PWM高电平时间
PWM_low = j; //装载PWM低电平时间
EA = 1;
}

/********************* Timer0中断函数************************/
void timer0_int (void) interrupt 1
{
if(P_PWM)
{
TH0 = (u8)(PWM_low >> 8); //如果是输出高电平,则装载低电平时间。
TL0 = (u8)PWM_low;
}
else
{
TH0 = (u8)(PWM_high >> 8); //如果是输出低电平,则装载高电平时间。
TL0 = (u8)PWM_high;
}
}
但是我没太懂。中断里不应该加P_PWM=!P_PWM之类的语句吗?但我一直没有找到程序是如何改变P3^5的电平的。

貌似确实如此,if....else里面应该再加一个P_PWM置位、清零语句。
温馨提示:答案为网友推荐,仅供参考
第1个回答  2017-08-05
不用加,你的想法是单片机没有CAP和PWM模块时的常用做法,但是这个是基于CAP模块的,原理是通过设置寄存器,让CAP比较从而改变管脚状态产生PWM,你只需要配置寄存器就好。