一、前置准备
前置知识:需要学习stm32,建议去b站看江科大的视频,讲的很详细,学完串口那一块就可以制作了,软件用的是Keil5,开发语言C语言,手机连接蓝牙模块软件是蓝牙调试器。
需要准备的器件:小车底盘,面包板,stm32f103c8t6,电机驱动模块(tb6612)、蓝牙模块(hc06)、超声波测距模块(HC-SR04)、红外寻迹模块(TCRT5000)、舵机(sg90)、杜邦线若干、电源模块(可以换成充电宝,用5伏那一口)、黑色胶布(用于制作轨迹)、超声波测距模块云台。
二、演示
寻迹演示
基于STM32制作智能小车
自动避障(忘记录了后续补上)
三、功能实现
1、接线图
2、引脚定义表
3、PWM驱动电机旋转
3.1、让一个轮子转起来
电机旋转就是我们小车轮子旋转了,我们先看看然后让一个轮子转起来。
电机驱动的PWMA接PA1口,AIN2与AIN1接PA5与PA4口,根据定义表中,我们要使用定时器(TIM) 2的通道(Channel) 2,所以初始化代码是。
3.2、代码实现
void PWM_Init(void)
{
/*GPIO重映射*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_Cmd(TIM2, ENABLE);
}
设置CCR代码
void PWM_SetCompare(uint8_t Num,uint16_t Compare)
{
if(Num == 2)
{
TIM_SetCompare1(TIM2, Compare); // 使用通道2
}
else if(Num == 3)
{
TIM_SetCompare2(TIM2, Compare); // 使用通道3
}else if(Num == 4)
{
TIM_SetCompare4(TIM2, Compare); // 使用通道4
}
}
电机驱动代码
思路:使用PA4,与PA5口,对GPIO进行初始化,对于void Motor_SetSpeed(int8_t Speed),当速度大于0正转,小于0反转,对4口5口分别设置高低电平,并且调用PWM_SetCompare3(),修改CCR的值,也就是转速(TIM_OCInitStructure.TIM_Pulse = 0;)。
void Motor_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // GPIO_Mode_Out_PP: GPIO引脚在该模式下可以输出高或低电平,而不会受到其他引脚的影响。
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
PWM_Init();
}
void Motor_SetSpeed(int8_t Speed)
{
if(Speed >= 0)
{
GPIO_SetBits(GPIOA, GPIO_Pin_4);
GPIO_ResetBits(GPIOA, GPIO_Pin_5);
PWM_SetCompare3(Speed);
}else
{
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
GPIO_SetBits(GPIOA, GPIO_Pin_5);
PWM_SetCompare3(-Speed);
}
}
主函数
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "Key.h"
int main(void)
{
Motor_Init(); //直流电机初始化
Motor_SetSpeed(30);
while (1)
{
}
}
3.2、让四个轮子转起来
这时,电机就转起来了。
提问:这样就能让一个轮子转起来,那我cv 4份,就能都转起来,即简单又方便,我太聪明了,hhh~
答:这样做肯定不对的,如何实现请看思路。
思路:我们可以使用PWMA控制左边两个轮子,PWMB控制右边两个轮子,当然下图知识作为参考,可以自行脑补。
可以仔细看看下面四图。我们让PWMA控制左边的轮子,可以看看第二张图的接线,将左边的电机正负极接到AO1、AO2上面;PWMB控制右边的轮子,将右边的电机正负极接到BO1、BO2上面。
注意:当正负极接反时,电机会反转,当按下前进按钮,三个轮子前进,一个轮子后退,这个肯定不是我们想要的,所以,这里接线的时候注意下!
这时我们的线就接好了,我们来看看代码是如何实现的。
3.4、代码实现
思路:这里使用pa4、pa5、pa6、pa7 做控制四个电机,根据Aspet的值控制左边与右边的轮子
void Motor_SetSpeed(unsigned char Aspet,int8_t Speed)
{
if(Aspet == 1)
{
if(Speed > 0)
{
GPIO_SetBits(GPIOA, GPIO_Pin_6);
GPIO_ResetBits(GPIOA, GPIO_Pin_7);
PWM_SetCompare(3,Speed);
}else
{
GPIO_ResetBits(GPIOA, GPIO_Pin_6);
GPIO_SetBits(GPIOA, GPIO_Pin_7);
PWM_SetCompare(3,-Speed);
}
}else if(Aspet == 2)
{
if(Speed > 0)
{
GPIO_SetBits(GPIOA, GPIO_Pin_4);
GPIO_ResetBits(GPIOA, GPIO_Pin_5);
PWM_SetCompare(2,Speed);
}else
{
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
GPIO_SetBits(GPIOA, GPIO_Pin_5);
PWM_SetCompare(2,-Speed);
}
}
}
3.5、前进后退等功能
根据Motor_SetSpeed的Speed参数正负值控制前进与后退、Aspet控制左轮与右轮,新建一个车模块,封装前进、后退、左拐、右拐、后左拐、后右拐等功能。
void Car_Init(void){
Motor_Init();
}
void Go_Ahead(void){
Motor_SetSpeed(1,50);
Motor_SetSpeed(2,50);
}
void Go_Back(void){
Motor_SetSpeed(1,-50);
Motor_SetSpeed(2,-50);
}
void Turn_Left(void){
Motor_SetSpeed(1,0);
Motor_SetSpeed(2,90);
}
void Turn_Right(void){
Motor_SetSpeed(2,0);
Motor_SetSpeed(1,90);
}
void Self_Left(void){
Motor_SetSpeed(1,-90);
Motor_SetSpeed(2,90);
}
void Self_Right(void){
Motor_SetSpeed(1,90);
Motor_SetSpeed(2,-90);
}
void Car_Stop(void){
Motor_SetSpeed(1,0);
Motor_SetSpeed(2,0);
}
4、蓝牙模块
串口通信里面,tx发送信息,rx接受信息,这里我使用了pa9口作为tx,pa10作为rx,
注:在蓝牙模块的tx与rx中,要记得反插,也就是蓝牙的tx接pa10,蓝牙的rx接pa9。
4.1、代码实现
uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
void Serial_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // tx
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // rx
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);
// 下面是用中断的方法实现串口发送
// 使能 USART1 的接收中断,以便在接收到新的数据时触发中断处理程序。
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 开启串口接收数据的中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 配置NVIC为分组2
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; // 选择配置NVIC的USART1线
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 指定NVIC线路使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 指定NVIC线路的抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 将结构体变量交给NVIC_Init,配置NVIC外设
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1, ENABLE);
}
// 串口发送一个字节
void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART1, Byte);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
// 串口发送一个数组
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for (i = 0; i < Length; i ++) //遍历数组
{
Serial_SendByte(Array[i]); //依次调用Serial_SendByte发送每个字节数据
}
}
// 串口发送一个字符串
void Serial_SendString(char *String)
{
uint8_t i;
for (i = 0; String[i] != '\0'; i ++)//遍历字符数组(字符串),遇到字符串结束标志位后停止
{
Serial_SendByte(String[i]); //依次调用Serial_SendByte发送每个字节数据
}
}
// 次方函数(内部使用)
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
uint32_t Result = 1; //设置结果初值为1
while (Y --) //执行Y次
{
Result *= X; //将X累乘到结果
}
return Result;
}
// 串口发送数字
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i ++) //根据数字长度遍历数字的每一位
{
Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0'); //依次调用Serial_SendByte发送每位数字
}
}
// 使用printf需要重定向的底层函数
int fputc(int ch, FILE *f)
{
Serial_SendByte(ch); //将printf的底层重定向到自己的发送字节函数
return ch;
}
// 自己封装的prinf函数
void Serial_Printf(char *format, ...)
{
char String[100]; //定义字符数组
va_list arg; //定义可变参数列表数据类型的变量arg
va_start(arg, format); //从format开始,接收参数列表到arg变量
vsprintf(String, format, arg); //使用vsprintf打印格式化字符串和参数列表到字符数组中
va_end(arg); //结束变量arg
Serial_SendString(String); //串口发送字符数组(字符串)
}
// 获取串口接收标志位
uint8_t Serial_GetRxFlag(void)
{
if(Serial_RxFlag == 1)
{
Serial_RxFlag = 0;
return 1;
}
return 0;
}
// 获取串口接收的数据
uint8_t Serial_GetRxData(void)
{
return Serial_RxData;
}
4.2、中断函数
// USART1中断函数
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET) // 判断是否是USART1的接收事件触发的中断
{
// USART_ReceiveData: 将接收到的数据从 USART1 的接收数据寄存器中读取
Serial_RxData1 = USART_ReceiveData(USART1);
OLED_ShowHexNum(1,1, Serial_RxData1, 10);
if(Serial_RxData1 == 0x30) Car_Stop();
if(Serial_RxData1 == 0x31) Go_Ahead();
if(Serial_RxData1 == 0x32) Go_Back();
if(Serial_RxData1 == 0x33) Turn_Left();
if(Serial_RxData1 == 0x34) Turn_Right();
if(Serial_RxData1 == 0x35) Self_Left();
if(Serial_RxData1 == 0x36) Self_Right();
if(Serial_RxData1 == 0x37)
{
Car_Stop();
Servo_SetAngle(0);
}
if(Serial_RxData1 == 0x38)
{
Car_Stop();
Servo_SetAngle(90);
}
if(Serial_RxData1 == 0x39)
{
Car_Stop();
Servo_SetAngle(180);
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
5、自动避障功能
舵机与超声波模块联合使用,实现检查前面是否有障碍物,如有,左拐或右拐,如果遇到死胡同(前左右都有障碍物)停下来。
4.1、舵机模块
舵机使用的PB0口,根据引脚定义表进行定时器与通道的初始化,前面有讲,这里就不过多进行复述了。
代码实现
void PWMServo_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OC3Init(TIM3, &TIM_OCInitStructure);
TIM_Cmd(TIM3, ENABLE);
}
void PWMServo_SetCompare3(uint16_t Compare)
{
TIM_SetCompare3(TIM3, Compare);
}
对舵机初始化封装与转弯角度。
void Servo_Init(void)
{
PWMServo_Init();
}
void Servo_SetAngle(float Angle)
{
PWMServo_SetCompare3(Angle / 180 * 2000 + 500);
}
主函数调用,就可以使用了。
4.2、超声波模块
使用的是pb12口,原理可以看看这位大佬的。
uint16_t Cnt;
uint16_t OverCnt;
void Ultrasound_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // trig
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; // echo
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM4);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 60000 - 1; // arr
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; // psc
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure);
}
float Test_Distance()
{
GPIO_SetBits(GPIOB, GPIO_Pin_12);
Delay_us(20);
GPIO_ResetBits(GPIOB, GPIO_Pin_12);
while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13) == RESET){};
TIM_Cmd(TIM4, ENABLE);
while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13) == SET){};
TIM_Cmd(TIM4, DISABLE);
Cnt = TIM_GetCounter(TIM4);
float distance = (Cnt * 1.0 / 10 * 0.34) / 2;
TIM4->CNT = 0;
Delay_us(100);
return distance;
}
我们来看看自动寻迹的代码,先让他一直前进,当检测的具体小于15cm时,停下来,舵机左转或右转,然后再进行检测,前进或停下来操作。
void Obstacle_Avoidance()
{
Go_Ahead();
uint16_t Distance = Test_Distance();
if(Distance < 15){
Car_Stop();
Servo_SetAngle(0);
Delay_ms(1000);
Distance= Test_Distance();
if(Distance > 15){
Delay_ms(1000);
Turn_Right();
Delay_ms(1300);
Servo_SetAngle(90);
Go_Ahead();
}
else
{
Servo_SetAngle(180);
Delay_ms(1000);
Distance = Test_Distance();
if(Distance > 15){
Delay_ms(1000);
Turn_Left();
Delay_ms(1300);
Servo_SetAngle(90);
Go_Ahead();
}else{
Servo_SetAngle(90);
while(1){};
}
}
}
Delay_ms(100);
}
这里代码后续进行优化
4.3、主函数调用
int main(void)
{
Car_Init();
Serial_Init();
Servo_Init();
Servo_SetAngle(90);
Ultrasound_Init();
//Go_Ahead();
while (1)
{
Obstacle_Avoidance(); // 自动规避障碍
//Auto_Tracing(); // 自动寻迹
}
}
6、自动寻迹功能
寻迹模块使用的红外,这个原理自行搜索,使用的PB5到PB8口,然后使用GPIO_ReadInputDataBit 读取信号,也就是0或1 ,0代表没有检测到黑线,1代表检测到黑线,下面的代码待优化
6.1、代码实现
// 寻迹模块
void Track_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
// b6,b5在左边 b7 b8在右边
void Auto_Tracing()
{
// 没有黑线往前走
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==0&&
// GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)==0&&
// GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)==0&&
GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8)==0){
Go_Ahead();
}
// 有黑线往后走
else if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==1&&
// GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)==1&&
// GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)==1&&
GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8)==1){
Car_Stop();
}
// 后右拐
else if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==0&&
// GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)==0&&
// GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)==1&&
GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8)==1){
Turn_Left();
}
// 右拐
else if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==0&&
// GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)==0&&
// GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)==1&&
GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8)==0){
Turn_Left();
}
// 右拐
else if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==0&&
// GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)==0&&
// GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)==0&&
GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8)==1){
Turn_Left();
}
// 左拐
else if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==0&&
// GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)==1&&
// GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)==0&&
GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8)==0){
Turn_Right();
}
// 后左拐
else if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==1&&
// GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)==1&&
// GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)==0&&
GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8)==0){
Turn_Right();
}
// 左拐
else if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==1&&
// GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)==0&&
// GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)==0&&
GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8)==0){
Turn_Right();
}
}
这样,自动寻迹就完成了,主函数调用就可以跑了。
四、总结
代码待优化,后续来总结。