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

本文章学习借鉴于创客学院团队,以表感谢。教学视频

B站学习地址

HC-SRO4 超声波测距避障功能开发
TSL1401 CCD摄像头实现小车巡线功能
小车通信功能分析及ESP32模块介绍
oled 显示置入屏幕显示小车状态


文章目录

  • stm32项目平衡车详解(stm32F407)下
  • 前言
  • 一、HC-SRO4 超声波测距避障功能开发
    • HC-SRO4超声波测距模块?
    • 超声波测距避障功能开发
    • 避障模式开发
  • 二、TSL1401 CCD摄像头实现小车巡线功能
    • TSL1401 CCD摄像头?
    • 巡线小车功能开发(编写程序)
      • TSL1401 示例代码如下:
      • 项目工程开始
  • 三、遥控小车
    • 蓝牙控制
    • esp32 项目工程的使用
    • esp32 使用例程模板
    • 通讯协议的制定
    • 通讯协议定制库函数文件(范例)
    • oled 显示置入屏幕显示小车状态
      • 开始配置工程
  • 四、stm32项目平衡车项目下载源码

前言

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


一、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、确定直立环的PWMBalance_Pwm = Vertical_Ring_PD(OutMpu.pitch,OutMpu.gyro_x); //*形参:(float Angle):x轴的角度/(float Gyro):x轴的角速度//2、确定速度环的PWMEncoder_left = Read_Encoder(1); //左轮Encoder_right = -Read_Encoder(2); //右轮Vertical_Pwm = Vertical_speed_PI(Encoder_left,Encoder_right,OutMpu.pitch,Movement);//3、确定方向环的PWMif(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度elseTrun_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);elsewhile(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");//启动PWMHAL_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,开启中断

使用keil5 打开工程,配置串口接受esp32数据
FreeRTOS 任务里面配置数据的接收,其中使用到了队列管理xQueueCreate ,引入范例文件esp32 到工程,

void StartTask_Interaction(void const * argument)
{/* USER CODE BEGIN StartTask_Interaction */printf("交互进程运行\n");Message_Queue =  xQueueCreate (Message_Q_NUM,Message_Q_length);//创建一个队列HAL_UART_Receive_DMA(&huart6, Uart6_Rcv.RcvBuf, 255);设置串口接收__HAL_UART_ENABLE_IT(&huart6,UART_IT_IDLE); //使能中断ESP32_Init();/* Infinite loop */for(;;){ESP32_Data_Rcv(); //接受数据Car_Task_Interaction(); //交互进程osDelay(1);}/* USER CODE END StartTask_Interaction */
}

esp32 使用例程模板

方法函数的介绍
ESP32_Init(); esp32 的初始化
ESP32_Send_Data() esp32 数据的发送
ESP32_Cmd_Rcv()命令的接受
ESP32_Data_Rcv()数据的接受
ESPSend_Cmd() 命令的发送
uart_data_send() 串口的发送

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*/

通讯协议的制定

  1. 引入范例文件connect 到工程,

通讯协议定制库函数文件(范例)

connect.h

