stm32 HAL仓库制作转速器
前言
在运行过程中,需要实时检测电机转速的稳定性,有效反映电机的运行情况。
本文介绍了基础stm32转速器的设计可以用光电门传感器和红外对管传感器来测量,可以选择传感器和计数方法来显示测量结果。描述整体设计方案、设备选型、各模块原理分析、软件设计思路及过程。从精度、稳定性等角度制作测试仪并进行测试。转速仪可正常稳定工作,具有结构简单、便携、操作方便等优点,适用于小型直流电机的转速测量。
本文展示用cubeMX MDK制作红外测温枪的过程。 下载工程 关注公众号,回复""建议结合获取工程文件等资料keil工程阅读本文。
效果
{#fig:转速仪}
总体方案设计
方案
红外循迹模块和光耦测速模块分别实现远程测速和近程测速功能。测量小风扇时,每当风扇叶片通过时,模块就会输出脉冲stm32计数器接收脉冲并计数,同时打开定时器进行一秒定时,KaTeX parse error: Undefined control sequence: \mbox at position 1: \?m?b?o?x?{转速}=\frac{\mbo…
用stm32的adc用终端输入检测摇杆XYZ输入,摇杆Y向切换扇叶数,范围为1 9.摇杆的X方向是切换红外测速(远程测速)和光电门测速(近程测速)。 stm32通过SPI与OLED通信、显示屏显示速度、扇叶数量和速度测量模式,按照摇杆的Z方向切换OLED显示方向,辅助数字管显示转速。
{#fig:总体方案框图}
供电模块
采用两节18650电池供电,通过降压稳压模块获得系统工作电压3.3V。
{#fig:供电模块}
主控
使用stm32f103c8t6最小系统板,处理速度数据,执行摇杆指令,控制显示模块。
{#fig:最小系统板}最小系统板}
测速模块
远程测速采用红外循迹模块。
{#fig:红外循迹模块}
近程测速采用光电门模块。
{#fig:槽型光耦传感器}
控制模块
采用双轴按键摇杆传感器模块,控制计数方法,切换传感器,翻转显示屏。
{#fig:双轴按键摇杆传感器}
显示模块
使用0.96寸OLED显示速度、计数方法和当前传感器。
{#fig:0.96寸OLED显示屏模块}
控制模块
由于测试设备的速度有限,只使用四位数字管来显示转速,剩下的两位备用。
{#fig:数码管}
组装
以面包板为载体,结合杜邦线、铜柱等固定模块,完成手持仪器。
测试设备
两节18650电池通过电源模块供电8V、5V、3.3V。 用三个开关分别连接三个电压,另一边连接直流减速电机,模拟三个档位。 三叶小风扇由直流减速电机驱动,作为直接测量的目标。
{#fig:手持测试仪}
{#fig:手持测试仪}
{#fig:手持测试仪}
硬件设计
电源模块
AMS1117芯片
AMS117是一种由正向低压降压器组成的稳压调节管PNP驱动的NPN管组成的,在1A电流压降为1.2V。有AMS固定输出电压1117和可调版.5V,1.8V,2.5V,2.85V,3.0V,3.3V,5.0V,精度为1%,固定输出电压为1.2V精度为2%,典型电路如图3所示.1。
{#fig:AMS1117典型电路}
AMS1117典型电路
选用AMS117-33芯片,88650电池V电压转换为系统工作电压3V3
{#fig:电源模块原理图}
PCB绘制
根据原理图3.2,使用Altium Designer 2019绘制PCB板
{#fig:PCB板三维模型}板三维模型
测速模块
红外循迹模块
红外对射计数传感器TCRT5000可用于电表脉冲数据检测、传真机纸张检测、障碍检测、黑白线检测。
其特点是:检测反射距离为1mm~25mm输出形式为数字开关量输出(0和1)。TCRT5000型传感器的红外发射二极管不断发射红外线。当发射的红外线没有反射或反射,但强度不够大时,红外接收管已熄灭;当检测对象出现在检测范围内时,红外线反射强度足够大,红外接收管饱和,模块输出端低电平,表示二极管点亮。
{#fig:红外循迹模块电路图
对射光电传感器
广泛应用于电机转速检测、脉冲记数、位置限位等领域。
其特点是当模块槽中没有堵塞时,接收管道,模块DO输出低电平;DO输出高电平;DO可与单片机一起输出接口IO口直接连接,检测传感器是否堵塞,如电机码盘,可检测电机转速;模块DO可与继电器连接,形成限位开关等功能。
{#fig:光电门模块电路图
控制模块
双轴按键传感器
两个模拟输出,一个数字输出 Y轴输出为两个电位器,可通过AD将扭转角度转换并向下按下摇杆。您可以一路触摸开关进行数字输出。上拉适用于两个自由舵机云台控制或其他遥控比控制。
采用双轴按键摇杆传感器模块,控制计数方法,切换传感器,翻转显示屏。
软件设计
总体方案
单片机选用stm32f103c8t6.开发平台为STM32CubeMX和Keil MDK,使用HAL库开发。MHz。
开启stm计数器接收传感器脉冲,ADC接收摇杆XY控制信号,外部中断接收摇杆Z信号,硬件SPI与OLED使用12个通信GPIO驱动数码管,USART作为调试接口。
{#fig:stm32资源使用情况}
红外循迹模块和光耦测速模块分别实现远程测速和近程测速功能。测量小风扇时,每当风扇叶片通过时,模块就会输出脉冲stm32计数器接收脉冲并计数,同时打开定时器进行一秒定时。KaTeX parse error: Undefined control sequence: \mbox at position 1: \?m?b?o?x?{转速}=\frac{\mbo…
用stm32的adc用终端输入检测摇杆XYZ输入,摇杆Y向切换扇叶数,范围为1 9.摇杆的X方向是切换红外测速(远程测速)和光电门测速(近程测速)。
stm32通过SPI与OLED通信、显示屏显示速度、扇叶数量和速度测量模式,按照摇杆的Z方向切换OLED显示方向,辅助数字管显示转速。
{#fig:程序流程图}
定时器/计数器
开启stm32的定时器TIM内部时钟输入为秒表。
stm32主频设置为72MHz。
{#fig:stm32时钟树}
设置TIM3分频率为7199,计数周期为999 f = 72 , 000 , 000 H z ( 7199 1 ) ( 9999 1 ) = 1 H z f=\frac{72,000,000Hz}{(7199 1)(9999 1)}=1Hz f=(7199+1)(9999+1)72,000,000Hz=1Hz
即每秒定时一次,同时开启中断,则每秒钟单片机会进入一次中断。
开启stm32计数器TIM1、TIM2接收测速传感器的脉冲,输入方式为外部脉冲,同时开启最大滤波以排除干扰。
则每当进入秒表中断时,读取计数器寄存器的值,并将该值与上一秒计数器的值作差(第一次时上一秒为0),得到的差即为计数值,该值除以叶片数(由摇杆Y方向控制,初始值为3)得到秒转速,该值可以提供给OLED显示。最后将当前计数器值保存为上一秒计数器值,以便下次调用。
定时器的中断回调函数放在文件counter.c中,程序如下
uint16_t CountThis, CountLast, CountDis; //定义计数器的值、上一秒计数器的值、转速
extern uint8_t Leaves, ModuleFlag; //定义叶片数、传感器标志
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//定时器中断回调函数
{
if(ModuleFlag == 0){ //采集红外传感器脉冲
CountThis = htim2.Instance->CNT;}
else{ //采集光电门传感器脉冲
CountThis = htim1.Instance->CNT;}
CountDis = (CountThis - CountLast)/Leaves;//计算转速
// printf("\t%d r/s\r\n",CountDis);
OLED_ShowNum(48,0,CountDis,3,16);//OLED显示刷新
OLED_Refresh();
CountLast = CountThis; //将此次计数器值保存为上一秒计数值
}
ADC
开启stm32的两个ADC采集摇杆模块的XY控制信号。由于当前ADC采集范围为0 3.3V,采集精度为12位。
{#fig:stm32ADC参数配置}
故摇杆模块供电VCC=3.3V,则当当X或Y轴不偏时,VRX/VRY管脚电压为1.65V;X/Y轴正方向偏到最大时,VRX/VRY管脚电压为3.3V;X/Y轴负方向偏到最大时,VRX/VRY管脚电压为0V。此时用ADC管脚接收,读取ADC寄存器可分别得数值2000、4096、0即代表不偏、正偏最大、反偏。
由三个值可判断摇杆的控制信号,设定当Y轴正偏一次,叶片数+1,反偏一次,叶片数-1;当X轴正偏或反偏则切换两个传感器。
ADC的采集放在main函数的while中,以5ms/次的频率扫描,程序如下:
while (1)
{
Dis_2Num(CountDis); //数码管显示
HAL_Delay(5); //每5ms进行一次采集
HAL_ADC_Start(&hadc1); //开启adc1
VRX = HAL_ADC_GetValue(&hadc1); //采集adc1的值
HAL_ADC_Start(&hadc2); //开启adc2
VRY = HAL_ADC_GetValue(&hadc2); //采集adc2的值
if(VRY > 3500){ //当VRY>3500,认为Y轴正偏一次
adc_Flag ++;
HAL_Delay(10);
if(adc_Flag == 2){
if(Leaves<9)Leaves ++; //叶片数+1
OLED_ShowNum(56,16,Leaves,1,16);//叶片数显示刷新
OLED_Refresh();
adc_Flag = 0;
HAL_Delay(400); //增加延时避免一次识别为多次
}
}
else if(VRY < 500){ //当VRY<500,认为Y轴正偏一次
adc_Flag ++;
HAL_Delay(10);
if(adc_Flag == 2){
if(Leaves>1)Leaves --; //叶片数-1
OLED_ShowNum(56,16,Leaves,1,16); //叶片数显示刷新
OLED_Refresh();
adc_Flag = 0;
HAL_Delay(400); //增加延时避免一次识别为多次
}
}
if((VRX > 3500)||(VRX < 500)){ //当VRX<500||VRX>3500,认为X轴偏一次
mol_Flag ++;
HAL_Delay(10);
if(mol_Flag == 2){
if(ModuleFlag == 0){ //当前传感器为红外传感器时
ModuleFlag = 1; //切换为光电门传感器
OLED_ShowChinese(32, 48, 8, 16);//显示刷新
OLED_ShowChinese(48, 48, 9, 16);
}
else{ //当前传感器为光电门传感器时
ModuleFlag = 0; //切换为红外传感器
OLED_ShowChinese(32, 48, 4, 16);//显示刷新
OLED_ShowChinese(48, 48, 5, 16);
}
mol_Flag = 0;
HAL_Delay(400); //增加延时避免一次识别为多次
}
}
}
外部中断
在遥感模块VCC=3.3V,SW管脚接上拉电阻前提下,当Z不按下时SW管脚为3.3V,当Z按下时SW管脚为0V。
故开启管脚PA3的外部中断输入模式,接上拉电阻,检测上升沿,即可判断Z是否按下。
{#fig:TIM3配置}
extern uint8_t TurnFlag;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)//中断回调函数
{
if(GPIO_Pin == KEY_Z_Pin) //判断PA3接收到中断
{
if(TurnFlag == 1)TurnFlag = 0;
else TurnFlag = 1;
OLED_DisplayTurn(TurnFlag); //反转屏幕指令
HAL_Delay(100);
}
}
SPI
开启stm32的spi控制OLED屏幕,调用HAL库SPI函数和现成OLED库函数可以控制OLED显示中文、数字、字幕。
{#fig:0.96寸OLED显示内容}
直接调用的上层函数有:
OLED_Init(); //OLED初始化
OLED_Clear(); //清除显示内容
OLED_DisplayTurn(TurnFlag); //显示方向设置
OLED_ShowChinese(0, 0, 0, 16); //显示中文
OLED_Printf(80, 0, "r/s", 16); //显示字母
OLED_ShowNum(56,16,Leaves,1,16); //显示数字
OLED_Refresh(); //显示刷新
数码管
由数码管的原理,由于本次显示内容少,显示要求低,stm32主频较高,故采用循环显示的方式。
由于stm32GPIO口的推挽输出模式可以提供足够大的电流,使LED有较高亮度,故本次不需要放大,直接在LED的阳极接推挽输出高电平,在LED的阴极接推挽输出低电平,配合控制代码可以显示数字。
开启stm32的十二个GPIO的推挽输出模式,其中八个作为阳极显示数字,四个作为阴极选择显示位置。
{#fig:数码管相关GPIO配置情况}
显示单个数字函数如下:(显示位置1,数字1,其余同理省略)
void Dis_Num(uint8_t DIG, uint8_t NUM)
{
switch(DIG)
{
case 1:
HAL_GPIO_WritePin(DIG1_GPIO_Port,DIG1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(DIG2_GPIO_Port,DIG2_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(DIG3_GPIO_Port,DIG3_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(DIG4_GPIO_Port,DIG4_Pin,GPIO_PIN_SET);
break;
……
}
switch(NUM)
{
case 1:
HAL_GPIO_WritePin(A_GPIO_Port,A_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(B_GPIO_Port,B_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(C_GPIO_Port,C_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(D_GPIO_Port,D_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(E_GPIO_Port,E_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(F_GPIO_Port,F_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(G_GPIO_Port,G_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(DP_GPIO_Port,DP_Pin,GPIO_PIN_RESET);
break;
……
}
}
显示两个数字可通过除和取余提取个位与十位实现,函数如下:
uint8_t NumFlag = 0; //个位与十位显示顺序标志,交换顺序使两位显示时长对称
void Dis_2Num(uint8_t Number)
{
uint8_t Decade,Uint;
Decade = Number/10; //除法取十位
Uint = Number%10; //取余取个位
if(NumFlag == 0){
Dis_Num(2,Decade); //显示十位
Dis_Num(3,Uint); //显示个位
NumFlag = 1;
}
else{
Dis_Num(3,Uint);
Dis_Num(2,Decade);
NumFlag = 0;
}
}
{#fig:显示效果}
到此转速仪已经完成。
下载
关注公众号,回复""获取工程文件及其他资料,建议结合工程阅读本文。