2018-08-20 00:39:33 HeGuang68207 阅读数 2207
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4002 人正在学习 去看看 朱有鹏

常规舵机
某型号舵机参数简介


伺服电机(servo motor )

伺服电机是指在伺服系统中控制机械元件运转的发动机,是一种补助马达间接变速装置。
伺服电机可以控制速度,位置精度非常准确,可以将电压信号转化为转矩和转速以驱动控制对象。
伺服电机转子转速受输入信号控制,并能快速反应,在自动控制系统中,用作执行元件,且具有机电时间常数小、线性度高、始动电压等特性,可把所收到的电信号转换成电动机轴上的角位移或角速度输出。分为直流和交流伺服电动机两大类,其主要特点是,当信号电压为零时无自转现象,转速随着转矩的增加而匀速下降。


舵机

舵机是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。目前,在高档遥控玩具,如飞机、潜艇模型,遥控机器人中已经得到了普遍应用。
舵机主要是由外壳、电路板、驱动马达、减速器与位置检测元件所构成。其工作原理是由接收机发出讯号给舵机,经由电路板上的 IC驱动无核心马达开始转动,透过减速齿轮将动力传至摆臂,同时由位置检测器送回讯号,判断是否已经到达定位。
位置检测器其实就是可变电阻,当舵机转动时电阻值也会随之改变,藉由检测电阻值便可知转动的角度。
一般的伺服马达是将细铜线缠绕在三极转子上,当电流流经线圈时便会产生磁场,与转子外围的磁铁产生排斥作用,进而产生转动的作用力。依据物理学原理,物体的转动惯量与质量成正比,因此要转动质量愈大的物体,所需的作用力也愈大。舵机为求转速快、耗电小,于是将细铜线缠绕成极薄的中空圆柱体,形成一个重量极轻的无极中空转子,并将磁铁置於圆柱体内,这就是空心杯马达。
为了适合不同的工作环境,有防水及防尘设计的舵机;并且因应不同的负载需求,舵机的齿轮有塑胶及金属之区分,金属齿轮的舵机一般皆为大扭力及高速型,具有齿轮不会因负载过大而崩牙的优点。较高级的舵机会装置滚珠轴承,使得转动时能更轻快精准。


伺服电机与步进电机的性能比较

步进电机作为一种开环控制的系统,和现代数字控制技术有着本质的联系。在目前国内的数字控制系统中,步进电机的应用十分广泛。随着全数字式交流伺服系统的出现,交流伺服电机也越来越多地应用于数字控制系统中。为了适应数字控制的发展趋势,运动控制系统中大多采用步进电机或全数字式交流伺服电机作为执行电动机。虽然两者在控制方式上相似(脉冲串和方向信号),但在使用性能和应用场合上存在着较大的差异。

