前言
有需要帮忙代做51和32小车或者其他单片机项目,课程设计,报告,pcb原理图的小伙伴,可以在文章最下方加我v交流咨询,本篇文章的小车所有功能实现的代码还有硬件清单放在资源包里,有需要的自行下载即可!
目录
1.电机模块开发
l9110s概述
接通vcc,gnd 模块电源指示灯亮, 以下资料来源官方,具体根据实际调试
ia1输入高电平,ia1输入低电平,【oa1 ob1】电机正转;
ia1输入低电平,ia1输入高电平,【oa1 ob1】电机反转;
ia2输入高电平,ia2输入低电平,【oa2 ob2】电机正转;
ia2输入低电平,ia2输入高电平,【oa2 ob2】电机反转;
接线参考:
b-1a -- pa0
b-1b -- pb1
a-1a -- pa1
a-1b -- pb10
1.1 让小车动起来
代码实现:
motor.c
#include "motor.h"
void goforward(void)
{
// 左轮
hal_gpio_writepin(gpiob, gpio_pin_2, gpio_pin_set);
hal_gpio_writepin(gpiob, gpio_pin_10, gpio_pin_reset);
// 右轮
hal_gpio_writepin(gpiob, gpio_pin_0, gpio_pin_set);
hal_gpio_writepin(gpiob, gpio_pin_1, gpio_pin_reset);
}
void goback(void)
{
// 左轮
hal_gpio_writepin(gpiob, gpio_pin_2, gpio_pin_reset);
hal_gpio_writepin(gpiob, gpio_pin_10, gpio_pin_set);
// 右轮
hal_gpio_writepin(gpiob, gpio_pin_0, gpio_pin_reset);
hal_gpio_writepin(gpiob, gpio_pin_1, gpio_pin_set);
}
void goleft(void)
{
// 左轮
hal_gpio_writepin(gpiob, gpio_pin_2, gpio_pin_reset);
hal_gpio_writepin(gpiob, gpio_pin_10, gpio_pin_reset);
// 右轮
hal_gpio_writepin(gpiob, gpio_pin_0, gpio_pin_set);
hal_gpio_writepin(gpiob, gpio_pin_1, gpio_pin_reset);
}
void goright(void)
{
// 左轮
hal_gpio_writepin(gpiob, gpio_pin_2, gpio_pin_set);
hal_gpio_writepin(gpiob, gpio_pin_10, gpio_pin_reset);
// 右轮
hal_gpio_writepin(gpiob, gpio_pin_0, gpio_pin_reset);
hal_gpio_writepin(gpiob, gpio_pin_1, gpio_pin_reset);
}
void stop(void)
{
// 左轮
hal_gpio_writepin(gpiob, gpio_pin_2, gpio_pin_set);
hal_gpio_writepin(gpiob, gpio_pin_10, gpio_pin_set);
// 右轮
hal_gpio_writepin(gpiob, gpio_pin_0, gpio_pin_reset);
hal_gpio_writepin(gpiob, gpio_pin_1, gpio_pin_reset);
}
motor.h
#ifndef __motor_h__
#define __motor_h__
#include "main.h"
void goforward(void);
void goback(void);
void goleft(void);
void goright(void);
void stop(void);
#endif
main.c
#include "motor.h"
//main函数的while循环部分:
while (1)
{
goforward();
hal_delay(1000);
goback();
hal_delay(1000);
goleft();
hal_delay(1000);
goright();
hal_delay(1000);
stop();
hal_delay(1000);
}
1.2 串口控制小车方向
- 串口分文件编程进行代码整合——通过现象来改代码
- 接入蓝牙模块,通过蓝牙控制小车
- 添加点动控制,如果app支持按下一直发数据,松开就停止发数据(蓝牙调试助手的自定义按键不 能实现),就能实现前进按键按下后小车一直往前走的功能
代码实现:
usart.c
#include "usart.h"
#include "string.h"
#include "stdio.h"
#include "motor.h"
//串口接收缓存(1字节)
uint8_t buf=0;
//定义最大接收字节数 200,可根据需求调整
#define uart1_rec_len 200
// 接收缓冲, 串口接收到的数据放在这个数组里,最大uart1_rec_len个字节
uint8_t uart1_rx_buffer[uart1_rec_len];
// 接收状态
// bit15, 接收完成标志
// bit14, 接收到0x0d
// bit13~0, 接收到的有效字节数目
uint16_t uart1_rx_sta=0;
#define size 12
char buffer[size];
// 接收完成回调函数,收到一个数据后,在这里处理
void hal_uart_rxcpltcallback(uart_handletypedef *huart)
{
// 判断中断是由哪个串口触发的
if(huart->instance == usart1)
{
// 判断接收是否完成(uart1_rx_sta bit15 位是否为1)
if((uart1_rx_sta & 0x8000) == 0)
{
// 如果已经收到了 0x0d (回车),
if(uart1_rx_sta & 0x4000)
{
// 则接着判断是否收到 0x0a (换行)
if(buf == 0x0a)
{
// 如果 0x0a 和 0x0d 都收到,则将 bit15 位置为1
uart1_rx_sta |= 0x8000;
// 灯控指令
if(!strcmp(uart1_rx_buffer, "m1"))
goforward();
else if(!strcmp(uart1_rx_buffer, "m2"))
goback();
else if(!strcmp(uart1_rx_buffer, "m3"))
goleft();
else if(!strcmp(uart1_rx_buffer, "m4"))
goright();
else
stop();
memset(uart1_rx_buffer, 0, uart1_rec_len);
uart1_rx_sta = 0;
}
else
// 否则认为接收错误,重新开始
uart1_rx_sta = 0;
}
else // 如果没有收到了 0x0d (回车)
{
//则先判断收到的这个字符是否是 0x0d (回车)
if(buf == 0x0d)
{
// 是的话则将 bit14 位置为1
uart1_rx_sta |= 0x4000;
}
else
{
// 否则将接收到的数据保存在缓存数组里
uart1_rx_buffer[uart1_rx_sta & 0x3fff] = buf;
uart1_rx_sta++;
// 如果接收数据大于uart1_rec_len(200字节),则重新开始接收
if(uart1_rx_sta > uart1_rec_len - 1)
uart1_rx_sta = 0;
}
}
}
// 重新开启中断
hal_uart_receive_it(&huart1, &buf, 1);
}
}
int fputc(int ch, file *f)
{
unsigned char temp[1]={ch};
hal_uart_transmit(&huart1,temp,1,0xffff);
return ch;
}
1.3 如何进行小车pwm调速
原理:
全速前进是leftcon1a = 0; leftcon1b = 1;
完全停止是leftcon1a = 0;leftcon1b = 0;
那么单位时间内,比如20ms, 有15ms是全速前进,5ms是完全停止, 速度就会比5ms全速前进,15ms完全停止获得的功率多,相应的速度更快!
开发:借用pwm的舵机控制代码
将控制车轮的4个 gpio 口配置修改如下,否则小车动不起来。
原因:l9110每个控制口需要一高一低才可以动起来,如果pwm有效电平为高电平,则另一个 gpio口则需要输出低电平才可以驱动轮子。
代码实现:
main.c
// main函数里
hal_tim_pwm_start(&htim2,tim_channel_1);
hal_tim_pwm_start(&htim2,tim_channel_2);
while (1)
{
__hal_tim_setcompare(&htim2, tim_channel_1, 8);
__hal_tim_setcompare(&htim2, tim_channel_2, 8);
hal_delay(1000);
__hal_tim_setcompare(&htim2, tim_channel_1, 10);
__hal_tim_setcompare(&htim2, tim_channel_2, 10);
hal_delay(1000);
__hal_tim_setcompare(&htim2, tim_channel_1, 15);
__hal_tim_setcompare(&htim2, tim_channel_2, 15);
hal_delay(1000);
}
1.4 pwm方式实现小车转向
右转原理: 左轮速度大于右轮
左转原理: 右轮速度大于左轮
左右轮各自调速代码实现:
// main函数里
while (1)
{
__hal_tim_setcompare(&htim2, tim_channel_1,8);
__hal_tim_setcompare(&htim2, tim_channel_2,15);
hal_delay(1000);
__hal_tim_setcompare(&htim2, tim_channel_1,15);
__hal_tim_setcompare(&htim2, tim_channel_2,8);
hal_delay(1000);
}
2.循迹小车
2.1 循迹模块介绍
- tcrt5000传感器的红外发射二极管不断发射红外线
- 当发射出的红外线没有被反射回来或被反射回来但强度不够大时
- 红外接收管一直处于关断状态,此时模块的输出端为高电平,指示二极管一直处于熄灭状态
- 被检测物体出现在检测范围内时,红外线被反射回来且强度足够大,红外接收管饱和
- 此时模块的输出端为低电平,指示二极管被点亮
- 总结就是一句话,没反射回来,d0输出高电平,灭灯
接线方式
- vcc:接电源正极(3-5v)
- gnd:接电源负极 do:ttl开关信号输出0、1
- ao:模拟信号输出(不同距离输出不同的电压,此脚一般可以不接)
2.2 循迹小车原理
由于黑色具有较强的吸收能力,当循迹模块发射的红外线照射到黑线时,红外线将会被黑线吸收,导致 循迹模块上光敏三极管处于关闭状态,此时模块上一个led熄灭。在没有检测到黑线时,模块上两个led常亮
总结就是一句话,有感应到黑线,d0输出高电平 ,灭灯
2.3 循迹小车核心代码
硬件接线
- b-1a -- pa0
- b-1b -- pb1
- a-1a -- pa1
- a-1b -- pb10
- 循迹模块(左)-- pb3
- 循迹模块(右) -- pb4
代码示例:
#define leftwheel_value hal_gpio_readpin(gpiob, gpio_pin_3)
#define rightwheel_value hal_gpio_readpin(gpiob, gpio_pin_4)
// main函数里
while (1)
{
if (leftwheel_value == gpio_pin_reset && rightwheel_value == gpio_pin_reset)
goforward();
if (leftwheel_value == gpio_pin_set && rightwheel_value == gpio_pin_reset)
goleft();
if (leftwheel_value == gpio_pin_reset && rightwheel_value == gpio_pin_set)
goright();
if (leftwheel_value == gpio_pin_set && rightwheel_value == gpio_pin_set)
stop();
}
2.4 循迹小车解决转弯平滑问题
原理:两轮都有速度且一轮速度大于另一轮
代码实现:
#define leftwheel_value hal_gpio_readpin(gpiob, gpio_pin_3)
#define rightwheel_value hal_gpio_readpin(gpiob, gpio_pin_4)
// main函数里
while (1)
{
if(leftwheel_value == gpio_pin_reset && rightwheel_value == gpio_pin_reset)
{
__hal_tim_setcompare(&htim2, tim_channel_1,19);
__hal_tim_setcompare(&htim2, tim_channel_2,19);
}
if(leftwheel_value == gpio_pin_set && rightwheel_value == gpio_pin_reset)
{
__hal_tim_setcompare(&htim2, tim_channel_1,15);
__hal_tim_setcompare(&htim2, tim_channel_2,8);
}
if(leftwheel_value == gpio_pin_reset && rightwheel_value == gpio_pin_set)
{
__hal_tim_setcompare(&htim2, tim_channel_1,8);
__hal_tim_setcompare(&htim2, tim_channel_2,15);
}
if(leftwheel_value == gpio_pin_set && rightwheel_value == gpio_pin_set)
{
__hal_tim_setcompare(&htim2, tim_channel_1,0);
__hal_tim_setcompare(&htim2, tim_channel_2,0);
}
}
3.跟随/避障小车
3.1 红外壁障模块分析
原理和循迹是一样的,循迹红外观朝下,跟随朝前
3.2 跟随小车的原理
- 左边跟随模块能返回红外,输出低电平,右边不能返回,输出高电平,说明物体在左边,需要左转
- 右边跟随模块能返回红外,输出低电平,左边不能返回,输出高电平,说明物体在右边,需要右转
3.3 跟随小车开发和调试代码
硬件接线
- b-1a -- pb0
- b-1b -- pb1
- a-1a -- pb2
- a-1b -- pb10
- 跟随模块(左) -- pb5
- 跟随模块(右) -- pb6
代码示例:
#define leftwheel_value hal_gpio_readpin(gpiob, gpio_pin_5)
#define rightwheel_value hal_gpio_readpin(gpiob, gpio_pin_6)
// main函数里
while (1)
{
if(leftwheel_value == gpio_pin_reset && rightwheel_value == gpio_pin_reset)
goforward();
if(leftwheel_value == gpio_pin_set && rightwheel_value == gpio_pin_reset)
goright();
if(leftwheel_value == gpio_pin_reset && rightwheel_value == gpio_pin_set)
goleft();
if(leftwheel_value == gpio_pin_set && rightwheel_value == gpio_pin_set)
stop();
}
3.4 超声波模块介绍
使用超声波模块,型号:hc-sr04
- 怎么让它发送波 trig ,给trig端口至少10us的高电平
- 怎么知道它开始发了 echo信号,由低电平跳转到高电平,表示开始发送波
- 怎么知道接收了返回波 echo,由高电平跳转回低电平,表示波回来了
- 怎么算时间 echo引脚维持高电平的时间! 波发出去的那一下,开始启动定时器 波回来的拿一下,我们开始停止定时器,计算出中间经过多少时间
- 怎么算距离 距离 = 速度 (340m/s)* 时间/2
时序图:
3.5 舵机模块介绍
1. 什么是舵机
如下图所示,最便宜的舵机sg90,常用三根或者四根接线,黄色为pwm信号控制 用处:垃圾桶项目开盖用、智能小车的全比例转向、摄像头云台、机械臂等 常见的有0-90°、0-180°、0-360°
2. 怎么控制舵机
向黄色信号线“灌入”pwm信号
pwm波的频率不能太高,大约50hz,即周期=1/频率=1/50=0.02s,20ms左右
确定周期/频率:
如果周期为20ms,则 psc=7199,arr=199
角度控制
0.5ms-------------0度; 2.5% 对应函数中ccrx为5
1.0ms------------45度; 5.0% 对应函数中ccrx为10
1.5ms------------90度; 7.5% 对应函数中ccrx为15
2.0ms-----------135度; 10.0% 对应函数中ccrx为20
2.5ms-----------180度; 12.5% 对应函数中ccrx为25
3.6 摇头避障小车开发和调试代码
硬件接线
- sg90 -- pb9
cubemx配置
代码实现
sg90.c
#include "sg90.h"
#include "gpio.h"
#include "tim.h"
void initsg90(void)
{
hal_tim_pwm_start(&htim4,tim_channel_4); //启动定时器4
__hal_tim_setcompare(&htim4, tim_channel_4, 17); //将舵机置为90度
}
void sgmiddle(void)
{
__hal_tim_setcompare(&htim4, tim_channel_4, 17); //将舵机置为90度
}
void sgright(void)
{
__hal_tim_setcompare(&htim4, tim_channel_4, 5); //将舵机置为0度
}
void sgleft(void)
{
__hal_tim_setcompare(&htim4, tim_channel_4, 25); //将舵机置为180度
}
sg90.h
#ifndef __sg90_h__
#define __sg90_h__
void initsg90(void);
void sgmiddle(void);
void sgright(void);
void sgleft(void);
#endif
main.c
initsg90();
hal_delay(1000);
while (1)
{
sgleft();
hal_delay(1000);
sgmiddle();
hal_delay(1000);
sgright();
hal_delay(1000);
sgmiddle();
hal_delay(1000);
}
封装超声波传感器
超声波模块接线:
- trig -- pb7
- echo -- pb8
cubemx配置
代码实现
sr04.c
#include "sr04.h"
#include "gpio.h"
#include "tim.h"
//使用tim2来做us级延时函数
void tim2_delay_us(uint16_t n_us)
{
/* 使能定时器2计数 */
__hal_tim_enable(&htim2);
__hal_tim_setcounter(&htim2, 0);
while(__hal_tim_getcounter(&htim2) < ((1 * n_us)-1) );
/* 关闭定时器2计数 */
__hal_tim_disable(&htim2);
}
double get_distance(void)
{
int cnt=0;
//1. trig ,给trig端口至少10us的高电平
hal_gpio_writepin(gpiob, gpio_pin_7, gpio_pin_set);//拉高
tim2_delay_us(20);
hal_gpio_writepin(gpiob, gpio_pin_7, gpio_pin_reset);//拉低
//2. echo由低电平跳转到高电平,表示开始发送波
//波发出去的那一下,开始启动定时器
while(hal_gpio_readpin(gpiob, gpio_pin_8) == gpio_pin_reset);//等待输入电平拉高
hal_tim_base_start(&htim2);
__hal_tim_setcounter(&htim2,0);
//3. 由高电平跳转回低电平,表示波回来了
while(hal_gpio_readpin(gpiob, gpio_pin_8) == gpio_pin_set);//等待输入电平变低
//波回来的那一下,我们开始停止定时器
hal_tim_base_stop(&htim2);
//4. 计算出中间经过多少时间
cnt = __hal_tim_getcounter(&htim2);
//5. 距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
return (cnt*340/2*0.000001*100); //单位:cm
}
sr04.h
#ifndef __sr04_h__
#define __sr04_h__
double get_distance(void);
#endif
main.c
while (1)
{
if(dir != middle){
sgmiddle();
dir = middle;
hal_delay(300);
}
dismiddle = get_distance();
if(dismiddle > 35){
//前进
}
else
{
//停止
//测左边距离
sgleft();
hal_delay(300);
disleft = get_distance();
sgmiddle();
hal_delay(300);
sgright();
dir = right;
hal_delay(300);
disright = get_distance();
}
}
封装电机驱动
代码实现:
while (1)
{
if(dir != middle){
sgmiddle();
dir = middle;
hal_delay(300);
}
dismiddle = get_distance();
if(dismiddle > 35){
//前进
goforward();
}else if(dismiddle < 10){
goback();
}else
{
//停止
stop();
//测左边距离
sgleft();
hal_delay(300);
disleft = get_distance();
sgmiddle();
hal_delay(300);
sgright();
dir = right;
hal_delay(300);
disright = get_distance();
if(disleft < disright){
goright();
hal_delay(150);
stop();
}
if(disright < disleft){
goleft();
hal_delay(150);
stop();
}
}
hal_delay(50);
}
4.测速小车
4.1 测速模块
- 用途:广泛用于电机转速检测,脉冲计数,位置限位等。
- 有遮挡,输出高电平;无遮挡,输出低电平
- 接线 :vcc 接电源正极3.3-5v
- gnd 接电源负极 do ttl开关信号输出
- ao 此模块不起作用
4.2 测试原理和单位换算
- 轮子走一圈,经过一个周长,c = 2x3.14x半径= 3.14 x 直径(6.5cm)
- 对应的码盘也转了一圈,码盘有20个格子,每经过一个格子,会遮挡(高电平)和不遮挡(低电平), 那么一个脉冲就是走了 3.14 * 6.5 cm /20 = 1.0205cm
- 定时器可以设计成一秒,统计脉冲数,一个脉冲就是1cm
- 假设一秒有80脉冲,那么就是80cm/s
4.3 定时器和中断实现测速开发和调试代码
测试数据通过串口发送到上位机
硬件接线
测速模块:
- vcc -- 3.3v 不能接5v,否则遮挡一次会触发3次中断
- out -- pb14
cubemx配置
代码实现:
unsigned int speedcnt;
void hal_gpio_exti_callback(uint16_t gpio_pin)
{
if (gpio_pin == gpio_pin_14)
if (hal_gpio_readpin(gpiob, gpio_pin_14) == gpio_pin_reset)
speedcnt++;
}
void hal_tim_periodelapsedcallback(tim_handletypedef *htim)
{
printf("speed: %d\r\n", speedcnt);
speedcnt = 0;
}
main函数里:
hal_tim_base_start_it(&htim2);
4.4 小车速度显示在oled屏
oled模块介绍:stm32 oled屏幕显示详解
硬件接线
- scl -- pb6
- sda -- pb7
代码示例:
oled.c
#include "oled.h"
#include "i2c.h"
#include "oledfont.h"
void oled_write_cmd(uint8_t datacmd)
{
hal_i2c_mem_write(&hi2c1, 0x78, 0x00, i2c_memadd_size_8bit,
&datacmd, 1, 0xff);
}
void oled_write_data(uint8_t datadata)
{
hal_i2c_mem_write(&hi2c1, 0x78, 0x40, i2c_memadd_size_8bit,
&datadata, 1, 0xff);
}
void oled_init(void){
oled_write_cmd(0xae);//--display off
oled_write_cmd(0x00);//---set low column address
oled_write_cmd(0x10);//---set high column address
oled_write_cmd(0x40);//--set start line address
oled_write_cmd(0xb0);//--set page address
oled_write_cmd(0x81); // contract control
oled_write_cmd(0xff);//--128
oled_write_cmd(0xa1);//set segment remap
oled_write_cmd(0xa6);//--normal / reverse
oled_write_cmd(0xa8);//--set multiplex ratio(1 to 64)
oled_write_cmd(0x3f);//--1/32 duty
oled_write_cmd(0xc8);//com scan direction
oled_write_cmd(0xd3);//-set display offset
oled_write_cmd(0x00);//
oled_write_cmd(0xd5);//set osc division
oled_write_cmd(0x80);//
oled_write_cmd(0xd8);//set area color mode off
oled_write_cmd(0x05);//
oled_write_cmd(0xd9);//set pre-charge period
oled_write_cmd(0xf1);//
oled_write_cmd(0xda);//set com pin configuartion
oled_write_cmd(0x12);//
oled_write_cmd(0xdb);//set vcomh
oled_write_cmd(0x30);//
oled_write_cmd(0x8d);//set charge pump enable
oled_write_cmd(0x14);//
oled_write_cmd(0xaf);//--turn on oled panel
}
void oled_screen_clear(void){
char i,n;
oled_write_cmd (0x20); //set memory addressing mode
oled_write_cmd (0x02); //page addressing mode
for(i=0;i<8;i++){
oled_write_cmd(0xb0+i);
oled_write_cmd(0x00);
oled_write_cmd(0x10);
for(n=0;n<128;n++)oled_write_data(0x00);
}
}
void oled_show_char(char row,char col,char oledchar){ //row*2-2
unsigned int i;
oled_write_cmd(0xb0+(row*2-2)); //page 0
oled_write_cmd(0x00+(col&0x0f)); //low
oled_write_cmd(0x10+(col>>4)); //high
for(i=((oledchar-32)*16);i<((oledchar-32)*16+8);i++){
oled_write_data(f8x16[i]); //写数据oledtable1
}
oled_write_cmd(0xb0+(row*2-1)); //page 1
oled_write_cmd(0x00+(col&0x0f)); //low
oled_write_cmd(0x10+(col>>4)); //high
for(i=((oledchar-32)*16+8);i<((oledchar-32)*16+8+8);i++){
oled_write_data(f8x16[i]); //写数据oledtable1
}
}
/******************************************************************************/
// 函数名称:oled_show_char
// 输入参数:oledchar
// 输出参数:无
// 函数功能:oled显示单个字符
/******************************************************************************/
void oled_show_str(char row,char col,char *str){
while(*str!=0){
oled_show_char(row,col,*str);
str++;
col += 8;
}
}
main.c
extern uint8_t buf;
unsigned int speedcnt = 0;
char speedmes[24]; //主程序发送速度数据的字符串缓冲区
void hal_gpio_exti_callback(uint16_t gpio_pin)
{
if (gpio_pin == gpio_pin_14)
if (hal_gpio_readpin(gpiob, gpio_pin_14) == gpio_pin_reset)
speedcnt++;
}
void hal_tim_periodelapsedcallback(tim_handletypedef *htim)
{
printf("speed: %d\r\n", speedcnt);
sprintf(speedmes,"speed:%2d cm/s",speedcnt);//串口数据的字符串拼装,speed是格子,每个格子1cm
oled_show_str(2,2,speedmes);
speedcnt = 0;
}
5.远程控制小车
5.1 蓝牙控制小车
- 使用蓝牙模块,串口透传
- 蓝牙模块,又叫做蓝牙串口模块
串口透传技术:
- 透传即透明传送,是指在数据的传输过程中,通过无线的方式这组数据不发生任何形式的改变,仿 佛传输过程是透明的一样,同时保证传输的质量,原封不动地到了最终接收者手里。
- 以太网,蓝牙,zigbee, gprs 等模块玩法一样,对嵌入式程序员来说,不需要关心通讯模块内部数据 及协议栈工作原理,只要通过串口编程获得数据即可
代码实现:
整合前面串口控制小车代码,接入蓝牙模块
if (!strcmp(uart1_rx_buffer, "m1"))
{
goforward();
hal_delay(10);
}
else if (!strcmp(uart1_rx_buffer, "m2"))
{
goback();
hal_delay(10);
}
else if (!strcmp(uart1_rx_buffer, "m3"))
{
goleft();
hal_delay(10);
}
else if (!strcmp(uart1_rx_buffer, "m4"))
{
goright();
hal_delay(10);
}
else
stop();
5.2 蓝牙控制并测速小车
原理:运用上面讲到的蓝牙模块和测速模块,将两者代码整合
5.3 wifi控制测速小车
- wifi模块-esp-01s
- 蓝牙,esp-01s,zigbee, nb-iot等通信模块都是基于at指令的设计
at指令介绍:
- at指令集是从终端设备(terminal equipment,te)或数据终端设备(data terminal equipment,dte)向终端适配器(terminal adapter,ta)或数据电路终端设备(data circuit terminal equipment,dce)发送的。
- 其对所传输的数据包大小有定义:即对于at指令的发送,除at两个字符外,最多可以接收1056个 字符的长度(包括最后的空字符)。
- 每个at命令行中只能包含一条at指令;对于由终端设备主动向pc端报告的urc指示或者response 响应,也要求一行最多有一个,不允许上报的一行中有多条指示或者响应。at指令以回车作为结 尾,响应或上报以回车换行为结尾。
硬件接线
- 把esp8266插进串口1
使用方法:
wifi模块-esp-01s_esp01s波特率-csdn博客
5.4 4g控制小车
原理:运用ec03-dnc4g通信模块
模块介绍:
- 基于串口at指令的开发方式
- 有两种工作模式,默认是透传模式,通过其他方式进入at指令模式
- 注意插卡不要出错,下图红色位置为sim卡状态灯,亮才是正常
代码不做修改,直接基于蓝牙小车整合, 4g模块只要做好外网透传就可以了
6.语音控制小车
6.1语音模块配置:
使用su-03t / ld3320
具体介绍看我之前写过的博客:su-03t语音模块的使用_su-03t开发板语音指令-csdn博客
6.2 语音控制小车开发和调试代码
硬件接线:
循迹小车:
- 循迹模块(左) -- pb3
- 循迹模块(右) -- pb4
跟随小车:
- 跟随模块(左) -- pa8
- 跟随模块(右) -- pa9
避障小车:
- sg90:pb9
- trig:pa10
- echo:pa11
oled模块:
- scl -- pb6
- sda -- pb7
语音模块:
- a25 -- pa15 (跟随)
- a26 -- pa13 (避障)
- a27 -- pa14 (循迹)
cubemx配置
代码示例:
#include "main.h"
#include "i2c.h"
#include "tim.h"
#include "gpio.h"
#include "sg90.h"
#include "sr04.h"
#include "motor.h"
#include "oled.h"
#define middle 0
#define left 1
#define right 2
#define bz 1
#define xj 2
#define gs 3
#define leftwheel_value_xj hal_gpio_readpin(gpiob, gpio_pin_3)
#define rightwheel_value_xj hal_gpio_readpin(gpiob, gpio_pin_4)
#define leftwheel_value_gs hal_gpio_readpin(gpioa, gpio_pin_8)
#define rightwheel_value_gs hal_gpio_readpin(gpioa, gpio_pin_9)
#define a25 hal_gpio_readpin(gpioa, gpio_pin_15)
#define a26 hal_gpio_readpin(gpioa, gpio_pin_13)
#define a27 hal_gpio_readpin(gpioa, gpio_pin_14)
void systemclock_config(void);
char dir;
void xunjimode()
{
if(leftwheel_value_xj == gpio_pin_reset && rightwheel_value_xj == gpio_pin_reset)
goforward();
if(leftwheel_value_xj == gpio_pin_set && rightwheel_value_xj == gpio_pin_reset)
goleft();
if(leftwheel_value_xj == gpio_pin_reset && rightwheel_value_xj == gpio_pin_set)
goright();
if(leftwheel_value_xj == gpio_pin_set && rightwheel_value_xj == gpio_pin_set)
stop();
}
void gensuimode()
{
if(leftwheel_value_gs == gpio_pin_reset && rightwheel_value_gs == gpio_pin_reset)
goforward();
if(leftwheel_value_gs == gpio_pin_set && rightwheel_value_gs == gpio_pin_reset)
goright();
if(leftwheel_value_gs == gpio_pin_reset && rightwheel_value_gs == gpio_pin_set)
goleft();
if(leftwheel_value_gs == gpio_pin_set && rightwheel_value_gs == gpio_pin_set)
stop();
}
void bizhangmode()
{
double dismiddle;
double disleft;
double disright;
if(dir != middle){
sgmiddle();
dir = middle;
hal_delay(300);
}
dismiddle = get_distance();
if(dismiddle > 35){
//前进
goforward();
}else if(dismiddle < 10){
goback();
}else
{
//停止
stop();
//测左边距离
sgleft();
hal_delay(300);
disleft = get_distance();
sgmiddle();
hal_delay(300);
sgright();
dir = right;
hal_delay(300);
disright = get_distance();
if(disleft < disright){
goright();
hal_delay(150);
stop();
}
if(disright < disleft){
goleft();
hal_delay(150);
stop();
}
}
hal_delay(50);
}
int main(void)
{
int mark = 0;
hal_init();
systemclock_config();
mx_gpio_init();
mx_tim4_init();
mx_tim2_init();
mx_i2c1_init();
initsg90();
hal_delay(1000);
dir = middle;
oled_init();
oled_screen_clear();
oled_show_str(2,2,"-----ready----");
while (1)
{
//满足寻迹模式的条件
if(a25 == 1 && a26 == 1 && a27 == 0){
if(mark != xj){
oled_screen_clear();
oled_show_str(2,2,"-----xunji----");
}
mark = xj;
xunjimode();
}
//满足跟随模式的条件
if(a25 == 0 && a26 == 1 && a27 == 1){
if(mark != gs){
oled_screen_clear();
oled_show_str(2,2,"-----gensui----");
}
mark = gs;
gensuimode();
}
//满足避障模式的条件
if(a25 == 1 && a26 == 0 && a27 == 1){
if(mark != bz){
oled_screen_clear();
oled_show_str(2,2,"-----bizhang----");
}
mark = bz;
bizhangmode();
}
}
}
发表评论