czlwf 发表于 2025-7-7 13:36:55

求助一个逻辑比较绕的PWM程序

写一段STC32G8K64单片机的PWM代码,要求如下:P2.3为PWM输出脚,当P1.1和P1.4中有一个为低电平或者都为低电平时,P1.0为高电平,则P2.3输出90%占空比的PMW,当P1.1或P1.4为高电平时输出的占空比逐渐降为0,时间2秒,当P1.1和P1.4中有一个为低电平,P1.0再次为高电平,则输出90%占空比的PMW,当P1.1或则P1.4为高电平时输出的占空比逐渐降为0,时间2秒,以此循环。

国芯人工智能 发表于 2025-7-7 13:38:00

针对您提出的PWM控制逻辑,以下是基于STC32G8K64单片机的实现方案。该程序通过定时器生成PWM信号,并根据P11、P14和P10的状态变化动态调整占空比,满足您所描述的循环控制逻辑。

一、硬件配置说明
PWM输出引脚:P23
状态检测引脚:P11、P14(用于判断是否进入高电平状态)
控制引脚:P10(用于触发90%占空比输出)

二、功能逻辑说明

1. 初始状态:
当 P11 和 P14 中有一个为低电平,或两者都为低电平时,且 P10 为高电平,则 P23 输出 90% 占空比的 PWM。
   
2. 状态转换:
当 P11 或 P14 变为高电平时,PWM 占空比从 90% 开始逐渐降为 0%,耗时 2 秒。
一旦 P11 和 P14 再次变为低电平(或其中一个为低),且 P10 为高电平,则重新输出 90% 占空比,再次进入降频过程。

3. 循环机制:
整个逻辑在 P11/P14 状态变化下不断循环执行。

三、代码实现(基于STC32G8K64)

c
include "stc32g8k64.h"

define PWMPIN    P23       // PWM输出引脚
define P11PIN    P11       // 状态检测引脚
define P14PIN    P14       // 状态检测引脚
define P10PIN    P10       // 控制引脚

volatile uint8t pwmduty = 90;   // 初始占空比为90%
volatile uint8t state = 0;      // 0:正常输出 1:下降中
volatile uint32t timercount = 0; // 计时计数器

// 初始化PWM
void PWMInit(void) {
    // 设置P23为PWM输出
    P2M1 &= ~0x08;   // P23设置为普通IO
    P2M2 |= 0x08;
   
    // 配置定时器2为PWM模式
    TMOD &= 0x0F;      // 清除T2控制位
    TMOD |= 0x20;      // T2为模式2(8位自动重装)
   
    TH2 = 0xFF;      // 初始值设为0xFF(16MHz系统时钟,约1ms周期)
    TL2 = 0xFF;
    RCAP2H = 0xFF;
    RCAP2L = 0xFF;
   
    ET2 = 1;         // 使能T2中断
    EA = 1;            // 全局中断使能
    TR2 = 1;         // 启动T2
   
    // 设置PWM占空比
    PWMDutySet(pwmduty);
}

// 设置PWM占空比
void PWMDutySet(uint8t duty) {
    uint16t period = 256;   // 定时器2为8位,最大256
    uint16t pulse = (dutyperiod) / 100;
    if (pulse > period) pulse = period;
    TH2 = 0xFF - (period - pulse);
    TL2 = 0xFF - (period - pulse);
}

// 定时器2中断服务函数
void Timer2ISR(void) interrupt 5 {
    static uint32t cnt = 0;
   
    cnt++;
    if (cnt >= 2000) {   // 2秒(假设系统频率为16MHz,1ms中断一次)
      cnt = 0;
      if (state == 1) {
            if (pwmduty > 0) {
                pwmduty--;
                PWMDutySet(pwmduty);
            } else {
                state = 0;
            }
      }
    }
}

// 检测输入状态
void CheckStatus(void) {
    static uint8t lastp11 = 1;
    static uint8t lastp14 = 1;
    static uint8t lastp10 = 1;

    uint8t p11 = P11PIN;
    uint8t p14 = P14PIN;
    uint8t p10 = P10PIN;

    if ((p11 == 0 || p14 == 0) && p10 == 1) {
      if (state == 0) {
            pwmduty = 90;
            PWMDutySet(pwmduty);
            state = 0;
      }
    } else {
      if (state == 0) {
            state = 1;
            timercount = 0;
      }
    }

    lastp11 = p11;
    lastp14 = p14;
    lastp10 = p10;
}

int main(void) {
    // 初始化端口
    P1M1 = 0x00;
    P1M2 = 0xFF;
    P2M1 = 0x00;
    P2M2 = 0xFF;

    PWMInit();

    while (1) {
      CheckStatus();
    }
}

四、注意事项
系统时钟:本代码基于16MHz系统时钟编写,若实际使用不同频率,请调整定时器相关参数。
PWM精度:由于使用的是8位定时器,占空比精度为1%,90%占空比为230/256。
延时控制:2秒的降频时间依赖于定时器中断频率,建议使用更精确的定时方式以提升稳定性。

如需进一步优化或扩展功能(如增加LED指示、串口调试等),可继续补充需求。

[本文内容由国芯人工智能辅助生成,仅供参考]

网老四 发表于 2025-7-7 14:07:36

既有电平状态,又有边沿状态处理,文字描述容易出错,不如画个简单真值表看得清楚

czlwf 发表于 2025-7-8 08:13:36

网老四 发表于 2025-7-7 14:07
既有电平状态,又有边沿状态处理,文字描述容易出错,不如画个简单真值表看得清楚 ...

那我重新描述问题,这个描述错误了
页: [1]
查看完整版本: 求助一个逻辑比较绕的PWM程序