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

news2024/11/19 16:30:27

文章目录

  • 前言
  • 一、设计思路
  • 二、代码及仿真
    • 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个脉冲。


总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

React Native 桥接原生实现 JS 调用原生方法

一、为什么需要桥接原生 为了满足在React 层无法实现的需求 复杂高性能的组件&#xff1a;复杂表格、视频播放原生层开发能力&#xff1a;传感器编程、widget平台属性&#xff1a;系统信息、设备信息对接第三方应用&#xff1a;相机、相册、地图 真实的开发过程中是不可能完…

OpenGL学习笔记-Blending

混合方程中&#xff0c;Csource是片段着色器输出的颜色向量&#xff08;the color output of the fragment shader&#xff09;&#xff0c;其权重为Fsource。Cdestination是当前存储在color buffer中的颜色向量&#xff08;the color vector that is currently stored in the …

欢乐的周末 - 华为OD统一考试

OD统一考试 题解&#xff1a; Java / Python / C 题目描述 小华和小为是很要好的朋友&#xff0c;他们约定周末一起吃饭。 通过手机交流&#xff0c;他们在地图上选择了多个聚餐地点(由于自然地形等原因&#xff0c;部分聚餐地点不可达)。求小华和小为都能到达的聚餐地点有多…

私域爆款活动实操指南,让你轻松成为营销高手!

私域运营活动是公司运营中非常重要的一环&#xff0c;它能够提高用户参与度、增加用户忠诚度&#xff0c;并为公司带来更多的商业机会。然而&#xff0c;策划和执行一场成功的私域运营活动并不容易&#xff0c;需要思维缜密、部门合作以及落地能力等方面的综合素养。今天来跟大…

Orchestrator源码解读2-故障失败发现

目录 前言 核心流程函数调用路径 GetReplicationAnalysis 故障类型和对应的处理函数 ​编辑 拓扑结构警告类型 核心流程总结 与MHA相比 前言 Orchestrator另外一个重要的功能是监控集群&#xff0c;发现故障。根据从复制拓扑本身获得的信息&#xff0c;它可以识别各种故…

JDK21和 Flowable 7.0.0

JDK21和 Flowable 7.0.0 一.Flowable二.项目搭建1.依赖包2.数据库3.资源文件1.YML配置文件2.Drools kbase3.Drools rule4.DMN 决策表5.BPMN 流文件 4.BPMN 流程图绘制插件5.测试代码1.启动类2.Flowable 配置3.Camel 配置1.Camel 配置2.Camel Router 定义 4.扩展类监听1.外部工作…

【MySQL】视图,15道常见面试题---含考核思路详细讲解

目录 一 视图 1.1视图是什么 1.2 创建视图 1.3 查看视图(两种) 1.4 修改视图(两种) 1.5 删除视图 二 外连接&内连接&子查询介绍 2.1 外连接 2.2 内连接 2.3 子查询 三 外连接&内连接&子查询案例 3.1 了解表结构与数据 3.2 15道常见面试题 四 思…

Java中内存模型

参数传递图解与结论 通过上面的两段程序可以得出如下结论&#xff1a;根据内存去解释&#xff0c;局部变量随方法栈的弹出而消失&#xff1b; 当调用方法时&#xff0c;如果传入的数值为基本数据类型&#xff08;包含String类型&#xff09;&#xff0c;形式参数的改变对实际…

虚拟机Ubuntu网络配置

电脑有两个系统&#xff0c;windows系统和ubuntu系统&#xff0c;那网卡到底给哪一个用呢&#xff0c;所以要选择桥接模式&#xff0c;就可以共用网卡 但是我们电脑网卡&#xff0c;有线网卡&#xff0c;无线网卡&#xff0c;到底使用哪个网卡&#xff0c;所以选择桥接到自动或…

IP地址的网络安全防护和预防

