stm32项目平衡车详解(stm32F407)下

news2025/3/1 14:10:15

stm32项目平衡车详解(stm32F407)下

HC-SRO4 超声波测距避障功能开发
TSL1401 CCD摄像头实现小车巡线功能


文章目录

  • stm32项目平衡车详解(stm32F407)下
  • 前言
  • 一、HC-SRO4 超声波测距避障功能开发
    • HC-SRO4超声波测距模块?
    • 超声波测距避障功能开发
    • 避障模式开发
  • 二、TSL1401 CCD摄像头实现小车巡线功能
    • TSL1401 CCD摄像头?
    • 巡线小车功能开发(编写程序)
        • TSL1401 示例代码如下:
        • 项目工程开始
  • 三、遥控小车
    • 蓝牙控制
    • esp32 网络控制


前言

前面我们已经实现了平衡小车的直立环,平衡环,转向环,下面我们将实现小车平衡小车蔽障与巡线功能的开发。如下如所示:
在这里插入图片描述
在这里插入图片描述


一、HC-SRO4 超声波测距避障功能开发

HC-SRO4超声波测距模块?

在这里插入图片描述
在这里插入图片描述
HC- SR04是一种超声波接近传感器,可以告诉您物体是否在它前面,并且还提供传感器和物体之间的距离。这些传感能力使其特别适用于需要知道远离物体或障碍物的机器人,例如墙壁或不应撞击的家具。

点击查看,HC-SR04超声波传感器原理

超声波测距避障功能开发

cube 搭建工程项目
在这里插入图片描述
下面给中断使能
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
启动定时器TIM7 去计时

在这里插入图片描述

在这里插入图片描述

避障模式开发

避障模式原理就是通过超声波加测距离,通过转向来躲避障碍物。所以我们会用转向环来控制小车转向。

//启动超声波,检测距离


//启动超声波检测函数

void HC_SRC04_Start(void)
{
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0, GPIO_PIN_SET); //设置高电平启动
	
	delay_us(20); 
	
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0, GPIO_PIN_RESET); //设置高低平启动
}

调用定时器中毒阿女函数进行计数,利用声音传播速度和接收时间测算距离


/**
  * @brief This function handles TIM7 global interrupt.
  */
void TIM7_IRQHandler(void)
{
  /* USER CODE BEGIN TIM7_IRQn 0 */

  /* USER CODE END TIM7_IRQn 0 */
  HAL_TIM_IRQHandler(&htim7);
  /* USER CODE BEGIN TIM7_IRQn 1 */

  /* USER CODE END TIM7_IRQn 1 */
}

/* USER CODE BEGIN 1 */
uint8_t ECHO_IRQ_FLAG = 0;

uint8_t time_cnt = 0; //参数二,溢出次数
static uint8_t last_distence =0;


void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	int time = 0;
	if(GPIO_Pin == GPIO_PIN_1)
	{
		if(ECHO_IRQ_FLAG == 0) //上升沿中断
		{
			ECHO_IRQ_FLAG=1; 
			HAL_TIM_Base_Start_IT(&htim7); //开启定时器,开始计时
		}else{
			ECHO_IRQ_FLAG = 0;   //下降沿中断
			HAL_TIM_Base_Stop_IT(&htim7);//关闭定时器,计时结束
			
			time = time_cnt*1000 + TIM7->CNT / 2; //统计声(单次)音返回时间
			
			Distence = 340*100* time /1000000; //微妙转化为秒
			if(Distence == 0)  Distence = last_distence;
			else               last_distence = Distence;
				
		}
	}
	
}

配合pid 控制函数,使用超声波测距的距离,进行避障,小车达到避障距离就开始转弯避障,(避障距离建议超过小车直径即可)



int Balance_Pwm,Vertical_Pwm,Trun_Pwm;
int Motor1,Motor2;
int Encoder_left,Encoder_right;
float Movement = 0; //目标速度
int CCD; //目标角度

int FS_MODE;        //0 遥控模式1,避障模式  2巡线模式
int Distence;       //检测小车与障碍物的距离


