ПОСЛЕДОВАТЕЛЬНЫЙ ПОРТ УЧЕБНОГО СТЕНДА SDK-6.1 Последовательный порт (англ. Serial port) — двунаправленный последовательный интерфейс, предназначенный для обмена битовой информацией. Последовательным данный порт называется потому, что информация через него передаётся по одному биту, бит за битом (в отличие от параллельного порта). Хотя некоторые другие интерфейсы компьютера — такие как Ethernet, FireWire и USB — также используют последовательный способ обмена, название «последовательный порт» закрепилось за портом, имеющим стандарт RS-232C, и предназначенным изначально для обмена информацией с модемом. Последовательный интерфейс предполагает для передачи данных в одном направлении единственную сигнальную линию, по которой информационные биты передаются друг за другом последовательно. При этом скорость изменения передатчиком состояния линии должна равняться скорости распознавания состояний приемником. Эта скорость измеряется в бодах (baud) – количестве изменений состояния линии за одну секунду. В простейшем случае в линии имеется всего два состояния сигнала, т.е. одним состоянием кодируется один бит, и тогда скорость изменения состояния в бодах совпадает со скоростью передачи двоичной информации, определяемой количеством передаваемых за секунду бит информации, bps (bits per second, бит/с). Однако, при использовании других методов модуляции возможны несколько состояний сигнала, что позволяет одним состоянием кодировать сразу несколько передаваемых бит, и здесь скорость передачи данных bps превышает скорость изменения сигнала baud. Обмен данными может быть: дуплексным – предполагает прием и передачу данных одновременно; полудуплексным – данные передаются в одном направлении с возможностью смены направления; симплексным – данные передаются только в одном направлении. Передача может осуществляться в синхронном и асинхронном режимах. Синхронный режим предполагает наличие средств синхронизации передатчика и приемника. Как правило, для синхронизации используют специальную линию для передачи тактовых импульсов. Информация в канале данных считывается приемником только в те моменты, когда на линии синхронизации сигнал активный. В асинхронном режиме посылке очередного байта информации предшествует специальный старт-бит, сигнализирующий о начале передачи (обычно логический «0»). Затем следуют биты данных (их обычно 8), за которыми может следовать дополнительный бит (его наличие зависит от режима передачи, обычно этот бит выполняет функцию контроля четности). Завершается посылка стоп-битом (логическая «1»), длина которого (длительность единичного состояния линии) может соответствовать длительности передачи 1, 1.5 («полтора стоп-бита») или 2 бит. Стоп-бит гарантирует некоторую выдержку между соседними посылками, при этом пауза между ними может быть сколь угодно долгой (без учета понятия «тайм-аута»). Для асинхронного режима предусмотрен ряд стандартных скоростей обмена: 50, 75, 110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600 и 115200 bps1.  Рис. 8. Передача по последовательному порту На рисунке 8 приведена структура передаваемых данных со синхронизирующим тактовым сигналом (для асинхронной передачи это внутренний сигнал). В данном случае используется 8 бит данных, бит четности и стоп бит. Такая структура также обозначается 8Е1. Сигнальная линия может находиться в двух состояниях: включена и выключена. Линия в состоянии ожидания всегда включена. Когда устройство или компьютер хотят передать данные, они переводят линию в состояние выключено - это установка старт-бита. Биты сразу после старт-бита являются битами данных. Стоп-бит позволяет устройству или компьютеру произвести синхронизацию при возникновении сбоев. Например, помеха на линии скрыла старт-бит. Период между старт- и стоп-битами постоянен, согласно значению скорости обмена, числу бит данных и бита четности. Стоп-бит всегда включен. Если приемник определяет выключенное состояние, когда должен присутствовать стоп-бит, фиксируется появление ошибки. Стоп-бит не просто один бит минимального интервала времени в конце каждой передачи данных. На компьютерах обычно он эквивалентен 1 или 2 битам, и это должно учитываться программе драйвера. Хотя, 1 стоп бит наиболее общий, выбор 2 бит в худшем случае немного замедлит передачу сообщения. В SDK-6.1 для преобразования уровня LVTTL (или LVCMOS) от -3.3 В до +3.3 В к диапазону от -5 В до +5 В (в худшем случае) используется шинный драйвер/приемник Sipex SP202E. Однако никакого взаимодействия с ним предусматривать не надо – все реализовано аппаратно и не требует управления. Для передачи данных по протоколу RS-232 необходимо считывать данные с TXD_RS232 и отправлять их на RXD_RS232 (смотри таблицу 6) в соответствии с протоколом и выбранной скоростью передачи. Скорость передачи задается делителем частоты в устройствах приема и передачи данных и может быть изменена в соответствии с таблицей 5. Таблица 5. Назначение выводов ПЛИС -
Скорость, бит/с | Делитель | 9 600 | 4167 | 14 400 | 2778 | 19 200 | 2083 | 28 800 | 1389 | 38 400 | 1042 | 57 600 | 694 | 115 200 | 347 | Таблица 6. Назначение выводов ПЛИС Номер вывода ПЛИС | Обозначение на схеме | Назначение | 134 | TXD_RS232 | асинхронный канал для передачи данных | 139 | RXD_RS232 | асинхронный канал для приема данных |
На рисунках 9 – 11 приведены функциональные схемы устройства для работы с последовательным портом на языках Verilog, VHDL и AHDL, соответственно. Также для наглядности приведены листинги программ на данных языках.
 Рис. 9. Функциональная схема устройства для работы с последовательным портом на языке Verilog module main_verilog ( input CLK, // входной тактовый сигнал с частотой 40 МНг и периодом 25нс input [7:0] IN_BYTE, // байт принятый по RS232 input SEND_RECEIVE, // сигнал переключения прприема и отправки после схемы подавления дребезга контактов input SBUSY, // сигнал занятости подчиненного устройства (0-свободен, 1-занят) output reg [7:0] OUT_BYTE, // байт посылаемый по RS232 output reg SEND, // управляющий сигнал - начать отправку приема байт по RS232 output reg RECEIVE, // управляющий сигнал - начать прием байт по RS232 output reg RESET // сброс ведомых устройств (для вывода их из режима ожидания байта по RS232) );
parameter BAUD = 347; // выбор делителя для скорости 115200
reg [31:0] buffer; // буфер для хранения временных данных reg [2:0] send_cnt = 0; // счетчик отправленных байт reg [2:0] receive_cnt = 0; // счетчик полученных байт reg [2:0] r_state = 0; // автомат приема байт reg [2:0] s_state = 0; // автомат отправки принятых байт
always @(posedge CLK) begin case (SEND_RECEIVE) //режим отправки данных 0: begin RECEIVE = 0; RESET = 1; r_state <= 0;
case (s_state) 0: if (send_cnt != receive_cnt) s_state <= 1; 1: begin SEND = 1; case (send_cnt) 0: OUT_BYTE = buffer[7:0]; 1: OUT_BYTE = buffer[15:8]; 2: OUT_BYTE = buffer[23:16]; 3: OUT_BYTE = buffer[31:24]; endcase; s_state <= 2; end 2: begin if (SBUSY == 1) begin send_cnt = send_cnt + 1; SEND = 0; s_state <= 3; end end 3: if (SBUSY == 0) s_state <= 4; 4: begin if (send_cnt == receive_cnt) begin receive_cnt = 0; send_cnt = 0; end s_state <= 0; end default: s_state <= 0; endcase end //режим приема 1: begin case (r_state) 0: begin SEND = 0; RESET = 0; RECEIVE = 0; r_state <= 1; end 1: begin if (SBUSY == 1) begin RECEIVE = 0; r_state <= 2; end else RECEIVE = 1; end 2: begin if (SBUSY == 0) begin RESET = 1; case (receive_cnt) 0: begin buffer[7:0] = IN_BYTE; r_state <= 3; end 1: begin buffer[15:8] = IN_BYTE; r_state <= 3; end 2: begin buffer[23:16] = IN_BYTE; r_state <= 3; end 3: begin buffer[31:24] = IN_BYTE; receive_cnt = receive_cnt + 1; r_state <= 4; end endcase; end end 3: begin receive_cnt = receive_cnt + 1; r_state <= 0; end 4: begin RESET = 1; end default: r_state = 0; endcase; end endcase; end endmodule
module txd_neg_edge_verilog( input CLK, // входной тактовый сигнал с частотой 40МГц и периодом 25нс input TXD, // линия приема данных с RS232 input SBUSY, // сигнал занятости подчиненного устройства (0-свободен, 1-занят) input SRESET, // управляющий сигнал сброса output reg NEG_EDGE // вырабатываемый сигнал обнаружения среза (заднего фронта) сигнала на линии TXD );
reg [3:0] intgr = 0; // регистр для обнаружения среза (заднего фронта) сигнала посылаемого по RS232 reg [1:0] state = 0; // регистр для определения среза (заднего фронта) сигнала reg eflag = 0; // флаг, показывающий был ли обнаружен единичный уровень на линии TXD
always @(posedge CLK) begin if (SRESET == 1) state = 0; //организация сброса //автомат обнаружения спадающего фронта case (state) 0: begin NEG_EDGE = 0; eflag = 0; intgr = 0; if (SRESET == 0 && SBUSY == 1) state = 1; end 1: begin if (TXD == 1 && intgr < 15) intgr = intgr + 1; if (TXD == 0 && intgr > 0) intgr = intgr - 1; state = 2; end 2: begin if (intgr == 15) begin eflag = 1; state = 1; end else if (intgr == 0 && eflag == 1) state = 3; else state = 1; end 3: begin NEG_EDGE = 1; end default: state = 0; endcase end endmodule
module receiver_verilog( input CLK, // входной тактовый сигнал с частотой 40 МГц и периодом 25нс input TXD, // линия приема данных c RS232 input RECEIVE, // управляющий сигнал - начать прием байта по RS232 input SRESET, // сигнал сброса ведомого устройства input NEG_EDGE, // сигнал обнаружения среза (заднего фронта) сигнала на линии txd output [7:0] BYTE, // выдача принятого байта output reg RESET, // сброс ведомых устройств (для вывода их из режима ожидания байта по RS232) output reg BUSY // сигнал занятости текущего устройства (0-свободен, 1-занят)
); parameter BAUD = 347; // выбор делителя частоты для скорости ~115273 (для скорости 115200) reg [2:0] state = 0; // автомат приема байта по RS232 reg [8:0] delay = 0; // регистр задержки для выработки нужной частоты reg [7:0] data = 0; // внутренний регистр для приема байта reg [3:0] cnt_bit = 0; // счетчик отсылаемых бит
assign BYTE = data; //связь выхода с внутренним регистром
always @(posedge CLK) begin if (SRESET == 1) state = 0; //автомат приема байт по RS232 case (state) 0: begin BUSY = 0; RESET = 1; delay = 0; cnt_bit = 0; if (SRESET == 0 && RECEIVE == 1) state = 1; end 1: begin BUSY = 1; RESET = 0; if (NEG_EDGE == 1) state = 2; end 2: begin //проверка нулевого уровня старт-бита if (delay >= BAUD/2) if (TXD == 0) begin delay = 0; state = 3; end else state = 0; else delay = delay + 1; end 3: begin if (delay >= BAUD) begin delay = 0; cnt_bit = cnt_bit + 1; data = {TXD, data[7:1]}; state = 4; end else delay = delay + 1; end 4: begin if (cnt_bit < 8) state = 3; else if (delay >= (BAUD)) begin //ожидаем стоп бита delay = 0; BUSY = 0; end else delay = delay + 1; end endcase end endmodule
module transmitter_verilog ( input CLK, // входной тактовый сигнал с частотой 40 МГц и периолом 25нс input [7:0] BYTE, // байт, отсылаемый по RS232 input SEND, // управляющий сигнал - начать отправку байта по RS232 output reg BUSY, // сигнал занятости текущего устройства (0-свободен, 1-занят) output reg RXD // линия отправки данных по RS232 );
parameter BAUD = 347; //выбор делителя частоты для скорости ~115273 (для скорости 115200) reg [2:0] state = 0; //автомат отправки байта по RS232 reg [8:0] delay = 0; //регистр задержки для выбранной нужной частоты reg [3:0] cnt_bit = 0; //счетчик отсылаемых бит
always @(posedge CLK) begin //автомат отправки байта по RS232 case (state) 0: begin BUSY = 0; RXD = 1; delay = 0; cnt_bit = 0; if (SEND == 1) state = 1; end 1: begin BUSY = 1; RXD = 0; state = 2; end 2: begin if (delay >= BAUD) begin delay = 0; cnt_bit = cnt_bit + 1; state = 3; end else delay = delay + 1; end 3: begin if (cnt_bit < 10) begin case (cnt_bit) 1: RXD = BYTE[0]; 2: RXD = BYTE[1]; 3: RXD = BYTE[2]; 4: RXD = BYTE[3]; 5: RXD = BYTE[4]; 6: RXD = BYTE[5]; 7: RXD = BYTE[6]; 8: RXD = BYTE[7]; 9: RXD = 1; endcase state = 2; end else state = 0; end endcase end
endmodule
 Рис. 10. Функциональная схема устройства для работы с последовательным портом на языке VHDL library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
entity main_vhdl is port( CLK : in std_logic; -- входной тактовый сигнал с частотой 40МГц и периодом 25нс IN_BYTE: in std_logic_vector (7 downto 0); -- байт принятый по RS232 SEND_RECEIVE: in std_logic; -- сигнал переключения приёма и отправки после схемы подавления дребезга контактов SBUSY: in std_logic; -- сигнал занятости подчиненного устройства (0-свободен, 1-занят) OUT_BYTE: out std_logic_vector (7 downto 0);-- байт, отсылаемый по RS232 SEND: out std_logic; -- управляющий сигнал - начать отправку байта по RS232 RECEIVE: out std_logic; -- управляющий сигнал - начать приём байта по RS232 RESET: out std_logic -- сброс ведомых устройств (для вывода их из режима ожидания байта по RS232 ); end entity;
architecture main of main_vhdl is type state_type is (s0, s1, s2, s3, s4); signal r_state, s_state : state_type; begin
process(CLK) variable delay : natural range 0 to 347; -- регистр задержки для выбранной нужной частоты variable send_cnt : natural range 0 to 4; -- счетчик отправленных байт variable receive_cnt : natural range 0 to 4;-- счетчик полученных байт variable data : std_logic_vector (7 downto 0); --внутренний регистр для приема байт variable buffer_bytes : std_logic_vector (31 downto 0); -- буфер для хранения принятых байт
begin if (rising_edge(CLK)) then case SEND_RECEIVE is --режим отправки данных when '0' => RECEIVE <= '0'; RESET <= '1'; r_state <= s0; -- автомат отправки принятых байт case s_state is when s0 => if (send_cnt < receive_cnt) then s_state <= s1; end if; when s1 => SEND <= '1'; OUT_BYTE <= buffer_bytes (7 + 8*send_cnt downto 8*send_cnt); s_state <= s2; when s2 => if (SBUSY = '1') then send_cnt := send_cnt + 1; SEND <= '0'; s_state <= s3; end if; when s3 => if (SBUSY = '0') then s_state <= s4; end if; when s4 => if (send_cnt = receive_cnt) then receive_cnt := 0; send_cnt := 0; end if; s_state <= s0; when others => s_state <= s0; end case; --автомат приёма байт when '1' => case r_state is when s0 => SEND <= '0'; RESET <= '0'; RECEIVE <= '0'; r_state <= s1; when s1 => if (SBUSY = '1') then RECEIVE <= '0'; r_state <= s2; else RECEIVE <= '1'; end if; when s2 => if (SBUSY = '0') then RESET <= '1'; if (receive_cnt < 3) then buffer_bytes(7 + 8*receive_cnt downto 8*receive_cnt) := IN_BYTE; r_state <= s3; else buffer_bytes(7 + 8*receive_cnt downto 8*receive_cnt) := IN_BYTE; receive_cnt := receive_cnt + 1; r_state <= s4; end if; end if; when s3 => receive_cnt := receive_cnt + 1; r_state <= s0; when s4 => RESET <= '1'; when others => r_state <= s0; end case; end case; end if; end process; end main;
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
entity txd_neg_edge_vhdl is port( CLK : in std_logic; -- входной тактовый сигнал с частотой 40 МГц и периодом 25нс TXD: in std_logic; -- линия приёма данных с RS232 SBUSY: in std_logic; -- сигнал о начале работы устройства приёма байта с RS232 SRESET: in std_logic; -- управляющий сигнал сброса NEG_EDGE: out std_logic -- вырабатываемый сигнал обнаружения среза (заднего фронта) сигнала на линии ); end entity;
architecture txd_neg_edge of txd_neg_edge_vhdl is type state_type is (s0, s1, s2, s3); --описание состояний автомата signal state : state_type; -- автомат обнаружения среза (заднего фронта) сигнала begin
process(CLK) variable intgr : natural range 0 to 15; -- регистр, для обнаружения среза (заднего фронта) сигнала variable eflag : std_logic; -- флаг, показывающий был ли обнаружен единичный уровень на линии TXD
begin if (rising_edge(CLK)) then if (SRESET = '1') then state <= s0; end if;-- сброс -- автомат обнаружения спадающего фронта case state is when s0 => NEG_EDGE <= '0'; eflag := '0'; intgr := 0; if (SRESET = '0' and SBUSY = '1') then state <= s1; end if; when s1 => if (TXD = '1' and intgr < 15) then intgr := intgr + 1; end if; if (TXD = '0' and intgr > 0) then intgr := intgr - 1; end if; state <= s2; when s2 => if (intgr = 15) then eflag := '1'; state <= s1; elsif (intgr = 0 and eflag = '1') then state <= s3; else state <= s1; end if; when s3 => NEG_EDGE <= '1'; when others => state <= s0; end case; end if; end process; end txd_neg_edge;
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
entity receiver_vhdl is port( CLK : in std_logic; -- входной тактовый сигнал с частотой 40МГц и периодом 25нс TXD: in std_logic; -- линия приёма данных с RS232 RECEIVE: in std_logic; -- управляющий сигнал - начать приём байта по RS232 SRESET: in std_logic; -- сигнал сброса ведомого устройства - txd_neg_edge NEG_EDGE: in std_logic; -- сигнал обнаружения среза (заднего фронта) сигнала на линии TXD (начало start-bit) BYTE: out std_logic_vector (7 downto 0); -- выдача принятого байта RESET: out std_logic; -- сброс ведомых устройств (для вывода их из режима ожидания байта по RS232) BUSY: out std_logic -- сигнал занятости текущего устройства (0-свободен, 1-занят) ); end entity;
architecture receiver of receiver_vhdl is type state_type is (s0, s1, s2, s3, s4); --описание состояний автомата signal state : state_type; -- автомат обнаружения среза (заднего фронта) сигнала constant BAUD : natural range 0 to 347 := 347; -- выбор делителя частоты для скорости ~115273 (для скорости 115200) begin
process(CLK) variable delay : natural range 0 to 347; -- регистр задержки для выработки нужной частоты variable bit_cnt : natural range 0 to 8; -- счётчик отсылаемых бит variable data : std_logic_vector (7 downto 0); --внутренний регистр для приёма байта
begin if (rising_edge(CLK)) then BYTE <= data; -- связь выхода с внутренним регистром if (SRESET = '1') then state <= s0; end if; -- сброс -- автомат приёма байта по RS232 case state is when s0 => BUSY <= '0'; RESET <= '1'; delay := 0; bit_cnt := 0; if (SRESET = '0' and RECEIVE = '1') then state <= s1; end if; when s1 => BUSY <= '1'; RESET <= '0'; if (NEG_EDGE = '1') then state <= s2; end if; when s2 => --проверка нулевого уровня старт-бита if (delay >= BAUD/2) then if (TXD = '0') then delay := 0; state <= s3; else state <= s0; end if; else delay := delay + 1; end if; when s3 => if (delay >= BAUD) then delay := 0; bit_cnt := bit_cnt + 1; data := (TXD) &(data(7 downto 1)); state <= s4; else delay := delay + 1; end if; when s4 => if (bit_cnt < 8) then state <= s3; elsif (delay >= BAUD) then --ожидаем стоп бита delay := 0; BUSY <= '0'; else delay := delay + 1; end if; end case; end if; end process; end receiver;
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
entity transmitter_vhdl is port( CLK : in std_logic; --входной тактовый сигнал с частотой 40 МГц и периодом 25нс BYTE: in std_logic_vector (7 downto 0); -- байт, отсылаемый по RS232 SEND: in std_logic; -- управляющий сигнал - начать отправку байта по RS232 BUSY: out std_logic; -- сигнал занятости текущего устройства (0-свободен, 1-занят) RXD : out std_logic -- линия отправки данных по RS232 ); end entity;
architecture transmitter of transmitter_vhdl is type state_type is (s0, s1, s2, s3); signal state : state_type; -- автомат отправки байта по RS232 constant BAUD : natural range 0 to 347 := 347; -- выбор делителя частоты для скорости ~115273 (для скорости 115200) begin
process(CLK) variable delay : natural range 0 to 347; -- регистр задержки для выработки нужной частоты variable bit_cnt : natural range 0 to 10; -- счётчик отсылаемых бит
begin if (rising_edge(CLK)) then -- автомат отправки байта по RS232 case state is when s0 => BUSY <= '0'; RXD <= '1'; delay := 0; bit_cnt := 0; if (SEND = '1') then state <= s1; end if; when s1 => BUSY <= '1'; RXD <= '0'; state <= s2; when s2 => if (delay >= BAUD) then delay := 0; bit_cnt := bit_cnt + 1; state <= s3; else delay := delay + 1; end if; when s3 => if (bit_cnt < 10) then if (bit_cnt < 9) then RXD <= BYTE (bit_cnt - 1); else RXD <= '1'; end if;
state <= s2; else state <= s0; end if; end case; end if; end process; end transmitter;
 Рис. 11. Функциональная схема устройства для работы с последовательным портом на языке AHDL SUBDESIGN main_ahdl ( CLK : INPUT; -- входной тактовый сигнал с частотой 40МГц и периодом 25нс IN_BYTE[7..0] : INPUT; -- байт, принятый по RS232 SEND_RECEIVE : INPUT; -- сигнал переключения приёма и отправки данных, после схемы подавления дребезга контактов SBUSY : INPUT; -- сигнал занятости подчиненного устройства (0-свободен, 1-занят) OUT_BYTE[7..0] : OUTPUT; -- байт, отсылаемый по RS232 SEND : OUTPUT; -- управляющий сигнал - начать отправку байта по RS232 RECEIVE : OUTPUT; -- управляющий сигнал - начать приём байта по RS232 RESET : OUTPUT; -- сброс ведомых устройств (для вывода их из режима ожидания байта по RS232) )
VARIABLE r_state : MACHINE OF BITS(r_state_reg[2..0]) WITH STATES(rs0 = X"00", rs1 = X"01", rs2 = X"02", rs3 = X"03", rs4 = X"04"); -- описание состояний цифрового автомата s_state : MACHINE OF BITS(s_state_reg[2..0]) WITH STATES(ss0 = X"00", ss1 = X"01", ss2 = X"02", ss3 = X"03", ss4 = X"04"); -- описание состояний цифрового автомата
OUT_BYTE[7..0] : DFF; -- регистр для хранения выходных данных SEND : DFF; -- регистр управляющего сигнала RECEIVE : DFF; -- флаг приема управляющего сигнала по RS232 RESET : DFF; -- флаг сброса ведомых устройств (для вывода их из режима ожидания байта по RS232 - возврящение в нулевое состояние) send_cnt[2..0] : DFF; -- счетчик отправленных байт receive_cnt[2..0] : DFF; -- счетчик полученных байт buffer_bytes[31..0] : DFF; -- буфер для хранения принятых байт
BEGIN
OUT_BYTE[].clk = CLK; SEND.clk = CLK; RECEIVE.clk = CLK; RESET.clk = CLK; send_cnt[].clk = CLK; receive_cnt[].clk = CLK; buffer_bytes[].clk = CLK; r_state.clk = CLK; s_state.clk = CLK;
CASE SEND_RECEIVE IS --режим отправки данных WHEN B"0" => RECEIVE = B"0"; RESET = B"1";
buffer_bytes[] = buffer_bytes[]; CASE s_state IS WHEN ss0 => OUT_BYTE[] = X"00"; SEND = B"0";
send_cnt[] = send_cnt[]; receive_cnt[] = receive_cnt[]; IF (send_cnt[] < receive_cnt[]) THEN s_state = ss1; END IF; WHEN ss1 => CASE send_cnt[] IS WHEN X"0" => OUT_BYTE[] = buffer_bytes[7..0]; WHEN X"1" => OUT_BYTE[] = buffer_bytes[15..8]; WHEN X"2" => OUT_BYTE[] = buffer_bytes[23..16]; WHEN X"3" => OUT_BYTE[] = buffer_bytes[31..24]; WHEN OTHERS => OUT_BYTE[] = X"00"; END CASE; SEND = B"1";
send_cnt[] = send_cnt[]; receive_cnt[] = receive_cnt[]; s_state = ss2; r_state = rs0; WHEN ss2 => CASE send_cnt[] IS WHEN X"0" => OUT_BYTE[] = buffer_bytes[7..0]; WHEN X"1" => OUT_BYTE[] = buffer_bytes[15..8]; WHEN X"2" => OUT_BYTE[] = buffer_bytes[23..16]; WHEN X"3" => OUT_BYTE[] = buffer_bytes[31..24]; WHEN OTHERS => OUT_BYTE[] = X"00"; END CASE;
send_cnt[] = send_cnt[]; receive_cnt[] = receive_cnt[]; IF (SBUSY == B"1") THEN SEND = B"0"; s_state = ss3; ELSE SEND = B"1"; END IF; WHEN ss3 => CASE send_cnt[] IS WHEN X"0" => OUT_BYTE[] = buffer_bytes[7..0]; WHEN X"1" => OUT_BYTE[] = buffer_bytes[15..8]; WHEN X"2" => OUT_BYTE[] = buffer_bytes[23..16]; WHEN X"3" => OUT_BYTE[] = buffer_bytes[31..24]; WHEN OTHERS => OUT_BYTE[] = X"00"; END CASE; SEND = B"0";
receive_cnt[] = receive_cnt[]; IF (SBUSY == B"0") THEN send_cnt[] = send_cnt[] + 1; s_state = ss4; ELSE send_cnt[] = send_cnt[]; END IF; WHEN ss4 => OUT_BYTE[] = X"00"; SEND = B"0";
IF (send_cnt[] == receive_cnt[]) THEN send_cnt[] = X"0"; receive_cnt[] = X"0"; ELSE send_cnt[] = send_cnt[]; receive_cnt[] = receive_cnt[]; END IF; s_state = ss0; END CASE; --режим приема WHEN B"1" => OUT_BYTE[] = X"00"; SEND = B"0";
CASE r_state IS WHEN rs0 => RECEIVE = B"0"; RESET = B"0";
receive_cnt[] = receive_cnt[]; buffer_bytes[] = buffer_bytes[]; r_state = rs1; s_state = ss0; WHEN rs1 => RESET = B"0";
receive_cnt[] = receive_cnt[]; buffer_bytes[] = buffer_bytes[]; IF (SBUSY == B"1") THEN RECEIVE = B"0"; r_state = rs2; ELSE RECEIVE = B"1"; END IF; WHEN rs2 => RECEIVE = B"0"; RESET = B"0";
IF (SBUSY == B"0") THEN CASE receive_cnt[] IS WHEN X"0" => buffer_bytes[7..0] = IN_BYTE[]; receive_cnt[] = X"1"; r_state = rs3; WHEN X"1" => buffer_bytes[7..0] = buffer_bytes[7..0]; buffer_bytes[15..8] = IN_BYTE[]; receive_cnt[] = X"2"; r_state = rs3; WHEN X"2" => buffer_bytes[15..0] = buffer_bytes[15..0]; buffer_bytes[23..16] = IN_BYTE[]; receive_cnt[] = X"3"; r_state = rs3; WHEN X"3" => buffer_bytes[23..0] = buffer_bytes[23..0]; buffer_bytes[31..24] = IN_BYTE[]; receive_cnt[] = X"4"; r_state = rs4; WHEN OTHERS => buffer_bytes[] = buffer_bytes[]; receive_cnt[] = receive_cnt[]; END CASE; ELSE buffer_bytes[] = buffer_bytes[]; receive_cnt[] = receive_cnt[]; END IF; WHEN rs3 => RECEIVE = B"0"; RESET = B"1";
buffer_bytes[] = buffer_bytes[]; receive_cnt[] = receive_cnt[]; r_state = rs0; WHEN rs4 => RECEIVE = B"0"; RESET = B"1";
buffer_bytes[] = buffer_bytes[]; receive_cnt[] = receive_cnt[]; END CASE; END CASE; END;
SUBDESIGN txd_neg_edge_ahdl ( CLK : INPUT; -- входной тактовый сигнал с частотой 40МГц и периодом 25нс TXD : INPUT; -- линия приёма данных с RS232 SBUSY : INPUT; -- сигнал занятости подчиненного устройства (0-свободен, 1-занят) SRESET : INPUT; -- управляющий сигнал сброса NEG_EDGE : OUTPUT; -- вырабатываемый сигнал обнаружения среза (заднего фронта) сигнала на линии TXD ) VARIABLE state : MACHINE OF BITS(state_reg[1..0]) WITH STATES(s0 = X"00", s1 = X"01", s2 = X"02", s3 = X"03"); -- описание состояний цифрового автомата
NEG_EDGE : DFF; -- регистр для флага обнаружения среза (заднего фронта) сигнала intgr[3..0] : DFF; -- регистр для определения среза (заднего фронта) сигнала eflag : DFF; -- флаг, показывающий был ли обнаружен единичный уровень на линии TXD
BEGIN
NEG_EDGE.clk = CLK; intgr[].clk = CLK; eflag.clk = CLK; state.clk = CLK;
IF (SRESET == B"1") THEN state = s0; END IF;
CASE state IS WHEN s0 => NEG_EDGE = B"0"; eflag = B"0"; intgr[] = X"0"; IF (SRESET == B"0" AND SBUSY == B"1") THEN state = s1; END IF; WHEN s1 => IF (TXD == B"1" AND intgr[] < X"F") THEN intgr[] = intgr[] + 1; ELSIF (TXD == B"0" AND intgr[] > X"0") THEN intgr[] = intgr[] - 1; ELSE intgr[] = intgr[]; END IF; eflag = eflag; state = s2; WHEN s2 => intgr[] = intgr[]; IF (intgr[] == X"F") THEN eflag = B"1"; state = s1; ELSIF (intgr[] == X"0" AND eflag == B"1") THEN state = s3; ELSE eflag = eflag; state = s1; END IF; WHEN s3 => NEG_EDGE = B"1"; WHEN others => state = s0; END CASE; END;
CONSTANT BAUD = 347; -- выбор делителя частоты для скорости ~115273 (для скорости 115200) CONSTANT BAUD_2 = 174;
SUBDESIGN receiver_ahdl ( CLK : INPUT; -- входной тактовый сигнал с частотой 40МГц и периодом 25 нс TXD : INPUT; -- линия приёма данных с RS232 RECEIVE : INPUT; -- управляющий сигнал - начать приём байта по RS232 SRESET : INPUT; -- сигнал сброса ведомого устройства - txd_neg_edge NEG_EDGE : INPUT; -- сигнал обнаружения среза (заднего фронта) сигнала на линии TXD (начало start-bit) BYTE[7..0] : OUTPUT;-- выдача принятого байта RESET : OUTPUT; -- сброс ведомых устройств (для вывода их из режима ожидания байта по RS232) BUSY : OUTPUT; -- сигнал занятости текущего устройства (0-свободен, 1-занят) ) VARIABLE state : MACHINE OF BITS(state_reg[2..0]) WITH STATES(s0 = X"00", s1 = X"01", s2 = X"02", s3 = X"03", s4 = X"04"); -- описание состояний цифрового автомата
RESET : DFF; -- флаг сброса ведомых устройств (для вывода их из режима ожидания байта по RS232 - возврящение в нулевое состояние) BUSY : DFF; -- флаг занятости текущего устройства (0-свободен, 1-занят) delay[8..0] : DFF; -- регистр задержки для выработки нужной частоты bit_cnt[3..0] : DFF;-- счетчик отсылаемых бит data[7..0] : DFF; -- регистр хранения принимаемых бит поступающих с RS232
BEGIN
RESET.clk = CLK; BUSY.clk = CLK; delay[].clk = CLK; bit_cnt[].clk = CLK; data[].clk = CLK; state.clk = CLK;
BYTE[] = data[]; -- связать выхода с внутренним регистром IF (SRESET == B"1") THEN state = s0; END IF; -- сброс
-- автомат приёма байта по RS232 CASE state IS WHEN s0 => BUSY = B"0"; RESET = B"1"; delay[] = X"000"; bit_cnt[] = X"0"; data[] = data[]; IF (SRESET == B"0" AND RECEIVE == B"1") THEN state = s1; END IF; WHEN s1 => BUSY = B"1"; RESET = B"0";
delay[] = X"000"; bit_cnt[] = X"0"; data[] = data[]; IF (NEG_EDGE == B"1") THEN state = s2; END IF; WHEN s2 => --проверка нулевого уровня старт-бита BUSY = B"1"; RESET = B"0";
bit_cnt[] = bit_cnt[]; data[] = data[]; IF (delay[] >= BAUD_2) THEN IF (TXD == B"0") THEN delay[] = X"000"; state = s3; ELSE state = s0; END IF; ELSE delay[] = delay[] + 1; END IF; WHEN s3 => BUSY = B"1"; RESET = B"0";
IF (delay[] >= BAUD) THEN delay[] = X"000"; bit_cnt[] = bit_cnt[] + 1; data[6..0] = data[7..1]; data[7] = TXD; state = s4; ELSE delay[] = delay[] + 1; bit_cnt[] = bit_cnt[]; data[] = data[]; END IF; WHEN s4 => RESET = B"0";
bit_cnt[] = bit_cnt[]; data[] = data[]; IF (bit_cnt[] < X"8") THEN delay[] = X"000"; BUSY = B"1"; state = s3; ELSIF (delay[] >= BAUD) THEN --ожидаем стоп бита delay[] = delay[]; BUSY = B"0"; ELSE BUSY = B"1"; delay[] = delay[] + 1; END IF; END CASE; END;
CONSTANT BAUD = 347; --выбор делителя частоты для скорости ~115273 (для скорости 115200)
SUBDESIGN transmitter_ahdl ( CLK : INPUT; -- входной тактовый сигнал с частотой 40 МГц и периодом 25нс BYTE[7..0]: INPUT; -- сигнал занятости текущего устройства (0-свободен, 1-занят) SEND: INPUT; -- управляющий сигнал - начать отправку байта по RS232 BUSY: OUTPUT; -- сигнал занятости текущего устройства (0-свободен, 1-занят) RXD : OUTPUT; -- линия отправки данных по RS232 ) VARIABLE state : MACHINE OF BITS(state_reg[1..0]) WITH STATES(s0 = X"00", s1 = X"01", s2 = X"02", s3 = X"03"); -- описание состояний цифрового автомата
BUSY : DFF; -- сигнал занятости RXD : DFF; -- линия отправки данных по RS232 delay[8..0] : DFF; -- регистр задержки для выработки нужной частоты bit_cnt[3..0] : DFF; -- счётчик отсылаемых бит
BEGIN
BUSY.clk = CLK; RXD.clk = CLK; delay[].clk = CLK; bit_cnt[].clk = CLK; state.clk = CLK;
-- автомат отправки байта по RS232 CASE state IS WHEN s0 => BUSY = B"0"; RXD = B"1"; delay[] = X"00"; bit_cnt[] = X"0"; IF (SEND == B"1")THEN state = s1; END IF; -- WHEN s1 => BUSY = B"1"; CASE bit_cnt[] IS WHEN X"0" => RXD = B"0"; WHEN X"1" => RXD = BYTE[0]; WHEN X"2" => RXD = BYTE[1]; WHEN X"3" => RXD = BYTE[2]; WHEN X"4" => RXD = BYTE[3]; WHEN X"5" => RXD = BYTE[4]; WHEN X"6" => RXD = BYTE[5]; WHEN X"7" => RXD = BYTE[6]; WHEN X"8" => RXD = BYTE[7]; WHEN X"9" => RXD = B"1"; END CASE; IF (delay[] >= BAUD) THEN delay[] = X"00"; bit_cnt[] = bit_cnt[] + 1; state = s2; ELSE bit_cnt[] = bit_cnt[]; delay[] = delay[] + 1; END IF; WHEN s2 => BUSY = B"1"; CASE bit_cnt[] IS WHEN X"0" => RXD = B"0"; WHEN X"1" => RXD = BYTE[0]; WHEN X"2" => RXD = BYTE[1]; WHEN X"3" => RXD = BYTE[2]; WHEN X"4" => RXD = BYTE[3]; WHEN X"5" => RXD = BYTE[4]; WHEN X"6" => RXD = BYTE[5]; WHEN X"7" => RXD = BYTE[6]; WHEN X"8" => RXD = BYTE[7]; WHEN X"9" => RXD = B"1"; END CASE;
bit_cnt[] = bit_cnt[]; IF (bit_cnt[] < X"A") THEN state = s1; ELSE state = s0; END IF; WHEN OTHERS => state = s0; END CASE; END; |