28BYJ-48 电机驱动(Linux)

17、28BYJ-48 电机驱动

什么,学完了pinctrl子系统和GPIO子系统还只会点灯?
今天就来个高级点的点灯

这个电机驱动程序说白了就是 点灯

1、28BYJ-48 电机是四相八拍电机,所以需要4个GPIO来控制

简介:

28:步进电机的有效最大外径是28毫米

B:表示是步进电机

Y:表示是永磁式

J:表示是减速型(减速比1:64)

48:表示四相八拍

内部结构示意图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qYxCbNM4-1619338578619)(linux%E9%A9%B1%E5%8A%A8.assets/image-20210331103907659.png)]

1、相数:是指产生不同对极N、S磁场的激磁线圈对数。常用m表示 例如上图 有四对线圈 A、B、C、D

2、拍数:完成一个磁场周期性变化所需脉冲数,以四相电机为例,

​ 有单相四拍运行方式即A-B-C-D,

​ 有双相四拍运行方式即AB-BC-CD-DA

​ 有四相八拍运行方式即A-AB-B-BC-C-CD-D-DA

3、步进角:

​ 步进电机的定子绕组每改变一次通电状态,转子转过的角度称步进角。

转子磁极数越多,步进角 越小

定子相数越多,步进角越小

通电方式节拍越多,步进角越小

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OiPsXu02-1619338578620)(linux%E9%A9%B1%E5%8A%A8.assets/image-20210331105744982.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zbm5R4w6-1619338578621)(linux%E9%A9%B1%E5%8A%A8.assets/image-20210331132503666.png)]

![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-StbP69af-1619338578624)(linux%E9%A9%B1%E5%8A%A8.assets/image-20210331105932827.png)]]

例如 八拍模式下 360/(4 * 8 * 2) = 5.625

​ 关于启动频率,也就是pps 这里间隔时间最好是大于1200us

在这里插入图片描述

与开发板的管脚连接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OCWIQIdg-1619338578626)(file://C:\Users\74550\Desktop\宠物喂食器\宠物喂食器开发文档\串口通信以及电机控制.assets\image-20210322171611542.png?lastModify=1618904441)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jg90mlXA-1619338578628)(linux%E9%A9%B1%E5%8A%A8.assets/image-20210420154149818.png)]

第一步 在pinctrl子系统中,对这几个管脚进行配置

exynos4412-pinctrl.dtsi 文件中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5tk1Be60-1619338578629)(linux%E9%A9%B1%E5%8A%A8.assets/image-20210420154940506.png)]

		mymoter: mymoter {
			samsung,pins = "gpj0-3", "gpj0-4", "gpj0-5", "gpj0-6";
			samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>; //设置为输出模式
			samsung,pin-val = <0x0>;  //默认输出低电平
		//	samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
		};
		

2、第二步 在根节点下添加MOTOR节点

exynos4412-itop-elite.dts 文件中 在根节点中添加节点

	/*motor*/
	my_motor:my_motor{
		compatible = "motor";			//描述
		pinctrl-names = "default";		
		pinctrl-0 = <&mymotor>;		
		status = "okay"
		/*GPIO管脚  "gpj0-3", "gpj0-4", "gpj0-5", "gpj0-6";*/
		motorA-gpios = <&gpj0 3 GPIO_ACTIVE_HIGH>;	//GPJ0_3 GPIO_ACTIVE_HIGH 表示高电平有效
		motorB-gpios = <&gpj0 4 GPIO_ACTIVE_HIGH>;
		motorC-gpios = <&gpj0 5 GPIO_ACTIVE_HIGH>;
		motorD-gpios = <&gpj0 6 GPIO_ACTIVE_HIGH>;
	}

3、 编写driver程序

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>

#include <linux/pinctrl/consumer.h> 
#include <dt-bindings/pinctrl/samsung.h>

#include <linux/of_gpio.h>


/*  字符设备框架
    1、注册 platform driver
    2、构建file_operations
    3、获取硬件资源
    4、注册字符设备驱动
    4、生成字符设备节点
*/  
/*  
    定义各个管脚的命令
*/
#define MOTOR_CMD_A _IOW('M',0,long)
#define MOTOR_CMD_B _IOW('M',1,long)
#define MOTOR_CMD_C _IOW('M',2,long)
#define MOTOR_CMD_D _IOW('M',3,long)