现就二者的使用性能进行如下比较:
  • 控制精度不同
    两相混合式步进电机步距角一般为 1.8°、0.9°,五相混合式步进电机步距角一般为0.72 °、0.36°。也有一些高性能的步进电机通过细分后步距角更小。如三洋公司(SANYO DENKI)生产的二相混合式步进电机其步距角可通过拨码开关设置为1.8°、0.9°、0.72°、0.36°、0.18°、0.09°、0.072°、0.036°,兼容了两相和五相混合式步进电机的步距角。
    交流伺服电机的控制精度由电机轴后端的旋转编码器保证。以三洋全数字式交流伺服电机为例,对于带标准2000线编码器的电机而言,由于驱动器内部采用了四倍频技术,其脉冲当量为360°/8000=0.045°。对于带17位编码器的电机而言,驱动器每接收131072个脉冲电机转一圈,即其脉冲当量为360°/131072=0.0027466°,是步距角为1.8°的步进电机的脉冲当量的1/655。
  • 低频特性不同
    步进电机在低速时易出现低频振动现象。振动频率与负载情况和驱动器性能有关,一般认为振动频率为电机空载起跳频率的一半。这种由步进电机的工作原理所决定的低频振动现象对于机器的正常运转非常不利。当步进电机工作在低速时,一般应采用阻尼技术来克服低频振动现象,比如在电机上加阻尼器,或驱动器上采用细分技术等。
    交流伺服电机运转非常平稳,即使在低速时也不会出现振动现象。交流伺服系统具有共振抑制功能,可涵盖机械的刚性不足,并且系统内部具有频率解析机能(FFT),可检测出机械的共振点,便于系统调整。
  • 矩频特性不同
    步进电机的输出力矩随转速升高而下降,且在较高转速时会急剧下降,所以其最高工作转速一般在300~600RPM。交流伺服电机为恒力矩输出,即在其额定转速(一般为2000RPM或3000RPM)以内,都能输出额定转矩,在额定转速以上为恒功率输出。
  • 过载能力不同
    步进电机一般不具有过载能力。交流伺服电机具有较强的过载能力。以三洋交流伺服系统为例,它具有速度过载和转矩过载能力。其最大转矩为额定转矩的二到三倍,可用于克服惯性负载在启动瞬间的惯性力矩。步进电机因为没有这种过载能力,在选型时为了克服这种惯性力矩,往往需要选取较大转矩的电机,而机器在正常工作期间又不需要那么大的转矩,便出现了力矩浪费的现象。
  • 运行性能不同
    步进电机的控制为开环控制,启动频率过高或负载过大易出现丢步或堵转的现象,停止时转速过高易出现过冲的现象,所以为保证其控制精度,应处理好升、降速问题。交流伺服驱动系统为闭环控制,驱动器可直接对电机编码器反馈信号进行采样,内部构成位置环和速度环,一般不会出现步进电机的丢步或过冲的现象,控制性能更为可靠。
  • 速度响应性能不同
    步进电机从静止加速到工作转速(一般为每分钟几百转)需要200~400毫秒。交流伺服系统的加速性能较好,以山洋400W交流伺服电机为例,从静止加速到其额定转速3000RPM仅需几毫秒,可用于要求快速启停的控制场合。
    综上所述,交流伺服系统在许多性能方面都优于步进电机。但在一些要求不高的场合也经常用步进电机来做执行电动机。所以,在控制系统的设计过程中要综合考虑控制要求、成本等多方面的因素,选用适当的控制电机。

伺服电机优点【其他电机(如步进电机)相比】:


1、精度:实现了位置,速度和力矩的闭环控制;克服了步进电机失步的问题;


2、转速:高速性能好,一般额定转速能达到2000~3000转;


3、适应性:抗过载能力强,能承受三倍于额定转矩的负载,对有瞬间负载波动和要求快速起动的场合特别适用;


4、稳定:低速运行平稳,低速运行时不会产生类似于步进电机的步进运行现象。适用于有高速响应要求的场合;


5、及时性:电机加减速的动态相应时间短,一般在几十毫秒之内;


6、舒适性:发热和噪音明显降低。


简单点说就是:平常看到的那种普通的电机,断电后它还会因为自身的惯性再转一会儿,然后停下。而伺服电机和步进电机是说停就停,说走就走,反应极快。但步进电机存在失步现象。


舵机控制

舵机有很多规格,但所有的舵机都有外接三根线,分别用棕、红、橙三种颜色进行区分:棕色为接地线,红色为电源正极线,橙色为信号线。由于舵机品牌不同,颜色也会有所差异


  • 舵机工作原理:

由接收机或者单片机发出信号给舵机,其内部有一个基准电路,产生周期为20ms,宽度为1.5ms 的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。经由电路板上的IC 判断转动方向,再驱动无核心马达开始转动,透过减速齿轮将动力传至摆臂,同时由位置检测器送回信号,判断是否已经到达定位。
适用于那些需要角度不断变化并可以保持的控制系统。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。一般舵机旋转的角度范围是0 度到180 度。
舵机的转动的角度是通过调节PWM(脉冲宽度调制)信号的占空比来实现的,标准PWM(脉冲宽度调制)信号的周期固定为20ms(50Hz)。
理论上脉宽分布应在1ms到2ms 之间,但是,事实上脉宽可由0.5ms 到2.5ms 之间,脉宽和舵机的转角0°~180°相对应。
由于舵机品牌不同,对于同一信号,不同舵机旋转的角度也会有所不同。
PWM角度调节


实例演示

    了解了上面这些烦人的基础知识,下面我们进行一个通过Arduino控制舵机的实例。

本实验所需要的元器件很少:Arduino Pro MINI*1、舵机*1、跳线若干。

