搜索
bottom↓
回复: 38

共享:74HC595产生256步PWM驱动LED(我的重量级资料)

[复制链接]

出0入0汤圆

发表于 2011-3-26 11:19:18 | 显示全部楼层 |阅读模式
利用AVR的硬件SPI驱动74HC595产生256级(即8位)PWM,74HC595还可以联级,我试过一次联级了16个74HC959。程序是用AVR汇编写的,已经写成模块化了的,移植很简单。在这个坛里混了一段时间了,一直都没有贡献出什么,现在将我的重量级资料共享给大家!!如果有不懂的地方大家可以留言,我尽量为大家解答~~~
另:这里也有一个关于“如何控制74hc595驱动led产生灰度等级 ”
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=985613&bbs_page_no=1&bbs_id=9999

#include <avr/io.h>

.global            TIMER2_COMP_vect

.comm cPwmCount                             1, 1       ;声明变量,第一个数字表示变量的大小,第二个表示一组   

TIMER2_COMP_vect:

        sbi     _SFR_IO_ADDR(PORTB), 2         ;置位PORTB的第二位  这里是连接74HC595的数据锁存口         
        cbi     _SFR_IO_ADDR(PORTB), 2         ;清除PORTB的第二位  

;        sei    打开总中断,这个可以根据自己的程序需要做决定

        push    r24                            ;堆栈
        in      r24, _SFR_IO_ADDR(SREG)        ;将SREG数据读到r24中
        push    r24                            ;堆栈
        push    r25                            ;堆栈
        push    r26                            ;堆栈
        push    r30                            ;堆栈
        push    r31                            ;堆栈


        lds     r26, cPwmCount                  ;将cPwmCount的值送到r24(是直接从SRAM中读取的)      
        subi    r26, 1                          ;r24减去1之后将结果保存到r24中,即r24自减1
        brcc    save_pwmCount                   ;当c标志等于0时跳转到save_pwmCount
        ldi     r26, 255                        ;加载立即数,将255送到r24 这里的255就是你所要产生的PWM步数,最大为255,根据需要做调整save_pwmCount:
        sts     cPwmCount, r26                  ;将立即数直接储存到SRAM中

        ldi     r30, lo8(Led)                   ;将低8位数据送到r30 Led是一个结构体,结构体的头一个变量是数组,数组的空间=N个74HC595 * 8
        ldi     r31, hi8(Led)                   ;将高8位数据送到r31

comp_r25_red_0:
        ld      r25, z+                         ;取LED的首地址给r25后地址指针自加1
        cp      r26, r25                        ;r26与r25比较
        ror     r24                             ;通过进位位C向右移动
comp_r25_red_1:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_red_2:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_red_3:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_red_4:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_red_5:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_red_6:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_red_7:
        ld      r25, z+
        cp      r26, r25
        ror     r24
        out     _SFR_IO_ADDR(SPDR), r24             ;将r24的数据送到SPDR驱动    我这里是联级了4个74HC595

comp_r25_green_0:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_green_1:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_green_2:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_green_3:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_green_4:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_green_5:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_green_6:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_green_7:
        ld      r25, z+
        cp      r26, r25
        ror     r24
        out     _SFR_IO_ADDR(SPDR), r24

comp_r25_blue_0:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_blue_1:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_blue_2:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_blue_3:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_blue_4:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_blue_5:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_blue_6:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_blue_7:
        ld      r25, z+
        cp      r26, r25
        ror     r24
        out     _SFR_IO_ADDR(SPDR), r24
       
comp_r25_while_0:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_while_1:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_while_2:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_while_3:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_while_4:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_while_5:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_while_6:
        ld      r25, z+
        cp      r26, r25
        ror     r24
comp_r25_while_7:
        ld      r25, z+
        cp      r26, r25
        ror     r24       
        out     _SFR_IO_ADDR(SPDR), r24         

        pop     r31                             ;弹出堆栈
        pop     r30                             ;弹出堆栈
        pop     r26                             ;弹出堆栈
        pop     r25                             ;弹出堆栈
        pop     r24                             ;弹出堆栈
        out     _SFR_IO_ADDR(SREG), r24         ;将状态数据送到SREG端口
        pop     r24                             ;弹出堆栈

        reti                                    ;中断返回

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2011-3-26 11:39:01 | 显示全部楼层
弄个视频来看一下嘛

出0入0汤圆

 楼主| 发表于 2011-3-26 11:47:12 | 显示全部楼层
回复【1楼】laolu
弄个视频来看一下嘛
-----------------------------------------------------------------------

- -!我现在是在公司上班的,哪里敢弄视频啊?

出0入0汤圆

发表于 2011-3-26 11:50:23 | 显示全部楼层
回复【楼主位】chenyuqiu 小陈
-----------------------------------------------------------------------

