一、前言
我的毕设已接近尾声,要用到舵机,用传统的32裸板控制舵机大家都比较熟悉,我也是,但是用Linux开发板来精准控制舵机,让我顿时没有头绪,一度想自己写一个Linux驱动,通过定时器来模拟PWM波输出,由于某些原因我放弃这种方式。经过查阅资料,Linux板控制舵机的方式有
- 通过sysfs的方式进行操控。
- 在设备驱动程序中通过辅助函数device_create()创建设备节点。
- 新手初期常用的mknod命令。(我本想这样做,但放弃了)
参考资料:http://t.csdnimg.cn/EVu9m
参考了好几个老哥的文章,虽然这些资料要么不太合适,要么有些小错误,但是在综合参考这几篇文章精华以及百度学习以后,终于可以控制舵机了。
二、 PWM驱动及测试
2.1
参考资料:
在Ubuntu中:
进入源码文件,编辑设备树
book@100ask:~/100ask_imx6ull-sdk/Linux-4.9.88/arch/arm/boot/dts$ vi 100ask_imx6ull-14x14.dts
如图:
输入:
&pwm7 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm7>;
status = "okay";
};
继续,如图:
输入:
pinctrl_pwm7: pwm7grp {
fsl,pins = <
MX6UL_PAD_CSI_VSYNC__PWM7_OUT 0x000010B0
>;
};
好的,现在vi编辑另一个文件
book@100ask:~/100ask_imx6ull-sdk/Linux-4.9.88/arch/arm/boot/dts$ vi imx6ull.dtsi
参考资料:设置imx6ull GPIO扩展板PWM7/8中的pwm0/period后卡死 - #5,来自 jxaa1991aa - IMX6ULL_PRO - 嵌入式开发问答社区
然后就可以编译设备树了,输入:
book@100ask:~/100ask_imx6ull-sdk/Linux-4.9.88$ make dtbs
编译成功后,将编译好的设备树文件100ask_imx6ull-14x14.dtb 复制到开发板
2.2
进入开发板:
跟着我操作:
[root@100ask:~]# cd /sys/class/pwm
//看看这个目录下有什么
root@100ask:/sys/class/pwm]# ls
pwmchip0 pwmchip1 pwmchip2 pwmchip3 pwmchip4 pwmchip5 pwmchip6 pwmchip7
//由于我们选择的是pwm7,然后pwm控制器pwmchip0对应pwm1,所以我们pwm7对应pwmchip6
root@100ask:/sys/class/pwm]# cd pwmchip6
//调出pwm0目录下设备节点
root@100ask:/sys/class/pwm/pwmchip6]# echo 0 > export
//注意,一定要先配置好pwm的周期和占空比才能使能pwm
//配置周期
[root@100ask:/sys/class/pwm/pwmchip6]# echo 20000000 > pwm0/period
//配置占空比,高电平时间
root@100ask:/sys/class/pwm/pwmchip6]# echo 1000000 > pwm0/duty_cycle
//最后使能pwm
root@100ask:/sys/class/pwm/pwmchip6]# echo 1 > pwm0/enable
接着就可以直接连续修改占空比控制舵机反复运动了。测试,连续输入:
[root@100ask:/sys/class/pwm/pwmchip6]# echo 1200000 > pwm0/duty_cycle
[root@100ask:/sys/class/pwm/pwmchip6]# echo 800000 > pwm0/duty_cycle
可以看到我的舵机变化如下:
三、百问网imx6ull开发板的拓展板引脚号和pwm对应关系
参考:设置imx6ull GPIO扩展板PWM7/8中的pwm0/period后卡死 - IMX6ULL_PRO - 嵌入式开发问答社区
首先查看原理图:
拓展板原理图:
而这个老哥:http://t.csdnimg.cn/EVu9m
利用官方NXP的工具i.MX pins v6,得出结论就是gpio4_io19对应csi_vsync , gpio4_io20对应csi_hsync ,百问网的拓展板就只有这两路gpio有专门的pwm波功能。
我的线路图:
四、 控制舵机的Linux应用程序代码
参考这个老哥:http://t.csdnimg.cn/f0yTn
想漂亮一点封装函数的,可以看这个老哥:http://m.eeworld.com.cn/bbs_thread-1271111-1-1.html
#include "stdio.h"
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
static char file_path[] = "/sys/class/pwm/pwmchip5/pwm0";
static int pwm_config(char* attr,char* val){
char path[100];
int fd;
sprintf(path,"%s/%s",file_path,attr);
fd = open(path,O_WRONLY);
if(fd <= 0){
perror("open error:");
return fd;
}
int len = strlen(val);
if(len != write(fd,val,len)){
perror("write error!");
close(fd);
return 1;
}
close(fd);
return 0;
}
int main(int argc,char *argv[]){
int fd;
int angle;
long duty_cycle;
if(argc != 2){
printf("use err,please use %s + -90 / -45 / 0 / 45 / 90\n",
argv[0]);
}
if(access(file_path,F_OK)){
fd = open("/sys/class/pwm/pwmchip5/export",O_WRONLY);
if(fd <=0){
perror("open error");
exit(-1);
return fd;
}
if(1!=write(fd,"0",1)){
perror("write error");
close(fd);
exit(-1);
}
close(fd);
}
angle = atoi(argv[1]);
duty_cycle = 2000000.0/180.0*angle+500000; //单位角度高电平时间*角度+零度的高电平时间
char duty_cycle_str [10];
sprintf(duty_cycle_str,"%d",duty_cycle);
if(pwm_config("period","20000000"))
exit(-1);
if(pwm_config("duty_cycle",duty_cycle_str))
exit(-1);
if(pwm_config("enable","1"))
exit(-1);
return 0;
}