有需要帮忙代做51和32小车或者其他单片机项目,课程设计,报告,PCB原理图的小伙伴,可以在文章最下方加我V交流咨询,本篇文章的小车所有功能实现的代码还有硬件清单放在资源包里,有需要的自行下载即可!
目录
1.电机模块开发
1.1 让小车动起来
1.2 串口控制小车方向
1.3 如何进行小车PWM调速
1.4 PWM方式实现小车转向
2.循迹小车
2.1 循迹模块使用
2.2 循迹小车原理
2.3 循迹小车核心代码
2.4 循迹小车解决转弯平滑问题
3.跟随/避障小车
3.1 红外壁障模块分析编辑
3.2 跟随小车的原理
3.3 跟随小车开发和调试代码
3.4 超声波模块介绍
3.5 舵机模块介绍
3.6 摇头避障小车开发和调试代码
4.测速小车
4.1 测速模块
4.2 测试原理和单位换算
4.3 定时器和中断实现测速开发和调试代码
4.4 小车速度显示在OLED屏
5.远程控制小车
5.1 蓝牙控制小车
5.2 蓝牙控制并测速小车
5.3 wifi控制测速小车
5.4 4g控制小车
6.语音控制小车
6.1语音模块配置:
6.2 语音控制小车开发和调试代码
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
代码实现:
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); }
代码实现:
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; }
原理:
全速前进是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); }
右转原理: 左轮速度大于右轮
左转原理: 右轮速度大于左轮
左右轮各自调速代码实现:
// 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); }
接线方式
由于黑色具有较强的吸收能力,当循迹模块发射的红外线照射到黑线时,红外线将会被黑线吸收,导致 循迹模块上光敏三极管处于关闭状态,此时模块上一个LED熄灭。在没有检测到黑线时,模块上两个LED常亮
总结就是一句话,有感应到黑线,D0输出高电平 ,灭灯
硬件接线
代码示例:
#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(); }
原理:两轮都有速度且一轮速度大于另一轮
代码实现:
#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); } }
原理和循迹是一样的,循迹红外观朝下,跟随朝前
硬件接线
代码示例:
#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(); }
使用超声波模块,型号:HC-SR04
时序图:
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
硬件接线
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); }
封装超声波传感器
超声波模块接线:
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); }
测试数据通过串口发送到上位机
硬件接线
测速模块:
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);
OLED模块介绍:STM32 OLED屏幕显示详解
硬件接线
代码示例:
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; }
串口透传技术:
代码实现:
整合前面串口控制小车代码,接入蓝牙模块
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();
原理:运用上面讲到的蓝牙模块和测速模块,将两者代码整合
AT指令介绍:
硬件接线
使用方法:
Wifi模块-ESP-01s_esp01s波特率-CSDN博客
原理:运用EC03-DNC4G通信模块
模块介绍:
代码不做修改,直接基于蓝牙小车整合, 4g模块只要做好外网透传就可以了
使用SU-03T / LD3320
具体介绍看我之前写过的博客:SU-03T语音模块的使用_su-03t开发板语音指令-CSDN博客
硬件接线:
循迹小车:
跟随小车:
避障小车:
OLED模块:
语音模块:
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(); } } }