jiang887786 发表于 2012-11-20 18:29:23

有人在用595扩展pwm信号吗?谁有思路?指教一二!

有人在用595扩展pwm信号吗?谁有思路?指教一二!我看见一个舵机驱动板有32路pwm输出,问了老板,他说是用595在扩展pwm输出,不知道他是不是用的专业pwm芯片。想不通是什么原理。请大神指教一下!他的地址:http://item.taobao.com/item.htm?spm=937.1000770.1000419.1.tXERTh&id=19214924650&asker=wangwang&wwdialog=bbxxbbmc&ad_id=&am_id=&cm_id=&pm_id=

先声明本人绝不是做广告的,广告者死光!谢谢大家指点!还有谁有pudn的账号帮忙下了看看呢?感谢!
http://www.pudn.com/downloads149/sourcecode/embed/detail643936.html

jiang887786 发表于 2012-11-20 18:32:19

自己先顶一个!大家共同讨论进步,谢谢!

jimmy_xt 发表于 2012-11-20 19:12:33

常见舵机,PWM频率很低。用595搞没啥问题。

一般就是MCU+一堆595.

jiang887786 发表于 2012-11-20 19:33:01

有资料给点看看吗?谢谢了。

geniuskim 发表于 2012-11-20 19:44:38

jiang887786 发表于 2012-11-20 19:33 static/image/common/back.gif
有资料给点看看吗?谢谢了。

模拟舵机频率超级低

只是用595扩展io而已。由于频率低,就用定时器做都没问题。

jiang887786 发表于 2012-11-20 19:58:44

那么占空比很好做吗?如果想做占空比0-99%,可以做到吗?

zhutr99 发表于 2012-11-20 20:54:55

没有问题的啊,只不过是通过复杂点的程序控制595输出的状态,频率没有直接单片机IO那么快而已,而且595可以支持很高的频率,如果用FPGA,可以做得比单片机的PWM好

jiang887786 发表于 2012-11-21 22:03:53

{:sad:},你们都说简单,可我比较菜啊,谁能说说思路啊?我发现了一个飞思卡尔的单片机程序是用定时器模拟的pwm不知道怎么样,程序我贴一下不知道篇幅够不够。
#include <hidef.h>      /* common defines and macros */
#include <MC9S12XEP100.h>   /* derivative information */
#pragma LINK_INFO DERIVATIVE "mc9s12xep100"

#define ECT_OC7D_OC7D4_MASK 16   // ??? not defined in library in CW 4.7 ???

//******************************************************************************
// This software is classified as Engineering Sample Software.               
//******************************************************************************
// - OSCILLATOR = 16MHz
// - BUS CLOCK = 25 MHz
// - the sample software does:
// - It generates periodic signal on the port PT4 with variable frequency and stop and start feature
//
//******************************************************************************
// DEFINITIONS
//******************************************************************************
#define   UBYTE       unsigned char
#define   SBYTE                char
#define   UWORD       unsignedint
#define   SWORD               int
#define   ULONG       unsignedlong
#define   SLONG               long
//******************************************************************************
// FUNCTION PROTOTYPES
//******************************************************************************
#define   BUSCLK      25000 //
//******************************************************************************
// FUNCTION PROTOTYPES
//******************************************************************************
static void PLL_Init(UBYTE synr, UBYTE refdv, UBYTE postdiv);

void TimerSetup(void);
void startOutputSignal_on_PT4(void);
void stopOutputSignal_on_PT4(void);
void permanent_1_on_PT4(void);
void changePeriod(ULONG per_us);            // input parameter = required period in us
void changeDuty(UWORD duty);      // duty cycle = 0~period (period is calculated global variable)
                                          // IOW it is value of period register TC7

