目录
一、工作原理
步进电机由定子和转子两部分组成。定子上有多组线圈,通常称为相,每组相通常由两个电流互相反向的线圈组成。转子上有多个磁极,通常称为步进角。
当电流通过其中一组线圈时,该线圈就会产生一个磁场。由于线圈中电流方向的变化,磁场也会随之改变方向。转子的磁极会受到相邻线圈磁场的作用而进行转动。当电流改变到下一组线圈时,转子又会根据新的磁场方向进行转动。通过不断改变电流的方向和大小,可以控制步进电机的转动角度。
二、接口图
三、真值表
下图为驱动芯片MX1508输入输出真值表:
可以看出OUTB1、OUTA1不能同时输出1(只能同时为高阻态),因步进电 机的公共端是接到5V的,可以用高阻态代替1,OUTB2、OUTA2也是如此。 根据电机激励序列推出驱动芯片的输出序列;根据MX1508输入输出真值表, 可以从输出信号序列推出输入序列;由电机驱动芯片的输入推导出 100ASK_IMX6ULL的GPIO的信号序列:
四、编写思路
1.构造file_operations结构体
cpp
static struct file_operations gpio_key_drv = {
.owner = THIS_MODULE,
.write = motor_write,
};
2.编写入口函数
先每个申请引脚,然后每个引脚配置为输出模式,初始电平为低电平。
注册file_operations结构体
- register_chrdev()
- class_create()
- device_create()
3.编写出口函数
卸载驱动程序,释放gpio
- device_destroy()
- class_destroy()
- unregister_chrdev()
- gpio_free()
4.编写write函数
应用层会传入步进数和延时时间,根据步进数的正负判断电机转动的方向。
static int g_motor_pin_ctrl[8]= {0x2,0x3,0x1,0x9,0x8,0xc,0x4,0x6};
根据步进数按正或反顺序从该数组中取出值,对引脚进行设置。
完成转动后,将引脚输出电平都设置为低电平。
五、bug记录
请求到gpio后,忘记给gpio设置输出。
六、源码
驱动
cpp
#include "asm-generic/gpio.h"
#include "asm/gpio.h"
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>
struct gpio_desc{
int gpio;
int irq;
char *name;
int key;
struct timer_list motor_timer;
};
static struct gpio_desc gpios[4] = {
{115, 0, "motor_gpio0", },
{116, 0, "motor_gpio1", },
{117, 0, "motor_gpio2", },
{118, 0, "motor_gpio3", },
};
static int major;
static struct class *motor_class;
static int g_motor_pin_ctrl[8]= {0x2,0x3,0x1,0x9,0x8,0xc,0x4,0x6};
static ssize_t motor_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
int kernel_buf[2];
int ret;
int step;
int index = 0;
int i;
if (size != 8)
{
return -EINVAL;
}
ret = copy_from_user(kernel_buf, buf, size);
if (kernel_buf[0] > 0)
{
for (step = 0; step < kernel_buf[0]; step++)
{
for (i = 0; i < 4; i++)
{
gpio_set_value(gpios[i].gpio, g_motor_pin_ctrl[index] & (1 << i) ? 1 : 0);
}
index--;
mdelay(kernel_buf[1]);
if (index < 0)
{
index = 7;
}
}
}
else
{
kernel_buf[0] = 0 - kernel_buf[0];
for (step = 0; step < kernel_buf[0]; step++)
{
for (i = 0; i < 4; i++)
{
gpio_set_value(gpios[i].gpio, g_motor_pin_ctrl[index] & (1 << i) ? 1 : 0);
}
index++;
mdelay(kernel_buf[1]);
if(index > 7)
{
index = 0;
}
}
}
for (i = 0; i < 4; i++)
{
gpio_set_value(gpios[i].gpio, 0);
}
return 8;
}
static struct file_operations motor_drv = {
.owner = THIS_MODULE,
.write = motor_drv_write,
};
static int __init motor_drv_init(void)
{
int i ;
int count = sizeof(gpios) / sizeof(gpios[0]);
for (i = 0; i < count; i++)
{
gpio_request(gpios[i].gpio, gpios[i].name);
gpio_direction_output(gpios[i].gpio, 0);
}
major = register_chrdev(0, "motor_drv", &motor_drv);
motor_class = class_create(THIS_MODULE, "motor_class");
if (IS_ERR(motor_class))
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
unregister_chrdev(major, "motor_drv");
return PTR_ERR(motor_class);
}
device_create(motor_class, NULL, MKDEV(major, 0), NULL, "motor_drv");
return 0;
}
static void __exit motor_drv_exit(void)
{
int i ;
int count = sizeof(gpios) / sizeof(gpios[0]);
device_destroy(motor_class, MKDEV(major, 0));
class_destroy(motor_class);
unregister_chrdev(major, "motor_drv");
for (i = 0; i < count; i++)
{
gpio_free(gpios[i].gpio);
}
}
module_init(motor_drv_init);
module_exit(motor_drv_exit);
MODULE_LICENSE("GPL");
应用
cpp
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <poll.h>
#include <signal.h>
#include <stdlib.h>
static int fd;
/*
* ./button_test /dev/motor -100 1
*
*/
int main(int argc, char **argv)
{
int buf[2];
int ret;
/* 1. 判断参数 */
if (argc != 4)
{
printf("Usage: %s <dev> <step_number> <mdelay_number>\n", argv[0]);
return -1;
}
/* 2. 打开文件 */
fd = open(argv[1], O_RDWR);
if (fd == -1)
{
printf("can not open file %s\n", argv[1]);
return -1;
}
buf[0] = strtol(argv[2], NULL, 0);
buf[1] = strtol(argv[3], NULL, 0);
ret = write(fd, buf, 8);
close(fd);
return 0;
}