007-可调脉冲数触发之FPGA实现(Zynq也可驱动,带启动停止及完成中断输出)

文章目录

  • 前言
  • 一、设计思路
  • 二、代码及仿真
    • 1.资源消耗
    • 2.具体代码
    • 3.仿真波形
  • 总结


前言

此代码是在做显微镜高速聚焦系统中自己写的步进电机电机驱动源码,为了达到最快的驱动速度,因此选用脉冲触发方式进行驱动。在电机驱动的过程中往往需要对脉冲进行使能,启动,配置好输出N个脉冲,设置电机转动的方向,发送脉冲的过程中发送急停信号,停止当前的脉冲输出以及脉冲输出完后反馈回来中断触发信号。经过实测代码能够满足步进电机的驱动需求,且能够在驱动完毕后反馈中断信号提示脉冲信号已经输出完毕。

此代码适用的地方主要在需要脉冲触发的应用场景,最终输出两个信号出去(输出脉冲和电机方向电平),若有需要可以把脉冲触发跟运动坐标系建立起来,内部加一个计数器做大致位置的驱动,但为了避免步进电机丢步带来的影响,建议还是加上闭环的编码器进行坐标系的建立,我采用的是张大头步进电机的闭环驱动,实测效果OK,120KHz全功率运行没问题,噪声较小。


一、设计思路

拟设定五路输入信号,三路输出信号以及两个全局信号加时钟复位信号

sys_clk:时钟信号(通常情况下100M左右)
sys_rst:复位信号(低电平复位)
motor_enable:此路脉冲输出使能信号(低电平失能,高电平使能)
motor_start:脉冲开始输出信号(默认低电平,拉高后脉冲开始输出)
motor_pulse:脉冲个数信号(根据需求赋值)
motor_stop:脉冲急停信号(默认低电平,拉高后脉冲停止输出)
motor_direct:脉冲方向信号(低电平代表一个方向,高电平代表另外一个方向)
motor_exti:完成脉冲输出后中断信号(持续时间可定)
motor_step:外接至脉冲输出引脚
motor_dir:外接至步进电机驱动器方向引脚

主要代码通过状态机实现,状态机采用一段式状态机。状态机分为三个状态,当motor_enable信号拉高了高电平时,代表这路脉冲驱动信号有效,可以进行脉冲的输出。

通过case语句判断当前的状态的阶段,若处于第一个状态(idle)就对启动信号的上升沿进行判断,我们会在motor_start信号输入进行后打一个拍,然后判断其上升沿,当上升沿信号拉高后,代表脉冲即将输出,满足这个条件后状态机状态跳往第二个状态。若满足不了这个状态则持续为先前的状态。

进入到one第二个状态后,外部调用一个always语句,判断当前的状态是否跟上一个状态不同,且当前的状态属于第二个状态。如果判断成功就拉高pulse_status信号,这个信号处于高电平时,脉冲的计数器cnt_pulse_us就开始计数,当计数到指定脉宽的计数值后,翻转输出电平。脉宽计数值通过全局变量PULSE_WIDTH设定,比如基频为100MHz,当PULSE_WIDTH为50时,脉冲的工作频率为100M/50/2为1MHz。每计数到PULSE_WIDTH-1后,now_pulse_num就会自加到我们设定的脉冲个数*2(因为涉及到电平的翻转),当到达这个设定脉冲数后,pulse_status就会拉低,cnt_pulse_us就不会再计数,同时now_pulse_num归零,motor_step引脚输出低电平。从第二个状态跳转到第三个状态的条件也是这个。

第三个状态只持续一个时钟周期,在这个时钟周期内将rst_status拉高,同时state的状态转换成idle状态。等待下一个启动信号的来临。rst_status是整体的复位信号,也是输出中断信号的触发信号。当复位信号为1的时候,motor_step信号拉低,中断信号motor_exti信号拉高,pulse_status信号拉低。当motor_exti信号被拉高后,cnt_exti_us信号就会不断计数,当计数到EXTI_WIDTH-1时,拉低motor_exti信号。相当于将motor_exti信号拉高了一段时间然后再拉低。在外部我们可以设置PULSE_WIDTH和EXTI_DIDTH信号,以求获得较好我们可控的脉冲频率和中断信号时长。

