这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » (1602初探)hanshuyujifen的进程贴

共40条 1/4 1 2 3 4 跳转至

(1602初探)hanshuyujifen的进程贴

高工
2012-10-20 22:44:46     打赏
我来玩了  我来晚了

九月底就收到了板子,一直空着。
今天刚买到了元件,开始焊接              2012.10.20
外围板焊接完成,核心板主片两个引脚歪了。连焊。正在想办法处理 2012.10.21

期间焊接完毕,开始硬件调试。焊接信息和调试方法见2楼                 2012.10.22
再次焊接失败。片子焊反                    2012.11.22

2012.11.26  继续学习VerilogHDL  ,ModelSim仿真实现三分频器

2012.11.27 LED闪烁实验

2012.12.04  板子故障排除

2012-12-05  LED实验及作业

2012-12-06  数码管动态扫描及静态扫描

2012-12-06  数码管作业,模六十计数器
2012-12-08  按键输入实验,按键控制LED
2012-12-08  按键控制数码管显示0到9

2012-12-08 简单的按键消抖
2012-12-08  循环语句使用练习
2012-12-09 蜂鸣器输出救护车声音(两种频率声音)

2012-12-09 使用状态机实现周期性改变频率(一段式)
2012-12-10 使用状态机实现周期性改变频率(三段式)

2012-12-12 AD转换实验  未滤波,数据跳变
2012-12-16 DAC实验  
2012-12-21 PLL实验
2012-12-23 开始小实验    
2012-12-24 移位操作(参数传递)
2012-12-24 同步复位触发器
2012-12-24 带异步复位,时钟使能,上升沿触发的触发器      
2012-12-25

2012-12-28  VGA显示黑白条  同步模块
2013-01-07 初探1602




牛贴参考
http://forum.eepw.com.cn/thread/222760/1


-------------------------------------------------------------------------------



关键词: 初探     hanshuyujifen     进程    

高工
2012-10-20 22:46:50     打赏
2楼
焊接信息:


自购元件,自己焊接。问题多多
焊接时的第一个问题
主片引脚歪了,连焊,如图。焊接主片时候没注意,烙铁是垂直片子的边拖的,要是往外拖应该不会歪的



解决方法,用一个很薄的刀片插在两个引脚之间,然后烙铁点焊盘。刀片轻轻地撬,往下压降锡切开。等冷却后拿开刀片就OK了:



注意千万不要用力太刀了,不然焊盘废了就完蛋了。

第二个问题:D1灯不好好亮
焊接完核心板,上电测试。
先测电压,3.3V  1.2V都正常。
D3正常,D1不亮。
在群里边问了下,这是不正常的。D1应该在配置完成之后才熄灭的。
于是,我到处找问题。刚开始以为LED有问题。换了个,还是老样子。把周围相关的几个电阻、三极管都检查了一遍,没问题。

偶然间发现,按住D1那个角(如图)D1就会亮。怀疑板子有什么问题。又把周围的零件用烙铁点了一遍。还是不行。

没招,看电路吧。发现D1是否亮受CONF_ DONE信号控制。于是,三用表笔按住这个引脚。D1正常了。

最后 烙铁点了下这个引脚  D1就正常了

手压住一角之后的效果


硬件还在调试  此帖还会更新

高工
2012-10-20 22:48:34     打赏
3楼
此处为焊接完成后板子的效果:
外围版正面


外围版背面




核心板正面


核心板背面


焊接的比较匆忙。尤其是主片,还有问题没搞定。烙铁还不能封存

高工
2012-10-20 22:48:59     打赏
4楼
此处为测试效果,下载51FPGA版主提供的测试程序,下载后的效果。
第一个:共阳数码管
虽然照片是出来了,可还是有问题。数字会闪烁,或者只显示数字0,别的显示不出来。问题还没找到。

高工
2012-10-20 22:49:27     打赏
5楼
2012.11.05
板子焊坏了,拿出去拆掉主片  重新焊接
由于那靠近SDRAM排引脚全部歪了  最后还是没焊好