//PID控制任务
void Car_Task_100HZ(void)
{
	//启动超声波检测模式
	HC_SRC04_Start();
	
	
	//1、确定直立环的PWM
	
	Balance_Pwm = Vertical_Ring_PD(OutMpu.pitch,OutMpu.gyro_x); //*形参:(float Angle):x轴的角度/(float Gyro):x轴的角速度
	
	//2、确定速度环的PWM
	Encoder_left = Read_Encoder(1); //左轮
	Encoder_right = -Read_Encoder(2); //右轮
	
	Vertical_Pwm = Vertical_speed_PI(Encoder_left,Encoder_right,OutMpu.pitch,Movement);
	//3、确定方向环的PWM
	
	if(FS_MODE == 0) //遥控模式
		Trun_Pwm = Vertical_turn_PD(CCD,OutMpu.yaw);
	else if(FS_MODE == 1) //避障模式
	{
		if(Distence < 20) //直线距离在20cm 直接转向 20度
			Trun_Pwm = Vertical_turn_PD(20,OutMpu.yaw); //直接转向 20度
		else
			Trun_Pwm = 0; //直行
			
	}
	else if(FS_MODE == 2) //巡线模式
	{
		
	}
	
	
	
	//4、确定最终电机的左右pwm 
	
	Motor1 = Balance_Pwm+Vertical_Pwm+Trun_Pwm;
	Motor2 = Balance_Pwm+Vertical_Pwm-Trun_Pwm;
	
	PWM_Limiting((int) Motor1,(int) Motor2);

	//4、设置电机
	Set_PWM(Motor1,Motor2); //*形参;(int motor1):电机1对应的PWM值/(int motor2):电机2对应的PWM值
			
}
			
}

二、TSL1401 CCD摄像头实现小车巡线功能

巡线就是小车按照轨迹进行一定的运动,我们通过设计头模块进项轨迹实施采集分析调整车辆运动方向。

在这里插入图片描述

TSL1401 CCD摄像头?

参考案例 STM32版CCD线性摄像头寻线寻迹小车

在这里插入图片描述
在这里插入图片描述
CCD采集到外部像素,感应光线的强度通过AD 输出

在这里插入图片描述
不同的光线强度的灰度值是不一样的,通过信号传输给控制器,控制器根据灰度值来确定我们的条件。
在这里插入图片描述
上图所从左到右,由亮变暗在变亮,中间黑色区域是最暗大的,我们使用线性 就是横排采集一条线,判断内容。

在这里插入图片描述
上图看到SI由采集的到最后AD输出的电压值。
在这里插入图片描述

巡线小车功能开发(编写程序)

电路图如下:

在这里插入图片描述
在这里插入图片描述
CCD查看使用教程

TSL1401 示例代码如下:

/**
  ******************************************************************************
  * File Name          : main.c
  * Description        : Main program body
  ******************************************************************************
  ** This notice applies to any and all portions of this file
  * that are not between comment pairs USER CODE BEGIN and
  * USER CODE END. Other portions of this file, whether 
  * inserted by the user or by software development tools
  * are owned by their respective copyright owners.
  *
  * COPYRIGHT(c) 2018 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f0xx_hal.h"
#include "adc.h"
#include "usart.h"
#include "gpio.h"

/* USER CODE BEGIN Includes */
#include "stdio.h"
#include <math.h>

#define CCD_MIDDLE 			0
#define CCD_THRESHOLD		1
#define CCD_LEFT				2
#define CCD_RIGHT				3

#define TSL_CLK_H HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,GPIO_PIN_SET) 
#define TSL_CLK_L HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,GPIO_PIN_RESET)

#define TSL_SI_H HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_SET) 
#define TSL_SI_L HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_RESET) 
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */
uint16_t ADV[128]={0};  
uint8_t i;



struct tCCD
{
	uint16_t middle;      //中间位置值
	uint16_t threshold;   //像素ad阈值
	uint16_t left;        //左跳变的位置
	uint16_t right;       //右跳变的位置
};

