2022电赛小车开源代码讲解开源

2023-10-26

2022电赛小车我认为有主要是几个主要的问题,我将分这几个部分来讲解

目录

一、循迹

二、蓝牙通信,双车数据传输

三、起始路口的识别

四、分叉路口的识别

五、源码


 2022电赛,双车稳定行驶_哔哩哔哩_bilibili

一、循迹

循迹我们组用的是五路灰度,灰度跟红外对管的作用是差不多的,在淘宝上就能买到,检测到黑线就输入高电平,那么就需要在单片机上捕获到这个IO口的电平就可以知道哪个灰度检测到了黑线。

步骤很简单   初始化IO口->捕获IO口  代码如下:

#ifndef __GRAY_H_
#define __GRAY_H_
//主函数定义
#include "sys.h"
void GRAY_Init(void);
int Gray_values(void);

#endif
#include "gray.h"
void GRAY_Init(void)//初始化IO口
{
	 GPIO_InitTypeDef  GPIO_InitStructure;
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	 //使能PA,PD端口时钟
		
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 		 			//上拉输入
	 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		  //IO口速度为50MHz
	 GPIO_Init(GPIOA, &GPIO_InitStructure);				//根据设定参数初始化
}


u8 Gray_values()//得到IO口的值并返回
{
   static u8 Gray_Value;
   Gray_Value=GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4);//获得GPIO的值
   return Gray_Value;
}

可以根据自己的需求进行IO口的配置,最后用一个数组来放这几个IO值。

二、蓝牙通信,双车数据传输

首先配对两个小车的蓝牙,将一个蓝牙设置为主一个为从机模式,具体配对方法点击这里。然后就是蓝牙初始化了。初始化比较简单到处都能找得到源码。

#ifndef __USART2_H
#define __USART2_H
#include "sys.h"



#define USART2_MAX_RECV_LEN		37					//最大接收缓存字节数
#define USART2_MAX_SEND_LEN		3					//最大发送缓存字节数
#define USART2_RX_EN 			1					//0,不接收;1,接收.

#define	DATA1			12550
#define	DATA2			12806
#define	DATA3			13062

extern u8  USART2_RX_BUF[USART2_MAX_RECV_LEN]; 		//接收缓冲,最大USART3_MAX_RECV_LEN字节
extern u8  USART2_TX_BUF[USART2_MAX_SEND_LEN]; 		//发送缓冲,最大USART3_MAX_SEND_LEN字节
extern vu16 USART2_RX_STA;   						//接收数据状态
void dataSend(u8 *sendArry);
void usart2_init(u32 bound);				//串口2初始化
void u2_printf(char* fmt, ...);
#endif

#include "delay.h"
#include "usart2.h"
#include "stdarg.h"	 	 
#include "usart.h"
#include "timer.h"
#include "stdio.h"	 	 
#include "string.h"	



//串口接收缓存区
u8 USART2_RX_BUF[USART2_MAX_RECV_LEN]; 				//接收缓冲,最大USART3_MAX_RECV_LEN个字节.
u8 USART2_TX_BUF	[USART2_MAX_SEND_LEN];		//发送缓冲,最大USART3_MAX_SEND_LEN字节

u16 uart2rec;
u8 END_FLAG1;

u8	RECEIVE_FLAG = 0; 

//初始化IO 串口3
//pclk1:PCLK1时钟频率(Mhz)
//bound:波特率
void usart2_init(u32 bound)
{

    NVIC_InitTypeDef NVIC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	// GPIOB时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //串口3时钟使能
    USART_DeInit(USART2);  //复位串口3
    //USART2_TX   PA2
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PB10
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PB10
    //USART2_RX	  PA3
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PB11
	 //设置中断优先级
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ; //抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
    USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式

    USART_Init(USART2, &USART_InitStructure); //初始化串口	
    //使能接收中断
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断
		USART_Cmd(USART2, ENABLE);                    //使能串口
 
}

void dataSend(u8 *sendArry) {//发送数据函数,注意这里发的是一个数组,3位数组,第一个与第三个用于判断
	int i;
   for(i=0;i<3;i++)   		
   {
	   USART_SendData(USART2,sendArry[i]);
     while((USART2->SR&0x40)==0);
	}

}


void USART2_IRQHandler(void)//接收数据中断
{
static  u8 i = 0;
    u8 res;
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
    {
        
      res = USART_ReceiveData(USART2);
			if(res == 0x01 )//帧头判断
			{
				i = 0;
			}
			USART2_RX_BUF[i] = res;//将接收到的数据放在数组中
			i++;
			if(i == 2 && USART2_RX_BUF[2] == 0x06)//帧尾判断
			{
				uart2rec = (u16)((u16)USART2_RX_BUF[1]<<8 | (u16)USART2_RX_BUF[2]);//将接收到的数据进行移位操作
		
		 }
    }

}


