硬件介绍

小车:

面包板:

用于扩展接线,由于小车可以扩展许多模块,所以使用面包板增加容错性

L9110s:

电机的驱动模块,接通VCC,GND模块电源指示灯亮;下图中集成了两个L9110s。

B-1A -> P3.2; B-1B -> P3.3; A-1A -> P3.4; A-1B -> P3.5;

正转时:B_1A = 0; B_1B = 1; A_1A = 0; A_1B = 1;

反转时:B_1A = 1; B_1B = 0; A_1A = 1; A_1B = 0;

初步接线图:

PS:面包板,开关和单片机均采用热熔胶固定,电机及其驱动模块均由电池供电,除了上面提到L9110s和单片机的控制接线和电源之外,注意要有一根杜邦线让单片机和L9110s共地

让小车动起来

将小车组装完成后,首先就是要让小车动起来,由刚刚对于电机驱动模块的讲解可以很容易实现让电机正反转,基于此,前进后退,左转右转的代码就都能写出来了:

void move_backward() //后退
{B_1A_le = 1;B_1B_le = 0;A_1A_ri = 1;A_1B_ri = 0;
}void move_forward() //前进
{B_1A_le = 0;B_1B_le = 1;A_1A_ri = 0;A_1B_ri = 1;
}void move_leftturn() //左转
{B_1A_le = 0; //左轮不动B_1B_le = 0;A_1A_ri = 0; //右轮往前A_1B_ri = 1;
}void move_rightturn() //右转
{B_1A_le = 0; //左轮往前B_1B_le = 1;A_1A_ri = 0; //右轮不动A_1B_ri = 0;
}void move_stop() //停止
{B_1A_le = 0;B_1B_le = 0;A_1A_ri = 0;A_1B_ri = 0;
}

让小车前进的 实现效果:

代码封装

由于小车代码肯定会巨长无比,所以养成良好的习惯,习惯性的完成一个模块之后就封装,方法和上节DHT11的末尾方法一样, 创建motor的c和h文件。

小车的控制

在熟悉了小车如何进行移动之后,就要开始学习如何控制小车,在之前已经学习过各种模块了,其中就有很多可以用来控制小车:

1. 串口/蓝牙控制小车

依然采用封装函数的方法:

UART.c:

#include "reg52.h"
#include "delay.h"
#include "motor.h"
#include <string.h>sfr AUXR = 0x8E; //配置了这句话,才可以在UART的初始化里写AUXR寄存器,原因见STC89系列的手册
static int i = 0; //此时这句命令只会被执行一次。避免每次发生中断i都会清0
char cmd[12];void UartInit(void)        //9600bps@11.0592MHz
{PCON &= 0x7F;     //波特率不倍速SCON = 0x50;       //8位数据,可变波特率AUXR &= 0xBF;      //定时器1时钟为Fosc/12,即12TAUXR &= 0xFE;     //串口1选择定时器1为波特率发生器TMOD &= 0x0F;        //清除定时器1模式位TMOD |= 0x20;       //设定定时器1为8位自动重装方式TL1 = 0xFD;       //设定定时初值TH1 = 0xFD;        //设定定时器重装值ET1 = 0;     //禁止定时器1中断TR1 = 1;     //启动定时器1
}void printSTR(char *msg)
{while(*msg != '\0'){SBUF = *msg; //往发送缓冲器里写入数据,就完成了数据的发送while(TI == 0); //只有当TI为1时,才往下走,根据手册,TI只有在发送完8位数据后才会硬件自动置1TI = 0;msg++;}}void Dealstr()
{if(cmd[0] == 'M' && cmd[1] == '1'){ //前进move_forward();memset(cmd,'\0',12); //将字符串清空}if(cmd[0] == 'M' && cmd[1] == '2'){ //后退move_backward();memset(cmd,'\0',12); //将字符串清空}if(cmd[0] == 'M' && cmd[1] == '3'){ //左转move_leftturn();memset(cmd,'\0',12); //将字符串清空}if(cmd[0] == 'M' && cmd[1] == '4'){ //右转move_rightturn();memset(cmd,'\0',12); //将字符串清空}if(cmd[0] == 'M' && cmd[1] == '5'){ //停止move_stop();memset(cmd,'\0',12); //将字符串清空}}void UARTinter() interrupt 4 //由于不管TI还是RI置1时,中断都会发生,所以为了逻辑严谨,可以在中断处理函数中添加判断
{if(RI == 1){ //如果是RI引起的中断char tmp;tmp = SBUF;if(tmp == 'M'|| i == 12){ //M1=前进;M2=后退;M3=左转;M4=右转; M5=停止i = 0;}cmd[i] = tmp; //从SBUF里面读发来的数据i++;Dealstr();RI = 0;//软件复位}}

main.c:

#include "reg52.h"
#include "intrins.h" //这个库加了,delay函数里面的nop()才不会报错
#include "motor.h"
#include "delay.h"
#include "UART.h"sbit D5 = P3^7;void main()
{UartInit();ES = 1;EA = 1; //打开中断!while(1){printSTR("mjm");Delay1000ms();}}

实现效果:

可以不断接受心跳指令的同时,写下M1,M2,M3,M4,M5电机会做出对应的动作。

实现了串口,就相当于实现了蓝牙,因为蓝牙模块也使用了串口:

同样, 可以不断接受心跳指令的同时,写下M1,M2,M3,M4,M5电机会做出对应的动作。

PS: 连一根杜邦线接面包板的正极和单片机的VCC,加上之前连的共地线,就可以实现电池给单片机的供电,从而实现小车的无线控制。并且,这种方式不是点动,比如左转一点点我要输入M3,然后再输入M5停下,但是现实生活中的遥控车,按下左转的时候左转,不按就不会左转,即现实中的遥控车是点动的,而我以上实现的并不是。

同时注意到虽然我输入的是M1是前进的意思,但是车子并没有笔直往前,说明小车两边的电机输出可能存在一定的差异。

2.使用无线遥控器遥控

我同样尝试了使用做电瓶车遥控器时用过的433M无线收发模块:

433M.c:

#include "reg52.h"
#include "motor.h"
#include "delay.h"sbit D0 = P0^0;
sbit D1 = P0^1;
sbit D2 = P0^2;
sbit D3 = P0^3;void statusCheck()
{if(D0 == 1){ //D0(A)为前进move_forward();}else if(D1 == 1){ //D1(B)为右转move_rightturn();}else if(D2 == 1){ //D2(C)为左转move_leftturn();}else if(D3 == 1){ //D3(D)为后退move_backward();}else{move_stop();}
}

main.c:

#include "reg52.h"
#include "intrins.h" //这个库加了,delay函数里面的nop()才不会报错
#include "motor.h"
#include "delay.h"
#include "433M.h"void main()
{while(1){statusCheck();}}

PS:这种实现方式虽然可以实现点动,但是太“点”了,即我按一下按钮,电机只会微弱的转一下,而如果我长按,电机也只会不停的一抽一抽的微弱转动没法连续转动。。。

小车的PWM调速

在刚刚的控制中,实现了上下左右的控制,但是小车的速度无法控制,所以需要用PWM波来对小车的速度来进行控制:已知,对于电机,写1就是全速前进,那么比如在20ms内,如果一半的时间写1,一半的时间写0,那就会比20ms一直是1来的速度慢一半,基于这种思路就可以用PWM波,通过调整占空比来控制小车的速度:

timer0.c:

#include "reg52.h"
#include "motor.h"sfr AUXR = 0x8E; //配置了这句话,才可以在UART的初始化里写AUXR寄存器,原因见STC89系列的手册
int cnt = 0;
char speed;void Timer0Init(void)        //0.5毫秒@11.0592MHz
{AUXR &= 0x7F;     //定时器时钟12T模式TMOD &= 0xF0;      //设置定时器模式TMOD |= 0x01;     //设置定时器模式TL0 = 0x33;       //设置定时初值TH0 = 0xFE;        //设置定时初值TF0 = 0;       //清除TF0标志TR0 = 1;      //定时器0开始计时ET0 = 1;EA = 1;   //打开中断!
}//timer0的中断处理程序 //中断程序一般写在main函数的后面 //定时器0溢出时将触发这个中断函数
void timer0_inter() interrupt 1
{cnt++;TL0 = 0x33;       //重新给初值!!TH0 = 0xFE;if(cnt < speed){ //cnt =1 时,爆表了一次,过了0.5ms,speed的值越大,属于动的代码就占比越大,速度就越快//动move_forward();}else{//停止move_stop();}if(cnt == 39){//每经过(40*0.5毫秒 = )20毫秒,PWM波经过一个周期cnt = 0;}}

main.c:

#include "reg52.h"
#include "intrins.h" //这个库加了,delay函数里面的nop()才不会报错
#include "motor.h"
#include "delay.h"
#include "UART.h"
#include "433M.h"
#include "timer0.h"extern char speed;void main()
{UartInit();Timer0Init();while(1){speed = 10; //10/40 = 1/4的时间全速前进Delay1000ms();Delay1000ms();speed = 30; //30/40 = 3/4的时间全速前进Delay1000ms();Delay1000ms();}}

实现效果:

可以看到,小车每隔两秒就会在慢速和快速之间切换:

左右轮的分别调速:

要实现这个效果,首先要在motor.c中添加单独控制左右轮前进后退的代码:

void move_backward_left() //左轮后退
{B_1A_le = 1;B_1B_le = 0;
}void move_backward_right() //右轮后退
{A_1A_ri = 1;A_1B_ri = 0;
}void move_forward_left() //左轮前进
{B_1A_le = 0;B_1B_le = 1;
}void move_forward_right() //右轮前进
{A_1A_ri = 0;A_1B_ri = 1;
}void move_stop_left() //左轮停止B_1A_le = 0;B_1B_le = 0;
}void move_stop_right() //右轮停止
{A_1A_ri = 0;A_1B_ri = 0;
}

然后在timer0.c中进行修改,我名字起的不太好,要是要实现左右轮的控制,就需要两个timer,一个控制左轮一个控制右轮:

#include "reg52.h"
#include "motor.h"sfr AUXR = 0x8E; //配置了这句话,才可以在UART的初始化里写AUXR寄存器,原因见STC89系列的手册
int cnt1 = 0;
int cnt2 = 0;
char speed_left;
char speed_right;void Timer0Init(void)      //timer0控制左轮
{AUXR &= 0x7F;     //定时器时钟12T模式TMOD &= 0xF0;      //设置定时器模式TMOD |= 0x01;     //设置定时器模式TL0 = 0x33;       //设置定时初值TH0 = 0xFE;        //设置定时初值TF0 = 0;       //清除TF0标志TR0 = 1;      //定时器0开始计时ET0 = 1;EA = 1;   //打开中断!
}void Timer1Init(void)      //timer1控制右轮
{AUXR &= 0xBF;     //定时器时钟12T模式TMOD &= 0x0F;      //设置定时器模式TMOD |= 0x10;     //设置定时器模式TL1 = 0x33;       //设置定时初值TH1 = 0xFE;        //设置定时初值TF1 = 0;       //清除TF1标志TR1 = 1;      //定时器1开始计时ET1 = 1;EA = 1;   //打开中断!
}//timer0的中断处理程序 //中断程序一般写在main函数的后面 //定时器0溢出时将触发这个中断函数
void timer0_inter() interrupt 1
{cnt1++;TL0 = 0x33;      //重新给初值!!TH0 = 0xFE;if(cnt1 < speed_left){ //cnt =1 时,爆表了一次,过了0.5ms,speed的值越大,属于动的代码就占比越大,速度就越快//动move_forward_left();}else{//停止move_stop_left();}if(cnt1 == 39){//每经过(40*0.5毫秒 = )20毫秒,PWM波经过一个周期cnt1 = 0;}}//timer1的中断处理程序 //中断程序一般写在main函数的后面 //定时器1溢出时将触发这个中断函数
void timer1_inter() interrupt 3
{cnt2++;TL1 = 0x33;      //重新给初值!!TH1 = 0xFE;if(cnt2 < speed_right){ //cnt =1 时,爆表了一次,过了0.5ms,speed的值越大,属于动的代码就占比越大,速度就越快//动move_forward_right();}else{//停止move_stop_right();}if(cnt2 == 39){//每经过(40*0.5毫秒 = )20毫秒,PWM波经过一个周期cnt2 = 0;}}

智能小车的初认识---1相关推荐

  1. 清华校庆正当时,智能小车决赛日

    人工智能这一科技浪潮正在深刻改变着世界,智能机器人作为人工智能的一个综合性载体已经开始渗透进日常生活的方方面面,汽车行业亦是如此. 清华校庆正当时 110年砥砺奋进,110年春风化雨,清华大学与时代共 ...

  2. 华清远见智能小车视频服务器,华清远见版世界杯足球对抗赛,智能小车C位出道...

    哎,听说了吗?前天德国输了 听说了,简直扎心,不想接着看了,感觉人生失去了方向 世界杯不看了,可以看华清远见版世界杯足球对抗赛啊 听说还有视频彩蛋呢! 那还等啥啊,走,看看去! 4年一次的世界杯,简直 ...

  3. 树莓派综合项目2:智能小车(一)四轮驱动

    一.介绍   树莓派的小项目中,我首选了智能小车这个项目作为我探索的第一个目标,因为和很多小朋友一样,对遥控小汽车有种喜欢,特别是有过小时候欲求而不得的经历的大人们哈.   其实也还有现实因素考虑,智 ...

  4. 自动跟随小车c语言,基于OpenCV的智能小车运动轨迹跟踪方法研究

    摘要: 随着人工智能技术的快速发展,智能小车开发受到越来越多研究者的关注,也已经成为一个重要的研究方向,而解决智能小车在路径规划中行驶的运动故障重要手段是对其进行的视频监控,但是智能小车的视频监控只能 ...

  5. 如何利用深度学习知识--快速部署高速目标检测智能小车?

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 3月26日,英伟达图像处理系列公开课第三期线上开播,来自NVIDI ...

  6. 从我开始学单片机到完成一个智能小车的制作我都需要掌握哪些知识?

    10年前,我就是通过智能小车这个项目找到工作,成功入行的. 一些套件的购买记录和当时的笔记,很庆幸还能找到,不然大家以为我是键盘侠. 看了很多不同的文章,具备实际参考意义的不多,最大的问题就是方向错误 ...

  7. 【STM32 .Net MF开发板学习-17】Wifi遥控智能小车

    恰好以前购买的一个PDA含Wifi功能,所以与其用PC通过Zigbee控制智能小车,不如用PDA来控制,这样更为方便,不过由于目前.NET MF开发板不直接支持Wifi功能,所以我们也只好间接控制了, ...

  8. matlab智能小车避障,Arduino智能小车系列教程4——超声波避障

    Arduino智能小车系列教程4--超声波避障 Arduino智能小车系列教程 准备材料 超声波模块HC-SR04 舵机固定架 舵机安装 超声波接线 代码测试 代码详解 int getDistance ...

  9. 英伟达公开课 | 手把手教你部署一辆高速目标检测Jetbot智能小车

    主讲人 | 何琨 英伟达 量子位编辑 | 公众号 QbitAI 3月26日,英伟达图像处理系列公开课第三期线上开播,来自NVIDIA开发者社区的何琨老师,与数百位开发者共同探讨了: 利用NVIDIA迁 ...

  10. 智能小车设计指导 第二版

    这是我负责主编的设计指导,2009年9月初的第一版,一年之后出了第二版,现在吧链接放出来,有兴趣的可以参考. 点击此处下载 ourdev_599585DAN8LI.rar(文件大小:3.39M) (原 ...

最新文章

  1. 怎么在python下载网站内容-Python下载网页的几种方法
  2. node和java性能_服务端I/O性能大比拼:Node、PHP、Java和Go(二)
  3. 61-1 认识webpack
  4. Codeforces Round #743 (Div. 2) E. Paint 区间dp + 暴力
  5. 《团队之美》笔记——领导力
  6. Windows 10如何消除文件夹右上角的“相对箭头”?
  7. CAN笔记(6) CAN协议(一)
  8. 基于k8s安装配置kubeflow
  9. VUE项目中引入135编辑器
  10. Linux内核启动内核解压过程分析
  11. 机器人相关的会议期刊
  12. Java爬虫(三)后台发请求获取页面解析数据
  13. Glance 镜像服务
  14. java se运行环境_Java运行环境Java SE Runtime Environment (JRE) 下载
  15. java:JDBC的使用与封装
  16. 《笨方法学python》第三版 来自Percal25号行星的哥顿人
  17. 【计算机网络】因特网概述
  18. 量子计算 11 NSA的随机数阴谋
  19. 月入过万的虚拟项目?还不赶快进来一探究竟
  20. 2019数据结构考研(一)

热门文章

  1. A component required a bean of type ‘com.hao.mall.service.UserService‘ that could not be found.
  2. 20170213心情总结
  3. laravel 图像验证码 Gregwar\\Captcha 和 mews/captcha
  4. 科创板迎来首个云计算玩家,意味着什么?
  5. Selectsystem项目总结
  6. Black Screen of Life息屏软件汉化1.20
  7. 管理经济学基本概念(四): 定价策略、价格歧视等
  8. python 批量重命名数据集中的图片和标签
  9. Memory read error at 0xF8007080. AHB AP transaction error, DAP status f0000021
  10. mysql中的group变异_全基因组单核苷酸变异数据库建立