//******************************************************************************
static UWORD period;
//******************************************************************************
// void main(void)
//******************************************************************************
void main(void)
{
ULONG i;
UWORD j;
//----------------------------------------
ECLKCTL_NECLK = 0;                           // see bus clock on PE4
//----------------------------------------
// set 25MHz bus clock from 16MHz OSCCLK // PLL_Init(SYNR;REFDV;POSTDIV)
PLL_Init(0xD8,0x07,0x01);
//----------------------------------------
// - The 1 MHz frequency is generated by means of Main Timer counter in the underflow interrupt by toggling required port.
//   Generated on the port PT4.
TimerSetup();
//----------------------------------------
startOutputSignal_on_PT4();
for(;;)
    {
   changePeriod(10000); //10ms
   changeDuty(period/2);

   for(i=0;i<0x1FFFFF;i++) asm nop;      // SW delay
   stopOutputSignal_on_PT4();
   for(i=0;i<0x1FFFFF;i++) asm nop;      // SW delay
   startOutputSignal_on_PT4();
   for(i=0;i<0x1FFFFF;i++) asm nop;      // SW delay
   permanent_1_on_PT4();
   for(i=0;i<0x1FFFFF;i++) asm nop;      // SW delay
   changePeriod(4000);//4ms
   startOutputSignal_on_PT4();
   
   for(j=0;j<=period;j++)
      {
      changeDuty(j);
      for(i=0;i<0x3FF;i++) asm nop;      // SW delay
      }
   for(i=0;i<0x1FFFFF;i++) asm nop;      // SW delay
    }         
}
//******************************************************************************
// void changePeriod(ULONG period)
//******************************************************************************
// timer frequency = BUSCLK/(TC7+1)/prescaler=BUSCLK/(TC7+1)/16
// 50% duty cycle; = (TC7-1)/2