//串口2,printf 函数
//确保一次发送数据不超过USART3_MAX_SEND_LEN字节
void u2_printf(char* fmt, ...)
{
    u16 i, j;
    va_list ap;
    va_start(ap, fmt);
    vsprintf((char*)USART2_TX_BUF, fmt, ap);
    va_end(ap);
    i = strlen((const char*)USART2_TX_BUF);		//此次发送数据的长度

    for(j = 0; j < i; j++)							//循环发送数据
    {
        USART_SendData(USART2, USART2_TX_BUF[j]);

        while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET); //循环发送,直到发送完毕

       

    }
}

主要是用好发送函数和接收中断,移位操作是将后两位16进制转换为10进制,

列:发送数组data[3]={0x01,0x31,0x06}        则0x31,0x06->12550  uart2rec=12550

 通过改变中间的值改变uartrec的值,判断走哪个问。

三、起始路口的识别

根据灰度的的亮灭则可判断,经过停车位置时,中间三个灯灭,则让其做出指令。

四、分叉路口的识别

在这里有很多种方法,我们用的方法是根据起始的三个灯灭来判断,如果三个灯灭了,若走外圈则利用延时向前冲一段,还有可以利用最外边的灰度进行判断。说起来很抽象,还是直接上代码吧。

五、源码

用了很多标志位导致阅读感很不舒服。大家见谅,主要这代码是一个月前的了我也不想再去改了,主要给大家提供一个思路,欢迎评论区讨论学习。

链接: https://pan.baidu.com/s/1X8O7z_afGnofAl8y89iRAQ?pwd=1234 提取码: 1234 

#include "test.h"
#include "control.h"
#include "gray.h"
#include "tb6612.h"
#include "led.h"
#include "usart2.h"
#include "test.h"
#include "encoder.h"
u8 TRACE_FLAG = 1,STOP_FLAG ,START_FLAG = 1;

u8 send_data5[3] = {0x01,0x35,0x06};//13574
u8 send_data6[3] = {0x01,0x36,0x06};//13574
u8 Instruction_Flag;
int cross_num;
void test1()
{
	Basic_Speed = 2600;				//2400   0.3
	Gray_values();
	Encoder4();
	if(START_FLAG)
	{
		trace(Basic_Speed);
		if(TURN_FLAG == 1)
		{
			Direction(10,10,0,1);			//0  外圈
		}
		if(Gray_Number >= 3  && Gray_Number < 5 && TURN_FLAG == 0)
		{
			TURN_FLAG = 1;
			Qingling = 0;
		}
		if(cross_num == 2)
		{
			START_FLAG = 0;
			END_FLAG = 1;
		}
	}
			//停止行进标志位
	if(END_FLAG == 1)
	{
		LED0 = 1;
		STOP;	
		dataSend(send_data5);
		if(delay(40))
		{
			LED0 = 0;
			END_FLAG = 0;
			START_FLAG = 0;
			TRACE_FLAG = 0;
		}
	}
}


void test2()
{
	Basic_Speed = 3300;				//3100   0.5	
	Gray_values();
	Encoder4();
	if(START_FLAG)
	{
		trace(Basic_Speed);
		if(TURN_FLAG == 1)
		{
			Direction(10,10,0,1);
		}
		if(Gray_Number >= 3 && Gray_Number < 5 && TURN_FLAG == 0 )
		{
			TURN_FLAG = 1;
			Qingling = 0;
		}

		if(cross_num == 3)
		{
			START_FLAG = 0;
			END_FLAG = 1;
		}
	}
	
	if(END_FLAG == 1)/结束
	{
		dataSend(send_data5);
		LED0 = 1;
		BACKWORD;	
		PWM_L = 0;
		PWM_R = 0;
		if(delay(30))
		{
			START_FLAG = 0;
			LED0 = 0;
			END_FLAG = 0;
			DELAY_FLAG = 1;
		}
	}
}