struct tCCD  CCD;
/**************************************************************************************************
*函数名:abs()
*功能:将数进行绝对值处理
*形参:number 需要进行绝对值处理的数
*返回值:经过处理后绝对值
**************************************************************************************************/
int abs (int number)
{
	return( number>=0 ? number : -number );
}
/**************************************************************************************************
*函数名:Dly_us()
*功能:延时函数,用来调整CCD曝光
*形参:无
*返回值:无
***************************************************************************************************/
void Dly_us(void)
{
   int ii;    
   for(ii=0;ii<220;ii++);      
}
/**************************************************************************************************
*函数名:Get_Adc()
*功能:得到CCD数据
*形参:无
*返回值:读取到的电压值
***************************************************************************************************/
uint16_t Get_Adc(void)
{
	HAL_ADC_Start(&hadc);
	HAL_ADC_PollForConversion(&hadc, 50);
	if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc), HAL_ADC_STATE_REG_EOC))
	return 	HAL_ADC_GetValue(&hadc);
		else
			while(1);
}
/***************************************************************************************************
*函数名:RD_TSL()
*功能:读取CCD原始数据
*形参:无
*返回值:无
****************************************************************************************************/
 void RD_TSL(void) 
 {
	uint8_t i=0,tslp=0;
	TSL_CLK_H;
	TSL_SI_L;
	Dly_us();
	 
	TSL_SI_H;
	TSL_CLK_L;
	Dly_us();
	 
	TSL_CLK_H;
	TSL_SI_L;
	Dly_us();
	  for(i=0;i<128;i++){
			TSL_CLK_L;
			Dly_us();
			ADV[tslp]=(Get_Adc())>>4;
			++tslp;
			TSL_CLK_H;
			Dly_us();
		}			
 }
 /************************************************************************************************************************
 *函数名:Find_Middle_CCD()
 *功能:读取CCD中值
 *形参:无
 *返回值:CCD中值位置
 *************************************************************************************************************************/
 uint8_t Find_CCD_DATA(void)
 {
	 static uint8_t i,j;
	 //static uint8_t Last_Middle_CCD;
	 uint8_t Middle_CCD_Value;
	 static uint16_t  value1_max,value1_min;
	 value1_max=ADV[0];
	 //读取最大值
		for(i=5;i<123;i++){
        if(value1_max<=ADV[i])
        value1_max=ADV[i];
     }
	 value1_min=ADV[0]; 
		 //得到最小值
		for(i=5;i<123;i++){
       if(value1_min>=ADV[i])
       value1_min=ADV[i];
     } 
		//计算阈值
	 CCD.threshold=(value1_max+value1_min)/2;
		 //计算左跳变值
		for(i = 5;i<118; i++){
		if(ADV[i]>CCD.threshold&&ADV[i+1]>CCD.threshold&&ADV[i+2]>CCD.threshold&&ADV[i+3]<CCD.threshold&&ADV[i+4]<CCD.threshold&&ADV[i+5]<CCD.threshold){	
		  CCD.left=i;
		  break;	
		}
	}
		//计算右跳变值
		for(j = 118;j>5; j--){
		if(ADV[j]<CCD.threshold&&ADV[j+1]<CCD.threshold&&ADV[j+2]<CCD.threshold&&ADV[j+3]>CCD.threshold&&ADV[j+4]>CCD.threshold&&ADV[j+5]>CCD.threshold){	
		  CCD.right=j;
		  break;	
		}
  }
		//计算中值
		CCD.middle =(CCD.right+CCD.left)/2;
//		if(abs(Middle_CCD_Value-Last_Middle_CCD)>70){
//			Middle_CCD_Value=Last_Middle_CCD;
//			Last_Middle_CCD=Middle_CCD_Value;
//		}
		return Middle_CCD_Value;
 }
 
 /***************************************************************************************************************************/
 void ANO_Send_Data(void)
{
		 HAL_UART_Transmit(&huart1,(uint8_t *)&CCD,sizeof(CCD),0xFFFF); 
}

/* USER CODE END 0 */

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC_Init();
  MX_USART1_UART_Init();

  /* USER CODE BEGIN 2 */
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */
		//每5ms发送一帧数据
		HAL_Delay(5);
		//读取CCD原始数据,读取128个像素,
		RD_TSL();
		//对CCD数据进行处理(求阈值、中值、左右跳变值)
		Find_CCD_DATA();
		//通过串口将封装好的CCD数据向外发送
		ANO_Send_Data();
  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_PeriphCLKInitTypeDef PeriphClkInit;

    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSI14;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSI14State = RCC_HSI14_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.HSI14CalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL12;
  RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Configure the Systick interrupt time 
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    /**Configure the Systick 
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  None
  * @retval None
  */
void _Error_Handler(char * file, int line)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  while(1) 
  {
  }
  /* USER CODE END Error_Handler_Debug */ 
}

#ifdef USE_FULL_ASSERT

/**
   * @brief Reports the name of the source file and the source line number
   * where the assert_param error has occurred.
   * @param file: pointer to the source file name
   * @param line: assert_param error line source number
   * @retval None
   */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
    ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */

}

#endif

/**
  * @}
  */ 

/**
  * @}
*/ 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

项目工程开始

工程CCD工程 ,将工程下载到051 开发板进行数据采集发送
在这里插入图片描述

F407,串口3 使能,开启中断
在这里插入图片描述

开启DMA 接受数据
在这里插入图片描述
导出工程即可打开工程文件
定义ccd
在这里插入图片描述

main 函数使用

//启动CCD数据接受
HAL_UART_Receive_DMA(&huart3, (uint8_t)&CCD, sizeof(CCD));*


