598网站建设,外贸网站特效,成立公司怎么做网站,关于营销策划的方案这个是全网最详细的STM32项目教学视频。 第一篇在这里: 视频在这里 STM32智能小车V3-STM32入门教程-openmv与STM32循迹小车-stm32f103c8t6-电赛 嵌入式学习 PID控制算法 编码器电机 跟随 第18章-综合以上功能
18-按键和app按钮切换功能
根据上面介绍#xff0c;我们的模式可…这个是全网最详细的STM32项目教学视频。 第一篇在这里: 视频在这里 STM32智能小车V3-STM32入门教程-openmv与STM32循迹小车-stm32f103c8t6-电赛 嵌入式学习 PID控制算法 编码器电机 跟随 第18章-综合以上功能
18-按键和app按钮切换功能
根据上面介绍我们的模式可以有
**OLED显示模式: 速度、里程、电压、超声波数据、MPU6050俯仰角、横滚角、航向角 数据显示在OLED上和通过串口发送蓝牙APP **
PID循迹模式:红外对管PID循迹
手机遥控普通运动模式:遥控前、后、左、右加速运动
超声波避障模式
PID跟随模式:超声波PID定距离跟随
手机遥控角度闭环模式MPU6050角度PID控制
可以设置标志位通过按键改变标志位以实现功能切换。
定义一个全局变量
uint8_t g_ucMode 0;
//小车运动模式标志位 0:显示功能、1:PID循迹模式、2:手机遥控普通运动模式、3.超声波避障模式、4:PID跟随模式、5:遥控角度闭环uint8_t g_ucMode 0; //小车运动模式标志位在gpio.h声明一下 extern uint8_t g_ucMode ; //小车运动模式标志位按键中断回调函数里面补充按下按键后的处理
先不进行消抖如果后面KEY1 KEY2效果不好再消抖
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin KEY1_Pin) //判断一下那个引脚触发中断{//这里编写触发中断后要执行的程序if(g_ucMode 5) g_ucMode 1;//g_ucMode模式是0 1 2 3 4 5 else{g_ucMode1;}HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);}if(GPIO_Pin KEY2_Pin) //判断一下那个引脚触发中断{//这里编写触发中断后要执行的程序g_ucMode0;HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);}
}然后主函数显示当前处于的模式
然后判断当前模式 执行不同代码
方法一个功能一个功能的添加代码添加好一个调试测试一下然后再添加下一个
下面这个就是我们主函数的代码。 sprintf((char *)OledString, g_ucMode:%d,g_ucMode);//显示g_ucMode 当前模式OLED_ShowString(0,6,OledString,12); //显示在OLED上sprintf((char *)Usart3String, g_ucMode:%d,g_ucMode);//蓝牙APP显示HAL_UART_Transmit(huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小if(g_ucMode 0){//0LED显示功能sprintf((char*)OledString, V1:%.2fV2:%.2f, Motor1Speed,Motor2Speed);//显示速度OLED_ShowString(0,0,OledString,12);//这个是oled驱动里面的是显示位置的一个函数sprintf((char*)OledString, Mileage:%.2f, Mileage);//显示里程OLED_ShowString(0,1,OledString,12);//这个是oled驱动里面的是显示位置的一个函数sprintf((char*)OledString, U:%.2fV, adcGetBatteryVoltage());//显示电池电压OLED_ShowString(0,2,OledString,12);//这个是oled驱动里面的是显示位置的一个函数sprintf((char *)OledString,HC_SR04:%.2fcm\r\n,HC_SR04_Read());//显示超声波数据OLED_ShowString(0,3,OledString,12);//这个是oled驱动里面的是显示位置的一个函数sprintf((char *)OledString,p:%.2f r:%.2f \r\n,pitch,roll);//显示6050数据 俯仰角 横滚角OLED_ShowString(0,4,OledString,12);//这个是oled驱动里面的是显示位置的一个函数sprintf((char *)OledString,y:%.2f \r\n,yaw);//显示6050数据 航向角OLED_ShowString(0,5,OledString,12);//这个是oled驱动里面的是显示位置的一个函数//蓝牙APP显示sprintf((char*)Usart3String, V1:%.2fV2:%.2f, Motor1Speed,Motor2Speed);//显示速度HAL_UART_Transmit(huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小//阻塞方式发送可以保证数据发送完毕中断发送不一定可以保证数据已经发送完毕才启动下一次发送sprintf((char*)Usart3String, Mileage:%.2f, Mileage);//显示里程HAL_UART_Transmit(huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小sprintf((char*)Usart3String, U:%.2fV, adcGetBatteryVoltage());//显示电池电压HAL_UART_Transmit(huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小sprintf((char *)Usart3String,HC_SR04:%.2fcm\r\n,HC_SR04_Read());//显示超声波数据HAL_UART_Transmit(huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小sprintf((char *)Usart3String,p:%.2f r:%.2f \r\n,pitch,roll);//显示6050数据 俯仰角 横滚角HAL_UART_Transmit(huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小sprintf((char *)Usart3String,y:%.2f \r\n,yaw);//显示6050数据 航向角HAL_UART_Transmit(huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小//获得6050数据while(mpu_dmp_get_data(pitch,roll,yaw)!0){} //这个可以解决经常读不出数据的问题//显示模式电机停转motorPidSetSpeed(0,0);}if(g_ucMode 1){///**** 红外PID循迹功能******************/g_ucaHW_Read[0] READ_HW_OUT_1;//读取红外对管状态、这样相比于写在if里面更高效g_ucaHW_Read[1] READ_HW_OUT_2;g_ucaHW_Read[2] READ_HW_OUT_3;g_ucaHW_Read[3] READ_HW_OUT_4;if(g_ucaHW_Read[0] 0g_ucaHW_Read[1] 0g_ucaHW_Read[2] 0g_ucaHW_Read[3] 0 ){
// printf(应该前进\r\n);//注释掉更加高效减少无必要程序执行g_cThisState 0;//前进}else if(g_ucaHW_Read[0] 0g_ucaHW_Read[1] 1g_ucaHW_Read[2] 0g_ucaHW_Read[3] 0 )//使用else if更加合理高效{
// printf(应该右转\r\n);g_cThisState -1;//应该右转}else if(g_ucaHW_Read[0] 1g_ucaHW_Read[1] 0g_ucaHW_Read[2] 0g_ucaHW_Read[3] 0 ){
// printf(快速右转\r\n);g_cThisState -2;//快速右转}else if(g_ucaHW_Read[0] 1g_ucaHW_Read[1] 1g_ucaHW_Read[2] 0g_ucaHW_Read[3] 0){
// printf(快速右转\r\n);g_cThisState -3;//快速右转}else if(g_ucaHW_Read[0] 0g_ucaHW_Read[1] 0g_ucaHW_Read[2] 1g_ucaHW_Read[3] 0 ){
// printf(应该左转\r\n);g_cThisState 1;//应该左转 }else if(g_ucaHW_Read[0] 0g_ucaHW_Read[1] 0g_ucaHW_Read[2] 0g_ucaHW_Read[3] 1 ){
// printf(快速左转\r\n);g_cThisState 2;//快速左转}else if(g_ucaHW_Read[0] 0g_ucaHW_Read[1] 0g_ucaHW_Read[2] 1g_ucaHW_Read[3] 1){
// printf(快速左转\r\n);g_cThisState 3;//快速左转}g_fHW_PID_Out PID_realize(pidHW_Tracking,g_cThisState);//PID计算输出目标速度 这个速度会和基础速度加减g_fHW_PID_Out1 3 g_fHW_PID_Out;//电机1速度基础速度循迹PID输出速度g_fHW_PID_Out2 3 - g_fHW_PID_Out;//电机1速度基础速度-循迹PID输出速度if(g_fHW_PID_Out1 5) g_fHW_PID_Out1 5;//进行限幅 限幅速度在0-5之间if(g_fHW_PID_Out1 0) g_fHW_PID_Out1 0;if(g_fHW_PID_Out2 5) g_fHW_PID_Out2 5;if(g_fHW_PID_Out2 0) g_fHW_PID_Out2 0;if(g_cThisState ! g_cLastState)//如何这次状态不等于上次状态、就进行改变目标速度和控制电机、在定时器中依旧定时控制电机{motorPidSetSpeed(g_fHW_PID_Out1,g_fHW_PID_Out2);//通过计算的速度控制电机}g_cLastState g_cThisState;//保存上次红外对管状态 }if(g_ucMode 2){//***************遥控模式***********************////遥控模式的控制在串口三的中断里面}if(g_ucMode 3){//******超声波避障模式*********************//
避障逻辑if(HC_SR04_Read() 25)//前方无障碍物{motorPidSetSpeed(1,1);//前运动HAL_Delay(100);}else{ //前方有障碍物motorPidSetSpeed(-1,1);//右边运动 原地 HAL_Delay(500);if(HC_SR04_Read() 25)//右边无障碍物{motorPidSetSpeed(1,1);//前运动HAL_Delay(100);}else{//右边有障碍物motorPidSetSpeed(1,-1);//左边运动 原地HAL_Delay(1000);if(HC_SR04_Read() 25)//左边无障碍物{motorPidSetSpeed(1,1);//前运动HAL_Delay(100);}else{motorPidSetSpeed(-1,-1);//后运动HAL_Delay(1000);motorPidSetSpeed(-1,1);//右边运动HAL_Delay(50);}}}}if(g_ucMode 4){//**********PID跟随功能***********//g_fHC_SR04_ReadHC_SR04_Read();//读取前方障碍物距离if(g_fHC_SR04_Read 60){ //如果前60cm 有东西就启动跟随g_fFollow_PID_Out PID_realize(pidFollow,g_fHC_SR04_Read);//PID计算输出目标速度 这个速度会和基础速度加减if(g_fFollow_PID_Out 6) g_fFollow_PID_Out 6;//对输出速度限幅if(g_fFollow_PID_Out -6) g_fFollow_PID_Out -6;motorPidSetSpeed(g_fFollow_PID_Out,g_fFollow_PID_Out);//速度作用与电机上}else motorPidSetSpeed(0,0);//如果前面60cm 没有东西就停止HAL_Delay(10);//读取超声波传感器不能过快}if(g_ucMode 5){//*************MPU6050航向角 PID转向控制*****************//sprintf((char *)Usart3String,pitch:%.2f roll:%.2f yaw:%.2f\r\n,pitch,roll,yaw);//显示6050数据 俯仰角 横滚角 航向角HAL_UART_Transmit(huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),0xFFFF);//通过串口三输出字符 strlen:计算字符串大小 //mpu_dmp_get_data(pitch,roll,yaw);//返回值:0,DMP成功解出欧拉角while(mpu_dmp_get_data(pitch,roll,yaw)!0){} //这个可以解决经常读不出数据的问题g_fMPU6050YawMovePidOut PID_realize(pidMPU6050YawMovement,yaw);//PID计算输出目标速度 这个速度会和基础速度加减g_fMPU6050YawMovePidOut1 1.5 g_fMPU6050YawMovePidOut;//基础速度加减PID输出速度g_fMPU6050YawMovePidOut2 1.5 - g_fMPU6050YawMovePidOut;if(g_fMPU6050YawMovePidOut1 3.5) g_fMPU6050YawMovePidOut1 3.5;//进行限幅if(g_fMPU6050YawMovePidOut1 0) g_fMPU6050YawMovePidOut1 0;if(g_fMPU6050YawMovePidOut2 3.5) g_fMPU6050YawMovePidOut2 3.5;if(g_fMPU6050YawMovePidOut2 0) g_fMPU6050YawMovePidOut2 0;motorPidSetSpeed(g_fMPU6050YawMovePidOut1,g_fMPU6050YawMovePidOut2);}可以测试上面的代码 然后没有问题后我们添加一个通过蓝牙APP按钮切换模式代码 if(g_ucUsart3ReceiveData J) //改变模式{if(g_ucMode 5) g_ucMode 1;//g_ucMode模式是0 1 2 3 4 5 else{g_ucMode1;}}if(g_ucUsart3ReceiveData K) g_ucMode0;//设置为显示模式然后对应APP也要添加 按钮设置 我们 按键没有消抖效果不好我们消抖一下 我们增加了 HAL延时和再次判断电平
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin KEY1_Pin) //判断一下那个引脚触发中断{HAL_Delay(10);//延时消抖 主要if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) GPIO_PIN_SET)//判断KEY1引脚仍为高电平{//这里编写触发中断后要执行的程序if(g_ucMode 5) g_ucMode 1;//g_ucMode模式是0 1 2 3 4 5 else{g_ucMode1;}HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);}}if(GPIO_Pin KEY2_Pin) //判断一下那个引脚触发中断{HAL_Delay(10);//延时消抖if(HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) GPIO_PIN_RESET)//判断KEY2引脚仍为低电平{//这里编写触发中断后要执行的程序g_ucMode0;HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);}}
}
但是测试不能执行中断程序异常卡死了
原因是HAL_Delay使用的是sysTick 中断优先级在软件初始化是默认最低的比外部中断优先级低所以HAL_Delay不能在外部中断服务函数中调用。
所以我们可以通过提高sysTick 中断的优先级提高的比HAL_Delay高。 然后我们提高至 如下图 然后编译烧录测试按键是否更加稳定。 下面的章节我们讲解视觉RTOS系统电磁循迹等功能