#![no_std]
#![no_main]
#![deny(
clippy::mem_forget,
reason = "mem::forget is generally not safe to do with esp_hal types, especially those \
holding buffers for the duration of a data transfer."
)]
use esp_hal::{
clock::CpuClock, ledc::{
channel::{Channel, ChannelIFace}, timer::{self, TimerIFace}, Ledc, LowSpeed
}, rmt::Rmt, time::Rate, timer::systimer::SystemTimer
};
use esp_hal_smartled::{smart_led_buffer, SmartLedsAdapter};
use smart_leds::{RGB8, SmartLedsWrite as _};
use esp_println as _;
use defmt::info;
use embassy_executor::Spawner;
use embassy_time::{Duration, Timer};
use static_cell::{StaticCell};
#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
loop {}
}
esp_bootloader_esp_idf::esp_app_desc!();
// 舵机控制结构体
struct ServoController<'a> {
channel: &'a mut Channel<'a, LowSpeed>,
max_duty: u32,
}
// static TIMER_STATIC: StaticCell<&mut timer::Timer<'static, LowSpeed>> = StaticCell::new();
impl<'a> ServoController<'a> {
fn new(
timer:&'a mut timer::Timer<'a, LowSpeed>,
channel:&'a mut Channel<'a, LowSpeed>,
) -> Self {
// 配置 PWM 参数:50Hz 频率,14位分辨率
let timer_config = esp_hal::ledc::timer::config::Config {
duty: esp_hal::ledc::timer::config::Duty::Duty14Bit,
clock_source: esp_hal::ledc::timer::LSClockSource::APBClk, // 请根据实际可用的时钟源选择
frequency: Rate::from_hz(50), // 舵机标准频率
};
timer.configure(timer_config).unwrap();
// 配置通道
let channel_config = esp_hal::ledc::channel::config::Config{
timer: timer,
duty_pct: 0, // 初始占空比为0
pin_config: esp_hal::ledc::channel::config::PinConfig::PushPull,
};
channel.configure(channel_config).unwrap();
let max_duty = (1 << 14) - 1; // 14位最大计数值
Self { max_duty, channel }
}
// 设置舵机角度 (0-180度)
fn set_angle(&mut self, angle: u8) {
// 限制角度范围
let angle = angle.clamp(0, 180);
// SG90 舵机参数:
// - 频率: 50Hz (周期 20ms = 20000μs)
// - 0度: 0.5ms 脉冲 (500μs)
// - 90度: 1.5ms 脉冲 (1500μs)
// - 180度: 2.5ms 脉冲 (2500μs)
let angle = angle.clamp(0, 180);
// SG90 舵机参数
let min_pulse_us = 500; // 0度脉冲宽度
let max_pulse_us = 2500; // 180度脉冲宽度
let period_us = 20000; // 20ms周期
// 计算脉冲宽度
let pulse_width_us = min_pulse_us + (angle as u32 * (max_pulse_us - min_pulse_us)) / 180;
// 计算占空比百分比 (0-100)
let duty_percent = (pulse_width_us * 100) / period_us;
info!("角度: {}°, 脉冲宽度: {}μs, 占空比: {}%",
angle, pulse_width_us, duty_percent);
// 使用百分比设置占空比
if let Err(e) = self.channel.set_duty(duty_percent as u8) {
info!("设置占空比失败: {:?}", e);
} else {
info!("成功设置舵机角度: {}°", angle);
}
}
}
// 全局舵机控制器
static SERVO_CONTROLLER: StaticCell<ServoController<'static>> = StaticCell::new();
static SERVO_TIMER: StaticCell<timer::Timer<'static, LowSpeed>> = StaticCell::new();
static SERVO_CHANNEL: StaticCell<Channel<'static, LowSpeed>> = StaticCell::new();
#[esp_hal_embassy::main]
async fn main(spawner: Spawner) {
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
let peripherals = esp_hal::init(config);
// 初始化 LEDC (PWM 控制器) 用于舵机控制
let ledc = Ledc::new(peripherals.LEDC);
// 配置 PWM 定时器
let timer_pwd = ledc.timer::<LowSpeed>(timer::Number::Timer0);
// 配置 PWM 通道 (使用 GPIO2 控制舵机,可根据需要更改)
let channel_pwd = ledc.channel(esp_hal::ledc::channel::Number::Channel0, peripherals.GPIO7);
let timer_static = SERVO_TIMER.init(timer_pwd);
let channel_static = SERVO_CHANNEL.init(channel_pwd);
// 创建舵机控制器
let mut servo: ServoController<'_> = ServoController::new(timer_static, channel_static);
let mut servo_static = SERVO_CONTROLLER.init(servo);
// servo.set_angle(30u8);
info!("舵机控制器初始化完成!");
let timer0 = SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init(timer0.alarm0);
info!("Embassy initialized!");
// RGB LED 配置
let rmt = Rmt::new(peripherals.RMT, Rate::from_mhz(80)).unwrap();
let mut led = SmartLedsAdapter::new(rmt.channel0, peripherals.GPIO48, smart_led_buffer!(1));
const LEVEL: u8 = 20; // 亮度级别
// 启动舵机控制任务
spawner.spawn(servo_control_task(servo_static)).unwrap();
loop {
let color = RGB8 { r: 0, g: LEVEL, b: 0 };
// 设置 LED 为绿色并闪烁
led.write([color].into_iter()).unwrap();
info!("绿色 LED 亮起 - 舵机旋转");
Timer::after(Duration::from_millis(500)).await;
// LED 熄灭
let color = RGB8::default();
led.write([color].into_iter()).unwrap();
Timer::after(Duration::from_millis(500)).await;
info!("----------------------------------------------------------------");
}
}
// 舵机控制任务
#[embassy_executor::task]
async fn servo_control_task(servo: &'static mut ServoController<'static>) {
let mut servo_angle: u8 = 0;
let mut angle_direction: bool = true; // true: 增加角度, false: 减少角度
loop {
// 获取舵机控制器
// if let Some(servo) = unsafe { SERVO_REF } {
// 设置舵机角度
info!("舵机最大max_duty: {}", servo.max_duty);
servo.set_angle(servo_angle);
// 更新角度
if angle_direction {
servo_angle += 30;
if servo_angle >= 180 {
servo_angle = 180;
angle_direction = false;
}
} else {
if servo_angle >= 30 {
servo_angle -= 30;
} else {
servo_angle = 0;
angle_direction = true;
}
}
// }
// 等待下一次旋转(与LED闪烁同步)
Timer::after(Duration::from_secs(1)).await;
}
}