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、步进角:
步进电机的定子绕组每改变一次通电状态,转子转过的角度称步进角。
转子磁极数越多,步进角 越小
定子相数越多,步进角越小
通电方式节拍越多,步进角越小
例如 八拍模式下 360/(4 * 8 * 2) = 5.625
关于启动频率,也就是pps 这里间隔时间最好是大于1200us
与开发板的管脚连接
第一步 在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 driver2、构建file_operations3、获取硬件资源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); //释放GPIOdevice_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;elsestep = 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;
}
28BYJ-48 电机驱动(Linux)相关推荐
- Linux学习总结(48)——Linux防火墙iptables与firewalld学习总结
iptables命令是Linux上常用的防火墙软件,是netfilter项目的一部分.可以直接配置,也可以通过许多前端和图形界面配置. 语法 iptables(选项)(参数) 选项 -t<表&g ...
- 2009-07-03 19:48 在linux中如何获得微秒精度的时间?-转
※使用C的<time.h>库函数是无法达到微秒级别的时间的,所以上网找了一下答案,原文如下: ------------------------ 使用C语言进行计时,在用户空间中可以使用C语 ...
- 48、Linux共享内存传递cv::Mat
基本思想:最近在研究RoboMater源码,学习了如何使用共享内存传递cv::Mat 所以记录一下: send.cpp 读取了一张576*768*3通道的图片 #include <iostrea ...
- Linux期末复习题库(1)
[试题分类]: 1.下列哪种说法是错误的( ) . A.操作系统是裸机之上的第一层软件 B.操作系统控制和管理全部的计算机资源 C.Microsoft Office 是操作系统的一种 D.操作系统应为 ...
- linux相关面试题总结!
选择题 1 在终端下输入mount -a命令的作用是:C A 强制进行磁盘检查 B 显示当前挂载的所有磁盘分区的信息 C 挂载/etc/fstab文件中的除noauto以外的所有磁盘分区 D 以只读方 ...
- linux软件安装非系统盘,linux操作系统可不可以像安装windows软件一样在windows系统下的硬盘上安装...
linux操作系统可不可以像安装windows软件一样在windows系统下的硬盘上安装 答案:2 信息版本:手机版 解决时间 2020-07-24 14:13 已解决 2020-07-23 16: ...
- linux下被遗忘的gpio_keys按键驱动
我们新项目硬件设计上使用gpio口做按键,所以我就需要搞定这个驱动,本来想自己写一个gpio口的按键驱动,然后看了下内核下面的代码,已经有现成的了.Linux内核下游很多很多的现成驱动,只要你想得到的 ...
- RPM方式安装MySQL5.5.48 (Aliyun CentOS 7.0 卸载MySQL5.7)
环境是阿里云的CentOS7.0,更新了yum源(更新yum源请参考https://help.aliyun.com/knowledge_detail/5974184.html)之后先是尝试安装了MyS ...
- 【备忘】linux视频
参考笔记 内部参考脚本 [M哥linux-多年内部积累电子书-无价之宝]Books7 01.M哥亲讲Linux运维发展与学习路线图.mp4 02.Linux云计算学习环境介绍.mp4 03.Linu ...
最新文章
- (转)有关Android线程的学习
- 测试集的构成比例对网络分类性能的影响cp
- SpringBoot配置嵌入式Servlet容器
- 梅森增益matlab求解,梅森公式互不接触回路及其增益
- oracle分区和锁的难,oracle使用三(锁和表分区)
- 《笑傲网湖》第二回 VLAN
- python 把list中的所有元素串起来变为字符串
- 2020年下系统集成项目管理工程师真题基础知识+解析1/3
- 深度学习:文本CNN-textcnn
- 什么是0day漏洞?
- java 获取本机地址_java如何获取本机IP地址
- 关于英语论文范文参考步骤的详细介绍
- 叉积的证明_矢量叉乘分配律的几何证明
- Tesla M40 下Ubuntu anaconda pycharm pytorch安装
- 华师大计算机基础在线作业,华东师范大学计算机作业答案
- Chino with Rewrite
- ubuntu home目录下的主用户目录被删处理
- 自己搭建的三相永磁同步电机直接转矩控制(DTC)模型
- 打印100-200以内的素数
- PAT(B) 1044 火星数字(Java)进制转换
热门文章
- Android ijkplayer播放rtsp直播流
- 通过在线制图工具绘制阿里云部署图
- python多个箱线图_python-matplotlib | 箱线图及解读
- Linux文件系统与持久性内存介绍:块设备、闪存(NAND/NOR)、NVDIMM(非易失性内存)、PMEM(PMDK)- ndctl
- B: 火车站(stack)
- 天地水火雷风山泽 乾坤坎离震巽艮兑
- 通过Windows防火墙禁止某程序(或软件)联网
- Django企业开发实战--by胡阳,学习记录1127
- easy-mock使用
- 精彩回顾|展会圆满收官,落幕不散场,期待与您的再次相遇,下一站上海!