stm32项目平衡车详解(stm32F407)下
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*/
通讯协议的制定
- 引入范例文件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 数据传输。
- oled 显示电路
2. 按键原理图
蜂鸣器 电气原理图
电池adc接口 电气原理图
开始配置工程
cube工程配置端口
输出数据到oled 屏幕
控制板需要接收按键按下电平,所以设置输入模式
oled 管脚设置输出模式
蜂鸣器一样设置输出模式
ok 导出工程打开keil5 开始编辑程序
四、stm32项目平衡车项目下载源码
本文章学习借鉴于创客学院团队,以表感谢。教学视频
资源是免费下载的,点击下载即可
上一节,stm32项目平衡车详解(stm32F407)上
stm32项目平衡车详解(stm32F407)下相关推荐
- maven 与intellij IDEA 下maven 为groovy 项目生成jar 详解
2019独角兽企业重金招聘Python工程师标准>>> W7下安装 maven与intellij IDEA 下maven为groovy项目生成jar详解(适合新手) 第一步:下载ma ...
- Python实战项目:高血压项目详解(下)
Python实战项目 高血压项目详解(下) 四.爬虫 数据来源 ⇒ 有关高血压文章.文献.论文--外国网站 爬取翻译 ⇒ 爬取文章(高血压--Hypertension)+ ...
- Git学习系列之Git基本操作提交项目(图文详解)
前面博客 Git学习系列之Git基本操作克隆项目(图文详解) 然后可以 cd 切换到 LispGentleIntro 目录, 新增或者修改某些文件.这里只是模拟一下操作, 实际情况可能是 使用 Ecl ...
- STM32—— AHB、APB详解
STM32-- AHB.APB详解 2016-07-14 20:35 590人阅读 评论(0) 收藏 举报 本文章已收录于: 版权声明:本文为博主原创文章,未经博主允许不得转载. 一.概括 首先 ...
- AVL树平衡旋转详解
AVL树平衡旋转详解 概述 AVL树又叫做平衡二叉树.前言部分我也有说到,AVL树的前提是二叉排序树(BST或叫做二叉查找树).由于在生成BST树的过程中可能会出现线型树结构,比如插入的顺序是:1, ...
- angular 标准目录结构_Angular-cli新建项目目录结构详解
Angular-cli新建项目目录结构详解 在上一篇博客中我们已经通过Angular CLI命令行工具创建出来一个全新的Angular项目,要想写项目,首先我们要先搞清楚项目的目录结构是怎样的,每个文 ...
- 怎么创建python django项目_创建Django项目图文实例详解
本文实例讲述了创建Django项目的方法.分享给大家供大家参考,具体如下: 创建Django项目 创建一个HelloDjango项目 GitHub地址:https://github.com/liang ...
- docker 打包部署 python项目_Docker如何部署Python项目的实现详解
Docker 是一个开源项目,为开发人员和系统管理员提供了一个开放平台,可以将应用程序构建.打包为一个轻量级容器,并在任何地方运行.Docker 会在软件容器中自动部署应用程序. 在本篇中,我将介绍如 ...
- STM32开发 -- 低功耗模式详解
很多单片机都有低功耗模式,STM32 也不例外.当 CPU 不需继续运行时,可以利用多个低功耗模式来节省功耗. 这部分不是我负责,但是也是有必要看一下的. 参看: STM32F1开发指南-库函数版本_ ...
最新文章
- 使用Java创建内存泄漏
- 针对远程主机认证生成并使用 SSH 密钥
- 【郭林专刊】MVC已过时,MOVE时代来临?
- 我们计划招收300名学员,免费攻读人工智能专业!
- None.org.apache.spark.api.python.PythonAccumulatorV2
- php将图片导入,php中图片文件的导入,上传与下载
- Spring事务—方法调用事务回滚
- Volcano:带你体验容器与批量计算的碰撞的火花
- mathtype2022数学公式编辑器快捷键及操作技巧分享教程
- 论文查重 降重复度?如何进行毕业论文查重--总结贴
- iOS 15 越狱情报
- 教育培训行业的SOP
- 重装电脑?先来个PE盘!
- cannot be cast to com.baomidou.mybatisplus.core.metadata.IPage
- flink生成Watermark之WatermarkStrategy
- msr830设置虚拟服务器,h3c msr830设置教程
- Jetpack Compose——Scaffold(脚手架)、SnackBar(通知,类似Toast)的简单使用
- ZEMAX | 室内照明案例分享2 —— 室内场景模拟
- AcWing 有向图的拓补排序 题解 (拓补排序 模板)
- 阿里云ACE 同城 活动 总结
热门文章
- 马云曾经偶像,终于把阿里留下的 1400 亿败光了!
- psychopy_免费和有用的软件– PsychoPy
- dz论坛php5,S!淘专辑 3.0.1 For php5.2 php5.3版 dz插件分享,淘专辑是用户将喜欢的论坛帖子...
- Unity中EnableDisableComponent的用法
- Linux——磁盘Part 4:磁盘阵列(raid0、raid1、raid5、raid6、raid1+0)
- Vue 中 keep-alive 组件与 router-view 组件的那点事
- 深入浅出 - Android系统移植与平台开发(五)- 定制手机模拟器ROM
- Sailfish OS 2.0之初体验
- 视频教程- 项目管理工具(1) WBS-工作分解结构-研发管理
- 【kimol君的无聊小发明】—用python写PDF转换器