wanmyqawdr 发表于 2009-11-7 17:32:03

CycloneII 驱动移位寄存器74HC595 调试手记 ----------祭奠为我所犯错误而牺牲的时

CycloneII 驱动移位寄存器74HC595 调试手记
----------祭奠为我所犯错误而牺牲的时间
一直在忙FPGA数据采集的设计。由于FPGA引脚十分紧张,所以想到用移位寄存器(串入并出)级联来节省引脚,之前从来没有用过74HC595,但是看了下片子感觉好简单啊(我的心态已近决定我要倒霉),还好我有个习惯就是不喜欢到网上找源码,因为够自信,我喜欢直接看datasheet,然后自己写代码。

74HC595的结构如下:
http://cache.amobbs.com/bbs_upload782111/files_21/ourdev_500865.JPG
(原文件名:74HC595 strcture.JPG)

我一看,那么简单,一共两级,si是串行数据输入,SCK是移位时钟(上升沿寄存),SCLR是移位寄存器清零,RCK是输出寄存时钟(上升沿),G输出时能(低电平使能)。

靠,我想这个有什么啊!简单!在洞洞板上 一来二去把线接好了。
接线如下:
      VCC                --------------------                5V   (这里又埋下错误的伏笔)
        SCLR                --------------------                VCC
         G                  -------------------                  GND
      SI,SCK,RCK      -------------------               CycloneII
        Qa ~ QH             ------------------               8个LED(共阴)看效果(这里又搞错了)下边在讲。
我是一次直接更新8位所以就不同清零了,所以直接把SCLR接VCC。
G接GND,输出一直使能。
然后我想了下Verilog程序结构---------简单啊! 典型的控制器加数据通路设计

控制器就是一个状态机:
http://cache.amobbs.com/bbs_upload782111/files_21/ourdev_500868.JPG
(原文件名:Serial_74hc595 FSM.JPG)

数据通路:
http://cache.amobbs.com/bbs_upload782111/files_21/ourdev_500866.JPG
(原文件名:data path.JPG)

设计思路如下:
因为驱动74hc595的模块是大工程的一部分,驱动74hc595的模块本接受顶层模块的控制,工作流程如下,调用模块先把待发送的数据打到总线上(data),然后置Load= 1,此时8位数据被serial_tansfer_74hc595寄存到data_byte(移位寄存器) 内,然后调用模块置start = 1,serial_transfer_74hc595开始发送,发送的过程如下是:通过控制移位寄存器data_byte发送数据,同时bit_count 计数,当8位数据全部发完,serial_transfer_74hc595置transfer_over = 1, 此时调用模块发现transfer_over = 1 ,传送完毕,完美啊!!!(真自恋)

如意算盘完成后开始堆码……….


三下五除二把发送模块写好了:


//Module        :       
//Desc                :        Transfer datas to shift 74hc595;

