CPLD如何根据一个输入波形输出如图的波形
EPM570t100C5N 编程如何实现如图,输入波形输入CPLD,CPLD根据这个波形产生输出波形输出?最好是VHDL 本帖最后由 NJ8888 于 2015-11-26 16:31 编辑除了第一个波形,后面三个一样的?
还有,输入脉冲时间参数固定的吗? 本帖最后由 NJ8888 于 2015-11-26 16:40 编辑
我仔细看了下,每组其实一样,只是楼主你第一个波形之前的部分没画出来是吧.如果输入波形时间固定,那输出最简单,如果不固定,那要测量后定输出,但是有问题,你第一个脉冲一半处,输出就要下跳,这不能实现,因为测量没完成.变通的办法输出延时滞后到第一个负脉冲完成之后,如果你要相位保持现在这样,前提你的输入是恒定的-------------------------------------------我看的不仔细,前面作废.实现很简单,对第一个脉冲输出2mm,第二个输出19ms,再加上超时以便重新同步下一组两个脉冲 NJ8888 发表于 2015-11-26 16:29
除了第一个波形,后面三个一样的?
都是一样的,第一个波形初始状态,你就看第二个和第三个怎么实现,用状态机吗 NJ8888 发表于 2015-11-26 16:32
还有,输入脉冲时间参数固定的吗?
输入脉冲时间是固定的 NJ8888 发表于 2015-11-26 16:32
还有,输入脉冲时间参数固定的吗?
第一次用CPLD,不知道从哪下手,第一个脉冲不看,就从第二个开始,编程思路能说一下吗 本帖最后由 NJ8888 于 2015-11-26 16:43 编辑
你给出一组内高电平时间参数以及两组之间高电平时间参数,还有输出脉冲的分辨率(决定用多少频率控制时钟) linbo411 发表于 2015-11-26 16:40
第一次用CPLD,不知道从哪下手,第一个脉冲不看,就从第二个开始,编程思路能说一下吗 ...
我思路是检测输入波形的下降沿,然后延时跳变。但是我没办法写下去了 状态机,检测电平,时钟频率高点就行了 linbo411 发表于 2015-11-26 16:41
我思路是检测输入波形的下降沿,然后延时跳变。但是我没办法写下去了
思路是状态记忆记住是第一个还是第二个负脉冲,然后有个计时器,时间超过同组之间的高电平时间就复位状态以便接收下一组第一个脉冲 linbo411 发表于 2015-11-26 16:41
我思路是检测输入波形的下降沿,然后延时跳变。但是我没办法写下去了
做一个计数器,在检测到下降沿的时候清零,延迟你要的时钟,再变状态 chenchaoting 发表于 2015-11-26 16:45
做一个计数器,在检测到下降沿的时候清零,延迟你要的时钟,再变状态
在一个进程里不能对端口赋两次值,我思路是检测到输入信号下降沿,输出高电平,延时2ms输出低电平,再检测到第二个下降沿输出高电平,延时19ms输出低电平,但是只能对端口赋一次值怎么回事呢? linbo411 发表于 2015-11-26 16:49
在一个进程里不能对端口赋两次值,我思路是检测到输入信号下降沿,输出高电平,延时2ms输出低电平,再检 ...
晚上吃过饭有空就帮你写一个,你先告诉我输出分辨率以及两个高电平时间范围 一个上升沿输出一个低电平 我的帖子有边沿触发单稳态HDL linbo411 发表于 2015-11-26 16:49
在一个进程里不能对端口赋两次值,我思路是检测到输入信号下降沿,输出高电平,延时2ms输出低电平,再检 ...
谁跟你说只能赋值一次呢,你用不同的CASE 赋不同的值就行了 NJ8888 发表于 2015-11-26 16:51
晚上吃过饭有空就帮你写一个,你先告诉我输出分辨率以及两个高电平时间范围 ...
我仔细看看需要的功能 NJ8888 发表于 2015-11-26 16:51
晚上吃过饭有空就帮你写一个,你先告诉我输出分辨率以及两个高电平时间范围 ...
两个高电平时间范围是指什么? NJ8888 发表于 2015-11-26 16:51
晚上吃过饭有空就帮你写一个,你先告诉我输出分辨率以及两个高电平时间范围 ...
CPLD时钟是10M时钟,我做了一个8分频器得到1.25MHZ频率,CPLD有一个输入时钟就是图上的,是单片机产生的,CPLD需要根据单片机的输入时钟,输出如图的波形,第一个负脉冲产生的高电平时间是2ms,第二个负脉冲产生的高电平时间是19ms,你帮我写个程序帮我打开以下思路 chenchaoting 发表于 2015-11-26 16:58
谁跟你说只能赋值一次呢,你用不同的CASE 赋不同的值就行了
if语句可以吗,我怎么编译不过去 linbo411 发表于 2015-11-26 17:29
if语句可以吗,我怎么编译不过去
楼上帮你写一个你就明白了 哪有那么啰嗦,就是一个单稳态触发器而已。 always @(posedge clk) input_r <= input;
assign trig = {input_r, input} == 2'b01;
always @(posedge clk)
if(trig) timer <= xxxxxx;
else if(timer != 0) timer <= timer - 1;
assign output = (timer == 0); agilityChen 发表于 2015-11-26 17:44
always @(posedge clk) input_r
你这里没有用到我输入波形 linbo411 发表于 2015-11-26 17:28
CPLD时钟是10M时钟,我做了一个8分频器得到1.25MHZ频率,CPLD有一个输入时钟就是图上的,是单片机产生的, ...
我看出输出参数,我问的是输入脉冲的高电平 低电平参数,还有你输出2ms 19ms的分辨精度 NJ8888 发表于 2015-11-26 18:45
我看出输出参数,我问的是输入脉冲的高电平 低电平参数,还有你输出2ms 19ms的分辨精度 ...
10 ms 11ms 9ms ,49ms NJ8888 发表于 2015-11-26 18:45
我看出输出参数,我问的是输入脉冲的高电平 低电平参数,还有你输出2ms 19ms的分辨精度 ...
分辨率1us 本帖最后由 NJ8888 于 2015-11-26 19:53 编辑
signal h_level_count,out_count: integer rang 0 to 32767;
signal temp_count: integer rang 0 to 7;
signal temp_pulse,first_flag: std_logic;
--中间脉冲发生器,因为你输入负脉冲宽度10ms,而输出2ms,19ms两种,跨度在两者之间,直接用输入脉冲电平不好处理输出,
--所以先用中间脉冲把输入搞成5us的负脉冲,使它小于2ms的输出脉冲,类似于微分
process(clk1MHz,inpulse)
begin
if rising_edge(clk1MHz) then
if inpulse='1' then
temp_count<=0;
temp_pulse<='1';
else
temp_count<=tempcount+1;
if temp_count<5 then
temp_pulse<='0';
else
temp_count<=5;
temp_pulse<='1';
end if;
end if;
end if;
end process;
process(clk1MHz,temp_pulse)
begin
if falling_edge(clk1MHz) then
if temp_pulse='1' then
if out_count>0 then
out_count<=out_count+1;
if first_flag='1' then --第一个触发脉冲
if out_count<2000 then
dout<='1';
else
out_count<=2000; --输出2ms后停止
dout<='0';
first_flag<='0';
end if;
else
if out_count<19000 then
dout<='1';
else
out_count<=19000; --输出2ms后停止
dout<='0';
end if;
end if;
end if;
h_lvevl_count<=h_level_count+1;
if h_level_count>20000 then --脉冲组间隔49ms,组内10ms,以20ms为判断门限
first_flag<='1';
h_level_count<=20000;
end if;
else
h_lvevl_count<=0;
dout<='1';
out_count<=5; --因为temp_pulse宽度是5,所以宽度计数初始值位5;
end if;
end if;
end process; NJ8888 发表于 2015-11-26 19:49
signal h_level_count,out_count: integer rang 0 to 32767;
signal temp_count: integer rang 0 to 7;
sig ...
非常感谢,我好好的读一下 http://www.amobbs.com/thread-5597618-1-1.html NJ8888 发表于 2015-11-26 19:49
signal h_level_count,out_count: integer rang 0 to 32767;
signal temp_count: integer rang 0 to 7;
sig ...
我老是用单片机的思维去想,有一点搞不明白,为什么要弄个中间脉冲,直接在下降沿处理不行么 直接以信号下降沿处理不好计数延时 NJ8888 发表于 2015-11-26 20:38
直接以信号下降沿处理不好计数延时
我一开始是只要检测到信号的下降沿,开起计数,并复位计数,但是编译通过不了,
process(Wave1_XOR_Wave2,VFCLKDIV8,CountEN)
begin
if Wave1_XOR_Wave2 'event and Wave1_XOR_Wave2 ='0' then-- 信号输入A下降沿
CTL_FREQ_Temp <= '1';
Flag_CTL_FREQ <= not Flag_CTL_FREQ;
Delayms <= "00000000000000000";--复位延时
CountEN <= '1';--允许延时
else
end if;
-- if VFCLKDIV8 'event and VFCLKDIV8 ='1' then-- 时钟上升沿
-- if CountEN = '1' then
-- if Flag_CTL_FREQ ='1' then--
-- if Delayms = "10011100010" then--1ms
--
-- end if;
-- if Delayms = "11111010000" then--2ms
-- --CTL_FREQ_Temp <= '0';
-- end if;
-- else--
-- if Delayms = "1111010000100100" then--49ms
---- --CTL_FREQ_Temp <= '0';
-- end if;
-- end if;
-- end if;
-- end if; CountEN <= '1';--允许延时
else
这里没代码,要把else去掉
end if; NJ8888 发表于 2015-11-26 20:49
CountEN
编译就出现这个错误,好像是 CTL_FREQ_Temp <= '1';这句话在两个地方赋值,我这种写法对吗? 从你给的片段看,这句没问题,有问题的是else下面空的 NJ8888 发表于 2015-11-26 21:00
从你给的片段看,这句没问题,有问题的是else下面空的
else 去掉了也不通过,老是提示上面哪个,我把if Wave1_XOR_Wave2 'event and Wave1_XOR_Wave2 ='0' then-- 信号输入A下降沿
CTL_FREQ_Temp <= '1';
Flag_CTL_FREQ <= not Flag_CTL_FREQ;
Delayms <= "00000000000000000";--复位延时
CountEN <= '1';--允许延时
这个里面的 CTL_FREQ_Temp <= '1'; 和下面出现对这个赋值的语句只能保留一个编译就通过了,所以我郁闷了,为什么不能赋值,我是这么定义的signal CTL_FREQ_Temp: std_logic :='0';
你下面不是已经注释掉了吗?我看只有一处赋值,没问题 本帖最后由 linbo411 于 2015-11-27 07:56 编辑
NJ8888 发表于 2015-11-26 21:09
你下面不是已经注释掉了吗?我看只有一处赋值,没问题
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
Entity ControlWave is
port(
Sysclk_in :instd_logic; -- 10M时钟输入
Wave1_XOR_Wave2 :instd_logic; -- 基准波形1输入
VFCLK :out std_logic; -- 系统10M时钟8分频=1.25M
CTL_FREQ :out std_logic -- 控制信号输出
);
end ControlWave;
architecture main of ControlWave is
signal VFCLKDIV8: std_logic :='0'; -- 8分频时钟暂存
signal DIV8: std_logic_vector(3 downto 0) := "0000"; -- 8分频计数
signal KG5KHZ: std_logic :='0'; -- VFCLKDIV8 250分频
signal DIV250: std_logic_vector(7 downto 0) := "00000000"; -- 250分频计数
signal CTL_FREQ_Temp: std_logic :='0'; -- 控制信号中间变量
signal Flag_CTL_FREQ: std_logic :='0'; -- 第几个脉冲标志
signal CountEN: std_logic :='0'; -- 延时计数使能
signal Delayms: std_logic_vector(16 downto 0); -- 延时计数
begin
process(Sysclk_in)--系统10M时钟8分频=1.25M
begin
if Sysclk_in 'event and Sysclk_in ='1' then-- 系统时钟上升沿
if(DIV8 /= 3) then
DIV8 <= DIV8 + 1;
else
VFCLKDIV8 <= not VFCLKDIV8;
DIV8 <= (others =>'0');
end if;
end if;
end process;
process(VFCLKDIV8)-- KG5KHZ = VFCLK/250 =1.25M/250 = 5KHZ
begin
if VFCLKDIV8 'event and VFCLKDIV8 ='1' then-- 时钟上升沿
if (DIV250 /= "01111100") then --124
DIV250<= DIV250 +1;
else
KG5KHZ<= not KG5KHZ;
DIV250<= (others =>'0');
end if;
end if;
end process;
process(Wave1_XOR_Wave2,VFCLKDIV8,CountEN)
begin
if Wave1_XOR_Wave2 'event and Wave1_XOR_Wave2 ='0' then-- 信号输入A下降沿
CTL_FREQ_Temp <= '1';
Flag_CTL_FREQ <= not Flag_CTL_FREQ;
Delayms <= "00000000000000000";--复位延时
CountEN <= '1';--允许延时
end if;
if VFCLKDIV8 'event and VFCLKDIV8 ='1' then-- 时钟上升沿
if CountEN = '1' then
if Flag_CTL_FREQ ='1' then--
if Delayms = "10011100010" then--1ms
end if;
if Delayms = "11111010000" then--2ms
CTL_FREQ_Temp <= '0';
end if;
else--
if Delayms = "1111010000100100" then--49ms
--CTL_FREQ_Temp <= '0';
end if;
end if;
end if;
end if;
end process;
CTL_FREQ <= CTL_FREQ_Temp; -- 控制信号
VFCLK <= VFCLKDIV8; -- 8分频输出到引脚
end main;
NJ8888 发表于 2015-11-26 21:09
你下面不是已经注释掉了吗?我看只有一处赋值,没问题
我写的完整代码,下面注释掉是因为编译没通过我查问题的,如果不注释是不是就不对了,我这个思路本身就是错的?只能用你上面写的方法? 奥,原来你说的是没注释前,是错的,在一个process中,只能一个时钟信号源且只能一个边。好多初学者困惑,会碰到想在两个边赋值或是两个process中赋值,都是不可能的。因为硬件D触发器只有一个时钟输入脚且没有双沿的 NJ8888 发表于 2015-11-26 21:16
奥,原来你说的是没注释前,是错的,在一个process中,只能一个时钟信号源且只能一个边。好多初学者困惑, ...
你写的程序 中间脉冲为什么是5us 不是3us 2us或是其他的呢 linbo411 发表于 2015-11-26 21:26
你写的程序 中间脉冲为什么是5us 不是3us 2us或是其他的呢
只要小于2ms都行,两位数是0--3也够了,我用3位数能到7,一位数麻烦不好用 linbo411 发表于 2015-11-26 18:40
你这里没有用到我输入波形
我把输入输出看反了。不过,换过来,也不难。
思路: 1.输入信号的下降沿触发一个单稳态触发器;
2.单稳态触发器的输出脉宽可切换;
3.用一个定时器控制单稳态触发器的输出脉宽;
实现: 1.下降沿的检测用上一个时钟周期的input和这一个周期的比较,1->0为下降沿;
2.单稳态触发器由一个倒计时定时器实现;
3.每次单稳态触发器被触发时同时启动另一个定时器。在这个定时器到期以前,单稳态触发器的输出脉宽切换为19ms,否则为2ms。
要用硬件的思路写HDL,不要软件思维。 linbo411 发表于 2015-11-26 18:40
你这里没有用到我输入波形
//input信号下降沿检测
always @(posedge clk) input_r <= input;
assign trig = ({input_r, input} == 2'b10);
//单稳态触发器
always @(posedge clk)
if(trig) timer <= on_time;
else if(timer != 0) timer <= timer - 1;
always @(posedge clk) output = (timer != 0);
//单稳态触发器输出脉宽mux
assign on_time = on_time_sel ? N : M;
//脉宽切换用定时器
assign on_time_sel = (timer2 != 0);
always @(posedge clk)
if(trig) timer2 <= X;
else if(timer2 != 0) time2r <= timer2 - 1; agilityChen 发表于 2015-11-26 21:35
我把输入输出看反了。不过,换过来,也不难。
思路: 1.输入信号的下降沿触发一个单稳态触发器;
我是初学者,可能看不明白你说的意思,能不能写个代码看看,和上面那位高手思路不一样吗? linbo411 发表于 2015-11-26 21:42
我是初学者,可能看不明白你说的意思,能不能写个代码看看,和上面那位高手思路不一样吗? ...
思考一下,如果用搭电路的方法如何实现?电路怎么搭,代码就应该怎么写。记住,写HDL就是在搭电路。 我也把输入输出看反了,不过反过来,也不难,搭建双份的单稳态电路,加个MUX进行乒乓选择 agilityChen 发表于 2015-11-26 21:39
//input信号下降沿检测
always @(posedge clk) input_r
/input信号下降沿检测
always @(posedge clk) input_r <= input;
assign trig = ({input_r, input} == 2'b10);这边没看的懂, input是我输入信号吗,clk是系统时钟? NJ8888 发表于 2015-11-26 21:29
只要小于2ms都行,两位数是0--3也够了,我用3位数能到7,一位数麻烦不好用 ...
agilityChen 用单稳态触发器实现,这样可以吗,我看的不是很懂 linbo411 发表于 2015-11-27 08:54
/input信号下降沿检测
always @(posedge clk) input_r
input是输入信号,input_r是输入信号延迟一拍的寄存器,clk是系统时钟。
标准的边沿检测电路。建议自己查一下,单片机IO口边沿检测电路。 agilityChen 发表于 2015-11-27 10:18
input是输入信号,input_r是输入信号延迟一拍的寄存器,clk是系统时钟。
标准的边沿检测电路。建议自己查 ...
单片机简单,直接用IO检测检测中断,在中断里判断IO口电平 agilityChen 发表于 2015-11-26 21:35
我把输入输出看反了。不过,换过来,也不难。
思路: 1.输入信号的下降沿触发一个单稳态触发器;
3.每次单稳态触发器被触发时同时启动另一个定时器。在这个定时器到期以前,单稳态触发器的输出脉宽切换为19ms,否则为2ms。
这里另外一个定时器 定时时间怎么确定? linbo411 发表于 2015-11-27 10:34
3.每次单稳态触发器被触发时同时启动另一个定时器。在这个定时器到期以前,单稳态触发器的输出脉宽切换为 ...
看你自己的需求啊。从图上看,输入脉冲间隔一小一大,那这个时间就是介于大小间隔时间之间啊。只能通过这个间隔时间来区分输出2ms还是19ms了。 linbo411 发表于 2015-11-27 10:24
单片机简单,直接用IO检测检测中断,在中断里判断IO口电平
让你看单片机的内部电路,不是软件。
把电路图画出来了,自己用VHDL写一遍吧。
如果你连电路都看不懂,那就不是语言的问题了,而是电路基础的问题。 agilityChen 发表于 2015-11-27 11:03
把电路图画出来了,自己用VHDL写一遍吧。
如果你连电路都看不懂,那就不是语言的问题了,而是电路基础的 ...
谢谢你了 还是很喜欢CPLD的,容易上手 agilityChen 发表于 2015-11-27 11:03
把电路图画出来了,自己用VHDL写一遍吧。
如果你连电路都看不懂,那就不是语言的问题了,而是电路基础的 ...
你这个,我怎么分析都感觉19ms产生不了 agilityChen 发表于 2015-11-27 11:03
把电路图画出来了,自己用VHDL写一遍吧。
如果你连电路都看不懂,那就不是语言的问题了,而是电路基础的 ...
我把我的要求的输入输出更详细的画了一下,我还是感觉19ms产生不了,希望你帮我看一下 linbo411 发表于 2015-11-28 08:29
我把我的要求的输入输出更详细的画了一下,我还是感觉19ms产生不了,希望你帮我看一下 ...
我只是提供个思路,电路里的X,M,N值自己计算确定。
之前手机看图不够清楚,从你的图来看: 输入脉冲短的间隔21ms,长的间隔59ms。那么第二个单稳脉宽就取40ms,不就好了?
你是真的没有理解思路?还是在挑刺? agilityChen 发表于 2015-11-28 10:59
我只是提供个思路,电路里的X,M,N值自己计算确定。
之前手机看图不够清楚,从你的图来看: 输入脉冲短的 ...
你的思路懂了,但是我的确对这一块不是很熟悉,当天你写得每一句话我都当时正确的,所以分析不过去啊,才问你的,不是有意挑刺,感谢你 NJ8888 发表于 2015-11-26 16:37
我仔细看了下,每组其实一样,只是楼主你第一个波形之前的部分没画出来是吧.如果输入波形时间固定,那输出最简 ...
5us的脉冲产生,有的问题,怎么有时候没有 NJ8888 发表于 2015-11-26 21:29
只要小于2ms都行,两位数是0--3也够了,我用3位数能到7,一位数麻烦不好用 ...
怎么有时候对,有时候不对,上面是5us脉冲,下面是输出波形 NJ8888 发表于 2015-11-26 19:49
signal h_level_count,out_count: integer rang 0 to 32767;
signal temp_count: integer rang 0 to 7;
sig ...
思路是对的,但是还有些问题第几个脉冲的标志为,为什么会有500K和333k脉冲信号,搞不清楚,一开始输出信号也是这样后来我把 if first_flag='1' then --第一个触发脉冲
if out_count<2000 then
dout<='1';
else这里面的 dout<='1';去掉,还有 else
if out_count<19000 then
dout<='1';
else这里面的, 为什么要把dout<='1'去掉就OK呢 本帖最后由 NJ8888 于 2015-11-28 18:49 编辑
linbo411 发表于 2015-11-28 17:08
思路是对的,但是还有些问题第几个脉冲的标志为,为什么会有500K和333k脉冲信号,搞不清楚,一开始输出信 ...
现在temp_pulse能不能全对?
if h_level_count>20000 then --脉冲组间隔49ms,组内10ms,以20ms为判断门限
first_flag<='1';
h_level_count<=20000;
end if;
上面 h_level_count<<=20000改成20001 NJ8888 发表于 2015-11-28 18:45
现在temp_pulse能不能全对?
if h_level_count>20000 then --脉冲组间 ...
没用不是这个原因 NJ8888 发表于 2015-11-28 18:45
现在temp_pulse能不能全对?
if h_level_count>20000 then --脉冲组间 ...
找到问题了,逻辑上面有错误,第一个脉冲来以后 2ms脉冲输出以后,你把first_flag清0,还没有到第二个脉冲你就开始计19ms时间
页:
[1]