程序完整吗? 看起来不完整!!不知道是不是没看懂,

出0入0汤圆

 楼主| 发表于 2011-3-26 11:54:11 | 显示全部楼层
回复【3楼】rjinglan

回复【楼主位】chenyuqiu 小陈
-----------------------------------------------------------------------
程序完整吗? 看起来不完整!!不知道是不是没看懂,
-----------------------------------------------------------------------

呵呵,其实是完整的了,只是你还没好好看看

出0入0汤圆

发表于 2011-3-26 12:07:14 | 显示全部楼层
回复【4楼】chenyuqiu 小陈
-----------------------------------------------------------------------

牛!还是看没明白,发个C版本的吧!这样一目了然了,汇编菜鸟!

下班回去再研究研究!

出0入0汤圆

发表于 2011-3-26 12:09:04 | 显示全部楼层
Mark

出0入0汤圆

 楼主| 发表于 2011-3-26 12:18:28 | 显示全部楼层
回复【5楼】rjinglan
回复【4楼】chenyuqiu 小陈
-----------------------------------------------------------------------
牛!还是看没明白,发个c版本的吧!这样一目了然了,汇编菜鸟!
下班回去再研究研究!
-----------------------------------------------------------------------

因为是模拟PWM的,所以在时间上要求比较搞,用C的话效率不高的。

出0入0汤圆

发表于 2011-3-26 13:36:44 | 显示全部楼层
mark

lz上c版的吧,,,

出0入0汤圆

 楼主| 发表于 2011-3-26 14:19:31 | 显示全部楼层
回复【8楼】guxingganyue

mark
lz上c版的吧,,,
-----------------------------------------------------------------------

回8楼:我这个程序已经是一个模块化了,不需要你去更改什么,直接可以调用。

出0入0汤圆

发表于 2011-3-26 14:55:37 | 显示全部楼层
强烈建议上C!!!

出0入0汤圆

 楼主| 发表于 2011-3-26 16:00:28 | 显示全部楼层
回复【10楼】danielmi 俊俊
强烈建议上c!!!
-----------------------------------------------------------------------

- -!

出0入0汤圆

发表于 2011-3-26 16:36:14 | 显示全部楼层
C的话效率的确要低,楼主的“重量级”就在于汇编,C仅供参考;

大概是这样的,
1,硬件上,MOSI接595的DS,SCK接595的SH_CP,595的OE可以直接接地,MR可以直接接高电平,ST_CP接PB2(楼主硬件);
2,设置好SPI,主机模式;
3,因为每隔一定的时间要更新一次数据,最好使用定时器作时间基准,普通模式或CTC模式都可以;所以设置定时器,溢出时间有刷新频率和灰度决定;
4,以在T2溢出中断程序里面处理该函数为例(其实楼主的就是,因为(reti)),下面是C程序(ICCAVR);

unsigned char cPwmCount;
unsigned char led_pwm[32];  //每个LED的灰度,4个595,可单独控制32个LED
                            //第0个为最远端LED的数据

#pragma interrupt_handler TIMER2_COMP_vect:iv_TIMER2_COMP
void TIMER2_COMP_vect (void)
{
  unsigned char i,j;
  unsigned char data_buf;
  unsigned char *p;
  
  PORTB|=0x04;                     //锁存数据
  PORTB&=0xFB;
  
  cPwmCount--;                     //0-1=255
                                   //楼主的"save_pwmCount:"在"sts     cPwmCount, r26"前
  p=led_pwm;

  for(j=0;j<4;j++)                 //多少个595就循环多少次
  {
    data_buf=0x00;
    for(i=0;i<8;i++)               //得到一个8位调光数据,SPI数据寄存器是8位的
    {
      data_buf<<=1;
      if(cPwmCount<(*p))data_buf|=0x01;
      p++;
    }
    SPDR=data_buf;                 //要保证启动下一次发送时数据已发送完毕
  }                                //由于发送之后不等待是否完成,所以数据锁存放在下一次数据更新开始                  

}

如有不妥,请指正;如有侵权,请告知删除!

出0入0汤圆

 楼主| 发表于 2011-3-26 16:49:54 | 显示全部楼层
回复【12楼】xiaowu191 小屋
-----------------------------------------------------------------------

呵呵,原来是屋工啊!!!看来你对我的汇编程序可是了解得一清二楚啊,呵呵。我之所以不用C就是因为实际应用中用C的话其实效果很不理想的,谢谢你把我的汇编程序翻译成C的,这样方便大家学习!!

出0入0汤圆

 楼主| 发表于 2011-3-26 16:51:52 | 显示全部楼层
另:我的汇编程序是用WinAVR编译器的

