Светодиодные фонари и световые приборы. Всё о светотехнике.
Изображения Дневники Группы Поиск
Вернуться   Форум FONAREVKA.RU Лаборатория Электроника и схемотехника Электроника
Расширенный поиск
Забыли пароль? Регистрация

  • О нашем проекте
  • Светотехника и световые приборы
  • Правила форума
Проект FONAREVKA.RU специализируется на предоставлении всей необходимой информации по светотехнике:

— светодиодные фонари;
— различные источники питания;
— разнообразные зарядные устройства;
— освещение помещений и наружное освещение;
— световые приборы для личного, пассажирского и грузового транспорта;
— специальные световые приборы для медицины, для растений, для аквариумов, для террариумов, а также аварийно-сигнальные световые приборы;
— альтернативные источники света;
— лазеры и лазерная техника.

Если у вас есть вопросы по выбору фонарей, аккумуляторов и зарядных устройств ознакомьтесь с FAQ от наших экспертов:

F.A.Q. по выбору фонарей различных типов;
F.A.Q. по выбору аккумуляторов;
F.A.Q. по выбору зарядных устройств.
Ответ  Создать новую тему
Просмотров в теме 2501   Ответов в теме 1   Подписчиков на тему 1   Добавили в закладки 0
Опции темы Поиск в этой теме
Старый 26.12.2013, 04:56 Автор темы   1
Ветеран Фонарёвки
 
Аватар для ites
 
Регистрация: 28.10.2010
Последняя активность: 10.05.2023 13:50
Адрес: Германия
Сообщений: 1195
Записей в дневнике: 1
Сказал(а) спасибо: 27
Поблагодарили: 120 раз(а) в 53 сообщениях

По умолчанию аналоговый выход

Приветствую. Сегодня первый день как начал играться с Arduino UNO, опыта в программировании контроллеров у меня раньше не было. Начал с первого урока -- моргающий светодиод. Усложнил задачу, чтобы диод стал медленно гаснуть и загораться без использования analogWrite. Не понравилась идея 490 Гц, да и вообще, в учёбе не должно быть лёгких путей. Помучившись изрядно, добился результата, теперь хотелось бы услышать комментарии и ответы на возникшие вопросы. Код немного длинноват, поскольку писался в Eclipse, а не в стандартной среде.

Основные вопросы у меня по скорости работы разных участков. Например, как я понимаю, при OCR1A = 1 и TCCR1B |= (1 << CS10) -- прерывание таймера должно работать с максимальной скоростью, но я, признаться, так и не понял с какой именно. Увеличивая счётчики прескейлинга или OCR1A, скрость падает, но как-то не так линейно как я ожидал.

В программе не использовал плавающую точку нигде, все функции на первый взгляд кажутся почти оптимильными. Никак не мог понять что происходит, пока не перенёс запись в pin13 внутрь обработчика прерывания, в связи с этим второй вопрос -- не съел ли мой таймерный обаботчик всё быстродействие, что на loop() уже почти ничего не осталось?

Проблема в том, что если в loop не использовать delay, а сделать эту логику через millis, то переменная current_grad перестаёт увеличиваться совсем -- это совсем не удаётся понять. В итоге сделал увеличение current_grad безусловно и визуально скорость смены яркости вполне комфортная.

Логика аналогового выхода в том, что уровни HIGH и LOW распределяются равномерно и при этом пропорционально нужному коэффициенту.

Код:
#include <Arduino.h>
#include <avr/io.h>
#include "HardwareSerial.h"

typedef struct _int_ratio {
	int ante, conseq;
} int_ratio;
int tbl_sinus_scale = 255;
byte tbl_sinus[] = { 0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44, 49, 53, 57, 62, 66, 70, 75, 79, 83,
		87, 91, 96, 100, 104, 108, 112, 116, 120, 124, 127, 131, 135, 139, 143, 146, 150, 153, 157,
		160, 164, 167, 171, 174, 177, 180, 183, 186, 190, 192, 195, 198, 201, 204, 206, 209, 211,
		214, 216, 219, 221, 223, 225, 227, 229, 231, 233, 235, 236, 238, 240, 241, 243, 244, 245,
		246, 247, 248, 249, 250, 251, 252, 253, 253, 254, 254, 254, 255, 255, 255, 255 };

