【技术支持】ARM9无线遥控视频实时监控小车(二)--------摄像头舵机控制模块
舵机控制原理及使用说明更具一下地址的文件就可以了
http://wenku.baidu.com/view/8902f4125f0e7cd18425361d.html
最主要是的怎么样让我的ARM开发板产生PWM波
S3C2440的开发板上义工也就5个定时器
我主要用的是定时器0和定时器1,可以根据自己的手册找到他们所在的位置
我的ARM班的两个GPB0和GPB1分别对应开发板上的蜂鸣器和R47
因为我不用液晶屏所以用掉GPB0是没有关系的,还有我把蜂鸣其给卸了
接下来是编写驱动,定时器驱动网上有很多参考的推荐看楼下的,第一篇看不懂看第二篇
http://apps.hi.baidu.com/share/detail/20885191
http://wenku.baidu.com/view/b1a04da0284ac850ad02426d.html
对于初学的我,当时是先看第二篇。
但是第二篇里面的一些库函数在我的linux版本中已经没有了
下面是我写的定时器驱动,我控制的是两个舵机所以需两路PWM
1 #include <linux/module.h>
2 #include <linux/init.h>
3 #include <linux/kernel.h>
4 #include <linux/fs.h>
5 #include <linux/errno.h>
6 #include <linux/clk.h>
7 #include <linux/device.h>
8 #include <asm/io.h>
9 #include <asm-arm/arch-s3c2410/hardware.h>
10 #include <asm-arm/arch-s3c2410/regs-gpio.h>
11 #include <asm-arm/plat-s3c/regs-timer.h>
12
13 MODULE_AUTHOR("FOX,GMAIL:huli_131@hotmail.com);
14 MODULE_DESCRIPTION("Driver test pwm");
15 MODULE_LICENSE("GPL");
16
17 #define PWM_MAJOR 0 //主设备号
18 #define PWM_NAME "pwm-drv" //设备名称
19 static int device_major = PWM_MAJOR; //系统动态生成的主设备号
20 static struct class *pwm_class;
21
22 static int pwm_open(struct inode *inode, struct file *file)
23 {
24 //对GPB0和GPB1复用口进行复用功能设置,设置为TOUT
25 s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_TOUT0);
26 s3c2410_gpio_cfgpin(S3C2410_GPB1, S3C2410_GPB1_TOUT1);
27
28 return 0;
29 }
30
31 static int pwm_close(struct inode *inode, struct file *file)
32 {
33 return 0;
34 }
35
36 static int pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
37 {
38 if(cmd <= 0)//如果输入的参数小于或等于0的话,将GPB0和GPB1
39 {
40
41 s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);
42 s3c2410_gpio_setpin(S3C2410_GPB0, 1);
43 s3c2410_gpio_cfgpin(S3C2410_GPB1, S3C2410_GPB1_OUTP);
44 s3c2410_gpio_setpin(S3C2410_GPB1, 1);
45 }
46 else
47 {
48 unsigned long tcon;
49 unsigned long tcnt;
50 unsigned long trate; //控制舵机旋转的角度变量
51 unsigned long tcfg1;
52 unsigned long tcfg0;
53 struct clk *clk_p;
54 unsigned long pclk;
55
56 trate=arg;
57 tcfg0 = __raw_readl(S3C2410_TCFG0); //读取定时器配置寄存器0的值
58 tcfg1 = __raw_readl(S3C2410_TCFG1); //读取定时器配置寄存器1的值
59 tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
60 tcfg0 |= (250 - 1); //设置tcfg0的值为249
61
62 if(cmd == 1) //GPB 0
63 {
64 s3c2410_gpio_cfgpin(S3C2410_GPB1, S3C2410_GPB1_OUTP);
65 s3c2410_gpio_setpin(S3C2410_GPB1, 1);
66 s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_TOUT0);
67
68 printk("cmd:%d.\t",cmd);
69 printk("GPB0.\n");
70 tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;
71 tcfg1 |= S3C2410_TCFG1_MUX0_DIV2;
72
73 __raw_writel(tcfg1, S3C2410_TCFG1); //将值tcfg1写入定时器配置寄存器1中
74 __raw_writel(tcfg0, S3C2410_TCFG0); //将值tcfg0写入定时器配置寄存器0中
75
76 tcfg1 = __raw_readl(S3C2410_TCFG1); //读取定时器配置寄存器1的值
77 tcfg0 = __raw_readl(S3C2410_TCFG0);
78 printk("tcfg0:%X.\n",tcfg0);
79 printk("tcfg1:%X.\n",tcfg1);
80
81 clk_p = clk_get(NULL, "pclk");
82 pclk = clk_get_rate(clk_p); //从系统平台时钟队列中获取pclk的时钟频率,在include/linux/clk.h中定义
83 //tcnt = (pclk/50/16)/cmd; //计算定时器0的输出时钟频率(pclk/{prescaler0 + 1}/divider value)
84 //tcnt = 25*16*2500;
85
86 tcnt=2000;
87 printk("pclk:%d.\n",pclk);
88 printk("tcnt:%d.\n",tcnt);
89 printk("trate:%d.\n",trate);
90
91 __raw_writel(tcnt, S3C2410_TCNTB(0)); //设置定时器0计数缓存寄存器的值
92 __raw_writel(trate*10, S3C2410_TCMPB(0)); //设置定时器0比较缓存寄存器的值
93
94 tcon = __raw_readl(S3C2410_TCON); //读取定时器控制寄存器的值
95
96 tcon &= ~0x1f;
97 tcon |= 0xb; //关闭死区、自动重载、关反相器、更新TCNTB0&TCMPB0、启动定时器0
98
99 __raw_writel(tcon, S3C2410_TCON); //设置定时器控制寄存器的0-4位,即对定时器0进行控制
100 tcon &= ~2;
101 __raw_writel(tcon, S3C2410_TCON); //清除定时器0的手动更新位
102
103 printk("tcon:%X.\n",tcon);
104 printk("contol ok\n");
105 }
106
107 else if(cmd == 2) //GPB1
108 {
109 s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);
110 s3c2410_gpio_setpin(S3C2410_GPB0, 1);
111 s3c2410_gpio_cfgpin(S3C2410_GPB1, S3C2410_GPB1_TOUT1);
112 printk("cmd:%d.\t",cmd);
113 printk("GPB1.\n");
114 tcfg1 &= ~S3C2410_TCFG1_MUX1_MASK;
115 tcfg1 |= S3C2410_TCFG1_MUX1_DIV2;
116
117 __raw_writel(tcfg1, S3C2410_TCFG1); //将值tcfg1写入定时器配置寄存器1中
118 __raw_writel(tcfg0, S3C2410_TCFG0); //将值tcfg0写入定时器配置寄存器0中
119
120 tcfg1 = __raw_readl(S3C2410_TCFG1); //读取定时器配置寄存器1的值
121 tcfg0 = __raw_readl(S3C2410_TCFG0);
122 printk("tcfg0:%X.\n",tcfg0);
123 printk("tcfg1:%X.\n",tcfg1);
124
125 tcnt=2000;
126 printk("pclk:%d.\n",pclk);
127 printk("tcnt:%d.\n",tcnt);
128 printk("trate:%d.\n",trate);
129
130 __raw_writel(tcnt, S3C2410_TCNTB(1));
131 __raw_writel(trate*10, S3C2410_TCMPB(1));
132
133 tcon = __raw_readl(S3C2410_TCON); //读取定时器控制寄存器的值
134 tcon &= ~(0xf10);
135 tcon |= (0xb00);// timer 1
136
137 __raw_writel(tcon, S3C2410_TCON); //设置定时器控制寄存器的8-11位,即对定时器1进行控制
138 tcon &= ~(0x200);
139 __raw_writel(tcon, S3C2410_TCON); //清除定时器0的手动更新位
140 printk("tcon:%X.\n",tcon);
141 printk("contol ok\n");
142 }
143
144 }
145 return 0;
146 }
147
148 //设定函数的接口
149 static struct file_operations pwm_fops =
150 {
151 .owner = THIS_MODULE,
152 .open = pwm_open,
153 .release = pwm_close,
154 .ioctl = pwm_ioctl,
155 };
156
157 static int __init pwm_init(void)
158 {
159 //注册为字符设备
160 device_major = register_chrdev(0,PWM_NAME,&pwm_fops);
161 if(device_major < 0)
162 {
163 printk("register %s error\n",PWM_NAME);
164 return 1;
165 }
166 printk("Dev number:%d,%d\n",device_major,0);
167 pwm_class = class_create(THIS_MODULE,PWM_NAME);
168 if(pwm_class == NULL)
169 {
170 printk("device class create fail\nTODO::mknod /dev/%s c %d %d\n",PWM_NAME,device_major,0);
171 }
172 else
173 {
174 device_create(pwm_class,NULL,MKDEV(device_major,0),"%s%d",PWM_NAME,0);
175 printk("/dev/%s%d register success\n",PWM_NAME,0);
176 }
177 return 0;
178 }
179 static void __exit pwm_exit(void)
180 {
181 unregister_chrdev(device_major, PWM_NAME);
182 device_destroy(pwm_class, MKDEV(device_major, 0));
183 class_destroy(pwm_class);
184 }
185 module_init(pwm_init);
186 module_exit(pwm_exit);
编译的makefile文件在
【技术支持】ARM9无线遥控视频实时监控小车(一)--------小车电机控制模块中
下面是测试程序
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <fcntl.h>
4 #include <sys/ioctl.h>
5 int main(int argc, char **argv)
6 {
7 int tmp;
8 int rate;
9 int fd;
10 int i;
11
12 if(argc!=2){printf("cmd error\n");return 1;}
13 fd=open(argv[1],O_RDWR);
14
15 //fd = open("/dev/pwm-drv0", O_RDWR);
16 if(fd < 0)
17 {
18 printf("Open PWM Device Faild!\n");
19 exit(1);
20 }
21
22 printf("please enter 2 times number(0 is stop):\n");
23 while(1)
24 {
25 //输入参数
26 scanf("%d", &tmp);
27 scanf("%d", &rate);
28 printf("times = %d\n", tmp);
29 printf("rate = %d\n", rate);
30 //IO控制
31 ioctl(fd,tmp,rate);
32 if(tmp <= 0)
33 {
34 continue;
35 }
36 }
37 //关闭设备
38 close(fd);
39 return 0;
40 }
OK舵机基本控制已经实现,tmp是开启哪个驱动rate是舵机转动的角度大小,按照找空比来说rate不能小于8最大不能超过24否则舵机到了两段的时候会颤抖。这样就完成了对舵机的运动的测试.到时候就可以控制摄像头。到时候封装几个函数调用控制函数就可以实现舵机有规律的运动了。got it!

浙公网安备 33010602011771号