void test3()
{
	Basic_Speed = 2600;
	Gray_values();
	Encoder4();
	if(START_FLAG)
	{
		trace(Basic_Speed);
		if(TURN_FLAG == 1)
		{
			switch(cross_num)
			{
				case 0:
							 Direction(10,10,0,1);     break;
				case 1:
							 Direction(10,10,0,1);     break;
				case 2:
							 Direction(10,10,0,1);     break;
				case 3:
							 Direction(10,10,1,1);     
								LED1 = 1;								 break;
				case 4:
							 Direction(10,10,1,1);     break;
			}
		}
		if(Gray_Number >= 3 && Gray_Number < 5 && TURN_FLAG == 0)
		{
			TURN_FLAG = 1;
			Qingling = 0;
		}
		if(cross_num == 4)
		{
			START_FLAG = 0;
			END_FLAG = 1;
		}
	}
	if(END_FLAG == 1)/结束
	{
		dataSend(send_data5);
		LED0 = 1;
		BACKWORD;	
		PWM_L = 0;
		PWM_R = 0;
		if(delay(30))
		{
			START_FLAG = 0;
			LED0 = 0;
			END_FLAG = 0;
			DELAY_FLAG = 0;
		}
	}
}


void test4()
{
	Basic_Speed = 4000;
	Gray_values();
	Encoder4();
	if(START_FLAG)
	{
		if(Instruction_Flag == 0  && Gray_Number >= 3 && TURN_FLAG == 0)
		{
			TURN_FLAG = 1;
		}
		if(TURN_FLAG == 1)
		{
			if(delay(20))
			{
				Instruction_Flag  = 1;
				TURN_FLAG = 2;
				DELAY_FLAG = 0;
			}
		}

		if(Instruction_Flag  == 1 && TURN_FLAG == 2 && Gray_Number >= 3)
		{
			TURN_FLAG = 3;
		}
		if(TURN_FLAG == 3)
		{
				BACKWORD;
				PWM_L = 0;
				PWM_R = 0;
				Instruction_Flag  = 2;
				if(delay(150))
				{
					TURN_FLAG = 4;
					Instruction_Flag  = 3;
					FORWARD;
					DELAY_FLAG = 0;
					TIM_SetCounter(TIM2,0);
				}	
		}
			
		if(Instruction_Flag == 3 && Gray_Number >= 3 && Read_Encoder(2) > 1000)
		{
			START_FLAG = 0;
			END_FLAG = 1;
		}
		if(Instruction_Flag != 2)
		{
			trace(Basic_Speed);
		}
	}

	if(END_FLAG)
	{
		START_FLAG = 0;
		BACKWORD;
		PWM_L = 0;
		PWM_R = 0;	
		LED0 = 1;
		dataSend(send_data5);
		if(delay(50))
		{
			LED0 = 0;
			END_FLAG = 0;
			START_FLAG = 0;
			TRACE_FLAG = 0;
			DELAY_FLAG = 0;
		}
	}
	
}
	

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

2022电赛小车开源代码讲解开源 的相关文章

  • 【廖雪峰python入门笔记】Unicode编码_UnicodeDecodeError处理

    1 Unicode编码的由来 字符串还有一个编码问题 计算机只能处理数字 如果要处理文本 就必须先把文本转换为数字才能处理 最早的计算机在设计时采用8个比特 bit 作为一个字节 byte 所以 一个字节能表示的最大的整数就是255 二进制
  • JAVA String的问题

    String s1 字符串 String s2 字符串 System out println s1 s2 输出true String s3 new String 字符串 String s4 new String 字符串 System out