/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  MX_TIM1_Init();
  MX_TIM2_Init();
  MX_TIM4_Init();
  MX_TIM5_Init();
  MX_TIM7_Init();
  MX_USART3_UART_Init();
  /* USER CODE BEGIN 2 */
	
  printf("平衡小车开发项目\n");
	
	//启动PWM
	HAL_TIM_PWM_Start(&htim5, TIM_CHANNEL_3);
	HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);
	
	//启动编码器
	HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);
	HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL);
	
	
	//启动CCD数据接受
	 HAL_UART_Receive_DMA(&huart3,  (uint8_t*)&CCD, sizeof(CCD));
	
  /* USER CODE END 2 */
	
 

  /* Call init function for freertos objects (in freertos.c) */
  MX_FREERTOS_Init();
  /* Start scheduler */
  osKernelStart();

  /* We should never get here as control is now taken by the scheduler */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

设置中断检测初始化128像素后再次重新接受
在这里插入图片描述
下面可以打印了
在这里插入图片描述
通过CCD 获取摄像头捕捉的中间值得差值在64以内就可以让小车通过转弯来重新定义方向和位置
Trun_Pwm = Vertical_turn_PD(CCD.middle,OutMpu.yaw); //直接转向 20度

struct tCCD
{
uint16_t middle; //中间位置值
uint16_t threshold; //像素ad阈值
uint16_t left; //左跳变的位置
uint16_t right; //右跳变的位置
};

三、遥控小车

在这里插入图片描述

蓝牙控制

esp32 网络控制

在这里插入图片描述
使用过esp8266 的就了解过esp32 是 8266 升级款。
前期有几期是关于Node mcu esp8266 物联网模块的

工作原理,小车F407 通过esp32 联网,和手机上位机软件进行数据交互请求,esp32 通过串口6 发送小车指令,来控制小车,前后,转向。

打开工程,使能串口6,开启中断
在这里插入图片描述

esp32 使用例程模板
esp32.c


#include "esp32.h"
#include "usart.h"
#include <stdarg.h>
#include <string.h>
#include "connect.h"
#include "FreeRTOS.h"
#include "task.h"
#include "cmsis_os.h"


uint8_t NET_MODE = 0;             //0、蓝牙模式     1、wifi模式   默认蓝牙
uint8_t WIFI_CONNECT_FLAG = 0;    //WIFI连接标志位
uint8_t BLE_CONNECT_FLAG = 0;     //BLE连接标志位

tEsp32_RcvBuf Esp32Rcv;      //ESP数据接收缓冲区


tTimeDelay    ESP32_TimeDelay;


extern 	QueueHandle_t Message_Queue;

#define AT_CWSAP_STRING   "AT+CWSAP=\"FarsightESP32\",\"123456789\",5,3\r\n"
#define AT_BLEADVDATA_STRING    "AT+BLEADVDATA=\"0201060B09466172736967687420030302A0\"\r\n"

volatile tATCmd  ATCmds[20]=
{
  //*CmdSend,              *CmdRcv,    TimeOut,   CmdStatus,  
  {NULL,NULL,0,NO_RCV},
  {"AT\r\n",             "OK",         5000,      NO_RCV, },   //检测AT指令       
  {"AT+CIPAPMAC?\r\n",   "CIPAPMAC",   2000,      NO_RCV, },	 //获取MAC地址    
  {AT_CWSAP_STRING,       "CWSAP" ,    2000,      NO_RCV, },   //建立MAC相关的AP名称  
  {"AT+CWMODE=3\r\n",    "OK" ,        2000,      NO_RCV, },   //设置WIFI模式AP+Station
  {"AT+CIPMUX=1\r\n",    "OK" ,        2000,      NO_RCV, },   //设置多连接
  {"AT+CIPSERVER=1\r\n", "OK" ,        2000,      NO_RCV, },   //初始化TCP服务器 默认IP(192.168.4.1)默认端口号(333)
  {"AT+CIPSTO=0\r\n",    "OK" ,        2000,      NO_RCV, },   //设置TCP连接时间
  {"AT+CIPSEND=0\r\n",   "OK" ,        500,       NO_RCV, },   //TCP发送数据

	{"AT+RST\r\n",          "ready" ,    1000,      NO_RCV, },   //重启AT指令:
  {"AT+BLEINIT=2\r\n",   "OK" ,        1000,      NO_RCV, },   //初始化为 BLE server:
  {"AT+BLEADDR?\r\n",    "BLEADDR" ,   2000,      NO_RCV, },   //查询自身的 BLE 地址
  {AT_BLEADVDATA_STRING,  "OK" ,       2000,      NO_RCV, },   //配置广播数据包
  {"AT+BLEGATTSSRVCRE\r\n",  "OK",     1000,      NO_RCV, },   //创建服务:
  {"AT+BLEGATTSSRVSTART\r\n", "OK" ,   3000,      NO_RCV, },   //开启服务 
  {"AT+BLEADVSTART\r\n",   "OK" ,      1000,      NO_RCV, },   //开始广播
  {"AT+BLEGATTSNTFY\r\n" , ">" ,       500,       NO_RCV, },   //服务器发送数据
	
  {"CMDSTR_NOUSE",       "OK" ,        2000,      NO_RCV, }, 
};


