Test program for my solar controller breadboard
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

234 lines
8.5 KiB

/*
* MIT License
*
* Copyright (c) 2017 David Antliff
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "driver/ledc.h"
#include "owb.h"
#include "owb_rmt.h"
#include "ds18b20.h"
#define GPIO_DS18B20_0 (CONFIG_ONE_WIRE_GPIO)
#define MAX_DEVICES (8)
#define DS18B20_RESOLUTION (DS18B20_RESOLUTION_12_BIT)
#define SAMPLE_PERIOD (1000) // milliseconds
static void led_task(void *pvParameters) {
// Prepare and then apply the LEDC PWM timer configuration
ledc_timer_config_t ledc_timer_0 = {
.speed_mode = LEDC_HIGH_SPEED_MODE,
.timer_num = LEDC_TIMER_0,
.duty_resolution = LEDC_TIMER_8_BIT,
.freq_hz = 1000, // Set output frequency at 5 kHz
.clk_cfg = LEDC_AUTO_CLK
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer_0));
// Prepare and then apply the LEDC PWM channel configuration
ledc_channel_config_t ledc_channel_1 = {
.speed_mode = LEDC_HIGH_SPEED_MODE,
.channel = LEDC_CHANNEL_0,
.timer_sel = LEDC_TIMER_0,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = GPIO_NUM_19,
.duty = 0, // Set duty to 0%
.hpoint = 0
};
ledc_channel_config_t ledc_channel_2 = {
.speed_mode = LEDC_HIGH_SPEED_MODE,
.channel = LEDC_CHANNEL_1,
.timer_sel = LEDC_TIMER_0,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = GPIO_NUM_21,
.duty = 0, // Set duty to 0%
.hpoint = 0
};
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel_1));
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel_2));
int steps[] = {
0, 16, 32, 48, 64, 80, 96, 112, 128, 128, 112, 96, 80, 64, 48, 32, 16, 0
};
int n_steps = sizeof(steps) / sizeof(steps[0]);
for (;;) {
for (int i = 0; i < n_steps; i++) {
// Wait 10s and update the duty cycle
vTaskDelay(100.0 / portTICK_PERIOD_MS);
ESP_ERROR_CHECK(ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, steps[i]));
ESP_ERROR_CHECK(ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, steps[(i+4)%n_steps]));
ESP_ERROR_CHECK(ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0));
ESP_ERROR_CHECK(ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1));
}
}
vTaskDelete(NULL);
}
_Noreturn void app_main()
{
// Override global log level
esp_log_level_set("*", ESP_LOG_INFO);
// To debug, use 'make menuconfig' to set default Log level to DEBUG, then uncomment:
//esp_log_level_set("owb", ESP_LOG_DEBUG);
//esp_log_level_set("ds18b20", ESP_LOG_DEBUG);
BaseType_t xReturned;
xReturned = xTaskCreate(led_task,
"led_task",
4096, /* Stack size in words, not bytes. */
NULL, /* Parameter passed into the task. */
tskIDLE_PRIORITY + 12,
NULL);
if (xReturned != pdPASS) {
ESP_LOGE("led", "xTaskCreate('led_task'): %d", xReturned);
abort();
}
// Stable readings require a brief period before communication
vTaskDelay(2000.0 / portTICK_PERIOD_MS);
// Create a 1-Wire bus, using the RMT timeslot driver
OneWireBus * owb;
owb_rmt_driver_info rmt_driver_info;
owb = owb_rmt_initialize(&rmt_driver_info, GPIO_DS18B20_0, RMT_CHANNEL_1, RMT_CHANNEL_0);
owb_use_crc(owb, true); // enable CRC check for ROM code
// Find all connected devices
printf("Find devices:\n");
OneWireBus_ROMCode device_rom_codes[MAX_DEVICES] = {0};
int num_devices = 0;
OneWireBus_SearchState search_state = {0};
bool found = false;
owb_search_first(owb, &search_state, &found);
while (found)
{
char rom_code_s[17];
owb_string_from_rom_code(search_state.rom_code, rom_code_s, sizeof(rom_code_s));
printf(" %d : %s\n", num_devices, rom_code_s);
device_rom_codes[num_devices] = search_state.rom_code;
++num_devices;
owb_search_next(owb, &search_state, &found);
}
printf("Found %d device%s\n", num_devices, num_devices == 1 ? "" : "s");
// Create DS18B20 devices on the 1-Wire bus
DS18B20_Info * devices[MAX_DEVICES] = {0};
for (int i = 0; i < num_devices; ++i)
{
DS18B20_Info * ds18b20_info = ds18b20_malloc(); // heap allocation
devices[i] = ds18b20_info;
if (num_devices == 1)
{
printf("Single device optimisations enabled\n");
ds18b20_init_solo(ds18b20_info, owb); // only one device on bus
}
else
{
ds18b20_init(ds18b20_info, owb, device_rom_codes[i]); // associate with bus and device
}
ds18b20_use_crc(ds18b20_info, true); // enable CRC check on all reads
ds18b20_set_resolution(ds18b20_info, DS18B20_RESOLUTION);
}
// Check for parasitic-powered devices
bool parasitic_power = false;
ds18b20_check_for_parasite_power(owb, &parasitic_power);
if (parasitic_power) {
printf("Parasitic-powered devices detected");
}
// In parasitic-power mode, devices cannot indicate when conversions are complete,
// so waiting for a temperature conversion must be done by waiting a prescribed duration
owb_use_parasitic_power(owb, parasitic_power);
#ifdef CONFIG_ENABLE_STRONG_PULLUP_GPIO
// An external pull-up circuit is used to supply extra current to OneWireBus devices
// during temperature conversions.
owb_use_strong_pullup_gpio(owb, CONFIG_STRONG_PULLUP_GPIO);
#endif
// Read temperatures more efficiently by starting conversions on all devices at the same time
int errors_count[MAX_DEVICES] = {0};
int sample_count = 0;
if (num_devices > 0)
{
TickType_t last_wake_time = xTaskGetTickCount();
while (1)
{
ds18b20_convert_all(owb);
// In this application all devices use the same resolution,
// so use the first device to determine the delay
ds18b20_wait_for_conversion(devices[0]);
// Read the results immediately after conversion otherwise it may fail
// (using printf before reading may take too long)
float readings[MAX_DEVICES] = { 0 };
DS18B20_ERROR errors[MAX_DEVICES] = { 0 };
for (int i = 0; i < num_devices; ++i)
{
errors[i] = ds18b20_read_temp(devices[i], &readings[i]);
}
// Print results in a separate loop, after all have been read
printf("\nTemperature readings (degrees C): sample %d\n", ++sample_count);
for (int i = 0; i < num_devices; ++i)
{
if (errors[i] != DS18B20_OK)
{
++errors_count[i];
}
printf(" %d: %.1f %d errors\n", i, readings[i], errors_count[i]);
}
vTaskDelayUntil(&last_wake_time, SAMPLE_PERIOD / portTICK_PERIOD_MS);
}
}
else
{
printf("\nNo DS18B20 devices detected!\n");
}
// clean up dynamically allocated data
for (int i = 0; i < num_devices; ++i)
{
ds18b20_free(&devices[i]);
}
owb_uninitialize(owb);
printf("Restarting now.\n");
fflush(stdout);
vTaskDelay(1000 / portTICK_PERIOD_MS);
esp_restart();
}