STM32使用USART串口调试ULN2003驱动步进电机

2023-11-01

传送门:STM32控制ULN2003驱动步进电机28BYJ-48最基础版

使用串口调试步进电机28BYJ-48获得需要转速

当使用STM32控制ULN2003驱动步进电机28BYJ-48时,步进电机转速变化缓慢,想要得到合适的控制速度,需要不断的调试,不断的更改代码,编辑、编译、下载到STM32中,不断的重复下载造成开发速度慢同时对单片机也是一种损耗,废话不多说直接上代码。

  • 定义struct.h进行宏定义,如下:
#define STRUCT(type)    typedef struct _tag_##type      type;\
struct _tag_##type

电机部分代码改进

  • 在step_motor.h中定义类型,使用对象可以使数据组织起来使用更加方面,如下:
/* 类型定义 ------------------------------------------ */
STRUCT(StepMotor_t)
{
    /* 
     *state: bit0  0 表示电机处于非运行态;     1 表示运行态
     *       bit1  0 表示电机正转       1 反转   
     */
    uint8_t state;
    /* 每步时间片 */
    uint16_t step_slice;
    /* 总步数 */
    u32 step_num; 
    void (*run)(StepMotor_t *motor);
};
  • 在step_motor.c中定义电机运行函数,如下:
/**
 * @name: Step_Motor_Run
 * @description: step motor run.
 * @param {StepMotor_t} *motor
 * @return {*}
 */
void Step_Motor_Run(StepMotor_t *motor)
{
    /* 判断正反转 */
    if(!(motor->state & 0x02))
    {
        printf("motor ready run cw... , period is %d .\r\n", motor->step_slice);
        Step_Motor_CW(motor);
    }
    else
    {
        printf("motor ready run ccw... , period is %d .\r\n", motor->step_slice);
        Step_Motor_CCW(motor);
    }
    motor->state &= ~0x01; 
}

  • 同时进行运行正反转的函数定义:
/**
 * @name: Step_Motor_CW
 * @description: 电机正转函数
 * @param {uint32_t} nms
 * @return {*}
 */
static void Step_Motor_CW(StepMotor_t *motor)
{
    volatile uint8_t i;
    uint32_t j, pieces; /* pieces 表示8个位一组的脉冲一共多少组 */
    uint8_t temp = 0;
    
    pieces = motor->step_num / 8;
    for(j = 0; j < pieces; j++)
        for(i = 0; i < 8; i++)
        {
            temp = steps[i];
            LA = (uint8_t)((temp&PLA) >> 0);
            LB = (uint8_t)((temp&PLB) >> 1);
            LC = (uint8_t)((temp&PLC) >> 2);
            LD = (uint8_t)((temp&PLD) >> 3);
            
            delay_us(motor->step_slice);
        }
    Step_Motor_Stop(&StepMotor);
}

串口部分代码改进

  • 在usart.h中进行宏配置,可以方便的开关USART接收中断,配置如下:
/* 串口1接收配置使能,使用串口进行调试 */
#define USART1_RCV_EN      1
  • 在usart.c中进行USART初始化,在初始化中开启接收中断,并对中断进行配置
void Usart1_Init(unsigned int baud)
{
	GPIO_InitTypeDef gpio_initstruct;
	USART_InitTypeDef usart_initstruct;
	NVIC_InitTypeDef nvic_initstruct;
	/* 时钟使能 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	/* gpio口配置 */
	//PA9	TXD
	gpio_initstruct.GPIO_Mode = GPIO_Mode_AF_PP;
	gpio_initstruct.GPIO_Pin = GPIO_Pin_9;
	gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &gpio_initstruct);
	
	//PA10	RXD
	gpio_initstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	gpio_initstruct.GPIO_Pin = GPIO_Pin_10;
	gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &gpio_initstruct);
	
	/* 串口配置 */
	usart_initstruct.USART_BaudRate = baud; /* 波特率设置 */
	usart_initstruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;		//无硬件流控
	usart_initstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;						//接收和发送
	usart_initstruct.USART_Parity = USART_Parity_No;									//无校验
	usart_initstruct.USART_StopBits = USART_StopBits_1;								//1位停止位
	usart_initstruct.USART_WordLength = USART_WordLength_8b;							//8位数据位
	USART_Init(USART1, &usart_initstruct);
	
	USART_Cmd(USART1, ENABLE);														//使能串口
	/* 接收中断使能 */
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);									//使能接收中断
	/* 接收中断配置 */
	nvic_initstruct.NVIC_IRQChannel = USART1_IRQn;
	nvic_initstruct.NVIC_IRQChannelCmd = ENABLE;
	nvic_initstruct.NVIC_IRQChannelPreemptionPriority = 0;
	nvic_initstruct.NVIC_IRQChannelSubPriority = 2;
	NVIC_Init(&nvic_initstruct);
}
  • 设置一个结构类型,用来处理数据和USART接收中的状态
/* 类型定义 ------------------------------------------------- */
STRUCT(RcvDta_t)
{
    uint8_t rcv_dta[13];/* 接收数据 */
    uint8_t worked_dta[13];/* 处理数据 */
    /* state:   bit0 ~ bit6 记录data数量
     *          bit7 : 0 表示接收状态
     *                 1 表示处理状态         
     */
    uint8_t state;
    void (*func)(RcvDta_t *rcv_ptr);
};
  • 定义结构体数据
/* 变量定义 ---------------------------------------------- */
#if USART1_RCV_EN
RcvDta_t RcvMsg;
#endif
  • 串口中断函数,在串口中接收并判断是不是接收完成
void USART1_IRQHandler(void)
{
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
	{
#if USART1_RCV_EN
		uint8_t ch = USART_ReceiveData(USART1);
		/* 结束条件判断,在发送数据的时候需要在末尾加上回车 */
		if(ch == '\n')
			RcvMsg.state |= 0x80;

		if(!(RcvMsg.state & 0x80))
		{
			if((RcvMsg.state & 0x7f) < sizeof(RcvMsg.rcv_dta) - 1)
			{
				
				RcvMsg.rcv_dta[RcvMsg.state++] = ch;
			}
		}
#endif
		USART_ClearFlag(USART1, USART_FLAG_RXNE);
	}
}
  • 定义app.c和app.h,并在app.c中定义串口接收处理函数
#if USART1_RCV_EN
/**
 * @name: Dubug_MsgHandler
 * @description: 处理串口接收数据,将接收数据处理为电机的数据
 * @param {RcvDta_t} *rcv_ptr 串口数据结构体指针
 * @param {StepMotor_t} *motor 电机结构体指针
 * @return {*}
 */
void Dubug_MsgHandler(RcvDta_t *rcv_ptr, StepMotor_t *motor)
{
	char *ret = NULL;
	char *is_space = NULL;
    int speed;

    /* 将内容复制到worked_dta, rcv_dta将清空下次接收 */
	strncpy((char *)rcv_ptr->worked_dta, (char *)rcv_ptr->rcv_dta, 11);
	// printf("usart rcv: %s state: %#x\r\n", rcv_ptr->worked_dta, rcv_ptr->state);

    /* 指令处理 ------------------------------------ */
    /* 电机运转 --------- */
	ret = strstr((char *)rcv_ptr->worked_dta, "run");
	if(ret != NULL)
	{
        motor->state |= 0x01;
        motor->state &= ~(1<<1);
        ret = NULL;
	}

    /* 电机正转 --------- */
	ret = strstr((char *)rcv_ptr->worked_dta, "run_cw");
	if(ret != NULL)
	{
        motor->state |= 0x01;
        motor->state &= ~(1<<1);
        ret = NULL;
	}

    /* 电机反转 --------- */
	ret = strstr((char *)rcv_ptr->worked_dta, "run_ccw");
	if(ret != NULL)
	{
        motor->state |= 0x01;
        motor->state |= (1<<1);
        ret = NULL;
	}

    /* 电机速度设置 --------- */
    ret = strstr((char *)rcv_ptr->worked_dta, "speed");
    if(ret)
    {
        ret += strlen("speed");
        ret++;
        is_space = strchr(ret, ' ');
        if(is_space) ret++;
        speed = atoi(ret);
        motor->step_slice = speed;

        ret = NULL;
    }

	memset(rcv_ptr->rcv_dta, 0, sizeof(rcv_ptr->rcv_dta));
	rcv_ptr->state &= 0x00;
}
#endif

