一、HC-SR04超声波模块的使用
二、OLED的HAL库代码介绍及使用
三、直流减速电机的测速以及电机驱动的使用(本篇)
文章目录
由于之后要着手开始做一些闭环的小项目,比如常见的两轮平衡小车,那就必须使用编码器来测量直流减速电机的转速,本文将介绍如何使用stm32f103c8t6的编码器模式测量带15线霍尔编码器的直流减速电机的空载转速。
预告:我即将会写一篇全网最详细PID平衡小车教程(HAL库版)
先放上最终效果展示吧
使用STM32的编码器模式测量直流减速电机的转速
提示:以下是本篇文章正文内容,下面案例可供参考
所用的带15线霍尔编码器的GM25-370直流减速电机及其参数见下图


所用模块的具体作用:
蓝牙模块:通过手机蓝牙直接改变电机转速
OLED:实时显示电机的转速以及读取到的脉冲数
特别注意:这步至关重要,稍有不慎就会烧坏单片机
下面给出原理图:(最好不要把电机驱动板上所有的GND都与单片机共地,VCC下面的GND可以不与单片机共地,还有就是STM32只外接信号线,不要用它给电机驱动板的VCC供电,STM32接一些感性负载(比如电机)时最好加光耦隔离,我之前也是用了光耦隔离,但是要想完全隔离只能用双电源,最终就没加)

(1)点击RCC ,开启HSE,并选择RC或晶体作为时钟源

(2)配置时钟树

(1)点击TIM4,在Mode选项中设置Clock Source为Internal Clock。设置Channel1为PWM Generation CH1,其余默认即可。

(2)设置Configuration选项中Parameter Settings的参数
将PWM设置为10KHz

(3)TIM4_CH1 的GPIO参数设置
PB6参数设置

(1)点击TIM3,在Mode选项中设置Combined Channels为编码器模式。

(2)设置Configuration选项中Parameter Settings的参数
注意:将Encoder Mode 设置为Encoder Mode TI1 and TI2,使得编码器模式为4倍频模式,得到的脉冲值X4
编码器模式中Polarity是用来设置触发的信号是否反向,即用来匹配编码器与电机的旋转方向,而不是像“输入捕获”功能那样用来设置触发的边沿


(3)GPIO参数设置

配置定时器,配置为0.1S定时中断一次读取TIM3编码器模式记录的脉冲值

这部分就是开启I2C1的I2C模式,开启USART2的异步模式
开启TIM1 update interrupt,USART2 global interrupt 两个中断并将USART2 global interrupt的优先级设置的高于TIM1 update interrupt,因为要通过串口接收中断来改变转速,如果串口中断的优先级低于定时器中断的优先级,此时串口中断就不能立刻执行



