基于STM32与红外感应开关的自动门设计与实现
采用STM32作为主控,设计了自动和手动开门装置,MLX90614作为设计测温装置。
前言说明
元器件清单说明
- STM32F103C8T6系统板
- 微型滑台,步进电机
- TMC2208步进电机驱动器
- 红外接近开关
- MLX90614测温模块
- 四线0.96寸OLED屏幕
- 按键
- 限位触碰开关
Soildworks模型绘制
原理图绘制
TMC2208驱动介绍
TMC2208是一款超静音的两相步进电机驱动芯片,持续驱动电流1.4A,峰值电流2A,电压范围4.75V-36V,256细分;灵活的microPlyer插值单元,可提供高达256的细分,即使是在脉冲频率有限的系统中仍可完美地实现正弦控制;由于stealthChop2超静音技术在3D打印中被广泛应用,因此这些组件的设计也与现有3D打印机电子设备兼容,省去了重新设计所产生的昂贵费用。具有标准的step/dir接口,使用起来简单方便。可以替代原有的TMC2100,更低的发热量,特别适合3D打印市场。关键引脚说明
引脚 | 说明 |
---|---|
GND | 地 |
VM | 我给的是5V1A |
VIN | 逻辑电平输入3-5V |
1A | 相A+ |
2A | 相B+ |
1B | 相A- |
2B | 相B- |
DIR | 方向输入 |
EN | 使能,低电平有效 |
STEP | 输入脉冲数 |
MS1 | 细分 |
MS2 | 细分 |
步进电机介绍
采用SM15-80L微型滑台作为门的载体,该滑台属于步进电机控制直接给高低电平是驱动不了的。
关键代码
下面展示一些 内联代码片
。
void EXTI0_IRQHandler(void)
{
delay_ms(10); //消抖
if(KEY_Limit_Switch==0)
{
Limit_Switch_Finish=0;
}
EXTI_ClearITPendingBit(EXTI_Line0); //清除EXTI0线路挂起位
}
void EXTI4_IRQHandler(void)
{
delay_ms(10); //消抖
u8 i,j;
float Temperature = 0; //温度数据变量(浮点型)
char TempValue[80] = {0}; //温度值(字符串)
if(KEY_Infrared==0&&Opening==0)
{
Opening=1;
Door_Open_Flag = 1;
Locate_Rle3(5000,CCW,24000); //CCW往电机
Temperature = SMBus_ReadTemp();
sprintf(TempValue,"%.1f", Temperature); //浮点型转换成字符串
//温度单位显示 (℃)
for(i = 6;i < 7;i++)
{
j = i - 6;
OLED_ShowCHinese16x16(i*16,4,j,TempCompany);
}
OLED_ShowString(40,4,(uint8_t *)TempValue,16);//在在OLED上显示实际测量的温度
}
else if(KEY_Infrared==0&&Opened==1)
{
Door_Opened_Flag = 1;
}
EXTI_ClearITPendingBit(EXTI_Line4); //清除LINE5上的中断标志位
}
void EXTI15_10_IRQHandler(void)
{
delay_ms(10); //消抖
u8 i,j;
float Temperature = 0; //温度数据变量(浮点型)
char TempValue[80] = {0}; //温度值(字符串)
if(KEY==0&&Opening==0)
{
Opening=1;
Door_Open_Flag = 1;
Locate_Rle3(5000,CCW,24000); //CCW往电机
Temperature = SMBus_ReadTemp();
sprintf(TempValue,"%.1f", Temperature); //浮点型转换成字符串
//温度单位显示 (℃)
for(i = 6;i < 7;i++)
{
j = i - 6;
OLED_ShowCHinese16x16(i*16,4,j,TempCompany);
}
OLED_ShowString(40,4,(uint8_t *)TempValue,16);//在在OLED上显示实际测量的温度
}
else if(KEY==0&&Opened==1)
{
Door_Opened_Flag = 1;
}
EXTI_ClearITPendingBit(EXTI_Line15); //清除LINE15线路挂起位
}
程序主要是通过外部引起中断执行的,一共用了三个中断,分别对应着手动开门,红外感应开门以及限位开关三个部分。
驱动代码块
#include "driver.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
long current_pos[2]={0,0}; //有符号方向
u16 Motor_Step;
DIR_Type motor_dir3=CW;
u16 count[3]={0,0,0};
extern u8 Door_Open_Flag;
extern u8 Limit_Switch_Finish;
u8 Time_Flag=0;
u8 Limit_Switch_Flag=0;
u8 Flag=0;
extern u8 Opening;
u8 Opened=0;
/************** 驱动器控制信号线初始化 ****************/
void Driver_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE); //使能PA端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //PC0.2 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA
GPIO_SetBits(GPIOA,GPIO_Pin_5); //PA8输出高 顺时针方向 DRIVER_DIR
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_ResetBits(GPIOB,GPIO_Pin_1); //PA11输出低 使能输出 DRIVER_OE
Limit_Switch_Flag=1;
Locate_Limit(5000,CCW);
while(Flag==0);
Flag=0;
Locate_Limit(5000,CW);
}
void TIM3_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler =psc;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
TIM_UpdateRequestConfig(TIM3,TIM_UpdateSource_Regular);
TIM_SelectOnePulseMode(TIM3,TIM_OPMode_Single);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = arr>>1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3, ENABLE);
TIM_ITConfig(TIM3, TIM_IT_Update ,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
TIM_Cmd(TIM3, DISABLE);
}
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_FLAG_Update)!=RESET)
{
TIM_ClearITPendingBit(TIM3,TIM_FLAG_Update); //清除中断
if(motor_dir3==CW) //关门
{
TIM_GenerateEvent(TIM3,TIM_EventSource_Update);
TIM_Cmd(TIM3, ENABLE);
if(Limit_Switch_Finish==0)
{
Limit_Switch_Finish=1;
Opening = 0;
TIM_Cmd(TIM3, DISABLE);
}
}
else
{
if(Limit_Switch_Flag==1) //开始限位
{
count[0]++;
TIM_GenerateEvent(TIM3,TIM_EventSource_Update);
TIM_Cmd(TIM3, ENABLE);
if(count[0]==1000)
{
count[0]=0;
Flag=1;
TIM_Cmd(TIM3, DISABLE);
LED0=0;
Limit_Switch_Flag=0;
}
}
else
{
count[1]++;
TIM_GenerateEvent(TIM3,TIM_EventSource_Update);
TIM_Cmd(TIM3, ENABLE);
if(count[1]==Motor_Step) //24000
{
Opened = 1;
count[1]=0;
TIM_Cmd(TIM3, DISABLE);
if(Door_Open_Flag==1)
{
Time_Flag=1;
}
}
}
}
}
}
void TIM3_Startup(u32 frequency)
{
u16 temp_arr=1000000/frequency-1;
TIM_SetAutoreload(TIM3,temp_arr);
TIM_SetCompare2(TIM3,temp_arr>>1);
TIM_SetCounter(TIM3,0);
TIM_Cmd(TIM3, ENABLE);
}
/********************************************
//相对定位函数
//num 0~2147483647
//frequency: 20Hz~100KHz
//dir: CW(顺时针方向) CCW(逆时针方向)
*********************************************/
void Locate_Rle3(u32 frequency,DIR_Type dir,u16 step) //相对定位函数
{
if(TIM3->CR1&0x01)
{
// printf("\r\nThe last time pulses is not send finished,wait please!\r\n");
return;
}
if((frequency<20)||(frequency>100000))
{
// printf("\r\nThe frequency is out of range! please reset it!!(range:20Hz~100KHz)\r\n");
return;
}
motor_dir3=dir;
DRIVER_DIR3=motor_dir3;
Motor_Step = step;
TIM3_Startup(frequency);
LED0=1;
}
void Locate_Limit(u32 frequency,DIR_Type dir) //相对定位函数
{
if(TIM3->CR1&0x01)
{
// printf("\r\nThe last time pulses is not send finished,wait please!\r\n");
return;
}
if((frequency<20)||(frequency>100000))
{
// printf("\r\nThe frequency is out of range! please reset it!!(range:20Hz~100KHz)\r\n");
return;
}
motor_dir3=dir;
DRIVER_DIR3=motor_dir3;
TIM3_Startup(frequency);
}