进程10,DS1302数字时钟
参考DS1302手册可知:访问DS1302时钟芯片使用串行通讯方式,需要3条信号线:/RST,SCLK,SIO。
DS1302读写时序
读/写的时序图如上图,第一个字节是“访问寄存器地址”第二个字节是“写数据”,写操作中都是时钟上升沿有效。读数据则不需要第二字节操作,读出的数据在时钟的下降沿有效。操作器件/RST必须拉高。数据都是从LSB开始,MSB结束。
寄存器格式
读/写操作寄存器格式见上图,“访问寄存器地址”这个字节的格式:
命令格式
BIT7 固定
BIT6 访问寄存器空间/访问RAM空间
BIT5..1 地址数据
BIT0 读/写操作
于是,在Verilog HDL语言中,访问寄存器地址的格式可以写成:{2'b10,5'd Addr,1'b R/W}
其中BIT7固定为1、BIT6固定为0,
则读分钟寄存器就可以写成:{2'b10,5‘d2,1’b1}
写分钟寄存器59写成:{2'b10,5‘d2,1’b0}{4'd5,4'd9}
秒寄存器的BIT7位为0,启动DS1302,为1关闭之,
时寄存器的BIT7位为0,是24小时制,为1是12小时制,
控制寄存器BIT7位为0,关闭写保护,为1,打开写保护。
SIO三态门
读写DS1302时的数据线为双向SIO,图中isOut为高时IO为输出,向DS1302写操作,isOut为低时SIO为输入,对DS1302读操作。Verilg HDL 语言表示方法:
assign SIO=isOut ? Data_Out : 1'bz;
assign Data_In = SIO;
进程中将8位LED数码管动态显示与读写DS1302进程相结合,首先关闭DS1302写保护,接着对时分秒写入23时59分00秒,然后就一直读取这3个寄存器的数据并在8位LED数码管上显示。运行中可以观察到当时钟运行到23-59-59后,下1秒显示为:00-00-00。同时跑马灯用的LED管也利用起来,显示了从0-59秒的二进制格式。最右边的黄色LED每隔1秒亮灭变化。由于Verilg HDL是并行操作,虽然没有使用任何中断,但FPGA同时处理多个进程很轻松,数码LED没有任何闪烁的感觉。
module clock_top
(
CLK, RSTn,
KEY,
SEG, DIG,
RST,
SCLK,
SIO,
SEC_Data,
MIN_Data,
HOU_Data,
LED,
YELLOW
);
input CLK;
input RSTn;
input [7:0]KEY;
output [7:0]SEG;
output [7:0]DIG;
output RST;
output SCLK;
inout SIO;
output [7:0]SEC_Data;
output [7:0]MIN_Data;
output [7:0]HOU_Data;
output [7:0]LED;
output [2:0]YELLOW;
/**************************************/
wire [3:0]Data7;
wire [3:0]Data6;
wire [3:0]Data5;
wire [3:0]Data4;
wire [3:0]Data3;
wire [3:0]Data2;
wire [3:0]Data1;
wire [3:0]Data0;
number_swap_module U1
(
.CLK( CLK ),
.RSTn( RSTn ),
.KEY( Number_Data ),
.SEC_Data(SEC_Data),
.MIN_Data(MIN_Data),
.HOU_Data(HOU_Data),
.Data7 ( Data7 ),
.Data6 ( Data6 ),
.Data5 ( Data5 ),
.Data4 ( Data4 ),
.Data3 ( Data3 ),
.Data2 ( Data2 ),
.Data1 ( Data1 ),
.Data0 ( Data0 )
);
/****************************************/
wire [7:0]Bit7;
wire [7:0]Bit6;
wire [7:0]Bit5;
wire [7:0]Bit4;
wire [7:0]Bit3;
wire [7:0]Bit2;
wire [7:0]Bit1;
wire [7:0]Bit0;
seg_encoder_module U2
(
.CLK( CLK ),
.RSTn( RSTn ),
.Data7 ( Data7 ),
.Data6 ( Data6 ),
.Data5 ( Data5 ),
.Data4 ( Data4 ),
.Data3 ( Data3 ),
.Data2 ( Data2 ),
.Data1 ( Data1 ),
.Data0 ( Data0 ),
.Bit7 ( Bit7 ),
.Bit6 ( Bit6 ),
.Bit5 ( Bit5 ),
.Bit4 ( Bit4 ),
.Bit3 ( Bit3 ),
.Bit2 ( Bit2 ),
.Bit1 ( Bit1 ),
.Bit0 ( Bit0 ) );
/*****************************************/
comp_scan_module U3
(
.CLK( CLK ),
.RSTn( RSTn ),
.Bit7 ( Bit7),
.Bit6 ( Bit6 ),
.Bit5 (Bit5 ),
.Bit4 ( Bit4),
.Bit3 ( Bit3 ),
.Bit2 (Bit2 ),
.Bit1 ( Bit1),
.Bit0 ( Bit0 ),
.SEG ( SEG ),
.DIG ( DIG )
);
exp13_demo_module U4
(
.CLK( CLK ),
.RSTn( RSTn ),
.RST(RST),
.SCLK(SCLK),
.SIO(SIO),
.SEC_Data(SEC_Data),
.MIN_Data(MIN_Data),
.HOU_Data(HOU_Data),
.LED(LED),
.YELLOW(YELLOW)
);
/*******************************/
endmodule
module function_module
(
CLK, RSTn,
Start_Sig,
Words_Addr,
Write_Data,
Read_Data,
Done_Sig,
RST,
SCLK,
SIO
);
input CLK;
input RSTn;
input [1:0]Start_Sig;
input [7:0]Words_Addr;
input [7:0]Write_Data;
output [7:0]Read_Data;
output Done_Sig;
output RST;
output SCLK;
inout SIO; //SIO和寄存器isOut组成三态门IO口
/*****************************/
parameter T0P5US = 4'd9;
/*****************************/
reg [3:0]Count1;
always @ ( posedge CLK or negedge RSTn )
if( !RSTn )
Count1 <= 4'd0;
else if( Count1 == T0P5US )
Count1 <= 4'd0;
else if( Start_Sig[0] == 1'b1 || Start_Sig[1] == 1'b1 )
Count1 <= Count1 + 1'b1;
else
Count1 <= 4'd0;
/*****************************/
reg [5:0]i; //执行步骤的寄存器
reg [7:0]rData; //暂存数据的寄存器
reg rSCLK; //用来驱动SCLK的寄存器
reg rRST; //用来驱动RST的寄存器
reg rSIO; //用来驱动SIO输出的寄存器
reg isOut; //用来控制IO方向寄存器
reg isDone; //完成标志寄存器
always @ ( posedge CLK or negedge RSTn )
if( !RSTn )
begin
i <= 6'd0;
rData <= 8'd0;
rSCLK <= 1'b0;
rRST <= 1'b0;
rSIO <= 1'b0;
isOut <= 1'b0;
isDone <= 1'b0;
end
/***************************************************************************************
Start_Sig为2'b10 时是“写字节操作”。
步骤0:对rData,rSCL,rRST(CE),isOut等寄存器进行初始化。
步骤1-16:将“第一字节数据”(访问寄存器地址字节)发送出去。传输规则与SPI有点相似,在时间下降
沿设置数据,时间上升沿锁存数据。
步骤17:再次对rData设置为“第二字节数据”。
步骤18-33:将“第二字节数据”发送出去。
步骤34:对rRST(CE)拉低。以示“写字节操作”已经结束。
步骤35-36:反馈完成信号。
Start_Sig为2'b01 时是“读字节操作”。
*****************************************************************************************/
else if( Start_Sig[1] )
case( i )
0 :
begin rSCLK <= 1'b0; rData <= Words_Addr; rRST <= 1'b1; isOut <= 1'b1; i <= i + 1'b1; end
1, 3, 5, 7, 9, 11, 13, 15 :
if( Count1 == T0P5US ) i <= i + 1'b1;
else begin rSIO <= rData[ (i >> 1) ]; rSCLK <= 1'b0; end
2, 4, 6, 8, 10, 12, 14, 16 :
if( Count1 == T0P5US ) i <= i + 1'b1;
else begin rSCLK <= 1'b1; end
17 :
begin rData <= Write_Data; i <= i + 1'b1; end
18, 20, 22, 24, 26, 28, 30, 32 :
if( Count1 == T0P5US ) i <= i + 1'b1;
else begin rSIO <= rData[ (i >> 1) - 9 ]; rSCLK <= 1'b0; end
19, 21, 23, 25, 27, 29, 31, 33 :
if( Count1 == T0P5US ) i <= i + 1'b1;
else begin rSCLK <= 1'b1; end
34 :
begin rRST <= 1'b0; i <= i + 1'b1; end
35 :
begin isDone <= 1'b1; i <= i + 1'b1; end
36 :
begin isDone <= 1'b0; i <= 6'd0; end
endcase
/***************************************************************************************
Start_Sig为2'b01 时是“读字节操作”。在读操作中,第一字节和第二字节数据显然对时间沿的敏感不同。
步骤0:对rData,rSCL,rRST(CE),isOut等寄存器进行初始化。
步骤1-16:将“第一字节数据”(访问寄存器地址字节)发送出去。传输规则与SPI有点相似,在时间下降
沿设置数据,时间上升沿锁存数据。
步骤17:对IO口的方向改变为输入,亦即将isOut设置为逻辑0。
步骤18-33:“读取一个字节数据操作”,该操作在时间的下降沿从SIO读取数据。DS1302的数据传输都是从
LSB开始到MSB结束。
步骤34:对rRST(CE)拉低。以示“写字节操作”已经结束。
步骤35-36:恢复IO口为输出,拉高isOut寄存器,然后产生一个完成信号。
从DS1302芯片读取的数据会暂存在rData寄存器,该寄存器会驱动Read_Data这条信号线。assign Read_Data = rData;
*****************************************************************************************/
else if( Start_Sig[0] )
case( i )
0 :
begin rSCLK <= 1'b0; rData <= Words_Addr; rRST <= 1'b1; isOut <= 1'b1; i <= i + 1'b1; end
1, 3, 5, 7, 9, 11, 13, 15 :
if( Count1 == T0P5US ) i <= i + 1'b1;
else begin rSIO <= rData[ (i >> 1) ]; rSCLK <= 1'b0; end
2, 4, 6, 8, 10, 12, 14, 16 :
if( Count1 == T0P5US ) i <= i + 1'b1;
else begin rSCLK <= 1'b1; end
17 :
begin isOut <= 1'b0; i <= i + 1'b1; end
18, 20, 22, 24, 26, 28, 30, 32 :
if( Count1 == T0P5US ) i <= i + 1'b1;
else begin rSCLK <= 1'b1; end
19, 21, 23, 25, 27, 29, 31, 33 :
if( Count1 == T0P5US ) begin i <= i + 1'b1; end
else begin rSCLK <= 1'b0; rData[ (i >> 1) - 9 ] <= SIO; end
34 :
begin rRST <= 1'b0; isOut <= 1'b1; i <= i + 1'b1; end
35 :
begin isDone <= 1'b1; i <= i + 1'b1; end
36 :
begin isDone <= 1'b0; i <= 6'd0; end
endcase
/********************************/
assign Read_Data = rData; //
assign Done_Sig = isDone;
assign RST = rRST;
assign SCLK = rSCLK;
assign SIO = isOut ? rSIO : 1'bz; //该行定义了SDA这个IO口是由isOut这个寄存器控制着“输入输出”。
//当isOut为逻辑1时,SIO口是输出状态,反之是输入状态
/********************************/
endmodule
相关LED数码动态扫描显示代码省略
点击下载DS1302数字时钟.rar
进程11、交通灯
交通灯是通过将进程4中的LED数码动态显示模块与本模块组合成的交通信号灯。秒信号计数器从50MHZ分频得到,初值设定为35秒,计数到5秒后黄灯开始闪烁,计数到0秒后黄灯熄灭。绿灯与红灯交换亮起。
秒信号:
/************************************/
parameter T1S = 26'd49_999_999;
/************************************/
reg [25:0]Count1;
always @ ( posedge CLK or negedge RSTn )
if( !RSTn )
Count1 <= 26'd0;
else if( Count1 == T1S )
Count1 <= 26'd0;
else
Count1 <= Count1 + 1'b1;
控制过程:
reg [7:0]Counter_Sec;
reg rRED;
reg rYELLOW;
always @ ( posedge CLK or negedge RSTn )
if( !RSTn )
begin
Counter_Sec <= 8'd35; //秒计数初值
rRED <= 1'd1; //红灯灭
rYELLOW <= 1'd1; //黄灯灭
end
else if( Count1 == T1S )
begin
if( Counter_Sec > 8'd0 )
begin
Counter_Sec <= Counter_Sec - 1'b1;
if((Counter_Sec == 8'd6)||(Counter_Sec == 8'd4)||(Counter_Sec == 8'd2) )
rYELLOW <= 1'd0; //黄灯闪烁亮期间
else
rYELLOW <= 1'd1; //黄灯闪烁灭期间
end
else
begin
Counter_Sec <= 8'd35;
rRED <= ~rRED; //2个秒计数周期红绿灯交换亮灭
rYELLOW = 1'd1;
end
end
/******************************************/
assign RED = rRED; //输出
assign GREEN = ~rRED;
assign YELLOW = rYELLOW;
I/O分配图
通行期间绿灯亮, 计数到5秒后黄灯闪烁期的黄灯熄灭期间
禁行期间红灯亮, 计数到5秒后黄灯闪烁期的黄灯亮起期间
点击下载交通灯演示SOFsample_demo.rar
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
与电子爱好者谈读图四被打赏50分 | |
与电子爱好者谈读图二被打赏50分 | |
【FRDM-MCXN947评测】Core1适配运行FreeRtos被打赏50分 | |
【FRDM-MCXN947评测】双核调试被打赏50分 | |
【CPKCORRA8D1B评测】---移植CoreMark被打赏50分 | |
【CPKCORRA8D1B评测】---打开硬件定时器被打赏50分 | |
【FRDM-MCXA156评测】4、CAN loopback模式测试被打赏50分 | |
【CPKcorRA8D1评测】--搭建初始环境被打赏50分 | |
【FRDM-MCXA156评测】3、使用FlexIO模拟UART被打赏50分 | |
【FRDM-MCXA156评测】2、rt-thread MCXA156 BSP制作被打赏50分 |