打印
[电机应用]

PWM(12bit脉冲宽度调制)

[复制链接]
3729|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一、资源简介
前面介绍了使用 SH79F9476 的可编程计数器阵列 PCA0 生成PWM波,其支持8位、16位脉宽调制。
主要特性如下:

两路12位PWM模块:SH79F9476提供了两个PWM模块,每个模块可以生成具有可调周期和占空比的脉宽调制波形。

周期溢出中断:每个PWM周期都提供了溢出中断功能,可以在周期结束时触发中断处理程序。

输出极性可选择:可以通过设置PWM控制寄存器来选择PWM输出的极性,从而决定占空比期间输出的电平。

PWM模块控制:使用PWM控制寄存器(PWMxCON)可以配置PWM模块的时钟源、输出极性、周期中断等参数。

周期设置:使用PWM周期寄存器(PWMxPH/L)可以设置PWM输出波形的周期,以控制脉冲的频率。

占空比设置:使用PWM占空比寄存器(PWMxDH/L)可以设置PWM输出波形的占空比,以控制脉冲的宽度。

二、PWM工作流程
SH79F9476的PWM工作流程如下:

选择PWM模块时钟源:
在开始配置PWM模块之前,首先需要选择PWM模块的时钟源。可以通过设置PWM控制寄存器(PWMxCON)中的PWMxCK[2:0]位来选择时钟源,以确定PWM模块的工作时钟频率。

设置PWM周期:
使用PWM周期寄存器(PWMxPH/L)设置PWM输出波形的周期。这些寄存器用于控制PWM脉冲的频率。在设置周期之前,需要确定所需的PWM输出频率,并根据所选的时钟源来计算周期寄存器的值。

设置PWM占空比:
使用PWM占空比寄存器(PWMxDH/L)设置PWM输出波形的占空比。这些寄存器用于控制PWM脉冲的宽度。在设置占空比之前,需要确定所需的PWM输出占空比,并根据所选的周期来计算占空比寄存器的值。

选择PWM输出模式:
使用PWM控制寄存器(PWMxCON)中的PWMxS位选择PWM输出模式。可以选择PWM占空比期间输出高电平还是低电平。

使能PWM模块:
设置PWM使能位(PWMxEN)来启用所需的PWM模块。这将启动PWM输出并使其按照设置的周期和占空比工作。

修改周期和占空比(可选):
在PWM输出允许期间,可以根据需要修改周期和占空比寄存器的值。修改后的值将在下一个PWM周期开始生效。

处理PWM周期中断(可选):
如果启用了PWM周期中断,当PWM周期结束时,将触发中断处理程序。可以在中断处理程序中执行相应的操作,例如更新周期和占空比等。

调整PWM输出(可选):
根据实际需求,可以根据系统的运行情况调整PWM输出的周期和占空比。可以根据外部输入信号或系统状态来动态调整PWM输出。

三、寄存器介绍
1. PWMx控制寄存器PWMxCON



位功能说明:



下面示例:

PWM0CON = 0x81;


允许 PWM0模块
PWM0占空比期间输出高电平,占空比溢出后输出低电平
PWM0使用系统时钟,不分频
禁止PWM0周期中断
PWM0输出允许
PWM1CON=0xC1; //11000001


允许PWM1模块
PWM1占空比期间输出低电平,占空比溢出后输出高电平
PWM1使用系统时钟
禁止PWM1周期中断
PWM1输出允许
2. PWM0周期寄存器PWM0PH/L



输出周期为 [PWM0PH,PWM0PL] * PWM时钟周期 。
PWM0的计数器计数至PWM0PH/L值后归0,这时如果PWM0S=0,则PWM0输出低电平 ;如果PWM0S=1,则PWM0输出高电平。

示例:

        PWM0PL = 0xff;
        PWM0PH = 0x0f;


周期为 0xfff*系统时钟周期,假设系统时钟为12MHz,则PWM0周期为 0xfff/12MHz=0.34125ms

3. PWM1周期寄存器PWM1PH/L



4. PWM0占空比控制寄存器PWM0DH/L



位功能说明:



5. PWM1占空比控制寄存器 PWM1DH/L



位功能说明:



修改占空比要注意的是:

修改寄存器 PWMxDH 将使得 PWMx 的输出在下一个周期生效。
用户需先修改 PWMxDL ,再修改 PWMxDH 以修改 PWM占空比。
无论 PWMxDH 是否被修改,都需要将 PWMxDH 再写一次。否则,低位的修改无效。
6. 占空比寄存器与周期关系
下图示例可以比较清楚看出PWMP和PWMD所指的时间:



