搜索
bottom↓
回复: 58

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

[复制链接]

出0入0汤圆

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

74HC595的结构如下:

(原文件名: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程序结构---------简单啊! 典型的控制器加数据通路设计

控制器就是一个状态机:

(原文件名:Serial_74hc595 FSM.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[7 : 0] data;
       
        reg rck;
        reg transfer_over, shift;
        reg[7 : 0] data_byte;
        reg[2 : 0] bit_count;
        reg[3 : 0] 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[7];
        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[2 : 0] 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[7 : 0] 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[2 : 0] 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



全齐了!!

下面就是仿真了

先功能仿真:

结果如下:


(原文件名:functional sim.JPG)

欧也!!!莫有问题!





好接着时序仿真:

再看:

(原文件名:timing sim.JPG)

欧也!
也没问题。

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


(原文件名:si-sck ts th.JPG)

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


(原文件名:rck- sck ts th.JPG)  

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


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


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

………

先测试了下 发送 data_byte[7 : 0] = 8’b0101_0101

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

算了,再发个别的数据   这次是 data_byte[7 : 0] = 8’b1111_0000

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

难道真实少发了一位??

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

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

我有证据:



(原文件名:pin.JPG)

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

在往下看,又发现:


(原文件名:pin15.JPG)

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


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

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

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

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

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

我有证据:


(原文件名: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)

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

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

出0入0汤圆

发表于 2009-11-7 17:50:48 | 显示全部楼层
不错,很详细

出0入0汤圆

发表于 2009-11-7 18:28:50 | 显示全部楼层
不错,很认真

出0入0汤圆

发表于 2009-11-7 19:24:54 | 显示全部楼层
嗯,楼主!

出0入0汤圆

发表于 2009-11-7 19:32:38 | 显示全部楼层
额,确实很认真。

出0入0汤圆

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

谢谢楼主啊。

出0入0汤圆

发表于 2009-11-7 21:21:28 | 显示全部楼层
谢谢楼主,有时候出错的经验比成功的经验更有价值。

出200入0汤圆

发表于 2009-11-7 21:47:53 | 显示全部楼层
赞态度

出0入0汤圆

发表于 2009-11-7 21:59:22 | 显示全部楼层
错误不怕、、有错误就要分析总结,精神可嘉

出0入0汤圆

发表于 2009-11-27 16:36:10 | 显示全部楼层
学习,如果程序再加点注释就完美了。

出0入0汤圆

发表于 2009-12-9 09:27:30 | 显示全部楼层
开始学习VHDL,楼主的经验教训值得学习!

出0入0汤圆

发表于 2009-12-9 12:38:51 | 显示全部楼层
不错,值得学习

出0入0汤圆

发表于 2009-12-11 14:37:44 | 显示全部楼层
学习

出0入4汤圆

发表于 2010-1-22 15:43:34 | 显示全部楼层
不错,顶一个。

出0入0汤圆

发表于 2010-1-22 17:19:14 | 显示全部楼层
楼主说的是···以后要注意

出0入0汤圆

发表于 2010-1-22 17:23:16 | 显示全部楼层
mark~学习~

出0入0汤圆

发表于 2010-1-22 20:32:34 | 显示全部楼层
呵呵,引以为戒

出0入0汤圆

发表于 2010-1-22 22:15:44 | 显示全部楼层

出0入0汤圆

发表于 2010-1-22 23:00:22 | 显示全部楼层
mark.  。。

出0入0汤圆

发表于 2010-2-6 01:04:48 | 显示全部楼层
不错,厉害啊,顶一下!

出0入0汤圆

发表于 2010-2-6 01:34:30 | 显示全部楼层
不错!

出0入0汤圆

发表于 2010-2-6 02:17:55 | 显示全部楼层
不错的贴子

出0入0汤圆

发表于 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的。呵呵

出0入0汤圆

发表于 2010-4-24 16:28:39 | 显示全部楼层
人过留名

出0入0汤圆

发表于 2010-4-29 23:38:47 | 显示全部楼层
赞一个,并且mark以下。

出0入0汤圆

发表于 2010-4-30 06:57:43 | 显示全部楼层
记号~~

出0入0汤圆

发表于 2010-9-8 16:15:50 | 显示全部楼层
mark,这玩意儿从开头就一点马虎不得啊,楼主幸亏有旁人指点,如果一个人摸索,估计得浪费更多时间。

出0入0汤圆

发表于 2010-9-8 17:04:46 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-10 11:14:32 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-12 23:01:57 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-13 13:21:07 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-14 21:25:50 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-14 22:41:39 | 显示全部楼层
学习了。谢谢!!!

出0入0汤圆

发表于 2010-9-14 22:48:45 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-29 12:46:35 | 显示全部楼层
very good!

出0入0汤圆

发表于 2010-10-3 18:34:51 | 显示全部楼层
cool

出0入0汤圆

发表于 2010-10-4 13:14:57 | 显示全部楼层
好东西

出0入0汤圆

发表于 2010-10-4 21:11:56 | 显示全部楼层
mark

出0入0汤圆

发表于 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 : IN  STD_LOGIC_VECTOR(0 TO 7);            
        HOUTPUT: OUT STD_LOGIC_VECTOR(0 TO 3);
        VINPUT : IN  STD_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 one  OF 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位移位寄存器;怎么移位有时候出错,怎么整啊!  我是初学者,前辈指点下;

出0入0汤圆

发表于 2010-10-15 19:53:50 | 显示全部楼层
不错,学习了

出0入0汤圆

发表于 2010-10-15 22:27:16 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-10-15 23:19:44 | 显示全部楼层
我觉得一次成功,并不是好事儿。。。。。。当然,经验丰富的除外。

出0入0汤圆

发表于 2010-10-16 09:11:37 | 显示全部楼层
学习!@

出0入0汤圆

 楼主| 发表于 2010-10-16 09:30:24 | 显示全部楼层
回复【39楼】gzmcon1  
-----------------------------------------------------------------------

不会vhdl啊 :)—

出0入0汤圆

发表于 2011-4-19 11:05:33 | 显示全部楼层
请问楼主在吗?!

出0入0汤圆

发表于 2011-4-19 12:20:54 | 显示全部楼层
呵呵,知识经验都是在一个一个错误中积累起来的。

出0入0汤圆

发表于 2011-4-20 16:25:17 | 显示全部楼层
mark!!!!!!!!!!!

出0入0汤圆

发表于 2011-5-23 10:00:22 | 显示全部楼层
mark!!!

出0入0汤圆

发表于 2011-5-23 13:42:45 | 显示全部楼层
Mark

出0入0汤圆

发表于 2011-5-26 15:12:10 | 显示全部楼层
学习

出0入0汤圆

发表于 2011-5-26 16:01:42 | 显示全部楼层
一个595的verilog写的有些麻烦了,而且给我感觉并不是一个很规范的并行结构的思想,呵呵,仅仅是我自己的见解,LZ莫怪

出0入0汤圆

发表于 2011-6-1 22:37:09 | 显示全部楼层
引用图片【楼主位】wanmyqawdr
-----------------------------------------------------------------------

(原文件名:pin15.JPG)

出0入0汤圆

 楼主| 发表于 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

出0入0汤圆

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

出0入0汤圆

发表于 2011-6-2 08:27:28 | 显示全部楼层
多谢楼主提供宝贵的经验。

出0入0汤圆

发表于 2012-2-3 23:39:09 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-2-9 21:17:54 | 显示全部楼层
mark,。。。。

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-7-24 11:26

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

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