用Arduino 控制舵机的方法有两种:
  • 第一种是通过Arduino具备PWM的数字I/O接口产生占空比不同的方波,模拟产生PWM 信号进行舵机定位.

  • 第二种是直接利用Arduino 自带的Servo 函数进行舵机控制,这种控制方法的优点在于程序编写简便,缺点是只能控制2 路舵机。因为Arduino 自带函数只能利用D9、D10 接口。
    Arduino 的驱动能力有限,所以当需要控制1 个以上的舵机时需要外接电源。

实物连接


方法1代码示例:


    /**
     通过串口,让舵机转动到用户输入数字所对应的角度数的位置。
     将角度打印显示到屏幕上。
     将舵机信号线接在D3接口
     */
    int servoPin = 3;    //定义D3连接伺服舵机信号线3,5,6,9,10,11均可
    int myAngle;      //定义角度变量
    int val;
    void setup(){
        pinMode(servoPin,OUTPUT);//设定舵机接口为输出接口
        Serial.begin(9600);//连接到串行端口,波特率为9600
        Serial.println("Please input Angle." );
    }
    void loop(){
        val=Serial.read();    //读取串行端口的值
        if(val>='0' && val<='9'){
        val = val - '0';    //将特征量转化为数值变量,
        myAngle = val*(180/9);//将数字转化为角度
        Serial.print("moving servo to ");
        Serial.print(val,DEC);
        Serial.println();
        analogWrite(servoPin,myAngle);
        }
    }

方法1实物连接示意


方法2代码示例:
Arduino
#include <Servo.h>
/**
attach()
设定舵机的接口,只有9或10接口可利用。
write()
用于设定舵机旋转角度的语句,可设定的角度范围是0°到180°。
writeMicroseconds() 
用于设定舵机旋转角度的语句,直接用微秒作为参数。
read()
用于读取舵机角度的语句,可理解为读取最后一条write()命令中的值。
attached()
判断舵机参数是否已发送到舵机所在接口。
detach()
使舵机与其接口分离,该接口(9或10)可继续被用作PWM接口。
*/
Servo myservo; // create servo object to control a servo
// a maximum of eight servo objects can be created
int pos = 0; // variable to store the servo position
void setup(){
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}
void loop(){
pos = 90;
myservo.write(pos); // 设定舵机转动的初始角度
delay(100);
for(pos; pos < 135; pos++){ // 设置转动角 1-180向右转,每一步转动1度
myservo.write(pos); //设定舵机转动的角度
delay(100);
}
delay(1000);
pos = 90;
myservo.write(pos);
delay(1000);
for(pos; pos>=45; pos--){
myservo.write(pos);
delay(100);
}
}

方法2实物连接示意

以上就是控制舵机的两种方法,各有优缺点大家根据自己的喜好和需要进行选择。不足之处还请大家批评指正。


    感谢一直关注着禾灮成长进步的朋友们。你们的信任、支持和鼓励,鞭策着我们一路走到了今天。

    感谢所有的合作伙伴,我们相互促进,共同见证了彼此的成长。

    感谢所有曾经在禾灮彼此倚靠、相互鼓励、携手同心、砥砺同行的兄弟姐妹。这里承载了我们的青春与热血。

                禾灮,感谢有你。

    未来,我们将一如既往,砥砺前行。

                                        禾灮·小楊
                                       2018.07.04

2019-02-21 22:12:28 LuDanTongXue 阅读数 2446
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4002 人正在学习 去看看 朱有鹏

单片机控制步进电机-线路连接

说明:如何利用单片机去控制步进电机?本案例讲解的内容是硬件连接部分,采用常用的电子器件去实现单片机控制步进电机的功能。后续会分别讲解单片机程序,S曲线生成方法,上位机等相关内容。

硬件清单:
1、单片机最小系统(本案例使用Atmega16芯片)
2、步进电机(二相四线)
3、稳压电源(24V)
4、步进电机驱动器(TB6600)
步进电机单片机最小系统
稳压电源驱动器
整体连接图:
整体图
原理图:
原理图

控制原理:
1、单片机最小系统作用:
①输出脉冲到步进电机驱动器,从而控制步进电机的速度大小
②控制步进电机的使能
③控制步进电机的转动方向
2、步进电机作用:
①提供机械动力
3、稳压电源作用:
①为步进电机提供电源
4、步进电机驱动器作用:
①将单片机脉冲信号转化为步进电机的驱动信号,简化控制过程

