PWM可调波形设计


PWM可调波形,修改函数参数,即可产生各种可调占空比的PWM波

我也来说两句 查看全部回复

最新回复

  • yuxu9710108 (2008-8-15 10:12:38)

    //PWM 波形产生源码

    #include "reg51.h"

    #ifndef FREQ_OSC
    #define FREQ_OSC  (12)//12Mhz
    #endif

    #define HIGH_WAVE  1
    #define LOW_WAVE   0

    sbit LED=P1^0;

    static unsigned char __TL0_high;
    static unsigned char __TH0_high;
    static unsigned char __TL0_low;
    static unsigned char __TH0_low;
    static int flag;


    /* 1)CPU时序:
    * XTAL1, XTAL2并联石英谐振器和振荡电容后产生单片机的基本时钟频率fosc
    * 基本时钟:fosc  -->  振荡周期:Tosc <--> 一个Tosc对应一个节拍P1/P2相 --> 2个Tosc构成一个状态周期Ts
    * --> 6个状态周期Ts组成一个机器周期TM --> 机器周期是指令周期的基本单位
    *  fosc --> Tosc == P1/P2 -->Ts  --> TM -->指令周期
    *  所以一个指令周期 == 1个TM == 6Ts == 12Tosc == 6个P1+6个P2
    *  单周期指令 = 1个指令周期 = 1TM = 6Ts = 12Tosc
    *  双周期指令 = 2个指令周期 = 2TM = 12Ts = 24Tosc
    *
    * 指令运行速度:MIPS = fosc/12 (MIPS)
    * fosc 6Mhz  MIPS 6Mhz/12=0.5 MIPS 每秒伍十万条指令
    * fosc 12Mhz  MIPS 12Mhz/12=1 MIPS 每秒一百万条指令
    * fosc 24Mhz  MIPS 24Mhz/12=2 MIPS 每秒二百万条指令
    * fosc 48Mhz  MIPS 48Mhz/12=4 MIPS 每秒四百万条指令
    *
    * 2)反汇编代码如下:
    * 16:     TH0 = __TL0_HIGH;
    * C:0x08CE    85088C   MOV      TH0(0x8C),0x08
    * 17:     TL0 = __TL0_LOW;
    * C:0x08D1    85098A   MOV      TL0(0x8A),0x09
    * 18:     TR0 = 1;
    * C:0x08D4    D28C     SETB     TR0(0x88.4)
    * 19:     LED = ~LED;
    * C:0x08D6    B290     CPL      LED(0x90.0)
    * 注意:MOV, SETB, CPL均为1个TM,1个指令周期
    * 这里每次时钟中断都要重设TH0,TL0,TR0,均要多消耗3个指令周期所以计数值__TL0_LOW再加上3个周期以校正
    */

    void led_int() interrupt 1 using 0
    {
        if( flag == LOW_WAVE){
            TH0 = __TH0_high;
            TL0 = __TL0_high;
            TR0 = 1;
            LED = ~LED;
            flag = HIGH_WAVE;

        }

        else if(flag == HIGH_WAVE){
            TH0 = __TH0_low;
            TL0 = __TL0_low;
            TR0 = 1;
            LED = ~LED;
            flag = LOW_WAVE;
        }
        else{
        }
    }

    int check_us(unsigned short x_us)
    {
        if(x_us < (12 / FREQ_OSC)){
            return  -1;
        }
        return  0;
    }

    //计数脉冲周期:
    //T(us) = 1/(fosc (Mhz) / 12)将fosc进行12分频后再送入计数器,所以不同频率的CPU其计数脉冲周期不同,最小可分辨的时间精度不同。
    //不同频率的CPU的/计数脉冲周期
    //6Mhz: T(us) = 12 / (6 Mhz) = 2us
    //12Mhz:T(us) = 12 / (12 Mhz) = 1us
    //24Mhz:T(us) = 12 / (24 Mhz) = 0.5us
    //48Mhz:T(us) = 12 / (48 Mhz) = 0.25us

    //单次定时方式1,16位计数,最大定时长度:
    //6Mhz: 2us * 2^16 /1000 131ms
    //12Mhz: 1us * 2^16 /1000 65ms
    //24Mhz: 0.5us * 2^16 /1000 32ms
    //48Mhz: 0.25us * 2^16 /1000 16ms

    //x:所定的半周期时间,以微秒为单位
    //计数初值m = 2^16 - x*fosc/12
    void init_rectangular_wave(unsigned short x_us_high, unsigned short x_us_low)
    {
        unsigned short m;//计数初值

        if(-1 == check_us(x_us_high))
            return ;

        if(-1 == check_us(x_us_low))
            return ;

        TMOD = 0x01;//TMOD: GATE  c/nT  M1 M0 : 计数器由内部TRi位控制启停,计时功能,方式一:16位计数

        m = 2^16 - (x_us_high * FREQ_OSC) / 12;
        __TL0_high = m & 0x00ff;
        __TH0_high = (m & 0xff00) >> 8;
        __TL0_high -= 5;//校正计时常数,当定时越小时,这个校正因数当越大

        m = 2^16 - (x_us_low * FREQ_OSC) / 12;
        __TL0_low = m & 0x00ff;
        __TH0_low = (m & 0xff00) >> 8;
        __TL0_low -= 7;//校正计时常数,当定时越小时,这个校正因数当越大

        LED = 1;
        TL0 = __TL0_high;
        TH0 = __TH0_high;
        EA = 1;
        ET0 = 1;
        TR0 = 1;
        flag = HIGH_WAVE;
    }

    void init_led()
    {
        LED = 0;
    }

    int main()
    {
        init_led();
        init_rectangular_wave(30, 120);
        while( 1 )
        {
            ;
        }
        return 0;
    }
  • yuxu9710108 (2008-8-15 10:15:17)

    即单片机外接一个电阻而矣,没什么大的。
  • hekun559 (2008-8-17 21:23:52)


    顶下楼主~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
  • bj301 (2008-8-18 00:32:25)

    顶一下。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
  • yuxu9710108 (2008-8-18 17:40:50)

    但是当用不同频率的CPU时,调节不同的占空比时,会有些误差,需调节下较正定时常数,
    不知有没有更好更精确的方法[软件上]来统一解决之
  • janfen406 (2008-8-19 22:37:27)

    dddddddddddddddddddddddddddddddddddddddddddd
  • fghjkl (2008-8-20 11:09:38)

    我也做过,使用定时器做的,挺占CPU资源的,而且频率也不能做太大.
  • fghjkl (2008-8-20 11:13:20)

    我个人觉得最好用本身能产生PWM的单片机作是最好的.
  • djh2007 (2008-8-20 11:22:00)

    这好东西啊 ,顶顶~~~~~~