WiFi遥控小车(四):简单直流电机驱动及UDP通信程序

之前说过只要能控制高低电平就可以控制电机的正反转,我想通过修改友善官方的LED驱动程序来达到控制GPIO高低电平的目的,但是看了很久都没有怎么看懂,就去网上找看有没有比较好理解的程序,找到一个,原帖地址如下,十分感谢intel版主的无私分享

http://www.arm9home.net/read.php?tid-15941.html

原帖作者的小车是通过左右轮子的差速来实现转向的,可我的小车是后轮驱动,靠前轮转向的,所以对源程序做了些修改:

C代码 
  1. #include <linux/miscdevice.h>  
  2. #include <linux/delay.h>  
  3. #include <asm/irq.h>  
  4. //#include <mach/regs-gpio.h>  
  5. #include <mach/hardware.h>  
  6. #include <linux/kernel.h>  
  7. #include <linux/module.h>  
  8. #include <linux/init.h>  
  9. #include <linux/mm.h>  
  10. #include <linux/fs.h>  
  11. #include <linux/types.h>  
  12. #include <linux/delay.h>  
  13. #include <linux/moduleparam.h>  
  14. #include <linux/slab.h>  
  15. #include <linux/errno.h>  
  16. #include <linux/ioctl.h>  
  17. #include <linux/cdev.h>  
  18. #include <linux/string.h>  
  19. #include <linux/list.h>  
  20. #include <linux/pci.h>  
  21. #include <asm/uaccess.h>  
  22. #include <asm/atomic.h>  
  23. #include <asm/unistd.h>  
  24.   
  25. #include <mach/map.h>  
  26. #include <mach/regs-clock.h>  
  27. #include <mach/regs-gpio.h>  
  28. #include <mach/gpio.h>  
  29.   
  30. //#include <linux/gpio.h>  
  31.   
  32. #include <plat/gpio-cfg.h>  
  33. #include <mach/gpio-bank-e.h>  
  34. #include <mach/gpio-bank-k.h>  
  35.   
  36. #define DEVICE_NAME "car"  
  37.   
  38. //控制前后的电机  
  39. #define MOTOR_QH_ENA    S3C64XX_GPM(4)  
  40. #define MOTOR_QH_ENB    S3C64XX_GPM(5)  
  41. //控制方向的电机  
  42. #define MOTOR_FX_ENA    S3C64XX_GPE(3)  
  43. #define MOTOR_FX_ENB    S3C64XX_GPE(4)  
  44.   
  45.   
  46. #define debug 1  
  47.   
  48. static unsigned long motor_table [] = {  
  49.     MOTOR_QH_ENA,  
  50.     MOTOR_QH_ENB,  
  51.     MOTOR_FX_ENA,  
  52.     MOTOR_FX_ENB  
  53. };  
  54.   
  55. //初始化GPIO口  
  56. static int car_motor_init(void)  
  57. {  
  58.   int ret=0,i;  
  59.     for (i = 0; i < 4; i++)   
  60.     {  
  61.           
  62.         if(gpio_is_valid(motor_table[i])==-EINVAL)  
  63.         {  
  64.           printk("ERROR,GPIO used by other devices ! \n");  
  65.           break;  
  66.         }  
  67.         //上拉GPIO  
  68.       s3c_gpio_setpull(motor_table[i], S3C_GPIO_PULL_UP);  
  69.       //设置为输出  
  70.       s3c_gpio_cfgpin(motor_table[i], S3C_GPIO_OUTPUT);  
  71.       //设置默认值为低电平  
  72.       gpio_set_value(motor_table[i],0);  
  73.        
  74.     }  
  75.       
  76.   return ret;  
  77. };  
  78.   
  79.   
  80. static void car_motor_status(void)  
  81. {  
  82.     printk("MOTOR_QH_ENA=%d\nMOTOR_QH_ENB=%d\nMOTOR_FX_ENA=%d\nMOTOR_FX_ENB=%d\n",  
  83.     gpio_get_value(MOTOR_QH_ENA),  
  84.     gpio_get_value(MOTOR_QH_ENB),  
  85.     gpio_get_value(MOTOR_FX_ENA),  
  86.     gpio_get_value(MOTOR_FX_ENB));  
  87.       
  88. };  
  89.   
  90. static void car_motor_run(void)  
  91. {  
  92.     gpio_set_value(MOTOR_QH_ENA,1);  
  93.     gpio_set_value(MOTOR_QH_ENB,0);  
  94. };  
  95.   
  96.   
  97. static void car_motor_stop(void)  
  98. {  
  99. #if debug  
  100.      car_motor_status();  
  101. #endif  
  102.     gpio_set_value(MOTOR_QH_ENA,0);  
  103.     gpio_set_value(MOTOR_QH_ENB,0);  
  104. };  
  105.   
  106.   
  107. static void car_motor_back(void)  
  108. {  
  109.     gpio_set_value(MOTOR_QH_ENA,0);  
  110.     gpio_set_value(MOTOR_QH_ENB,1);  
  111. };  
  112.   
  113. static void car_motor_left(void)  
  114. {  
  115.     gpio_set_value(MOTOR_FX_ENA,1);  
  116.     gpio_set_value(MOTOR_FX_ENB,0);  
  117. };  
  118.   
  119. static void car_motor_right(void)  
  120. {  
  121.     gpio_set_value(MOTOR_FX_ENA,0);  
  122.     gpio_set_value(MOTOR_FX_ENB,1);  
  123. };  
  124.   
  125. static void car_motor_zheng(void)  
  126. {  
  127.     gpio_set_value(MOTOR_FX_ENA,0);  
  128.     gpio_set_value(MOTOR_FX_ENB,0);  
  129. };  
  130.   
  131.   
  132. static long car_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  
  133. {  
  134. #if debug  
  135.     printk("cmd=%d\n",cmd);  
  136. #endif  
  137.     long ret=0;  
  138.     switch(cmd)  
  139.     {  
  140.       case '0'case 0:  
  141.       //小车停止  
  142.       car_motor_stop();  
  143.       break;  
  144.         
  145.       case '1'case 1:  
  146.       //小车前进  
  147.       car_motor_run();  
  148.       break;  
  149.       //小车后退  
  150.       case '2'case 2:  
  151.       car_motor_back();  
  152.       break;  
  153.       //左转  
  154.       case '3'case 3:  
  155.       car_motor_left();  
  156.       break;  
  157.       //右转  
  158.       case '4'case 4:  
  159.       car_motor_right();    
  160.       break;  
  161.       //直走  
  162.       case '5'case 5:   
  163.       car_motor_zheng();  
  164.       break;  
  165.       //小车后退  
  166.       case '6'case 6:  
  167.       car_motor_back();  
  168.       break;  
  169.   
  170.         return 0;  
  171.     default:  
  172.         return -EINVAL;  
  173.     }  
  174.     return ret;  
  175. }  
  176.   
  177. static struct file_operations dev_fops = {  
  178.     .owner          = THIS_MODULE,  
  179.     .unlocked_ioctl = car_ioctl,  
  180. };  
  181.   
  182. static struct miscdevice misc = {  
  183.     .minor = MISC_DYNAMIC_MINOR,  
  184.     .name = DEVICE_NAME,  
  185.     .fops = &dev_fops,  
  186. };  
  187.   
  188. static int __init dev_init(void)  
  189. {  
  190.     int ret;  
  191.   
  192.     car_motor_init();  
  193. //  car_motor_run();  
  194.     ret = misc_register(&misc);  
  195.   
  196.     printk (DEVICE_NAME"\tinitialized\n");  
  197.   
  198.     return ret;  
  199. }  
  200.   
  201. static void __exit dev_exit(void)  
  202. {  
  203.     misc_deregister(&misc);  
  204. }  
  205.   
  206. module_init(dev_init);  
  207. module_exit(dev_exit);  
  208. MODULE_LICENSE("GPL");  
  209. MODULE_AUTHOR("Lintel.");  

 为了测试驱动,根据友善的LED测试程序进行了修改,修改的程序如下:

C代码
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <sys/ioctl.h>  
  5. #include <sys/types.h>  
  6. #include <sys/stat.h>  
  7. #include <fcntl.h>  
  8.   
  9. int main(int argc, char **argv)  
  10. {  
  11.     int cmd;  
  12.     int led_no;  
  13.     int fd;  
  14.   
  15.     if (argc != 3 || sscanf(argv[1], "%d", &led_no) != 1 || sscanf(argv[2],"%d", &cmd) != 1 ||  
  16.             cmd < 0 || cmd > 9 || led_no < 0 || led_no > 3) {  
  17.         fprintf(stderr, "Usage: car led_no 0|1\n");  
  18.         exit(1);  
  19.     }  
  20.   
  21.     fd = open("/dev/car0", 0);  
  22.     if (fd < 0) {  
  23.         fd = open("/dev/car", 0);  
  24.     }  
  25.     if (fd < 0) {  
  26.         perror("open device car");  
  27.         exit(1);  
  28.     }  
  29.   
  30.     printf("CMD=%d\n",cmd);  
  31.     ioctl(fd, cmd, led_no);  
  32.     close(fd);  
  33.   
  34.     return 0;  
  35. }  

 这个测试程序有个小问题,当传入的参数为‘0’‘1’时没有问题,但是当参数为‘2’时,怎么也传不进去,所以我把驱动代码的‘6’设置为了和‘2’一样的行为。

