Индикация 00:00 = Часы:Мнуты (Mега88V)

Обсуждаем контроллеры компании Atmel.
Ответить
Открыл глаза
Сообщения: 47
Зарегистрирован: Ср ноя 12, 2014 14:48:39

Сообщение krokodandi »

Получается, что разложение long int действительно затратно. больше на 300-500 кбайт. Столько памяти на дороге не валяется.
Реклама
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Быстрый в плане вычислений вариант кода без делений, но чуть больше размером (586 байт Flash, 23 байт RAM):
Спойлер

Код: Выделить всё

#include <avr/io.h>
#include <avr/interrupt.h>

#define DIG_CNT		4

#define DIG_DDR		DDRC
#define DIG_PORT	PORTC

#define DIG_0		(1<<0) // Крайний правый разряд
#define DIG_1		(1<<1)
#define DIG_2		(1<<2)
#define DIG_3		(1<<3) // Крайний левый разряд
#define DIGITS		(DIG_0 | DIG_1 | DIG_2 | DIG_3)

#define SEGM_DDR	DDRD
#define SEGM_PORT	PORTD

#define SEG_A		(1<<0)
#define SEG_B		(1<<1)
#define SEG_C		(1<<2)
#define SEG_D		(1<<3)
#define SEG_E		(1<<4)
#define SEG_F		(1<<5)
#define SEG_G		(1<<6)
#define SEG_P		(1<<7)
#define SEGMENTS	(SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G | SEG_P)

#define CH_0		(SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F)
#define CH_1		(SEG_B | SEG_C)
#define CH_2		(SEG_A | SEG_B | SEG_D | SEG_E | SEG_G)
#define CH_3		(SEG_A | SEG_B | SEG_C | SEG_D | SEG_G)
#define CH_4		(SEG_B | SEG_C | SEG_F | SEG_G)
#define CH_5		(SEG_A | SEG_C | SEG_D | SEG_F | SEG_G)
#define CH_6		(SEG_A | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G)
#define CH_7		(SEG_A | SEG_B | SEG_C)
#define CH_8		(SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G)
#define CH_9		(SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G)

// Массив, хранящий коды цифр выводимого числа
static volatile uint8_t ind[DIG_CNT];
// Массив, хранящий коды десятичных цифр
static const uint8_t num[] = {CH_0, CH_1, CH_2, CH_3, CH_4, CH_5, CH_6, CH_7, CH_8, CH_9};
// Позиция активного символа
static uint8_t pos = 0;
// Время (десятки(T) и единицы (U) часов (h), минут (m) и секунд (s).
static volatile int8_t hT, hU, mT, mU, sT, sU;

// Прерывание вызывается 1000 раз в секунду
ISR (TIMER2_COMP_vect)
{
	static volatile int16_t ms; // миллисекунды

	// Гасим все сегменты и разряды
	SEGM_PORT &= ~SEGMENTS;
	DIG_PORT |= DIGITS;
	// Переключаемся на следующий разряд
	if (++pos >= DIG_CNT)
		pos = 0;
	// Устанавливаем текущее число и секундную точку на сегменты и включаем нужный разряд
	SEGM_PORT |= ind[pos];
	if (pos == 2 && sU & 0x01)
		SEGM_PORT |= SEG_P;
	DIG_PORT &= ~(1<<pos);

	// Отсчёт таймера
	ms++;
	if (ms >= 1000) {
		ms = 0;
		if (--sU < 0) {
			sU = 9;
			if (--sT < 0) {
				sT = 5;
				if (--mU < 0) {
					mU = 9;
					if (--mT < 0) {
						mT = 5;
						if (--hU < 0) {
							hT = 9;
							if (--hT < 0) {
								hT = 9;
							}
						}
					}
				}
			}
		}
	}

	return;
}

