考虑到大部分学校,会发放简易小车来作为智能车初期培训和筛选的工具,
于是,我写一个简单的教程,能够实现简单小车的电磁循迹。
通过这个教程,能够通过简化的步骤搭建寻迹小车,进而了解整个智能车是如何实现的,快速上手,为后续参与智能车竞赛做准备。
这里我不会讲解原理,直接手把手带着使用,需要看原理的时候就看我相关博客。
目录
一、准备
C语言
单片机
二、器件
三、安装编程环境软件KEIL
1.安装KEIL
2.激活License
3.安装pack包
四、下载逐飞开源库
五、测试器件
电机转
屏幕
ADC
六、装车
七、循迹
电机
循迹
一、准备
C语言
智能车入门——编程语言(c)的学习
智能车入门补充篇——模块化编程
首先要有一定的C语言基础。
想要学好嵌入式,C语言必须学会!
这里一定不要为了进度图快,打好基础很重要。当时带我们的学长,给了我们一周的时间让我们复习C语言。
推荐平台:
菜鸟教程 - 学的不仅是技术,更是梦想!
郝斌C语言
下面必须要掌握:
初学阶段要学会掌握基本的概念、函数、数组、语法关键词if,for,while的使用即可,指针与结构体部分可以在后期再进行补充学习。
这虽然就两行字,但是一定要扎实,好好打好基础,数据类型、运算符号都要会,别到时候用除法打了个"\"还不知道哪里错了。uint=unsigned int这种小知识别漏了。
单片机
需要简单了解一下什么是单片机,起码知道什么是IO口。
智能车入门——I/O、PWM
推荐学习平台:
51单片机普中科技视频完整版0基础入门学习_哔哩哔哩_bilibili
51单片机入门教程-2020版 程序全程纯手打 从零开始入门_哔哩哔哩_bilibili
最低的要求是跟着教程,能够点亮LED灯。
二、器件
一个舵机将近100块,一个摄像头得两三百,大部分学校选拔应该会选用这种廉价的小车,靠电机实现前进和转向。
那么我就拿这种最简单的小车举例,介绍循迹最起码有的器件:
单片机(一般是STC)
电源(电池),
电机驱动(一般练手用的是L298N),
电机(小马达)、轱辘,
还有传感器,光电循迹用光电传感器,电磁循迹用电容电感对+运放
如果硬件给力点,还会有主板将前面的接口合并到一个板子上
为了方便看参数,还会有屏幕。
三、安装编程环境软件KEIL
Keil C51是美国Keil软件公司(现已被ARM公司收购)出品的支持8051系列单片机架构的一款 IDE
【精选】智能车入门——IDE安装以及库函数选用
STC8系列 MDK FOR C51 IDE软件
链接:https://pan.baidu.com/s/10eqOQOFn7JapLJ_1Wc_DTQ 提取码:aom2
STC16专用 MDK FOR C251 IDE软件:链接:https://pan.baidu.com/s/1euVGEsRCV_novTHqnhQD7Q 提取码:krw6
需要这三个文件,MDK532是keil的安装文件,keygen是破解软件,C51V960a是C51的pack包
1.安装KEIL
首先点击运行mdk532.exe文件
然后一路Next
路径自己选,name随便填
2.激活License
(1)右击图标,用管理员身份运行!
(2)把ID复制下来
(3)把电脑静音
(4)右击keygen_new2032,用管理员身份运行
把ID粘贴进去,
Target这里,STC8选C51,STC32选C251
不知道自己手里的该装哪个,你就百度或者问卖板子的客服
下面的选prof....PLUS
点击Generate,生成激活码
(5)打开KEIL复制生成的激活码,粘贴在New License ID Code处,点击Add LIC,即可成功激活mdk,显示mdk的使用期限2032年
3.安装pack包
双击c51v960a.exe,一路next。
这里pack包需要与自己的单片机相匹配,没有pack包的话,向卖板子的客服要就行了。
四、下载逐飞开源库
智能车入门——库函数选用
找到自己的型号下载
SeekFree (seekfree) - Gitee.com
复制Seekfree_XXXXXXX_Opensource_Library文件夹,在此基础上增添代码,最后放到中文路径。
Seekfree_STC8A8K64S4_Opensource_Library\Project\MDK
双击该路径下的SEEKFREE.uvproj文件,即可打开工程
五、测试器件
首先写代码,看自己能不能调用那些器件。
【逐飞科技】STC8G2K 核心板与智能车常用模块搭配使用视频教程_哔哩哔哩_bilibili
【精选】智能车入门——简单驱动常用模块
电机转
电机驱动有两种
一种是两路PWM,另一种是一路PWM,一路 GPIO。
两路PWM,就是根据两个pwm信号 差值的正负决定电机转动方向,差值大小决定电机转速,
一路PWM,一路 GPIO,就是pwm控制转速,GPIO控制方向。
想知道你手上的驱动属于哪一种,你就淘宝扫一扫识图,看哪家店卖的一模一样,然后看商品介绍。
以一路PWM,一路 GPIO举例:
#include "headfile.h"
uint16 duty = 7000;
void main()
{
DisableGlobalIRQ(); //¹Ø±Õ×ÜÖжÏ
board_init();
pwm_init(PWM5_P25, 10000, 9500);
EnableGlobalIRQ(); //¿ªÆô×ÜÖжÏ
while(1)
{
pwm_duty(PWM5_P25,duty);
gpio_pull_set(P2_6, 0);
}
}
这就实现了让一个电机固定转速转。
接下来测试整个驱动好不好使
#include "My.h"
void pwm_duty_init()
{
pwm_init(PWM3_P63,17000,0);
pwm_init(PWM4_P64,17000,0);
}
/****************************************************************
电机驱动测试
12假设2路pwm的正反转
34假设64口控制方向的正反转(1个PWM,1控制方向)
56假设63口控制方向的正反转(1个PWM,1控制方向)
****************************************************************/
void mitor_duty(char mode)
{
if(mode==1)
{
pwm_duty(PWM3_P63,0);
pwm_duty(PWM4_P64,800);
}
if(mode==2)
{
pwm_duty(PWM3_P63,800);
pwm_duty(PWM4_P64,0);
}
if(mode==3)
{
pwm_duty(PWM3_P63,800);
pwm_duty(PWM4_P64,0);
}
if(mode==4)
{
pwm_duty(PWM3_P63,800);
pwm_duty(PWM4_P64,1000);
}
if(mode==5)
{
pwm_duty(PWM3_P63,0);
pwm_duty(PWM4_P64,800);
}
if(mode==6)
{
pwm_duty(PWM3_P63,1000);
pwm_duty(PWM4_P64,800);
}
}
#ifndef __MY_H_
#define __MY_H_
#include "headfile.h"
void pwm_duty_init();
void mitor_duty(char mode);
#endif
屏幕
下面是常见三款屏幕,同样的,不知道什么型号就淘宝搜,不会接线就问客服。
我以1.8TFT举例:
首先去淘宝搜到这个型号屏幕,在商品详情页可以看到引脚名称
在 seekfree_peripheral文件夹下找到屏幕对应的文件
首先打开18TFT.h文件找到接线定义:
接线定义:
------------------------------------
模块管脚 单片机管脚
SCL 查看TFT_SCL_PIN 宏定义的引脚 硬件SPI引脚不可随意切换
SDA 查看TFT_SDA_PIN 宏定义的引脚 硬件SPI引脚不可随意切换
RES 查看REST_PIN 宏定义的引脚
DC 查看DC_PIN_PIN 宏定义的引脚
CS 查看TFT_CS_PIN 宏定义的引脚
电源引脚
BL 3.3V电源(背光控制引脚,也可以接PWM来控制亮度)
VCC 3.3V电源
GND 电源地
最大分辨率128*160
------------------------------------
//--------------------软件SPI--------------------
#define TFT_SCL_SIMSPI_PIN P25 //定义SPI_SCK引脚
#define TFT_SDA_SIMSPI_PIN P23 //定义SPI_MOSI引脚
#define TFT_REST_SIMSPI_PIN P20 //定义复位引脚
#define TFT_DC_SIMSPI_PIN P21 //液晶命令位引脚定义
#define TFT_CS_SIMSPI_PIN P22 //定义SPI_CS引脚
#define TFT_BL_SIMSPI_PIN P24 //液晶背光引脚定义//--------------------硬件SPI--------------------
#define TFT_SPIN SPI_2 //定义使用的SPI号
#define TFT_SCL_PIN SPI2_SCLK_P25 //定义SPI_SCK引脚
#define TFT_SDA_PIN SPI2_MOSI_P23 //定义SPI_MOSI引脚
#define TFT_SDA_IN_PIN SPI2_MISO_P24 //定义SPI_MISO引脚 TFT屏幕没有MISO引脚,但是这里任然需要定义,在spi的初始化时需要使用#define TFT_REST_PIN P20
#define TFT_DC_PIN P21
#define TFT_CS_PIN P22 //定义SPI_CS引脚
#define TFT_BL_PIN P24
根据接线定义去接线,硬件SPI、软件SPI根据喜好去选就行了。
函数有这些:
//--------------------Ó²¼þSPI--------------------
void lcd_init(void);
void lcd_clear(int color);
void lcd_drawpoint(uint16 x,uint16 y,uint16 color);
void lcd_showchar(uint16 x,uint16 y,uint8 dat);
void lcd_showstr(uint16 x,uint16 y,uint8 dat[]);
void lcd_showint8(uint16 x,uint16 y,int8 dat);
void lcd_showuint8(uint16 x,uint16 y,uint8 dat);
void lcd_showint16(uint16 x,uint16 y,int16 dat);
void lcd_showuint16(uint16 x,uint16 y,uint16 dat);
void lcd_showint32(uint16 x,uint16 y,int32 dat,uint8 num);
void lcd_showfloat(uint16 x,uint16 y,double dat,uint8 num,uint8 pointnum);
void showimage(const unsigned char *p);
然后初始化、调用代码就行了
/*********************************************************************************************************************
* COPYRIGHT NOTICE
* Copyright (c) 2020,逐飞科技
* All rights reserved.
* 技术讨论QQ群:一群:179029047(已满) 二群:244861897(已满) 三群:824575535
*
* 以下所有内容版权均属逐飞科技所有,未经允许不得用于商业用途,
* 欢迎各位使用并传播本程序,修改内容时必须保留逐飞科技的版权声明。
*
* @file main
* @company 成都逐飞科技有限公司
* @author 逐飞科技(QQ790875685)
* @version 查看doc内version文件 版本说明
* @Software MDK FOR C51 V9.60
* @Target core STC8A8K64S4
* @Taobao https://seekfree.taobao.com/
* @date 2020-5-13
********************************************************************************************************************/
#include "headfile.h"
board.h文件中FOSC的值设置为0,则程序自动识别系统频率
///*board.h文件中FOSC的值设置不为0,则系统频率为FOSC的值,
//在使用stc-isp工具下载程序的时候需要将IRC频率设置为FOSC的值*/
void main()
{
DisableGlobalIRQ(); //关闭总中断
board_init(); //初始化内部寄存器,勿删除此句代码。
lcd_init();
//此处编写用户代码(例如:外设初始化代码等)
EnableGlobalIRQ(); //开启总中断
while(1)
{
//此处编写需要循环执行的代码
// lcd_showstr(0,0,"lucky");
// pca_delay_ms(1000);
lcd_showchar(0,0,'x');//坐标0,0写一个字符x
}
}
ADC
同样的运放,哪里弄得,从哪里获取资料
最简单的循迹只需要2个电感电容对,按照下面的接线就行
将采集到的电感值显示到屏幕上
/*********************************************************************************************************************
* COPYRIGHT NOTICE
* Copyright (c) 2020,逐飞科技
* All rights reserved.
* 技术讨论QQ群:一群:179029047(已满) 二群:244861897(已满) 三群:824575535
*
* 以下所有内容版权均属逐飞科技所有,未经允许不得用于商业用途,
* 欢迎各位使用并传播本程序,修改内容时必须保留逐飞科技的版权声明。
*
* @file main
* @company 成都逐飞科技有限公司
* @author 逐飞科技(QQ790875685)
* @version 查看doc内version文件 版本说明
* @Software MDK FOR C51 V9.60
* @Target core STC8A8K64S4
* @Taobao https://seekfree.taobao.com/
* @date 2020-5-13
********************************************************************************************************************/
#include "headfile.h"
board.h文件中FOSC的值设置为0,则程序自动识别系统频率
///*board.h文件中FOSC的值设置不为0,则系统频率为FOSC的值,
//在使用stc-isp工具下载程序的时候需要将IRC频率设置为FOSC的值*/
void main()
{
DisableGlobalIRQ(); //关闭总中断
board_init(); //初始化内部寄存器,勿删除此句代码。
lcd_init();
adc_init(ADC_P01,ADC_SYSclk_DIV_2); //
adc_init(ADC_P02,ADC_SYSclk_DIV_2); //
//此处编写用户代码(例如:外设初始化代码等)
EnableGlobalIRQ(); //开启总中断
while(1)
{
//此处编写需要循环执行的代码
lcd_showuint16(2,2,adc_once(ADC_P01, ADC_10BIT) );
lcd_showuint16(3,3,adc_once(ADC_P02, ADC_10BIT) );
}
}
六、装车
七、循迹
智能车入门——跑车前的零碎知识
智能车入门补充篇——电感值处理、转向控制与巡线
智能车入门——电磁循迹原理与实现
电机
#include "dianji.h"
// 电机初始化
void dianji_init()
{
pwm_init(PWM3_P63,17000,0); //IN1 右
pwm_init(PWM4_P64,17000,0); //IN2 右 +前
pwm_init(PWM5_P65,17000,0); //IN3 左 +前
pwm_init(PWM6_P66,17000,0); //IN4 左
}
//驱动电机
void dianji_Control(int32 LDuty, int32 RDuty)
{
if(LDuty > 0) //左正
{
pwm_duty(PWM5_P65, LDuty);
pwm_duty(PWM6_P66, 0);
}
if(LDuty < 0) //左反
{
pwm_duty(PWM5_P65, 0);
pwm_duty(PWM6_P66, LDuty);
}
if(RDuty > 0) //右正
{
pwm_duty(PWM3_P63, 0);
pwm_duty(PWM4_P64, RDuty);
}
if(RDuty < 0) //右反
{
pwm_duty(PWM3_P63, RDuty);
pwm_duty(PWM4_P64, 0);
}
if(LDuty == 0)
{
pwm_duty(PWM3_P63, 0);
pwm_duty(PWM4_P64, 0);
}
if(RDuty == 0)
{
pwm_duty(PWM5_P65, 0);
pwm_duty(PWM6_P66, 0);
}
}
//限幅保护
int32 range_protect(int32 duty, int32 min, int32 max)
{
if (duty >= max)
{
return max;
}
if (duty <= min)
{
return min;
}
else
{
return duty;
}
}
#ifndef __dianji_H__
#define __dianji_H__
#include "headfile.h"
int32 range_protect(int32 duty, int32 min, int32 max);//限幅保护
void dianji_init();
void dianji_Control(int32 LDuty, int32 RDuty);
#endif
循迹
我找的小车,循迹只能靠电机的差速,由于这种小车速度很慢,因此,只需要偏差乘一个比例系数就能简单循迹,相当于PID中只给P系数,I、D的值为0.
首先初始化各个器件
void all_init()
{
adc_init(ADC_P01,ADC_SYSclk_DIV_2); //³õʼ»¯P1.0ΪADC¹¦ÄÜ,ADCʱÖÓƵÂÊ£ºSYSclk/2
adc_init(ADC_P02,ADC_SYSclk_DIV_2); //³õʼ»¯P1.0ΪADC¹¦ÄÜ,ADCʱÖÓƵÂÊ£ºSYSclk/2
dianji_init(); //µç»ú³õʼ»¯
lcd_init(); //ÆÁÄ»³õʼ»¯
pd_init();
}
获取ADC
void adc_collect()
{
adc1=adc_once(ADC_P01, ADC_10BIT);
adc4=adc_once(ADC_P02, ADC_10BIT);
}
差速循迹
float kp=1.2;
now_error = adc1-adc4;
output=kp*now_error
LeftDuty =600-output;
RightDuty=600+output;
LeftDuty = range_protect( LeftDuty,-200, 1000);
RightDuty= range_protect(RightDuty,-200, 1000);
dianji_Control(LeftDuty,RightDuty);
我会贴上完整代码,用来参考。
举一反三,如果要用到按键、舵机、陀螺仪等也是同样的步骤。