В школе увлекался микроэллектроникой, ходил в радиокружок, собрал несколько простых устройств. Затем ВУЗ, работа, женитьба и о своем хобби очень редко вспоминал.
С появлением в моем доме интернета я узнал подробности о микроконтроллерах, посмотрел цены и загорелся желанием собрать что-нибудь на AVR или STM. Перечитал много форумов и подборок проектов на микроконтроллерах, но все было что-то не то, а понять «что не так» не мог. Вроде интересная вещь музыкальный плеер проигрывающий файлы с карты памяти, или часы будильник с термометром, да много еще чего, но ощущения что вот это я хочу так и не возникало…
Наткнулся на несколько статей о часах на газоразрядных индикаторах серии ИН и подобных, всплыло воспоминание из детства как в магазине я разглядывал цифры на весах, а они там отдельные в виде тонких проволочек и одна из них светится.
Решено — буду делать часы. Газоразрядные индикаторы работают при напржении около 180 вольт, поэтому для согласования с контроллером чаще всего используется микросхема к155ид1 — единственная высоковольтная микросхема, двоично-десятичный дешифратор. Для получения высокого напряжения в большинстве проектов также используется отдельная специализированная ШИМ микросхема. А во многих проектах еще и часы реального времени в виде отдельной микросхемы или готовой сборки.
Читая описание на сайте магазина для простого Atmega8 представлял себе что там и аналого-цифровой преобразователь и широтно-импульсная модуляция, последовательные интерфейсы и т.д., а используются они чще всего только для выполнения программы часов, даже дешифратор для индикатора ставится внешний. Обидно стало за микроконтроллер, он такой «могучий» а ему развернуться не дают.
В итоге минуя схему сразу стал рисовать печатную плату в SprintLayout и за пару недель родилась вот эта:
На одной плате все вместе с питанием, на другой только индикаторы:
В микроконтроллере atmega8 в данном проекте используются все три таймера, один из которых асинхронно работает от внешнего часового кварца. Сам контроллер работает на частоте 8 мегагерц от внутренней RC цепочки. ШИМ используется для генерации высокого напряжения в бустерном преобразователе, а напряжение контролируется аналоговым входом, и при необходимости корректурется скважность. Ну и 28 ног хватило чтобы засветить четыре индикатора ИН 12, и еще на пару лампочек осталось.
Вот как это выглядит в собранном виде:
И светится:
Часть функций контроллера конечно остались не использованными, но уже не так обидно когда рядом не стоят отдельный ШИМ и RTC.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
//Программа инициализации ШИМ
void init_pwm (void)
{
//Инициализация порта
DDRB=0xFF; //OC1A,OC1B,OC2 — выхода
TCCR1A=(1<<COM1B1)|(1<<WGM10)|(1<<WGM11); //Конфигурация счетчика OC1A
TCCR1B=(1<<CS10)|(1<<WGM12)|(1<<WGM13); //Конфигурация счетчика OC1B
//Установка начальных значений счетчиков
OCR1A=250;
OCR1B=215; //Выключен 0 от 200/170 до 250/215
}
volatile unsigned char second, minute, hour, h, m;
int voltage_ADC, dimm;
// Прерывание по переполнению Т2
ISR (TIMER2_OVF_vect)
{
if(second++ >= 59)
{
second = 0;
minute++;
}
if(minute > 59)
{
minute = 0;
hour++;
}
if(hour > 23)
hour = 0;
//set_time(hour,minute,second); // Выводим данные на дисплей
}
ISR (TIMER0_OVF_vect)
{
PORTC |= (1 << PC2);
}
ISR (ADC_vect)//прерывание по завершению преобразования АЦП
{
voltage_ADC = ADCW;//считываем значение АЦ преобразования
if(voltage_ADC<260 && OCR1A<300){OCR1A++;OCR1B=OCR1A-dimm;}
if(voltage_ADC>260 && OCR1A>170){OCR1A--;OCR1B=OCR1A-dimm;}
ADCSR |= (1<<ADSC);//запускаем очередное преобразование
}
//Основная программа
int main(void)
{
unsigned char r;
unsigned char mode;
init_pwm(); //Инициализация ШИМ каналов
PORTD=0x00; //Выставляем все выходы порта D на 0, то есть выключаем весь порт D
DDRD=0xFF; //Делаем порт D как выход, чтобы на выходах порта было напряжение 5В
PORTC = 0b00000000; DDRC = 0b11101111;
TIMSK &= ~(1 << OCIE2)|(1 << TOIE2); // Запрещаем прерывания по T2
ASSR |= (1 << AS2); // Включаем асинхронный режим T2
TCNT2 = 0; // Сбрасываем регистр счета
TCCR2 |= (1 << CS22)|(0 << CS21)|(1 << CS20); // Предделитель на 128-(32768/128 = 256 тиков/c)
TIMSK |= (1 << TOIE2); // Разрешаем прерывание по переполнению Т2
TCCR0|=(0<<CS02)|(1<<CS00);
//TIMSK |= (1 << TOIE0); // Разрешаем прерывание по переполнению Т2
//ads
ADMUX|= (1<<REFS0)|(1<<REFS1)|(1<<MUX2); //ВНУТРЕННЕЕ ОПОРНОЕ
//ADCSRA|=(1<<ADEN)|(1<<ADFR)|(1<<ADIE)|(1<<ADPS1)|(1<<ADPS0);
ADCSRA |= (1<<ADEN) | (1<<ADSC) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
sei(); // Глобально разрешаем прерывания
hour = 23; // Начальная установка времени
minute = 13;
second = 23;
mode=1;
while (1) //Вечный цикл
{
/*
PORTD |= (1 << PD1); // установка бита 1
PORTD &= ~ (1 << PD1); // сброс бита 1
*/
dimm=35;
PORTC &= ~ (1 << PC2);
if(mode==1){m=minute; h=hour;}
if(mode==2){m=second; h=minute;}
if(mode==3){m=voltage_ADC%100; h=voltage_ADC/100;};
for (r=0;r<4;r++)
{
if(r==1)
{
PORTC |= (1 << PC3);//минуты десятки
if (m/10==0) PORTD |= (1 << PD3);//0
if (m/10==1) PORTD |= (1 << PD2);//1
if (m/10==2) PORTB |= (1 << PB1);//2
if (m/10==3) PORTB |= (1 << PB3);//3
if (m/10==4) PORTB |= (1 << PB4);//4
if (m/10==5) PORTD |= (1 << PD5);//5
if (m/10==6) PORTD |= (1 << PD6);//6
if (m/10==7) PORTD |= (1 << PD7);//7
if (m/10==8) PORTB |= (1 << PB0);//8
if (m/10==9) PORTD |= (1 << PD4);//9
}
if(r==0)
{
PORTC |= (1 << PC5);//минуты единицы
if (m%10==0) PORTD |= (1 << PD3);//0
if (m%10==1) PORTD |= (1 << PD2);//1
if (m%10==2) PORTB |= (1 << PB1);//2
if (m%10==3) PORTB |= (1 << PB3);//3
if (m%10==4) PORTB |= (1 << PB4);//4
if (m%10==5) PORTD |= (1 << PD5);//5
if (m%10==6) PORTD |= (1 << PD6);//6
if (m%10==7) PORTD |= (1 << PD7);//7
if (m%10==8) PORTB |= (1 << PB0);//8
if (m%10==9) PORTD |= (1 << PD4);//9
}
if(r==2)
{
PORTD |= (1 << PD1);//часы десятки
if (h/10==0) PORTD |= (1 << PD3);//0
if (h/10==1) PORTD |= (1 << PD2);//1
if (h/10==2) PORTB |= (1 << PB1);//2
if (h/10==3) PORTB |= (1 << PB3);//3
if (h/10==4) PORTB |= (1 << PB4);//4
if (h/10==5) PORTD |= (1 << PD5);//5
if (h/10==6) PORTD |= (1 << PD6);//6
if (h/10==7) PORTD |= (1 << PD7);//7
if (h/10==8) PORTB |= (1 << PB0);//8
if (h/10==9) PORTD |= (1 << PD4);//9
}
if(r==3)
{
PORTD |= (1 << PD0);//часы единицы
if (h%10==0) PORTD |= (1 << PD3);//0
if (h%10==1) PORTD |= (1 << PD2);//1
if (h%10==2) PORTB |= (1 << PB1);//2
if (h%10==3) PORTB |= (1 << PB3);//3
if (h%10==4) PORTB |= (1 << PB4);//4
if (h%10==5) PORTD |= (1 << PD5);//5
if (h%10==6) PORTD |= (1 << PD6);//6
if (h%10==7) PORTD |= (1 << PD7);//7
if (h%10==8) PORTB |= (1 << PB0);//8
if (h%10==9) PORTD |= (1 << PD4);//9
}
_delay_ms(3);
PORTC &= ~ (1 << PC3);
PORTC &= ~ (1 << PC1);
PORTC &= ~ (1 << PC5);
PORTD &= ~ (1 << PD1);
PORTB=0x00;PORTC=0x00;PORTD=0x00;
_delay_ms(1);
}
}
}
Автор: alexhott