STM32F103C8T6编码器电机的使用_stm32驱动编码器电机_曦考的博客-程序员宅基地

技术标签: stm32  c语言  单片机  

目录

前言

一、定时器部分和按键部分

二、PWM调速

三、电机驱动部分​​​​​​​

三、编码器接口部分(测速)

四.主函数

总结​​​​​​​


推荐STM32学习课程:

[6-8] 编码器接口测速_哔哩哔哩_bilibili[6-8] 编码器接口测速是STM32入门教程-2022持续更新中的第20集视频,该合集共计30集,视频收藏或关注UP主,及时了解更多相关视频内容。https://www.bilibili.com/video/BV1th411z7sn/?p=20&spm_id_from=pageDriver&vd_source=ed36b2700bbc2bac7746c270bc391540OLED显示屏代码:

STM32F103C8T6延时函数和OLED显示屏代码_HX091624的博客-程序员宅基地

前言

电机编码器是安装在电机上的旋转编码器,它通过跟踪电机轴的速度和/或位置来提供闭环反馈信号。监视的参数由应用的类型确定,可以包括速度,距离,RPM,位置等。利用编码器或其他传感器控制的特定参数的应用称为闭环反馈或闭环控制系统


一、定时器部分和按键部分

#include "stm32f10x.h"                  // Device header

//定时中断->1s
void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}

/*
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}
*/
#include "stm32f10x.h"    

void Key_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

uint8_t Key_GetNum(void)
{
	uint8_t KeyNum = 0;
	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
	{
		Delay_ms(20);
		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);
		Delay_ms(20);
		KeyNum = 1;
	}
	
	return KeyNum;
}

二、PWM调速

#include "stm32f10x.h"                 
//定时器3->PWM调速  周期20MS  计一个数->1US
void PWM_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	//电动机PWM输出 PA6 PA7
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	//舵机PWM输出  PB0
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM3);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;		 			//CCR
	TIM_OC1Init(TIM3, &TIM_OCInitStructure); 			//PWM输出引脚
	TIM_OC2Init(TIM3, &TIM_OCInitStructure);
	TIM_OC3Init(TIM3, &TIM_OCInitStructure);
	
	TIM_Cmd(TIM3, ENABLE);
}

//左右电机输出比较
void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM3, Compare);
}

void PWM_SetCompare2(uint16_t Compare)
{
	TIM_SetCompare2(TIM3, Compare);
}

//舵机输出比较
void PWM_SetCompare3(uint16_t Compare)
{
	TIM_SetCompare3(TIM3, Compare);
}

三、电机驱动部分

电机:电机如何驱动在我之前的文章有写,这里就不再解释了。

 

#include "stm32f10x.h"             
#include "PWM.h"

//左右电机初始化
void Motor_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	//电机控制模拟输入端
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	//控制左电机->PA0 PA1 控制右电机->PA4 PA5
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1|GPIO_Pin_4 | GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	PWM_Init();
}

//右边电机向前
void Right_moto_go(void)
{
	//正转
	GPIO_SetBits(GPIOA, GPIO_Pin_4);
	GPIO_ResetBits(GPIOA, GPIO_Pin_5);
}

//右边电机向后
void Right_moto_back(void)
{
	//反转
	GPIO_ResetBits(GPIOA, GPIO_Pin_4);
	GPIO_SetBits(GPIOA, GPIO_Pin_5);
}

//右边电机停止
void Right_moto_Stop(void)
{
	//停车
	GPIO_ResetBits(GPIOA, GPIO_Pin_4);
	GPIO_ResetBits(GPIOA, GPIO_Pin_5);
}

//左边电机向前
void Left_moto_go(void)
{
	//正转
	GPIO_SetBits(GPIOA, GPIO_Pin_0);
	GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}

//左边电机向后
void Left_moto_back(void)
{
	//反转
	GPIO_ResetBits(GPIOA, GPIO_Pin_0);
	GPIO_SetBits(GPIOA, GPIO_Pin_1);
}

//左边电机停止
void Left_moto_Stop(void)
{
	//停车
	GPIO_ResetBits(GPIOA, GPIO_Pin_0);
	GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}

#include "stm32f10x.h"                  
#include "Motor.h"
#include "PWM.h"
	
//小车调速函数
void Speed_Control(uint16_t Compare)
{
	Compare*=200; 				//100->20000	
	PWM_SetCompare1(Compare); 	//调速
	PWM_SetCompare2(Compare);
}

//小车前进函数
void run(uint16_t Compare)
{
	Speed_Control(Compare);
	Left_moto_go();      		//左电机往前
	Right_moto_go();       		//右电机往前
}

