2019 电子设计大赛 激光炮题目 写的程序
代码:
main.c
#include "stm32f4xx.h"
#include "usart_all.h"
#include "stdio.h"
#include "math.h"
#include "delay.h"
#include "hmi.h" //串口屏相关
#include "servo.h" //舵机控制
#include "shoot.h" //充电/发射控制
#include "laser.h" //激光测距
#include "redtube.h"//红外对管
#include "camera.h" //摄像头openMV
#include "speak.h" //语音模块
s16 distance_goal = 0, anglex_x_goal = 0;
/*主状态机状态定义 */
#define MODE0_WaitInput 0x00
#define MODE1_HandShoot 0x01
#define MODE2_AutoShoot 0x02
#define MODE3_ScanShoot 0x03
#define MODE4_Calibration 0x04
u8 STATE_Main = MODE0_WaitInput;
/*主状态机状态函数声明 */
void Mode1_HandShoot(void);
void Mode2_AutoShoot(void);
void Mode3_ScanShoot(void);
/*二级状态机状态定义 */
#define MODE40_Calibration_WaitInput 0x40
#define MODE41_Calibration_Camera 0x41
#define MODE42_Calibration_Laser 0x42
#define MODE43_Calibration_Volage 0x43
#define MODE44_Calibration_Exit 0x44
u8 STATE_Mode4 = MODE40_Calibration_WaitInput;
/*二级状态机状态函数声明 */
void Mode41_Calibration_Camera(void);
void Mode42_Calibration_Laser(void);
void Mode43_Calibration_Volage(void);
void Mode44_Calibration_Exit(void);
void LED_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
//静态充电GPIO PA1、放电GPIO PA2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);
}
//pc0
void LED_Light(void) {
PCout(0) = 0;
}
void LED_Dark(void) {
PCout(0) = 1;
}
int main(void) {
u8 mode4_end = 0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
delay_init(168); //初始化延时函数
delay_ms(1000);
HMI_Init(); //串口屏初始化
delay_ms(5);
HMI_sendCmdEnd();
HMI_SendCmd("page modemenu");
SERVO_Init(); //舵机初始化
SHOOT_Init(); //充电发射系统初始化,1000ms充电时长
LASER_Init(); //激光测距模块初始化
REDTUBE_Init();//红外对管初始化
CAMERA_Init(); //摄像头openMV初始化
SPEAK_Init(); //语音模块初始化
LED_Init();
LED_Dark();
while(1){
switch (STATE_Main)
{
/*状态0:等待状态选择,1或2 */
case MODE0_WaitInput:
HMI_GetMode(&STATE_Main); //直至获得状态成功才退出该语句
break;
/*状态1:选择功能1,手动输入距离角度 */
case MODE1_HandShoot:
SPEAK_Display(1); //语音播报
SERVO_X_SetAngle(0); //设置云台初始x角度为0°
SERVO_Y_SetPWM(Servo_Y_ccr_pos0);//设置云台初始y角度为0°
HMI_GetAngleAndDis(&anglex_x_goal ,&distance_goal);
while(!HMI_CheckShootStart());//等待串口屏发射命令
SPEAK_Display(5); //语音播报“一键启动”
Mode1_HandShoot(); //执行发射函数
delay_ms(1000);
SPEAK_Display(6); //语音播报“发射完成”
while(!HMI_CheckBack()); //等待串口屏返回命令
SERVO_X_SetAngle(0); //设置云台初始x角度为0°
SERVO_Y_SetPWM(Servo_Y_ccr_pos0);//设置云台初始y角度为0°
HMI_sendCmdEnd();
HMI_SendCmd("page modemenu"); //串口屏返回主页面,同时反应程序是否正常
HMI_ClearRX(); //清空串口屏错误返回信息
STATE_Main = MODE0_WaitInput; //切换回主状态
break;
/*状态2:选择功能2,自动找目标,停止后射击 */
case MODE2_AutoShoot:
SPEAK_Display(2); //语音播报
SERVO_X_SetAngle(0); //设置云台初始x角度为0°
SERVO_Y_SetPWM(Servo_Y_ccr_pos0);//设置云台初始y角度为0°
while(!HMI_CheckShootStart());//等待串口屏发射命令
SPEAK_Display(5); //语音播报“一键启动”
Mode2_AutoShoot(); //执行发射函数
delay_ms(1000);
SPEAK_Display(6); //语音播报“发射完成”
while(!HMI_CheckBack()); //等待串口屏返回命令
SERVO_X_SetAngle(0); //设置云台初始x角度为0°
SERVO_Y_SetPWM(Servo_Y_ccr_pos0);//设置云台初始y角度为0°
HMI_sendCmdEnd();
HMI_SendCmd("page modemenu"); //串口屏返回主页面,同时反应程序是否正常
HMI_ClearRX(); //清空串口屏错误返回信息
STATE_Main = MODE0_WaitInput; //切换回主状态
break;
/*状态3:选择功能3,自动找目标,不停止后射击 */
case MODE3_ScanShoot:
SPEAK_Display(3); //语音播报
LED_Dark();
SERVO_X_SetAngle(-30); //设置云台初始x角度为-30°
SERVO_Y_SetPWM(Servo_Y_ccr_pos0);//设置云台初始y角度为0°
while(!HMI_CheckShootStart());//等待串口屏发射命令
SPEAK_Display(5); //语音播报“一键启动”
Mode3_ScanShoot(); //执行发射函数
delay_ms(1000);
SPEAK_Display(6); //语音播报“发射完成”
while(!HMI_CheckBack()); //等待串口屏返回命令
SERVO_X_Scan_End(); //扫描结束
SERVO_X_SetAngle(0); //设置云台初始x角度为0°
SERVO_Y_SetPWM(Servo_Y_ccr_pos0);//设置云台初始y角度为0°
HMI_sendCmdEnd();
HMI_SendCmd("page modemenu"); //串口屏返回主页面,同时反应程序是否正常
HMI_ClearRX(); //清空串口屏错误返回信息
STATE_Main = MODE0_WaitInput; //切换回主状态
break;
/*状态4:校准模式 */
case MODE4_Calibration:
SPEAK_Display(4); //语音播报
STATE_Mode4 = MODE40_Calibration_WaitInput;
SERVO_X_SetAngle(0); //设置云台初始x角度为0°
SERVO_Y_SetPWM(Servo_Y_ccr_pos0);//设置云台初始y角度为0°
mode4_end = 0;
while(1) {
switch(STATE_Mode4) {
/*状态40:校准模式--等待输入校准对象 */
case MODE40_Calibration_WaitInput:
HMI_GetMode(&STATE_Mode4); //直至获得状态成功才退出该语句
break;
/*状态41:校准模式--校准摄像头 */
case MODE41_Calibration_Camera:
SERVO_X_SetAngle(0); //设置云台初始x角度为0°
SERVO_Y_SetPWM(Servo_Y_ccr_pos0);//设置云台初始y角度为0°
HMI_sendCmdEnd();
HMI_SendCmd("page camera_sample"); //串口屏进入配置页面,同时反应程序是否正常
//状态机函数
Mode41_Calibration_Camera();
//状态机函数擦屁股
CAMERA_ClearRX();
HMI_sendCmdEnd();
HMI_SendCmd("page calibration"); //串口屏返回校准选择页面,同时反应程序是否正常
HMI_ClearRX(); //清空串口屏错误返回信息
STATE_Mode4 = MODE40_Calibration_WaitInput; //二级状态--校准模式 停留在等待输入校准对象
break;
/*状态42:校准模式--校准激光器 */
case MODE42_Calibration_Laser:
SERVO_X_SetAngle(0); //设置云台初始x角度为0°
SERVO_Y_SetPWM(Servo_Y_ccr_pos0);//设置云台初始y角度为0°
HMI_sendCmdEnd();
HMI_SendCmd("page laser"); //串口屏进入配置页面,同时反应程序是否正常
//状态机函数
Mode42_Calibration_Laser();
while(!HMI_CheckBack()); //等待串口屏返回命令
//状态机函数擦屁股
SERVO_X_Scan_End();
LASER_Open_Light(0);
delay_ms(500);
HMI_sendCmdEnd();
HMI_SendCmd("page calibration"); //串口屏返回校准选择页面,同时反应程序是否正常
HMI_ClearRX(); //清空串口屏错误返回信息
STATE_Mode4 = MODE40_Calibration_WaitInput; //二级状态--校准模式 停留在等待输入校准对象
break;
/*状态43:校准模式--校准动态充电稳压 */
case MODE43_Calibration_Volage:
SERVO_X_SetAngle(0); //设置云台初始x角度为0°
SERVO_Y_SetPWM(Servo_Y_ccr_pos0);//设置云台初始y角度为0°
HMI_sendCmdEnd();
HMI_SendCmd("page charge"); //串口屏进入配置页面,同时反应程序是否正常
//状态机函数
Mode43_Calibration_Volage();
while(!HMI_CheckBack()); //等待串口屏返回命令
//状态机函数擦屁股
HMI_sendCmdEnd();
HMI_SendCmd("page calibration"); //串口屏返回校准选择页面,同时反应程序是否正常
HMI_ClearRX(); //清空串口屏错误返回信息
STATE_Mode4 = MODE40_Calibration_WaitInput; //二级状态--校准模式 停留在等待输入校准对象
break;
/*状态44:退出校准模式 */
case MODE44_Calibration_Exit:
SERVO_X_SetAngle(0); //设置云台初始x角度为0°
SERVO_Y_SetPWM(Servo_Y_ccr_pos0);//设置云台初始y角度为0°
mode4_end = 1;
break;
//其他状态
default:
mode4_end = 1;
break;
}
if(mode4_end == 1) {
break;
}
}
HMI_sendCmdEnd();
HMI_SendCmd("page modemenu"); //串口屏返回主页面,同时反应程序是否正常
HMI_ClearRX(); //清空串口屏错误返回信息
STATE_Main = MODE0_WaitInput; //切换回主状态
break;
//其他状态
default:
HMI_sendCmdEnd();
HMI_SendCmd("page modemenu");
HMI_ClearRX();
STATE_Main = MODE0_WaitInput;
break;
}
}
}
void Mode1_HandShoot(void) {
SHOOT_Elec_Enable(); //开始充电
SERVO_X_SetAngle(anglex_x_goal); //控制水平舵机
SERVO_Y_SetDistance(distance_goal, anglex_x_goal); //控制垂直舵机
delay_ms(1000); //等待舵机就位
while(!SHOOT_CheckElec()); //等待充电完成
SHOOT_Go();
}
void Mode2_AutoShoot(void) {
u16 distance = 200;
u16 goal_pwm = 0;
s8 goal_erro = 60;
u8 p = 10;
u8 i;
u8 times = 0;
SERVO_X_SetAngle(-30); //云台y方向设置为瞄准250cm
SHOOT_Elec_Enable(); //开始充电
delay_ms(2000);
CAMERA_ClearRX(); //清除之前openMV发送的数据
delay_ms(10);
//获得角度的循环
while(1) {
CAMERA_Get_GoalErro(&goal_erro); //获取最近数据
if(abs(goal_erro)>30) { //摄像头返回目标差距较大,粗调
SERVO_X_ChangeAngle(goal_erro);
delay_ms(abs(goal_erro)*p);
} else { //摄像头返回目标差距较小,细调
SERVO_X_ChangeAngle(goal_erro>0?1:(-1)); //线性改变pwm,步进为1
delay_ms(20);
times++;
if(abs(goal_erro)<=0) { //摄像头返回目标差距小于等于1
goal_pwm = Servo_X_ccr_Laster; //记住摄像头瞄准时的pwm
break; //跳出获得角度循环
}
if(times > 8) {
if(abs(goal_erro)<=1) { //摄像头返回目标差距小于等于1
goal_pwm = Servo_X_ccr_Laster; //记住摄像头瞄准时的pwm
break; //跳出获得角度循环
}
}
}
if(Servo_X_ccr_Laster>Servo_X_ccr_pos30) {
//从-30°到30°没找到,就返回转
goal_erro = -goal_erro;
} else if(Servo_X_ccr_Laster < Servo_X_ccr_neg30) {
//从30°到-30°没找到,就返回转
goal_erro = -goal_erro;
}
}
//获得距离的循环
LASER_get_distance(&distance); //获得引导标识的距离
distance = distance - 30; //获得靶心的距离
if(distance > 190 && distance < 310) {
//获得距离成功
} else {
// //获得距离失败
// for(i=0; i<20; i++) {
// SERVO_X_SetPWM(goal_pwm-20+i*2); //设置角度
// delay_ms(400);
// LASER_get_distance(&distance); //获得引导标识的距离
// distance = distance - 30; //获得靶心的距离
// if(distance > 190 && distance < 310) {
// //获得距离成功
// break;
// }
// }
distance = 250;
}
// SERVO_X_SetPWM(goal_pwm-5); //设置角度
// if(Servo_X_ccr_Laster>Servo_X_ccr_pos0) {
// SERVO_X_ChangeAngle(-2);
// }
SERVO_Y_SetDistance(distance, SERVO_X_PWM2Angle(goal_pwm)); //设置高度
delay_ms(1000); //等待建立
while(!SHOOT_CheckElec()); //等待充电完成
SHOOT_Go(); //发射炮弹
}
void Mode3_ScanShoot(void) {
s8 goal_erro = 30;
u8 delta1 = 1;
u8 delta2 = 13;
LED_Dark();
SHOOT_Elec_Enable(); //开始充电
SERVO_Y_SetDistance(250, 0); //云台y方向设置为瞄准250cm
SERVO_X_Scan_Start(Angle2PWMX[-30+30]-18, Angle2PWMX[30+30]+18, 2, 1, 1);
CAMERA_ClearRX(); //清除之前openMV发送的数据
while(!SHOOT_CheckElec());//直至充满电
while(1) {
CAMERA_Get_GoalErro(&goal_erro);
if(Servo_X_ccr_Laster>Angle2PWMX[0+30]) {
//转到左半部分
LED_Light();
if(abs(goal_erro)<=delta1) {
LED_Light();
SHOOT_Go();
LED_Dark();
break;
} else if(Servo_X_ccr_Laster>Angle2PWMX[28+30]) {
if(abs(goal_erro)<=delta2) {
LED_Light();
SHOOT_Go();
LED_Dark();
break;
}
}
} else if(Servo_X_Scan_Times==1){
//回转第二个单程
if(abs(goal_erro)<=delta1) {
LED_Light();
SHOOT_Go();
LED_Dark();
break;
}
} else if(Servo_X_Scan_Times==2) {
//当转到两圈自动发射
SHOOT_Go();
break;
}
}
}
void Mode41_Calibration_Camera(void) {
HMI_ConfigCamera();
}
//未完成
void Mode42_Calibration_Laser(void) {
LASER_Open_Light(1); //打开可见激光
delay_ms(500);
while(!HMI_CheckShootStart()); //等待串口屏发送开始扫描
SERVO_X_Scan_Start(Angle2PWMX[-30+30], Angle2PWMX[30+30], 3, 2, 1);//-30°~30°循环扫描看是否水平
}
void Mode43_Calibration_Volage(void) {
SHOOT_Elec_Enable(); //开始充电
while(!HMI_CheckShootStart()); //等待串口屏发射命令
SHOOT_Go(); //按下放电按钮,放电
}
void Mode44_Calibration_Exit(void) {
}