void uart_data_send(uint8_t *fmt, uint16_t len)
{
	taskENTER_CRITICAL();  
	HAL_UART_Transmit(&huart6, (uint8_t *)fmt, len,100);
	taskEXIT_CRITICAL(); 
}


tCmdStatus ESPSend_Cmd(tATCmdNum ATCmdNum)
{		
		uint8_t len;
	
		//清空接收缓存以及接收状态

		ATCmds[ATCmdNum].CmdStatus = NO_RCV;
		
		//发送命令
		len = strlen(ATCmds[ATCmdNum].CmdSend);
		uart_data_send((uint8_t *)ATCmds[ATCmdNum].CmdSend, len);
		HAL_UART_Transmit(&huart1,(uint8_t *)ATCmds[ATCmdNum].CmdSend, len,100);

		
	 //打开超时定时器
	 SetTime(&ESP32_TimeDelay, ATCmds[ATCmdNum].TimeOut);
		 
	 while(ATCmds[ATCmdNum].CmdStatus != RCV_SUCCESS)
	 {
		 
			ESP32_Cmd_Rcv(ATCmdNum);
		  if(ATCmds[ATCmdNum].CmdStatus == RCV_TIMEOUT)
				return RCV_TIMEOUT;
	 }
	 
	 return RCV_SUCCESS;
}

/*发送数据函数*/
tCmdStatus ESP32_Send_Data(uint8_t *SendBuf,uint8_t len)
{
	  uint8_t buf[30] =  {0};
		tATCmdNum ATCmdNum;
	
		if(! (BLE_CONNECT_FLAG || WIFI_CONNECT_FLAG))  //未连接状态不能发送数据
		{
			DBG("未连接设备\n");
			return NO_CONNECT;
		}		
		
		if(NET_MODE == BLE_MODE)    //蓝牙模式
		{
			sprintf((char *)buf,"AT+BLEGATTSNTFY=%d,%d,%d,%d\r\n",0,1,2,len);
			ATCmdNum = AT_BLEGATTSNTFY;		
		}
		else 			//WIFI模式
		{
			sprintf((char *)buf,"AT+CIPSEND=%d,%d\r\n",0,len);
			ATCmdNum = AT_CIPSEND;
		}
			
		uart_data_send(buf,strlen((char *)buf));     //发送命令
		
		//打开超时定时器
	 ATCmds[ATCmdNum].CmdStatus = NO_RCV;        //清接收状态
	 SetTime(&ESP32_TimeDelay, ATCmds[ATCmdNum].TimeOut);
		 
	 while(ATCmds[ATCmdNum].CmdStatus != RCV_SUCCESS)
	 {		 
			ESP32_Cmd_Rcv(ATCmdNum);
		  if(ATCmds[ATCmdNum].CmdStatus == RCV_TIMEOUT)
				return RCV_TIMEOUT;
	 }
		
		uart_data_send( SendBuf,len);                //发送数据

		DBG("send data ok\n");
	 
	 return RCV_SUCCESS;

}



void ESP32_Cmd_Rcv(tATCmdNum ATCmdNum)
{
	memset(&Esp32Rcv,0,sizeof(Esp32Rcv));
	
	if(xQueueReceive(Message_Queue, &Esp32Rcv,0 ))
	{
				DBG("%s", Esp32Rcv.RcvBuf);
		
				
				//接收处理命令
				if(strstr((const char*)Esp32Rcv.RcvBuf,ATCmds[ATCmdNum].CmdRcv) != NULL)
				{
					ATCmds[ATCmdNum].CmdStatus = RCV_SUCCESS;						
				}			
	 
				//打开接收指示灯
				//SetLedRun(LED_RX);
				
				
	}
	else
	{
			if(CompareTime(&ESP32_TimeDelay))
			{
				ATCmds[ATCmdNum].CmdStatus = RCV_TIMEOUT;
			}
	}	

}