提示:OLED代码见OLED的HAL库代码介绍及使用,这里就不再赘述
#ifndef ENCODER_ENCODER_H_
#define ENCODER_ENCODER_H_
#include "stm32f1xx_hal.h" //HAL库文件声明
#include <main.h>
extern TIM_HandleTypeDef htim1;
extern TIM_HandleTypeDef htim3;
void GET_NUM(void);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
#endif /* ENCODER_ENCODER_H_ */
#include"encoder.h"
#include"../oled/oled.h"
float n=0;//转速,单位为:转/秒
short encoder_counter=0;//STM32编码器模式读取的总脉冲数
/**
* @function: void GET_NUM(void)
* @description: 使用STM32编码器模式,读取编码器产生的脉冲值
* @param {*}
* @return {*}
*/
void GET_NUM(void)
{
encoder_counter=(short) __HAL_TIM_GET_COUNTER(&htim3);
__HAL_TIM_SET_COUNTER(&htim3,0);
}
/**
* @function:void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
* @description: 定时器中断回调函数,0.1S中断一次并计算转速,将电机转速以及编码器产生的脉冲数显示在OLED屏上
* @param {TIM_HandleTypeDef *htim}
* @return {*}
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim==&htim1)
{
GET_NUM();//得到所记录的脉冲数
OLED_Showdecimal(0,6,encoder_counter,5,2,12,0);//在特定位置显示5位整数+2位小数的脉冲数
n=(float)encoder_counter/2040/0.1;//转速为n,r/s
//编码器单圈15脉冲,减速后单圈为510脉冲每圈,可以通过stm32编码器模式4倍频至2040脉冲每圈。定时器中断是0.1S执行一次
OLED_Showdecimal(0,4,n,2,2,12,0);//在特定位置显示2位整数+2位小数的电机转速
}
}
这个.h就是给电机驱动板AO1,AO2赋高低电位的
#ifndef MOTOR_MOTOR_H_
#define MOTOR_MOTOR_H_
#include "stm32f1xx_hal.h" //HAL库文件声明
#include <main.h>
#define MOTOR_GO HAL_GPIO_WritePin(GPIOA, AIN1_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOB, AIN2_Pin, GPIO_PIN_SET)
#endif /* MOTOR_MOTOR_H_ */
/* USER CODE BEGIN Includes */
#include "../../icode/motor/motor.h"
#include "../../icode/usart/usart.h"
#include "../../icode/encoder/encoder.h"
#include "../../icode/oled/oled.h"
/* USER CODE END Includes */
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1); //开启TIM4 PWMA模式
HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);//开启TIM3编码器模式
HAL_UART_Receive_IT(&huart2,(uint8_t *)&USART2_NewData,1); //开启串口二的接收中断,用于蓝牙改变电机转速
HAL_TIM_Base_Start_IT(&htim1);//开启TIM1的定时器中断
OLED_Init(); //OLED初始
OLED_Clear(); //清屏
OLED_ShowString(0,0,"Rotational Speed:",12,0);
OLED_ShowString(50,4,"rad/s",12,0);
/* USER CODE END 2 */
下面这部分main.c内容是通过蓝牙改变电机转速,与本文的重点>通过STM32编码器模式对直流减速电机测速的讲解关系不大
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(USART2_RX_STA&0x8000) //判断中断接收标志位(蓝牙模块使用USART2)
{
if((USART2_RX_STA&0x7FFF) ==4 //判断接收数量是不是为四个
&& USART2_RX_BUF[0]==0xA5 //判断接收第一个数据是不是包头0xA5
&& USART2_RX_BUF[3]==(USART2_RX_BUF[1]+USART2_RX_BUF[2])%0x100) //判断接收校验码是不是原数据之和的低八位
{
switch(USART2_RX_BUF[2]) //接收并读取蓝牙发送过来的第三个数,改变车速
{ //ARR的在CubeMX中设置为20000
case(0x00):__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1,0);break; //0%的speed
case(0x14):__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1,1440) ;break;//20%
case(0x28):__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1,2880) ;break;//40%
case(0x3C):__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1,4320);break;//60%
case(0x50):__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1,5760);break;//80%
case(0x64):__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1,7200);break;//100%
default:break;
}
}
USART2_RX_STA=0;//标志位清0
}
MOTOR_GO;
}
/* USER CODE END 3 */
最终结果就是文章开头视频中显示的,还是测量的比较精准,和电机的参数十分接近,这部分内容对于之后的平衡小车至关重要,因为后续PID控制时要经常读取电机转速来对小车进行闭环控制。
码字不易,希望喜欢的小伙伴别忘了点赞+收藏+关注,你们的肯定就是我创作的动力
欢迎大家积极交流,本文未经允许谢绝转载!!!
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我正在使用ruby1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
在VMware16.2.4安装Ubuntu一、安装VMware1.打开VMwareWorkstationPro官网,点击即可进入。2.进入后向下滑动找到Workstation16ProforWindows,点击立即下载。3.下载完成,文件大小615MB,如下图:4.鼠标右击,以管理员身份运行。5.点击下一步6.勾选条款,点击下一步7.先勾选,再点击下一步8.去掉勾选,点击下一步9.点击下一步10.点击安装11.点击许可证12.在百度上搜索VM16许可证,复制填入,然后点击输入即可,亲测有效。13.点击完成14.重启系统,点击是15.双击VMwareWorkstationPro图标,进入虚拟机主
我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功
查看Ruby代码,它具有以下proc_arity:staticVALUEproc_arity(VALUEself){intarity=rb_proc_arity(self);returnINT2FIX(arity);}更多的是C编码风格问题,但为什么staticVALUE在单独的一行而不是像这样的:staticVALUEproc_arity(VALUEself) 最佳答案 它来自UNIX世界,因为它有助于轻松grep函数的定义:$grep-n'^proc_arity'*.c或使用vim:/^proc_arity
我创建了一个由于“在运行时执行的单例元类定义”而无法编码的对象(这段代码的描述是否正确?)。这是通过以下代码执行的:#defineclassXthatmyusesingletonclassmetaprogrammingfeatures#throughcallofmethod:break_marshalling!classXdefbreak_marshalling!meta_class=class我该怎么做才能使对象编码正确?是否可以从对象instance_of_x的classX中“移除”单例组件?我真的需要一个建议,因为我们的一些对象需要通过Marshal.dump序列化机制进行缓存。
我在使用Ruby1.9.2p290更改文本文件的编码时遇到问题。我收到错误消息invalidbytesequenceinUTF-8(ArgumentError)。问题(我认为)在于字符集似乎是未知的。如果我执行以下操作,则从命令行:$filetest.txt我得到:Non-ISOextended-ASCIIEnglishtext,withCRLFlineterminators或者,或者,如果我这样做:$file-itest.txt我得到:test.txt:text/plain;charset=unknown但是,如果我这样做,在Ruby中:data=File.open("test.tx
我正在向我的Controller发送一个base64图像并按原样保存它。现在我需要显示该图像。这是我要显示的内容,但未显示图像:"/>为了编码,我使用了这个java脚本函数encodeURIComponent();我的编码图像格式:data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/........ 最佳答案 你不需要解码base64应该可以 关于ruby-on-rails-在rails中显示base64编码的图像,我们在StackOve