出0入0汤圆

发表于 2011-3-26 17:46:56 | 显示全部楼层
回复【12楼】xiaowu191 小屋
-----------------------------------------------------------------------

太给力啦! 另外问问?
                            //每个LED的灰度,4个595,可单独控制32个LED
                            //第0个为最远端LED的数据

这两句话说单独控制意思是控制一个全彩的 一个基色 是吧!要是想全彩那么32个LED 就需要 4*3(R+G+B)=12个595是吗?
有此疑问想确认一下,望指点!
有C看就明白快了,明白之后做汇编.

出0入0汤圆

发表于 2011-3-27 17:47:13 | 显示全部楼层
好资料。研究一下!

出0入0汤圆

发表于 2011-3-27 19:44:51 | 显示全部楼层
请教楼主,您发的程序是不是和
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=985613&bbs_page_no=1&search_mode=1&search_text=LED&bbs_id=9999  帖子中的26楼将的方法不同啊? 原帖中控制思路是使用PWM控制OE的方式。你这是将OE端直接接地。不一样吧?能否讲讲驱动的思路。

出0入0汤圆

发表于 2011-3-27 22:57:30 | 显示全部楼层
好思路 学习了

出0入0汤圆

 楼主| 发表于 2011-3-27 23:12:21 | 显示全部楼层
回复【17楼】zldiy
-----------------------------------------------------------------------
我这个程序的思路很简单:其实就是将74HC595的每个I/O的的状态与时基基数cPwmCount不断的进行比较,用串行方式输出每个74HC595的8个I/O的状态;举个例子:一个74HC595有8个输出I/O口,我用8个缓冲器为“LedBuffer[8]”,时基基数为“cPwmCount”,其中时基基数cPwmCount一直做自减动作,每中断一次cPwmCount自减一次,之后就依次分别与8个缓冲器LedBuffer[0],LedBuffer[1],LedBuffer[2],LedBuffer[3],LedBuffer[4],LedBuffer[5],LedBuffer[6],LedBuffer[7]做比较,如果比cPwmCount小的话就为“0”,比cPwmCount大的话就为“1”,这样8个缓冲器就有8个状态,这8个状态利用移位算法转化为一个8位宽的变量输出到74HC595的输出端;多个74HC595联级原理也是这样。

出0入0汤圆

发表于 2011-3-28 00:47:31 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-3-28 09:22:27 | 显示全部楼层
mark

出0入0汤圆

 楼主| 发表于 2011-3-29 08:56:59 | 显示全部楼层
自己顶一下~~~

出0入0汤圆

发表于 2011-4-9 20:05:02 | 显示全部楼层
mark!

出0入0汤圆

发表于 2011-4-9 22:15:19 | 显示全部楼层
mark!

出0入0汤圆

发表于 2011-7-6 08:10:22 | 显示全部楼层
学习了

出0入0汤圆

发表于 2011-11-22 23:12:11 | 显示全部楼层
不错!学习了

出0入0汤圆

发表于 2011-11-23 08:26:54 | 显示全部楼层
mark

出20入12汤圆

发表于 2011-11-23 10:23:08 | 显示全部楼层
看看了

出0入0汤圆

发表于 2011-11-23 23:00:00 | 显示全部楼层
mark

出0入0汤圆

 楼主| 发表于 2011-11-24 09:10:41 | 显示全部楼层
回复【32楼】liyuguang
我还是那句话!我敢肯定这些代码不是你这个层次的人能写得出来的,既然是人家的代码,何必在这里装13! 阿b哥之后阿c哥!恶心王
-----------------------------------------------------------------------

我现在只觉得你很可怜!!

出0入0汤圆

发表于 2011-11-24 16:31:26 | 显示全部楼层
完全汇编写的,楼主的那个算法不错哦,看来又得复习了!

出0入0汤圆

发表于 2011-12-2 16:38:49 | 显示全部楼层
哈哈,厉害

出0入0汤圆

发表于 2012-8-12 11:03:11 | 显示全部楼层
楼主请问一下,这样的PWM能做到多高频率?因为现在手上有一个产品要用到36路PWM的,而且每路PWM至少要30KHZ以上,且36要独立!正在犯愁中。。。

出0入0汤圆

发表于 2013-4-2 00:07:04 | 显示全部楼层
试过8个。加上效果、64路AVR32的。CPU已经很吃力了。

出0入0汤圆

发表于 2013-4-2 09:25:08 | 显示全部楼层
mark

出0入0汤圆

发表于 2013-10-5 02:39:25 | 显示全部楼层
强烈关注陈老师

出0入0汤圆

发表于 2013-10-5 10:41:30 来自手机 | 显示全部楼层
很好很强大   强烈支持
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 02:28

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表