Использование микроконтроллеров существенно упрощает построение светодиодных мигалок. Светодиодная мигалка - это, наверное, одно из самых подходящих устройств для изготовления новичками в области построения схем на микроконтроллерах. Здесь приведен пример построения мигалки и исходный код для микроконтроллера ATmega8 на языке C++.
На сайте myrobot.ru в разделе "шаг за шагом" понятным языком описано как программировать микроконтроллеры и часть информации, приведенной здесь, взята от туда. Рассмотрим схему приведенную на рисунке:
Пусть кнопка SB1 будет для переключения режима мигания, а кнопка SB2 для изменения частоты мигания. Исходный код приведен ниже:
int main(void)
{
DDRD = 0xff; /* все выводы порта D сконфигурировать как выходы */
DDRC = 0x00; //выводы порта С сконфигурировать как входы
PORTC = 0xff; // установить "1" на всех выводах порта C,
// включаем подтягивающие резисторы
int i=0; //для задержек
int j=0; //для смены битов порта D
int d=20; //для изменения периода миганий
int sw=0; //для изменения режимов миганий
while (1) // Бесконечный цикл
{
if (!(PINC & (1<<PINC4))) //если логический ноль на 4 бите порта С
{
sw++; //преключить режим миганий
if(sw>4)sw=0;
}
if (!(PINC & (1<<PINC3))) //если логический ноль на 3 бите порта С
{
d+=20; //увеличить период миганий
if(d>260)d=20;
}
switch(sw)
{
case 0:
DDRD |= 1<<j;
for(i=0;i<d;i++)_delay_us(50);
DDRD &= ~(1<<j);
for(i=0;i<d;i++)_delay_us(50);
j++;
if(j>3)j=0;
break;
case 1:
DDRD |= 1<<j;
for(i=0;i<d;i++)_delay_us(50);
DDRD &= ~(1<<j);
for(i=0;i<d;i++)_delay_us(50);
j--;
if(j<0)j=3;
break;
case 2:
DDRD &= ~(1<<j);
for(i=0;i<d;i++)_delay_us(50);
DDRD |= 1<<j;
for(i=0;i<d;i++)_delay_us(50);
j++;
if(j>3)j=0;
break;
case 3:
DDRD &= ~(1<<j);
for(i=0;i<d;i++)_delay_us(50);
DDRD |= 1<<j;
for(i=0;i<d;i++)_delay_us(50);
j--;
if(j<0)j=3;
break;
case 4:
DDRD=0xff;
for(i=0;i<d;i++)_delay_us(50);
DDRD=0x00;
for(i=0;i<d;i++)_delay_us(50);
break;
}
}
}
При каждой итерации цикла while проверяется нажатие кнопок. Если нажата кнопка SB1 то переменная sw инкрементируется. Если переменная sw равна нулю (это проверяет команда switch) то в нулевой бит порта D записывается единица, потом происходит задержка, после чего в этот бит записывается ноль, затем снова задержка, потом переменная j инкрементируется и, если кнопка SB1 не была нажата, то все повторяется для следующего бита и таким образом происходит "движение светодиода", когда переменная j становится больше трех, ей присваивается ноль и все повторяется. Если нажимается кнопка SB1 то sw увеличивается и если она была равна нулю то она становиться равной единице и тогда происходит тоже что и при sw равной нулю только j теперь не инкрементируется а декрементируется (за счёт этого "движение светодиода" происходит в другую сторону) а при становлении j меньше нуля ей присваивается 3 и всё повторяется. Если sw равно двум или трем то происходит тоже только "бегущий светодиод" инвертирован, потому что порядок записи нуля и единицы в биты портов изменен. Если sw равно четырем то мигают все светодиоды. Если нажата кнопка SB2 то переменная d увеличивается на 20 и т.о. увеличиваются все задержки, следовательно увеличивается период мигания светодиодов при всех режимах. Если d>260 то ей снова присваивается значение 20 и период миганий резко уменьшается (частота увеличивается).
Исходный код компилировался в hex файл программой WinAVR. hex файл записывался в микроконтроллер программой PonyProg.
Не увидел С++ в примере :)
ОтветитьУдалитьКак бы выглядел данный код будь он написан на
ОтветитьУдалитьС++??? (если С++ в примере нет).
Ни смотря на то как, чем и т.д. был написан этот код он был записан в микроконтроллер и всё заработало как надо! Цель была достигнута!
Зачем выделять память под int если хватит unsigned char?
ОтветитьУдалитьИ не плохо бы на нажатие кнопки сделать проверку на залипание... короче, код для новичка просто ужасен, плохому со старта научится.
ОтветитьУдалитьИ не _delay_us(), а _delay_ms()
Удалить_delay_us() -для микросекунд,
ОтветитьУдалить_delay_ms() -для миллисекунд
(если я не ошибаюсь).
unsigned char занимает 1 байт,
int занимает 2 байт (или 4 точно не знаю)
поэтому для экономии памяти лучше использовать unsigned char.
В atmeg8 8Мб доступной памяти поэтому для данной простой программы это не так важно, это просто надо учитывать.
Дребезг контактов при данном коде ПОЧТИ не страшен так как состояние вывода к которому подключена кнопка проверяется относительно редко и контакты, в большинстве случаев, успевают "продребезжать" прежде чем кнопка провериться.
А что подразумевается под залипанием?
Когда контакты не размыкаются после нажатия или что-то программное или что-то ещё?
Что-то типа:
ОтветитьУдалитьif (PINC.1 ==1)
{
while (PINC.1 == 1) { }
... код для выполнения
}
Спасибо за ответ!
ОтветитьУдалитьПоправка:
У atmega8 8кбайт а не 8Мбайт доступной флеш-памяти, согласно даташиту: http://www.atmel.com/images/doc2486.pdf