处理函数只进行了简单处理,需要复杂功能都可以在此函数中进行处理。

  • 在main.c中调用
int main(void)
{
	uint32_t t = 0;

	initSysTick();
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	Usart1_Init(115200);
	LED1_Init();
	Step_Motor_Init();

	for(;;)
	{
		/* 串口接收是否接受到 */
		if(RcvMsg.state & 0x80)
		{
			Dubug_MsgHandler(&RcvMsg, &StepMotor);
			delay_ms(1);
		}
		
		/* 是否启动电机 */
		if(StepMotor.state & 0x01)
		{
			StepMotor.run(&StepMotor);	
		}
		
		if(t % 100 < 50)
			LED1_Open();
		else
			LED1_Close();

		if(t > 1000)
			t = 0;

		t++;
		delay_ms(10);
	}
}

调试结果

  • 使用串口调试助手进行调试
    在这里插入图片描述

调试结果图

以上的调试过程中,需要注意每次输入的时候使用回车,不然程序会卡住或者下调指令执行错误,有稍微的不方便之处,可以使用定时器中断进行程序改进,各有优略。


以上代码传送门: 串口调试步进电机,再也不用担心调试重复下载啦


喜欢请点个赞哦,谢谢!欢迎指正

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32使用USART串口调试ULN2003驱动步进电机 的相关文章

  • HITiCS大作业——程序人生

    计算机系统 大作业 题 目 程序人生 Hello s P2P 专 业 计算机科学与技术 学 号 2021112155 班 级 2103103 学 生 谷佳熠 指 导 教 师 刘宏伟 计算机科学与技术学院 2022年11月 摘 要 本篇文章详
  • springboot定时任务详解

    文章目录 一 基于注解 静态 1 添加依赖 2 创建定时任务 3 参数说明 二 基于接口 动态 1 添加依赖 2 添加数据库记录 3 创建定时器 4 启动测试 三 Quartz 1 添加依赖 2 编写任务类 3 编写配置类 4 启动项目 在
  • MySQL数据库的性能优化----(一步一个脚印)

    一 MySQL数据库的优化目标 基本原则 1 优化目标 MySQL数据库是常见的两个瓶颈是CPU和I O的瓶颈 无论是索引优化 还是表结构优化 参数优化 最后都可以归纳到这这两个分类中 1 减少 I O 次数 I O是数据库最容易瓶颈的地方
  • Exception in thread "main" java.lang.NoClassDefFoundError: com/google/common/base/Function问题解决

    场景 java eclipse 调用问题 java eclipse selenium3 脚本 gt package LoginScript import org openqa selenium import org openqa selen