硬件连接图:
实物连接图与原理图如上图所示。Atmega16单片机最小系统(其他单片系统接线原理类同)与步进电机驱动器(TB6600)采用共阴极接法(驱动器的ENA-、DIR-、PUL-与单片机的GND连接)。
单片机PA0口控制ENA+,PA0高电位的时,步进电机掉电,步进电机自由状态,用手可以转动;PA0低电位的时,步进电机上电,根据输入的脉冲信号进行转动,无脉冲信号时处于自锁状态;
单片机PA1口控制DIR+,PA1高电位与低点位分别对应步进电机的正转与反转;
单片机PA2口控制PUL+,通过PA2口高低电位的切换形成脉冲,单片机输出一个脉冲(一个高电位加一个低电位即为一个脉冲),步进电机就会走一步。对于二相四线步进电机而言,在驱动器无细分的情况下,单片机一个脉冲对应步进电机一个步距角1.8°;驱动器如果是2细分状态,单片机一个脉冲对应步进电机转动角度为1.8°/2=0.9°;驱动器如果是4细分状态,单片机一个脉冲对应步进电机转动角度为1.8°/4=0.45°;其他细分依次类推。TB6600驱动器上的SW1、SW2、SW3三个拨码开关控制细分数(1细分、2细分、4细分、8细分、16细分、32细分),细分数越大,步进电机转动过程中越平稳。通过脉冲的快慢可以控制步进电机的速度,一般分为三个过程:开始加速、然后匀速、最后减速,后续会单独讲解控制程序部分。
步进电机的A、B相分别接在驱动器A、B相。在不知道步进电机那两根线是一相的时候,有个简单的判断方法:将步进电机的任意两更线接在一起,用手转动步进电机,如果有较大的阻力说明这两根线对应的是一相。
稳压电源输入端接交流220V,输出端正负极(本案例采用的是24V步进电机)分别接在驱动器VCC、GND即可。
至此硬件电路连接完成,下篇将讲解单片机程序。https://blog.csdn.net/LuDanTongXue/article/details/87869806
(微信ID:saskingku)

2019-06-06 18:05:40 weixin_38679924 阅读数 2412
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4002 人正在学习 去看看 朱有鹏

简介:
用单片机控制步进电机正转 反转 加速 减速;
由LCD1602实时显示步进电机的状态;F-正转 B-反转;数字越大,转速越大;
仿真原理图如下:
MCU和LCD1602显示模块:
在这里插入图片描述
ULN2803驱动和步进电机模块:
在这里插入图片描述
C语言代码如下:

/*-----------------------------
FileName: StepperMotor.h
Function: 函数头文件
Author: Zhang Kaizhou
Date: 2019-6-6 17:59:39
------------------------------*/
#include <reg52.h>
#include <string.h>
#define uchar unsigned char
#define uint unsigned int
#define Factor 5 // 转速控制常数	

/*LCD1602端口设置*/
sbit lcdrs = P1^0;
sbit lcdrw = P1^1;
sbit lcden = P1^2;

/*步进电机驱动器端口设置*/
sbit direcChange = P1^3; // 方向翻转
sbit speedUp = P1^4; // 加速
sbit slowDown = P1^5; // 减速

/*主函数声明*/
void keyScan();
void execute();

/*LCD1602显示相关函数声明*/
void LCDInit();
void displayInit();
void display(uchar oper, uchar dat);
void writeCommand(uchar command);
void writeData(uchar dat);
void delay(uchar xms);
/*-------------------------------------------
FileName:main.c
Function: MCU控制步进电机
Description:控制步进电机正转 反转 加速 减速;
由LCD1602实时显示步进电机的状态;
F-正转 B-反转;数字越大,转速越大;
---------------------------------------------
Author: Zhang Kaizhou
Date: 2019-6-6 17:56:41
-------------------------------------------*/
#include "StepperMotor.h"

uchar code pulseTable0[] = {0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x04, 0x08}; // 一相励磁(同一时刻只有一个线圈通电,旋转角1.8度)
uchar code pulseTable1[] = {0x0c, 0x06, 0x03, 0x09, 0x09, 0x03, 0x06, 0x0c}; // 二相励磁(同一时刻有两个线圈通电,旋转角1.8度)
uchar code pulseTable2[] = {0x08, 0x0c, 0x04, 0x06, 0x02, 0x03, 0x01, 0x09,
						    0x09, 0x01, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08}; // 一-二相励磁场(一二相交替励磁,旋转角0.9度)