#ifndef __CONNECT_H
#define __CONNECT_H#include <stdint.h>//功能宏定义
#define MOVEMENT              0X01         //小车动作
#define READINFO              0X02         //读取PID、模式、版本,恢复默认参数
#define SETMODE               0X03         //设置小车工作模式
#define WRITEPID1             0X10         //设置PID1
#define WRITEPID2             0X11         //设置PID2//小车动作宏定义
#define CAR_STOP              0X00         //停止
#define CAR_FORWARD           0X01         //前进
#define CAR_BACK              0X02         //后退
#define CAR_TURN_LEFT         0X03         //左转
#define CAR_TURN_RIGHT        0X04         //右转//小车工作模式定义
#define REMOTE_MODE           0X01        //遥控模式
#define LINE_TRACK_MODE       0X02        //巡线模式
#define AVOID_MODE            0X03        //蔽障模式//读取小车信息定义
#define READ_ALL_ARG          0X00        //读取所有的数据
#define READ_PID              0X01        //读取PID数据
#define READ_WORK_MODE        0X02        //读取当前工作模式
#define READ_VERINFO          0XA0        //读取版本信息
#define RESTORE_DEFAULT_ARG   0XA1        //恢复默认参数//定义版本相关信息
#define Hardware_Type           10
#define Hardware_VER            10
#define Software_VER            10
#define Protocol_VER            10//定义小车上报数据的功能类型
#define CAR_VER                                     0x00                    //版本信息
#define CAR_POSE                                  0x01                  //姿态
#define CAR_SENSER                              0x02                    //传感器原始数据
#define CAR_RCDATA                              0x03                    //小车接收到的遥控数据
#define CAR_POWER                                   0x04                    //小车电量
#define CAR_MOTO                                    0x05                    //电机转速
#define CAR_SENSER2                             0x06                    //超声波距离
#define CAR_MOD                                     0X07                    //小车模式
#define CAR_PID_1                                   0x10                    //PID1数据
#define CAR_PID_2                                   0x11                    //PID2的数据
#define CAR_PID_3                                   0X12                    //PID3的数据
#define CAR_CCD_SEN                             0XF1                    //CCD的数据
#define CAR_User_Waveform                   0xA1    typedef struct
{u8 send_check;u8 send_version;u8 send_status;u8 send_senser;u8 send_senser2;u8 send_pid1;u8 send_pid2;u8 send_pid3;u8 send_pid4;u8 send_pid5;u8 send_pid6;u8 send_rcdata;u8 send_offset;u8 send_motopwm;u8 send_power;u8 send_user;u8 send_speed;u8 send_location;}dt_flag_t;u8 EP32_RcvData_Extract(const uint8_t *Buff,int len);
void Connect_Send_data(u8 CMD_Data);#endif

connect.c

