Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: модуль энкодеров на верилоге
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
sergey sva
Модуль энкодеров делаю для этой платы. Набросал заготовку, только заготовку.
Какие замечания, что бы сразу переделать? Может кто помочь захочет. )
CODE
//*************************************************************************//
// |------|
// ____| |____ A
//
// |------|
// _____| |____ B
//
// R ноль метка
//************************************************************************//
module ENCODERS(
ENCOD1_A,ENCOD1_B,ENCOD1_R, //
ENCOD2_A,ENCOD2_B,ENCOD2_R, //
ENCOD3_A,ENCOD3_B,ENCOD3_R, //Сигналы от энкодеров
SEL_MOD_E,ADRES_MOD,CLCK, //Сигнал от модуля clck_manage. Сигнал ADRES_MOD выдает адреса всех модулей.
//после трансляции адреса через 5 тактов устанавливается сигнал разрешения SEL_MOD_E
//Если адрес совпадает с адресом этого модуля thisadresmod, то можно записывть данные в
//двух портовую память.
WRITE_EN_MEMORI, //Разрешение записи 1 = запись; 0 = чтение.
RST_MEMORY, //сброс выхода памяти.
DATA_TO_MEMORY, //данные для записи.
DATA_FROM_MEMORY, //данные для чтения.
MEMORY_ADRES //Адрес чтение / записи.

);

input ENCOD1_A,ENCOD1_B,ENCOD1_R,ENCOD2_A,ENCOD2_B,ENCOD2_R,ENCOD3_A,ENCOD3_B,ENCOD3_R
, SEL_MOD_E, CLCK;
input[3:0] ADRES_MOD;
output WRITE_EN_MEMORI, RST_MEMORY;
output[31:0] DATA_TO_MEMORY;
input[31:0] DATA_FROM_MEMORY;
output[9:0] MEMORY_ADRES;
// Адрес этого модуля
parameter [3:0] thisadresmod = 4'h1;

//-----------------------------------------------------------------//
// Выбор модуля. Если модуль выбран можно читать писать в память. >>
reg select_module_ok;
reg wrmem,rstmem;
reg[31:0] dat_to_mem;
reg[9:0] adrmem;

always @( SEL_MOD_E )
begin

if(SEL_MOD_E == 1)
begin
if(ADRES_MOD[3:0] == thisadresmod[3:0] )
begin
select_module_ok <= 1;
end
else begin
select_module_ok <= 0;

end
end
else begin
select_module_ok <= 0;
end
end

assign WRITE_EN_MEMORI = select_module_ok ? wrmem : 1'bZ;
assign RST_MEMORY = select_module_ok ? rstmem : 1'bZ;
assign DATA_TO_MEMORY = select_module_ok ? dat_to_mem : 32'bZ;
assign MEMORY_ADRES = select_module_ok ? adrmem : 10'bZ;
// Выбор модуля. Если модуль выбран можно читать писать в память. <<
//------------------------------------------------------------------//

//------------------------------------------------------------------//
// Главный процесс модуля энкодеров >>
reg[31:0] encode1_value;
reg[31:0] encode2_value;
reg[31:0] encode3_value;
always @(posedge CLCK)
begin

//----------------------------//
if(select_module_ok == 1)
begin

// Здесь моно читать писать в память.
// Сигналы (wrmem, rstmem; dat_to_mem[31:0], DATA_FROM_MEMORY[31:0]; adrmem[9:0]wink.gif

// мапинг памяти
// энкодер 1 смещение в памяти 0x0
// адрес 0 "множитель" формат флоат 32 бита (для чтения,записывается с компьютера)
// адрес 4 "позиция" формат флоат, получается из encode1_value * "множитель".

// энкодер 2 смещение в памяти 0x30
// адрес 30 "множитель" формат флоат 32 бита (для чтения,записывается с компьютера)
// адрес 34 "позиция" формат флоат, получается из encode2_value * "множитель".

// энкодер 3 смещение в памяти 0x60
// адрес 60 "множитель" формат флоат 32 бита (для чтения,записывается с компьютера)
// адрес 64 "позиция" формат флоат, получается из encode3_value * "множитель".




end
//---------------------------//


//сигналы от энкодеров
//(ENCOD1_A || ENCOD1_B || ENCOD1_R || ENCOD2_A || ENCOD2_B || ENCOD2_R || ENCOD3_A || ENCOD3_B || ENCOD3_R)

//переменные для результат подсчета
// encode1_value[31:0]; encode2_value[31:0]; encode3_value[31:0];



end

// Главный процесс модуля энкодеров <<
//---------------------------------------------------------------------//