即PWMP为PWM周期 ,
PWMD为PWM输出高/低电平时间,具体输出高还是低取决于PWMS的值。

四、代码实现示例
1. 基本功能
下面实例实现PWM输出的基本代码:

void init_pwm0()
{
        _push_(INSCON);
        Select_Bank0();
        PWM0PL = 0xff;
        PWM0PH = 0x0f;
        PWM0DL = 0xff;
        PWM0DH = 0x07;
        PWM0CON = 0x81;
        _pop_(INSCON);
}

void init_pwm1()
{
        _push_(INSCON);
        Select_Bank1();
        PWM1PL = 0xff;
        PWM1PH = 0x0f;
        PWM1DL = 0xff;
        PWM1DH = 0x07;
        PWM1CON = 0xc1;
        _pop_(INSCON);
}



代码选项设置,时钟使用128K:



2路PWM波形对比: (2路垂直偏移设置不同以方便观察)



2. 封装PWM函数
(1)pwm_utils.c
#include "pwm_utils.h"

/**
* @param frequency 频率
* @param duty 占空比,单位是百分比
* @param polar 极性
* @brief 初始化PWM0
*/
void Pwm0_Init(volatile U16 frequency, volatile U16 duty, volatile U16 polar) {
    // 周期,单位是ms
    volatile U16 period = 1000 / frequency;
    volatile U16 PWM0P = period * 128;
    volatile U16 PWM0D = (PWM0P / 100) * duty;
    _push_(INSCON);
    Select_Bank0();
    // 周期寄存器, 0x0fff=4095,周期=4095/128K=32ms
    // 通过周期计算PWM0Px的值,PWM0Px=period*128K/1000
    PWM0PL = PWM0P & 0xff;
    PWM0PH = PWM0P >> 8;
    // 占空比寄存器,0x07ff=2047
    // 计算占空比寄存器的值,PWM0Dx=周期寄存器值*duty/100
    PWM0DL = PWM0D & 0xff;
    PWM0DH = PWM0D >> 8;

    if (polar == 1) {
        PWM0CON |= 0x40;
    } else {
        PWM0CON &= 0xbf;
    }
    // PWM0控制寄存器 1000_0001, 使能、输出允许
    PWM0CON |= 0x81;
    _pop_(INSCON);
}

/**
* @param frequency 频率
* @param duty 占空比,单位是百分比
* @param polar 极性
* @brief 初始化PWM1
*/
void Pwm1_Init(volatile U16 frequency, volatile U16 duty, volatile U16 polar) {
    // 周期,单位是ms
    volatile U16 period = 1000 / frequency;
    volatile U16 PWM1P = period * 128;
    volatile U16 PWM1D = (PWM1P / 100) * duty;
    _push_(INSCON);
    Select_Bank1();
    // 周期寄存器
    PWM1PL = PWM1P & 0xff;
    PWM1PH = PWM1P >> 8;
    // 占空比寄存器
    PWM1DL = PWM1D & 0xff;
    PWM1DH = PWM1D >> 8;

    if (polar == 1) {
        PWM1CON |= 0x40;
    } else {
        PWM1CON &= 0xbf;
    }
    // PWM1控制寄存器 1100_0001,使能、占空比期间输出低电平、占空比溢出后输出高电平、输出允许
    PWM1CON |= 0x81;
    _pop_(INSCON);
}




(2)main.c
#include "SH79F9476.h"
#include "clk_utils.h"
#include "pwm_utils.h"


void main() {
       
    // 选择低速时钟
    lowFrequenceClk();

        Pwm0_Init(32, 50, 0);
    Pwm1_Init(32, 80, 1);

    while (1) {
    }
}




输出频率32Hz、占空比80、极性相反的波形运行示例:



本文参考资源来自中颖官网。
本文代码开源地址: https://gitee.com/xundh/learn-sinowealth-51
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/xundh/article/details/137996604

使用特权

评论回复
沙发
LEDyyds| | 2024-5-14 13:23 | 只看该作者
这个确实很实用

使用特权

评论回复
板凳
亚瑟| | 2024-5-24 22:10 | 只看该作者
pwm可不可以用io模拟出来啊

使用特权

评论回复
地板
狄克爱老虎油| | 2024-7-22 16:15 | 只看该作者
亚瑟 发表于 2024-5-24 22:10
pwm可不可以用io模拟出来啊

可以的

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

77

主题

4122

帖子

4

粉丝