随机推荐

  • MySQL数据库多列索引详解

    多列索引的概念 多列索引 是指在创建索引时所关联的字段不是一个字段 而是多个字段 虽然可以通过所关联的字段进行查询 但是只有查询条件中使用了所关联字段中的第一个字段 多列索引才会被使用 多列索引的创建 创建表时定义索引 语法 CREATE
  • UE4蓝图:初体验(4)循环

    在C 中循环的关键字有for while do while三种 而在蓝图中 1 For循环 1 在蓝图中 右键输入for loop 获得ForLoop节点 该节点左边的按钮分别是循环计数的初始值和终止值 图中的是指从1 4共循环4次 右边的
  • eclipse中出现红线错误但不提示错误信息解决办法

    eclipse中出现红线报错 但鼠标悬停不提示错误信息 如图例 经过摸索找到了其中的解决方案 这主要与Hovers 的设置相关 通过如下设置修改 Window gt Preferences gt Java gt Editor gt Hove
  • AIX mount RedHat的NFS

    AIX mount RedHat的NFS RedHat 192 168 8 202 AIX 192 168 8 193 在RedHat服务器上设置NFS服务 1 RedHat服务器端的设定NFS都是在 etc exports这个文件中进行设
  • 敏捷运维

    序言 表面上都是自由的 实际上四周围墙 无法跨越 表面上都有很多选择 实际上没得选 成功是一种考验 失败也是 原因能想出来吗 敏捷运维 敏捷开发 在各种压力进行运维 有一定的适合场景 你知道么 风言风语 运维到底根据什么样的节奏走 是快一点
  • 【C语言】- printf 和scanf 函数详解!

    一 printf函数 这是在stdio h中声明的一个函数 因此使用前必须加入 include
  • 时序预测方法总结

    时序预测 本人博客只是平时学习中做的笔记 若文中有错误请大家指出 一 单变量时间预测 1 AR AutoRegression 自回归 自回归基于输入变量的线性组合为输出建模 输入 先前时间步长的值 输出 下一步的值 在时间序列中 鉴于当前和
  • 关于unity3d分享功能之ShareSDK的研究续二

    关于微信分享 前面的博客也是提到了 总有一下问题 有些注意的事项再一次总结一下 注意一 微信需要开发者认证审核通过app 这个时候会有AppID和AppSecret 把这个在脚本ShareSDKDevInfo cs中替换掉 注意在面板中一样
  • 学习QT的意义以及QT平台的安装

    文章目录 前言 一 为什么要学习QT 1 学习Qt的意义 2 Qt的一些应用案例 二 Qt软件的安装 1 Qt的下载 2 具体安装环节 总结 前言 Qt 是一个1991年由Qt Company开发的跨平台C 图形用户界面应用程序开发框架 它
  • 【分析】string中size与length

    结论 没有区别 length是因为沿用C语言的习惯而保留下来的 string类最初只有length 引入STL之后 为了兼容又加入了size 它是作为STL容器的属性存在的 便于符合STL的接口规则 以便用于STL的算法 具体解释 cplu
  • Nreal for Unity SDK 发布安卓参数设置

    Getting Started with NRSDK NRSDK 原文链接 Quickstart for Android NRSDK 1 7 0 documentationhttps nrealsdkdoc readthedocs io e
  • C#学习笔记 文件操作

    获得文件和文件夹信息 NET管理文件和文件夹信息的类有如下几个 Directory和File类是两个静态类 可以静态地获取文件和文件夹的信息而无需实例化对象 这在只对某个文件或者文件夹执行一次操作的时候是很有用的 Path也是一个静态类 为
  • 智慧城市大脑3.0白皮书:城市大协同,未来可持续。

    智慧城市大脑3 0白皮书 城市大协同 未来可持续 一 中国智慧城市建设真实现状 二 中国智慧城市建设的未来 三 智慧城市 脑3 0核 价值 四 2023年 lt 智慧城市解决方案全套 gt 大合集 一 中国智慧城市建设真实现状 中国智慧城市
  • 用了MQ消息中间件后,我开始后悔了...

    V xin ruyuanhadeng获得600 页原创精品文章汇总PDF 一 前情回顾 上篇文章 为什么要使用MQ消息中间件 这几个问题必须拿下 给大家讲了讲消息中间件引入系统架构的作用 主要是解决哪些问题的 其比较常见的实践场景是 复杂系
  • 家里Wifi网速突然变慢,一招瞬间提速

    家中网速突然变慢 通常是有人蹭你家的Wifi 不用担心 我教你一招瞬间提速 这个提速妙招的原理很简单 把你家的上网设备全部管起来 没加入的一律不让蹭网 接下来跟我一起实操 查看设备信息 我家的路由器是TP LINK 型号 TL WR886N
  • 门面模式

    类图 实现 HardDrive java package com facade public class HardDrive public byte read long lba int size byte bin null read ret
  • 成功解决:把python 3.9降到python3.8

    conda install python 3 8
  • yaml value中双引号转义

    aaa bbb 由于转义 aaa的值会被输出为bbb 若想输出为 bbb 需要改成 aaa bbb
  • python程序memory error_详解解决Python memory error的问题(四种解决方案)

    昨天在用用Pycharm读取一个200 M的CSV的过程中 竟然出现了Memory Error 简直让我怀疑自己买了个假电脑 毕竟是8G内存i7处理器 一度怀疑自己装了假的内存条 下面说一下几个解题步骤 一般就是用下面这些方法了 按顺序试试
  • STM32使用USART串口调试ULN2003驱动步进电机

    传送门 STM32控制ULN2003驱动步进电机28BYJ 48最基础版 使用串口调试步进电机28BYJ 48获得需要转速 当使用STM32控制ULN2003驱动步进电机28BYJ 48时 步进电机转速变化缓慢 想要得到合适的控制速度 需要