uchar speed = 0, startPos = 0; // 默认正转
bit oper = 0/*操作数*/, direcFlag = 0; // 初始状态为正向

void main(){
	LCDInit(); // LCD1602显示初始化
	displayInit();
	while(1){
		keyScan(); // 按键扫描
		display(0, direcFlag);
		display(1, speed);
		execute();
	}
}

/*按键扫描*/
void keyScan(){
	if(!speedUp){ // 加速
		delay(5);
		if(!speedUp){
			if(speed < 4){
				while(!speedUp);
				speed++;
			}else{
				while(!speedUp);
				speed = 3;
			}
		}
	}
	if(!slowDown){ // 减速
		delay(5);
		if(!slowDown){
			if(speed != 0){
				speed--;
			}else{
				while(!slowDown);
				speed = 0;
			}
		}
	}
	if(!direcChange){ // 方向翻转
		delay(5);
		if(!direcChange){
			while(!direcChange);
			direcFlag = ~direcFlag;
		}
	}
}

/*步进电机控制执行函数*/
void execute(){
	uchar i, j;
	startPos = (direcFlag == 0) ? 0 : 4; // 方向控制
	for(i = startPos; i <= (startPos + 4); i++){
		P2 = pulseTable0[i];
		for(j = 0; j < (speed + 1) * Factor; j++){ // 用延时来控制脉冲输出的频率,从而控制步进电机转速
			delay(10);
		} 
	}
}
/*-----------------------------
FileName:display.c
Function: LCD1602显示函数
Author: Zhang Kaizhou
Date: 2019-6-6 17:58:42
------------------------------*/
#include "StepperMotor.h"

uchar code table0[] = {"Direction:"}; // 每行的字符数据
uchar code table1[] = {"Speed:"};
uchar code table2[] = {"1234"};
uchar code table3[] = {"FB"}; // F-正向 B-反向

/*初始化LCD1602的设置*/
void LCDInit(){
	lcden = 0; // 拉低使能端,准备产生使能高脉冲信号
	writeCommand(0x38); // 显示模式设置(16x2, 5x7点阵,8位数据接口)
	writeCommand(0x0c); // 开显示,不显示光标
	writeCommand(0x06); // 写一个字符后地址指针自动加1
	writeCommand(0x01); // 显示清零,数据指针清零
}

/*LCD上电界面*/
void displayInit(){
	uchar i;
	writeCommand(0x80); // 将数据指针定位到第一行首
	for(i = 0; i < strlen(table0); i++){
		writeData(table0[i]);
		delay(5);
	}
	
	writeCommand(0x80 + 0x40); // 将数据指针定位到第二行首
	for(i = 0; i < strlen(table1); i++){
		writeData(table1[i]);
		delay(5);
	}
}

/*LCD显示函数*/
void display(uchar oper, uchar dat){
	if(oper == 0){ // 方向显示
		if(dat == 0){ // 正向
			writeCommand(0x80 + strlen(table0)); // 数据指针定位到第一行空闲处
			writeData(table3[0]);
		}else if(dat == 1){ // 反向
			writeCommand(0x80 + strlen(table0)); // 数据指针定位到第一行空闲处
			writeData(table3[1]);
		}
	}
	if(oper == 1){ // 速度显示
		writeCommand(0x80 + 0x40 + strlen(table1)); // 数据指针定位到第二行空闲处
		writeData(table2[dat]);
	}
}

/*写指令函数*/
void writeCommand(uchar command){
	lcdrs = 0; // 命令选择
	lcdrw = 0;
	P0 = command;
	delay(5);
	
	lcden = 1; // 产生一个正脉冲使能信号
	delay(5);
	lcden = 0;
}

/*写数据函数*/
void writeData(uchar dat){
	lcdrs = 1; // 数据选择
	lcdrw = 0;
	P0 = dat;
	delay(5);
	
	lcden = 1;
	delay(5);
	lcden = 0;
}

