由于涉及到定时器中断和按键扫描,需要使用中断和定时器来实现。

首先,需要配置定时器的计时器模式和计数值,以实现PWM波的生成。计时器模式选择16位自动重装载模式,计数值为12,即定时器每计满12个时钟周期就会产生一个中断。然后,需要通过占空比计算来设置定时器中断的触发时间,即占空比越大,定时器中断的触发时间越晚,PWM波的高电平时间越长。

其次,需要配置按键的输入方式和中断方式,以实现按键的响应。按键的输入方式选择上拉输入,按键的中断方式选择下降沿触发中断。按下S1键,占空比就增加5%,按下S2键,占空比就减少5%,需要通过修改占空比计算来实现。

最后,需要在主函数中循环等待中断触发,以保持程序的运行。

下面是程序的具体实现:

#include <reg52.h>

sbit S1 = P1^0;  // S1键
sbit S2 = P1^1;  // S2键

unsigned int count;     // 定时器计数值
unsigned int period;    // PWM波周期
unsigned int high_time; // PWM波高电平时间
unsigned char duty;     // 占空比

void timer0_init(void)
{
    TMOD |= 0x01;  // 16位自动重装载模式
    count = 12;    // 计数值为12
    period = 20000; // PWM波周期为1/50000秒
    high_time = period / 2;   // PWM波高电平时间为半个周期
    duty = 50;     // 占空比初始值为50%
    TH0 = (65536 - count) / 256;  // 设置定时器初值
    TL0 = (65536 - count) % 256;
    ET0 = 1;  // 允许定时器0中断
    EA = 1;   // 允许总中断
    TR0 = 1;  // 启动定时器0
}

void key_init(void)
{
    P1 = 0xff;  // 上拉输入
    EX1 = 1;    // 允许INT1中断
    IT1 = 1;    // 下降沿触发
    EX0 = 1;    // 允许INT0中断
    IT0 = 1;    // 下降沿触发
}

void increase_duty(void)
{
    if (duty < 100) {
        duty += 5;
        high_time = period * duty / 100;
    }
}

void decrease_duty(void)
{
    if (duty > 0) {
        duty -= 5;
        high_time = period * duty / 100;
    }
}

void main(void)
{
    timer0_init();
    key_init();
    while (1);
}

void timer0_isr(void) interrupt 1
{
    TH0 = (65536 - count) / 256;  // 重置定时器初值
    TL0 = (65536 - count) % 256;
    if (high_time == 0) {
        P2 = 0x00;  // 输出低电平
    } else if (high_time == period) {
        P2 = 0xff;  // 输出高电平
    } else if (high_time == count * 4) {
        P2 = ~P2;   // 输出方波
    }
    high_time--;
}

void key_isr(void) interrupt 0
{
    if (!S1) {
        increase_duty();
    }
}

void key2_isr(void) interrupt 2
{
    if (!S2) {
        decrease_duty();
    }
}
89C52RC单片机PWM波输出控制程序(频率50kHz,占空比可调)

原文地址: https://www.cveoy.top/t/topic/obLn 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录