void changePeriod(ULONG per_us) //; (1.28us < period < 41942.4us) for 25MHz busclk and tim prsclr=16 (see TSCR2 setup)
{                               // max err in the setup is (TC7min+1)*16/busclk=(0+1)*16/25000000=640ns
ULONG per;
per= per_us*BUSCLK/1000/16-1;
ECT_TC7= (UWORD) per;
period = (UWORD) per;
}
//******************************************************************************
// void changeDuty(UWORD duty)
//******************************************************************************
void changeDuty(UWORD duty) //; (1.28us < period < 41942.4us) for 25MHz busclk and tim prsclr=16
{               // max error in the setup is (TC7min+1)*16/busclk=(0+1)*16/25000000=640ns
if(duty>period) duty=period;
ECT_TC4= duty;
}
//******************************************************************************
// void permanent_1_on_PT4(void)
//******************************************************************************
void permanent_1_on_PT4(void)
{
ECT_TCTL1 |= ECT_TCTL1_OM4_MASK | ECT_TCTL1_OL4_MASK; // channel 4 - PT4 - set output on compare, channels 0,2,3 disconnected from output pin logic
ECT_OC7D|= ECT_OC7D_OC7D4_MASK;               // set PT4 on PT7 compare
}
//******************************************************************************
// void startOutputSignal(void)
//******************************************************************************
void startOutputSignal_on_PT4(void)
{
// see description of stopOutputSignal
ECT_TCTL1 &= (~(ECT_TCTL1_OM4_MASK | ECT_TCTL1_OL4_MASK)); // clear bits of channel PT4
ECT_TCTL1 |= ECT_TCTL1_OM4_MASK;                     // channel 4 - PT4 - clear output on compare, channels 0,2,3 disconnected from output pin logic
ECT_OC7D |= ECT_OC7D_OC7D4_MASK;                     // set PT4 on PT7 compare
}
//******************************************************************************
// void stopOutputSignal(void)
//******************************************************************************
void stopOutputSignal_on_PT4(void)      // log 0 on PT4
{ // do not use OMn,OLn bit combination "Disconnected from output pin logic"
// because in the case of PT7 is used as a period generator then this option does not
// work. - Not documented erratum - I discovered it 3 weeks ago. The bug is in solution.

// The solution can be done by correct signal setup. Because, on the TC7 compare bit OC7D bit n says
// "set corresponding channel n to 1 on TC7 compare" and the channel n compare action is clear on compare
// then it is enough to change OC7D bit n to 0 => clear corresponding bit of channel n on TC7 compare.
ECT_TCTL1 &= (~(ECT_TCTL1_OM4_MASK | ECT_TCTL1_OL4_MASK)); // channel 4 - PT4 - clear output on compare, channels 0,2,3 disconnected from output pin logic
ECT_OC7D&= (~ECT_OC7D_OC7D4_MASK);                   // clear PT4 on PT7 compare
}
//******************************************************************************
// static void TimerSetup(void)
//******************************************************************************
void TimerSetup(void)
{
//--- channel 0-7 setup -------------------
ECT_TCTL1 = 0x01;                        // channels 7-5 disconnected from output pin logic
ECT_TIOS= 0x90;                        // channel 7,4 - PT4 - output compare
ECT_OC7M= ECT_OC7M_OC7M4_MASK;         // channel 4 - PT4 - is an output port for channel 7 compare
//-----------------------------------------
changePeriod(10000);                     // ; (1.28us < period < 41942.4us) for 25MHz busclk and tim prsclr=16
changeDuty(period/2);                      // 50% duty cycle
stopOutputSignal_on_PT4();               // channel 4 - PT4 - set PT4 on PT7 compare =>left aligned PWM
ECT_TSCR2 = 0x0C;                        // prescaler =16,reset tim by a output compare of channel 7
                                          // ovf int disable
//-----------------------------------------
ECT_TSCR1 = 0xF0;                        // enable timer,stop in wait,stop in freeze, fast flag clear
}
//******************************************************************************
// static void PLL_Init(UBYTE syn, UBYTE refdv)
//******************************************************************************
static void PLL_Init(UBYTE synr, UBYTE refdv, UBYTE postdiv)
{
PLLCTL_PLLON= 0;                        // Disable the Phase Lock Loop   
CLKSEL_PLLSEL = 0;                        // Select clock source from OSCCLK
CLKSEL_PLLWAI = 1;                        // PLL stops in wait mode   
SYNR          = synr;   
REFDV         = refdv;
POSTDIV       = postdiv;
PLLCTL_PLLON= 1;                        // Enable the Phase Lock Loop   
while(!CRGFLG_LOCK);                      // Wait till the PLL VCO is within tolerance
CLKSEL_PLLSEL = 1;                        // Select clock source from PLLCLK
}
//******************************************************************************
// Services performed by FREESCALE in this matter are performed AS IS and without any warranty. CUSTOMER retains
// the final decision relative to the total design and functionality of the end product. FREESCALE neither
// guarantees nor will be held liable by CUSTOMER for the success of this project.
// FREESCALE DISCLAIMS ALL WARRANTIES, EXPRESSED, IMPLIED OR STATUTORY INCLUDING, BUT NOT LIMITED TO, IMPLIED
// WARRANTY OF MERCHANTABILITY ORFITNESS FOR A PARTICULAR PURPOSE ON ANY HARDWARE, SOFTWARE ORE ADVISE SUPPLIED
// TO THE PROJECT BY FREESCALE, AND OR NAY PRODUCT RESULTING FROM FREESCALE SERVICES . IN NO EVENT SHALL FREESCALE
// BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT.
//
// CUSTOMER agrees to hold FREESCALE harmless against any and all claims demands or actions by anyone on account of
// any damage, or injury, whether commercial, contractual, or tortuous, rising directly or indirectly as a result of
// the advise or assistance supplied CUSTOMER in connection with product, services or goods supplied under this Agreement.
//******************************************************************************

jiang887786 发表于 2012-12-11 17:21:04

{:lol:}dingyigr顶一个

jiang887786 发表于 2012-12-11 21:29:23

#include <stc89c5x.h>//STC89C52

//串行驱动1602,powered by 595
#define LCD1602_BACKLIGHT      P1_3//背光
#define LCD1602_SDA                        P1_0//数据输入
#define LCD1602_SCK                        P1_1//移位时钟,SHCP,11pin
#define LCD1602_SCL                        P1_2//锁存时钟,STCP,12pin