void ESP32_Data_Rcv(void)
{
	memset(&Esp32Rcv,0,sizeof(Esp32Rcv));
	if(xQueueReceive(Message_Queue, &Esp32Rcv,0 ))
	{
			 //接收处理数据(保护客户端发来的数据,还有其他调试数据)			

				DBG("%s", Esp32Rcv.RcvBuf);
		
			 if(NET_MODE == BLE_MODE)    //蓝牙模式
			 {
						
						if(strstr((char *)(Esp32Rcv.RcvBuf),"WRITE") != NULL ) //收到客户端数据
						{
								DBG("收到上位机数据\n");
				
								BLE_CONNECT_FLAG = 1;   //对方打开读写特征值时,置连接标志
							
							
								//提取处理数据;
								EP32_RcvData_Extract(Esp32Rcv.RcvBuf,Esp32Rcv.DataLen);	
												
								return ;			          				
						}
						
						if(strstr((char *)(Esp32Rcv.RcvBuf),"BLEDISCONN") != NULL) //客户端断开连接
					 {
							 DBG("蓝牙断开连接,重新广播\n");	
						 
							 BLE_CONNECT_FLAG = 0;    //清除连接标志位
								//重新广播
							 ESPSend_Cmd(AT_BLEADVDATA);
							 ESPSend_Cmd(AT_BLEADVSTART);
					 }

		  }
			else     //WIFI模式
			{
				
				   if((!WIFI_CONNECT_FLAG) && (strstr((char *)(Esp32Rcv.RcvBuf),"CONNECT")!=NULL )) //收到客户端数据
					 {
							DBG("WIFI已连接\n");	
						 
							WIFI_CONNECT_FLAG = 1;   //置连接标志位
					 }

			
				
					if(strstr((char *)(Esp32Rcv.RcvBuf),"+IPD") != NULL  ) //收到客户端数据
				  {
				 		DBG("WIFI收到上位机数据\n");	
						
						//提取并处理数据;
						EP32_RcvData_Extract(Esp32Rcv.RcvBuf,Esp32Rcv.DataLen);	
											
						return ;						
					
				  }	

					if(strstr((char *)(Esp32Rcv.RcvBuf),"CLOSED") != NULL) //客户端断开连接
					 {
							 DBG("WIFI断开连接\n");	
						 
							 WIFI_CONNECT_FLAG = 0;    //清除连接标志位

					 }	
				
			}
			
			
	}
}
	



void ESP32_Init(void)
{
		tATCmdNum i = AT_IDIE;
	
		if(NET_MODE == BLE_MODE)                //蓝牙模式初始化
		{
			for(i = AT_BLEINIT; i<=AT_BLEADVSTART ; i++)
			{
				if( ESPSend_Cmd(i) != RCV_SUCCESS)
				{				
					DBG("PES32 Init failed\n");
					return ;
				}
				
			}
		}
		else                                  //WIFI模式初始化
		{
					for(i = AT; i<=AT_CIPSTO ; i++)
					{						
						if( ESPSend_Cmd(i) != RCV_SUCCESS)
						{
							DBG("PES32 Init failed\n");
							return ;
						}
					}
					
						DBG("PES32 Init Success\n");
		}
}

esp32.h

#ifndef __ESP32_H
#define __ESP32_H

#include <stdint.h>
#include <stdio.h>
#include "delay.h"

extern uint8_t Esp32_RcvBuf [255];
extern uint8_t Esp32_RBuffLen ; 

//#define DEBUG 

#ifdef DEBUG 
#define DBG(x...)   printf(x) 
#else 
#define DBG(x...) 
#endif  



#define  BLE_MODE   0
#define  WIFI_MODE  1



//AT命令序列号
typedef enum
{
	AT_IDIE  = 0,
	AT,
	AT_CIPAPMAC,
	AT_CWSAP,
	AT_CWMODE,
	AT_CIPMUX,
	AT_CIPSERVER,
	AT_CIPSTO,
	AT_CIPSEND,
	
	AT_RST,
	AT_BLEINIT,
	AT_BLEADDR,
	AT_BLEADVDATA,
	AT_BLEGATTSSRVCRE,
	AT_BLEGATTSSRVSTART,
	AT_BLEADVSTART,
	AT_BLEGATTSNTFY,
	CMDSTR_NOUSE,

}tATCmdNum;


//命令返回结果的状态
typedef enum{
	NO_RCV  = 0,
	RCV_SUCCESS,
	RCV_TIMEOUT,
	NO_CONNECT,
}tCmdStatus;


