差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
数字万年历设计 [2018/10/31 16:39] anran [实验原理] |
数字万年历设计 [2021/01/06 23:02] gongyu |
||
---|---|---|---|
行 1: | 行 1: | ||
- | =====数字万年历设计===== | + | ### 数字万年历设计 |
----- | ----- | ||
====实验任务==== | ====实验任务==== | ||
行 110: | 行 111: | ||
endcase | endcase | ||
end | end | ||
- | <\code> | + | </code> |
芯片支持连续读寄存器操作(寄存器地址自加1),时序流程如下: | 芯片支持连续读寄存器操作(寄存器地址自加1),时序流程如下: | ||
行 148: | 行 149: | ||
endcase | endcase | ||
end | end | ||
- | <\code> | + | </code> |
上面两段程序就是对于DS1340Z芯片的两种操作,调时间和读时间,对于万年历来说因为有电池供电,实时时钟一直都处于工作状态,当给FPGA上电时只需要读时间即可,只有遇到时间不对的时候才需要调时间,所以DS1340Z驱动模块平时都在循环读取时间,所以如果将调时间和读时间的时序操作融合到同一个状态下时,对于cnt_main要加以控制,cnt_main初值为12,且运行轨迹在12~32之间,控制程序调整如下: | 上面两段程序就是对于DS1340Z芯片的两种操作,调时间和读时间,对于万年历来说因为有电池供电,实时时钟一直都处于工作状态,当给FPGA上电时只需要读时间即可,只有遇到时间不对的时候才需要调时间,所以DS1340Z驱动模块平时都在循环读取时间,所以如果将调时间和读时间的时序操作融合到同一个状态下时,对于cnt_main要加以控制,cnt_main初值为12,且运行轨迹在12~32之间,控制程序调整如下: | ||
行 157: | 行 158: | ||
else cnt_main <= 6'd12; //否则只执行时间读取操作 | else cnt_main <= 6'd12; //否则只执行时间读取操作 | ||
else cnt_main <= cnt_main + 1'b1; | else cnt_main <= cnt_main + 1'b1; | ||
- | <\code> | + | </code> |
上面set_flag为时间调整标志位,只有按动编码器在调时间模式时需要用到写时间数据的操作流程,可以根据按键脉冲置位set_flag并自锁,每次完成写入操作后再将set_flag复位。程序实现如下: | 上面set_flag为时间调整标志位,只有按动编码器在调时间模式时需要用到写时间数据的操作流程,可以根据按键脉冲置位set_flag并自锁,每次完成写入操作后再将set_flag复位。程序实现如下: | ||
行 169: | 行 170: | ||
else set_flag <= set_flag; | else set_flag <= set_flag; | ||
end | end | ||
- | <\code> | + | </code> |
模块端口如下: | 模块端口如下: | ||
行 188: | 行 189: | ||
output [7:0] rtc_year, rtc_mon, rtc_day, rtc_week //实时年份输出 | output [7:0] rtc_year, rtc_mon, rtc_day, rtc_week //实时年份输出 | ||
); | ); | ||
- | <\code> | + | </code> |
到这里就完成了万年历中DS1340Z模块的驱动设计,宏观上讲,该模块的功能可以这样描述: | 到这里就完成了万年历中DS1340Z模块的驱动设计,宏观上讲,该模块的功能可以这样描述: | ||
行 211: | 行 212: | ||
else state <= 3'd7; | else state <= 3'd7; | ||
else state <= state; | else state <= state; | ||
- | <\code> | + | </code> |
**<wrap hi>调时控制</wrap>** | **<wrap hi>调时控制</wrap>** | ||
行 232: | 行 233: | ||
end | end | ||
end | end | ||
- | <\code> | + | </code> |
调秒模式与其他调节模式操作一样,不同的是调节的规则不同,例如秒和分的调节范围为0~59,小时调节范围0~11或0~23,日期调节范围需要考虑年和月的值(1、3、5、7、8、10、12月范围1~31,4、6、9、11月范围1~30,2月平年范围1~28,2月闰年范围1~29),周调节范围1~7,月调节范围1~12,年调节范围0~99。对秒钟数据进行调节,程序实现如下: | 调秒模式与其他调节模式操作一样,不同的是调节的规则不同,例如秒和分的调节范围为0~59,小时调节范围0~11或0~23,日期调节范围需要考虑年和月的值(1、3、5、7、8、10、12月范围1~31,4、6、9、11月范围1~30,2月平年范围1~28,2月闰年范围1~29),周调节范围1~7,月调节范围1~12,年调节范围0~99。对秒钟数据进行调节,程序实现如下: | ||
行 249: | 行 250: | ||
end else adj_sec <= adj_sec; | end else adj_sec <= adj_sec; | ||
end | end | ||
- | <\code> | + | </code> |
**<wrap hi>显示控制</wrap>** | **<wrap hi>显示控制</wrap>** | ||
行 266: | 行 267: | ||
else if(R_pulse) disp_en <= 4'b0111; //顺时针转显示第二页,时分秒亮 | else if(R_pulse) disp_en <= 4'b0111; //顺时针转显示第二页,时分秒亮 | ||
else disp_en <= disp_en; | else disp_en <= disp_en; | ||
- | <\code> | + | </code> |
调秒模式下,小时和分钟数码管点亮,秒钟闪烁显示,转动编码器时秒钟强制显示,最后按动旋转编码器切到常态模式时,时分秒数码管都回复显示,程序实现如下: | 调秒模式下,小时和分钟数码管点亮,秒钟闪烁显示,转动编码器时秒钟强制显示,最后按动旋转编码器切到常态模式时,时分秒数码管都回复显示,程序实现如下: | ||
行 278: | 行 279: | ||
else disp_en[0] <= disp_en[0]; | else disp_en[0] <= disp_en[0]; | ||
end | end | ||
- | <\code> | + | </code> |
===系统总体实现=== | ===系统总体实现=== | ||
行 291: | 行 292: | ||
wire [7:0] data_en = {{2{disp_en[3]}},{2{disp_en[2]}},{2{disp_en[1]}},{2{disp_en[0]}}}; //数码管位选控制 | wire [7:0] data_en = {{2{disp_en[3]}},{2{disp_en[2]}},{2{disp_en[1]}},{2{disp_en[0]}}}; //数码管位选控制 | ||
wire [7:0] dot_en = {1'b0,disp_en[3],1'b0,disp_en[2],1'b0,disp_en[1],1'b0,disp_en[0]}; //数码管小数点显示控制 | wire [7:0] dot_en = {1'b0,disp_en[3],1'b0,disp_en[2],1'b0,disp_en[1],1'b0,disp_en[0]}; //数码管小数点显示控制 | ||
- | <\code> | + | </code> |
**<wrap hi>数码管内容控制</wrap>** | **<wrap hi>数码管内容控制</wrap>** | ||
行 297: | 行 298: | ||
万年历的显示分两页实现,我们以最右侧两个数码管显示内容为例,这两位数码管在第一页中显示周数据,在第二页中显示秒数据,那么我们怎么控制显示内容呢?分析,万年历8中模式, | 万年历的显示分两页实现,我们以最右侧两个数码管显示内容为例,这两位数码管在第一页中显示周数据,在第二页中显示秒数据,那么我们怎么控制显示内容呢?分析,万年历8中模式, | ||
- | 1.常态模式下,显示读取的实时时钟数据,具体显示周还是秒再次细化 | + | <wrap em>1</wrap>.常态模式下,显示读取的实时时钟数据,具体显示周还是秒再次细化 |
* disp_en等于4'b1111的时候,对应第一页,显示周数据 | * disp_en等于4'b1111的时候,对应第一页,显示周数据 | ||
* disp_en等于4'b0111的时候,对应第二页,显示秒数据 | * disp_en等于4'b0111的时候,对应第二页,显示秒数据 | ||
行 305: | 行 306: | ||
<code verilog> | <code verilog> | ||
wire [7:0] data_rtc0 = disp_en[3]? rtc_week:rtc_sec; //常态下数码管显示数据 | wire [7:0] data_rtc0 = disp_en[3]? rtc_week:rtc_sec; //常态下数码管显示数据 | ||
- | <\code> | + | </code> |
- | 2.调节模式下,显示写入的调节时钟数据,具体显示周还是秒再次细化 | + | <wrap em>2</wrap>.调节模式下,显示写入的调节时钟数据,具体显示周还是秒再次细化 |
* 调年、调月、调日、调周 状态下(state>=3),对应第一页,显示周数据 | * 调年、调月、调日、调周 状态下(state>=3),对应第一页,显示周数据 | ||
* 调时、调分、调秒 状态下(state<3),对应第二页,显示秒数据 | * 调时、调分、调秒 状态下(state<3),对应第二页,显示秒数据 | ||
行 315: | 行 316: | ||
<code verilog> | <code verilog> | ||
wire [7:0] data_adj0 = state[2]? adj_week:adj_sec; //调节状态下数码管显示数据 | wire [7:0] data_adj0 = state[2]? adj_week:adj_sec; //调节状态下数码管显示数据 | ||
- | <\code> | + | </code> |
- | 3.最后根据常态模式还是调节模式控制数码管显示实时时钟数据还是调节时钟数据 | + | <wrap em>3</wrap>.最后根据常态模式还是调节模式控制数码管显示实时时钟数据还是调节时钟数据 |
根据state选择显示实时时钟数据还是调节时钟数据,程序实现如下: | 根据state选择显示实时时钟数据还是调节时钟数据,程序实现如下: | ||
行 323: | 行 324: | ||
<code verilog> | <code verilog> | ||
assign {data_7,data_8} = state? data_adj0:data_rtc3; //根据状态选择显示常态数据还是调节状态数据 | assign {data_7,data_8} = state? data_adj0:data_rtc3; //根据状态选择显示常态数据还是调节状态数据 | ||
- | <\code> | + | </code> |
综合后的设计框图如下: | 综合后的设计框图如下: | ||
行 341: | 行 342: | ||
====实验现象==== | ====实验现象==== | ||
+ | |||
+ | 将程序下载到FPGA中,按照设计要求的功能操作调节万年历的时间,观察数码管万年历显示,如图时间为18年6月27日,周三,19点15分14秒。 | ||
+ | |||
+ | {{:11-实验现象1.png?500|实验现象}} {{:11-实验现象2.png?500|实验现象}} |