随机推荐

  • 以太坊 geth常用命令行

    命令行组成为geth lt 命令 gt 参数 geth datadir 指定数据存储位置 也是默认的私钥仓库位置 nodiscover 标志此节点私有 不被别人添加 maxpeer 0 设置网络中可以被接入的最大节点数目 0代表不被其它节点
  • 【线性代数01】矩阵的转置和逆

    这方面的总结一直都有想写 我们先从矩阵的转置和逆谈起 本篇内容整理自网页 矩阵的转置和逆 给出这部分叙事的主角 矩阵A和矩阵B A 1
  • 【深度学习】语义分割-源代码汇总

    目录 Transformer 1 vit 2 Swin Transformer 3 PVT 4 SETR 5 segformer Transformer 1 vit 1 官方 vision transformer 2 Swin Transf
  • Linux内核:内存管理——CMA预留内存

    平时看 proc meminfo中 总能看到CMA的身影 且好像总是被用光了 他是做什么的呢 为啥作为预留内存能用的干干净净呢 一起看下 CmaTotal 438272 kB CmaFree 0 kB Contiguous Memory A
  • 电路设计中LDO与DC-DC的选择问题(DC-DC篇)

    版权声明 本文为博主原创文章 转载请注明出处 https blog csdn net NeverImagine article details 93193105 接上文 上文讨论了LDO的原理和特性 本文再分析一下DC DC 二 DC DC
  • 查看mysql root账户密码

    cat root mysql secret 查看root账号密码
  • 虹膜识别系统 python实现

    先上传效果图 main py An highlighted block Demonstration of the GazeTracking library Check the README md for complete documenta
  • 【从嵌入式视角学习香山处理器】六、NutShell代码结构(乱画的框图)

    文章目录 一 前言 二 简单粗暴版 最终成品的框图 三 不要太凌乱版 去掉连线后的框图 一 前言 这是从上一篇文章 从嵌入式视角学习香山处理器 五 香山开发工作流实践1 主要子模块工程之间的关系 引出的对果壳核 NutShell 一个简单入
  • MySQL存储过程入门教程及实例详解

    1 存储过程简介 存储过程是可编程的函数 在数据库中创建并保存 可以由SQL语句和控制结构组成 当想要在不同的应用程序或平台上执行相同的函数 或者封装特定功能时 存储过程是非常有用的 数据库中的存储过程可以看做是对编程中面向对象方法的模拟
  • 不同集合中判断元素相同的方法

    判断集合中的元素是否相同 对于增删改查有重要意义 不同Collection的实现的判断依据不同 1 List类 线性表 统一标准是equals 2 HashSet和HashMap 哈希表 先hashcode 后equals 3 TreeSe
  • k8s selector_k8s(二)——kubectl的使用以及创建deployment

    kubectl的使用以及创建deployment kubectl的使用 常见概念 kubectl管理命令概要 管理和使用deployment 基于deployment创建nginx pod 有一个副本 查看k8s对象状态 发布应用 服务伸缩
  • SpringBoot:切面AOP实现权限校验:实例演示与注解全解

    1 理解AOP 1 1 什么是AOP AOP Aspect Oriented Programming 面向切面思想 是Spring的三大核心思想之一 两外两个 IOC 控制反转 DI 依赖注入 那么AOP为何那么重要呢 在我们的程序中 经常
  • SM4 CBC模式加密的C语言实现

    因为工作的关系 最近在研究国密算法 其中无线局域网使用的SM4算法颇为神秘 网上资源也是少的可怜 不过在笔者的努力下 还是成功搞定了 有感于SM4相关正确资料的稀少 同时也算是自我的学习积累 故写下此文 希望可以帮助后来人少走些弯路 此处给
  • 有意思的心理学现象

  • Elasticsearch 实战之三:ES 基本操作

    目录 0 数据格式说明 1 ES的基本操作 1 1 索引操作 1 1 1 建立索引 1 1 2 删除索引 1 1 3 查询索引 1 2 映射操作 1 2 1 建立映射 1 2 2 查询映射 1 3 基本操作 CRUD 1 3 1 新增和替换
  • Zephyr-环境搭建

    目录 1 前言 2 安装主机依赖 3 获取源码 4 安装工具链 5 编译一个Demo 1 前言 Zephyr支持Ubuntu macOS Windows环境下开发 本文介绍基于Ubuntu的环境搭建 包括 Ubuntu开发环境搭建 主要是工
  • VBA设置默认/缺省运行路径的方法

    在设计VBA脚本时 有时我们需要在指定目录中运行或打开第三方程序 文件 那么最好的方法就是使用ChDir命令更改当前默认的运行路径 以便脚本能轻松地找到所需文件 更改缺省文件夹或驱动器 ChDir 语句和ChDrive语句 使用ChDir语
  • 改进的PSO-BP算法在工业机器人末端位姿误差补偿中的应用

    摘要 提出了一种全梯度标准粒子群优化反馈 FGSPSO BP 神经网络的工业机器人末端位姿补偿模型 首先 提出一种运动学逆变换算法 通过机器人末端位姿对机器人各关节角度值进行计算 并采用Matlab验证了运动学逆变换算法的准确性 然后 提出
  • VS2019打包WPF安装程序最新教程

    VS2019打包WPF安装程序最新教程 使用Visual Studio 2019开发的WPF程序如果想要打包为安装程序 除了在VS2019找到WPF项目类库直接右键发布之外 更常用的还是将其打包为exe或者msi的安装程序 打包成安装程序的
  • 2022电赛小车开源代码讲解开源

    2022电赛小车我认为有主要是几个主要的问题 我将分这几个部分来讲解 目录 一 循迹 二 蓝牙通信 双车数据传输 三 起始路口的识别 四 分叉路口的识别 五 源码 2022电赛 双车稳定行驶 哔哩哔哩 bilibili 一 循迹 循迹我们组