下面进行连线,按照驱动的GPIO口连接到电机驱动模块上,因为没有买到间距为2mm的接口,先用一根一根的线代替了,小车现在是这个样子:


接下来马上就进行UDP通信部分,我也买了友善的SDWIFI模块,插上就能用,按照文档连上了我的路由器,用ifconfig命令查看开发板ip,开发板和笔记本互相能ping通,接下来就是写程序来监听指定端口上得到的数据并做出相应的反应,这部分不是很难,我是借了本书《嵌入式Linux案例开发指南》按照上面的例程修改的,源码如下:

C代码 
  1. /* 
  2.  * main.c 
  3.  * 
  4.  *  Created on: 2012-10-18 
  5.  *      Author: micro 
  6.  */  
  7. #include<sys/types.h>  
  8. #include<sys/socket.h>  
  9. #include<string.h>  
  10. #include<netinet/in.h>  
  11. #include<stdio.h>  
  12. #include<stdlib.h>  
  13. #include <sys/ioctl.h>  
  14. #define MAXLINE 5  
  15.   
  16. #define SERV_PORT 12345  
  17.   
  18. void do_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen) {  
  19.     int n;  
  20.     socklen_t len;  
  21.     char mesg[MAXLINE];  
  22.     for (;;) {  
  23.         len = clilen;  
  24.         printf("Waiting for Data...\n");  
  25.         //等待数据  
  26.         n = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);  
  27.         //将数据返回  
  28.         //sendto(sockfd, mesg, n, 0, pcliaddr, len);  
  29.         //打印数据  
  30.         //printf("%s\n", mesg);  
  31.         colcars(mesg[0]);  
  32.     }  
  33. }  
  34. //根据收到的信息执行操作  
  35. void colcars(char cmd) {  
  36.     if (cmd < '0' || cmd > '10') {  
  37.         printf("cmd error\n");  
  38.     } else {  
  39.         if (cmd == '2') {  
  40. //          printf("car back\n");  
  41.             car_col('6');  
  42.         } else {  
  43.             car_col(cmd);  
  44.         }  
  45.     }  
  46. }  
  47.   
  48. void car_col(char cmd) {  
  49.     int fd;  
  50.     fd = open("/dev/car0", 0);  
  51.     if (fd < 0) {  
  52.         fd = open("/dev/car", 0);  
  53.     }  
  54.     if (fd < 0) {  
  55.         perror("open device car");  
  56.         return;  
  57.     }  
  58.     ioctl(fd, cmd, 0);  
  59.     close(fd);  
  60. }  
  61.   
  62. int main(void) {  
  63.     int sockfd;  
  64.     struct sockaddr_in servaddr, cliaddr;  
  65.     //建立socket  
  66.     sockfd = socket(AF_INET, SOCK_DGRAM, 0);  
  67.   
  68.     //初始化服务器地址  
  69.     bzero(&servaddr, sizeof(servaddr));  
  70.     servaddr.sin_family = AF_INET;  
  71.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY );  
  72.     servaddr.sin_port = htons(SERV_PORT);  
  73.   
  74.     //为socket绑定端口  
  75.     if (bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1) {  
  76.         perror("bind error");  
  77.         exit(1);  
  78.     }  
  79.     //执行服务器程序  
  80.     do_echo(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr));  
  81.     return 0;  
  82.   
  83. }  
         而我之前做过控制端的程序,包括安卓、黑莓上的控制程序现在都可以直接拿过来用,只需要把发送的字符串修改一下就好了,下图是我用台式机向开发版发送指令(在同一个路由器连接下),笔记本的终端只相当于一个通过串口显示的作用。


至此,我已经基本把我之前的学习内容总结了一遍,我的小车已经基本实现了通过WiFi来远程控制前后左右运动的目的。但是现在我还不会用PWM信号来调速或者控制舵机,而且现在的程序相对粗糙,控制协议也很简单,还存在着每次重启开发板都要手动连接wifi、手动安装驱动与运行服务器程序等不足,这些都是我接下来所要解决的,另外还有块难啃的骨头——视频实时传输……谢谢大家对于我的关注,我会继续努力~~~ 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值