• 分享一个实用任意路数PWM函数


    一、什么是PWM?

    1、科普一下什么是PWM,嘿嘿,莫闲啰嗦,好好看看,可能大多数人听过,但可能没详细了解过,至此不妨花费几分钟,详细了解哈,PWM中文译名为:脉冲宽度调制,即控制电路在输出频率不变的情况下,通过微控制器控制电平在一个周期内输出高低电平的比例来等效出模拟电压的大小。举个“栗子”吧:

    若电池9V,设9V工作时灯状态为全亮,1.8V工作时为微亮。

    若开关持续20%时间通,80%时间断,则可近似为用一个1.8V(9V*20%)的电池持续供电,此时为半亮。当然,开关通断时间需要特别短,否则,比如20s通80s断,灯泡会20s全亮,80s灭,而达不到微亮的效果。

    在上述例子中,即将持续通断高低电平代替模拟信号(1.8V)。

    占空比为:正脉冲的持续时间与脉冲总周期的比值。此例中占空比即为20%。(尊重原创)

    --------------------- 本文来自 HejaBVB 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/u013131866/article/details/36672671?utm_source=copy 

    二、软件如何模拟

    1、上面已经解释了什么是脉宽调制PWM,我们使用单片机模拟的思路是,首先使用单片机定时器来定个最小分辨的时间t;

    2、在定时器中断中,设置一个标志位(pwm_time),每次进中断,也就是每隔 t 时间加1,这就是我们要产生的PWM频率,则PWM周期为(100xt),频率为1/(100xt);

    3、再设置在100个t中,需要n个高电平(1)则需要的低电平(0)为(100-n)个,其实这个就是调节占空比(高电平时间占整个周期时间的比值);

    4、举个“栗子”,假如我要产生一个PWM频率是1Khz ,占空比为 20%的信号,则,需要首先计算出,最小分辨时间t,1Khz的频率,则周期为1ms=1000us,则t=1000us/100=10us;n呢,就是n/100%=20%,n=20;

    三、程序示例

     1 unsigned char pwm_time=0;
     2 unsigned char pwm_r_data=0;
     3 unsigned char pwm_g_data=0;
     4 unsigned char pwm_b_data=0;
     5 /*
     6   使用定时器T1,设定中断时间为10us,在中断函数面,设置一个标志位(pwm_time),来确定产生的PWM频率
     7 因为这里我们是产生周期为1ms(1kHZ)的PWM,所以可设置中断的时间基准为0.01ms,,然后中断100次即为1ms。在中断子程序内,可设置一个变量如pwm_time,在中断子程序内,有三条重要的语句:
     8 
     9 1、当time>=100时,time清零(此语句保证频率为1kHZ);
    10 
    11 2、当time>n时(n应该在0-100之间变化开),让单片相应的I/O口输出低电平;
    12 
    13 3、当time<=n时,让单片相应的I/O口输出高电平,此时占空比就为%n。
    14 
    15 */
    16 
    17 
    18 void IO_init() //设置P0.0口为上拉输入,(INT0),P0.1-P0.3为推挽输出
    19 {
    20   P0DPL=0XA9;   
    21 }
    22 
    23 
    24 void pwm_init()
    25 {
    26   TMOD=TMOD|0X20;            //定时器T1设置为模式2 8位自动重载模式
    27   TIMPRS=0X00;              //定时器工作时钟位PCLK/2       2分频
    28   TR1=1;                   //开启定时器T1
    29   TL1=235;                   //约10us,示波器测得
    30   TH1=TL1;                    //8位自动重载
    31   ET1=1;                   //允许定时器T1中断
    32   EA=1;                      //开总中断
    33 }
    34 void LED_PWM(unsigned char a,unsigned char b,unsigned char c)      //三路PWM,R/G/B
    35 {
    36     pwm_r_data=a;
    37     pwm_g_data=b;
    38     pwm_b_data=c;
    39 }
    40 void main()
    41 {
    42    SPKEY=0X36;              //打开写保护开关
    43    CKDS=0X03;              //4分频   MLCK=pclk=32mhz/4=8mhz   主时钟频率为8MHz 
    44    IO_init();              //I/O口初始化
    45    pwm_init();              //定时器初始化
    46   LED_PWM(20,20,20);
    47   while(1);
    48 }
    49 void timer1(void) interrupt 3     //定时器T1中断函数入口         //10us进一次中断  10usX100=1000us=1ms    f=1/1ms=1Khz
    50 {
    51              pwm_time++;
    52        if(pwm_time>=100)       pwm_time=0;
    53 
    54        if(pwm_time<=pwm_r_data)   R=1;
    55         else R=0;
    56 
    57        if(pwm_time<=pwm_g_data)   G=1;
    58         else G=0;
    59 
    60        if(pwm_time<=pwm_b_data)   B=1;
    61         else B=0;
    62 }

     

  • 相关阅读:
    关于git的文件内容冲突解决
    【C++】 四种强制类型转换(static_cast 与 dynamic_cast 的区别!)
    如何判断一个变量是不是指针
    类型识别
    C++中的异常处理(下)
    C++中的异常处理(中)
    C++中的异常处理(上)
    C语言异常处理
    用Zebra打造Linux下小型路由器
    Linux下PortSentry的配置
  • 原文地址:https://www.cnblogs.com/UPUPDay2152/p/9705394.html
Copyright © 2020-2023  润新知