(1602初探)hanshuyujifen的进程贴
九月底就收到了板子,一直空着。
今天刚买到了元件,开始焊接 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 进程
自购元件,自己焊接。问题多多
焊接时的第一个问题:
主片引脚歪了,连焊,如图。焊接主片时候没注意,烙铁是垂直片子的边拖的,要是往外拖应该不会歪的
解决方法,用一个很薄的刀片插在两个引脚之间,然后烙铁点焊盘。刀片轻轻地撬,往下压降锡切开。等冷却后拿开刀片就OK了:
注意千万不要用力太刀了,不然焊盘废了就完蛋了。
第二个问题:D1灯不好好亮
焊接完核心板,上电测试。
先测电压,3.3V 1.2V都正常。
D3正常,D1不亮。
在群里边问了下,这是不正常的。D1应该在配置完成之后才熄灭的。
于是,我到处找问题。刚开始以为LED有问题。换了个,还是老样子。把周围相关的几个电阻、三极管都检查了一遍,没问题。
偶然间发现,按住D1那个角(如图)D1就会亮。怀疑板子有什么问题。又把周围的零件用烙铁点了一遍。还是不行。
没招,看电路吧。发现D1是否亮受CONF_ DONE信号控制。于是,三用表笔按住这个引脚。D1正常了。
最后 烙铁点了下这个引脚 D1就正常了
手压住一角之后的效果
硬件还在调试 此帖还会更新
外围版正面
外围版背面
核心板正面
核心板背面
焊接的比较匆忙。尤其是主片,还有问题没搞定。烙铁还不能封存
第一个:共阳数码管
虽然照片是出来了,可还是有问题。数字会闪烁,或者只显示数字0,别的显示不出来。问题还没找到。
板子焊坏了,拿出去拆掉主片 重新焊接
由于那靠近SDRAM排引脚全部歪了 最后还是没焊好
再测试 发现电源还短路了
不敢上电
明天继续检查,看哪里短路了。造出了就好了
把那排引脚除了电源和底线全部切断再玩,不用SDram了
2012.11.22
今天收到了51FPGA寄来的新板子。兴奋地准备了半天,左对右对的终于把引脚对其了。下烙铁,开焊。焊的那个工整啊!
焊接一半的时候,歇会吧。于是乎,悲剧地发现,片子焊反了。焊反了。焊反了。焊反了。焊反了。焊反了。焊反了。焊反了。
彻底悲剧了。又花200块钱买了个热风枪,准备拆焊。等。。
算算时间,也不能等了,今晚开始工作。
今天的总结:
1、今天第二次焊接失败,失败的弱智。片子焊反了。
2、到十二月底只有一个月时间了,得抓紧时间要不老王不发工资了。
3、于是,晚上先是照着入门教程写了会代码,学习了最简单的QII操作。然后看了个FPGA的资料。
4、从今天开始,先学代码写东西,等着拆焊的热风来。板子好后,视频和图片一并发布。
次楼记录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按钮,希望以上分析是对的,板子故障不要再复现了。
点灯是做所有实验的第一步,板子好了之后第一件事就是点灯。
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
图片和视频稍后上传
共阳极数码管,引脚加低电平亮。
静态扫描
分频,变化周期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
图片和视频稍后上传
对于我来说,这个实验比较费劲。用了一晚上时间搞定的。
动态扫描方式控制数码管显示,是单片机时代信手捻来的东西,可到了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
感觉,先位码这种写法看着不好估计会出现毛刺什么的。段码和位码这两个东西更新的时钟是一样的,所以,更新段码的时候位码可能还没跟新或者已经更新。出现不确定的状态
本实验实现了八个按键控制八个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反转了好多次
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
vscode+cmake搭建雅特力AT32L021开发环境被打赏30分 | |
【换取逻辑分析仪】自制底板并驱动ArduinoNanoRP2040ConnectLCD扩展板被打赏47分 | |
【分享评测,赢取加热台】RISC-V GCC 内嵌汇编使用被打赏38分 | |
【换取逻辑分析仪】-基于ADI单片机MAX78000的简易MP3音乐播放器被打赏48分 | |
我想要一部加热台+树莓派PICO驱动AHT10被打赏38分 | |
【换取逻辑分析仪】-硬件SPI驱动OLED屏幕被打赏36分 | |
换逻辑分析仪+上下拉与多路选择器被打赏29分 | |
Let'sdo第3期任务合集被打赏50分 | |
换逻辑分析仪+Verilog三态门被打赏27分 | |
换逻辑分析仪+Verilog多输出门被打赏24分 |