/*延时函数*/
void delay(uchar xms){
	uint i, j;
	for(i = xms; i > 0; i--)
		for(j = 110; j > 0; j--);
}
2019-02-21 22:43:14 LuDanTongXue 阅读数 2003
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4002 人正在学习 去看看 朱有鹏

单片机控制步进电机-单片机程序(avr)

硬件线路连接图见上一篇文章:https://blog.csdn.net/LuDanTongXue/article/details/87869557

软件
ICCV7 FOR AVR-写程序
Progisp-烧程序
速度S曲线生成器(后续后单独讲解)-生成S曲线数组代码
硬件
Atmega16
ASP下载线
杜邦线

控制原理:
利用单片机定时器控制IO口高低电平产生脉冲,通过定时器控制每个脉冲的时间,以及脉冲的个数,从而控制步进电机速度以及转动角度,实现步进电机开环控制能力。步进电机常用的运动控制过程是:【静止】-【S曲线加速】-【匀速】-【S曲线减速】-【停止】,优点是速度平缓上升与下降,能够输出较大的扭矩,不容易失步、堵转。
以下会以【静止】-【正转180°】-【反转180°】-【停止】该运动控制过程进行演示,其中加减速过程均采用S曲线控制。
速度曲线具体控制过程是:
第一段S曲线加速30°:1转/秒启动,5转/秒结束
第二段匀速运动120°:5转/秒匀速
第三段S曲线减速30°:5转/秒启动,0.5转/秒结束
第四段S曲线反转加速30°:0.5转/秒启动,5转/秒结束
第五段匀速反转运动120°:5转/秒匀速
第六段S曲线反转减速30°:5转/秒启动,1转/秒结束

V-T图:
速度时间图
S-T图:
在这里插入图片描述

代码如下:(适用于Atmega16芯片,如用51芯片需要稍作改动)

//头文件
#include<iom16v.h>
#include<macros.h>//SEI()函数_NOP()BIT();
#define uint unsigned int
#define uchar unsigned char

//步进电机接口定义
#define ENA0 (PORTA &=~BIT(0))//电机由脉冲控制
#define ENA1 (PORTA |=BIT(0))//电机掉电、自由状态
#define DIR0 (PORTA &=~BIT(1))//电机正方向转动
#define DIR1 (PORTA |=BIT(1))//电机反方向转动
#define PUL0 (PORTA &=~BIT(2))//低电位
#define PUL1 (PORTA |=BIT(2))//高电位


unsigned int n0;//脉冲计数,用来控制电机转角
uchar duan;//步进电机曲线分段控制参数
uchar kaiguanflag;//该参数为0时,步进电机的启动开关才有效


//定义MEGA16接口输入输出
void port_init(void)
{
 PORTA = 0xFF; //BIT(4)为电机启动开关  BIT(5)电机释放开关
 DDRA  = 0x0F; 
 PORTB = 0xFF; 
 DDRB  = 0xFF; 
 PORTC = 0xFF; 
 DDRC  = 0xFF; 
 PORTD = 0xFF; 
 DDRD  = 0x02;
}


//ms延时函数
void delay_1ms(void) 
{  
unsigned int i;  
for(i=1;i<(unsigned int)(11.059*143-2);i++);//定义晶振频率
}  
void delay(unsigned int n)//延时微妙级 
{  
unsigned int i; 
for(i=0;i<n;i++) 
delay_1ms(); 
}


//主程序
//曲线数组的生成后续文章会单独分析
//第一段S曲线加速30°:1转/秒启动,5转/秒结束
A[67]={0XE5CF,0XE5EF,0XE614,0XE63E,0XE66E,0XE6A4,0XE6E2,0XE728,0XE777,0XE7D0,0XE832,0XE8A0,0XE919,0XE99E,0XEA2F,0XEACB,0XEB73,0XEC25,0XECE0,0XEDA3,0XEE6C,0XEF38,0XF006,0XF0D4,0XF19E,0XF264,0XF323,0XF3D9,0XF485,0XF526,0XF5BC,0XF646,0XF6C4,0XF737,0XF79E,0XF7FB,0XF84E,0XF898,0XF8D9,0XF913,0XF946,0XF972,0XF999,0XF9BB,0XF9D9,0XF9F3,0XFA09,0XFA1C,0XFA2D,0XFA3C,0XFA49,0XFA54,0XFA5D,0XFA65,0XFA6C,0XFA72,0XFA78,0XFA7C,0XFA80,0XFA83,0XFA86,0XFA89,0XFA8B,0XFA8D,0XFA8F,0XFA90,0XFA91};