void segmInit(void)
{
	// Выводы МК, отвещающие за разряды и сегменты - на выход
	DIG_DDR |= (DIG_0 | DIG_1 | DIG_2 | DIG_3);
	SEGM_DDR |= 0xFF;
	// Включаем прерывание по совпадению
	TIMSK |= (1<<OCIE2);
	// Устанавливаем предделитель таймера на 64 (125кГц) и частоту прерываний 1кГц
	TCCR2 |= (1<<CS22) | (0<<CS21) | (0<<CS20) | (1<<WGM21) | (0<<WGM20);
	OCR2 = 125;

	sei(); // Глобально включаем прерывания

	return;
}

void show(int8_t d3, int8_t d2, int8_t d1, int8_t d0)
{
	ind[0] = num[d0];
	ind[1] = num[d1];
	ind[2] = num[d2];
	ind[3] = num[d3];

	return;
}

int main(void)
{
	segmInit ();

	// Счёт с 01:00:08
	hT = 0; hU = 1;
	mT = 0; mU = 0;
	sT = 0; sU = 8;

	while (1) {
		if (hT > 0 || hU > 0) {
			show(hT, hU, mT, mU);
		} else {
			show(mT, mU, sT, sU);
		}
	}

	return 0;
}
Да, 8-битному контроллеру сложно работать с 4-байтовыми числами. Ладно, сложение-вычитание, ещё куда ни шло. Но алгоритмы умножения и, особенно, деления уже слишком сложны и занимают много места.
Контактная информация:
Реклама
Открыл глаза
Сообщения: 47
Зарегистрирован: Ср ноя 12, 2014 14:48:39

Сообщение krokodandi »

Дауш, вижу разницу.
Либо делаешь умножением и делением, но при этом теряешь в количестве памяти, либо простыми сложением вычитанием и получаешь взрыв мозга от обилия + и -.

А вот еще вопрос. На сколько целесообразно сохранять содержимое h и m в eeprom или просто как говорится, в ROM. Если это простой бытовой таймер? Большой ли смысл и много ли придется писать для такой фишки. Может есть там особенность - нужен отдельный таймер для записи в эту память и отдельная функция для чтения...
Стоит ли гемор свечь?
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Ещё один в по-своему красивый вариант с union и битовыми полями (576 байт Flash, 20 байт RAM):
Спойлер

Код: Выделить всё

#include <avr/io.h>
#include <avr/interrupt.h>

#define DIG_CNT		4

#define DIG_DDR		DDRC
#define DIG_PORT	PORTC

#define DIG_0		(1<<0) // Крайний правый разряд
#define DIG_1		(1<<1)
#define DIG_2		(1<<2)
#define DIG_3		(1<<3) // Крайний левый разряд
#define DIGITS		(DIG_0 | DIG_1 | DIG_2 | DIG_3)

#define SEGM_DDR	DDRD
#define SEGM_PORT	PORTD

#define SEG_A		(1<<0)
#define SEG_B		(1<<1)
#define SEG_C		(1<<2)
#define SEG_D		(1<<3)
#define SEG_E		(1<<4)
#define SEG_F		(1<<5)
#define SEG_G		(1<<6)
#define SEG_P		(1<<7)
#define SEGMENTS	(SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G | SEG_P)

#define CH_0		(SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F)
#define CH_1		(SEG_B | SEG_C)
#define CH_2		(SEG_A | SEG_B | SEG_D | SEG_E | SEG_G)
#define CH_3		(SEG_A | SEG_B | SEG_C | SEG_D | SEG_G)
#define CH_4		(SEG_B | SEG_C | SEG_F | SEG_G)
#define CH_5		(SEG_A | SEG_C | SEG_D | SEG_F | SEG_G)
#define CH_6		(SEG_A | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G)
#define CH_7		(SEG_A | SEG_B | SEG_C)
#define CH_8		(SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G)
#define CH_9		(SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G)