int_ratio irsinus(int grad) {
	int_ratio ret;
	int ag;
	grad %= 360;
	if (grad < 0)
		grad += 360;
	ag = grad % 180;
	if (ag > 90)
		ag = 180 - ag;
	ret.ante = tbl_sinus[ag];
	ret.conseq = tbl_sinus_scale - ret.ante;
	if (grad > 180)
		ret.ante = -ret.ante;
	return ret;
}

typedef struct _int_bresenham {
	int ante, conseq;
	int ante_err, conseq_err;
} int_bresenham;

int_ratio dither_bresenham(int_bresenham *br) {
	int_ratio ret = { 0, 0 };
	if (br->ante_err < br->ante && br->conseq_err < br->conseq) {
		br->conseq_err += br->ante;
		br->ante_err += br->conseq;
	}
	if (br->ante_err >= br->ante) {
		++ret.ante;
		br->ante_err -= br->ante;
	}
	if (br->conseq_err >= br->conseq) {
		++ret.conseq;
		br->conseq_err -= br->conseq;
	}
	return ret;
}

int led = 13;

// the setup routine runs once when you press reset:
void setup() {
	// initialize the digital pin as an output.
	pinMode(led, OUTPUT);
	// initialize timer1
	noInterrupts();
	// disable all interrupts
	TCCR1A = 0;
	TCCR1B = 0;
	TCNT1 = 0;

	OCR1A = 1;            // compare match register 16MHz/256/2Hz
	TCCR1B |= (1 << WGM12);   // CTC mode
	TCCR1B |= (1 << CS10);    // 1 prescaler
	TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt
	interrupts();
	// enable all interrupts
}

int current_grad = 1;
unsigned long next_turn = 0;

int_ratio current_state = { 0, 0 };
int_bresenham current_br = { 0, 0, 0, 0 };

void loop() {
	unsigned long time = millis();
//	if (time > next_turn) {
		++current_grad;
		if (current_grad >= 360)
			current_grad -= 360;
		int_ratio cs = irsinus(current_grad);
		if (cs.ante < 0)
			cs.ante = -current_state.ante;
		current_br.ante = cs.ante;
		current_br.conseq = cs.conseq;
		current_br.ante_err = current_br.conseq_err = 0;
		next_turn = time + 10;
//	}
}

ISR(TIMER1_COMPA_vect)          // timer compare interrupt service routine
{
	int led_level = HIGH;
	if (current_state.ante == 0 && current_state.conseq == 0) {
		current_state = dither_bresenham(&current_br);
	}
	if (current_state.ante > 0) {
		led_level = HIGH;
		--current_state.ante;
	} else if (current_state.conseq > 0) {
		led_level = LOW;
		--current_state.conseq;
	}
	digitalWrite(led, led_level);   // включаем LED
}

int main(void) {
	init();
	setup();
	//endless loop
	for (;;) {
		loop();
	}
	return 0;
}
ites вне форума   Ответить с цитированием Вверх
Старый 26.12.2013, 14:01 Автор темы   2
ites
Ветеран Фонарёвки
 
Аватар для ites
 
Регистрация: 28.10.2010
Последняя активность: 10.05.2023 13:50
Адрес: Германия
Сообщений: 1195
Записей в дневнике: 1
Сказал(а) спасибо: 27
Поблагодарили: 120 раз(а) в 53 сообщениях

По умолчанию Re: аналоговый выход

Последняя оптимизированная версия тут https://github.com/jabbervo...
ites вне форума   Ответить с цитированием Вверх
Ответ  Создать новую тему





Copyright ©2007 - 2024, FONAREVKA.RU

Powered by vBulletin®
Copyright ©2000 - 2022, Jelsoft Enterprises Ltd. Перевод: zCarot

Правила форума | Отказ от ответственности

Время генерации страницы 0.07759 секунды с 18 запросами