#include "inv_mpu_user.h"
#include "connect.h"
#include "string.h"
#include "stdio.h"
#include "esp32.h"
#include "car_task.h"
#include "contrl.h"/**************************************************************************************************************
*函数名:package_report_data()
*功能:添加帧头功能字及校验位
*形参:(u8 fun):功能字/(u8*data):要发送的数据包/(u8 len):长度
*返回值:无
**************************************************************************************************************/
static void package_report_data(u8 fun,u8*data,u8 len)
{static u8 send_buf[40]={0};   //添加static,给栈减小一点压力u16 check_sum=0;u8 i;//封装协议头if(len>28)return;   send_buf[0]=0XAA;  send_buf[1]=0XAA; send_buf[2]=fun;    send_buf[3]=len; //封装数据for(i=0;i<len;i++)send_buf[4+i]=data[i];//计算校验值for(i=0;i<len+4;i++)    check_sum+=send_buf[i];   send_buf[len+4]=((check_sum)&0xFF);//发送数据ESP32_Send_Data(send_buf,len+5);
}/*********************************************************************************************************
*函数名:ANO_VER()
*功能:发送版本信息
*形参:HardwareType,HardwareVER,SoftwareVER,ProtocolVER
*返回值:无
*********************************************************************************************************/
static void ANO_VER(u8 HardwareType,u16 HardwareVER,u16 SoftwareVER,u16 ProtocolVER)
{static u8 tbuf[7];   tbuf[0]=(HardwareType)&0XFF;tbuf[1]=((HardwareVER)>>8)&0XFF;tbuf[2]=(HardwareVER)&0XFF;tbuf[3]=((SoftwareVER)>>8)&0XFF;tbuf[4]=(SoftwareVER)&0XFF;tbuf[5]=((ProtocolVER)>>8)&0XFF;tbuf[6]=(ProtocolVER)&0XFF;package_report_data(CAR_VER,tbuf,7);
}/*************************************************************************************************************
*函数名:ANO_MOD()
*功能:发送当前模式
*形参:data模式
*返回值:无
*************************************************************************************************************/
static void ANO_MOD(u8 data)
{u8 tbuf[1];tbuf[0]=(data)&0XFF;  package_report_data(CAR_POSE,tbuf,1);
}
/**********************************************************************************************************
*函数名:ANO_CAR_POSE()
*功能:发送姿态
*形参:angle(x俯仰,y横滚,z偏航)
*返回值:无
***********************************************************************************************************/
static void ANO_CAR_POSE(void)
{static u8 tbuf[6]; int32_t anglex,angley,anglez;anglex=((short)(OutMpu.pitch))*100;angley=((short)(OutMpu.roll))*100;anglez=((short)(OutMpu.yaw))*100;tbuf[0]=((anglex)>>8)&0XFF;      tbuf[1]=(anglex)&0XFF;tbuf[2]=((angley)>>8)&0XFF;tbuf[3]=(angley)&0XFF;tbuf[4]=((anglez)>>8)&0XFF;tbuf[5]=(anglez)&0XFF;package_report_data(CAR_POSE,tbuf,6);
}/**************************************************************************************************************
*函数名:ANO_SENSER()
*功能:发送传感器原数据
*形参:acc:陀螺仪,gyro:加速度计,mag:电子罗盘
*返回值:无
**************************************************************************************************************/
static void ANO_SENSER(void)
{static u8 tbuf[18];    u8 accx,accy,accz,gyrox,gyroy,gyroz,magx,magy,magz;accx=(u8)((OutMpu.acc_x)*100);accy=(u8)((OutMpu.acc_y)*100);accz=(u8)((OutMpu.acc_z)*100);gyrox=(u8)((OutMpu.gyro_x)*100);gyroy=(u8)((OutMpu.gyro_x)*100);gyroz=(u8)((OutMpu.gyro_x)*100);//   magx=(u8)((mag->x)*100);
//  magy=(u8)((mag->y)*100);
//  magz=(u8)((mag->z)*100);tbuf[0]=((accx)>>8)&0XFF;      tbuf[1]=(accx)&0XFF;tbuf[2]=((accy)>>8)&0XFF;tbuf[3]=(accy)&0XFF;tbuf[4]=((accz)>>8)&0XFF;tbuf[5]=(accz)&0XFF;tbuf[6]=((gyrox)>>8)&0XFF;      tbuf[7]=(gyrox)&0XFF;tbuf[8]=((gyroy)>>8)&0XFF;tbuf[9]=(gyroy)&0XFF;tbuf[10]=((gyroz)>>8)&0XFF;tbuf[11]=(gyroz)&0XFF;tbuf[12]=((magx)>>8)&0XFF;      tbuf[13]=(magx)&0XFF;tbuf[14]=((magy)>>8)&0XFF;tbuf[15]=(magy)&0XFF;tbuf[16]=((magz)>>8)&0XFF;tbuf[17]=(magz)&0XFF;package_report_data(CAR_SENSER,tbuf,18);
}
/*************************************************************************************************************
*函数名:ANO_PID()
*功能:发送PID数据
*形参:PID1,PID2,PID3的参数
*返回值:无
**************************************************************************************************************/
static void ANO_PID(u8 Function)
{static u8 tbuf[18];int16_t PID1_P,PID1_I,PID1_D,PID2_P,PID2_I,PID2_D,PID3_P,PID3_I,PID3_D;PID1_P=(u16)((PID.Balance_Kp)*100);PID1_I=(u16)((PID.Balance_Ki)*100);PID1_D=(u16)((PID.Balance_Kd)*100);PID2_P=(u16)((PID.Velocity_Kp)*100);PID2_I=(u16)((PID.Velocity_Ki)*100);PID2_D=(u16)((PID.Velocity_Kd)*100);PID3_P=(u16)((PID.Turn_Kp)*100);PID3_I=(u16)((PID.Turn_Ki)*100);PID3_D=(u16)((PID.Turn_Kd)*100);tbuf[0]=((PID1_P)>>8)&0XFF;      tbuf[1]=(PID1_P)&0XFF;tbuf[2]=((PID1_I)>>8)&0XFF;tbuf[3]=(PID1_I)&0XFF;tbuf[4]=((PID1_D)>>8)&0XFF;tbuf[5]=(PID1_D)&0XFF;tbuf[6]=((PID2_P)>>8)&0XFF;      tbuf[7]=(PID2_P)&0XFF;tbuf[8]=((PID2_I)>>8)&0XFF;tbuf[9]=(PID2_I)&0XFF;tbuf[10]=((PID2_D)>>8)&0XFF;tbuf[11]=(PID2_D)&0XFF;tbuf[12]=((PID3_P)>>8)&0XFF;      tbuf[13]=(PID3_P)&0XFF;tbuf[14]=((PID3_I)>>8)&0XFF;tbuf[15]=(PID3_I)&0XFF;tbuf[16]=((PID3_D)>>8)&0XFF;tbuf[17]=(PID3_D)&0XFF;if(Function==1)package_report_data(CAR_PID_1,tbuf,18);if(Function==2)package_report_data(CAR_PID_2,tbuf,18);if(Function==3)package_report_data(CAR_PID_1,tbuf,18);
}/**************************************************************************************************************
*函数名:ANO_CCD_SEN()
*功能:发送CCD数据
*形参:ccd:CCD数据包括(阈值,中值,左跳变,右跳变)
*返回值:无
***************************************************************************************************************/
void    ANO_CCD_SEN(void)
{static u8 tbuf[8];u16 CCD_MIDDLE,CCD_THRESHOLD,CCD_LEFT,CCD_RIGHT;CCD_MIDDLE=CCD.middle;CCD_THRESHOLD=CCD.threshold;CCD_LEFT=CCD.left;CCD_RIGHT=CCD.right;tbuf[0]=((CCD_MIDDLE)>>8)&0XFF;tbuf[1]=(CCD_MIDDLE)&0XFF;tbuf[2]=((CCD_THRESHOLD)>>8)&0XFF;tbuf[3]=(CCD_THRESHOLD)&0XFF;tbuf[4]=((CCD_LEFT)>>8)&0XFF;tbuf[5]=(CCD_LEFT)&0XFF;tbuf[6]=((CCD_RIGHT)>>8)&0XFF;tbuf[7]=(CCD_RIGHT)&0XFF;package_report_data(CAR_CCD_SEN,tbuf,8);
}/*************************************************************************************************************
*函数名:ANO_POWER()
*功能:发送电量
*形参:data:电量(0%,25%,50%,75%,100%)
*返回值:
**************************************************************************************************************/
void ANO_POWER(u16 data)
{static u8 tbuf[2];tbuf[0]=((data)>>8)&0XFF;      tbuf[1]=(data)&0XFF;package_report_data(CAR_POWER,tbuf,2);
}
/*************************************************************************************************************
*函数名:ANO_MOTO()
*功能:发送电机转速
*形参:PWM_MOTO:电机转速
*返回值:无
**************************************************************************************************************/
void ANO_MOTO(float PWM_MOTO)
{u16 PWM_Percentage;static u8 tbuf[2];PWM_Percentage=fabs(PWM_MOTO)*1.24;tbuf[0]=((PWM_Percentage)>>8)&0XFF;      tbuf[1]=(PWM_Percentage)&0XFF;package_report_data(CAR_MOTO,tbuf,2);
}
/**************************************************************************************************************
*函数名:Connect_Send_data()
*功能:发送数据给上位机
*形参:
*返回值:无
**************************************************************************************************************/
void Connect_Send_data(u8 CMD_Data)
{switch(CMD_Data){case READ_ALL_ARG://          DBG("\r发送数据到上位机\n");//                            ANO_VER(Hardware_Type,Hardware_VER,Software_VER,Protocol_VER);
//                          ANO_MOD(FS_MODE);ANO_CAR_POSE();ANO_SENSER();
//                          ANO_RCDATA(F_CMD,Movement);
//                          ANO_POWER(power);ANO_MOTO(Encoder_right);
//                          ANO_SENSER2(Distance);ANO_CCD_SEN();break;case READ_PID:DBG("\r发送PID请求\n");ANO_PID(1);break;case READ_WORK_MODE:DBG("\r发送当前模式\n");ANO_MOD(FS_MODE);break;case READ_VERINFO:DBG("\r发送版本信息\n");ANO_VER(Hardware_Type,Hardware_VER,Software_VER,Protocol_VER);break;default:break;}}/**************************************************************************************************************
*函数名:Host_Data_Receive_Anl()
*功能:上位机数据包解析
*形参:(u8 *data_buf):缓存区中的接收到的数据/(u8 num):数据包长度
*返回值:无
**************************************************************************************************************/
void Host_Data_Receive_Anl(u8 *data_buf,u8 num)
{u8 sum = 0,i;u8 function = *(data_buf+2),cmd = *(data_buf+4);//从帧头道数据位的计算校验;DBG("收到有效数据:");for(i=0;i<(num-1);i++){DBG("%x  ",*(data_buf+i));sum += *(data_buf+i);}DBG("\r\n");校验不过直接返回if(sum != *(data_buf+num-1) )       return;     //判断帧头if(!(*(data_buf)==0xAA && *(data_buf+1)==0xAF))      return; switch(function){case MOVEMENT:     DBG("设置小车动作\n");switch(cmd){case CAR_STOP:DBG("小车停止\n");if(FS_MODE==0){Contrl_Turn=64;Movement=0;}break;case CAR_FORWARD:DBG("小车前进\n");if(FS_MODE==0){Contrl_Turn=64;Movement=50;}break;case CAR_BACK:DBG("小车后退\n");if(FS_MODE==0){Contrl_Turn = 64;Movement = -50;}break;case CAR_TURN_LEFT:DBG("小车左转\n");if(FS_MODE==0){Contrl_Turn=30;Movement=0;}break;case CAR_TURN_RIGHT:DBG("小车右转\n");if(FS_MODE==0){Contrl_Turn=98;Movement=0;}break;default:break;}break;case READINFO: DBG("读取小车基本信息\n");switch(cmd){case READ_PID:DBG("读取PID数据\n");break;case READ_WORK_MODE:DBG("读取当前工作模式\n");break;case READ_VERINFO:DBG("读取版本信息\n");break;case RESTORE_DEFAULT_ARG:DBG("恢复默认参数\n");PID.Balance_Kp=200;PID.Balance_Kd=1;PID.Velocity_Kp=-60;PID.Velocity_Ki=-0.3;PID.Turn_Kp = 18;PID.Turn_Kd = 0.18;break;            default:break;} break;case SETMODE: DBG("设置小车工作模式\n");switch(cmd){case REMOTE_MODE:DBG("遥控模式\n");FS_MODE = 0;break;case AVOID_MODE:DBG("避障模式\n");FS_MODE = 1;break;case LINE_TRACK_MODE:DBG("巡线模式\n");FS_MODE = 2;break;default:break;}      break;case WRITEPID1: //上位机发送9个的16位数,*100后发送过来的,DBG("设置小车PID1\n");PID.Balance_Kp  = 0.01*( (vs16)(*(data_buf+4)<<8)|*(data_buf+5) );PID.Balance_Ki  = 0.01*( (vs16)(*(data_buf+6)<<8)|*(data_buf+7) );PID.Balance_Kd  = 0.01*( (vs16)(*(data_buf+8)<<8)|*(data_buf+9) );PID.Velocity_Kp = 0.01*( (vs16)(*(data_buf+10)<<8)|*(data_buf+11) );PID.Velocity_Ki = 0.01*( (vs16)(*(data_buf+12)<<8)|*(data_buf+13) );PID.Velocity_Kd = 0.01*( (vs16)(*(data_buf+14)<<8)|*(data_buf+15) );PID.Turn_Kp  = 0.01*( (vs16)(*(data_buf+16)<<8)|*(data_buf+17) );PID.Turn_Ki    = 0.01*( (vs16)(*(data_buf+18)<<8)|*(data_buf+19) );PID.Turn_Kd      = 0.01*( (vs16)(*(data_buf+20)<<8)|*(data_buf+21) );break;case WRITEPID2: DBG("设置小车PID2\n");break;default:break;}}/**********************************************************************************************************
*函数名:EP32_RcvData_Extract
*功能:提取ESP32中有效数据,并且将其拷贝到缓存区中
*形参:中断接收的数据
*返回值:成功返回0,失败返回1
注:数据格式命令  帧头  帧头  功能  长度  数据  校验
例:          前进  0xaa  0xaf  0x01  0x01  0x01  计算
***********************************************************************************************************/u8 EP32_RcvData_Extract(const uint8_t *Buff,int len)
{   static u8 RxBuffer[50];static int data_len = 0,data_cnt = 0;static u8 state = 0;u8 i, data;for(i=0;i<len ;i++){data = Buff[i];//判断帧头      if(state==0&&data==0xAA){state=1;RxBuffer[0]=data;}else if(state==1&&data==0xAF){state=2;RxBuffer[1]=data;}//功能字截止到0XF1else if(state==2&&data<0XF1){state=3;RxBuffer[2]=data;}//数据长度小于50else if(state==3&&data<50){state = 4;RxBuffer[3]=data;data_len = data;data_cnt = 0;}//将数据复制到RxBuffer中else if(state==4&&data_len>0){data_len--;RxBuffer[4+data_cnt++]=data;if(data_len==0)state = 5;}//计算校验值else if(state==5){state = 0;RxBuffer[4+data_cnt]=data;Host_Data_Receive_Anl(RxBuffer,data_cnt+5);memset(RxBuffer,0,50);return 0;}}return 1;
}

oled 显示置入屏幕显示小车状态

096 oled 已经不陌生了,都已经使用很多次了。iic 数据传输。

  1. oled 显示电路


2. 按键原理图

  1. 蜂鸣器 电气原理图

  2. 电池adc接口 电气原理图

开始配置工程

cube工程配置端口


输出数据到oled 屏幕


控制板需要接收按键按下电平,所以设置输入模式


oled 管脚设置输出模式

蜂鸣器一样设置输出模式

ok 导出工程打开keil5 开始编辑程序

四、stm32项目平衡车项目下载源码

本文章学习借鉴于创客学院团队,以表感谢。教学视频
资源是免费下载的,点击下载即可


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

stm32项目平衡车详解(stm32F407)下相关推荐

  1. maven 与intellij IDEA 下maven 为groovy 项目生成jar 详解

    2019独角兽企业重金招聘Python工程师标准>>> W7下安装 maven与intellij IDEA 下maven为groovy项目生成jar详解(适合新手) 第一步:下载ma ...

  2. Python实战项目:高血压项目详解(下)

    Python实战项目 高血压项目详解(下) 四.爬虫 数据来源      ⇒   有关高血压文章.文献.论文--外国网站  爬取翻译      ⇒   爬取文章(高血压--Hypertension)+ ...

  3. Git学习系列之Git基本操作提交项目(图文详解)

    前面博客 Git学习系列之Git基本操作克隆项目(图文详解) 然后可以 cd 切换到 LispGentleIntro 目录, 新增或者修改某些文件.这里只是模拟一下操作, 实际情况可能是 使用 Ecl ...

  4. STM32—— AHB、APB详解

     STM32-- AHB.APB详解 2016-07-14 20:35 590人阅读 评论(0) 收藏 举报 本文章已收录于: 版权声明:本文为博主原创文章,未经博主允许不得转载. 一.概括 首先 ...

  5. AVL树平衡旋转详解

    AVL树平衡旋转详解 概述 AVL树又叫做平衡二叉树.前言部分我也有说到,AVL树的前提是二叉排序树(BST或叫做二叉查找树).由于在生成BST树的过程中可能会出现线型树结构,比如插入的顺序是:1, ...

  6. angular 标准目录结构_Angular-cli新建项目目录结构详解

    Angular-cli新建项目目录结构详解 在上一篇博客中我们已经通过Angular CLI命令行工具创建出来一个全新的Angular项目,要想写项目,首先我们要先搞清楚项目的目录结构是怎样的,每个文 ...

  7. 怎么创建python django项目_创建Django项目图文实例详解

    本文实例讲述了创建Django项目的方法.分享给大家供大家参考,具体如下: 创建Django项目 创建一个HelloDjango项目 GitHub地址:https://github.com/liang ...

  8. docker 打包部署 python项目_Docker如何部署Python项目的实现详解

    Docker 是一个开源项目,为开发人员和系统管理员提供了一个开放平台,可以将应用程序构建.打包为一个轻量级容器,并在任何地方运行.Docker 会在软件容器中自动部署应用程序. 在本篇中,我将介绍如 ...

  9. STM32开发 -- 低功耗模式详解

    很多单片机都有低功耗模式,STM32 也不例外.当 CPU 不需继续运行时,可以利用多个低功耗模式来节省功耗. 这部分不是我负责,但是也是有必要看一下的. 参看: STM32F1开发指南-库函数版本_ ...

最新文章

  1. 使用Java创建内存泄漏
  2. 针对远程主机认证生成并使用 SSH 密钥
  3. 【郭林专刊】MVC已过时,MOVE时代来临?
  4. 我们计划招收300名学员,免费攻读人工智能专业!
  5. None.org.apache.spark.api.python.PythonAccumulatorV2
  6. php将图片导入,php中图片文件的导入,上传与下载
  7. Spring事务—方法调用事务回滚
  8. Volcano:带你体验容器与批量计算的碰撞的火花
  9. mathtype2022数学公式编辑器快捷键及操作技巧分享教程
  10. 论文查重 降重复度?如何进行毕业论文查重--总结贴
  11. iOS 15 越狱情报
  12. 教育培训行业的SOP
  13. 重装电脑?先来个PE盘!
  14. cannot be cast to com.baomidou.mybatisplus.core.metadata.IPage
  15. flink生成Watermark之WatermarkStrategy
  16. msr830设置虚拟服务器,h3c msr830设置教程
  17. Jetpack Compose——Scaffold(脚手架)、SnackBar(通知,类似Toast)的简单使用
  18. ZEMAX | 室内照明案例分享2 —— 室内场景模拟
  19. AcWing 有向图的拓补排序 题解 (拓补排序 模板)
  20. 阿里云ACE 同城 活动 总结

热门文章

  1. 马云曾经偶像,终于把阿里留下的 1400 亿败光了!
  2. psychopy_免费和有用的软件– PsychoPy
  3. dz论坛php5,S!淘专辑 3.0.1 For php5.2 php5.3版 dz插件分享,淘专辑是用户将喜欢的论坛帖子...
  4. Unity中EnableDisableComponent的用法
  5. Linux——磁盘Part 4:磁盘阵列(raid0、raid1、raid5、raid6、raid1+0)
  6. Vue 中 keep-alive 组件与 router-view 组件的那点事
  7. 深入浅出 - Android系统移植与平台开发(五)- 定制手机模拟器ROM
  8. Sailfish OS 2.0之初体验
  9. 视频教程- 项目管理工具(1) WBS-工作分解结构-研发管理
  10. 【kimol君的无聊小发明】—用python写PDF转换器