struct device *device_cdev; 
struct class *class_cdev;

int GPIO_ID_A;
int GPIO_ID_B;
int GPIO_ID_C;
int GPIO_ID_D;

int motor_open(struct inode *inode, struct file *file)
{
    printk("open is success!\n");
    return 0;
}
int motor_release (struct inode *inode, struct file *file)
{
    printk("release is success!\n");
    return 0;
}
long motor_ioctrl(struct file *file, unsigned int cmd, unsigned long value)
{
    switch(cmd)
    {
        case MOTOR_CMD_A:
            gpio_set_value(GPIO_ID_A, value);
            break;
        case MOTOR_CMD_B:
            gpio_set_value(GPIO_ID_B, value);
            break;     
        case MOTOR_CMD_C:
            gpio_set_value(GPIO_ID_C, value);
            break;
        case MOTOR_CMD_D:
            gpio_set_value(GPIO_ID_D, value);
            break;
    }
}


/*2、获取硬件资源 */
int motor_probe(struct platform_device *pdev)
{
    int ret;
    /*1、获取GPIO号*/
    GPIO_ID_A = of_get_named_gpio(pdev->dev.of_node, "motorA-gpios", 0);//index=0 ,因为在设备树中只引用了一个
    if (GPIO_ID_A < 0)
    {
        printk("of get named gpio is error!\n");
        return -1;
    }
    GPIO_ID_B = of_get_named_gpio(pdev->dev.of_node, "motorB-gpios", 0);//index=0 ,因为在设备树中只引用了一个
    if (GPIO_ID_B < 0)
    {
        printk("of get named gpio is error!\n");
        return -1;
    }
    GPIO_ID_C = of_get_named_gpio(pdev->dev.of_node, "motorC-gpios", 0);//index=0 ,因为在设备树中只引用了一个
    if (GPIO_ID_C< 0)
    {
        printk("of get named gpio is error!\n");
        return -1;
    }
    GPIO_ID_D = of_get_named_gpio(pdev->dev.of_node, "motorD-gpios", 0);//index=0 ,因为在设备树中只引用了一个
    if (GPIO_ID_D< 0)
    {
        printk("of get named gpio is error!\n");
        return -1;
    }
    
    /*2、申请一个GPIO管脚*/
    ret = gpio_request(GPIO_ID_A, "motor_A_GPIO");
    if (ret != 0)
    {
        printk("gpio request is error!\n");
        return -1;
    }
    ret = gpio_request(GPIO_ID_B, "motor_B_GPIO");
    if (ret != 0)
    {
        printk("gpio request is error!\n");
        return -1;
    }
    ret = gpio_request(GPIO_ID_C, "motor_C_GPIO");
    if (ret != 0)
    {
        printk("gpio request is error!\n");
        return -1;
    }
        ret = gpio_request(GPIO_ID_D, "motor_D_GPIO");
    if (ret != 0)
    {
        printk("gpio request is error!\n");
        return -1;
    }
    /*3、 将管脚设置为输出*/
    /* 这里先不设置,因为在pinctrl复用中已经将管脚设置为了OUTPUT*/

    return 0;    
}
int motor_remove(struct platform_device *pdev)
{
    return 0;
}

struct of_device_id of_match_table = {      // 与设备树节点进行匹配
    .compatible = "motor"
};

/*1、初始化platform driver*/
struct platform_driver pdev = {
    .probe = motor_probe,          // 与 of_match_table 匹配成功后进入probe函数获取硬件资源
    .remove = motor_remove,
    .driver = {
        .name = "motor",     //无设备树时 使用.name 与device进行匹配
        .owner = THIS_MODULE,
        .of_match_table = &of_match_table,
    }
};
//3、注册字符设备驱动
/*3.1 分配设备号*/
dev_t dev_number;
/*3.2 定义cdev*/
struct cdev cdev_;