//第三段S曲线减速30°:5转/秒启动,0.5转/秒结束
B[67]={0XFA8F,0XFA8D,0XFA8B,0XFA89,0XFA87,0XFA84,0XFA81,0XFA7D,0XFA79,0XFA73,0XFA6D,0XFA67,0XFA5F,0XFA55,0XFA4A,0XFA3E,0XFA2F,0XFA1F,0XFA0B,0XF9F5,0XF9DB,0XF9BD,0XF99A,0XF972,0XF944,0XF90F,0XF8D2,0XF88C,0XF83C,0XF7E0,0XF777,0XF700,0XF678,0XF5DE,0XF531,0XF46F,0XF396,0XF2A4,0XF199,0XF073,0XEF33,0XEDD9,0XEC65,0XEAD9,0XE939,0XE786,0XE5C4,0XE3FA,0XE22A,0XE05B,0XDE91,0XDCD2,0XDB21,0XD983,0XD7FB,0XD68B,0XD534,0XD3F8,0XD2D6,0XD1CF,0XD0E1,0XD00B,0XCF4C,0XCEA2,0XCE0B,0XCD86,0XCD10};

//第四段S曲线反转加速30°:0.5转/秒启动,5转/秒结束
C[67]={0XCD86,0XCE0B,0XCEA2,0XCF4C,0XD00B,0XD0E1,0XD1CF,0XD2D6,0XD3F8,0XD534,0XD68B,0XD7FB,0XD983,0XDB21,0XDCD2,0XDE91,0XE05B,0XE22A,0XE3FA,0XE5C4,0XE786,0XE939,0XEAD9,0XEC65,0XEDD9,0XEF33,0XF073,0XF199,0XF2A4,0XF396,0XF46F,0XF531,0XF5DE,0XF678,0XF700,0XF777,0XF7E0,0XF83C,0XF88C,0XF8D2,0XF90F,0XF944,0XF972,0XF99A,0XF9BD,0XF9DB,0XF9F5,0XFA0B,0XFA1F,0XFA2F,0XFA3E,0XFA4A,0XFA55,0XFA5F,0XFA67,0XFA6D,0XFA73,0XFA79,0XFA7D,0XFA81,0XFA84,0XFA87,0XFA89,0XFA8B,0XFA8D,0XFA8F,0XFA90};

//第六段S曲线反转减速30°:5转/秒启动,1转/秒结束
D[67]={0XFA90,0XFA8F,0XFA8D,0XFA8B,0XFA89,0XFA86,0XFA83,0XFA80,0XFA7C,0XFA78,0XFA72,0XFA6C,0XFA65,0XFA5D,0XFA54,0XFA49,0XFA3C,0XFA2D,0XFA1C,0XFA09,0XF9F3,0XF9D9,0XF9BB,0XF999,0XF972,0XF946,0XF913,0XF8D9,0XF898,0XF84E,0XF7FB,0XF79E,0XF737,0XF6C4,0XF646,0XF5BC,0XF526,0XF485,0XF3D9,0XF323,0XF264,0XF19E,0XF0D4,0XF006,0XEF38,0XEE6C,0XEDA3,0XECE0,0XEC25,0XEB73,0XEACB,0XEA2F,0XE99E,0XE919,0XE8A0,0XE832,0XE7D0,0XE777,0XE728,0XE6E2,0XE6A4,0XE66E,0XE63E,0XE614,0XE5EF,0XE5CF,0XE5B3};


