#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_adc/adc_oneshot.h"
#include "driver/ledc.h"
#define CONFIG_LOG_MAXIMUM_LEVEL 5
static const char *TAG = "ADC_LED";
// 硬體配置 (不變)
#define ADC_CHAN ADC_CHANNEL_6
#define LED_PIN GPIO_NUM_41
#define LEDC_TIMER LEDC_TIMER_0
#define LEDC_MODE LEDC_LOW_SPEED_MODE
#define LEDC_CHANNEL LEDC_CHANNEL_0
#define LEDC_DUTY_RES LEDC_TIMER_12_BIT
#define LEDC_FREQUENCY 5000
// 宣告 Task Handle,用於指向接收通知的任務
static TaskHandle_t led_task_handle = NULL;
void ledc_init() {
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_MODE,
.timer_num = LEDC_TIMER,
.duty_resolution = LEDC_DUTY_RES,
.freq_hz = LEDC_FREQUENCY,
.clk_cfg = LEDC_AUTO_CLK
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
ledc_channel_config_t ledc_channel = {
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = LED_PIN,
.duty = 0,
.hpoint = 0
};
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
}
// ADC 讀取任務 (發送者)
void adc_task(void *arg) {
adc_oneshot_unit_handle_t adc_handle;
adc_oneshot_unit_init_cfg_t unit_cfg = { .unit_id = ADC_UNIT_1 };
ESP_ERROR_CHECK(adc_oneshot_new_unit(&unit_cfg, &adc_handle));
adc_oneshot_chan_cfg_t chan_cfg = {
.bitwidth = ADC_BITWIDTH_DEFAULT,
.atten = ADC_ATTEN_DB_12,
};
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle, ADC_CHAN, &chan_cfg));
int raw_val = 0;
int last_val = -1;
while (1) {
ESP_ERROR_CHECK(adc_oneshot_read(adc_handle, ADC_CHAN, &raw_val));
// 如果變化大於 10 且接收任務已就緒
if (abs(raw_val - last_val) >= 10 && led_task_handle != NULL) {
// 發送通知:更新 led_task 的通知值
// eSetValueWithOverwrite 確保任務收到的永遠是最新的 ADC 值
xTaskNotify(led_task_handle, (uint32_t)raw_val, eSetValueWithOverwrite);
last_val = raw_val;
}
vTaskDelay(pdMS_TO_TICKS(20));
}
}
// LED 控制任務 (接收者)
void led_task(void *arg) {
uint32_t received_adc_val = 0;
while (1) {
// 等待通知
// 第一個 0: 進入前不清除 bits
// 第二個 0xFFFFFFFF: 離開後清除所有 bits
// 第三個 &received_adc_val: 存入收到的數值
// 第四個 portMAX_DELAY: 無限期等待直到收到通知
if (xTaskNotifyWait(0, 0xffffffff, &received_adc_val, portMAX_DELAY) == pdTRUE) {
ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, received_adc_val);
ledc_update_duty(LEDC_MODE, LEDC_CHANNEL);
ESP_LOGI(TAG, "PWM 更新完成: %lu", received_adc_val);
}
}
}
void app_main(void) {
esp_log_level_set(TAG, ESP_LOG_VERBOSE);
ledc_init();
// 建立 LED 任務,並將其 Handle 存起來
xTaskCreate(led_task, "led_task", 3000, NULL, 4, &led_task_handle);
// 建立 ADC 任務
xTaskCreate(adc_task, "adc_task", 3000, NULL, 5, NULL);
}