再测试  发现电源还短路了

不敢上电 

明天继续检查,看哪里短路了。造出了就好了
把那排引脚除了电源和底线全部切断再玩,不用SDram了
2012.11.22
今天收到了51FPGA寄来的新板子。兴奋地准备了半天,左对右对的终于把引脚对其了。下烙铁,开焊。焊的那个工整啊!
焊接一半的时候,歇会吧。于是乎,悲剧地发现,片子焊反了。焊反了。焊反了。焊反了。焊反了。焊反了。焊反了。焊反了。
彻底悲剧了。又花200块钱买了个热风枪,准备拆焊。等。。
算算时间,也不能等了,今晚开始工作。
今天的总结:
1、今天第二次焊接失败,失败的弱智。片子焊反了。
2、到十二月底只有一个月时间了,得抓紧时间要不老王不发工资了。
3、于是,晚上先是照着入门教程写了会代码,学习了最简单的QII操作。然后看了个FPGA的资料。
4、从今天开始,先学代码写东西,等着拆焊的热风来。板子好后,视频和图片一并发布。

高工
2012-10-20 22:50:06     打赏
6楼

次楼记录VerilogHDL语言学习中的问题。
2012.11.23
昨天由于第一次写Verilog的东西,直接照着版主的教程敲代码。看着代码挺熟悉的,据说像C语言

几个小问题没理解。其中包括怎样将小模块添加到顶层模块中。
今天看书有点理解了。
各个小模块就相当于C语言中的函数。或者C++ 语言中的类,需要在顶层模块中实例化才算是加到程序里边了。

模块的实例化有两种方式:位置映射法,信号名称映射法。
1、位置映射法
    相当于一个类,定义了一个实例。比如我有一个模块名字叫compare_core
    compare_core的接口定义是这样的:
    module    compare_core(result,a,b);
    input        [7:0] a,b;
    output    result;
我要实例这个模块,需要这样写:
    compare_core    inst_compare_core0(result0,a0,b0);  //定义第一个实例,相当于在电路中放入了一个名字为inst_compare_core0的compare_core模块
    compare_core    inst_compare_core1(result1,a1,b1);  ////定义第一个实例,相当于在电路中放入了一个名字为inst_compare_core0的compare_core模块
以此类推

2、信号名称映射法
    利用“.”符号,表明原模块定义时的端口名。
    上述代码改为信号映射法制化是这样的:
    compare_core inst_compare_core0(.result(result0),.a(a0),.b(b0));
    compare_core inst_compare_core1(.result(result1),.a(a1),.b(b1));
    信号映射法同时将信号名称和被引用端口名称列出来,不必遵守严格的顺序定义,也不易出错。可读性和可移植性都比位置映射法好。

2012.11.26
 
继续学习VerilogHDL  ,ModelSim仿真实现三分频器

  2012.11.27
  更新LED闪烁实验 
2012.12.04
经过几天的折腾,在EEPW各位热心的朋友的帮助下,今天板子终于正常了。
先感谢下anmko再开始写经过。

故障现象是这样的:
板子焊接好之后,使用JTAG、AS下载,都能讲数据下载到片子里边。可是下载后,片子没有任何反应。Conf_Done信号也没有变化。一直是低电平。软件显示是Successful,片子没有任何反应。下载别人提供的测试程序也不行,我自己写的程序也不行。

检查了几天一直没结果。因为我的片子曾经用热风枪拆过一次,怀疑是片子烧掉了。Anmko提示可能是片子内部静态存储单元挂了,因为FPGA的逻辑是通过向内部静态存储单元加载编程数据来实现的。分析也有这种可能,加载后数据没有保持所以FPGA没有任何输出,CONF_DONE信号没拉高。于是,问Anmko同学要了一个主片。今天刚寄出去。

今天中午继续折腾,用示波器检查了电源和时钟部分均没有问题。
继续跟进anmko得到提示,检查几个关键的信号。confdone和nConfig。由于是confdone没拉高,我先将这个信号借大盘电源上,板子依旧没有任何反应。之后我直接将nConfig信号接到3.3V电源上,然后奇迹发生了,灯亮了。然后板子就好了。