以上都是无干扰情况下的正常运作流程,如果motor_stop信号在脉冲输出的时候被拉高了,检测到上升沿时,我们将下一个状态设置为下一个状态,且将pulse_status、cnt_exti_us、motor_step、now_pulse_num拉低,motor_exti信号拉高,即可实现急停停止输出脉冲的功能。

二、代码及仿真

1.资源消耗

在这里插入图片描述

2.具体代码

代码如下

`timescale 1ns / 1ps
/************************************
小董出品,必属精品
2023/8/18
************************************/

module motor_control#(
	parameter EXTI_WIDTH  = 50  ,
	parameter PULSE_WIDTH = 5000  
)
(
    input    wire            sys_clk     ,//时钟信号
	input    wire            sys_rst     ,//复位信号
 
    input    wire            motor_stop  ,//电机急停信号,停止脉冲输出
	input    wire            motor_start ,//触发输出脉冲信号,比如摄像头数据采集完毕
	input    wire            motor_enable,//电机使能信号,只有使能的时候才能运行
	input    wire   [15:0]   motor_pulse ,//单次行程总脉冲数
	input    wire            motor_direct,//单次行程方向
	
	output   reg             motor_exti  ,//电机完成单次行程后中断信号
	output   reg             motor_step  ,//实际输出脉冲引脚
	output   wire            motor_dir    //实际输出方向引脚
    );
localparam    idle   =   3'b001 ;
localparam    one    =   3'b010 ;
localparam    two    =   3'b100 ;
wire               start_pose   ;//上升沿触发信号
wire               stop_pose    ;//上升沿触发信号

reg                motor_start_r;//motor_start信号打了一拍
reg                motor_stop_r ;//motor_stop信号打了一拍
reg                motor_enable_r;//motor_enable信号打了一拍

reg                rst_status   ;//复位标志位

reg     [2:0]      state        ;//当前状态
reg     [2:0]      state_r      ;//上一次状态

reg     [15:0]     now_pulse_num;//当前脉冲数
reg                pulse_status ;//脉冲输出开始标志位

reg     [15:0]     cnt_pulse_us ;//脉冲一半周期定时计数,根据基频来
reg     [15:0]     cnt_exti_us  ;//中断信号定时计数,根据基频来

//motor_start打拍
always@(posedge sys_clk or negedge sys_rst)
	if(!sys_rst)
		motor_start_r <= 1'b0;
	else
		motor_start_r <= motor_start;
		
//motor_enable打拍
always@(posedge sys_clk or negedge sys_rst)
	if(!sys_rst)
		motor_enable_r <= 1'b0;
	else
		motor_enable_r <= motor_enable;

//motor_stop打拍
always@(posedge sys_clk or negedge sys_rst)
	if(!sys_rst)
		motor_stop_r   <= 1'b0;
	else
		motor_stop_r   <= motor_stop;
		
//motor_start信号上升沿判断		
assign start_pose = ~motor_start_r&&motor_start;	
assign stop_pose  = ~motor_stop_r&&motor_stop;
//state打拍	
always@(posedge sys_clk or negedge sys_rst)
	if(!sys_rst)
		state_r <= 'd0;
	else
		state_r <= state;	
		
//状态机逻辑	
always@(posedge sys_clk or negedge sys_rst)
	if(!sys_rst)
		begin
			state        <= idle;
			rst_status   <= 1'b0;
		end
	else if(stop_pose == 1'b1)
	    begin
			state        <= idle;
			rst_status   <= 1'b0;		
		end
	else if(motor_enable_r==1'b1)
		case(state)
			idle:	
				if(start_pose)
					begin
						state 	  <= one;
					end		
				else
					begin
					    rst_status<= 1'b0;
						state 	  <= state;
					end	
			one :  
				if(now_pulse_num == 2*motor_pulse)
					begin
						state 	  <= two;
					end
				else 
					begin
						state 	  <= state;
					end		
			two :  
					begin
					    rst_status<= 1'b1;
						state 	  <= idle;
					end			
			default:;
		endcase				
	else
		begin
			state <= idle;
		end	
		
always@(posedge sys_clk or negedge sys_rst)
	if(!sys_rst)
		pulse_status <= 1'b0;
	else if(stop_pose==1'b1)
	    pulse_status <= 1'b0;
	else if(state_r!=one&&state==one)
		pulse_status <= 1'b1;
	else if(now_pulse_num == 2*motor_pulse)
		pulse_status <= 1'b0;	
	else if(rst_status==1'b1)
	    pulse_status <= 1'b0;
    else
        pulse_status <= pulse_status;
		
always@(posedge sys_clk or negedge sys_rst)
	if(!sys_rst)
		motor_exti <= 1'b0;
	else if(stop_pose==1'b1)
	    motor_exti <= 1'b1;
	else if(rst_status==1'b1)
		motor_exti <= 1'b1;
	else if(cnt_exti_us == EXTI_WIDTH-1'b1)
		motor_exti <= 1'b0;	
    else
        motor_exti <= motor_exti;

always@(posedge sys_clk or negedge sys_rst)
	if(!sys_rst)
		cnt_exti_us <= 'd0;
	else if(stop_pose==1'b1)
	    cnt_exti_us <= 1'b0;
	else if(cnt_exti_us== EXTI_WIDTH-1'b1)
		cnt_exti_us <= 'd0;
	else if(motor_exti==1'b1)
		cnt_exti_us <= cnt_exti_us + 1'b1;
	else
		cnt_exti_us <= cnt_exti_us; 
		
always@(posedge sys_clk or negedge sys_rst)
	if(!sys_rst)
		cnt_pulse_us <= 1'b0;
	else if(stop_pose==1'b1)
	    cnt_pulse_us <= 1'b0;
	else if(cnt_pulse_us == PULSE_WIDTH-1'b1)
		cnt_pulse_us <= 1'b0;
	else if(pulse_status == 1'b1)
		cnt_pulse_us <= cnt_pulse_us + 1'b1;
	else
		cnt_pulse_us <= 1'b0;

always@(posedge sys_clk or negedge sys_rst)
	if(!sys_rst)
		motor_step <= 1'b0;
	else if(stop_pose==1'b1)
	    motor_step <= 1'b0;
	else if(cnt_pulse_us == PULSE_WIDTH-1'b1)
		motor_step <= ~ motor_step;
	else if(now_pulse_num == 2*motor_pulse )
		motor_step <= 1'b0;
	else if(rst_status==1'b1)
	    motor_step <= 1'b0;
	else 
		motor_step <= motor_step;  	
		
always@(posedge sys_clk or negedge sys_rst)
	if(!sys_rst)
		now_pulse_num <= 1'b0;
    else if(stop_pose==1'b1)
	    now_pulse_num <= 1'b0;
	else if(cnt_pulse_us == PULSE_WIDTH-1'b1)
		now_pulse_num <= now_pulse_num + 1'b1;
	else if(now_pulse_num == 2*motor_pulse)
		now_pulse_num <= 1'b0;
    else if(rst_status==1'b1)
	    now_pulse_num <= 1'b0;
	else
		now_pulse_num <= now_pulse_num;  
		
//电机运动方向与输入设定方向相同
assign motor_dir  = motor_direct;	
	
	
endmodule

3.仿真波形

在这里插入图片描述
在这里插入图片描述
可见脉冲脉宽为100个时钟周期,中断周期为50个时钟周期。在原先的参数设定中,PULSE_WIDTH为50,EXTI_WIDTH为50,符合设计要求。且发出脉冲为3个脉冲。


总结

今天吃了手撕鸡+豆腐,味道也很不错,手撕鸡挺柴的,晚上吃的鱼香肉丝拌面,味道确实不错,下次可以继续尝尝。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/307272.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

开源分布式任务调度系统DolphinScheduler本地部署与远程访问

文章目录 前言1. 安装部署DolphinScheduler1.1 启动服务 2. 登录DolphinScheduler界面3. 安装内网穿透工具4. 配置Dolphin Scheduler公网地址5. 固定DolphinScheduler公网地址 前言 本篇教程和大家分享一下DolphinScheduler的安装部署及如何实现公网远程访问&#xff0c;结合内…

two-stream HANet

作者未提供代码

全光谱照明灯真的护眼吗?适合考公使用的全光谱台灯

全光谱护眼台灯是一种新型的台灯产品&#xff0c;其特点是能够提供全光谱照明&#xff0c;给用户带来更好的视觉体验和护眼效果。传统的台灯大多使用白炽灯或荧光灯作为光源&#xff0c;这种光源在光谱中只包含有限的波长&#xff0c;导致照明效果不够均匀&#xff0c;容易产生…

VSCode C/C++(gdb)调试指南

1、安装插件 2、F5开启调试 左侧侧边栏->确保打开回调栈 右键函数栈->查看反汇编 3、打印寄存器、函数反汇编等 命令&#xff1a; 查看main反汇编 -exec disassemble /m main 查看寄存器 -exec info r 打印某个变量 -exec print s 或者 --s 打印寄存器&#xff0c;如p…

人大金仓恒生电子助力湘财证券TA系统国产化升级

近日&#xff0c;人大金仓&恒生电子助力湘财证券TA&#xff08;登记过户&#xff09;系统国产化升级上线&#xff0c;系统在性能、稳定性、安全可靠性等方面均表现良好。自2022年至今&#xff0c;在金仓数据库的支撑下&#xff0c;湘财证券已完成TA及其他近30个系统的升级或…

社交距离 - 华为OD统一考试

OD统一考试(C卷) 分值: 200分 题解: Java / Python / C++ 题目描述 疫情期间,需要大家保证一定的社交距离,公司组织开交流会议,座位有一排共N个座位,编号分别为[0…N-1],要求员工一个接着一个进入会议室,并且可以在任何时候离开会议室。 满足:每当一个员工进入时,…

Nginx实战 | 高性能HTTP和反向代理神器Nginx前世今生,以及它的“繁花之境”

专栏集锦&#xff0c;大佬们可以收藏以备不时之需&#xff1a; Spring Cloud 专栏&#xff1a;http://t.csdnimg.cn/WDmJ9 Python 专栏&#xff1a;http://t.csdnimg.cn/hMwPR Redis 专栏&#xff1a;http://t.csdnimg.cn/Qq0Xc TensorFlow 专栏&#xff1a;http://t.csdni…

翻页插件的bug不能被忽视

文章目录 概要翻页插件的构成&#xff1a;具体功能如下&#xff1a;简单设计的测试用例测试出来的bug如下&#xff1a;小结 概要 近几年测试过不少WEB管理平台类的项目&#xff0c;系统中只要有列表管理的模块&#xff0c;就免不了要引入翻页插件 。 但是基本上每一个项目涉及…

前端面试题集合四(html)

HTML 面试知识点总结 本部分主要是笔者在复习 HTML 相关知识和一些相关面试题时所做的笔记&#xff0c;如果出现错误&#xff0c;希望大家指出&#xff01; 目录 1. DOCTYPE 的作用是什么&#xff1f;2. 标准模式与兼容模式各有什么区别&#xff1f;3. HTML5 为什么只需要写…

PyTorch: torch.nn 子模块及其在循环神经网络中的应用

目录 torch.nn子模块详解 nn.utils.rnn.PackedSequence 参数说明 注意事项 示例代码 nn.utils.rnn.pack_padded_sequence 参数说明 返回值 注意事项 示例代码 nn.utils.rnn.pad_packed_sequence 参数说明 返回值 注意事项 示例代码 nn.utils.rnn.pad_sequence …

vue-vben-admin 与.net core 结合实例 【自学与教学 小白教程】---第4节---部门管理

ue-vben-admin 与.net core 结合实例 这里计划使用.net core 作为后端 。目标&#xff1a;打造好看 易用 开箱即用 的netcore一体化框架。Vue Vben Admin For NetCore 取命 hcrain-vvadmin 我不是前端人员 但有时开发还是要写一些界面。 之前使用layui是时候 狠心升级下了。 …

Parallel patterns: convolution —— An introduction to stencil computation

在接下来的几章中&#xff0c;我们将讨论一组重要的并行计算模式。这些模式是许多并行应用中出现的广泛并行算法的基础。我们将从卷积开始&#xff0c;这是一种流行的阵列操作&#xff0c;以各种形式用于信号处理、数字记录、图像处理、视频处理和计算机视觉。在这些应用领域&a…

win10在启动游戏时报错,提示“d3dx9_25.dll文件丢失”,怎么办?d3dx9_25.dll丢失如何自动修复

一、d3dx9_25.dll文件是什么&#xff1f; d3dx9_25.dll是DirectX的一部分&#xff0c;DirectX是一种由微软开发的专门处理与多媒体、游戏程序和视频相关的应用程序接口。d3dx9_25.dll文件是DirectX9中一个重要的dll文件&#xff0c;主要负责处理3D图形程序&#xff0c;作用是帮…

Node.js和npm

目录 01_Node.js01.什么是 Node.js目标讲解小结 02.fs模块-读写文件目标讲解小结 03.path模块-路径处理目标讲解小结 04.案例-压缩前端html目标讲解小结 05.认识URL中的端口号目标讲解小结 06.http模块-创建Web服务目标讲解小结 07.案例-浏览时钟目标讲解小结 02_Node.js模块化…

故事生成动漫解说视频,用Artflow AI做英语口语故事

大家好我是在看&#xff0c;记录普通人学习探索AI之路。 今天&#xff0c;我将再次为大家精心策划一个使用Artflow AI制作动漫解说视频的详尽教程&#xff0c;这个教程专为初学者设计。通过这款强大的Artflow AI工具&#xff0c;用户能够一键自动化完成从图像生成、视频剪辑到配…

CST2024的License服务成功启动,仍报错——“The desired daemon is down...”,适用于任何版本!基础设置遗漏!

CST2024的License服务成功启动&#xff0c;仍报错——“The desired daemon is down…”&#xff0c;适用于任何版本&#xff01;基础设置遗漏&#xff01; CST2024的License服务成功启动后报错 若不能成功启动License服务&#xff0c;有可能是你的计算机名称带中文&#xff…

牛刀小试 - C++ 实现2048(可存档)

参考文档 借助了这位大佬的开发思路&#xff0c; 开发过程中学到了很多 C语言实现《2048游戏》 技术点&#xff1a; system调整控制台大小的问题 unsigned and 符号位 C对齐输出&#xff08;左对齐和右对齐&#xff09; C goto语句详解 完整代码 /********************…

el-table实现多行合并的效果,并可编辑单元格

背景 数据为数组包对象&#xff0c;对象里面有属性值是数组&#xff1b;无需处理数据&#xff0c;直接使用el-table包el-table的方法&#xff0c;通过修改el-table的样式直接实现多行合并的效果 html代码 <template><div><el-table size"mini" :d…

酒店客房管理系统设计与实现(代码+数据库+文档)

&#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目 希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;一、研究背景 1.1 研究背景 当…

JKD的组成、Java跨平台、Path环境变量设置

一、JDK的组成 JVM&#xff1a;Java虚拟机&#xff0c;真正运行Java的地方 核心类库&#xff1a;Java自己写好的程序&#xff0c;给程序员自己调用 JRE&#xff1a;Java的运行环境&#xff0c;包含JVM和核心类库 JDK也就是Java开发工具&#xff0c;包含以上所有 二、Java的…