// Массив, хранящий коды цифр выводимого числа
static volatile uint8_t ind[DIG_CNT];
// Массив, хранящий коды десятичных цифр
static const uint8_t num[] = {CH_0, CH_1, CH_2, CH_3, CH_4, CH_5, CH_6, CH_7, CH_8, CH_9};
// Позиция активного символа
static uint8_t pos = 0;

typedef union {
	int8_t value;
	struct {
		uint8_t units:4;
		uint8_t tens:4;
	};
} time;

static volatile time hour, min, sec;

// Прерывание вызывается 1000 раз в секунду
ISR (TIMER2_COMP_vect)
{
	static volatile int16_t ms; // миллисекунды

	// Гасим все сегменты и разряды
	SEGM_PORT &= ~SEGMENTS;
	DIG_PORT |= DIGITS;
	// Переключаемся на следующий разряд
	if (++pos >= DIG_CNT)
		pos = 0;
	// Устанавливаем текущее число и секундную точку на сегменты и включаем нужный разряд
	SEGM_PORT |= ind[pos];
	if (pos == 2 && (sec.value & 0x01))
		SEGM_PORT |= SEG_P;
	DIG_PORT &= ~(1<<pos);

	// Отсчёт таймера
	ms++;
	if (ms >= 1000) {
		ms = 0;
		sec.value--;
		if (sec.units == 0x0F) sec.units = 0x09;
		if (sec.value < 0) {
			sec.value = 0x59;
			min.value--;
			if (min.units == 0x0F) min.units = 0x09;
			if (min.value < 0) {
				min.value = 0x59;
				hour.value--;
				if (hour.units == 0x0F) hour.units = 0x09;
				if (hour.value < 0)
					hour.value = 0x99;
			}
		}
	}

	return;
}

void segmInit(void)
{
	// Выводы МК, отвещающие за разряды и сегменты - на выход
	DIG_DDR |= (DIG_0 | DIG_1 | DIG_2 | DIG_3);
	SEGM_DDR |= SEGMENTS;
	// Включаем прерывание по совпадению
	TIMSK |= (1<<OCIE2);
	// Устанавливаем предделитель таймера на 64 (125кГц) и частоту прерываний 1кГц
	TCCR2 |= (1<<CS22) | (0<<CS21) | (0<<CS20) | (1<<WGM21) | (0<<WGM20);
	OCR2 = 125;

	sei(); // Глобально включаем прерывания

	return;
}

void show(time t32, time t10)
{
	ind[3] = num[t32.tens];
	ind[2] = num[t32.units];
	ind[1] = num[t10.tens];
	ind[0] = num[t10.units];

	return;
}

int main(void)
{
	segmInit ();

	// Счёт с 01:00:08
	hour.value = 0x01;
	min.value = 0x00;
	sec.value = 0x08;

	while (1) {
		if (hour.value > 0) {
			show(hour, min);
		} else {
			show(min, sec);
		}
	}

	return 0;
}
krokodandi писал(а):На сколько целесообразно сохранять содержимое h и m в eeprom или просто как говорится, в ROM
Тут не понял, зачем что-то сохранять и где. В EEPROM можно хранить некое начальное значение таймера. Или несколько часто используемых. Про ROM не понял, что именно Вы под ним понимаете.
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Открыл глаза
Сообщения: 47
Зарегистрирован: Ср ноя 12, 2014 14:48:39

Сообщение krokodandi »

Я про EEPROM. Именно про этот вид ПЗУ.
Тут описан некий вариант http://microsin.net/programming/AVR/sav ... inavr.html
Вроде бы он короткий, но кроме него еще что-то надо?

А что за запись сточкой? ind[3] = num[t32.tens];
Странная запись...
hour.value = 0x01;
min.value = 0x00;
sec.value = 0x08;
По моему это совсем оригинальный стиль :))

Спасибо. Буду дальше осваивать матчасть. Очень интересные варианты.
Если что будет новенькое, обновлю тему.
Реклама
Ответить

Вернуться в «AVR»