pcf8563芯片经过iic驱动得到的wire [23:0] rtc_time 从低位到高位依次是秒、分、时,各8bit,将其通过ASCII由串口uart_rx输出
时间: 2023-06-18 15:02:36 浏览: 108
实时时钟/日历芯片 PCF8563 的驱动方
5星 · 资源好评率100%
假设你已经完成了pcf8563芯片的iic驱动和rtc_time的获取,那么将其通过ASCII由串口uart_rx输出可以通过以下代码实现:
```verilog
module pcf8563_to_uart(
input wire clk,
input wire rst_n,
input wire iic_scl,
inout wire iic_sda,
input wire uart_rx_clk,
input wire uart_rx_rst_n,
output reg uart_tx,
output reg uart_tx_en
);
// 定义常量
localparam ADDR_SEC = 7'h02;
localparam ADDR_MIN = 7'h03;
localparam ADDR_HOUR = 7'h04;
localparam BAUD_RATE = 9600; // 波特率
localparam CLK_FREQ = 50_000_000; // 时钟频率
// 定义寄存器
reg [7:0] sec;
reg [7:0] min;
reg [7:0] hour;
// 定义计数器
reg [7:0] cnt;
// 定义状态机状态
localparam IDLE = 2'd0;
localparam SEND_SEC = 2'd1;
localparam SEND_MIN = 2'd2;
localparam SEND_HOUR = 2'd3;
// 定义状态机信号
reg [1:0] state_next;
wire [1:0] state;
// 时钟分频
reg [31:0] cnt_clk;
localparam CLK_DIV = CLK_FREQ / BAUD_RATE / 2 - 1;
// IIC总线
wire ack;
reg [7:0] data_in;
reg [7:0] data_out;
reg [6:0] addr_out;
reg [6:0] addr_next;
wire [6:0] addr;
reg [2:0] iic_state;
localparam IDLE_IIC = 3'd0;
localparam START = 3'd1;
localparam ADDR_OUT = 3'd2;
localparam DATA_OUT = 3'd3;
localparam RESTART = 3'd4;
localparam ADDR_IN = 3'd5;
localparam DATA_IN_ACK = 3'd6;
localparam DATA_IN_NACK = 3'd7;
localparam STOP = 3'd8;
// 状态机
always @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
cnt <= 0;
sec <= 0;
min <= 0;
hour <= 0;
state_next <= IDLE;
addr_out <= ADDR_SEC;
iic_state <= IDLE_IIC;
end else begin
cnt <= cnt + 1;
sec <= rtc_time[7:0];
min <= rtc_time[15:8];
hour <= rtc_time[23:16];
state_next <= state;
addr_out <= addr_next;
case (state)
IDLE: begin
uart_tx_en <= 0;
if (cnt >= CLK_DIV) begin
cnt <= 0;
state_next <= SEND_SEC;
addr_next <= ADDR_SEC;
end
end
SEND_SEC: begin
uart_tx_en <= 1;
uart_tx <= {8'h0A, sec + '0'};
if (cnt >= CLK_DIV) begin
cnt <= 0;
state_next <= SEND_MIN;
addr_next <= ADDR_MIN;
end
end
SEND_MIN: begin
uart_tx_en <= 1;
uart_tx <= {8'h0A, min + '0'};
if (cnt >= CLK_DIV) begin
cnt <= 0;
state_next <= SEND_HOUR;
addr_next <= ADDR_HOUR;
end
end
SEND_HOUR: begin
uart_tx_en <= 1;
uart_tx <= {8'h0A, hour + '0'};
if (cnt >= CLK_DIV) begin
cnt <= 0;
state_next <= IDLE;
addr_next <= ADDR_SEC;
end
end
endcase
end
end
// IIC总线
assign iic_sda = (iic_state == DATA_OUT || iic_state == ADDR_OUT) ? data_out[7] : 1'bZ;
always @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
data_in <= 0;
data_out <= 0;
addr_next <= ADDR_SEC;
iic_state <= IDLE_IIC;
end else begin
case (iic_state)
IDLE_IIC: begin
if (iic_scl == 0 && iic_sda == 0) begin
iic_state <= START;
end else if (iic_scl == 0 && iic_sda == 1) begin
iic_state <= STOP;
end
end
START: begin
iic_sda <= 0;
iic_state <= ADDR_OUT;
end
ADDR_OUT: begin
addr <= addr_out;
iic_sda <= addr[6];
addr_out <= addr_out + 1;
iic_state <= DATA_OUT;
end
DATA_OUT: begin
data_out <= (iic_state == DATA_OUT) ? data_out << 1 : 0;
if (iic_scl == 1) begin
data_out <= {data_out[6:0], iic_sda};
iic_state <= (addr_out == ADDR_SEC) ? RESTART : ADDR_OUT;
end
end
RESTART: begin
iic_sda <= 1;
iic_state <= ADDR_IN;
end
ADDR_IN: begin
addr <= addr_out;
iic_sda <= addr[6];
iic_state <= DATA_IN_ACK;
end
DATA_IN_ACK: begin
iic_sda <= 1;
if (iic_scl == 1) begin
iic_state <= DATA_IN_NACK;
end
end
DATA_IN_NACK: begin
if (iic_scl == 0) begin
data_in <= iic_sda;
iic_sda <= 1;
iic_state <= STOP;
end
end
STOP: begin
iic_sda <= 0;
iic_state <= IDLE_IIC;
end
endcase
end
end
endmodule
```
这个模块包含了一个状态机和一个IIC总线模块。状态机负责将rtc_time中的秒、分、时依次通过串口输出,其中波特率为9600,时钟频率为50MHz。IIC总线模块实现了主设备向从设备读取数据的功能,其中地址、数据、应答等信号都需要在状态机中进行控制。注意在发送数据时,需要在数据前加上一个换行符0A,以便在串口助手中能够正确显示。
阅读全文