赞
踩
使用型号为DS1302的实时时钟芯片完成日期、时间的实时显示。(通过UART发送至上位机显示)。
(1) 内含一个钮电池,断电情况下运行 10 年以上不丢失数据。
(2) 可计秒、 分、 时、 星期、 日、 月、 年,并有闰年补偿功能,有效年份 为 2100 年以前。
(3) 可选二进制码或 BCD 码表示时间、日历,具有闹钟定时功能。
(4) 可选 12 小时或 24 小时制,12 小时时钟模式带有 PM 和 AM 指示,有夏令时功能。
DS1302 的控制字符表示。控制字节的最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入DS1302中,位6如果为0,则表示存取日历时钟数据,为1表示存取RAM数据;位5至位1指示操作单元的地址;最低有效位(位0)如为0表示要进行写操作,为1表示进行读操作,控制字节总是从最低位开始输出
在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。
DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据位为BCD码形式,其日历、时间寄存器及其控制字。
第一个寄存器读写地址分别为0x81和0x80,其最高位CH用来判断系统上一次掉电后时钟是否仍然在正常工作,为1则系统掉电后备用电源没电或其他原因导致的时钟部分未正常工作,为0则掉电后DS1302正常使用备用电源。第六位至第四位表示的是秒数的十位数,最后四位则表示秒数的个位数,表示范围0~59。
第二个寄存器读写地址分别为0x83和0x82,最高位保留,后面七位同第一个寄存器一致,但表示结果是分数。
第三个寄存器读写地址分别为0x85和0x84,最高位为1表示使用12小时制,当选择12小时制时,第五位为0表示AM,为1表示PM,最高位为0时使用24小时制,第五位和第四位一块表示小时的十位数,最后四位则表示小时的个位数。
第四个寄存器读写地址分别为0x87和0x86,第五位和第四位表示日数的十位数,后四位表示日数的个位数。
第五个寄存器读写地址分别为0x89和0x88,第四位表示月份的十位数,后四位表示月份的个位数。
第六个寄存器读写地址分别为0x8B和0x8A,后三位表示星期几。
第七个寄存器读写地址分别为0x8D和0x8C,前四位表示年份的十位数,后四位表示年份的个位数,这里的0~99表示范围2000~2099。
这七个寄存器的数据需要同时读出,才能确保所读数据的准确性。举个不同时读取的例子,读秒数是59,分钟数是0,当下一次读分钟时,分钟变成了1,读出的时间可能是01:59,而实际时间却是00:59,显然是不正确的。为此,DS1302提供了一个burst模式一次性读出这七个寄存器的所有数据。burst模式读写地址分别为0xBF和0xBE,DS1302收到这两个指令后,将时间信息一并存入缓存器,从而保证了时间信息的准确性。
DS1302实时时钟芯片,一旦初始化后,它就会随着现实的时钟一直计数。
下图是 DS1302 芯片写操作的时序图。第一个字节是“访问寄存器的地址”,第二字节是“写数据”。在写操作的时候,都是“上升沿有效”,然而还有一个条件,就是 CE(/RST)信号必须拉高。(数据都是从 LSB 开始发送,亦即是最低位开始至最高位结束)。
需要注意的是在突发模式下,ce保持高,发送额外的扫描周期,直到突发结束。
下图是DS1302芯片读操作的时序图。基本上和写操作的时序图大同小异,区别的地方就是在第二个字节时“读数据”的动作。第二字节读数据开始时, SCLK 信号都是“下降沿有效”。嗯,别忘了 CE(/RST)信号同样是必须拉高。(第一节数据是从 LSB 开始输出,第二节数据是从 LSB 开始读入)。
DS1302 最高速率为 2Mhz 并且无下限, 50Mhz 的量化结果为 25。时钟信号拉高 TCH 或拉低 TCL至少需要保持 250ns,量化结果为 12.5。至于时钟信号上升时间 TR 或者下降时间 TF 最大时间为500ns,极端说是最小时间是 0ns。
1.系统框图
2.模块端口信号列表
3.状态图
- /**************************************功能介绍***********************************
- Date : 2023年10月16日19:16:20
- Author : Xlin.
- Version : 1.0
- Description: ds1302接口设计
- *********************************************************************************/
- //---------<模块及端口声名>------------------------------------------------------
- module ds1302_if(
- input clk ,
- input rst_n ,
- output reg [7:0] tx_data ,//输出数据
- output tx_vld ,//输出数据有效
- output done ,//读完一次时间
- //ds1302接口
- output sclk,
- inout io ,
- output ce
- );
- //---------<参数定义>---------------------------------------------------------
- parameter TIME_1S = 50_000_000,
- CYCLE = 50 ;
- //---------<内部信号定义>-----------------------------------------------------
- //DS1302 寄存器地址定义
- parameter SEC_RD = 8'h81,
- MIN_RD = 8'h83,
- HOUR_RD = 8'h85,
- DATA_RD = 8'h87,
- MON_RD = 8'h89,
- DAY_RD = 8'h8b,
- YEAR_RD = 8'h8d,
- WP_RD = 8'h8f;
-
- parameter SEC_WR = 8'h80,
- MIN_WR = 8'h82,
- HOUR_WR = 8'h84,
- DATA_WR = 8'h86,
- MON_WR = 8'h88,
- DAY_WR = 8'h8a,
- YEAR_WR = 8'h8c;
- //初始时间定义 23年10月15日 星期日 15:30:00
- parameter YEAR = 8'h23,//年
- MON = 8'h10,//月
- DATA = 8'h15,//日
- DAY = 8'h07,//星期
- HOUR = 8'h15,//小时
- MIN = 8'h30,//分
- SEC = 8'h00;//秒
-
- parameter BIT_MAX = 8 ;
- //状态机参数定义
- localparam IDLE = 'b0001,
- WRITE = 'b0010,
- READ = 'b0100,
- DONE = 'b1000;
-
- reg [3:0] state_c ;//现态
- reg [3:0] state_n ;//次态
- //状态机转移条件定义
- wire idle2write ;
- wire write2read ;
- wire write2done ;
- wire read2done ;
- wire done2idle ;
- //写信号
- reg write_flag ;
- //初始化完成
- reg start_flag ;
- //8bit计数器
- reg [2:0] cnt_bit ;
- wire add_cnt_bit ;
- wire end_cnt_bit ;
- //写字节计数器
- reg [2:0] cnt_byte ;
- wire add_cnt_byte ;
- wire end_cnt_byte ;
- //指令计数器
- reg [2:0] cnt_done ;
- reg [2:0] max ;
- wire add_cnt_done ;
- wire end_cnt_done ;
- //1s计数器
- reg [26:0] cnt_sec ;
- wire add_cnt_sec ;
- wire end_cnt_sec ;
- //周期计数器
- reg [5:0] cnt_cyc ;
- wire add_cnt_cyc ;
- wire end_cnt_cyc ;
- //三太门控制
- wire data_in ;
- reg data_out ;
- wire data_en ;
- //第一段:时序逻辑描述状态转移
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- state_c <= state_n;
- end
- else begin
- state_c <= state_n;
- end
- end
-
- //第二段:组合逻辑描述状态转移规律和状态转移条件
- always @(*) begin
- case(state_c)
- IDLE : if(idle2write)
- state_n = WRITE;
- else
- state_n = state_c;
- WRITE : if(write2read)
- state_n = READ ;
- else if(write2done)
- state_n = DONE;
- else
- state_n = state_c;
- READ : if(read2done )
- state_n = DONE ;
- else
- state_n = state_c;
- DONE : if(done2idle )
- state_n = IDLE ;
- else
- state_n = state_c;
- default : state_n = IDLE ;
- endcase
- end
- assign idle2write = state_c == IDLE && write_flag;//初始化信号,完成拉低
- assign write2read = state_c == WRITE && end_cnt_bit && start_flag;//写地址写完
- assign write2done = state_c == WRITE && end_cnt_byte&&~start_flag;//写的包括地址 和初始时间
- assign read2done = state_c == READ && end_cnt_bit;//读地址写完
- assign done2idle = state_c == DONE && 1'b1;
- //****************************************************************
- //-- 写信号 和 初始化完成信号
- //****************************************************************
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- write_flag<= 'd1;
- end
- else if(state_c==READ && end_cnt_done)begin
- write_flag<='d0;
- end
- else if(end_cnt_sec)//1s结束有开始读取时间
- write_flag<='d1;
- end
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- start_flag<= 'd0;
- end
- else if(done2idle)begin //初始化完成拉低
- start_flag<='d1;
- end
- end
- //****************************************************************
- //-- 计数器
- //****************************************************************
- //1s计数器
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- cnt_sec <= 'd0;
- end
- else if(add_cnt_sec)begin
- if(end_cnt_sec)begin
- cnt_sec <= 'd0;
- end
- else begin
- cnt_sec <= cnt_sec + 1'b1;
- end
- end
- end
-
- assign add_cnt_sec = 1;
- assign end_cnt_sec = add_cnt_sec && cnt_sec == TIME_1S-1;
- //bit计数器
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- cnt_bit <= 'd0;
- end
- else if(add_cnt_bit)begin
- if(end_cnt_bit)begin
- cnt_bit <= 'd0;
- end
- else begin
- cnt_bit <= cnt_bit + 1'b1;
- end
- end
- end
-
- assign add_cnt_bit = end_cnt_cyc;
- assign end_cnt_bit = add_cnt_bit && cnt_bit == BIT_MAX -1;
- //写字节计数器 写的地址加数据
- //字节计数 共计16bit
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- cnt_byte <= 'd0;
- end
- else if(add_cnt_byte)begin
- if(end_cnt_byte)begin
- cnt_byte <= 'd0;
- end
- else begin
- cnt_byte <= cnt_byte + 1'b1;
- end
- end
- end
-
- assign add_cnt_byte = end_cnt_bit;
- assign end_cnt_byte = add_cnt_byte && cnt_byte == 1;
- //指令个数计数
- //地址计数
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- cnt_done <= 'd0;
- end
- else if(add_cnt_done)begin
- if(end_cnt_done)begin
- cnt_done <= 'd0;
- end
- else begin
- cnt_done <= cnt_done + 1'b1;
- end
- end
- end
-
- assign add_cnt_done = read2done || write2done;
- assign end_cnt_done = add_cnt_done && cnt_done == max;
-
- assign done = read2done;
-
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- max <= 'd0;
- end
- else if(start_flag)begin
- max <= 'd6;
- end
- else begin
- max <= 'd7;
- end
- end
- //****************************************************************
- //-- ds1302 片选 时钟 数据设计
- //****************************************************************
- //片选信号 读数据 写数据拉高
- assign ce=(state_c==READ || state_c==WRITE);
- //时钟sclk
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- cnt_cyc <= 'd0;
- end
- else if(add_cnt_cyc)begin
- if(end_cnt_cyc)begin
- cnt_cyc <= 'd0;
- end
- else begin
- cnt_cyc <= cnt_cyc + 1'b1;
- end
- end
- end
-
- assign add_cnt_cyc = (state_c == WRITE) || (state_c == READ);
- assign end_cnt_cyc = add_cnt_cyc && cnt_cyc == CYCLE-1;
-
- assign sclk = cnt_cyc < (CYCLE>>1) ? 0 : 1;
- //三态门控制数据 io口
- assign data_in = io;
- assign io = data_en ? data_out : 1'bz;
- assign data_en = state_c == WRITE;
- //第三段:描述输出,时序逻辑或组合逻辑皆可
- //****************************************************************
- //-- 数据输出
- //****************************************************************
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- data_out <= 'd0;
- end
- else if(state_c == WRITE && cnt_cyc == 0 && ~start_flag)begin //写数据+地址 只有在初始化的时候才需要写入数据
- case (cnt_done)
- 0: begin
- case (cnt_byte)
- 0: data_out <= WP_RD[cnt_bit];//地址
- 1: data_out <= 1'b0;//数据
- default: data_out <= 'd0;
- endcase
- end
- 1: begin
- case (cnt_byte)
- 0: data_out <= YEAR_WR[cnt_bit];
- 1: data_out <= YEAR[cnt_bit];//初始年份
- default: data_out <= 'd0;
- endcase
- end
- 2: begin
- case (cnt_byte)
- 0: data_out <= MON_WR[cnt_bit];
- 1: data_out <= MON[cnt_bit];//初始月份
- default: data_out <= 'd0;
- endcase
- end
- 3: begin
- case (cnt_byte)
- 0: data_out <= DATA_WR[cnt_bit];
- 1: data_out <= DATA[cnt_bit];//初始日
- default: data_out <= 'd0;
- endcase
- end
- 4: begin
- case (cnt_byte)
- 0: data_out <= DAY_WR[cnt_bit];
- 1: data_out <= DAY[cnt_bit];//初始星期
- default: data_out <= 'd0;
- endcase
- end
- 5: begin
- case (cnt_byte)
- 0: data_out <= HOUR_WR[cnt_bit];
- 1: data_out <= HOUR[cnt_bit];
- default: data_out <= 'd0;
- endcase
- end
- 6: begin
- case (cnt_byte)
- 0: data_out <= MIN_WR[cnt_bit];
- 1: data_out <= MIN[cnt_bit];
- default: data_out <= 'd0;
- endcase
- end
- 7: begin
- case (cnt_byte)
- 0: data_out <= SEC_WR[cnt_bit];
- 1: data_out <= SEC[cnt_bit];
- default: data_out <= 'd0;
- endcase
- end
- default: data_out <= 'd0;
- endcase
- end
- else if(state_c == WRITE && cnt_cyc == 0 && start_flag)begin //写数据地址
- case (cnt_done)
- 0: data_out <= YEAR_RD[cnt_bit];
- 1: data_out <= MON_RD [cnt_bit];
- 2: data_out <= DATA_RD[cnt_bit];
- 3: data_out <= DAY_RD [cnt_bit];
- 4: data_out <= HOUR_RD[cnt_bit];
- 5: data_out <= MIN_RD [cnt_bit];
- 6: data_out <= SEC_RD [cnt_bit];
- default: data_out <= 'd0;
- endcase
- end
- end
- //****************************************************************
- //-- 数据采集
- //****************************************************************
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- tx_data <= 'd0;
- end
- else if(state_c == READ && cnt_cyc == (CYCLE>>1))begin
- tx_data[cnt_bit] = data_in;
- end
- end
- //采集完成
- assign tx_vld = read2done;
- endmodule
2.控制模块设计
- /**************************************功能介绍***********************************flag
- Date : 2023年10月15日14:11:59
- Author : xlin
- Version :
- Description: ds1302控制模块
- *********************************************************************************/
- //---------<模块及端口声名>------------------------------------------------------
- module ds1302_ctrl(
- input clk ,
- input rst_n ,
- input ds_vld ,
- input [7:0] ds_data ,
- input done ,
- output reg uart_vld ,
- output reg [7:0] uart_data
- );
- //---------<内部信号定义>-----------------------------------------------------
- reg [3:0] cnt ;
- wire add_cnt ;
- wire end_cnt ;
-
- reg [4:0] max ;
- reg [4:0] cnt_num ;
- wire add_cnt_num ;
- wire end_cnt_num ;
-
- reg start_flag ;
-
- reg [7:0] data_reg ;
- reg uart_vld_r ;
- //****************************************************************
- //-- 数据寄存
- //****************************************************************
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- data_reg<= 'd0;
- end
- else if(ds_vld)begin
- data_reg<=ds_data;
- end
- end
- //****************************************************************
- //-- 开始信号
- //****************************************************************
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- start_flag <= 'd0;
- end
- else if(done)begin
- start_flag <= 'd1;
- end
- else if(end_cnt_num)begin
- start_flag <= 'd0;
- end
- end
- //数据计数器
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- cnt_num <= 'd0;
- end
- else if(add_cnt_num)begin
- if(end_cnt_num)begin
- cnt_num <= 'd0;
- end
- else begin
- cnt_num <= cnt_num + 1'b1;
- end
- end
- end
-
- assign add_cnt_num = start_flag;
- assign end_cnt_num = add_cnt_num && cnt_num == max-1;
- //年月日 星期 时分秒计数
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- cnt <= 'd0;
- end
- else if(add_cnt)begin
- if(end_cnt)begin
- cnt <= 'd0;
- end
- else begin
- cnt <= cnt + 1'b1;
- end
- end
- end
-
- assign add_cnt = end_cnt_num;
- assign end_cnt = add_cnt && cnt == 7 -1;
-
- always @(*)begin
- case (cnt)
- 0: max = 6;
- 1: max = 4;
- 2: max = 4;
- 3: max = 6;
- 4: max = 3;
- 5: max = 3;
- 6: max = 6;
- default: max = 1;
- endcase
- end
- //数据有效信号
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- uart_vld <= 'd0;
- end
- else begin
- uart_vld <= start_flag;
- end
- end
- //数据输出
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- uart_data <= 'd0;
- end
- else begin
- case (cnt)
- 0: begin
- case (cnt_num)
- 0: uart_data <= 8'h32;//2
- 1: uart_data <= 8'h30;//0
- 2: uart_data <= {4'h3,data_reg[7:4]};//2
- 3: uart_data <= {4'h3,data_reg[3:0]};//3
- 4: uart_data <= 8'hc4;//年
- 5: uart_data <= 8'hea;
- default: uart_data <= 'd0;
- endcase
- end
- 1: begin
- case (cnt_num)
- 0: uart_data <= {4'h3,data_reg[7:4]};
- 1: uart_data <= {4'h3,data_reg[3:0]};
- 2: uart_data <= 8'hd4;//月
- 3: uart_data <= 8'hc2;
- default: uart_data <= 'd0;
- endcase
- end
- 2: begin
- case (cnt_num)
- 0: uart_data <= {4'h3,data_reg[7:4]};
- 1: uart_data <= {4'h3,data_reg[3:0]};
- 2: uart_data <= 8'hc8;//日
- 3: uart_data <= 8'hd5;
- default: uart_data <= 'd0;
- endcase
- end
- 3: begin
- case (cnt_num)
- 0: uart_data <= 8'h20;//空格
- 1: uart_data <= 8'hd0;//星
- 2: uart_data <= 8'hc7;
- 3: uart_data <= 8'hc6;//期
- 4: uart_data <= 8'hda;
- 5: uart_data <= {4'h3,data_reg[3:0]};
- default: uart_data <= 'd0;
- endcase
- end
- 4: begin
- case (cnt_num)
- 0: uart_data <= 8'h20;//空格
- 1: uart_data <= {4'h3,2'h0,data_reg[5:4]};//时
- 2: uart_data <= {4'h3,data_reg[3:0]};
- default: uart_data <= 'd0;
- endcase
- end
- 5: begin
- case (cnt_num)
- 0: uart_data <= 8'h3a;//:
- 1: uart_data <= {4'h3,data_reg[7:4]};//分
- 2: uart_data <= {4'h3,data_reg[3:0]};
- default: uart_data <= 'd0;
- endcase
- end
- 6: begin
- case (cnt_num)
- 0: uart_data <= 8'h3a;//:
- 1: uart_data <= {4'h3,data_reg[7:4]};//秒
- 2: uart_data <= {4'h3,data_reg[3:0]};
- 3: uart_data <= 8'h0d;
- 4: uart_data <= 8'h0d;
- default: uart_data <= 'd0;
- endcase
- end
- default: uart_data <= 'd0;
- endcase
- end
- end
- endmodule
3.顶层模块设计
- /**************************************功能介绍***********************************
- Date : 2023年10月15日14:26:41
- Author : Xlin.
- Version:
- Description: ds1302顶层模块
- *********************************************************************************/
- module ds1302_top(
- input clk , //系统时钟
- input rst_n , //复位按键
- output tx ,
- output ds1302_sclk, //ds1302时钟线
- output ds1302_ce , //ds1302片选线
- inout ds1302_data //ds1302数据线
- );
-
- //-----------------参数定义----------------
- wire ds_vld ;
- wire [7:0] ds_data ;
- wire done ;
- wire uart_vld ;
- wire [7:0] uart_data ;
- //fifo 参数定义
- wire fifo_rdreq;
- wire fifo_wrreq;
- wire fifo_empty;
- wire fifo_full;
- wire [7:0] fifo_data;
- wire tx_ready ;
- //ds1302控制模块
- ds1302_ctrl top_ctrl(
- /*input */.clk (clk ),
- /*input */.rst_n (rst_n ),
- /*input */.ds_vld (ds_vld ),
- /*input [7:0] */.ds_data (ds_data ),
- /*input */.done (done ),
- /*output reg */.uart_vld (uart_vld ),
- /*output reg [7:0] */.uart_data(uart_data)
- );
- // );
- ds1302_if top_interface(
- /*input */ .clk (clk ) ,
- /*input */ .rst_n (rst_n ) ,
- /*output */.done (done ) ,//操作完成
- /*output */.tx_vld (ds_vld ) ,//数据有效信号
- /*output reg [7:0] */.tx_data (ds_data ) ,//数据
- /*output */.ce (ds1302_ce ) ,
- /*output */.sclk(ds1302_sclk) ,
- /*inout */ .io (ds1302_data)
-
- );
- //fifo 调用
- fifo fifo_inst (
- .aclr (~rst_n ),
- .clock (clk ),
- .data (uart_data ),
- .rdreq (fifo_rdreq ),
- .wrreq (fifo_wrreq ),
- .empty (fifo_empty ),
- .full (fifo_full ),
- .q (fifo_data ),
- .usedw ()
- );
- assign fifo_wrreq=~fifo_full && uart_vld;
- assign fifo_rdreq=~fifo_empty && tx_ready;
- //列化接口
- uart_tx #(.BAUD (115200 ) ,//"NONE"无校验位,"ODD"奇校验位,"EVEN"偶校验位
- .CLK (50000000) ,
- .check("NONE" )
- )u_uart_tx(
- .clk (clk ),
- .rst_n (rst_n ),
- .tx_din ( fifo_data ),
- .tx_din_vld ( fifo_rdreq ),
- .ready ( tx_ready ),
- .tx_dout ( tx )
- );
- endmodule
4.串口模块设计
- /**************************************功能介绍***********************************
- Date : 2023年8月16日13:30:25
- Author : Xlin.
- Version :
- Description: UART--TX端口
- *********************************************************************************/
- //列化接口
- // uart_tx #(.BAUD (115200 ) ,//"NONE"无校验位,"ODD"奇校验位,"EVEN"偶校验位
- // .CLK (50000000) ,
- // .check("NONE" )
- // )u_uart_tx(
- // .clk (clk ),
- // .rst_n (rst_n ),
- // .tx_din ( ),
- // .tx_din_vld ( ),
- // .ready ( ),
- // .tx_dout ( )
- // );
- //---------<模块及端口声名>------------------------------------------------------
- module uart_tx#(parameter BAUD = 115200,
- CLK=50000000 ,
- check="EVEN")//"NONE"无校验位,"ODD"奇校验位,"EVEN"偶校验位
- (
- input clk ,
- input rst_n ,
- input [7:0] tx_din ,
- input tx_din_vld,
- output ready ,
- output reg tx_dout
- );
- //---------<参数定义>---------------------------------------------------------
- reg [7:0] tx_data;
- wire jo_check;
- //---------<内部信号定义>-----------------------------------------------------
- //波特率计数器
- reg [9:0] cnt_bit ;
- wire add_cnt_bit ;
- wire end_cnt_bit ;
- //bit计数器
- reg [3:0] max ;
- reg [3:0] cnt_1bit ;
- wire add_cnt_1bit ;
- wire end_cnt_1bit ;
- //状态机参数定义
- localparam IDLE = 'b00001,//空闲
- START = 'b00010,//起始位
- DATA = 'b00100,//数据位
- CHECK = 'b01000,
- STOP = 'b10000;//结束位
-
- reg [4:0] state_c ;//现态
- reg [4:0] state_n ;//次态
- //状态跳转条件
- wire idle2start;
- wire start2data;
- wire data2check;
- wire data2stop;
- wire check2stop;
- wire stop2idle;
- //第一段:时序逻辑描述状态转移
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- state_c <= IDLE;
- end
- else begin
- state_c <= state_n;
- end
- end
- //第二段:组合逻辑描述状态转移规律和状态转移条件
- always @(*) begin
- case(state_c)
- IDLE : if(idle2start)
- state_n=START;
- else
- state_n=IDLE;
- START : if(start2data)
- state_n=DATA;
- else
- state_n=START;
- DATA : if(data2stop)//无校验
- state_n=STOP;
- else if(data2check)//有校验
- state_n=CHECK;
- else
- state_n=DATA;
- CHECK :if(check2stop)
- state_n=STOP;
- else
- state_n=CHECK;
- STOP : if(stop2idle)
- state_n=IDLE;
- else
- state_n=STOP;
- default :state_n=IDLE ;
- endcase
- end
- assign idle2start = state_c ==IDLE && tx_din_vld;
- assign start2data = state_c ==START && end_cnt_1bit;
- assign data2check = state_c ==DATA && end_cnt_1bit;
- assign data2stop = state_c ==DATA && end_cnt_1bit && check=="NONE";
- assign stop2idle = state_c ==STOP && end_cnt_1bit;
- assign check2stop = state_c ==CHECK && end_cnt_1bit;
- //****************************************************************
- //--波特率 计数器
- //****************************************************************
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- cnt_bit <= 'd0;
- end
- else if(add_cnt_bit)begin
- if(end_cnt_bit)begin
- cnt_bit <= 'd0;
- end
- else begin
- cnt_bit <= cnt_bit + 1'b1;
- end
- end
- end
-
- assign add_cnt_bit = state_c!=IDLE;
- assign end_cnt_bit = add_cnt_bit && cnt_bit == (CLK/BAUD) - 1;//计算波特率115200对应434
- //****************************************************************
- //--bit 计数器
- //****************************************************************
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- cnt_1bit <= 'd0;
- end
- else if(add_cnt_1bit)begin
- if(end_cnt_1bit)begin
- cnt_1bit <= 'd0;
- end
- else begin
- cnt_1bit <= cnt_1bit + 1'b1;
- end
- end
- end
- assign add_cnt_1bit = end_cnt_bit;
- assign end_cnt_1bit = add_cnt_1bit && cnt_1bit == max - 1;
- always @(*)begin
- case(state_c)
- IDLE :max=1;
- START:max=1;
- DATA :max=8;
- CHECK:max=1;
- STOP :max=1;
- endcase
- end
- //数据寄存一拍
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n)
- tx_data<=0;
- else
- tx_data<=tx_din;
- end
- //****************************************************************
- //--判断奇偶检验
- //~^tx_data奇校验
- //^tx_data偶检验
- //****************************************************************
- assign jo_check=(check=="ODD")?~^tx_data:^tx_data;
- //第三段:描述输出,时序逻辑或组合逻辑皆可
- always @(*) begin
- case(state_c)
- IDLE :tx_dout=1;
- START:tx_dout=0;
- DATA :if(tx_data[cnt_1bit])
- tx_dout=1;
- else
- tx_dout=0;
- CHECK:tx_dout=jo_check;
- STOP :tx_dout=1;
- default:;
- endcase
- end
-
- assign ready=state_c==IDLE;
-
- endmodule
5.结果展示:
时钟视频
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。