Карма: 90
Рейтинг сообщений: 1435
Зарегистрирован: Чт мар 18, 2010 23:09:57 Сообщений: 4603 Откуда: Планета Земля
Рейтинг сообщения:1 Медали: 1
Опять пиар - "Я великий и могучий". Ни одного ответа на вопрос, ни слова в тему. Всё с вами понятно
Цитата:
К чему были вот эти ваши последние сообщения на этой странице??? Какую полезную инфу они несли?
Хорошо, будем значит по-другому, без всяких вопросов. Ещё раз увижу от вас бесполезные сообщения, опубликованные для набивания постов - улетите в БАНю за флуд. Бесполезность буду учитывать по своему вкусу, как и вы моё образование. Если есть ко мне личные вопросы - пишите в личку. Есть претензии - пишите Адимну.
правильно или нет - это только вам решать. я ж говорю: вы определите для себя набор правил и следуйте им всегда - это и будет правильно. главное, чтобы правила не противоречили здравому смыслу, а то проскакивало тут такое, что при помощи макросов некто приводил синтаксис Си к синтаксису паскаля... вот это уже извращение.
лично мне не очень нравится переменная или функция, наименование которой состоит из нескольких слов... но иногда просто деваться некуда: самодокументируемость кода для меня важнее удобства его написания.
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Подскажите пожалуйста, как правильно заполнить массив сразу блоком данных?
Код:
uint8_t states[24]={0xF0}; ... //где-то в процедуре void changeEffect(void){ switch(eff_id){ case 0: &states[0]=(0x00,0x10,0x80,0xF0,0x04,0x14,0x84,0xF4,0x06,0x16,0x86,0xF6);//Ошибка, но как-то так хотелось бы... break; ... }}
_________________ Не ошибается только то, кто ничего не делает. Тот, кто признает свои ошибки, на них учится. Глупец же, упорствуя в своих заблуждениях, остается глупцом.
Но уже готовый в libc и оптимизированный ) Хотя, если речь про ARM, то там векторные расширения имеются. Плюс libc в том, что будет выбран оптимизированный вариант для той платформы, под которую компилим.
_________________ Не ошибается только то, кто ничего не делает. Тот, кто признает свои ошибки, на них учится. Глупец же, упорствуя в своих заблуждениях, остается глупцом.
_________________ Не ошибается только то, кто ничего не делает. Тот, кто признает свои ошибки, на них учится. Глупец же, упорствуя в своих заблуждениях, остается глупцом.
Подскажите пожалуйста по коду. Нужно его переделать под таймер OCR2, чтобы можно было изменять скважность импульсов, а значит и яркость семисегментных индикаторов. Вот только что куда вставлять не пойму. Реализация изменения скважности импульсов показана тут http://radioparty.ru/prog-avr/program-c ... egment-avr Вот код программы которую нужно переделать под OCR2. Спойлер#define F_CPU 8000000UL // Тактовая частота микроконтроллера 8 МГц #define LEDS_OK // Раскомментировать, если используется индикатор с общим катодом
// Массив для перекодировки цифры в набор сегментов для семисегментного индикатора const uint8_t codes[16]= { (1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_F), // цифра 0 (1<<LED_SEG_B)|(1<<LED_SEG_C), // цифра 1 (1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_G), // цифра 2 (1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_G), // цифра 3 (1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // цифра 4 (1<<LED_SEG_A)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // цифра 5 (1<<LED_SEG_A)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // цифра 6 (1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_F), // цифра 7 (1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // цифра 8 (1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // цифра 9 0b00000000, // пробел (код 10) (1<<LED_SEG_G), // прочерк (код 11) (1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // символ градуса (код 12) (1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_F)|(1<<LED_SEG_G)|(1<<LED_SEG_DP), // зажечь все сегменты (код 13) (1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_G), // буква "c" для вывода слова "crc" (код 14) (1<<LED_SEG_E)|(1<<LED_SEG_G) // буква "r" для вывода слова "crc" (код 15) };
#define SEG_BLANK 10 // пробел #define SEG_MINUS 11 // прочерк #define SEG_DEGREE 12 // символ градуса #define SEG_ALL 13 // зажечь все сегменты #define SEG_C 14 // буква "c" для вывода слова "crc" #define SEG_R 15 // буква "r" для вывода слова "crc"
volatile uint8_t digit = 0; // Номер текущего знакоместа динамической индикации volatile uint8_t digit1 = 0; // Цифра или символ, выводимые в 1 знакоместо volatile uint8_t digit2 = 0; // Цифра или символ, выводимые во 2 знакоместо volatile uint8_t digit3 = 0; // Цифра или символ, выводимые в 3 знакоместо
uint8_t DS_scratchpad[9] = {0,0,0,0,0,0,0,0,0}; // 9 байт, считанных с DS18B20, или так называемый "блокнот" uint8_t Presense_errors = 0; // Счётчик ошибок - инициализация DS18B20 uint8_t Short_circuit_errors = 0; // Счётчик ошибок - КЗ линии данных DS18B20 int8_t Temperature = 0; // Температура преобразованная (целая часть градусов)
// Прерывание по переполнению таймера 0 (динамическая индикация) ISR (TIMER0_OVF_vect) { /////////////////////////////////// // Индикатор с общим анодом (ОА) /////////////////////////////////// // Выключаю все сегменты #ifndef LEDS_OK LED_SEG_PORT = ~(0b00000000);
// Деактивирую все знакоместа LED_DIG_PORT &= ~((1<<LED_DIG_1A)|(1<<LED_DIG_1B)|(1<<LED_DIG_2A)|(1<<LED_DIG_2B)|(1<<LED_DIG_3A)|(1<<LED_DIG_3B));
// Отображаю цифру в одном из знакомест switch (digit) { case 0: { LED_DIG_PORT |= (1<<LED_DIG_1A)|(1<<LED_DIG_1B); // Активирую 1 знакоместо LED_SEG_PORT = ~(codes[digit1]); // На сегментах отображаю цифру } break; case 1: { LED_DIG_PORT |= (1<<LED_DIG_2A)|(1<<LED_DIG_2B); // Активирую 2 знакоместо LED_SEG_PORT = ~(codes[digit2]); // На сегментах отображаю цифру } break; case 2: { LED_DIG_PORT |= (1<<LED_DIG_3A)|(1<<LED_DIG_3B); // Активирую 3 знакоместо LED_SEG_PORT = ~(codes[digit3]); // На сегментах отображаю цифру } break; };
/////////////////////////////////// // Индикатор с общим катодом (ОК) /////////////////////////////////// // Выключаю все сегменты #else LED_SEG_PORT = 0b00000000;
// Деактивирую все знакоместа LED_DIG_PORT |= (1<<LED_DIG_1A)|(1<<LED_DIG_1B)|(1<<LED_DIG_2A)|(1<<LED_DIG_2B)|(1<<LED_DIG_3A)|(1<<LED_DIG_3B);
// Отображаю цифру в одном из знакомест switch (digit) { case 0: { LED_DIG_PORT &= ~((1<<LED_DIG_1A)|(1<<LED_DIG_1B)); // Активирую 1 знакоместо LED_SEG_PORT = codes[digit1]; // На сегментах отображаю цифру } break; case 1: { LED_DIG_PORT &= ~((1<<LED_DIG_2A)|(1<<LED_DIG_2B)); // Активирую 2 знакоместо LED_SEG_PORT = codes[digit2]; // На сегментах отображаю цифру } break; case 2: { LED_DIG_PORT &= ~((1<<LED_DIG_3A)|(1<<LED_DIG_3B)); // Активирую 3 знакоместо LED_SEG_PORT = codes[digit3]; // На сегментах отображаю цифру } break; }; #endif
// Готовлюсь к отображению следующего знакоместа if (digit >= 2) digit = 0; else digit++; }
// Инициализирую DS18B20 void DS18B20_init (void) { if ((DS18B20_PIN & (1 << DS18B20)) == 0) Short_circuit_errors++; // Проверяю КЗ линии данных DS18B20_PORT &= ~(1 << DS18B20); // Устанавливаю низкий уровень DS18B20_DDR |= (1 << DS18B20); _delay_us(490); DS18B20_DDR &= ~(1 << DS18B20); _delay_us(68); if ((DS18B20_PIN & (1 << DS18B20)) > 0) Presense_errors++; // Ловлю импульс присутствия датчика // Если датчик не подключен, Presense_errors увеличиваю на 1 _delay_us(422); }
// Функция чтения байта из DS18B20 uint8_t DS18B20_read (void) { uint8_t dat = 0; for (uint8_t i=0; i<8; i++) { DS18B20_DDR |= (1 << DS18B20); _delay_us(2); DS18B20_DDR &= ~(1 << DS18B20); _delay_us(4); dat = dat >> 1; if (DS18B20_PIN & (1 << DS18B20)) { dat |= 0x80; } _delay_us(62); } return dat; }
// Функция чтения "блокнота" из DS18B20 void DS18B20_read_scratchpad (void) { for (uint8_t i=0; i<9; i++) // Считываю 9 байт данных, или так называемый "блокнот" { DS_scratchpad[i] = DS18B20_read(); } }
// Функция записи байта в DS18B20 void DS18B20_write (uint8_t dat) { for (uint8_t i=0; i<8; i++) { DS18B20_DDR |= (1 << DS18B20); _delay_us(2); if (dat & 0x01) { DS18B20_DDR &= ~(1 << DS18B20); } else { DS18B20_DDR |= (1 << DS18B20); } dat = dat >> 1; _delay_us(62); DS18B20_DDR &= ~(1 << DS18B20); _delay_us(2); } }
// Алгоритм для вычисления CRC-8 для DALLAS. // Для первого байта CRC = 0, для остальных - то, что получилось от предыдущего. // В расчёт CRC входят первые 8 байт DS18B20. // 1. Нахождение логического исключающего ИЛИ между младшим битом CRC и младшим битом данных. // 2. Если результат равен 0, то: // - Сдвиг вправо CRC. // 3. Если результат равен 1, то: // - Поиск нового значения CRC путем вычисления логического исключающего ИЛИ между CRC и полиномом CRC. // - Сдвиг вправо CRC. // - Установка старшего бита CRC в 1. // - Сдвиг вправо данных. // - Повтор данной последовательности 8 раз на 1 байт данных. uint8_t DS18B20_crc (uint16_t adress) { uint8_t crc = 0; // Переменная для накопления CRC for (uint8_t i=0; i<8; i++) // Считаю CRC 8-ми байт, 9-й байт это CRC { // Расчитываю CRC одного байта crc = crc ^ (*(uint16_t*)(adress+i)); for (uint8_t j=0; j<8; j++) { if (crc & 0x01) crc = (crc >> 1) ^ 0x8C; else crc >>= 1; } } return crc; // Возвращаю CRC }
// Главная программа int main (void) { // Настраиваю ножки МК для сегментов LED_SEG_DDR |= 0xFF; LED_SEG_PORT |= 0x00;
// При старте термометра делаю тест всех сегментов 0.5 секунды digit1 = SEG_ALL; digit2 = SEG_ALL; digit3 = SEG_ALL;
while(1) { DS18B20_init(); // Инициализирую DS18B20 DS18B20_write(0xCC); // Пропускаю проверку серийного номера DS18B20 DS18B20_write(0x44); // Запускаю температурное преобразование _delay_ms(1000); // Жду окончания температурного преобразования DS18B20_init(); // Инициализирую DS18B20 DS18B20_write(0xCC); // Пропускаю проверку серийного номера DS18B20 DS18B20_write(0xBE); // Команда на чтение содержимого ОЗУ DS18B20_read_scratchpad(); // Считываю "блокнот" if (Presense_errors | Short_circuit_errors) // Если датчик не отвечает на Presense-импульс, либо КЗ линии данных { // Cтавлю "---" во всех разрядах семисегментного индикатора digit1 = SEG_MINUS; digit2 = SEG_MINUS; digit3 = SEG_MINUS; } else { if (DS_scratchpad[8] == DS18B20_crc(&DS_scratchpad[0])) // Если принятая CRC совпала с расчётной CRC { Temperature = (int8_t)((DS_scratchpad[1] << 4)|(DS_scratchpad[0] >> 4)); // Совмещаю младший и старший байты, отбрасываю дробную часть, получаю температуру в градусах.
if (Temperature < 0) // Отрицательная температура { Temperature =-Temperature; // Перевожу отрицательное число в положительное digit1 = SEG_MINUS; // Символ "-" if (Temperature < 10) { // -9*...-1* digit2 = Temperature % 10; // Единицы градусов digit3 = SEG_DEGREE; // Символ градуса } else { // -55...-10 digit2 = Temperature % 100 / 10; // Десятки градусов digit3 = Temperature % 10; // Единицы градусов } } else // Положительная температура { if (Temperature > 99) { // 100...125 digit1 = Temperature % 1000 / 100; // Сотни градусов digit2 = Temperature % 100 / 10; // Десятки градусов digit3 = Temperature % 10; // Единицы градусов } else { if (Temperature > 9) { // 10*...99* digit1 = Temperature % 100 / 10; // Десятки градусов digit2 = Temperature % 10; // Единицы градусов digit3 = SEG_DEGREE; // Символ градуса } else { // 0*...9* digit1 = SEG_BLANK; // Пустой символ digit2 = Temperature % 10; // Единицы градусов digit3 = SEG_DEGREE; // Символ градуса } } } } else // Если принятая CRC не совпала с расчётной, выводим надпись "crc" на семисегментный индикатор { digit1 = SEG_C; // "c" digit2 = SEG_R; // "r" digit3 = SEG_C; // "c" } } Presense_errors=Short_circuit_errors=0; // Сбрасываю счётчик ошибок инициализации DS18B20, сбрасываю флаг КЗ } }
У вас индикатор обновляется по TIMER0, а для того, что вы хотите, нужен TIMER2. Поэтому настраивайте таймер-2, переделывайте ISR (TIMER0_OVF_vect) на ISR (TIMER2_OVF_vect) и добавляйте ISR (TIMER2_COMP_vect), в котором будете просто отключать общий электрод (анод/катод).
_________________ Каждый имеет право на свое личное ошибочное мнение.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
У вас индикатор обновляется по TIMER0, а для того, что вы хотите, нужен TIMER2. Поэтому настраивайте таймер-2, переделывайте ISR (TIMER0_OVF_vect) на ISR (TIMER2_OVF_vect) и добавляйте ISR (TIMER2_COMP_vect), в котором будете просто отключать общий электрод (анод/катод).
Прерывание по переполнению ISR (TIMER0_OVF_vect) просто заменить на ISR (TIMER2_OVF_vect) это понятно. А вот куда добавить прерывание по сравнению ISR (TIMER2_COMP_vect) не ясно. Не подскажите по коду?
Почитайте, полезно будет. Там же все понятно расписано. Это если общие аноды на порту В. Для ОК и другого порта надо делать изменения. Вставляете в любое место программы, но не внутрь другой функции.
Код:
// Обработчик прерывания по переполнению таймера 2 ISR (TIMER2_OVF_vect) { PORTB = 0x00; // Гасим все разряды }
Кроме того сам таймер настроить надо. Подсказывать не буду, в тексте по ссылке это тоже явно написано.
_________________ Каждый имеет право на свое личное ошибочное мнение.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 106
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения