首页>问题汇总>舵机步进电机和矩阵键盘的综合例程 - 韦照伟
韦照伟 - 舵机步进电机和矩阵键盘的综合例程

舵机
1.舵机简介
在机器人机电控制系统中,舵机控制效果是性能的重要影响因素。舵机可以在微机电系统和航模中作为基本的输出执行机构,其简单的控制和输出使得单片机系统非常容易与之接口。
   舵机是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。目前在高档遥控玩具,如航模,包括飞机模型,潜艇模型;遥控机器人中已经使用得比较普遍。舵机是一种俗称,其实是一种伺服马达。

2.     其工作原理是:
控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。当然我们可以不用去了解它的具体工作原理,知道它的控制原理就够了。就象我们使用晶体管一样,知道可以拿它来做开关管或放大管就行了,至于管内的电子具体怎么流动是可以完全不用去考虑的。
3.     舵机的控制:
舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。以180度角度伺服为例,那么对应的控制关系是这样的:
   0.5ms--------------0度;
   1.0ms------------45度;
   1.5ms------------90度;
   2.0ms-----------135度;
   2.5ms-----------180度;

 

28BYJ48旋转
按照设定方向转动一个固定的角度,28BYJ48型4相8拍电机,当对电机施加一系列连续不断的控制脉冲时,它可以连续不断的转动,当通电状态的改变完成一个循环时,转子转过一个齿距。4相步进电机可以在不同的脉冲序列下运行,常见的脉冲序列有单相四拍(单相绕组通电):A-B-C-D-A..,双相四拍(双向绕组通电):AB-BC-CD-DA-AB...,八拍:A-AB-B-BC-C-CD-D-DA-A...。

  1. 技术参数:

                             表2


参数

参数

电压VDC

12

空载牵入频率
Hz

≥500

直流电阻25°C Ω±7%

85

空载牵出频率
Hz

≥800

步距角

5.625°/64

绝缘耐压
V 1S

600

减速比

1/64

温升 K

≤55

牵入转矩(100Hz时)
gf.cm

550

噪音 dB

≤40

自定位转矩
gf.cm

300

驱动方式

四相八拍

连接线长:230mm,采用UL 26AWG  1061的电源线



二:接线示意图                    

 

 

矩阵按键扫描原理

方法一:
逐行扫描:我们可以通过高四位轮流输出低电平来对矩阵键盘进行逐行扫描,当低四位接收到的数据不全为1的时候,说明有按键按下,然后通过接收到的数据是哪一位为0来判断是哪一个按键被按下。
方法二:
行列扫描:我们可以通过高四位全部输出低电平,低四位输出高电平。当接收到的数据,低四位不全为高电平时,说明有按键按下,然后通过接收的数据值,判断是哪一列有按键按下,然后再反过来,高四位输出高电平,低四位输出低电平,然后根据接收到的高四位的值判断是那一行有按键按下,这样就能够确定是哪一个按键按下了。

接线方法及试验现象
本次试验采用的是stm32f103vct6Z作为控制器,键盘采用行列扫描,步进电机采用四相八拍的控制方法。

  1. 将28BYJ-48步进电机的导线插到开发板步进电机1接口处。将舵机的导线插到开发板舵机3接口处。如下图所示:

  1. 将开发板用数据线与电脑连接,然后打开USB下载器,将相应的HEX文件下载到开发板上。

舵机的试验现象为:
按下KEY1:
输出0.5ms的脉冲到舵机,舵机转动0°
按下KEY2:
输出1ms的脉冲到舵机,舵机转动45°
按下KEY3:
输出1.5ms的脉冲到舵机,舵机转动90°
按下KEY4:
输出2ms的脉冲到舵机,舵机转动135°
按下KEY5:
输出2.5ms的脉冲到舵机,舵机转动180°

步进电机的试验现象为:
按下KEY6:步进电机加速旋转
按下KEY7:步进电机减速旋转
按下KEY8:步进电机反向旋转

试验代码:
试验代码分为三部分。第一位主函数main.c,第二部分为key.c和key.h,第三部分为motor.c和motor.h。

1.
main.c
#include "stm32f10x.h"
#include "key.h"
#include "motor.h"

u8 key_num = 0;
u8 dir = 0;
u8 sp=8;
int main(void)
{  
ChipHalInit();          //片内硬件初始化
ChipOutHalInit();       //片外硬件初始化
while (1)    
{
key_num=key();
if(key_num=='1'){
SetSG90(1,1);
}
else if(key_num=='2'){
SetSG90 (1,45);
}
else if(key_num=='3'){
SetSG90(1,90);
}
else if(key_num=='4'){
SetSG90(1,135);
}
else if(key_num=='5'){
SetSG90(1,179);
}
else if(key_num=='6'){
sp++;
SteppingRun4(sp,dir,1);
}
else if(key_num=='7'){
sp--;
SteppingRun4(sp,dir,1);
}
else if(key_num=='8'){
dir=~dir;
SteppingRun4(sp,dir,1);
}

}
}

 

2.key.h

#ifndef _KEY_H_
#define _KEY_H_

#define COLKEY1_H() GPIOC->BSRR=0x00000200
#define COLKEY1_L() GPIOC->BRR=0x00000200
#define COLKEY2_H() GPIOC->BSRR=0x00000400
#define COLKEY2_L() GPIOC->BRR=0x00000400
#define COLKEY3_H() GPIOC->BSRR=0x00000800
#define COLKEY3_L() GPIOC->BRR=0x00000800
#define COLKEY4_H() GPIOC->BSRR=0x00001000
#define COLKEY4_L() GPIOC->BRR=0x00001000

