|
- `define IIC_START 3'd1
- `define IIC_ACK 3'd2
- `define IIC_STOP 3'd3
- `define IIC_WRITE 3'd4
- module tm1637( //带冒号的4位共阴动态扫描数码管模块
- input clk, //50Mhz 时钟输入 (clk与CLK大小写敏感)
- input colon, //冒号 1:点亮 0:熄灭
- input [6:0] A, //[7位宽] 千位段码 (七段段码,没有小数点)
- input [6:0] B, //[7位宽] 百位段码
- input [6:0] C, //[7位宽] 十位段码
- input [6:0] D, //[7位宽] 个位段码
- input [2:0] LM, //[3位宽] 亮度:0~7 (0最暗,7最亮)
- output OK, //发送成功置1 失败清0,表示未检测到TM1637
- inout DIO, //TM1637双向数据
- output reg CLK //TM1637时钟
- );
- reg IO = 1'b1; //DIO 1:输入 0:输出
- reg OUT = 1'b1; //DIO 输出电平
- reg [2:0] order = 3'd0; //指令
- reg [1:0] step = 2'd0; //步骤
- reg [4:0] pc = 5'd0; //程序指针
- reg [15:0] acktime = 16'd0; //ACK应答超时计数器
- reg [7:0] delay = 8'd0; //延时时钟数
- reg [7:0] dat = 8'd0; //IIC待发数据:0~255
- reg [2:0] bpc = 3'd0; //IIC字节位指针:0~7
- reg over = 1'b0; //指令结束标志
- reg [6:0] ack = 7'b0; //7个ACK应答信号
- assign OK = &ack; //ACK信号全部到位
- wire [31:0] new = {colon,A,B,C,D,LM}; //32位宽导线 {冒号亮灭,7位宽A,7位宽B,7位宽C,7位宽D,亮度}
- reg [31:0] old = 29'd0; //32位宽寄存器 (用于检测线网 new 的值是否发生改变)
- reg run = 1'b0; //运行标志 置1开始发送,完成后清0
- assign DIO = IO ? 1'bz : OUT;
- reg clkB = 1'b0;
- always @(posedge clk) begin //50Mhz分频25Mhz
- clkB <= !clkB;
- end
- always @(posedge clkB) begin
- old <= new;
- if(old != new) run <= 1'b1; //显示的数据发生改变,开始发送!
- if(run) begin
- if(|delay) begin //有延时
- delay <= delay - 8'd1;
- end else begin
- over = 1'b0;
- case(order) //有指令
- `IIC_START:case(step) //IIC开始
- 2'd0:begin //CLK与DIO拉高
- {CLK,IO,OUT} <= 3'b101;
- step <= 2'd1;
- delay <= 8'd1000; //延时100个时钟即4us
- end
- 2'd1:begin
- OUT <= 1'b0; //DIO拉低
- order <= 3'd0; //指令执行完毕
- step <= 2'd0;
- over = 1'b1;
- end
- endcase
- `IIC_ACK:case(step) //IIC应答
- 2'd0:begin
- {CLK,IO} <= 2'b01; //CLK拉低,DIO输入模式
- delay <= 8'd250; //延时10us
- step <= 2'd1;
- acktime <= 16'd0;
- end
- 2'd1:begin //等待应答
- if(DIO) begin //DIO高电平等待
- acktime = acktime + 16'd1;
- if(&acktime) begin //超时
- ack <= (ack << 1'b1);
- step <= 2'd2;
- end
- end else begin
- ack <= (ack << 1'b1) | 1'b1;
- step <= 2'd2;
- end
- end
- 2'd2:begin //CLK拉高并延时2us
- CLK <= 1'b1;
- delay <= 8'd100;
- step <= 2'd3;
- end
- 2'd3:begin
- CLK <= 1'b0; //CLK拉低
- over = 1'b1;
- order <= 3'd0; //指令执行完毕
- step <= 2'd0;
- end
- endcase
- `IIC_STOP:case(step) //IIC停止
- 2'd0:begin //CLK拉低并延时2us
- CLK <= 1'b0;
- delay <= 8'd100;
- step <= 2'd1;
- end
- 2'd1:begin //DIO拉低并延时2us
- {IO,OUT} <= 2'b00;
- delay <= 8'd100;
- step <= 2'd2;
- end
- 2'd2:begin //CLK拉高并延时2us
- CLK <= 1'b1;
- delay <= 8'd50;
- step <= 2'd3;
- end
- 2'd3:begin //DIO拉高并延时2us
- {IO,OUT} <= 2'b01;
- delay <= 8'd100;
- step <= 2'd0;
- order <= 3'd0; //指令执行完毕
- over = 1'b1;
- end
- endcase
- `IIC_WRITE:case(step) //写数据函数
- 2'd0:begin
- bpc <= 3'd0;
- step <= 2'd1;
- end
- 2'd1:begin
- {CLK,IO,OUT} <= {1'b0,dat[bpc],1'b0};
- delay <= 8'd150; //延时6us
- step <= 2'd2;
- end
- 2'd2:begin //CLK拉高并延时6us
- CLK <= 1'b1;
- delay <= 8'd150;
- step <= (&bpc) ? 2'd3 : 2'd1;
- bpc <= bpc + 3'd1;
- end
- 2'd3:begin
- bpc <= 3'd0;
- step <= 2'd0;
- order <= 3'd0;
- over = 1'b1;
- end
- endcase
- default:order <= 3'd0; //没有指令
- endcase
- if(!order) begin
- case(pc)
- 5'd0:order <= `IIC_START;
- 5'd1:{order,dat} <= {`IIC_WRITE,8'h40}; //写数据+自动地址加1+普通模式
- 5'd2:order <= `IIC_ACK;
- 5'd3:order <= `IIC_STOP;
- 5'd4:order <= `IIC_START;
- 5'd5:{order,dat} <= {`IIC_WRITE,8'hC0}; //设置显示首地址即第一个LED
- 5'd6:order <= `IIC_ACK;
- 5'd7:{order,dat} <= {`IIC_WRITE,1'b0,A};
- 5'd8:order <= `IIC_ACK;
- 5'd9:{order,dat} <= {`IIC_WRITE,colon,B};
- 5'd10:order <= `IIC_ACK;
- 5'd11:{order,dat} <= {`IIC_WRITE,1'b0,C};
- 5'd12:order <= `IIC_ACK;
- 5'd13:{order,dat} <= {`IIC_WRITE,1'b0,D};
- 5'd14:order <= `IIC_ACK;
- 5'd15:order <= `IIC_STOP;
- 5'd16:order <= `IIC_START;
- 5'd17:{order,dat} <= {`IIC_WRITE,5'h11,LM}; //开显示
- 5'd18:order <= `IIC_ACK;
- 5'd19:order <= `IIC_STOP;
- default:order <= 3'd0;
- endcase
- end
- if(over) begin
- pc = pc + 5'd1;
- if(pc > 19) begin
- pc = 5'd0;
- run <= 1'b0;
- end
- end
- end
- end else begin //run为0
- {CLK,IO,OUT} <= 3'b111;
- end
- end
- endmodule
- module main(
- input clk, //50Mhz Pin17
- inout DIO, //TM1637 Pin40
- output CLK, //TM1637 Pin42
- output led //LED Pin3(低电平点亮) 初始化正常点亮,否则熄灭
- );
- function [6:0] display; //16进制数码管段码查询
- input [3:0] hex;
- begin
- case(hex)
- 4'h0:display = 7'h3F;
- 4'h1:display = 7'h06;
- 4'h2:display = 7'h5B;
- 4'h3:display = 7'h4F;
- 4'h4:display = 7'h66;
- 4'h5:display = 7'h6D;
- 4'h6:display = 7'h7D;
- 4'h7:display = 7'h07;
- 4'h8:display = 7'h7F;
- 4'h9:display = 7'h6F;
- 4'hA:display = 7'h77;
- 4'hB:display = 7'h7C;
- 4'hC:display = 7'h39;
- 4'hD:display = 7'h5E;
- 4'hE:display = 7'h79;
- 4'hF:display = 7'h71;
- endcase
- end
- endfunction
- reg colon;
- integer i;
- always @(posedge clk) begin
- i = i + 1;
- if(i >= 25000000) begin
- i = 0;
- colon <= !colon; //冒号1HZ闪烁
- end
- end
- reg [13:0] sec = 14'd0; //秒:0~9999
- always @(negedge colon) begin
- sec = sec + 14'd1;
- if(sec > 9999) begin
- sec = 14'd0;
- end
- end
- wire OK;
- assign led = !OK;
- tm1637 tm1637(
- .clk(clk),
- .colon(colon),
- .A(display((sec/1000)%10)),
- .B(display((sec/100)%10)),
- .C(display((sec/10)%10)),
- .D(display(sec%10)),
- .LM(sec&7),
- .OK(OK),
- .DIO(DIO),
- .CLK(CLK)
- );
- endmodule
复制代码 |
|