void main(void)
{
TCCR1B=0X01;//不分频(定时小于5.9毫秒) 
TCNT1=0XE5F0;//存放初值,根据A[0]值确定
TIMSK|=0x00;//定时器中断关
SREG=0X80;//总中断开
port_init();//IO口初始化
DIR0;//定一个初始转向
ENA1;//上电后步进电机为自由状态
while(1)
{
//本程序将PA4口设置为一个开关,当PA4口与单片机GND连通时,电机开始启动,硬件图里面没有画出该部分
 if((PINA&0x10)==0 & kaiguanflag==0)//启动键
 {
  delay(10);//软件滤波
  if((PINA&0x10)==0 & kaiguanflag==0)
  {
  kaiguanflag=1;//防止在电机转动过程中再进入该部分程序
  n0=0;
  DIR1;//规定转向
  ENA0;//电机处于可操作状态
  TIMSK|=BIT(2);//开16位定时器1中中断,电机启动
  }
 }

//本程序将PA5口设置为一个开关,当PA5口与单片机GND连通时,电机处于掉电自由状态,防止在不用过程中电机一直带电发热,同时可以用手去转动电机,硬件图里面没有画出该部分
 if((PINA&0x20)==0)//切换步进电机可控状态
 {
  delay(10);
  if((PINA&0x20)==0)
  ENA1; 
 }
}
}

#pragma interrupt_handler time1:9//ATMEGA16定时器time1中断
void time1(void)
{
 switch(duan)//控制曲线处于哪个加速段
 {
//已第一段为例解释,后面几段原理一样
case 0: //第一段S曲线加速30°:1转/秒启动,5转/秒结束

  TCNT1=A[n0];//设置定时器初值
  PORTA ^=BIT(2);//PA2口取反,产生高低电平形成脉冲
  if((PINA & BIT(2))==0)//两次中断产生一个脉冲,取其中一次进行脉冲计数
   {
    n0++;
   	  if(n0==67)//判断是否到达指定脉冲数
	  {
		duan++;//到达脉冲个数之后,进入下一段速度
		n0=0;//清零
	  }
   	}break;
   	
case 1: //第二段匀速运动120°:5转/秒匀速
  TCNT1=0XFA99;//匀速5r/s;
  PORTA ^=BIT(2);
  if((PINA & BIT(2))==0)
   {
    n0++;
	if(n0==267)
	{
	 duan++;
	 n0=0;
	}
   }break;
   
case 2: //第三段S曲线减速30°:5转/秒启动,0.5转/秒结束
  TCNT1=B[n0];
  PORTA ^=BIT(2);
  if((PINA & BIT(2))==0)
   {
    n0++;
   	  if(n0==67)
	  {
	    duan++;
	    n0=0;
            DIR0;//开始换向
	  }
   	}break;
   	
case 3: //第四段S曲线反转加速30°:0.5转/秒启动,5转/秒结束
  TCNT1=C[n0];
  PORTA ^=BIT(2);
  if((PINA & BIT(2))==0)
   {
    n0++;
   	  if(n0==67)
	  {
	    duan++;
	    n0=0;
	  }
   	}break;
   	
case 4: //第五段匀速反转运动120°:5转/秒匀速
  TCNT1=0XFA99;//转速5r/s;
  PORTA ^=BIT(2);
  if((PINA & BIT(2))==0)
   {
    n0++;
   	  if(n0==267)
	  {
	    duan++;
	    n0=0;
	  }
   	}break;
case 5: //第六段S曲线反转减速30°:5转/秒启动,1转/秒结束
  TCNT1=D[n0];
  PORTA ^=BIT(2);
  if((PINA & BIT(2))==0)
   {
    n0++;
   	  if(n0==67)
	     {
		      duan=0;
		      kaiguanflag=0;//PA4开关标志清零,等待下一次PA4开关启动
		      TIMSK=0x00;//关闭中断,电机停止
	      }
   	}break;
 default:duan=0;kaiguanflag=0;TIMSK=0x00;break;
  } 
}

演示动画:
将单片机PA4口与GND口连通(时间有限没有接开关),步进电机按照上述设计的曲线进行运动,实现正转180°后反转180°回到原点。
(视频不好传,GIF质量不怎么好,将就看看)。(微信ID:saskingku)
在这里插入图片描述

2018-05-30 14:26:14 qq_34071268 阅读数 293
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4002 人正在学习 去看看 朱有鹏

实现功能:time4cap完成遥控RC信号采集,采集4路信号
对信号进行处理,利用函数关系进行速度匹配
速度控制实现电机控制,速度控制采用-10到10V的模拟量输出
单片机控制速度模式采用CRC MODBUS协议
出现问题:
在主函数中能够解析出来RC电压,但在主函数中无法发送出去,即电压无显示
解决方案:(1)解析放到主函数
(2)MODBUS协议放到定时器中断中
问题得以解决,具体原因分析不出来,类似于进程冲突

没有更多推荐了,返回首页