endmodule
Maverick
я не вижу саму обработку енкодеров
могу привести описание обработки енкодера, правда на VHDL
CODE
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity QuadratureDecoder is
Port ( QuadA : in STD_LOGIC;
QuadB : in STD_LOGIC;
Clk : in STD_LOGIC;
Position : out STD_LOGIC_VECTOR (7 downto 0));
end QuadratureDecoder;

architecture Behavioral of QuadratureDecoder is

signal QuadA_Delayed: STD_LOGIC_VECTOR (2 downto 0);
signal QuadB_Delayed: STD_LOGIC_VECTOR (2 downto 0);

signal Count_Enable: STD_LOGIC;
signal Count_Direction: STD_LOGIC;

signal Count: STD_LOGIC_VECTOR(7 downto 0);

begin

process (Clk)
begin
if Clk='1' and Clk'event then
QuadA_Delayed <= (QuadA_Delayed(1), QuadA_Delayed(0), QuadA);
QuadB_Delayed <= (QuadB_Delayed(1), QuadB_Delayed(0), QuadB);
if Count_Enable='1' then
if Count_Direction='1' then
Count <= Count + 1;
Position <= Count;
else
Count <= Count - 1;
Position <= Count;
end if;
end if;
end if;
end process;

Count_Enable <= QuadA_Delayed(1) xor QuadA_Delayed(2) xor QuadB_Delayed(1) xor QuadB_Delayed(2);
Count_Direction <= QuadA_Delayed(1) xor QuadB_Delayed(2);

end Behavioral;


PS если потребуется могу дать тестбенч...
Iptash
Посмотри http://www.fpga4fun.com/QuadratureDecoder.html
sergey sva
Цитата(Maverick @ Aug 8 2013, 21:35) *
я не вижу саму обработку енкодеров
могу привести описание обработки енкодера, правда на VHDL
CODE
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity QuadratureDecoder is
Port ( QuadA : in STD_LOGIC;
QuadB : in STD_LOGIC;
Clk : in STD_LOGIC;
Position : out STD_LOGIC_VECTOR (7 downto 0));
end QuadratureDecoder;

architecture Behavioral of QuadratureDecoder is

signal QuadA_Delayed: STD_LOGIC_VECTOR (2 downto 0);
signal QuadB_Delayed: STD_LOGIC_VECTOR (2 downto 0);

signal Count_Enable: STD_LOGIC;
signal Count_Direction: STD_LOGIC;

signal Count: STD_LOGIC_VECTOR(7 downto 0);

begin

process (Clk)
begin
if Clk='1' and Clk'event then
QuadA_Delayed <= (QuadA_Delayed(1), QuadA_Delayed(0), QuadA);
QuadB_Delayed <= (QuadB_Delayed(1), QuadB_Delayed(0), QuadB);
if Count_Enable='1' then
if Count_Direction='1' then
Count <= Count + 1;
Position <= Count;
else
Count <= Count - 1;
Position <= Count;
end if;
end if;
end if;
end process;

Count_Enable <= QuadA_Delayed(1) xor QuadA_Delayed(2) xor QuadB_Delayed(1) xor QuadB_Delayed(2);
Count_Direction <= QuadA_Delayed(1) xor QuadB_Delayed(2);

end Behavioral;


PS если потребуется могу дать тестбенч...

Благодарю. Сорри за не скромный вопрос,) первый вариант чем то не понравился?
Он нагляднее мне так показалось. Если сравнить с диаграмкой
Нажмите для просмотра прикрепленного файла
Maverick
Цитата(sergey sva @ Aug 9 2013, 10:23) *
Благодарю. Сорри за не скромный вопрос,) первый вариант чем то не понравился?
Он нагляднее мне так показалось. Если сравнить с диаграмкой

у меня было 2 варианта, вот этот:

CODE
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity Encoder is
Port ( clk : in STD_LOGIC;
A : in STD_LOGIC;
B : in STD_LOGIC;
Position : out STD_LOGIC_VECTOR (31 downto 0));
end Encoder;

architecture Behavioral of Encoder is
type zustaende is (Z00, Z01, Z11, Z10);
signal z : zustaende := Z00;
signal p : integer := 0;
signal i : std_logic_vector(1 downto 0);
signal e : std_logic_vector(1 downto 0);
begin
process begin
wait until rising_edge(clk);
i <= A & B;
e <= i;
end process;