#define ROWKEY1() (GPIOB->IDR & 0x00000400)
#define ROWKEY2() (GPIOB->IDR & 0x00000020)
#define ROWKEY3() (GPIOE->IDR & 0x00000001)
#define ROWKEY4() (GPIOE->IDR & 0x00000002)
u8 key(void);
u8 read_key(void);
#endif

 

Key.c

#include "stm32f10x.h"
#include "key.h"
u8 realkeynum[16][2] =
{
{17,'1'},{33,'2'},{49,'3'},{65,'A'},
{18,'4'},{34,'5'},{50,'6'},{66,'B'},
{19,'7'},{35,'8'},{51,'9'},{67,'C'},
{20,'*'},{36,'0'},{52,'#'},{68,'D'},

};
u8 read_key(void)
{
if(ROWKEY1() == 0)
return 1;
else if(ROWKEY2() == 0)
return 2;
if(ROWKEY3() == 0)
return 3;
if(ROWKEY4() == 0)
return 4;
return 0;
}

u8 key(void)
{
u8 key_return = 0,i;
COLKEY1_L();
COLKEY2_H();
COLKEY3_H();
COLKEY4_H();
if(read_key() > 0)
{
key_return = 0x10 + read_key();
}
COLKEY1_H();
COLKEY2_L();
COLKEY3_H();
COLKEY4_H();
if(read_key() > 0)
{
key_return = 0x20 + read_key();
}
COLKEY1_H();
COLKEY2_L();
COLKEY3_H();
COLKEY4_H();
if(read_key() > 0)
{
key_return = 0x20 + read_key();
}
COLKEY1_H();
COLKEY2_H();
COLKEY3_L();
COLKEY4_H();
if(read_key() > 0)
{
key_return = 0x30 + read_key();
}
COLKEY1_H();
COLKEY2_H();
COLKEY3_H();
COLKEY4_L();
if(read_key() > 0)
{
key_return = 0x40 + read_key();
}
for(i = 0;i < 16;i ++)
{
if(realkeynum[i][0] == key_return)
{
key_return = realkeynum[i][1];
break;
}
}
return key_return;
}

 

Motor.h

#ifndef __MOTOR_H                 
#define __MOTOR_H

#define  MOTOR1A_L()  GPIOB->BRR  = 0x00000002  //PB1
#define  MOTOR1A_H()  GPIOB->BSRR = 0x00000002
#define  MOTOR1B_L()  GPIOE->BRR  = 0x00000080  //PE7
#define  MOTOR1B_H()  GPIOE->BSRR = 0x00000080
#define  MOTOR1C_L()  GPIOE->BRR  = 0x00000100  //PE8
#define  MOTOR1C_H()  GPIOE->BSRR = 0x00000100
#define  MOTOR1D_L()  GPIOE->BRR  = 0x00000200  //PE9
#define  MOTOR1D_H()  GPIOE->BSRR = 0x00000200

void SteppingRun4(u8 sp,u8 dir,u8 en);
void SetSG90(u8 ch,u8 angle);
#endif

 

Motor.c

#include "stm32f10x.h"
#include "Motor.h"
#include "delay.h"
#include "pwm.h"

//步进电机4驱动 sp-速度,dir-方向 ,en - 使能
//定时执行,执行一次走一步(测试代码为500us执行一次)
void SteppingRun4(u8 sp,u8 dir,u8 en)
{
u16 i = 0;
static u8 flag = 1,sp_delay = 12;
if(en)
{
if(sp > 0 && sp <= 10)
{      

if(sp_delay <= sp)
{  
sp_delay = 12;
if(flag == 1)
{
MOTOR1A_H();
MOTOR1B_L();
MOTOR1C_L();
MOTOR1D_L();
}
else if(flag == 2)
{
MOTOR1A_H();
MOTOR1B_H();
MOTOR1C_L();
MOTOR1D_L();
}
else if(flag == 3)
{
MOTOR1A_L();
MOTOR1B_H();
MOTOR1C_L();
MOTOR1D_L();
}
else if(flag == 4)
{
MOTOR1A_L();
MOTOR1B_H();
MOTOR1C_H();
MOTOR1D_L();
}
else if(flag == 5)
{
MOTOR1A_L();
MOTOR1B_L();
MOTOR1C_H();
MOTOR1D_L();
}         
else if(flag == 6)
{
MOTOR1A_L();
MOTOR1B_L();
MOTOR1C_H();
MOTOR1D_H();
}
else if(flag == 7)
{
MOTOR1A_L();
MOTOR1B_L();
MOTOR1C_L();
MOTOR1D_H();
}
else if(flag == 8)
{
MOTOR1A_H();
MOTOR1B_L();
MOTOR1C_L();
MOTOR1D_H();
}
if(dir == 1)
{
flag ++;
if(flag > 8)
{
flag = 1;
}
}
else
{
flag --;
if(flag < 1)
{
flag = 8;
}
}                       
}
sp_delay--; 
}
}
}

//舵机角度设置 ch-通道数(0-4) angle-角度(0-180)
void SetSG90(u8 ch,u8 angle)
{
if(angle > 180)
{
angle = 180;
}
SetTim4Pwm(ch,angle);
}




Copyright © 2019 作者:张泽zzhang1@gzu.edu.cn. 大学教师. 网站备案号:黔ICP备18012493号