/*
* 硬件连接:
* 74HC595 Q7 - 1602 RS
* GND - 1602 RW(595没有输入功能,所以判定忙只能*延时,另外就是MCU的速度比较的慢。所以也可以直接去掉延时。但是在STC12系列上的表现,相当的不错
* 在传统51上面。PWM占空比低于50%将会出现扫描线。12系列的,很高兴的告诉大家。T0X12开了以后。不会有扫描线出现。但是如果一定要在传统51上使用的话,请把10级调光改成4级。谢谢合作!
* 74HC595 Q6 - 1602 EN
* 74HC595 Q5~Q2 - 1602 D5~D7(这一次硬件设计不合理,才只能搞软件修正了。不过好处就是直接就可以洞洞板上对着联,减少了烧坏595的概率。坏处就是CPU时间消耗的多了点。但是可以取消延时函数啦~
* 1602 D1~D4 直接悬空
* LCD_BACKLIGHT加一级PNP三极管射随器加到液晶的A上,如果无需调光可以去掉这一部分电路和代码
* 至于595的连接,只要不弄反SCL和SCK,就没有问题啦~
*/

__sbit__at0xE0 A_0;//方便位操作,硬件设置真的是败笔 - -
__sbit__at0xE1 A_1;
__sbit__at0xE2 A_2;
__sbit__at0xE3 A_3;
__sbit__at0xE4 A_4;
__sbit__at0xE5 A_5;
__sbit__at0xE6 A_6;
__sbit__at0xE7 A_7;
__sbit__at0xF1 B_1;
__sbit__at0xF2 B_2;
__sbit__at0xF3 B_3;
__sbit__at0xF4 B_4;
__sbit__at0xF5 B_5;
__sbit__at0xF6 B_6;
__sbit__at0xF7 B_7;

unsigned char PWM_Cycle=0;//PWM占空比
unsigned char PWM_T=0;//PWM当前所处周期
unsigned char OutBuf=0xff;//输出缓冲
#define      LCD_OFF         lcd_wcmd(0x08)
#define      LCD_CUR         lcd_wcmd(0x0E)
#define      LCD_FCUR       lcd_wcmd(0x0F)
void delay(unsigned int n)
{
unsigned int x,y;
for(x=n;x>0;x--)
for(y=100;y>0;y--);
}

void Send595()
{
      unsigned char i,j;
      j=0x80;
      LCD1602_SCK=0;
      for(i=0;i<8;i++)
      {
                LCD1602_SDA=OutBuf & j;
                j=j>>1;
                LCD1602_SCK=1;
                LCD1602_SCK=0;
      }
      LCD1602_SDA=1;
      LCD1602_SCL=0;
      LCD1602_SCL=1;
}
void lcd_en()
{
      //OutBuf=OutBuf|0x40;//E=1
      B=OutBuf;
      B_6=1;
      OutBuf=B;
      Send595();//输出数据
      B=OutBuf;
      B_6=0;
      OutBuf=B;//E=0
      Send595();
}

/**********************************************************/
void lcd_wcmd(unsigned char i)
{
//写命令
      B=OutBuf;
      B_7=0;//RS=0,RW=0;
      OutBuf=B;
      Send595();
//--------------
      B=OutBuf;
      ACC=i;
      B_2=A_7;//D7=D7
      B_3=A_6;//D6=D6
      B_4=A_5;//D5=D5
      B_5=A_4;//D4=D4
      OutBuf=B;
      Send595();
      lcd_en();
//================
      ACC=i;
      B=OutBuf;
      B_2=A_3;//D7=D3
      B_3=A_2;//D6=D2
      B_4=A_1;//D5=D1
      B_5=A_0;//D4=D0
      OutBuf=B;      
      Send595();
      lcd_en();
}
void lcd_wdat(unsigned char i)
{
//写数据
      B=OutBuf;
      B_7=1;//RS=0,RW=0;
      OutBuf=B;
      Send595();
//--------------
      B=OutBuf;
      ACC=i;
      B_2=A_7;//D7=D7
      B_3=A_6;//D6=D6
      B_4=A_5;//D5=D5
      B_5=A_4;//D4=D4
      OutBuf=B;
      Send595();
      lcd_en();
//================
      ACC=i;
      B=OutBuf;
      B_2=A_3;//D7=D3
      B_3=A_2;//D6=D2
      B_4=A_1;//D5=D1
      B_5=A_0;//D4=D0
      OutBuf=B;      
      Send595();
      lcd_en();
}