process
variable cu, cd : std_logic := '0';
begin
wait until rising_edge(clk);
cu := '0';
cd := '0';
case z is
when Z00 => if (e = "01") then z <= Z01; cu := '1';
elsif (e = "10") then z <= Z10; cd := '1';
end if;
when Z01 => if (e = "11") then z <= Z11; cu := '1';
elsif (e = "00") then z <= Z00; cd := '1';
end if;
when Z11 => if (e = "10") then z <= Z10; cu := '1';
elsif (e = "01") then z <= Z01; cd := '1';
end if;
when Z10 => if (e = "00") then z <= Z00; cu := '1';
elsif (e = "11") then z <= Z11; cd := '1';
end if;
end case;
if (cu='1') then p <= p+1;
elsif (cd='1') then p <= p-1;
end if;
end process;

Position <= std_logic_vector(to_signed(p,32));
end Behavioral;

и тот который сейчас в моем сообщении ранее.
Вечером решил сравнить - оказалось, что описание, которое приведено в данном сообщении (до замены) занимает чуть больше логики... sm.gif
sergey sva
Maverick спасибо. сделал на верелоге по вашему примеру, номер 2.
Правда пока не пробовал собирать, на этом компьютере нет ксалинкса.

CODE
//*************************************************************************//
// |------|
// ____| |____ A
//
// |------|
// _____| |____ B
//
// R ноль метка
//************************************************************************//
module ENCODERS(
ENCOD1_A,ENCOD1_B,ENCOD1_R, //
ENCOD2_A,ENCOD2_B,ENCOD2_R, //
ENCOD3_A,ENCOD3_B,ENCOD3_R, //Сигналы от энкодеров
SEL_MOD_E,ADRES_MOD,CLCK, //Сигнал от модуля clck_manage. Сигнал ADRES_MOD выдает адреса всех модулей.
//после трансляции адреса через 5 тактов устанавливается сигнал разрешения SEL_MOD_E
//Если адрес совпадает с адресом этого модуля thisadresmod, то можно записывть данные в
//двух портовую память.
WRITE_EN_MEMORI, //Разрешение записи 1 = запись; 0 = чтение.
RST_MEMORY, //сброс выхода памяти.
DATA_TO_MEMORY, //данные для записи.
DATA_FROM_MEMORY, //данные для чтения.
MEMORY_ADRES //Адрес чтение / записи.

);

input ENCOD1_A,ENCOD1_B,ENCOD1_R,ENCOD2_A,ENCOD2_B,ENCOD2_R,ENCOD3_A,ENCOD3_B,ENCOD3_R
, SEL_MOD_E, CLCK;
input[3:0] ADRES_MOD;
output WRITE_EN_MEMORI, RST_MEMORY;
output[31:0] DATA_TO_MEMORY;
input[31:0] DATA_FROM_MEMORY;
output[9:0] MEMORY_ADRES;
// Адрес этого модуля
parameter [3:0] thisadresmod = 4'h1;

//-----------------------------------------------------------------//
// Выбор модуля. Если модуль выбран можно читать писать в память. >>
reg select_module_ok;
reg wrmem,rstmem;
reg[31:0] dat_to_mem;
reg[9:0] adrmem;

always @( SEL_MOD_E )
begin

if(SEL_MOD_E == 1)
begin
if(ADRES_MOD[3:0] == thisadresmod[3:0] )
begin
select_module_ok <= 1;
end
else begin
select_module_ok <= 0;

end
end
else begin
select_module_ok <= 0;
end
end

assign WRITE_EN_MEMORI = select_module_ok ? wrmem : 1'bZ;
assign RST_MEMORY = select_module_ok ? rstmem : 1'bZ;
assign DATA_TO_MEMORY = select_module_ok ? dat_to_mem : 32'bZ;
assign MEMORY_ADRES = select_module_ok ? adrmem : 10'bZ;
// Выбор модуля. Если модуль выбран можно читать писать в память. <<
//------------------------------------------------------------------//

//------------------------------------------------------------------//
// Главный процесс модуля энкодеров >>
reg[31:0] encode1_value; // значение счетчика.
reg[31:0] encode2_value;
reg[31:0] encode3_value;
reg[31:0] encode1_turnpulse; // количество импульсов за оборот энкодера.
reg[31:0] encode2_turnpulse;
reg[31:0] encode3_turnpulse;
always @(posedge CLCK)
begin

//----------------------------//
if(select_module_ok == 1)
begin

// Здесь моно читать писать в память.
// Сигналы (wrmem, rstmem; dat_to_mem[31:0], DATA_FROM_MEMORY[31:0]; adrmem[9:0]wink.gif

// мапинг памяти
// энкодер 1 смещение в памяти 0x0
// адрес 0 "множитель" формат флоат 32 бита (для чтения,записывается с компьютера)
// адрес 4 "позиция" формат флоат, получается из encode1_value * "множитель".
// адрес 8 "импульс/оборот" количество импульсов на оборо энкодера.

