文章目录
概要
1.电路功能:使用光电传感器对直流电机转速进行测量,并用数码管显示当前转速。
2.工作原理:利用遮断式红外控制原理对通过的物件计数。红外发光管与光电接收管相对摆放,每当物件通过一次,红外光被遮挡一次,光电接收管的输出电压发生一次变化,这个变化的电压信号通过放大和处理后,形成计数脉冲,送入单片机进行计数,同时利用单片机定时器定时一段时间,即可测出电机的速度。
3.基本要求:使用模块电路,搭建测速系统,满足:A、速度可显示范围 1~9999。B、可设置3档速度模式。
4.扩展要求:使用分立原件(非模块),设计电路基本要求,并且满足:利用PID原理,实现电机速度的稳定闭环控制。
整体架构流程
`
电机转速测量技术在工业自动化、精密制造、航空航天等领域有广泛应用,大部分设备是通过光电码盘或霍尔元件测量电机转速,反馈至伺服驱动器实现闭环控制。
本设计转速信号采集部分选用的是光电码盘和红外光电传感器,其电路可分为前端信号采集、信号处理、显示和电机驱动三个部分。
(一)方案设计框图

(二)电路工作原理
具体电路图如下图所示,包括电源、单片机、光电信号采集与处理、电机驱动、显示五部分。

1.电源部分:整个系统采用5V供电,可利用烧录器提供的5V或者可调电源提供的5V信号。
2.光电信号采集与处理:可以采用槽型光电耦合器作为传感器,其输出信号经过LM393比较器进行处理,将信号整形放大输出,当有无物体遮挡,模块输出高低电平,同时有LED同步显示输出。模块输出的计数脉冲信号送入后续电路进行处理。


3.显示部分:采用四位共阳数码管,由四个PNP型三极管来驱动,由单片机P0、P3端口控制。
4.电机驱动部分:采用TB6612芯片驱动电机,芯片内部集成双通道H桥电路,可通过端口给定逻辑实现电机正反转、制动等功能,改变输入PMW信号占空比可控制电机转速变化。

(三)主要元件介绍
1.TB6612
TB6612FNG是一款新型驱动器件,能独立双向控制2个直流电机,它具有很高的集成度,同时能提供足够的输出能力,运行性能和能耗方面也具有优势,因此在集成化、小型化的电机控制系统中,它可以作为理想的电机驱动器件。AINI/AIN2、BIN1/BIN2、PWMA/PWMB为控制信号输人端;A01/A02、B01/B02为2路电机控制输出端;STBY为正常工作/待机状态控制引脚;VM(<10 V)和VCC(2.7~5.5 V)分别为电机驱动电压输入和逻辑电平输入端。具体引脚定义与控制逻辑见下图所示。


2.LM393
LM393是一种广泛使用的电压比较器IC,提供8引脚DIP、SO-8和其他封装。LM393包含两个独立的高精度比较器运算放大器,可由单电源或双电源供电。电源电压范围宽,可以用于多种应用。该芯片需要低工作电流,非常适合便携式和电池供电设备,输出驱动逻辑系统可以用在数字电路中。LM393的最大输出电流为20mA,足以驱动晶体管和逻辑系统。


技术细节
PCB顶层

PCB底层

c
#include <reg52.h>
#include <intrins.h>
#include <stdlib.h>
// =================== 1. ???? ===================
#define MOTOR_DISK_HOLES 36 // ???????36?
#define PID_PERIOD_MS 50 // PID ???? 50ms
// =================== 2. ???? ===================
sbit DIG_1 = P3^4;
sbit DIG_2 = P3^7;
sbit DIG_3 = P3^6;
sbit DIG_4 = P3^5;
// TB6612
sbit PWM_PIN = P2^0;
sbit AIN2 = P2^1;
sbit AIN1 = P2^2;
// ??
sbit KEY_SW1 = P1^0;
// =================== 3. ???? ===================
volatile unsigned int pulse_count = 0;
int real_rpm = 0;
int target_rpm = 0;
// --- PID ?? (?? 1000 RPM ??????) ---
int Kp = 120; // ?? (1.2) - ?????
int Ki = 45; // ?? (0.45) - ?????????
int Kd = 0; // ??
long err = 0;
long last_err = 0;
long sum_err = 0;
int pwm_duty = 0;
unsigned char pwm_tick = 0;
unsigned int pid_timer = 0;
unsigned char speed_mode = 0;
// ?????
unsigned char code SMG_Code[] = {0x28, 0xEE, 0x32, 0xA2, 0xE4, 0xA1, 0x21, 0xEA, 0x20, 0xA0};
unsigned char Display_Buf[4] = {0x28, 0x28, 0x28, 0x28};
// =================== ???? ===================
void Delay_Short(unsigned int t);
void Display_Scan();
void Set_Display_Num(int num);
void PID_Compute_Fast();
void Motor_Set_Mode(unsigned char mode);
// =================== ??? ===================
void main()
{
AIN1 = 0; AIN2 = 0; PWM_PIN = 0;
// ???0 ???
TMOD &= 0xF0; TMOD |= 0x01;
TH0 = (65536 - 100) / 256;
TL0 = (65536 - 100) % 256;
ET0 = 1; TR0 = 1;
// ????0 ???
IT0 = 1; EX0 = 1; EA = 1;
while(1)
{
Display_Scan(); // ??????
if(KEY_SW1 == 0)
{
Delay_Short(200); // ??
if(KEY_SW1 == 0)
{
speed_mode++;
if(speed_mode > 3) speed_mode = 0;
// ????????
Motor_Set_Mode(speed_mode);
while(KEY_SW1 == 0) Display_Scan();
}
}
}
}
// =================== ???? ===================
void Int0_Routine() interrupt 0
{
pulse_count++;
}
void Timer0_Routine() interrupt 1
{
TH0 = (65536 - 100) / 256;
TL0 = (65536 - 100) % 256;
// --- PWM ?? ---
pwm_tick++;
if(pwm_tick >= 100) pwm_tick = 0;
if(target_rpm > 0)
{
if(pwm_tick < pwm_duty) PWM_PIN = 1;
else PWM_PIN = 0;
}
else
{
PWM_PIN = 0;
}
// --- PID ?? (50ms) ---
pid_timer++;
if(pid_timer >= 500)
{
pid_timer = 0;
// ?? RPM: (?? * 1200) / 36
real_rpm = (int)(((long)pulse_count * 1200) / MOTOR_DISK_HOLES);
pulse_count = 0;
if(target_rpm > 0)
{
PID_Compute_Fast();
AIN1 = 1; AIN2 = 0; // ??
}
else
{
pwm_duty = 0;
sum_err = 0;
AIN1 = 0; AIN2 = 0;
}
Set_Display_Num(real_rpm);
}
}
// =================== ?? PID ?? ===================
void PID_Compute_Fast()
{
long output_val;
// 1. ????
err = (long)target_rpm - (long)real_rpm;
// 2. ????
sum_err += err;
// ????
if(sum_err > 4000) sum_err = 4000;
if(sum_err < -4000) sum_err = -4000;
// 3. ?? P + I
output_val = (Kp * err) + (Ki * sum_err);
// 4. ??? (??100)
output_val = output_val / 100;
// 5. ???? (????)
// ???1000?,?????????,?? 25
if(target_rpm > 0)
{
output_val += 25;
}
// 6. ????
if(output_val > 100) output_val = 100;
if(output_val < 0) output_val = 0;
pwm_duty = (int)output_val;
}
// =================== ?????? (????) ===================
void Motor_Set_Mode(unsigned char mode)
{
switch(mode) {
case 0:
target_rpm = 0;
break;
case 1:
target_rpm = 1000; // ???????? 1000
break;
case 2:
target_rpm = 2000; // ???????? 2000
break;
case 3:
target_rpm = 3000; // ???????? 3000
break;
}
// ??:?????????????2000?,????3000??,
// PWM????100%,?????????????????
}
// =================== ????? ===================
void Set_Display_Num(int num)
{
if(num < 0) num = 0;
if(num > 9999) num = 9999;
Display_Buf[0] = SMG_Code[num / 1000];
Display_Buf[1] = SMG_Code[num % 1000 / 100];
Display_Buf[2] = SMG_Code[num % 100 / 10];
Display_Buf[3] = SMG_Code[num % 10];
}
void Display_Scan()
{
P0 = 0xFF; DIG_1 = 0; DIG_2 = 1; DIG_3 = 1; DIG_4 = 1; P0 = Display_Buf[0]; Delay_Short(30);
P0 = 0xFF; DIG_1 = 1; DIG_2 = 0; DIG_3 = 1; DIG_4 = 1; P0 = Display_Buf[1]; Delay_Short(30);
P0 = 0xFF; DIG_1 = 1; DIG_2 = 1; DIG_3 = 0; DIG_4 = 1; P0 = Display_Buf[2]; Delay_Short(30);
P0 = 0xFF; DIG_1 = 1; DIG_2 = 1; DIG_3 = 1; DIG_4 = 0; P0 = Display_Buf[3]; Delay_Short(30);
P0 = 0xFF;
}
void Delay_Short(unsigned int t)
{
while(t--);
}
小结
本文设计并实现了一个基于51单片机的直流电机转速测量与控制系统。系统采用遮断式红外光电传感器(槽型光电耦合器)进行转速信号采集,通过LM393比较器对信号进行整形放大,生成计数脉冲送入单片机。单片机(STC89C52)通过定时器中断和外部中断对脉冲进行计数与定时,计算出实时转速,并驱动四位共阳数码管进行显示。电机驱动部分采用TB6612芯片,通过PWM信号控制电机转速。系统实现了三档速度模式(0、1000、2000、3000 RPM)的切换,并引入了简化的PID控制算法,对电机转速进行闭环调节,以提高系统的稳定性和响应速度。整个设计涵盖了从传感器信号采集、处理、显示到电机驱动的完整流程,并提供了详细的电路原理图、PCB布局以及核心单片机代码,是一个完整的嵌入式测控系统实践案例。