/*3.3 构建file_operation结构体*/
struct file_operations fop = {
    .owner = THIS_MODULE,
    .open    = motor_open,
    .release = motor_release,
    .unlocked_ioctl = motor_ioctrl
};
static int char_driver_init(void)
{
    /*1、注册platform driver*/
    int ret = platform_driver_register(&pdev);
    if (0 != ret)
    {   
        printk("platform driver register is error!\n");
        return -1;
    }
    /*3.1 分配设备号(动态分配设备号)*/
    ret = alloc_chrdev_region(&dev_number, 0, 1, "my_motor");
    if (0 != ret)
    {
        printk("alloc chrdev region is error!\n");
        return ret;
    }
    /*3.4 初始化cdev*/
    cdev_.owner = THIS_MODULE;
    cdev_init(&cdev_, &fop);
    /*3.5 注册字符设备到内核*/
    ret = cdev_add(&cdev_, dev_number, 1);
    if (0 != ret)
    {
        printk("cdev add is error!\n");
        return -1;
    }
    /*4、生成设备节点*/
    /*4.1 创建字符设备类*/
   class_cdev =  class_create(THIS_MODULE, "motor");
    if (NULL == class_cdev)
    {
        printk("class create is error!\n");
        return -1;
    }
    /*生成设备节点*/
    device_cdev = device_create (class_cdev, NULL, dev_number, NULL,  "my_motor");
    if (NULL == device_cdev)
    {
        printk("device create is error!\n");
    }
    return 0;
};

static void char_driver_exit(void)
{
    gpio_free(GPIO_ID_A);  
    gpio_free(GPIO_ID_B);    
    gpio_free(GPIO_ID_C);    
    gpio_free(GPIO_ID_D);    //释放GPIO
    device_destroy(class_cdev, dev_number); // 卸载设备节点
    class_destroy(class_cdev);              //卸载设备类
    cdev_del(&cdev_);                       //卸载cdev
 //   iounmap(led_con);                       // 取消地址映射
 //   iounmap(led_dat);                   
    unregister_chrdev_region(dev_number, 1);// 注销设备号 
    platform_driver_unregister(&pdev);       // 注销platform driver
   
}

module_init(char_driver_init);
module_exit(char_driver_exit);
MODULE_LICENSE("GPL");


4、应用程序

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>

#include <sys/ioctl.h>
#define MOTOR_DEV "/dev/my_motor"

/* 一个节拍 转动 5.625*/

#define MOTOR_CMD_A _IOW('M',0,long)
#define MOTOR_CMD_B _IOW('M',1,long)
#define MOTOR_CMD_C _IOW('M',2,long)
#define MOTOR_CMD_D _IOW('M',3,long)

#define HIGH 1
#define LOW 0

#define NUMBER 10000
#define SPEED 1500
//SPEED 越小转速越快  
int fd;
int motor_off(void)
{

    ioctl(fd, MOTOR_CMD_A, LOW);
    ioctl(fd, MOTOR_CMD_B, LOW);
    ioctl(fd, MOTOR_CMD_C, LOW);
    ioctl(fd, MOTOR_CMD_D, LOW);

}
static int meter_turn(int n)    
{
    switch(n)
    {
        case 0:

            ioctl(fd, MOTOR_CMD_A, LOW);
            ioctl(fd, MOTOR_CMD_B, HIGH);
            ioctl(fd, MOTOR_CMD_C, HIGH);
            ioctl(fd, MOTOR_CMD_D, HIGH);

            break;
        case 1:
            ioctl(fd, MOTOR_CMD_A, LOW);
            ioctl(fd, MOTOR_CMD_B, LOW);
            ioctl(fd, MOTOR_CMD_C, HIGH);
            ioctl(fd, MOTOR_CMD_D, HIGH);
            break;

        case 2:
            ioctl(fd, MOTOR_CMD_A, HIGH);
            ioctl(fd, MOTOR_CMD_B, LOW);
            ioctl(fd, MOTOR_CMD_C, HIGH);
            ioctl(fd, MOTOR_CMD_D, HIGH);
            break;

        case 3:
            ioctl(fd, MOTOR_CMD_A, HIGH);
            ioctl(fd, MOTOR_CMD_B, LOW);
            ioctl(fd, MOTOR_CMD_C, LOW);
            ioctl(fd, MOTOR_CMD_D, HIGH);
            break;

        case 4:
            ioctl(fd, MOTOR_CMD_A, HIGH);
            ioctl(fd, MOTOR_CMD_B, HIGH);
            ioctl(fd, MOTOR_CMD_C, LOW);
            ioctl(fd, MOTOR_CMD_D, HIGH);
            break;

        case 5:
            ioctl(fd, MOTOR_CMD_A, HIGH);
            ioctl(fd, MOTOR_CMD_B, HIGH);
            ioctl(fd, MOTOR_CMD_C, LOW);
            ioctl(fd, MOTOR_CMD_D, LOW);
            break;

        case 6:
            ioctl(fd, MOTOR_CMD_A, HIGH);
            ioctl(fd, MOTOR_CMD_B, HIGH);
            ioctl(fd, MOTOR_CMD_C, HIGH);
            ioctl(fd, MOTOR_CMD_D, LOW);
            break;

        case 7:
            ioctl(fd, MOTOR_CMD_A, LOW);
            ioctl(fd, MOTOR_CMD_B, HIGH);
            ioctl(fd, MOTOR_CMD_C, HIGH);
            ioctl(fd, MOTOR_CMD_D, LOW);
            break;

    }

    return 0;
}