module serial_transfer_74hc595(sck, rck, si, sclr_n,
                                data, load, start, transfer_over,
                                clk, reset_n);
        output sck, rck, si, sclr_n, transfer_over;
        input load, start, clk, reset_n;
        input data;
       
        reg rck;
        reg transfer_over, shift;
        reg data_byte;
        reg bit_count;
        reg state, next_state;
       
       
        parameter s_idle = 0;
        parameter s_wait_for_start = 1;
        parameter s_sending = 2;
        parameter s_over = 3;
       
        assign si = data_byte;
        assign sclr_n = 1;
        assign sck = clk;
       
        always@(posedge clk or negedge reset_n) begin
                if(!reset_n)
                        state <= s_idle;
                else
                        state <= next_state;
        end
       
        always@(state or load or start or bit_count) begin
                next_state = 0;
                shift = 0;
                transfer_over = 0;
                next_state = state;
                case(state)
                        s_idle :
                                if(load)
                                        next_state = s_wait_for_start;
                        s_wait_for_start :
                                if(start) begin
                                        next_state = s_sending;
                                        shift = 1;
                                end
                        s_sending :
                                if(bit_count == 3'b111) begin
                                        next_state = s_over;
                                end
                                else
                                        shift = 1;
                        s_over :
                                begin
                                        next_state = s_idle;
                                        transfer_over = 1;
                                end
                        default :
                                next_state = s_idle;
                endcase
        end
       
        always@(posedge clk or negedge reset_n) begin
                if(!reset_n) begin
                        bit_count <= 0;
                        data_byte <= 0;
                end
                else begin
                        if(load) begin
                                bit_count <= 0;
                                data_byte <= data;
                        end
                       
                        if(shift) begin
                                bit_count <= bit_count + 1;
                                data_byte <= data_byte << 1;
                        end
                end
        end
       
        always@(state or clk) begin
                if(state == s_over && ~clk)
                        rck = 1;
                else
                        rck = 0;
        end
endmodule


我的Cyclone II 核心板时钟 50Mhz 惟恐频率太高,所以我有写了分频模块:

//Module        :       
//Desc                :        Serial clock generator


module clk_gen(clk_out, clk_in, reset_n);
        output clk_out;
        input clk_in, reset_n;
       
        reg clk_out, clk_out_0, clk_out_reg;
        reg count;
       
        always@(posedge clk_in or negedge reset_n) begin
                if(!reset_n) begin
                        count <= 0;
                        clk_out_0 <= 0;
                        clk_out <= 0;
                        clk_out_reg <= 0;
                end
                else begin
                        count <= count + 1;
                        if(count == 3'b001) begin
                                clk_out_reg <= ~clk_out_reg;
                                count <= 0;
                        end
                        clk_out_0 <= clk_out_reg;
                        clk_out <= clk_out_0;
                end                               
        end
endmodule


最后写个顶层模块作为调用者:

//Module        :
//Desc                :        Top Moudle

module Test_For_74hc595(sck, rck, si, sclr_n, clk, reset_n);
        output sck, rck, si, sclr_n;
        input clk, reset_n;
       
        wire sck;
        wire wire_sck;
        wire wire_si;
        wire wire_clk = clk;
        wire wire_reset_n = reset_n;
        wire wire_rck;
        wire wire_sclr_n;
        wire wire_data = 8'b1111_0101;
        reg wire_load;
        reg wire_start;
        wire wire_transfer_over;
       
        parameter idle = 0;
        parameter load = 1;
        parameter start = 2;
        parameter sending = 3;
        parameter over = 4;
       
        reg state, next_state;
       
        assign rck = wire_rck;
        assign si = wire_si;
        assign sclr_n = wire_sclr_n;
       
        clk_gen u1(wire_sck, wire_clk, wire_reset_n);
        serial_transfer_74hc595 u2(sck, wire_rck, wire_si, wire_sclr_n,
                                 wire_data, wire_load, wire_start, wire_transfer_over,
                                 wire_sck, wire_reset_n);
                                                                                       
        always@(posedge wire_sck or negedge reset_n) begin
                if(!reset_n)
                        state <= idle;
                else
                        state <= next_state;
        end
       
        always@(state or wire_transfer_over) begin
                wire_load = 0;
                wire_start = 0;
                next_state = state;
                case(state)
                        idle :
                                next_state = load;
                        load :
                                begin
                                        wire_load = 1;
                                        next_state = start;
                                end
                        start :
                                begin
                                        wire_start = 1;
                                        next_state = sending;
                                end
                        sending :
                                if(wire_transfer_over)
                                        next_state = over;
                        over :
                                next_state = over;
                        default :
                                next_state = load;
                endcase
        end
endmodule



全齐了!!

下面就是仿真了

先功能仿真:

结果如下:

http://cache.amobbs.com/bbs_upload782111/files_21/ourdev_500867.JPG
(原文件名:functional sim.JPG)

欧也!!!莫有问题!





好接着时序仿真:

再看:
http://cache.amobbs.com/bbs_upload782111/files_21/ourdev_500874.JPG
(原文件名:timing sim.JPG)

欧也!
也没问题。

我主要看了SI---- SCK的建立和保持时间够不够,还有RCK ---- SCK的建立时间按够否 74HC595手册这样描述:

http://cache.amobbs.com/bbs_upload782111/files_21/ourdev_500871.JPG
(原文件名:si-sck ts th.JPG)

ts >= 10ns 够了
th >= 0ns也够了(实际有2ns左右,我的si,sck线是一样长的)

http://cache.amobbs.com/bbs_upload782111/files_21/ourdev_500872.JPG
(原文件名:rck- sck ts th.JPG)

ts >= 10ns
th >= 0ns(也全部够)


到此,我已经认为没有问题了


下步干嘛?当然是下载到板上测试啦:

………

先测试了下 发送 data_byte = 8’b0101_0101

看了下LED,发现貌似正确,再看下,诶,怎么LED 现实的结果是 8’b1010_1010
不对!!!!这怎么回事,貌似少发了一位。

算了,再发个别的数据   这次是 data_byte = 8’b1111_0000

再看结果,又不对,怎么是 8’b00011110

难道真实少发了一位??

我靠此刻我也没别的想法了,肯定程序不对吧~~~~~~,改!!!改了N各版本无果…..错误依旧。

此刻我已经无奈了,还有有个兄弟也在玩FPGA,我就去请教他,他看了电路说了句,哥们你找个电路连得不对吧~~~~~~我说怎么了??74hc595 的15脚是QA(最低位),你怎么把他当成QH了(最高位),晕,我一看还真是。这也就解释了为什么看起来少发一位的问题了。
想想自己明明记得手册上写的是 15脚是 QH啊,怎么又变成QA了???

我有证据:


http://cache.amobbs.com/bbs_upload782111/files_21/ourdev_500869.JPG
(原文件名:pin.JPG)

这明明就是15对QH啊!!!!!!!
怎么回事呢???

在往下看,又发现:

http://cache.amobbs.com/bbs_upload782111/files_21/ourdev_500870.JPG
(原文件名:pin15.JPG)

怪谁呢???唉~~~~还是怪自己吧,此刻我已经浪费了大半天。我完全没有想到会是电路接错,因为这确实太简单了~~~~~~~


好了结果了接线错误,我再测对了,这次我想看看发全一什么效果~~~~

诶,怎么有不对,只有一个灯亮???此刻我想到,可能是74HC595的驱动力不够。用万用表量了下输出脚,怎么是0V,驱动力不够也不该一点电压没有啊!!!!!

难道是我的FPGA有问题???算了换块板子试试。。

换了块板子,可以了,全亮了~~~~~结束了,我以为结束了,就把板子放在那里点着。我下意识的按了下FPGA复位键,诶~~~~~怎么又只有一个量了?????难道是代码的复位逻辑有错???再看代码~~~~是在找不出错误???到底怎么了????

此刻我忽然想到了我的74HC595接的是5V,FPGA是3.3V IO,但是我想即使是3.3V高电平,74HC595也该吃啊!!!

我有证据:

http://cache.amobbs.com/bbs_upload782111/files_21/ourdev_500873.JPG
(原文件名:VIH.JPG)

74hc595 接4.5V ,只要 3.15V就可以认为是高电平了,怎么不能吃3.3V???唉,实际上我接的是5V,肯定VIH也高了,侥幸啊!!!!全是侥幸心理。



到此,我把74hc595接3.3V吧,所有的问题都消失了~~~~结束了,终于结束了。一个小小的芯片让我明白了很多道理。

1 .   无论干什么都要认真,理性,耐心,思考
2.    永远不要认为事情简单,麻痹大意和侥幸心理会让我吃大亏,还好这次只是时间损失,要是……..唉

最后放上工程代码:Quartus II 9.0ourdev_500877.zip(文件大小:1.13M) (原文件名:TestFor74HC595.zip)

附上原文PDF : 点击此处下载 ourdev_500881.pdf(文件大小:1.23M) (原文件名:原文.pdf)

74HC595 datasheet : 点击此处下载 ourdev_500882.pdf(文件大小:627K) (原文件名:m74hc595.pdf)

durgy 发表于 2009-11-7 17:50:48

不错,很详细

pcs3 发表于 2009-11-7 18:28:50

不错,很认真

yvhksovo 发表于 2009-11-7 19:24:54

嗯,楼主!

wangli1013 发表于 2009-11-7 19:32:38

额,确实很认真。

yvhksovo 发表于 2009-11-7 20:10:45

其他的先不说,看楼主的仿真图,我至少学到了两样东西:
1,原来quartus ii自带的仿真也能仿真到1ms以上去的,原来以为最多能仿真到1us,因为每次想把时间设置的大一点的时候,都提示我,请输入一个合法的数值。
2,原来可以直接插入machine查看的,以前我想查看状态机的时候,都是把状态寄存器设置成输出端口。。。汗!

谢谢楼主啊。

flashman911 发表于 2009-11-7 21:21:28

谢谢楼主,有时候出错的经验比成功的经验更有价值。

wahaha 发表于 2009-11-7 21:47:53

赞态度

fjhcpu 发表于 2009-11-7 21:59:22

错误不怕、、有错误就要分析总结,精神可嘉

WXing 发表于 2009-11-27 16:36:10

学习,如果程序再加点注释就完美了。

AVRXX2009 发表于 2009-12-9 09:27:30

开始学习VHDL,楼主的经验教训值得学习!

footprint 发表于 2009-12-9 12:38:51

不错,值得学习

idly 发表于 2009-12-11 14:37:44

学习

bbandpp 发表于 2010-1-22 15:43:34

不错,顶一个。

cain.lee 发表于 2010-1-22 17:19:14

楼主说的是···以后要注意

cinderellah 发表于 2010-1-22 17:23:16

mark~学习~

quzegang 发表于 2010-1-22 20:32:34

呵呵,引以为戒

astudent 发表于 2010-1-22 22:15:44

beer 发表于 2010-1-22 23:00:22

mark.。。

avic 发表于 2010-2-6 01:04:48

不错,厉害啊,顶一下!

5696317 发表于 2010-2-6 01:34:30

不错!

ju748 发表于 2010-2-6 02:17:55

不错的贴子

jxc827 发表于 2010-2-10 14:22:45

74hc595 接4.5V ,只要 3.15V就可以认为是高电平了,怎么不能吃3.3V???

595输入为CMOS电平,接5V电源时,输入高电平最低门限约0.7*5V=3.5V>3.3V;即使你的FPGA为LVCMOS电平输出也是无法驱动HC595的。呵呵

xiaolou7 发表于 2010-4-24 16:28:39

人过留名

sagetom 发表于 2010-4-29 23:38:47

赞一个,并且mark以下。

zbjzxc 发表于 2010-4-30 06:57:43

记号~~

polygon 发表于 2010-9-8 16:15:50

mark,这玩意儿从开头就一点马虎不得啊,楼主幸亏有旁人指点,如果一个人摸索,估计得浪费更多时间。

vipcff 发表于 2010-9-8 17:04:46

mark

tangxiaolon 发表于 2010-9-10 11:14:32

mark

caozhu 发表于 2010-9-12 23:01:57

mark

ideality0214 发表于 2010-9-13 13:21:07

mark

tigerchen 发表于 2010-9-14 21:25:50

mark

wangxiaoacc 发表于 2010-9-14 22:41:39

学习了。谢谢!!!

eastbest 发表于 2010-9-14 22:48:45

mark

tiger100_diy 发表于 2010-9-29 12:46:35

very good!

yuphone 发表于 2010-10-3 18:34:51

cool

maqingbiao 发表于 2010-10-4 13:14:57

好东西

jielove2003 发表于 2010-10-4 21:11:56

mark

gzmcon1 发表于 2010-10-9 00:17:42

回复【楼主位】wanmyqawdr
-----------------------------------------------------------------------

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY HV0804 IS
PORT ( DATAIN,INCLK,INUPDATE,CE,RESET:IN STD_LOGIC;      
      HINPUT : INSTD_LOGIC_VECTOR(0 TO 7);            
      HOUTPUT: OUT STD_LOGIC_VECTOR(0 TO 3);
      VINPUT : INSTD_LOGIC_VECTOR(0 TO 7);
      VOUTPUT: OUT STD_LOGIC_VECTOR(0 TO 3);
       CON1,CON2,CON3,CON4,DATAOUT :OUT STD_LOGIC;
       EN1OUT11,EN1OUT12,EN1OUT13,EN1OUT14:OUT STD_LOGIC;
       EN1OUT21,EN1OUT22,EN1OUT23,EN1OUT24:OUT STD_LOGIC;
       EN1OUT31,EN1OUT32,EN1OUT33,EN1OUT34:OUT STD_LOGIC;
       EN1OUT41,EN1OUT42,EN1OUT43,EN1OUT44:OUT STD_LOGIC         
      );
END ENTITY HV0804;

ARCHITECTURE oneOF HV0804 IS
SIGNAL CLK,UPDATE : STD_LOGIC;
SIGNAL HO1,HO2,HO3,HO4: STD_LOGIC;
SIGNAL VO1,VO2,VO3,VO4: STD_LOGIC;
SIGNAL ShRig : STD_LOGIC_VECTOR(15 DOWNTO 0);
SIGNAL UpRig : STD_LOGIC_VECTOR(15 DOWNTO 0);

BEGIN
-- CLK<=NOT INCLK ; -- WHEN CE='0' ELSE '0';
-- CLK<=NOT(INCLK AND (NOT CE));
--   UPDATE<=NOT INUPDATE;-- WHEN CE='0' ELSE '0';
   -- UPDATE<=NOT(INUPDATE AND (NOT CE));
-- CON1<= UpRig(0);
-- CON2<= UpRig(4);
--CON3<= UpRig(8);
--CON4<= UpRig(12);
   DATAOUT<=ShRig(15);

PROCESS(INCLK,DATAIN,RESET)
BEGIN
IF (RESET='0') THEN
        ShRig<="0000000000000000";
ELSIF INCLK'EVENT AND (INCLK='0') THEN
        IF CE='0' THEN               
                   ShRig(15 DOWNTO 1) <= ShRig(14 DOWNTO 0);
                ShRig(0) <= DATAIN ;-- AFTER 100ns;
        else
                null;
        end if;
end if;
end process;

process(RESET,CE,INUPDATE)
begin
if (RESET='0') then
       UpRig<="0000000000000000";
elsif INUPDATE'event and (INUPDATE='0') then
        if CE='0' then
                   UpRig <= ShRig;
        else
                null;
        end if;
end if;
end process;


我做了一个16位移位寄存器;怎么移位有时候出错,怎么整啊!我是初学者,前辈指点下;

xtaens 发表于 2010-10-15 19:53:50

不错,学习了

wanwzy 发表于 2010-10-15 22:27:16

mark

laoxizi 发表于 2010-10-15 23:19:44

我觉得一次成功,并不是好事儿。。。。。。当然,经验丰富的除外。

kunpeng032 发表于 2010-10-16 09:11:37

学习!@

wanmyqawdr 发表于 2010-10-16 09:30:24

回复【39楼】gzmcon1
-----------------------------------------------------------------------

不会vhdl啊 :)—

muyanlong456 发表于 2011-4-19 11:05:33

请问楼主在吗?!

gaoyukun 发表于 2011-4-19 12:20:54

呵呵,知识经验都是在一个一个错误中积累起来的。

keilc 发表于 2011-4-20 16:25:17

mark!!!!!!!!!!!

wmf000000 发表于 2011-5-23 10:00:22

mark!!!

shiguiyuan 发表于 2011-5-23 13:42:45

Mark

shangdawei 发表于 2011-5-26 15:12:10

学习

Tokeyman 发表于 2011-5-26 16:01:42

一个595的verilog写的有些麻烦了,而且给我感觉并不是一个很规范的并行结构的思想,呵呵,仅仅是我自己的见解,LZ莫怪

yhzhx01 发表于 2011-6-1 22:37:09

引用图片【楼主位】wanmyqawdr
-----------------------------------------------------------------------
http://cache.amobbs.com/bbs_upload782111/files_21/ourdev_500870.JPG
(原文件名:pin15.JPG)

wanmyqawdr 发表于 2011-6-1 22:49:41

回复【51楼】Tokeyman
一个595的verilog写的有些麻烦了,而且给我感觉并不是一个很规范的并行结构的思想,呵呵,仅仅是我自己的见解,lz莫怪
-----------------------------------------------------------------------

这个写的很久了,我现在感觉我写的那个也不咋样,我现在也不做fpga了,但是还比较感兴趣,没事的时候还玩一玩(弄了块de2的板子),这个是我毕业时候做的一个东西,也用到了595

http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4166141&bbs_page_no=1&search_mode=3&search_text=wanmyqawdr&bbs_id=9999

ababvic 发表于 2011-6-2 08:11:54

mark

avrgogo 发表于 2011-6-2 08:27:28

多谢楼主提供宝贵的经验。

qinshi1208 发表于 2012-2-3 23:39:09

mark

ddny2008 发表于 2012-2-9 21:17:54

mark,。。。。

mailtoyj518168 发表于 2012-2-13 14:32:59

mark 学习
页: [1]
查看完整版本: CycloneII 驱动移位寄存器74HC595 调试手记 ----------祭奠为我所犯错误而牺牲的时