Индикация 00:00 = Часы:Мнуты (Mега88V)
- Сообщения: 47
- Зарегистрирован: Ср ноя 12, 2014 14:48:39
Получается, что разложение long int действительно затратно. больше на 300-500 кбайт. Столько памяти на дороге не валяется.
- Реклама
Быстрый в плане вычислений вариант кода без делений, но чуть больше размером (586 байт Flash, 23 байт RAM):
Да, 8-битному контроллеру сложно работать с 4-байтовыми числами. Ладно, сложение-вычитание, ещё куда ни шло. Но алгоритмы умножения и, особенно, деления уже слишком сложны и занимают много места.
Спойлер
Код: Выделить всё
#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;
}- Сообщения: 47
- Зарегистрирован: Ср ноя 12, 2014 14:48:39
Дауш, вижу разницу.
Либо делаешь умножением и делением, но при этом теряешь в количестве памяти, либо простыми сложением вычитанием и получаешь взрыв мозга от обилия + и -.
А вот еще вопрос. На сколько целесообразно сохранять содержимое h и m в eeprom или просто как говорится, в ROM. Если это простой бытовой таймер? Большой ли смысл и много ли придется писать для такой фишки. Может есть там особенность - нужен отдельный таймер для записи в эту память и отдельная функция для чтения...
Стоит ли гемор свечь?
Либо делаешь умножением и делением, но при этом теряешь в количестве памяти, либо простыми сложением вычитанием и получаешь взрыв мозга от обилия + и -.
А вот еще вопрос. На сколько целесообразно сохранять содержимое h и m в eeprom или просто как говорится, в ROM. Если это простой бытовой таймер? Большой ли смысл и много ли придется писать для такой фишки. Может есть там особенность - нужен отдельный таймер для записи в эту память и отдельная функция для чтения...
Стоит ли гемор свечь?
Ещё один в по-своему красивый вариант с 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;
}Тут не понял, зачем что-то сохранять и где. В EEPROM можно хранить некое начальное значение таймера. Или несколько часто используемых. Про ROM не понял, что именно Вы под ним понимаете.krokodandi писал(а):На сколько целесообразно сохранять содержимое h и m в eeprom или просто как говорится, в ROM
- Сообщения: 47
- Зарегистрирован: Ср ноя 12, 2014 14:48:39
Я про EEPROM. Именно про этот вид ПЗУ.
Тут описан некий вариант http://microsin.net/programming/AVR/sav ... inavr.html
Вроде бы он короткий, но кроме него еще что-то надо?
А что за запись сточкой? ind[3] = num[t32.tens];
Странная запись...
hour.value = 0x01;
min.value = 0x00;
sec.value = 0x08;
По моему это совсем оригинальный стиль
Спасибо. Буду дальше осваивать матчасть. Очень интересные варианты.
Если что будет новенькое, обновлю тему.
Тут описан некий вариант http://microsin.net/programming/AVR/sav ... inavr.html
Вроде бы он короткий, но кроме него еще что-то надо?
А что за запись сточкой? ind[3] = num[t32.tens];
Странная запись...
hour.value = 0x01;
min.value = 0x00;
sec.value = 0x08;
По моему это совсем оригинальный стиль
Спасибо. Буду дальше осваивать матчасть. Очень интересные варианты.
Если что будет новенькое, обновлю тему.
- Реклама