typedef struct{
	char *CmdSend;         //发送的命令
	char *CmdRcv; 	       //正确返回包含的字符串
	uint16_t TimeOut;      //超时的时间
	tCmdStatus CmdStatus;  //命令返回的状态
}tATCmd; 

typedef struct {
	uint8_t DataLen;
	uint8_t RcvBuf  [255];
}tEsp32_RcvBuf;

extern tTimeDelay    ESP32_TimeDelay; 

extern uint8_t Esp32_RcvBuf  [255];
extern uint8_t ESP32_RCV_FLAG;
extern uint8_t NET_MODE ; 
extern uint8_t WIFI_CONNECT_FLAG ;    //WIFI连接标志位
extern uint8_t BLE_CONNECT_FLAG ;     //BLE连接标志位


void ESP32_Cmd_Rcv(tATCmdNum ATCmdNum);
tCmdStatus ESP32_Send_Data(uint8_t *SendBuf,uint8_t len);
void ESP32_Init(void);
void ESP32_Data_Rcv(void);

#endif /*__ESP32_H*/



上一节,stm32项目平衡车详解(stm32F407)上

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/38841.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【微软】【ICLR 2022】TAPEX:通过学习神经 SQL 执行器进行表预训练

重磅推荐专栏&#xff1a; 《Transformers自然语言处理系列教程》 手把手带你深入实践Transformers&#xff0c;轻松构建属于自己的NLP智能应用&#xff01; 论文&#xff1a;https://arxiv.org/abs/2107.07653 代码&#xff1a;https://github.com/microsoft/Table-Pretrainin…

数字图像处理(十五)图像旋转

文章目录前言一、图像旋转算法1.算法原理2. 一些需要注意的点3.举例4. 均值插值法二、编程实现1.C代码2.实验结果参考资料前言 图像的旋转是指以图像中的某一点为原点以逆时针或者顺时针方向旋转一定的角度。通常是绕图像的起始点以逆时针进行旋转。 一、图像旋转算法 1.算法原…

JAVA并发之谈谈你对AQS的理解

文章目录一、AQS是什么二、AQS具备哪些特性三、用的哪种设计模式四、AQS与锁二者之间的关系五、如何基于AQS实现一把独占锁六、参考资料一、AQS是什么 AQS的全称是 &#xff08;AbstractQueuedSynchronizer &#xff09;&#xff0c;它定义了一套多线程访问共享资源的同步器框架…

【算法基础】(一)基础算法 --- 归并排序

✨个人主页&#xff1a;bit me ✨当前专栏&#xff1a;算法基础 &#x1f525;专栏简介&#xff1a;该专栏主要更新一些基础算法题&#xff0c;有参加蓝桥杯等算法题竞赛或者正在刷题的铁汁们可以关注一下&#x1f339; &#x1f339; &#x1f339; 归并排序&#x1f4a4;一.归…

猴子也能学会的jQuery第十期——jQuery元素操作(上)

&#x1f4da;系列文章—目录&#x1f525; 猴子也能学会的jQuery第一期——什么是jQuery 猴子也能学会的jQuery第二期——引用jQuery 猴子也能学会的jQuery第三期——使用jQuery 猴子也能学会的jQuery第四期——jQuery选择器大全 猴子也能学会的jQuery第五期——jQuery样式操作…

基于拟蒙特卡洛模拟法的随机潮流计算matlab程序

电力系统随机潮流计算中常采用模拟法&#xff0c;该方法原理简单、使用方便&#xff0c;能够精确地模拟实际物理过程&#xff0c;但是简单的蒙特卡洛模拟法收敛速度很慢&#xff0c;要得到精确的结果需要以大量的计算时间为代价。本章在此基础上提出了基于拟蒙特卡洛模拟的随机…

【菜菜的sklearn课堂笔记】逻辑回归与评分卡-用逻辑回归制作评分卡-异常值和样本不均衡处理

视频作者&#xff1a;菜菜TsaiTsai 链接&#xff1a;【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili 描述性统计处理异常值 现实数据永远都会有一些异常值&#xff0c;首先我们要去把他们捕捉出来&#xff0c;然后观察他们的性质。注意&#xff0c…

【雷达检测】基于复杂环境下的雷达目标检测技术附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

3.6、媒体接入控制

1、基本概念 有多台主机连接到这根同轴电缆上&#xff0c;共享这跟传输媒体&#xff0c;形成了总线型的局域网。 各主机竞争使用总线&#xff0c;随机的在信道发送数据。 主机 C 与主机 D 同时使用总线来发送数据&#xff0c;这必然会产生所发送信号的碰撞 2、静态划分信道…

