项目信息
名称:8086接口缓存与同步串行发送 VHDL ModelSim
软件:ModelSim
语言:VHDL
代码功能
该工程实现一个带缓冲的串行发送模块:外部以8086兼容的片选/读写/地址信号写入8位数据,模块内部用环形缓冲区存储数据;在同步信号FS到来时,若缓冲区累计数据达到阈值,则按固定节拍把若干字节从高位到低位串行输出到TXD;若数据不足,则输出空闲字节用于占位,保证链路连续性。
代码实现思路
实现上把“并行写入”和“串行发送”分离:写入过程在2MHz时钟下对片选与写信号进行采样,将D总线数据写入数组并推进写指针;发送过程使用状态机等待FS的有效窗口,在满足“缓存中至少4字节”等条件后进入发送状态。每个字节通过位计数器控制移位输出,高位先出;当一个字节发送完成时产生读走脉冲推进读指针并更新待发送字节。这种结构既能适配不均匀的写入节奏,又能在同步场景下稳定地输出固定长度的帧数据。
代码结构
代码主体由三部分组成:1)环形缓冲区与读写指针,完成数据入队/出队统计;2)主状态机,决定当前输出空闲字节还是输出有效数据;3)位计数与移位逻辑,将字节转换为串行比特流。模块的关键接口是FS:FS有效时优先尝试输出有效数据帧;否则维持空闲字节输出。通过data_count限制出队条件,避免在帧发送过程中出现数据不完整。
1、程序文件
Testbench
2、程序编译
3、仿真图
部分代码
serial_data_tx.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.ALL;
entity serial_data_tx is
Port (
-- 8086兼容接口信号
WR_n : inSTD_LOGIC; -- 写信号(低有效)
RD_n : inSTD_LOGIC; -- 读信号(低有效)
D : in STD_LOGIC_VECTOR(7 downto 0); -- 双向数据线
A0 : inSTD_LOGIC; -- 地址线
CS_n : inSTD_LOGIC; -- 片选信号
-- 时钟和同步信号
CLK_2M: inSTD_LOGIC; -- 2.048MHz时钟
FS : inSTD_LOGIC; -- 同步信号(低有效)
-- 串行输出
TXD : out STD_LOGIC -- 串行数据输出
);
end serial_data_tx;
architecture Behavioral of serial_data_tx is
-- 数据缓冲区 - 存储4个字节
type data_buffer_type is array (0 to 7) of STD_LOGIC_VECTOR(7 downto 0);
signal data_buffer : data_buffer_type;
signal write_ptr : integer range 0 to 7 := 0;-- 写指针
signal read_ptr : integer range 0 to 7 := 0;-- 读指针
signal data_count : integer range 0 to 8 := 0; -- 缓冲区中数据个数
signal FS_D : STD_LOGIC:='0';
signal ram_rd : STD_LOGIC:='0';
signal send_data : integer range 0 to 7 := 0;
signal bit_count : integer range 0 to 7 := 0;--每个字节的位计数0~7
signal bit_count_d: integer range 0 to 7 := 0;
signal preread_byte : STD_LOGIC_VECTOR(7 downto 0) := X"7E"; --当前发送的字节
signal current_send_byte : STD_LOGIC_VECTOR(7 downto 0) := X"7E"; --当前发送的字节
signal tx_byte : STD_LOGIC_VECTOR(7 downto 0) := X"7E"; --发送的字节
-- 状态机
type state_type is (IDLE, SYNC_WAIT, TRANSMIT, TRANS_DATA, TRANS_IDLE);
signal current_state : state_type := IDLE;
begin
-- 8086兼容的读写接口
process(CLK_2M)
begin
if rising_edge(CLK_2M) then
-- 写操作:向数据缓冲区写入数据
if CS_n = '0' and WR_n = '0' and A0 = '0' then
if data_count < 8 then
data_buffer(write_ptr) <= D;
write_ptr <= (write_ptr + 1) mod 8;
data_count <= data_count + 1;
end if;
elsif ram_rd = '1' then --读走
if data_count > 0 then
data_count <= data_count - 1;
--read_ptr <= (read_ptr + 1) mod 8;
end if;
end if;
end if;
end process;
-- 主状态机
process(CLK_2M)
begin
if rising_edge(CLK_2M) then
-- 主状态机
case current_state is
when IDLE =>
current_state <= SYNC_WAIT;
when SYNC_WAIT => --等待FS
if FS = '0' then
current_state <= TRANSMIT;
else
current_state <= TRANS_IDLE;
end if;
when TRANSMIT => --发送
if data_count >= 4 then --buffer中够4字节
current_state <= TRANS_DATA;
else
current_state <= TRANS_IDLE;
end if;
when TRANS_DATA => --发送数据
if send_data = 3 and bit_count = 7 then --已经发送4个字节
current_state <= TRANS_IDLE;
else
current_state <= TRANS_DATA;
end if;
when TRANS_IDLE => --发送空闲字节
if FS = '0'then --and bit_count = 7
if(data_count >= 4 )then
current_state <= TRANS_DATA;
else
current_state <= TRANS_IDLE;
end if;
else
current_state <= TRANS_IDLE;
end if;
when others =>
current_state <= IDLE;
end case;
end if;
end process;
--控制send_data,发送的字节数
process(CLK_2M)
begin
if rising_edge(CLK_2M) then
case current_state is
when TRANSMIT =>
send_data <= 0; -- 重置发送字节计数
when TRANS_DATA =>
if bit_count = 7 then -- 一个字节发送完成
if send_data < 3 then
send_data <= send_data + 1;
else
send_data <= 0;
end if;
end if;
when TRANS_IDLE =>
send_data <= 0; -- 重置发送字节计数
when others =>
null;
end case;
end if;
end process;
--控制bit_count--每个字节的位计数
process(CLK_2M)
begin
if rising_edge(CLK_2M) then
case current_state is
when TRANSMIT =>
bit_count <= 0; -- 重置位计数
when TRANS_DATA | TRANS_IDLE =>
if bit_count = 7 then
bit_count <= 0; -- 一个字节发送完成,重置位计数
else
bit_count <= bit_count + 1; -- 位计数递增
end if;
when others =>
null;
end case;
end if;
end process;
--控制每次发送的字节内容
process(CLK_2M)
begin
if rising_edge(CLK_2M) then
-- 默认ram_rd为低电平
ram_rd <= '0';
case current_state is
-- when TRANSMIT =>
--进入发送状态时,准备第一个字节
-- if data_count >= 4 then
-- preread_byte <= data_buffer(read_ptr);
-- else
-- preread_byte <= X"7E"; -- 空闲字节
-- end if;
when TRANS_DATA =>
if bit_count = 0 then -- 当前字节发送完成,准备下一个字节
-- 产生ram_rd脉冲,表示读走一个数据
ram_rd <= '1';
read_ptr <= (read_ptr + 1) mod 8;
-- 准备下一个字节
preread_byte <= data_buffer(read_ptr);
end if;
when TRANS_IDLE =>
preread_byte <= X"7E"; -- 空闲字节
when others =>
null;
end case;
end if;
end process;
process(CLK_2M)
begin
if rising_edge(CLK_2M) then
bit_count_d<=bit_count;
current_send_byte<=preread_byte;
end if;
end process;
-- tx_byte<=std_logic_vector(shift_left(unsigned (preread_byte),bit_count)); -- 数据左移
-- TXD <= tx_byte(7);--最终输出移位后信号的最高位
-- 控制将待发送的字节转换为串行输出,高位在前
process(current_state,preread_byte,bit_count_d)
begin
case current_state is
when IDLE | SYNC_WAIT =>
TXD <= '0'; -- 空闲时输出高电平
tx_byte<=X"7E";
when TRANSMIT =>
TXD <= '0'; -- 准备发送时输出高电平
when TRANS_DATA | TRANS_IDLE =>
---数据左移
146