<think>我们将在代码中添加控制激光灯的GPIO初始化函数和激光灯控制函数。
假设激光灯连接在GPIOA的Pin3上,使用推挽输出模式。
步骤:
1. 添加激光灯的宏定义(引脚和端口)
2. 在PWM_Init函数中初始化激光灯的GPIO(或者单独写一个激光灯初始化函数)
3. 编写激光灯控制函数(开和关)
4. 在需要的地方调用激光灯控制函数(例如在绘制矩形时开启激光,绘制完毕关闭激光)
修改后的代码:</think>### 添加激光灯控制代码
以下是修改后的代码,添加了激光灯的控制功能:
```c
#include "stm32f10x.h"
#include "math.h"
#include "delay.h"
// 舵机参数定义
#define PWM_PERIOD 20000 // 20ms周期
#define MIN_PULSE 500 // 0.5ms脉冲宽度
#define MAX_PULSE 2500 // 2.5ms脉冲宽度
#define ANGLE_RANGE 270.0f // 舵机角度范围
// 云台参数
#define CENTER_X 135.0f // 水平中心角度
#define CENTER_Y 135.0f // 垂直中心角度
#define RECT_WIDTH 10.0f // 矩形宽度
#define RECT_HEIGHT 10.0f // 矩形高度
#define STEPS_PER_SIDE 100 // 每条边的步数
// 激光灯控制引脚定义
#define LASER_PIN GPIO_Pin_3
#define LASER_PORT GPIOA
// 函数声明
void PWM_Init(void);
void Laser_Init(void); // 新增激光灯初始化
void Laser_On(void); // 新增激光开启
void Laser_Off(void); // 新增激光关闭
void Set_Servo_Angle(uint8_t servo_id, float angle);
float LinearInterpolate(float start, float end, float ratio);
void MoveToPoint(float x, float y, uint16_t steps);
void DrawRectangle(uint8_t laser_enable); // 修改为可控制激光
void Go_To_Center(uint16_t steps);
// 当前位置存储(全局变量)
float current_x = CENTER_X;
float current_y = CENTER_Y;
/**
* 函 数:PWM初始化
*/
void PWM_Init(void)
{
/* 开启时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/* GPIO初始化 */
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 配置时钟源 */
TIM_InternalClockConfig(TIM2);
/* 时基单元初始化 */
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = PWM_PERIOD - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
/* 输出比较初始化 */
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
TIM_OC3Init(TIM2, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);
TIM_Cmd(TIM2, ENABLE);
}
/**
* 函 数:激光灯初始化
*/
void Laser_Init(void)
{
/* 开启GPIOA时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* 配置激光灯引脚为推挽输出 */
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = LASER_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LASER_PORT, &GPIO_InitStructure);
/* 初始状态关闭激光 */
GPIO_ResetBits(LASER_PORT, LASER_PIN);
}
/**
* 函 数:开启激光灯
*/
void Laser_On(void)
{
GPIO_SetBits(LASER_PORT, LASER_PIN);
}
/**
* 函 数:关闭激光灯
*/
void Laser_Off(void)
{
GPIO_ResetBits(LASER_PORT, LASER_PIN);
}
/**
* 函 数:设置舵机角度
*/
void Set_Servo_Angle(uint8_t servo_id, float angle)
{
if (angle < 0) angle = 0;
if (angle > ANGLE_RANGE) angle = ANGLE_RANGE;
uint16_t pulse = MIN_PULSE + (uint16_t)((MAX_PULSE - MIN_PULSE) * angle / ANGLE_RANGE);
switch(servo_id) {
case 0: TIM_SetCompare2(TIM2, pulse); break;
case 1: TIM_SetCompare3(TIM2, pulse); break;
}
}
/**
* 函 数:线性插值
*/
float LinearInterpolate(float start, float end, float ratio) {
return start + ratio * (end - start);
}
/**
* 函 数:移动到指定点
*/
void MoveToPoint(float x, float y, uint16_t steps) {
for (uint16_t i = 0; i <= steps; i++) {
float ratio = (float)i / steps;
float interp_x = LinearInterpolate(current_x, x, ratio);
float interp_y = LinearInterpolate(current_y, y, ratio);
Set_Servo_Angle(0, interp_x);
Set_Servo_Angle(1, interp_y);
delay_ms(2);
}
current_x = x;
current_y = y;
}
/**
* 函 数:云台归中
*/
void Go_To_Center(uint16_t steps) {
MoveToPoint(CENTER_X, CENTER_Y, steps);
}
/**
* 函 数:绘制完整矩形(带激光控制)
* 参 数:laser_enable - 是否开启激光 (1:开启, 0:关闭)
*/
void DrawRectangle(uint8_t laser_enable) {
// 计算矩形的四个顶点
float top_left_x = CENTER_X - RECT_WIDTH/2;
float top_left_y = CENTER_Y - RECT_HEIGHT/2;
float top_right_x = CENTER_X + RECT_WIDTH/2;
float top_right_y = CENTER_Y - RECT_HEIGHT/2;
float bottom_right_x = CENTER_X + RECT_WIDTH/2;
float bottom_right_y = CENTER_Y + RECT_HEIGHT/2;
float bottom_left_x = CENTER_X - RECT_WIDTH/2;
float bottom_left_y = CENTER_Y + RECT_HEIGHT/2;
// 根据参数控制激光状态
if(laser_enable) {
Laser_On(); // 开启激光
} else {
Laser_Off(); // 关闭激光
}
// 绘制完整矩形路径
MoveToPoint(top_left_x, top_left_y, STEPS_PER_SIDE); // 起点:左上角
MoveToPoint(top_right_x, top_right_y, STEPS_PER_SIDE); // 右上角
MoveToPoint(bottom_right_x, bottom_right_y, STEPS_PER_SIDE); // 右下角
MoveToPoint(bottom_left_x, bottom_left_y, STEPS_PER_SIDE); // 左下角
MoveToPoint(top_left_x, top_left_y, STEPS_PER_SIDE); // 终点:返回起点
}
/**
* 函 数:主函数
*/
int main(void) {
delay_init();
PWM_Init();
Laser_Init(); // 初始化激光灯
// 初始位置归中
Go_To_Center(50);
delay_ms(500);
while(1) {
// 带激光绘制矩形
DrawRectangle(1); // 参数1表示开启激光
// 停留1秒(激光保持开启)
delay_ms(1000);
// 关闭激光并归中
Laser_Off();
Go_To_Center(100);
// 不带激光绘制矩形(仅运动)
DrawRectangle(0); // 参数0表示关闭激光
// 停留1秒
delay_ms(1000);
// 激光闪烁效果
for(int i = 0; i < 5; i++) {
Laser_On();
delay_ms(100);
Laser_Off();
delay_ms(100);
}
}
}
```
### 关键修改说明:
#### 1. 激光灯硬件配置
```c
// 激光灯控制引脚定义
#define LASER_PIN GPIO_Pin_3
#define LASER_PORT GPIOA
```
- 假设激光灯连接在GPIOA的Pin3上
- 可根据实际硬件连接修改引脚定义
#### 2. 激光灯初始化函数
```c
void Laser_Init(void)
{
/* 开启GPIOA时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* 配置激光灯引脚为推挽输出 */
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = LASER_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LASER_PORT, &GPIO_InitStructure);
/* 初始状态关闭激光 */
GPIO_ResetBits(LASER_PORT, LASER_PIN);
}
```
- 初始化GPIO为推挽输出模式
- 初始状态设置为低电平(激光关闭)
#### 3. 激光控制函数
```c
// 开启激光
void Laser_On(void) {
GPIO_SetBits(LASER_PORT, LASER_PIN);
}
// 关闭激光
void Laser_Off(void) {
GPIO_ResetBits(LASER_PORT, LASER_PIN);
}
```
- 提供简单的开关接口
- 可直接在主程序或中断中调用
#### 4. 矩形绘制函数增强
```c
void DrawRectangle(uint8_t laser_enable) {
// 根据参数控制激光状态
if(laser_enable) {
Laser_On(); // 开启激光
} else {
Laser_Off(); // 关闭激光
}
// ...绘制矩形路径...
}
```
- 添加`laser_enable`参数控制激光状态
- 在绘制前设置激光状态
- 保持激光状态直到绘制完成
#### 5. 主函数逻辑优化
```c
int main(void) {
// ...初始化...
while(1) {
// 带激光绘制矩形
DrawRectangle(1); // 开启激光
// 停留1秒(激光保持开启)
delay_ms(1000);
// 关闭激光并归中
Laser_Off();
Go_To_Center(100);
// 不带激光绘制矩形(仅运动)
DrawRectangle(0); // 关闭激光
// 激光闪烁效果
for(int i = 0; i < 5; i++) {
Laser_On();
delay_ms(100);
Laser_Off();
delay_ms(100);
}
}
}
```
- 演示多种激光控制模式
- 交替进行带激光和不带激光的绘制
- 添加闪烁效果展示
### 激光控制模式示例:
1. **持续开启模式**:
```c
// 绘制过程中持续开启激光
DrawRectangle(1);
```
2. **闪烁模式**:
```c
// 绘制时激光闪烁
for(int i = 0; i < 4; i++) {
Laser_On();
MoveToPoint(/* 一段路径 */);
Laser_Off();
MoveToPoint(/* 下一段路径 */);
}
```
3. **脉冲模式**:
```c
// 以特定频率脉冲激光
for(int step = 0; step < steps; step++) {
if(step % 10 == 0) Laser_On();
if(step % 10 == 5) Laser_Off();
// 移动云台...
}
```
4. **外部触发模式**:
```c
// 通过按键控制激光
if(GPIO_ReadInputDataBit(BUTTON_PORT, BUTTON_PIN)) {
Laser_On();
} else {
Laser_Off();
}
```
### 硬件连接建议:
1. **激光模块接线**:
- VCC: 3.3V/5V (根据激光模块规格)
- GND: 接地
- SIG: 连接至GPIOA_Pin3
2. **电流考虑**:
```c
// 如果激光功率较大,建议通过晶体管驱动
// 修改GPIO初始化:
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; // 开漏输出
```
- 大功率激光需使用外部电源和MOSFET驱动
- STM32 GPIO最大驱动电流约20mA
3. **保护电路**:
- 在激光模块VCC端添加100μF电容
- 在GPIO和激光模块间添加100Ω限流电阻
### 应用场景扩展:
1. **激光雕刻**:
```c
void DrawText(char* text) {
Laser_Off();
// 移动到起点
Laser_On();
// 绘制字符路径
}
```
2. **激光指示演示**:
```c
void PointAtTarget(float x, float y) {
Laser_On();
MoveToPoint(x, y, 50);
delay_ms(2000);
Laser_Off();
}
```
3. **安全激光幕**:
```c
void SecurityScan() {
Laser_On();
// 水平扫描
for(float x = 90; x <= 180; x += 0.5) {
Set_Servo_Angle(0, x);
delay_ms(10);
}
Laser_Off();
}
```
###