二阶锥松弛在配电网最优潮流计算中的应用(IEEE33节点配电网最优潮流算例matlab程序)(yalmip+cplex)

二阶锥规划在配电网最优潮流计算中的应用IEEE33节点配电网最优潮流算例matlab程序&#xff08;yalmipcplex&#xff09; 参考文献&#xff1a;二阶锥规划在配电网最优潮流计算中的应用 最优潮流计算是电网规划、优化运行的重要基础。首先建立了配电网全天有功损耗最小化的最优…

ABAP学习笔记之——第四章:模块化程序

一、子程序&#xff1a; 语法&#xff1a; 参数&#xff1a; 参数(Parameter)是指调用子程序时用于传入、传出的值。子程序中的参数与一般用 DATA语句定义的局部变量相同。调用子程序时使用的参数叫实参(Actual Parameter)&#xff0c;在子程序中使用的参数叫虚参(Formal Par…

nginx(六十八)http_proxy模块 nginx与上游的ssl握手

一 nginx作为客户端与上游的SSL/TLS握手 理解上&#xff1a; nginx作为客户端,此时类似浏览器的角色,发请求建立连接 nginx作为server端与下游进行SSL/TLS握手 ① nginx与后端选择什么样的协议 1&#xff09;如果nginx与上游是局域网内,一般通过http建立请求,不需要进行…

使用flv.js + websokect播放rtsp格式视频流

1.问题背景 在最近的项目中&#xff0c;涉及到海康接入的视频播放的问题&#xff0c;海康这边获取到的视频流是rtsp格式&#xff0c;web端目前没有直接可以播放的组件&#xff0c;于是最开始是后端处理了视频流&#xff0c;返回hls格式的m3u8地址&#xff0c;这样用videojs插件…

进程【JavaEE初阶】

目录 一、操作系统 二、进程 2.1 进程的概念 2.2 进程的管理 2.3 PCB 2.3.1 PCB里面的一些属性 2.3.2 进程的调度 2.3.3 进程的虚拟地址空间 2.3.4 进程间通信 一、操作系统 CPU、存储器、输入设备、输出设备&#xff0c;这些实物看得着摸得到的&#xff0c;都属于 …

web前端-javascript-switch条件分支语句(语法,执行流程,补充)

文章目录条件分支语句(switch 语句)1. 语法&#xff1b;2. 执行流程&#xff1a;2.1. 在执行时会依次将 case 后的条件表达式的值和 switch 后的条件表达式的值进行全等比较2.2. 如果比较结果为 true&#xff0c;则从当前 case 处开始执行代码2.3. 如果比较结果为 false&#x…

【知识网络分析】研究机构合作网络(co-investigator institution)

研究机构合作网络(co-investigator institution) 1 网络数据集读取2 网络最大子群数据获取与精简3 中心点指定网络半径子群获取4 节点中心度相关指标计算1 网络数据集读取 使用GC.networkCoInvestigatorInstitution()方法快速生成研究结构合作网络数据集,其中GC代表着读入p…

解析华为OSPF协议

文章目录 前言一、pandas是 目录 文章目录 OSPF基础 一、报文类型 二、LSA类型 三.LSA在各区域中传播的支持情况 四.邻居状态机 邻居关系 邻接关系 &#xff18;种状态机&#xff1a; OSPF报文认证 OSPF缺省路由 2.读入数据 总结 什么&#xff1f;二、使用步骤 1.引入库2.读入数…

卷积神经网络CNN各层基本知识

卷积神经网络 卷积神经网络(CNN)由输入层、卷积层、激活函数、池化层以及全连接层构成。 INPUT&#xff08;输入层&#xff09;-CONV&#xff08;卷积层&#xff09;-RELU&#xff08;激活函数&#xff09;-POOL&#xff08;池化层&#xff09;-FC&#xff08;全连接层&#…

[VNCTF2022]easyj4va

看源码 输入 /file?url 1报错 用伪协议可以读取到内容 /file?urlfile:///etc/passwd 然后就是查看java字节码文件的目录 file?urlfile:///usr/local/tomcat/webapps/ROOT/WEB-INF 这里官方给了另外一个协议netdoc&#xff0c;跟file用法是一样的&#xff0c;但是这个netd…

JDK动态代理与Cglib动态代理使用详解

JDK动态代理与Cglib动态代理使用详解一、JDK动态代理准备使用二、Cglib动态代理准备使用Enhancer.create(Class type, Callback callback)Enhancer.create((Class superclass, Class[] interfaces, Callback callback))Enhancer.create(Class superclass, Class[] interfaces, …