Linux驱动入门实验班——步进电机模块驱动(附百问网视频链接)

目录

一、工作原理

二、接口图

三、真值表

四、编写思路

1.构造file_operations结构体

2.编写入口函数

3.编写出口函数

4.编写write函数

五、bug记录

六、源码

课程链接


一、工作原理

步进电机由定子和转子两部分组成。定子上有多组线圈,通常称为相,每组相通常由两个电流互相反向的线圈组成。转子上有多个磁极,通常称为步进角。

当电流通过其中一组线圈时,该线圈就会产生一个磁场。由于线圈中电流方向的变化,磁场也会随之改变方向。转子的磁极会受到相邻线圈磁场的作用而进行转动。当电流改变到下一组线圈时,转子又会根据新的磁场方向进行转动。通过不断改变电流的方向和大小,可以控制步进电机的转动角度。

二、接口图

三、真值表

下图为驱动芯片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;
}

课程链接

46_步进马达控制原理与接线 (100ask.net)https://video.100ask.net/p/t_pc/course_pc_detail/video/v_636f7261e4b0276efeaffac6?product_id=p_634cbce4e4b00a4f37500252&content_app_id=&type=6

相关推荐
watermelonoops3 分钟前
Deepin和Windows传文件(Xftp,WinSCP)
linux·ssh·deepin·winscp·xftp
疯狂飙车的蜗牛1 小时前
从零玩转CanMV-K230(4)-小核Linux驱动开发参考
linux·运维·驱动开发
yutian06062 小时前
Keil MDK下载程序后MCU自动重启设置
单片机·嵌入式硬件·keil
远游客07133 小时前
centos stream 8下载安装遇到的坑
linux·服务器·centos
马甲是掉不了一点的<.<3 小时前
本地电脑使用命令行上传文件至远程服务器
linux·scp·cmd·远程文件上传
jingyu飞鸟3 小时前
centos-stream9系统安装docker
linux·docker·centos
超爱吃士力架4 小时前
邀请逻辑
java·linux·后端
析木不会编程4 小时前
【小白51单片机专用教程】protues仿真独立按键控制LED
单片机·嵌入式硬件·51单片机
cominglately6 小时前
centos单机部署seata
linux·运维·centos
魏 无羡6 小时前
linux CentOS系统上卸载docker
linux·kubernetes·centos