//小车后退函数
void backrun(uint16_t Compare)
{
	Speed_Control(Compare);
	Left_moto_back();      		//左电机往后
	Right_moto_back();     		//右电机往后
}

//小车停车函数
void stop(void)         		
{   	
	Left_moto_Stop();      		//左电机停止
	Right_moto_Stop();     		//右电机停止
}

三、编码器接口部分(测速)

编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度。

#include "stm32f10x.h"                  // Device header
//测速
void Encoder_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
    //TIM1的CH1和CH2
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
		
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure);

	//在TI1和TI2上计数
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICStructInit(&TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
	TIM_ICInit(TIM1, &TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
	TIM_ICInit(TIM1, &TIM_ICInitStructure);
	//定时器编码器接口配置  //通道不反相
	TIM_EncoderInterfaceConfig(TIM1, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
	
	TIM_Cmd(TIM1, ENABLE);
}

int16_t Encoder_Get(void)
{
	int16_t Temp;
	Temp = TIM_GetCounter(TIM1);
	TIM_SetCounter(TIM1, 0);
	return Temp;
}

四.主函数

#include "stm32f10x.h"            
#include "Key.h"
#include "OLED.h"
#include "Timer.h"
#include "Motor.h"
#include "MotorRun.h"
#include "Encoder.h"

int16_t Speed;
int8_t KeyNum;

int main(void)
{
	Key_Init();
	OLED_Init();
	Timer_Init();
	Motor_Init();
	Encoder_Init();
		
	OLED_ShowString(1, 1, "Speed:");
	
	while (1)
	{
		KeyNum=Key_GetNum();
        //电机旋转
		if(KeyNum==1)
		{
			run(50);
		}
		OLED_ShowSignedNum(1, 7, Speed, 5); //显示速度
	}
}

void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
        //每隔一段时间获取速度
		Speed = Encoder_Get();
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

总结

注意:两个输入引脚借用了输入捕获的通道1和通道2,而接通道3和通道4是没有用的。

以上就是编码器电机的代码,欢迎大家留言评论,遇到问题都可以在评论区留言。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/HX091624/article/details/127379465

智能推荐

cad尺寸标注快捷键_CAD软件中如何修改设置CAD标注尺寸的值?-程序员宅基地

使用浩辰CAD软件绘制图纸的过程中,在对CAD图纸进行CAD标注时,一般默认会标注上测量值。但是当我们需要在其中添加一些特殊符号或者是标注一些非比例数值的时候,比如在测量值的基础上添加文字或公差或者是用其他数值替代测量值,此时该如何修改呢?接下来给大家介绍一下浩辰CAD软件中修改设置CAD标注尺寸的操作教程吧!修改设置CAD标注尺寸的操作步骤:实际上非常简单,浩辰CAD软件中CAD标注的数值就是文..._cad标注双击改不了尺寸

UE4初学笔记_ue4笔记_水蓝城城主的博客-程序员宅基地

文章目录开放参数至蓝图暴露类暴露属性暴露函数暴露结构体代理单播代理和多播代理区别动态代理和非动态代理的区别使用代理多播TArray参考资料开放参数至蓝图C++中常常使用UE4中的一些宏来设置想要暴露于蓝图的类、属性、方法等。暴露类使用UCLASS([specifiers])暴露类至蓝图,其中的specifiers在暴露类的时候并不常用,并在第一行使用GENERATED_BODY(),添加头..._ue4笔记

学习Mybatis框架总结_mybatis框架技术是支持sql指令执行的orm框架。mybatis框架有独立项目结构与依赖,_桔桔win的博客-程序员宅基地

学习Mybatis框架(持久层框架)—介绍篇1.1.1 什么是框架框架(Framework)是整个或部分系统的可重设计,表现为一组抽象构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架。前者是从应用的方面,后者是从目的方面给出的定义。(半成品的应用)三层架构—表现层,业务层,持久层表现层:用于展示数据的业务层:是处理业务需求持久层:和数据库就行交互的持久层技术的解决方案:JDBC技术:1、Connection2、PreparedStatement3、Result_mybatis框架技术是支持sql指令执行的orm框架。mybatis框架有独立项目结构与依赖,

connect resource权限详解_smallke的博客-程序员宅基地

grant connect,resource to user;后用户包括的权限CONNECT角色: --是授予最终用户的典型权利,最基本的 ALTER SESSION --修改会话 CREATE CLUSTER --建立聚簇 CREATE DATABASE LINK --建立数据库链接 CREATE SEQUENCE --建

[Codevs][1296][营业额统计]_weixin_30527423的博客-程序员宅基地

原题地址模板题,就不说了,相信做了前面几道题就会这个了。。。就找一找前驱和后继嘛。。。。注意一个点:这里一个数的“前驱”和“后继”应包括那个数本身。[因为数据中有重复的数,我用bitset判重会re,不知是不是因为毒瘤数据。。。]强上代码 :#include<cstdio>#include<cstring>#include..._线性表的应用:营业额的统计

淘宝 生成 图片二维码分享_淘宝分享码实现_cm_xuan77的博客-程序员宅基地

最近公司需求提出仿淘宝分享生成一张含有图片/二维码/文字的图片实现方法:采用的canvas 插入图片和生成图片的功能生成二维码采用的是QRCode 插件实现效果:实现步骤:我是在vue环境中实现的1.引入qrcode1安装插件 npm install qrcode2、在main.js中引入import QRCode from 'qrcode' //定义生成二维码组件..._淘宝分享码实现

随便推点

python小项目--图片转字符画_bugkingyzy的博客-程序员宅基地

项目目的:输入一幅图像,输出一个文本,其中每个图像中的像素根据其颜色的不同,用不同的字符表示。效果:解析这个项目通过解析图片像素的亮度,通过rgb亮度公式找到相应的字符,代替原来的像素点。首先需要建立图像像素颜色(这里是灰度值)对应的字符列表。这里我们使用’’’$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/|()1{}[]?-_+~<>i!lI;:,"^`’. ‘’'这个字符串当中的字符建议灰度-字符映射表的右侧。使用int(0.2126

【git】【关联多个git账号】_git 账号 能不能关联其他账号_叩钉吧zz的博客-程序员宅基地

关联多个git账号的方法1 生成不同名字的ssh keyssh-keygen -t rsa -f ~/.ssh/id_rsa_gitlab_UCD -C "[email protected]"复制pub文件内容到gitlab的ssh上2 在.ssh文件夹下新建config编辑 host的前缀可以自定义,但是host name就要用gitlab的域名。前缀自定义后,clone时需要加上这个前缀,怪麻烦的,所以可以设置和host name一样。但这也限制了,同一个域名下,只能用一个g._git 账号 能不能关联其他账号

google运行速度最近突然变慢了!!怎么回事!!!完美解决!!_谷歌浏览器突然很卡_唔使般若的博客-程序员宅基地

有没有发现最近google(谷歌Chrome)浏览器突然变得很卡很慢,以前秒开的日子仿佛不复存来了!!ladies and gentleman ,Here comes the perfect solution!!!!我也是最近才发现google打开网页变得很慢了,我感觉可能是更新了的问题,我查看了关于google最近的更新日志,和设置,通过不断调试后发现了影响google打开网页速度的关键因素!!Google Chrome 从Chrome 83 开始推出l安全DNS,google默认使用的是国外的DN_谷歌浏览器突然很卡

python global和nonlocal_python-global和nonlocal区别_weixin_39859061的博客-程序员宅基地

原博文2020-04-24 17:14 −# L = Local 局部作用域# E = Enclosing 嵌套作用域# N = nonlocal 只作用于嵌套作用域,而且只是作用在函数里面# G = global 全局作用域# B = Built-in 内置作用域"""locals()函数返回一个当前位置的...相关推荐2019-12-22 16:35 −一:global:在函数内部引用/..._什么情况下global和nonl

【转】Java虚拟机详解----JVM常见问题总结_长江七号zzj的博客-程序员宅基地

文章来源:http://www.cnblogs.com/smyhvae/p/4810168.html 【正文】声明:本文只是做一个总结,有关jvm的详细知识可以参考本人之前的系列文章,尤其是那篇:Java虚拟机详解04----GC算法和种类。那篇文章和本文是面试时的重点。面试必问关键词:JVM垃圾回收、类加载机制。 先把本文的目录画一个思维导图:(图的源文件在本文...

什么是回调函数_smallsmallwhite1206的博客-程序员宅基地

回调函数,就是由你自己写的。你需要调用另外一个函数,而这个函数的其中一个参数,就是你的这个回调函数名。这样,系统在必要的时候,就会调用你写的回调函数,这样你就可以在回调函数里完成你要做的事。模块A有一个函数foo,它向模块B传递foo的地址,然后在B里面发生某种事件(event)时,通过从A里面传递过来的foo的地址调用foo,通知A发生了什么事情,让A作出相应反应。 那么我们就把foo称为回