// энкодер 2 смещение в памяти 0x30
// адрес 30 "множитель" формат флоат 32 бита (для чтения,записывается с компьютера)
// адрес 34 "позиция" формат флоат, получается из encode2_value * "множитель".
// адрес 38 "импульс/оборот" количество импульсов на оборо энкодера.

// энкодер 3 смещение в памяти 0x60
// адрес 60 "множитель" формат флоат 32 бита (для чтения,записывается с компьютера)
// адрес 64 "позиция" формат флоат, получается из encode3_value * "множитель".
// адрес 68 "импульс/оборот" количество импульсов на оборо энкодера.


//работа с пмятью пока ее здесь нет sad.gif

end
//---------------------------//


// Фильтр сигналов,энкодера 1
wire[2:0] encoder1;
DIG_FILTER filter1a(CLCK,ENCOD1_A,encoder1[0]);
DIG_FILTER filter1b(CLCK,ENCOD1_B,encoder1[1]);
DIG_FILTER filter1r(CLCK,ENCOD1_R,encoder1[2]);

// Фильтр сигналов,энкодера 2
wire[2:0] encoder2;
DIG_FILTER filter2a(CLCK,ENCOD2_A,encoder2[0]);
DIG_FILTER filter2b(CLCK,ENCOD2_B,encoder2[1]);
DIG_FILTER filter2r(CLCK,ENCOD2_R,encoder2[2]);

// Фильтр сигналов,энкодера 3
wire[2:0] encoder3;
DIG_FILTER filter3a(CLCK,ENCOD3_A,encoder3[0]);
DIG_FILTER filter3b(CLCK,ENCOD3_B,encoder3[1]);
DIG_FILTER filter3r(CLCK,ENCOD3_R,encoder3[2]);


//сигналы от энкодеров,после фильтра, на модули счетчиков
ENCODER enc1(encoder1[0],encoder1[1],encoder1[2],CLCK,encode1_value,encode1_turnpulse);
ENCODER enc2(encoder1[0],encoder1[1],encoder1[2],CLCK,encode1_value,encode1_turnpulse);
ENCODER enc3(encoder1[0],encoder1[1],encoder1[2],CLCK,encode1_value,encode1_turnpulse);



end

// Главный процесс модуля энкодеров <<
//---------------------------------------------------------------------//
endmodule//!
//---------------------------------------------------------------------//


//---------------------------------------------------------------------//
//---Цифровой фильтр --------------------------------------------------//
module DIG_FILTER(CLCK, D, Q);
//Сигналы модуля
input clk;
input D;
output Q;

reg[3:0] filter;
always @ (posedge clk)
begin
filter <= {filter[2:0], D};

case(filter)
4'b0000: Q <= 0;
4'b1111: Q <= 1;
default: Q <= Q;
endcase
end
endmodule
//---Цифровой фильтр --------------------------------------------------//
//---------------------------------------------------------------------//

//---------------------------------------------------------------------//
//---Энкодер Счетчик --------------------------------------------------//

module ENCODER(A,B,R,CLCK,POSITION,TURNPULSEVAL);
// Сигналы
input A;
input B;
input R;
input CLCK;
output[31:0] POSITION;
output[31:0] TURNPULSEVAL;
// Сигналы


reg[31:0] position;
position = 0;
reg[31:0] turnpulse;
turnpulse = 0;
reg[1:0] z;
z = 2'b00;
reg[1:0] e;
e = 2'b00;
reg[1:0] i;
i = 2'b00;
reg count_up;
count_up = 1'b0;
reg count_down;
count_down = 1'b0;
always @ (posedge clk)
begin
i <= {A,B};
e <= i;
count_down = 1'b0;
count_up = 1'b0;