之后检查电路,发现nConfig信号通过R_C1接地,因此又检查了这个按钮。反复按压,发现有时候也会出现原有的故障现象。这个按钮是我从旧板子拆下来的,可能是按下之后没有弹起来。如果没弹起来,nConfig就接地了,FPGA就不停地开始初始化,片子一直处于加载涨停,confdown信号一直处于低电平,核心板上D1灯一直亮着。
更换了R_C1按钮,希望以上分析是对的,板子故障不要再复现了。


高工
2012-10-20 22:50:38     打赏
7楼

点灯是做所有实验的第一步,板子好了之后第一件事就是点灯。
FPGA点灯比ARM简很多。只要控制引脚输出就OK了,不用再去设置一堆的寄存器打开引脚时钟什么的。
只需要一个assign语句就可以搞定,这里就不想写了。

要让LED等周期性地闪烁,需要将外部晶振输入进行分频得到周期性的控制信号,然后控制LED进行闪烁或者流水操作。

一下是LED部分的作用,LED等以2s的周期闪烁:

module myled(sys_clk,sys_rstn,led123);
input sys_clk;
input sys_rstn;
output [10:0] led123;

reg [25:0] delay_cnt;
reg [10:0] led123;

//分频
always@(posedge sys_clk or negedge sys_rstn)
 begin
  if(!sys_rstn)
   begin
    delay_cnt <= 26'b0;
   end
  else
   begin
    if(delay_cnt == 26'd50000000)
     delay_cnt <= 26'd0;
    else
     begin
      delay_cnt <= delay_cnt+1;
     end
   end
 end
//控制LED
always @(posedge sys_clk or negedge sys_rstn)
 begin
  if(!sys_rstn)
   led123 <= 11'b01010101010;
  else
   if(delay_cnt == 26'd50000000)
    led123 <= ~led123;
   else
    led123<=led123;
 end

endmodule

LED闪烁灯作业完成之后,我又做了一个实验。输出占空比为80%的波形控制LED.由于LED在FPGA引脚输出0时被点亮,因此LED亮的时间占20%。这个实验只要简单的改变LED控制部分就行了。代码如下:
//控制LED
always @(posedge sys_clk or negedge sys_rstn)
 begin
  if(!sys_rstn)
   led123 <= 11'b00000000000;
  else
   if(delay_cnt > 26'd45000000)
    led123 <= 11'b00000000000;
   else
    led123<=11'bb11111111111;
 end
这个看似很简单的改变,在综合的时候却发现多用了8个逻辑单元。使用的逻辑单元由原来的61个编程了69个。多出来的8个单元,是RTL中将原来的相等比较器变成了小于比较器。应该还有不同的地方,不过我还没搞清楚。

跟LED闪烁类似,流水灯的关键也是对时钟分频。
只是这里对LED的操作有些变化。教程里边使用了移位操作控制LED。

//控制LED,走马灯
always @(posedge sys_clk or negedge sys_rstn)
 begin
  if(!sys_rstn)
   led123 <= 11'b01111111110;
  else
   if(delay_cnt == 26'd50000000)
    begin
     led123 <= led123<<1;
     if(led123 == 11'b00000000000)
      led123 <=11'b11111111110;
    end
   else
    led123<=led123;
 end

还有一种操作是使用拼接运算符{}操作led寄存器中的数据,代码如下:
右移:
always @(posedge sys_clk or negedge sys_rstn)
 begin
  if(!sys_rstn)
   led123 <= 11'b11111111110;
  else
   if(delay_cnt == 24'd10000000)
    begin
     led123 <={led123[9:0],led123[10]};
    end
   else
    led123<=led123;
 end

左移:
always @(posedge sys_clk or negedge sys_rstn)
 begin
  if(!sys_rstn)
   led123 <= 11'b01111111111;
  else
   if(delay_cnt == 24'd10000000)
    begin
     led123 <={led123[10:1],led123[0]};
    end
   else
    led123<=led123;
 end

图片和视频稍后上传


高工
2012-10-20 22:50:56     打赏
8楼

共阳极数码管,引脚加低电平亮。

静态扫描
分频,变化周期200ms。时间到即改变需要显示的数据disp_dat。
disp_data更改时,使用利用那个一个always来进行译码和输出。

/*数码管实验,静态扫描*/

module sumaguan(sys_clk,sys_rstn,seg,smbit);
input sys_clk;
input sys_rstn;
output [7:0] seg,smbit;


wire [7:0]  smbit;
reg [7:0] seg;
reg [24:0] delay_cnt;   //1ms延时
reg [3:0] disp_dat;   //要显示的数据

//产生时钟滴答
always@(posedge sys_clk or negedge sys_rstn)
 begin
  if(!sys_rstn)
   delay_cnt <= 25'd0;
  else
   begin
    if(delay_cnt == 25'd9999999)   //1ms
     delay_cnt <= 25'd0;
    else
     delay_cnt <= delay_cnt +1'b1;
   end
 end
 
//改变要显示的数据
always @(posedge sys_clk or negedge sys_rstn)
 begin
  if(!sys_rstn)
   disp_dat<= 4'b0000;
  else
  begin
   if(delay_cnt == 25'd9999999)
    disp_dat = disp_dat+1'b1;
  end
 end 

always @(disp_dat)
begin
 case(disp_dat)
  4'h0 :seg = 8'hc0;
  4'h1 :seg = 8'hf9;
  4'h2 :seg = 8'ha4;
  4'h3 :seg = 8'hb0;
  4'h4 :seg = 8'h99;
  4'h5 :seg = 8'h92;
  4'h6 :seg = 8'h82;
  4'h7 :seg = 8'hf8;
  4'h8 :seg = 8'h80;
  4'h9 :seg = 8'h90;
  4'hA :seg = 8'h88;
  4'hB :seg = 8'h83;
  4'hC :seg = 8'hc6;
  4'hD :seg = 8'ha1;
  4'hE :seg = 8'h86;
  4'hF :seg = 8'h8e;
 endcase
end

assign smbit = 8'b00000000;

endmodule

 数码管动态扫描显示
位码周期性地扫描,扫到哪一位哪一位需要显示的段码加到数码管输入端。
扫描周期1ms。在处理位码的时候与版主的方法不太一样,他的目的可能是让第n个数码管显示数字n。
我这段代码可以解释为当数字变成n的时候,第n为数码管显示之。
思路不同,结果一样
代码如下:
/*数码管动态扫描显示*/

module scan_led(sys_clk,sys_rstn,seg,smbit);
input sys_clk;
input sys_rstn;
output [7:0] seg,smbit;

reg [15:0]     delay_cnt;
reg [7:0]    seg,smbit;
reg [2:0]    disp_dat;
reg [4:0]    dataout_buf;

//分频,50HZ
always @(posedge sys_clk or negedge sys_rstn)
    begin
        if(!sys_rstn)
            delay_cnt <= 16'd0;
        else
            begin
                if(delay_cnt == 16'd49999)
                    delay_cnt <=16'd0;
                else
                    delay_cnt <= delay_cnt +1'b1;
            end
    end

always @(posedge sys_clk or negedge sys_rstn)
    begin
        if(!sys_rstn)
            disp_dat <= 16'd0;
        else
            begin
                if(delay_cnt == 16'd49999)
                    disp_dat <= disp_dat+1'b1;
                else
                    disp_dat <= disp_dat;
            end
    end
    
always @(disp_dat)
    begin
        case(disp_dat)
            3'b000    :    smbit = 8'b11111110;
            3'b001    :    smbit = 8'b11111101;
            3'b010    :    smbit = 8'b11111011;
            3'b011    :    smbit = 8'b11110111;
            3'b100    :    smbit = 8'b11101111;
            3'b101    :    smbit = 8'b11011111;
            3'b110    :    smbit = 8'b10111111;
            3'b111    :    smbit = 8'b01111111;
        endcase
    end
always @(disp_dat)
    begin
        case(disp_dat)
            4'h0    :seg = 8'hc0;
            4'h1    :seg = 8'hf9;
            4'h2    :seg = 8'ha4;
            4'h3    :seg = 8'hb0;
            4'h4    :seg = 8'h99;
            4'h5    :seg = 8'h92;
            4'h6    :seg = 8'h82;
            4'h7    :seg = 8'hf8;
            4'h8    :seg = 8'h80;
            4'h9    :seg = 8'h90;
            4'hA    :seg = 8'h88;
            4'hB    :seg = 8'h83;
            4'hC    :seg = 8'hc6;
            4'hD    :seg = 8'ha1;
            4'hE    :seg = 8'h86;
            4'hF    :seg = 8'h8e;
        endcase
    end
    
endmodule

图片和视频稍后上传


高工
2012-10-20 22:51:14     打赏
9楼
数码管作业,模六十计数器

对于我来说,这个实验比较费劲。用了一晚上时间搞定的。
动态扫描方式控制数码管显示,是单片机时代信手捻来的东西,可到了FPGA到了VerilogHDL之中,却不一样了。用单片机那种写法好像是行不通了。单片机的我就不说了,之说说在FPGA里边折腾这个模60计数器的思路。

首先通过对系统时钟分频建立两个系统滴答,一个周期为0.5s一个周期为1ma。周期0.5ms的滴答用于更新要显示的数据,1ms的滴答用于动态扫描数码管的各个位。

折腾时间最长的就是动态扫描部分。最初我将位码更新和段码更新放到两个always里边,先更新位码再更新断码,出来的结果和奇怪。将断码和位吗放到一个always里边,更新位码之前更新段码。然后又改正了一些细节,之后程序就能正常运行了。

整个module的代码如下:
/*数码管实验,模60计数器*/

module mod60(sys_clk,sys_rstn,seg,smbit);
input sys_clk;                        //时钟
input sys_rstn;                    //复位
output [7:0] seg,smbit;

reg [7:0]     smbit;                //位码
reg    [7:0]    seg;                    //段码
reg [15:0]    delay_cnt1;            //扫描周期,1ms
reg [24:0]    delay_cnt2;            //数据更新周期,1s
reg [5:0]    disp_dat;            //要显示的数据

reg [3:0]    databuf1;

//分频,100HZ.得到扫描频率
always @(posedge sys_clk or negedge sys_rstn)
    begin
        if(!sys_rstn)
            delay_cnt1 <= 16'd0;
        else
            begin
                if(delay_cnt1 == 16'd49999)
                    delay_cnt1 <=16'd0;
                else
                    delay_cnt1 <= delay_cnt1 +1'b1;
            end
    end

//分频,周期0.5s.得到数据更新频率
always @(posedge sys_clk or negedge sys_rstn)
    begin
        if(!sys_rstn)
            delay_cnt2 <= 25'd0;
        else
            begin
                if(delay_cnt2 == 25'd24999999)
                    delay_cnt2 <=25'd0;
                else
                    delay_cnt2 <= delay_cnt2 +1'b1;
            end
    end

//对要显示的数据进行更新
always @(posedge sys_clk or negedge sys_rstn)
    begin
        if(!sys_rstn)
            disp_dat <= 6'd0;
        else
            begin
                if(delay_cnt2 == 25'd24999999)
                    begin
                        if(disp_dat == 6'd59)
                            disp_dat <=0;
                        else
                            disp_dat <= disp_dat+1'b1;
                    end
                else
                    disp_dat <= disp_dat;
            end
    end

//扫描部分,周期1ms。先设置段码再设置位码。
always @(posedge sys_clk or negedge sys_rstn)
    begin
        if(!sys_rstn)
            smbit <= 8'b11111110;
        else
            begin
                if(delay_cnt1 == 16'd49999)
                    begin
                        if(smbit == 8'b11111110)
                            begin
                                databuf1 <= disp_dat/10;
                                smbit <= 8'b11111101;
                            end
                        else if(smbit == 8'b11111101)
                            begin
                                databuf1 <= disp_dat%10;
                                smbit <=    8'b11111110;
                            end
                    end
            end
    end

   
//显示部分,相当于译码器
always @(databuf1)
    begin
        case(databuf1)
            4'h0    :seg = 8'hc0;
            4'h1    :seg = 8'hf9;
            4'h2    :seg = 8'ha4;
            4'h3    :seg = 8'hb0;
            4'h4    :seg = 8'h99;
            4'h5    :seg = 8'h92;
            4'h6    :seg = 8'h82;
            4'h7    :seg = 8'hf8;
            4'h8    :seg = 8'h80;
            4'h9    :seg = 8'h90;
            4'hA    :seg = 8'h88;
            4'hB    :seg = 8'h83;
            4'hC    :seg = 8'hc6;
            4'hD    :seg = 8'ha1;
            4'hE    :seg = 8'h86;
            4'hF    :seg = 8'h8e;
        endcase
    end   
endmodule


附注:后来我又复现了先更新位码后更新段码的现象。发现完全不是哪个先更新的原因。真正的原因是我写always的时候,使用了错误的敏感信号。我使用了smbit位码作为敏感信号造成了一大堆的乱现象。
先为码后段码的代码如下:
//这里只更新位码
always @(posedge sys_clk or negedge sys_rstn)
    begin
        if(!sys_rstn)
            smbit <= 8'b11111110;
        else
            begin
                if(delay_cnt1 == 16'd49999)
                    begin
                        if(smbit == 8'b11111110)
                            begin
                                //databuf1 <= disp_dat/10;
                                smbit <= 8'b11111101;
                            end
                        else if(smbit == 8'b11111101)
                            begin
                                //databuf1 <= disp_dat%10;
                                smbit <=    8'b11111110;
                            end
                    end
            end
    end

//这里根据位码更新更新段码。
always @(posedge sys_clk )
    begin
                if(smbit ==8'b11111110)
                    begin
                        databuf1 <= disp_dat%10;
                    end
                else
                    begin
                        databuf1 <= disp_dat/10;
                    end

    end

感觉,先位码这种写法看着不好估计会出现毛刺什么的。段码和位码这两个东西更新的时钟是一样的,所以,更新段码的时候位码可能还没跟新或者已经更新。出现不确定的状态

高工
2012-10-20 22:51:40     打赏
10楼
通过前两个实验,学习了操作fpga管脚进行输出。这个实验是处理输入。
本实验实现了八个按键控制八个LED的亮灭。
当按键按下时对应的led灯点亮,按键松开时led灯熄灭。八个按键独立使用,按下多个按键多个对于led亮。

实验代码如下:
/*按键控制LED灯实验*/
/*按键按下对应的亮*/
module mykeys(sys_clk,sys_rstn,leds,keys);
input sys_clk,sys_rstn;        //系统时钟和复位
input [7:0]    keys;                //对应外围版8个按键
output [7:0] leds;            //只使用了8个led
    
reg [7:0]    leds;

always@(posedge sys_clk or negedge sys_rstn)
    begin
        if(!sys_rstn)
            begin
                leds <= 8'b00000000;
            end
        else
            begin
                leds <= keys;
            end
    end

endmodule

按键控制led灯反转的always模块:
always@(posedge sys_clk or negedge sys_rstn)
    begin
        if(!sys_rstn)
            begin
                leds <= 8'b11111111;
            end
        else
            begin
                //leds <= keys;
                if(!keys[0])
                    leds[0] = ~leds[0];
                else
                    leds[0] = leds[0];
            end
    end
这里操作按键可以很清楚地看到抖动。有时候按几下按键灯都不灭,这并不是LED没按到位而是在按下的过程中LED反转了好多次

共40条 1/4 1 2 3 4 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]