光写Verilog知识和入门。再高级点的应用,肯定不会只有Verilog了
或许FPGA巅峰神人可以完全用Verilog搞定一切
26、DS1302实验
因为还没吧按键调节时间的弄好,就先上个图片吧
明天估计能上代码,,,嘻嘻
DS1302的驱动是这样的:
module ds1302_drive(clk,rst,srst,sclk,sdata,TimeData,DateData)
input rst; //外部复位
input clk; //输入时钟
output srst; //ds1302复位
output sclk; //ds1302时钟
inout sdata; //ds1302数据口
output[23:0] TimeData; //时间数据
output[31:0] DateData; //日历数据
reg data; //sdata的缓存,
reg isOut; //因为sdata是双向口,所以需要标志位isOut来管理数据的输入输出
assign sdata=(isOut)? data:1'bz; //isOut:1、输出;0、高阻
parameter
IDLE = 4'd0,
WR_Sec = 4'd1,
WR_Min = 4'd2,
WR_Hour = 4'd3,
WR_Week = 4'd4,
WR_Day = 4'd5,
WR_Mont = 4'd6,
WR_Year = 4'd7;
parameter
RD_Sec = 4'd8,
RD_Min = 4'd9,
RD_Hour = 4'd10,
RD_Week = 4'd11,
RD_Day = 4'd12,
RD_Mont = 4'd13,
RD_Year = 4'd14,
CLOSE_W = 4'd15;
parameter
WR_state_0 = 5'd0,
WR_state_1 = 5'd1,
WR_state_2 = 5'd2,
WR_state_3 = 5'd3,
WR_state_4 = 5'd4,
WR_state_5 = 5'd5,
WR_state_6 = 5'd6,
WR_state_7 = 5'd7,
WR_state_8 = 5'd8,
WR_state_9 = 5'd9,
WR_state_a = 5'd10,
WR_state_b = 5'd11,
WR_state_c = 5'd12,
WR_state_d = 5'd13,
WR_state_e = 5'd14,
WR_state_f = 5'd15,
WR_state_10 = 5'd16;
parameter
RD_state_0 = 5'd0,
RD_state_1 = 5'd1,
RD_state_2 = 5'd2,
RD_state_3 = 5'd3,
RD_state_4 = 5'd4,
RD_state_5 = 5'd5,
RD_state_6 = 5'd6,
RD_state_7 = 5'd7,
RD_state_8 = 5'd8,
RD_state_9 = 5'd9,
RD_state_a = 5'd10,
RD_state_b = 5'd11,
RD_state_c = 5'd12,
RD_state_d = 5'd13,
RD_state_e = 5'd14,
RD_state_f = 5'd15,
RD_state_10 = 5'd16;
reg[7:0]counter;
reg clk_sta; //状态机的时钟8us/period
always@(posedge clk ) begin //or negedge rst) begin
/* iRD_flag(!rst)
begin
counter <= 8'b0;
clk_sta <= 1'b0;
end
else */if(counter<=100)
counter<=counter+8'b1;
else
begin
clk_sta<=~clk_sta;
counter<=0;
end
end
reg sclk_r;//ds1302的工作时钟
always @ (negedge clk_sta ) begin//or negedge rst) begin
if(!srst_r)
sclk_r <= 1'b0;
else
sclk_r<=~sclk_r;
end
assign sclk=sclk_r;
reg Rest_flag; //重新设置标志位
reg [4:0]WR_state; //WR_SET的状态
reg [4:0]RD_state; //RD_T任务的状态
reg [23:0] TimeData_r;
reg [31:0] DateData_r;
reg RD_flag; //写任务的标志
reg WR_flag; //读任务标志
reg [7:0]CMD = 8'h00; //command
reg [7:0]SEC = 8'h50; //时间/日历
reg [7:0]MIN = 8'h59; //分钟
reg [7:0]HOU = 8'h23; //小时
reg [7:0]DAY = 8'h31; //天
reg [7:0]Month = 8'h12; //月
reg [7:0]Week = 8'h04; //星期
reg [7:0]Year = 8'h12; //年
reg [7:0]register1; //command
reg [7:0]register3;
reg [7:0]register4; //读进数据寄存器
reg [3:0]state; //状态机
reg srst_r;
always @(posedge clk_sta ) begin
if(rst==0)
begin
//初始化操作时,isOut<=0;所以输出呈现高阻态
srst_r<=0;
data<=0; //输出缓存器被清空
WR_flag<=0;
RD_flag<=0;
state<=IDLE;
isOut<=0;
register1<=8'b10001110; //关闭写保护
TimeData_r<=0;
DateData_r<=0;
Rest_flag<=1;
WR_state<=0;
RD_state<=0;
end
else
case(state)
//IDLE状态选择工作状态还是初始设置状态
IDLE : begin
//Rest_flag==1时,重新设置数据
if(Rest_flag == 1'b1)
begin
if(WR_flag == 1'b0)
begin
WR_SET(CMD);
state <= IDLE;
end
else
begin
Rest_flag <= 1'b0;
srst_r <= 1'b0;
isOut <= 1'b0;
WR_flag <= 1'b0;
register1 <= 8'b1000_0000;////写时钟/日历寄存器
state <= WR_Sec;
end
end
else if(Rest_flag == 1'b0)
begin
register4 <= 8'b1000_0001;
isOut <= 1'b0;
srst_r <= 1'b0;
RD_flag <= 1'b0;
state <= RD_Sec;
end
else state <= IDLE;
end
WR_Sec : begin
if(WR_flag == 1'b0) WR_SET(SEC);//写秒
else
begin
state <= WR_Min;
isOut <= 1'b0;
WR_flag <= 1'b0;
register1 <= 8'b1000_0010;
end
end
WR_Min : begin
if(WR_flag == 1'b0) WR_SET(MIN);
else
begin
state <= WR_Hour;
isOut <= 1'b0;
WR_flag <= 1'b0;
register1 <= 8'b1000_0100;
end
end
WR_Hour : begin
if(WR_flag == 1'b0) WR_SET(HOU);
else
begin
state <= WR_Week;
isOut <= 1'b0;
WR_flag <= 1'b0;
register1 <= 8'b1000_1010;
end
end
WR_Week : begin
if(WR_flag == 1'b0) WR_SET(Week);
else
begin
state <= WR_Day;
isOut <= 1'b0;
WR_flag <= 1'b0;
register1 <= 8'b1000_0110;
end
end
WR_Day : begin
if(WR_flag == 1'b0) WR_SET(DAY);
else
begin
state <= WR_Mont;
isOut <= 1'b0;
WR_flag <= 1'b0;
register1 <= 8'b1000_1000;
end
end
WR_Mont : begin
if(WR_flag == 1'b0) WR_SET(Month);
else
begin
state <= WR_Year;
isOut <= 1'b0;
WR_flag <= 1'b0;
register1 <= 8'b1000_1100;
end
end
WR_Year : begin
if(WR_flag == 1'b0) WR_SET(Year);
else
begin
state <= CLOSE_W;
isOut <= 1'b0;
WR_flag <= 1'b0;
register1 <= 8'b10001110;
end
end
RD_Sec : begin
if(RD_flag == 1'b0) RD_T;
else
begin
TimeData_r[7:0] <= register3;
srst_r <= 1'b0;
RD_flag <= 1'b0;
register4 <= 8'b1000_0011;
state <= RD_Min;
end
end
RD_Min : begin
if(RD_flag == 1'b0) RD_T;
else
begin
TimeData_r[15:8] <= register3;
srst_r <= 1'b0;
RD_flag <= 1'b0;
register4 <= 8'b1000_0101;
state <= RD_Hour;
end
end
RD_Hour : begin
if(RD_flag == 1'b0) RD_T;
else
begin
TimeData_r[23:16] <= register3;
srst_r <= 1'b0;
RD_flag <= 1'b0;
register4 <= 8'b1000_1011;
state <= RD_Week;
end
end
RD_Week : begin
if(RD_flag == 1'b0) RD_T;
else
begin
DateData_r[7:0] <= register3;
srst_r <= 1'b0;
RD_flag <= 1'b0;
register4 <= 8'b1000_0111;
state <= RD_Day;
end
end
RD_Day : begin
if(RD_flag == 1'b0) RD_T;
else
begin
DateData_r[15:8] <= register3;
srst_r <= 1'b0;
RD_flag <= 1'b0;
register4 <= 8'b1000_1001;
state <= RD_Mont;
end
end
RD_Mont : begin
if(RD_flag == 1'b0) RD_T;
else
begin
DateData_r[23:16] <= register3;
srst_r <= 1'b0;
RD_flag <= 1'b0;
register4 <= 8'b1000_1101;
state <= RD_Year;
end
end
RD_Year : begin
if(RD_flag == 1'b0) RD_T;
else
begin
DateData_r[31:24] <= register3;
srst_r <= 1'b0;
RD_flag <= 1'b0;
register4 <= 8'b1000_0001;
state <= RD_Sec;
// RD_flaglag_initial<=0;
end
end
CLOSE_W : begin
if(WR_flag == 1'b0) WR_SET(8'h10);
else
begin
state <= IDLE;
isOut <= 1'b0;
WR_flag <= 1'b0;
RD_flag <= 1'b0;
Rest_flag <= 1'b0;
end
end
default : begin
Rest_flag <= 1'b0;
srst_r <= 1'b0;
data <= 1'b0;
WR_flag <= 1'b0;
RD_flag <= 1'b0;
state <= RD_Sec;
register3 <= 1'b0;//接受数据的寄存器
register4 <= 8'b1000_0001;//读任务的指令寄存器
CMD <= 8'b0;
end
endcase
end
task RD_T;
begin
case(RD_state)
RD_state_0 : begin
if(!sclk_r)
begin
isOut <= 1'b1;
srst_r <= 1'b1;
data <= register4[0];
RD_state <= RD_state_1;
end
else
begin
srst_r <= 1'b0;
RD_state <= RD_state_0;
data <= register4[0];
isOut <= 1'b1;
end
end
RD_state_1 : begin
if(!sclk_r)
begin
data <= register4[1];
RD_state <= RD_state_2;
end
else
begin
data <= data;
RD_state <= RD_state;
end
end
RD_state_2 : begin
if(!sclk_r)
begin
data <= register4[2];
RD_state <= RD_state_3;
end
else
begin
data <= data;
RD_state <= RD_state;
end
end
RD_state_3 : begin
if(!sclk_r)
begin
data <= register4[3];
RD_state <= RD_state_4;
end
else
begin
data <= data;
RD_state <= RD_state;
end
end
RD_state_4 : begin
if(!sclk_r)
begin
data <= register4[4];
RD_state <= RD_state_5;
end
else
begin
data <= data;
RD_state <= RD_state;
end
end
RD_state_5 : begin
if(!sclk_r)
begin
data <= register4[5];
RD_state <= RD_state_6;
end
else
begin
data <= data;
RD_state <= RD_state;
end
end
RD_state_6 : begin
if(!sclk_r)
begin
data <= register4[6];
RD_state <= RD_state_7;
end
else
begin
data <= data;
RD_state <= RD_state;
end
end
RD_state_7 : begin
if(!sclk_r)
begin
data <= register4[7];
RD_state <= RD_state_8;
end
else
begin
data <= data;
RD_state <= RD_state;
end
end
RD_state_8 : begin
if(!sclk_r)
begin
isOut <= 1'b0;
RD_state <= RD_state_9;
end
else
RD_state <= RD_state;
end
RD_state_9 : begin
if(!sclk_r) RD_state <= RD_state_a;
else RD_state <= RD_state;
end
RD_state_a : begin
if(!sclk_r) RD_state <= RD_state_b;
else RD_state <= RD_state;
end
RD_state_b : begin
if(!sclk_r) RD_state <= RD_state_c;
else RD_state <= RD_state;
end
RD_state_c : begin
if(!sclk_r) RD_state <= RD_state_d;
else RD_state <= RD_state;
end
RD_state_d : begin
if(!sclk_r) RD_state <= RD_state_e;
else RD_state <= RD_state;
end
RD_state_e : begin
if(!sclk_r) RD_state <= RD_state_f;
else RD_state <= RD_state;
end
RD_state_f : begin
if(!sclk_r) RD_state <= RD_state_10;
else RD_state <= RD_state_f;
end
RD_state_10 : begin
if(!sclk_r)
begin//该begin end块不执行
RD_flag <= 1'b1;
srst_r <= 1'b0;
RD_state <= RD_state_0;//do not run
end
else
begin
RD_flag <= 1'b1;
srst_r <= 1'b0;
RD_state <= RD_state_0;
end
end
default : begin
RD_state <= RD_state_0;
end
endcase
end
endtask
always @( posedge sclk_r or negedge rst) begin
if(!rst)
register3<= 8'b0;
else
begin
case(RD_state)
RD_state_9 : register3[0] <= sdata;
RD_state_a : register3[1] <= sdata;
RD_state_b : register3[2] <= sdata;
RD_state_c : register3[3] <= sdata;
RD_state_d : register3[4] <= sdata;
RD_state_e : register3[5] <= sdata;
RD_state_f : register3[6] <= sdata;
RD_state_10 : register3[7] <= sdata;
default : register3 <= register3;
endcase
end
end
task WR_SET;
input [7:0]reg_store;
begin
case(WR_state)
WR_state_0 : begin
if(!sclk_r)
begin
isOut <= 1'b1;
srst_r <= 1'b1;//低电平时才可以将srst_r拉高
data <= register1[0];
WR_state <= WR_state_1;
end
else
begin
srst_r <= 1'b0;
WR_state <= 1'b0;
data <= register1[0];
isOut <= 1'b0;
end
end
WR_state_1 : begin
if(!sclk_r)
begin
isOut <= 1'b1;
data <= register1[1];
WR_state <= WR_state_2;
end
else
WR_state <= WR_state;
end
WR_state_2 : begin
if(!sclk_r)
begin
isOut <= 1'b1;
data <= register1[2];
WR_state <= WR_state_3;
end
else
WR_state <= WR_state;
end
WR_state_3 : begin
if(!sclk_r)
begin
data <= register1[3];
WR_state <= WR_state_4;
end
else
WR_state <= WR_state;
end
WR_state_4 : begin
if(!sclk_r)
begin
data <= register1[4];
WR_state <= WR_state_5;
end
else
WR_state <= WR_state;
end
WR_state_5 : begin
if(!sclk_r)
begin
data <= register1[5];
WR_state <= WR_state_6;
end
else
WR_state <= WR_state;
end
WR_state_6 : begin
if(!sclk_r)
begin
data <= register1[6];
WR_state <= WR_state_7;
end
else
WR_state <= WR_state;
end
WR_state_7 : begin
if(!sclk_r)
begin
data <= register1[7];
WR_state <= WR_state_8;
end
else
WR_state <= WR_state;
end
WR_state_8 : begin
if(!sclk_r)
begin
data <= reg_store[0];
WR_state <= WR_state_9;
end
else
WR_state <= WR_state;
end
WR_state_9 : begin
if(!sclk_r)
begin
srst_r <= 1'b1;
data <= reg_store[1];
WR_state <= WR_state_a;
end
else
WR_state <= WR_state;
end
WR_state_a : begin
if(!sclk_r)
begin
data <= reg_store[2];
WR_state <= WR_state_b;
end
else
WR_state <= WR_state;
end
WR_state_b : begin
if(!sclk_r)
begin
data <= reg_store[3];
WR_state <= WR_state_c;
end
else
WR_state <= WR_state;
end
WR_state_c : begin
if(!sclk_r)
begin
data <= reg_store[4];
WR_state <= WR_state_d;
end
else
WR_state <= WR_state;
end
WR_state_d : begin
if(!sclk_r)
begin
data <= reg_store[5];
WR_state <= WR_state_e;
end
else
WR_state <= WR_state;
end
WR_state_e : begin
if(!sclk_r)
begin
data <= reg_store[6];
WR_state <= WR_state_f;
end
else
WR_state <= WR_state;
end
WR_state_f : begin
if(!sclk_r)
begin
data <= reg_store[7];
WR_state <= WR_state_10;
end
else
WR_state <= WR_state;
end
WR_state_10 : begin
if(!sclk_r)
begin
WR_state <= WR_state_0;
WR_flag <= 1'b1;
srst_r <= 1'b0;
end
else
WR_state <= WR_state; //读完数据不能马上把延迟一段时间再srst_r拉低
end
default : WR_state <= WR_state_0;
endcase
end
endtask
//----------------------END of TASK------------------------
assign TimeData = TimeData_r;
assign DateData = DateData_r;
assign srst = srst_r;
endmodule
27、基于DS1302的万年历LCD1602显示(最终修改版)
1、解决了上电时间复位的问题;
2、加上了LED校时指示。D1点亮为调节年;D2点亮为调节月;D3点亮为调节日;D4点亮为调节兴趣;D5点亮为调节时;D6点亮为调节分;D7点亮为调节秒;全灭的时候为读取时间模式。
一、实验名称:基于DS1302的万年历LCD1602显示
二、实验目的:通过DS1302通信读取时间;按键校时;并显示在LCD1602上。
三、设计的思路:按功能要求划分四大模块:按键模块、DS1302驱动、2选1选择器、LCD1602显示模块。如下框图所示:
1、按键模块:校时数据输入。一个有三个键:S1功能键;S2计数加键;S3计数减键。调用了按键例化模块(前面更新的)
。
S1按键计数八种状态,分别为0)不校时、1)校对年、2)校对月、3)校对日、4)校对星期、5)校对时、6)校对分、7)校对秒。8个状态轮回一次则说明校时完毕,把校时的数据传递给DS1302驱动同时控制2选1选择器让LCD1602显示的是DS1302读出来的数据。
S2按键对以上的1~7种状态进行计数加处理。
S3按键对以上的1~7种状态进行计数加处理。
2、DS1302驱动:负责DS1302的读写控制,要求上电的时候数据不复位。
3、2选1选择器:这个是个下下选择,希望以后改进能把它去掉。在这里的作用是:校时的时候显示校时的时间数据;不校时的时候显示DS1302读出来的实时时间。
4、LCD1602显示:显示数据用的,具体的不细说了,前面已经在例化里介绍过。
四、相关代码:
1、顶层代码:
module ds1302_lcd(clk,rst,lcd_en,lcd_rs,lcd_rw,lcd_data,key_in,Led_Out,SCLK,SCE,SIO);
input clk;
input rst;
input[2:0] key_in;
output lcd_en;
output lcd_rs;
output lcd_rw;
output[7:0] lcd_data;
output[6:0] Led_Out;
output SCLK;
output SCE;
inout SIO;
wire[23:0] TimeData;
wire[31:0] DateData;
wire[23:0] TimeData1;
wire[31:0] DateData1;
wire[23:0] TimeData2;
wire[31:0] DateData2;
wire Mode_flag;
wire chanle;
key_mode Key
(
.clk(clk),
.rst(rst),
.key_in(key_in),
.TimeData2Ds(TimeData2),
.DateData2Ds(DateData2),
.Mode_flag(Mode_flag),
.Led_Out(Led_Out),
.chanle_out(chanle)
);
ds1302_drive DS1302
(
.clk(clk),
.rst(rst),
.srst(SCE),
.sclk(SCLK),
.sdata(SIO),
.TimeData(TimeData1),
.DateData(DateData1),
.TimeData_in(TimeData2),
.DateData_in(DateData2),
.WRTime_flag(Mode_flag)
);
TwoChanleToOne Two2One
(
.clk(clk),
.chanle_in(chanle),
.TimeData1(TimeData1),
.DateData1(DateData1),
.TimeData2(TimeData2),
.DateData2(DateData2),
.TimeDataToDs(TimeData),
.DateDataToDs(DateData)
);
lcd1602_driver LCD
(
.clk(clk),
.rst_n(rst),
.Disp_data1(TimeData),
.Disp_data2(DateData),
.lcd_en(lcd_en), // lcd enable
.lcd_rs(lcd_rs), // record,statement
.lcd_rw(lcd_rw),
.lcd_data(lcd_data)
);
endmodule
2、按键模块代码:
module key_mode(clk,rst,key_in,TimeData2Ds,DateData2Ds);
input clk;
input rst;
input[2:0] key_in;
output[23:0] TimeData2Ds;
output[31:0] DateData2Ds;
output Mode_flag;
wire key_flag;
wire[2:0] key_value;
key_interface key_inter
(
.clk(clk),
.rst(rst),
.key_trigger(key_in), //按键输入端口
.key_flag(key_flag), //按键标识
.key_value(key_value) //按键数值输出
);
reg[3:0] addr_seg_r = 4'b0;
reg[7:0] Year = 8'b0;
reg[7:0] Mont = 8'b0;
reg[7:0] Day = 8'b0;
reg[7:0] Week = 8'b0;
reg[7:0] Hour = 8'b0;
reg[7:0] Min = 8'b0;
reg[7:0] Sec = 8'b0;
always @(posedge key_flag) begin
case(key_value)
3'b001 : begin
if(addr_seg_r >= 3'd13)
begin
addr_seg_r <= 3'd0;
Mode_flag <= 1'b1;
end
else
begin
addr_seg_r <= addr_seg_r + 1'b1;
Mode_flag <= 1'b0;
end
end
3'b010 : begin
case(addr_seg_r)
3'd0 : begin
if(Year >= 8'd99)
Year <= 8'd0;
else
Year <= Year + 1'b1;
end
3'd1 : begin
if(Mont >= 8'd12)
Mont <= 8'd0;
else
Mont <= Mont + 1'b1;
end
3'd2 : begin
case(Mont)
8'd1,8'd3,8'd5,8'd7,8'd8,8'd10,8'd12: //31Day
begin
if(Day >= 8'd31)
Day <= 8'd1;
else
Day <= Day + 1'b1;
end
8'd2 : //28/29Day
begin
if(Year%4 == 8'd0)
begin
if(Day >= 8'd29)
Day <= 8'd1;
else
Day <= Day + 1'b1;
end
else
begin
if(Day >= 8'd28)
Day <= 8'd1;
else
Day <= Day + 1'b1;
end
end
8'd4,8'd6,8'd9,8'd11: //30Day
begin
if(Day >= 8'd30)
Day <= 8'd1;
else
Day <= Day + 1'b1;
end
endcase
end
3'd3 : begin
if(Hour >= 8'd23)
Hour <= 8'd0;
else
Hour <= Hour + 1'b1;
end
3'd5 : begin
if(Min >= 8'd59)
Min <= 8'd0;
else
Min <= Min + 1'b1;
end
3'd6 : begin
if(Sec >= 8'd59)
Sec <= 8'd0;
else
Sec <= Sec + 1'b1;
end
3'd7 : begin
if(Week >= 8'd7)
Week <= 8'd1;
else
Week <= Week + 1'b1;
end
default :;
endcase
end
3'b100 : begin
case(addr_seg_r)
3'd0 : begin
if(Year == 8'd0)
Year <= 8'd99;
else
Year <= Year - 1'b1;
end
3'd1 : begin
if(Mont == 8'd0)
Mont <= 8'd12;
else
Mont <= Mont - 1'b1;
end
3'd2 : begin
case(Mont)
8'd1,8'd3,8'd5,8'd7,8'd8,8'd10,8'd12: //31Day
begin
if(Day == 8'd1)
Day <= 8'd31;
else
Day <= Day - 1'b1;
end
8'd2 : //28/29Day
begin
if(Year%4 == 8'd0)
begin
if(Day == 8'd1)
Day <= 8'd29;
else
Day <= Day - 1'b1;
end
else
begin
if(Day == 8'd1)
Day <= 8'd28;
else
Day <= Day - 1'b1;
end
end
8'd4,8'd6,8'd9,8'd11: //30Day
begin
if(Day == 8'd1)
Day <= 8'd30;
else
Day <= Day - 1'b1;
end
endcase
end
3'd3 : begin
if(Hour == 8'd0)
Hour <= 8'd23;
else
Hour <= Hour - 1'b1;
end
3'd5 : begin
if(Min == 8'd0)
Min <= 8'd59;
else
Min <= Min - 1'b1;
end
3'd6 : begin
if(Sec == 8'd0)
Sec <= 8'd59;
else
Sec <= Sec - 1'b1;
end
3'd7 : begin
if(Week == 8'd1)
Week <= 8'd7;
else
Week <= Week - 1'b1;
end
default :;
endcase
end
default : ;
endcase
end
always @(posedge key_flag) begin
TimeData2Ds[3:0] <= Sec%10;
TimeData2Ds[7:4] <= Sec/10;
TimeData2Ds[11:8] <= Min%10;
TimeData2Ds[15:12]<= Min/10;
TimeData2Ds[19:16]<= Hour%10;
TimeData2Ds[23:20]<= Hour/10;
DateData2Ds[7:0] <= Week;
DateData2Ds[11:8] <= Day%10;
DateData2Ds[15:12]<= Day/10;
DateData2Ds[19:16]<= Mont%10;
DateData2Ds[23:20]<= Mont/10;
DateData2Ds[27:24]<= Year%10;
DateData2Ds[31:28]<= Year/10;
end
reg Mode_flag_r1,Mode_flag_r0;
always @(posedge clk or negedge rst) begin
if(!rst)
begin
Mode_flag_r0 <= 1'b0;
Mode_flag_r1 <= 1'b0;
end
else
begin
Mode_flag_r0 <= Mode_flag_r;
Mode_flag_r1 <= Mode_flag_r0;
end
end
assign Mode_flag = (!Mode_flag_r1) & Mode_flag_r0;
endmodule
3、DS1302驱动的最终代码:
module ds1302_drive(clk,rst,srst,sclk,sdata,TimeData,DateData,TimeData_in,DateData_in,WRTime_flag);
input rst; //外部复位
input clk; //输入时钟
input[23:0] TimeData_in;
input[31:0] DateData_in;
input WRTime_flag;
output srst; //ds1302复位
output sclk; //ds1302时钟
inout sdata; //ds1302数据
output[23:0] TimeData; //时间数据
output[31:0] DateData; //日历数据
// output clk_out;
reg data; //sdata的缓存,
reg isOut; //因为sdata是双向口,所以需要一个标志位isOut来管理数据的输入和输出
assign sdata=(isOut)? data:1'bz; //isOut:1:允许输出;0:是高阻,输入
parameter
IDLE = 4'd0,
WR_Sec = 4'd1,
WR_Min = 4'd2,
WR_Hour = 4'd3,
WR_Week = 4'd4,
WR_Day = 4'd5,
WR_Mont = 4'd6,
WR_Year = 4'd7;
parameter
RD_Sec = 4'd8,
RD_Min = 4'd9,
RD_Hour = 4'd10,
RD_Week = 4'd11,
RD_Day = 4'd12,
RD_Mont = 4'd13,
RD_Year = 4'd14,
CLOSE_W = 4'd15;
parameter
WR_state_0 = 5'd0,
WR_state_1 = 5'd1,
WR_state_2 = 5'd2,
WR_state_3 = 5'd3,
WR_state_4 = 5'd4,
WR_state_5 = 5'd5,
WR_state_6 = 5'd6,
WR_state_7 = 5'd7,
WR_state_8 = 5'd8,
WR_state_9 = 5'd9,
WR_state_a = 5'd10,
WR_state_b = 5'd11,
WR_state_c = 5'd12,
WR_state_d = 5'd13,
WR_state_e = 5'd14,
WR_state_f = 5'd15,
WR_state_10 = 5'd16;
parameter
RD_state_0 = 5'd0,
RD_state_1 = 5'd1,
RD_state_2 = 5'd2,
RD_state_3 = 5'd3,
RD_state_4 = 5'd4,
RD_state_5 = 5'd5,
RD_state_6 = 5'd6,
RD_state_7 = 5'd7,
RD_state_8 = 5'd8,
RD_state_9 = 5'd9,
RD_state_a = 5'd10,
RD_state_b = 5'd11,
RD_state_c = 5'd12,
RD_state_d = 5'd13,
RD_state_e = 5'd14,
RD_state_f = 5'd15,
RD_state_10 = 5'd16;
reg[7:0]counter;
wire clk_sta; //状态机的时钟8us/period
always@(posedge clk ) begin //or negedge rst) begin
if(counter <= 8'd100)
counter <= counter + 1'b1;
else
begin
counter <= 8'b0;
end
end
assign clk_sta = counter == 8'd100;
reg sclk_r;//ds1302的工作时钟
always @ (posedge clk_sta) begin
if(!srst_r)
sclk_r <= 1'b0;
else
sclk_r<=~sclk_r;
end
assign sclk=sclk_r;
always@ (posedge clk) begin
SEC[7:0] <= TimeData_in[7:0];
MIN[7:0] <= TimeData_in[15:8];
HOU[7:0] <= TimeData_in[23:16];
Week[7:0]<= DateData_in[7:0];
DAY[7:0] <= DateData_in[15:8];
Month[7:0]<= DateData_in[23:16];
Year[7:0]<= DateData_in[31:24];
end
reg Rest_flag; //重新设置标志位
reg [4:0]WR_state; //WR_SET的状态
reg [4:0]RD_state; //RD_T任务的状态
reg [23:0] TimeData_r;
reg [31:0] DateData_r;
reg RD_flag; //写任务的标志
reg WR_flag; //读任务标志
reg [7:0]CMD = 8'h00; //command
reg [7:0]SEC = 8'h50; //时间/日历
reg [7:0]MIN = 8'h59; //分钟
reg [7:0]HOU = 8'h23; //小时
reg [7:0]DAY = 8'h31; //天
reg [7:0]Month = 8'h12; //月
reg [7:0]Week = 8'h04; //星期
reg [7:0]Year = 8'h12; //年
reg [7:0]register1; //command
reg [7:0]register2;
reg [7:0]register3; //读进数据寄存器
reg [3:0]state; //状态机
reg srst_r;
always @(posedge clk ) begin
if(WRTime_flag)
begin
//初始化操作时,isOut<=0;所以输出呈现高阻态
srst_r <= 1'b0;
data <= 1'b0; //输出缓存器被清空
WR_flag <= 1'b0; //WR_SET任务的标志位
RD_flag <= 1'b0; //RD_T任务标志位
state <= IDLE;
isOut <= 1'b0;
register1 <= 8'b10001110; //关闭写保护
TimeData_r <= 24'b0;
DateData_r <= 32'b0;
Rest_flag <= 1'b1;
WR_state <= 1'b0;
RD_state <= 1'b0;
end
else if(clk_sta)
begin
case(state)
//IDLE状态选择工作状态还是初始设置状态
IDLE : begin
//Rest_flag==1时,重新设置数据
if(Rest_flag == 1'b1)
begin
if(WR_flag == 1'b0)
begin
WR_SET(CMD);
state <= IDLE;
end
else
begin
Rest_flag <= 1'b0;
srst_r <= 1'b0;
isOut <= 1'b0;
WR_flag <= 1'b0;
register1 <= 8'b1000_0000;////写时钟/日历寄存器
state <= WR_Sec;
end
end
else if(Rest_flag == 1'b0)
begin
register3 <= 8'b1000_0001;
isOut <= 1'b0;
srst_r <= 1'b0;
RD_flag <= 1'b0;
state <= RD_Sec;
end
else state <= IDLE;
end
WR_Sec : begin
if(WR_flag == 1'b0) WR_SET(SEC);//写秒
else
begin
state <= WR_Min;
isOut <= 1'b0;
WR_flag <= 1'b0;
register1 <= 8'b1000_0010;
end
end
WR_Min : begin
if(WR_flag == 1'b0) WR_SET(MIN);
else
begin
state <= WR_Hour;
isOut <= 1'b0;
WR_flag <= 1'b0;
register1 <= 8'b1000_0100;
end
end
WR_Hour : begin
if(WR_flag == 1'b0) WR_SET(HOU);
else
begin
state <= WR_Week;
isOut <= 1'b0;
WR_flag <= 1'b0;
register1 <= 8'b1000_1010;
end
end
WR_Week : begin
if(WR_flag == 1'b0) WR_SET(Week);
else
begin
state <= WR_Day;
isOut <= 1'b0;
WR_flag <= 1'b0;
register1 <= 8'b1000_0110;
end
end
WR_Day : begin
if(WR_flag == 1'b0) WR_SET(DAY);
else
begin
state <= WR_Mont;
isOut <= 1'b0;
WR_flag <= 1'b0;
register1 <= 8'b1000_1000;
end
end
WR_Mont : begin
if(WR_flag == 1'b0) WR_SET(Month);
else
begin
state <= WR_Year;
isOut <= 1'b0;
WR_flag <= 1'b0;
register1 <= 8'b1000_1100;
end
end
WR_Year : begin
if(WR_flag == 1'b0) WR_SET(Year);
else
begin
state <= CLOSE_W;
isOut <= 1'b0;
WR_flag <= 1'b0;
register1 <= 8'b10001110;
end
end
RD_Sec : begin
if(RD_flag == 1'b0) RD_T;
else
begin
TimeData_r[7:0] <= register2;
srst_r <= 1'b0;
RD_flag <= 1'b0;
register3 <= 8'b1000_0011;
state <= RD_Min;
end
end
RD_Min : begin
if(RD_flag == 1'b0) RD_T;
else
begin
TimeData_r[15:8] <= register2;
srst_r <= 1'b0;
RD_flag <= 1'b0;
register3 <= 8'b1000_0101;
state <= RD_Hour;
end
end
RD_Hour : begin
if(RD_flag == 1'b0) RD_T;
else
begin
TimeData_r[23:16] <= register2;
srst_r <= 1'b0;
RD_flag <= 1'b0;
register3 <= 8'b1000_1011;
state <= RD_Week;
end
end
RD_Week : begin
if(RD_flag == 1'b0) RD_T;
else
begin
DateData_r[7:0] <= register2;
srst_r <= 1'b0;
RD_flag <= 1'b0;
register3 <= 8'b1000_0111;
state <= RD_Day;
end
end
RD_Day : begin
if(RD_flag == 1'b0) RD_T;
else
begin
DateData_r[15:8] <= register2;
srst_r <= 1'b0;
RD_flag <= 1'b0;
register3 <= 8'b1000_1001;
state <= RD_Mont;
end
end
RD_Mont : begin
if(RD_flag == 1'b0) RD_T;
else
begin
DateData_r[23:16] <= register2;
srst_r <= 1'b0;
RD_flag <= 1'b0;
register3 <= 8'b1000_1101;
state <= RD_Year;
end
end
RD_Year : begin
if(RD_flag == 1'b0) RD_T;
else
begin
DateData_r[31:24] <= register2;
srst_r <= 1'b0;
RD_flag <= 1'b0;
register3 <= 8'b1000_0001;
state <= RD_Sec;
// RD_flaglag_initial<=0;
end
end
CLOSE_W : begin
if(WR_flag == 1'b0) WR_SET(8'h10);
else
begin
state <= IDLE;
isOut <= 1'b0;
WR_flag <= 1'b0;
RD_flag <= 1'b0;
Rest_flag <= 1'b0;
end
end
default : begin
Rest_flag <= 1'b0;
srst_r <= 1'b0;
data <= 1'b0;
WR_flag <= 1'b0;
RD_flag <= 1'b0;
state <= RD_Sec;
register2 <= 1'b0;//接受数据的寄存器
register3 <= 8'b1000_0001;//读任务的指令寄存器
CMD <= 8'b0;
end
endcase
end
end
task RD_T;
begin
case(RD_state)
RD_state_0 : begin
if(!sclk_r)
begin
isOut <= 1'b1;
srst_r <= 1'b1;
data <= register3[0];
RD_state <= RD_state_1;
end
else
begin
srst_r <= 1'b0;
RD_state <= RD_state_0;
data <= register3[0];
isOut <= 1'b1;
end
end
RD_state_1 : begin
if(!sclk_r)
begin
data <= register3[1];
RD_state <= RD_state_2;
end
else
begin
data <= data;
RD_state <= RD_state;
end
end
RD_state_2 : begin
if(!sclk_r)
begin
data <= register3[2];
RD_state <= RD_state_3;
end
else
begin
data <= data;
RD_state <= RD_state;
end
end
RD_state_3 : begin
if(!sclk_r)
begin
data <= register3[3];
RD_state <= RD_state_4;
end
else
begin
data <= data;
RD_state <= RD_state;
end
end
RD_state_4 : begin
if(!sclk_r)
begin
data <= register3[4];
RD_state <= RD_state_5;
end
else
begin
data <= data;
RD_state <= RD_state;
end
end
RD_state_5 : begin
if(!sclk_r)
begin
data <= register3[5];
RD_state <= RD_state_6;
end
else
begin
data <= data;
RD_state <= RD_state;
end
end
RD_state_6 : begin
if(!sclk_r)
begin
data <= register3[6];
RD_state <= RD_state_7;
end
else
begin
data <= data;
RD_state <= RD_state;
end
end
RD_state_7 : begin
if(!sclk_r)
begin
data <= register3[7];
RD_state <= RD_state_8;
end
else
begin
data <= data;
RD_state <= RD_state;
end
end
RD_state_8 : begin
if(!sclk_r)
begin
isOut <= 1'b0;
RD_state <= RD_state_9;
end
else
RD_state <= RD_state;
end
RD_state_9 : begin
if(!sclk_r) RD_state <= RD_state_a;
else RD_state <= RD_state;
end
RD_state_a : begin
if(!sclk_r) RD_state <= RD_state_b;
else RD_state <= RD_state;
end
RD_state_b : begin
if(!sclk_r) RD_state <= RD_state_c;
else RD_state <= RD_state;
end
RD_state_c : begin
if(!sclk_r) RD_state <= RD_state_d;
else RD_state <= RD_state;
end
RD_state_d : begin
if(!sclk_r) RD_state <= RD_state_e;
else RD_state <= RD_state;
end
RD_state_e : begin
if(!sclk_r) RD_state <= RD_state_f;
else RD_state <= RD_state;
end
RD_state_f : begin
if(!sclk_r) RD_state <= RD_state_10;
else RD_state <= RD_state_f;
end
RD_state_10 : begin
if(!sclk_r)
begin
RD_flag <= 1'b1;
srst_r <= 1'b0;
RD_state <= RD_state_0;//do not run
end
else
begin
RD_flag <= 1'b1;
srst_r <= 1'b0;
RD_state <= RD_state_0;
end
end
default : begin
RD_state <= RD_state_0;
end
endcase
end
endtask
always @( posedge sclk_r or negedge rst) begin
if(!rst)
register2<= 8'b0;
else
begin
case(RD_state)
RD_state_9 : register2[0] <= sdata;
RD_state_a : register2[1] <= sdata;
RD_state_b : register2[2] <= sdata;
RD_state_c : register2[3] <= sdata;
RD_state_d : register2[4] <= sdata;
RD_state_e : register2[5] <= sdata;
RD_state_f : register2[6] <= sdata;
RD_state_10 : register2[7] <= sdata;
default : register2 <= register2;
endcase
end
end
task WR_SET;
input [7:0]reg_store;
begin
case(WR_state)
WR_state_0 : begin
if(!sclk_r)
begin
isOut <= 1'b1;
srst_r <= 1'b1;//低电平时才可以将srst_r拉高
data <= register1[0];
WR_state <= WR_state_1;
end
else
begin
srst_r <= 1'b0;
WR_state <= 1'b0;
data <= register1[0];
isOut <= 1'b0;
end
end
WR_state_1 : begin
if(!sclk_r)
begin
isOut <= 1'b1;
data <= register1[1];
WR_state <= WR_state_2;
end
else
WR_state <= WR_state;
end
WR_state_2 : begin
if(!sclk_r)
begin
isOut <= 1'b1;
data <= register1[2];
WR_state <= WR_state_3;
end
else
WR_state <= WR_state;
end
WR_state_3 : begin
if(!sclk_r)
begin
data <= register1[3];
WR_state <= WR_state_4;
end
else
WR_state <= WR_state;
end
WR_state_4 : begin
if(!sclk_r)
begin
data <= register1[4];
WR_state <= WR_state_5;
end
else
WR_state <= WR_state;
end
WR_state_5 : begin
if(!sclk_r)
begin
data <= register1[5];
WR_state <= WR_state_6;
end
else
WR_state <= WR_state;
end
WR_state_6 : begin
if(!sclk_r)
begin
data <= register1[6];
WR_state <= WR_state_7;
end
else
WR_state <= WR_state;
end
WR_state_7 : begin
if(!sclk_r)
begin
data <= register1[7];
WR_state <= WR_state_8;
end
else
WR_state <= WR_state;
end
WR_state_8 : begin
if(!sclk_r)
begin
data <= reg_store[0];
WR_state <= WR_state_9;
end
else
WR_state <= WR_state;
end
WR_state_9 : begin
if(!sclk_r)
begin
srst_r <= 1'b1;
data <= reg_store[1];
WR_state <= WR_state_a;
end
else
WR_state <= WR_state;
end
WR_state_a : begin
if(!sclk_r)
begin
data <= reg_store[2];
WR_state <= WR_state_b;
end
else
WR_state <= WR_state;
end
WR_state_b : begin
if(!sclk_r)
begin
data <= reg_store[3];
WR_state <= WR_state_c;
end
else
WR_state <= WR_state;
end
WR_state_c : begin
if(!sclk_r)
begin
data <= reg_store[4];
WR_state <= WR_state_d;
end
else
WR_state <= WR_state;
end
WR_state_d : begin
if(!sclk_r)
begin
data <= reg_store[5];
WR_state <= WR_state_e;
end
else
WR_state <= WR_state;
end
WR_state_e : begin
if(!sclk_r)
begin
data <= reg_store[6];
WR_state <= WR_state_f;
end
else
WR_state <= WR_state;
end
WR_state_f : begin
if(!sclk_r)
begin
data <= reg_store[7];
WR_state <= WR_state_10;
end
else
WR_state <= WR_state;
end
WR_state_10 : begin
if(!sclk_r)
begin
WR_state <= WR_state_0;
WR_flag <= 1'b1;
srst_r <= 1'b0;
end
else
WR_state <= WR_state;
end
default : WR_state <= WR_state_0;
endcase
end
endtask
assign TimeData = TimeData_r;
assign DateData = DateData_r;
assign srst = srst_r;
endmodule
五、实验效果:1、解决了上电时间复位的问题;2、加上了LED校时指示,至于其他bug肯定是有的,但还待发现。
下面是今天晚上照的实际效果,视频今晚刚刚给老王发过去,他们明天不上班,所以得等等了。
更新过后的sof,pof(我用的时钟输入引脚是129,大伙注意一下)
文件下载:
http://share.eepw.com.cn/share/download/id/83600
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
【换取逻辑分析仪】-基于ADI单片机MAX78000的简易MP3音乐播放器被打赏48分 | |
我想要一部加热台+树莓派PICO驱动AHT10被打赏38分 | |
【换取逻辑分析仪】-硬件SPI驱动OLED屏幕被打赏36分 | |
换逻辑分析仪+上下拉与多路选择器被打赏29分 | |
Let'sdo第3期任务合集被打赏50分 | |
换逻辑分析仪+Verilog三态门被打赏27分 | |
换逻辑分析仪+Verilog多输出门被打赏24分 | |
【分享评测,赢取加热台】使用8051单片机驱动WS2812被打赏40分 | |
【换取逻辑分析仪】rtthread添加RRH62000传感器驱动-基于野火启明6M5被打赏48分 | |
换逻辑分析仪+Verilog多输入门被打赏27分 |