网络安全对于保护个人和组织的信息资产至关重要&#xff0c;而IP地址是网络通信的基础。在这篇文章中&#xff0c;IP数据云将探讨IP地址的网络安全防护和预防措施&#xff0c;以确保网络的安全性和可靠性。 IP地址是互联网上每个设备在网络中的唯一标识符。有IPv4和IPv6两种类…

苹果手机怎么设置提醒事项?详细方法在这,记得收藏!

无论是学生党还是上班族&#xff0c;大家每天都需要处理许多任务和事项。为了更好地管理这些事项&#xff0c;苹果手机为用户提供了提醒功能。 通过设置提醒事项&#xff0c;我们可以减少忘记重要任务的可能性。那么&#xff0c;苹果手机怎么设置提醒事项呢&#xff1f;在本文…

阳光宝宝的视界:新生儿补充叶黄素的小心指南

引言&#xff1a; 叶黄素&#xff0c;作为视觉健康的重要组成部分&#xff0c;对新生儿的眼睛发育和视觉保护具有重要意义。本文将深入探讨叶黄素的功能、补充时机&#xff0c;以及在给新生儿补充叶黄素时应该注意的事项&#xff0c;为小天使们提供最贴心的呵护。 第一部分&am…

【SQL】对表中的记录通过时间维度分组,统计出每组的记录条数

场景&#xff1a;一般用作数据统计&#xff0c;比如统计一个淘宝用户在年、月、日的维度上的订单数。 业务&#xff1a;一个集合&#xff0c;以时间维度来进行分组求和。 准备一张订单表order&#xff0c;有一些常规属性&#xff0c;比如创建时间&#xff0c;订单号。 DDL语句如…

Vue面试之虚拟DOM

Vue面试之虚拟DOM 什么是虚拟dom&#xff1f;虚拟dom是如何产生的&#xff1f;编写模板template模板编译Complie挂载Mounting 如何进行新旧Dom对比&#xff1f; 最近在整理一些前端面试中经常被问到的问题&#xff0c;分为vue相关、react相关、js相关、react相关等等专题&#…

【C语言】指针——从底层原理到应用

C语言指针-从底层原理到花式技巧&#xff0c;用图文和代码帮你讲解透彻 目录 一、前言二、变量与指针的本质 1. 内存地址2. 32位与64位系统3. 变量4. 指针变量5. 操作指针变量 5.1 指针变量自身的值5.2 获取指针变量所指向的数据5.3 以什么样的数据类型来使用/解释指针变量所指…

【研究僧毕业总结】第1024个创作日

目录 前言1. 机缘2. 收获3. 憧憬 前言 收到这封来信&#xff0c;代表从创作至今刚好满足1024天 1024&#xff0c;程序员的记忆 1. 机缘 从学生到社会&#xff0c;都在需求一个记录笔记的软件&#xff0c;而作为程序员&#xff0c;CSDN可云同步又可直接在云平台上看到 选择了…

【算法分析与设计】三数之和

题目 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元组。 示例…

ERD助力研发资产沉淀研发提效

一、从痛点中思考答案 痛点一&#xff1a;复杂系统的设计和逻辑碎片化散落&#xff0c;缺少沉淀导致系统后期维护、迭代以及架构升级都非常困难。 痛点二&#xff1a;由于新需求或新项目导致的系统的老旧逻辑梳理往往耗费大量人力&#xff0c;甚至造成人才的流失。 痛点三&a…

华为云AI:轻松实现图像识别调用

文章目录 前言一、环境配置关键步骤 二、图像识别实例媒资图像标签名人识别 总结 前言 基于华为云AI服务和java使用SDK实现图像识别&#xff0c;主要以媒资图像标签和名人识别为例。 一、环境配置 Maven&#xff08;没有直接下载华为的SDK包&#xff0c;而是使用Maven安装依赖…

CPT203-Software Engineering 笔记

Week 1 -- Introduction failure reason professional software development*** maintain, security, efficiency, acceptability two kinds***: generic, customized software deterioration 软件退化 reduce changes/ side effects after changes software engineering …