case(z)
2'b00: if(e[1:0] == 2'b01)
begin
z[1:0] <= 2'b01; count_up = 1'b1;
end
else if(e[1:0] == 2'b10)
begin
z[1:0] <= 2'b10; count_down = 1'b1;
end

2'b01: if(e[1:0] == 2'b11)
begin
z[1:0] <= 2'b11; count_up = 1'b1;
end
else if(e[1:0] == 2'b00)
begin
z[1:0] <= 2'b00; count_down = 1'b1;
end

2'b11: if(e[1:0] == 2'b10)
begin
z[1:0] <= 2'b10; count_up = 1'b1;
end
else if(e[1:0] == 2'b01)
begin
z[1:0] <= 2'b01; count_down = 1'b1;
end

2'b10: if(e[1:0] == 2'b00)
begin
z[1:0] <= 2'b00; count_up = 1'b1;
end
else if(e[1:0] == 2'b11)
begin
z[1:0] <= 2'b11; count_down = 1'b1;
end
endcase

if(count_up == 1'b1)
begin
position <= position +1;
end
if(count_down == 1'b1)
begin
position <= position -1;
end

end

always @ (posedge R)
begin

if((A == 1'b1) && (B == 1'b1))
begin
turnpulse[31:0] <= position[31:0];
end

end

assign POSITION = position;
assign TURNPULSEVAL = turnpulse;

endmodule
//---Энкодер Счетчик --------------------------------------------------//
//---------------------------------------------------------------------//
Maverick
Цитата(sergey sva @ Aug 9 2013, 15:56) *
Maverick спасибо. сделал на верелоге по вашему примеру, номер 2.

Всегда рад помочь...
Пожалуйста sm.gif
sergey sva
Добрался для ксалинкса , попробовал собрал, исправил ошибки которые наделал, все считает.
Только не нравиться как я сделал подсчет импульсов за оборот, может посоветуете как сделать это красивее?
Импульс R приходит когда датчик делает полный оборот.

CODE
//---------------------------------------------------------------------//
//---Энкодер Счетчик --------------------------------------------------//
module ENCODER(A,B,R,CLCK,POSITION,TURNPULSEVAL);
// Сигналы
input A;
input B;
input R;
input CLCK;
output[31:0] POSITION;
output[31:0] TURNPULSEVAL;
// Сигналы

reg[31:0] position;
reg[31:0] turnpulse;

reg count_up,count_down;
reg [1:0] z,e;

reg[31:0] count_up_r;
reg[31:0] count_down_r;
reg fagindex,norim;



// инициализация переменных
initial
begin
position = 0;
turnpulse = 0;

e = 2'b00;
z = 2'b00;

count_up =1'b0;
count_down =1'b0;

count_up_r = 32'd0;
count_down_r = 32'd0;
fagindex =1'b0;
norim =1'b0;
end
// инициализация переменных


always @ (posedge CLCK)
begin
e = {A,B};

count_down <=1 'b0;
count_up <= 1'b0;

case(z)
2'b00: if(e[1:0] == 2'b01)
begin
z[1:0] <= 2'b01;
count_up <= 1'b1;

end
else if(e[1:0] == 2'b10)
begin
z[1:0] <= 2'b10;
count_down <= 1'b1;

end

2'b01: if(e[1:0] == 2'b11)
begin
z[1:0] <= 2'b11;
//count_up <= 1'b1;

end
else if(e[1:0] == 2'b00)
begin
z[1:0] <= 2'b00;
//count_down <= 1'b1;

end

2'b11: if(e[1:0] == 2'b10)
begin
z[1:0] <= 2'b10;
//count_up <= 1'b1;

end
else if(e[1:0] == 2'b01)
begin
z[1:0] <= 2'b01;
//count_down <= 1'b1;
end

2'b10: if(e[1:0] == 2'b00)
begin
z[1:0] <= 2'b00;
//count_up <= 1'b1;
end
else if(e[1:0] == 2'b11)
begin
z[1:0] <= 2'b11;
//count_down <= 1'b1;
end
endcase


if(count_up)
begin
position<= position +1;
count_up_r <= count_up_r +1;

end
else if(count_down)
begin
position<= position -1;
count_down_r <= count_down_r +1;

end





if((count_up_r[31:0] > 32'd0) && (count_down_r[31:0] > 32'd0))
begin

if(norim)
begin
fagindex <= 1'b0;
count_up_r <=0;
count_down_r<=0;

end
else begin
fagindex <= 1'b1;
end

end



end



always @ (posedge R)
begin

if(fagindex == 1'b0)
begin

if((count_up_r[31:0] > 32'd0) && (count_down_r[31:0] == 32'd0))
begin
turnpulse[31:0] <= count_up_r;
end
else if ((count_up_r[31:0] == 32'd0) && (count_down_r[31:0] > 32'd0))
begin
turnpulse[31:0] <= count_down_r;
end
norim <= 1'b0;
end
else begin
norim <= 1'b1;

end

end

assign POSITION = position;
assign TURNPULSEVAL = turnpulse;

endmodule
//---Энкодер Счетчик --------------------------------------------------//
//---------------------------------------------------------------------//
sergey sva
Может быть кто подскажет еще какие сайты или коды для работы с энкодерами, буду благодарен.
PS Не для того что бы взять и использовать рабочий код, а для того что бы сравнить что есть,что мне нужно , и потом сделать лучше))
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.