void lcd_putchar(unsigned char addr,unsigned char ch)
{//写一个字
      lcd_wcmd(0x80+addr);
      lcd_wdat(ch);
}

void lcd_display(unsigned char *l1,unsigned char *l2)
{//写一屏幕
      unsigned char i=0;
      lcd_wcmd(0x80); //显示地址设为80H(即00H,)上排第一位
      for(i=0;i<16;i++)
      {
                lcd_wdat(l1);
      }
      lcd_wcmd(0x80+0x40); //重新设定显示地址为0xc0,即下排第1位
      for(i=0;i<16;i++)
      {
                lcd_wdat(l2);
      }
}

void lcd_cls()
{
      lcd_wcmd(0x01); //清屏延时函数可以省略
}
//米有读函数,但是功能可以由上面的函数扩展哦~
void lcd_init()
{
    OutBuf=0xff;
    Send595();//复位VIO,这段代码必须加。否则MCU忽然RESET会导致液晶乱码
    lcd_wcmd(0x30);//复位1602,这段代码必须加,同上
    lcd_en();//唤醒
      lcd_wcmd(0x20);
      lcd_en();//唤醒
      lcd_wcmd(0x28); //四位,5x7
      lcd_wcmd(0x0c); //开启显示屏,关光标,光标不闪烁
      lcd_wcmd(0x06); //显示地址递增,即写一个数据后,显示位置右移一位
      lcd_wcmd(0x01); //清屏      
      //调试的时候被设计失误的对比度电位器坑死了:就是两排小方块死都不显示
      //查了半天都不知道
      //最后捅了下电位器就正常了……
}
void lcd_print(unsigned char *str)
{
    unsigned char addr=0x80,len=0;
    lcd_wcmd(addr); //显示地址设为80H(即00H,)上排第一位
    while(*str!='\0')
    {//等待末尾
      if(len >= 16)
      {
            lcd_wcmd(0x80+0x40);//下排第一位,换行
            len=0;
      }
      if(*str=='\n')
      {
            lcd_wcmd(0x80+0x40);//下排第一位,换行
      }
      else
      {
            lcd_wdat(*str);   
      }
      str++;
      len++;
    }
}//写字符串函数
void PWM() __interrupt 1 __using 1
{
      ET0=0;
      TF0=0;//CLR
      TR0=0;
      EA=0;
      TH0=0xFC;TL0=0x00;//十级调光,频率400Hz
      if(PWM_T>10) {PWM_T=0;}
      if(PWM_Cycle>PWM_T){ LCD1602_BACKLIGHT=0;}
      if(PWM_Cycle<PWM_T){LCD1602_BACKLIGHT=1;}
      PWM_T++;
      TR0=1;
      ET0=1;
      EA=1;
}

void main()
{//主函数

      TMOD = 0x01 ;
      TH0=0xFC;TL0=0x00;
      TR0=1;ET0=1;
      EA=1;//开中断
      //-----------------
      lcd_init();
      PWM_Cycle=10;//背光100%
      //液晶初始化---------
      while(1)
      {
                lcd_display("Hello world!","Serial mode 1602");
                delay(2000);
                lcd_display("Drive by 74HC595","Design by rgwan ");
                delay(2000);
                lcd_display("Website address:"," www.rwzy.co.cc ");
                delay(2000);
                lcd_display("Backlight ctl by","T0 PWM 400Hz");
                delay(2000);
      }
}

页: [1]
查看完整版本: 有人在用595扩展pwm信号吗?谁有思路?指教一二!