void motor_direction(const char direction, int number)
{
    int i ;

    int step ;
    if (direction == 'R')
        step = -1;
    else
        step = 8;
    
    for (i = 0; i < number; i++)
    {
        if (direction == 'R')
        {
            step++;
            if (step > 7)
                step = 0;
        }
        else 
        {
            if (step == 0)
                step = 8;
            step--;
        }
        
        meter_turn(step);
        usleep(SPEED);

    }
   

}
int main(int argc, char * argv[])
{
    fd = open(MOTOR_DEV, O_RDWR);
    if (-1 == fd)
    {
        perror("open");
        return -1;
    }
    printf("open success!\n");
    motor_direction('L', NUMBER);
    motor_off();
    return 0;
}

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MicroPython可以通过GPIO口驱动28BYJ-48步进电机。步进电机是一种能够将电脉冲转化为旋转角度的电机,适用于需要精确控制旋转角度的应用。 首先,我们需要将MicroPython的开发环境搭建好,包括将MicroPython固件烧录到ESP8266开发板中。然后,我们需要将28BYJ-48步进电机的引脚与ESP8266的GPIO口连接起来。 28BYJ-48步进电机有5个引脚,分别是VCC、GND、IN1、IN2、IN3、IN4,其中VCC和GND分别接到ESP8266的电源正负极,IN1、IN2、IN3、IN4分别接到ESP8266的GPIO口。具体的连接方式可以参考步进电机和ESP8266的引脚定义。 一旦连接好硬件,我们可以在MicroPython中使用GPIO模块来控制步进电机。首先,我们需要导入GPIO模块: from machine import Pin 然后,我们可以定义步进电机的引脚: IN1 = Pin(4, Pin.OUT) IN2 = Pin(5, Pin.OUT) IN3 = Pin(6, Pin.OUT) IN4 = Pin(7, Pin.OUT) 接下来,我们可以定义一个函数来控制步进电机的旋转。以下是一个简单的函数: def rotate(): for i in range(512): IN1.value(1) IN2.value(0) IN3.value(1) IN4.value(0) sleep_us(1000) IN1.value(0) IN2.value(1) IN3.value(1) IN4.value(0) sleep_us(1000) IN1.value(0) IN2.value(1) IN3.value(0) IN4.value(1) sleep_us(1000) IN1.value(1) IN2.value(0) IN3.value(0) IN4.value(1) sleep_us(1000) 在这个函数中,我们通过改变IN1、IN2、IN3和IN4的值来控制步进电机的旋转方向和速度。而 sleep_us(1000)则是为了控制每个脉冲的时间间隔。 最后,我们只需要调用rotate()函数,就可以控制步进电机开始旋转了。 这只是一个简单的示例,实际上,我们可以根据实际应用的需要,进行更复杂的步进电机控制。希望这个回答对你有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值