На первом уроке мы научились подавать напряжение ножкой микроконтроллера. Теперь нужно научиться управлять микроконтроллером без перепрошивки.
Зачем это нужно? Например, вы сделали часы на микроконтроллере, нужно выставить время, но очень не удобно каждый раз перепрошивать, когда собьется время. Намного удобнее пользоваться кнопками, например, одной менять часы, другой минуты.
Помните в первом уроке мы настраивали ножку как выход, т.е. мы могли ей подавать напряжение. Так вот, ножку можно настроить как вход. В таком режиме можно проверить есть ли на ней напряжение или нет.
Пример: создаем проект при помощи мастера проектов. Первую ногу настраиваем как выход, вторую как вход. При создании мастером проектов указываем, что ножка PB1 будет входом, на ней же включаем подтягивающий резистор, реализуется это так:
После создания проекта приведем код к такому виду:
#include <mega8.h> #include <delay.h> void main(void) { PORTB=0x02; DDRB=0x01; while (1) { if(PINB.1==0) { PORTB.0=1; delay_ms(100); PORTB.0=0; delay_ms(100); } }; } |
Как мы видим, по сравнению с первым уроком изменилась настройка порта
PORTB=0x02; DDRB=0x01; |
Подробнее о том что значат данные строки можно почитать тут
Также появилась новая строчка
if(PINB.1==0) {} |
данную строчку нужно читать так — если на ножке 1 порта В подключили землю (0 потенциал), то выполнить код в фигурных скобках. В нашем примере это код из первого урока. Если кнопка не замкнута, то ничего не делать. Промоделировать можно в Proteuse.
Вместо кнопки можно поставить датчик, реле и т.п., вместо светодиода — пищалку, получится сигнализация.
Архив с прошивкой и файлом протеуса доступен тут
Update1: Зачем нужна подтяжка порта?
У входа мк большое сопротивление, если будут течь даже микротоки вызванные помехами, то по закону Ома U=R*I это может привести к тому, что на входе появится лог 1. Чтобы не было таких проблем в AVR микроконтроллерах можно подключить ножку к плюсу питания, через подтягивающий резистор. В этом случае даже, логика работы меняется наоборот — но если появится помеха, нам это не важно, ведь у нас на входе уже логическая единица.
Почему подключение через резистор? Допустим мы подключили вход к плюсу напрямую без резистора. Когда кнопка сработает, она притянет вход к земле, поэтому на входе будет короткое замыкание между + и землей. Если же стоит резистор, то при замыкании кнопки с одной стороны он так и останется подключен к +, а со второй стороны на нем появится земля от кнопки. Через резистор потечет ток, но его величина будет не такой большой.
Update2: Добавлен тест, в котором вы можете проверить на сколько хорошо вы усвоили материал урока
Админ, заходит, проверил. поставил задержки и вкл, выкл светодиод. в протеусе светодиод постоянно мигает.
ок следующий шаг, смотрите в протеусе заходит ли в условие, после определенного значения ацп
админ, да условия идет. написал если значения меньше того что я поставил значит мигать светодиодом, если нет то не мигать. все вроде работает) 😛
админ, наверное дело в кнопках было, малая задержка не помогает от дребезга или пока кнопка нажата то в это времья контроллер пару раз намотает. в общем тот код что выше я давал я написал только для верха, для низа так все и оставил. Включаю протеус и давай кнопкой додавать и отнимать верх. Все норм, работает, тогда взял низ плюсовать , нажал кнопку + и как начнут моргать диоди, что на елке. думаю низ стал выше чем верх, но как, минимум 4 раза нужно нажать что бы до значения верха достать. короче поместил и в низ значения, теперь нормально плюсует и минусует ). И тут ко мне мисль пришла, это ж надо как то условия написать что бы низ всегда меньше был верха, а то неопитный начнет на кнопки нажимать, так сгорит все)
добрый вечер
подскажите пожалуйста как прервать цикл внутри цикла
PORTD.0=1;PORTC.0=1;PORTB.7=1;PORTB.0=1;
delay_ms(1000);
PORTB.0=0;
while(1)
{
//ИНДИКАТОРЫ//
if(PIND.5==0) //STOP
{
PORTB.3=1;
}
else
{
PORTB.3=0;
}
if(PIND.6==0) //START
{
PORTB.4=1;
}
else
{
PORTB.4=0;
}
if(PIND.5==0) //ПУСК//
{
while (2)
{
//ИНДИКАТОРЫ//
if(PIND.2==0) //EMERG (АВАРИЯ)
{
PORTD.7=1;
}
else
{
PORTD.7=0;
}
if(PIND.0==0) //UPPER (ВЕРХНИЙ УРОВЕНЬ)
{
PORTC.4=1;
}
else
{
PORTC.4=0;
}
if(PIND.3==0) //MIN
{
PORTB.1=1;
}
else
{
PORTB.1=0;
}
if(PIND.4==0) //MAX
{
PORTB.2=1;
}
else
{
PORTB.2=0;
}
// EMERG (АВАРИЯ)//
if(PIND.2==0)
{
PORTC.0=0;
}
else
{
PORTB.7=1;PORTC.0=1;PORTC.1=0;PORTC.2=0;
}
// МАНОМЕТР//
if(PIND.3==0) //НИЗКОЕ ДАВЛЕНИЕ//
{
PORTC.1=1;
}
else
{
if(PIND.4==0) //ВЫСОКОЕ ДАВЛЕНИЕ//
{
PORTC.1=0;
}
}
//УРОВЕНЬ ВОДЫ//
if((PIND.0==0)&(PIND.2==1))
{
PORTB.7=1;PORTB.5=1;
}
else
{
if(PIND.0==0)
{
PORTB.7=0;
}
}
if(PIND.2==1)
{
PORTB.7=1;
}
else
{
PINB.7=0;
}
}
}
}
}
break
Админ извините за назойлевость,
Но цикл должен останавливаться при подачи сигнала на PORTD.6, у меня никак не получается.
Подробное описание как использовать break найти не смог.
Заранее спасибо
я у вас не увидел условия Pind.6
if(PIND.6==0)
{
break;
}
Админ спасибо Вам за Ваши уроки, очень помогают
оператор «break» вписал во втором цикле
if(PIND.6==0)break;
немного изменил условие остальных портов и все работает замечательно
ещё раз СПАСИБО
Всем доброго времени суток. Такой вопрос: codevisionavr не сохраняет проект в формате HEX. Помогите кто чем сможет))
он и не должен. hex появляется после компиляции
Очень полезный сайт!
Прям, подзавис тут! 😛
Спасибо большое за подробные уроки!
Очень хорошо, популярным языком, всё расписано.
Тест, в конце — порадовал!
Всё классно! Продолжайте это полезное, хорошее и интересное дело!
Спасибо Вам.
День добрый адмие. Есть такой вопрос или недопонимания. По поводу одной кнопкой управлять двумя режимами. Коротко нажал, будет уменьшать переменную, подержал дольше будет включать или отключать. (пример). Так вот, немного не доходит алгоритм. Сначала в условии если кнопка нажата заходим, и запускаем таймер и ждем, если меньше 100 пощитало значит это мы уменьшаем, а если больше то это уже другая задача. Както так? но если я правильно понял, кнопка должна быть на ножке по внешнему захвату. Или не туда смотрю. ?
не туда, смотрите в сторону внешних прерываний
хорошо. нажал на кнопку, зашло в преривания. дальше как, я сдесь не могу понять . делать цикл wile (pinx==1) // кнопка нажата
{
_delay_ms(1000);
a++;
return a;
}
потом if (a==1)
делаем то то
а=0;
if (a==2)
делаем другое
а=0;
опишу мисль свою, может так не понятно написано. Короче по прериванию заходим в цикл while , там наша переменная которая подождав секунду добавит 1. и так как ми уде не держим кнопку то виходим с цикла со значением а =1. и проверяеться условия в теле программи. Другой случай когда мы держим кнопку боольше секунди цикл как минимум 2 раза сработает у нас и а станет у нас 2. возвращаем значения а. что скажите?
заходим в первое прерывание, по спаду, запускаем аппаратный таймер. заходим во второе прерывание, по нарастанию, останавливаем таймер. смотрим время. выполняем выбор того что сделать. одна проблема дребезг, его придется отдельно обрабатывать.
а чем мой вариант плох? и дребезг можно устранить.
можно и по вашему, если программа позволяет
Но спасибо вам и за ваш пример. но думаю думаю с кнопками по дребезгу проблеми будут.
подскажите тут вот описано что кнопка если нажата то у ней цикл будет бесконечен до следующего откл.
а как написать так чтобы при на жатии и оставлении кнопки в нажатом положении led загорелся допустим 15сек и погас и чтобы цикл не повторялся
условиями if
в ассемблере покажите пожалуйста
у меня так
while (1)
{ if (PINC.0==0) {
PORTC.1=1;
delay_ms(3000);
PORTC.1=0;
PORTC.2=1;
delay_ms(3000);
PORTC.2=0;
};
а надо чтобы после нажатия на кнопку и появления if (PINC.0==0) прога отработала с условиями PINC.0==0 дальше программа чтобы убидилась в том что 0 держится болеее 5сек значит выполнить цикл и остановиться в конце цикла .Помоги пожалуйста
добавьте задержку в 5 сек и остановитесь в каком нибудь while(1)
это как
протеус на помойку/*вот эта программа работает в протеусе в железе не работает
* as_buton 1.cpp
*
* Created: 23.01.2016 5:14:10
* Author : User
*/
#define F_CPU 10000000UL
#include
#include
#include
volatile unsigned int r=0;
volatile unsigned char pauza=0;
volatile uint8_t pauza_ofv;
ISR(INT0_vect)
{
r++;
pauza=0;
//OCR2=250;//когда пдключаем вход OCR2 счёт идёт на этот вход
TCNT2=0;
}
ISR(INT1_vect)
{
r—;
pauza=0;
//OCR2=250;//когда пдключаем вход OCR2 счёт идёт на этот вход
TCNT2=0;
}
ISR(TIMER2_COMP_vect)
{
pauza++;
}
ISR(TIMER0_OVF_vect)
{
//pauza_ofv++;
}
void Program_15()
{
if (pauza==0)
{
PORTC|=(1<<0);
}
if (pauza==10)
{
PORTC&=~(1<<0);
}
if (pauza==11)
{
PORTC|=(1<<1);
}
if (pauza==21)
{
PORTC&=~(1<<1);
}
if (pauza==22)
{
PORTC|=(1<<2);
}
if (pauza==32)
{
PORTC&=~(1<<2);
}
if (pauza==33)
{
PORTC|=(1<<3);
}
if (pauza==43)
{
PORTC&=~(1<<3);
}
if (pauza==44)
{
PORTC|=(1<<2);
}
if (pauza==54)
{
PORTC&=~(1<<2);
}
if (pauza==55)
{
PORTC|=(1<<1);
}
if (pauza==65)
{
PORTC&=~(1<<1);
}
if (pauza==66)
{
PORTC|=(1<<0);
}
if (pauza==76)
{
PORTC|=(1<<1);
}
if (pauza==87)
{
PORTC|=(1<<2);
}
if (pauza==97)
{
PORTC|=(1<<3);
}
if (pauza==107)
{
PORTC&=~(1<<0);
}
if (pauza==117)
{
PORTC&=~(1<<1);
}
if (pauza==127)
{
PORTC&=~(1<<2);
}
if (pauza==137)
{
PORTC&=~(1<<3);
}
if (pauza==147)
{
PORTC|=(1<<0);
PORTC|=(1<<2);
}
if (pauza==157)
{
PORTC&=~(1<<0);
PORTC&=~(1<<2);
}
if (pauza==167)
{
PORTC|=(1<<1);
PORTC|=(1<<3);
}
if (pauza==177)
{
PORTC&=~(1<<1);
PORTC&=~(1<<3);
pauza=0;
}
}
void Program_14()
{
if (pauza==2)
{
PORTC|=(1<<0);
}
if (pauza==10)
{
PORTC|=(1<<1);
}
if (pauza==20)
{
PORTC|=(1<<2);
}
if (pauza==30)
{
PORTC|=(1<<3);
}
if (pauza==40)
{
PORTC&=~(1<<0);
}
if (pauza==50)
{
PORTC&=~(1<<1);
}
if (pauza==60)
{
PORTC&=~(1<<2);
}
if (pauza==70)
{
PORTC&=~(1<<3);
pauza=0;
}
}
void Program_13()
{
if (pauza==2)
{
PORTC|=(1<<3);
}
if (pauza==13)
{
PORTC&=~(1<<3);
}
if (pauza==15)
{
PORTC|=(1<<0);
}
if (pauza==26)
{
PORTC&=~(1<<0);
}
if (pauza==28)
{
PORTC|=(1<<1);
}
if (pauza==39)
{
PORTC&=~(1<<1);
}
if (pauza==41)
{
PORTC|=(1<<2);
}
if (pauza==52)
{
PORTC&=~(1<<2);
}
if (pauza==84)
{
PORTC&=~((1<<0)|(1<<1)|(1<<2)|(1<<3));
pauza=0;
}
}
void Program_12()
{
if (pauza==1)
{
PORTC|=(1<<3);
}
if (pauza==10)
{
PORTC&=~(1<<3);
}
if (pauza==11)
{
PORTC|=(1<<2);
}
if (pauza==20)
{
PORTC&=~(1<<2);
}
if (pauza==21)
{
PORTC|=(1<<1);
}
if (pauza==30)
{
PORTC&=~(1<<1);
}
if (pauza==31)
{
PORTC|=(1<<0);
}
if (pauza==40)
{
PORTC&=~(1<<0);
pauza=0;
}
}
void Program_11()
{
if (pauza==2)
{
PORTC|=(1<<0);
}
if (pauza==20)
{
PORTC&=~(1<<0);
}
if (pauza==22)
{
PORTC|=(1<<0);
}
if (pauza==40)
{
PORTC&=~(1<<0);
}
if (pauza==42)
{
PORTC|=(1<<1);
}
if (pauza==60)
{
PORTC&=~(1<<1);
}
if (pauza==62)
{
PORTC|=(1<<1);
}
if (pauza==80)
{
PORTC&=~(1<<1);
}
if (pauza==82)
{
PORTC|=(1<<2);
}
if (pauza==100)
{
PORTC&=~(1<<2);
}
if (pauza==102)
{
PORTC|=(1<<2);
}
if (pauza==120)
{
PORTC&=~(1<<2);
}
if (pauza==122)
{
PORTC|=(1<<3);
}
if (pauza==140)
{
PORTC&=~(1<<3);
}
if (pauza==142)
{
PORTC|=(1<<3);
}
if (pauza==160)
{
PORTC&=~(1<<3);
pauza=0;
}
}
void Program_10()
{
if (pauza==2)
{
PORTC|=(1<<0);
PORTC|=(1<<3);
}
if (pauza==20)
{
PORTC&=~(1<<0);
PORTC&=~(1<<3);
}
if (pauza==22)
{
PORTC|=(1<<1);
PORTC|=(1<<2);
}
if (pauza==40)
{
PORTC&=~(1<<1);
PORTC&=~(1<<2);
pauza=0;
}
}
void Program_9()
{
if (pauza==20)
{
PORTC|=(1<<0);
PORTC|=(1<<1);
}
if (pauza==40)
{
PORTC&=~(1<<0);
}
if (pauza==42)
{
PORTC|=(1<<2);
}
if (pauza==62)
{
PORTC&=~(1<<1);
}
if (pauza==64)
{
PORTC|=(1<<3);
}
if (pauza==86)
{
PORTC&=~(1<<2);
}
if (pauza==88)
{
PORTC&=~(1<<3);
pauza=0;
}
}
void Program_8()
{
if (pauza==20)
{
PORTC|=(1<<0);
PORTC|=(1<<1);
PORTC|=(1<<2);
PORTC|=(1<<3);
}
if (pauza==40)
{
PORTC&=~(1<<0);
PORTC&=~(1<<1);
PORTC&=~(1<<2);
PORTC&=~(1<<3);
pauza=0;
}
}
void Program_7()
{
if (pauza==2)
{
PORTC|=(1<<0);
PORTC|=(1<<1);
PORTC|=(1<<2);
PORTC|=(1<<3);
}
if (pauza==20)
{
PORTC&=~(1<<0);
}
if (pauza==22)
{
PORTC|=(1<<0);
PORTC&=~(1<<1);
}
if (pauza==42)
{
PORTC|=(1<<1);
PORTC&=~(1<<2);
}
if (pauza==44)
{
PORTC|=(1<<2);
PORTC&=~(1<<3);
}
if (pauza==64)
{
PORTC|=(1<<3);
pauza=0;
}
}
void Program_6()
{
if (pauza==2)
{
PORTC|=(1<<0);
PORTC|=(1<<2);
}
if (pauza==20)
{
PORTC&=~(1<<0);
PORTC&=~(1<<2);
}
if (pauza==22)
{
PORTC|=(1<<1);
PORTC|=(1<<3);
}
if(pauza==42)
{
PORTC&=~(1<<1);
PORTC&=~(1<<3);
pauza=0;
}
}
void Program_5()
{
if (pauza==2)
{
PORTC|=(1<<0);
}
if (pauza==4)
{
PORTC&=~(1<<0);
}
if (pauza==22)
{
PORTC|=(1<<1);
}
if (pauza==22)
{
PORTC&=~(1<<1);
}
if (pauza==42)
{
PORTC|=(1<<2);
}
if (pauza==44)
{
PORTC&=~(1<<2);
}
if (pauza==62)
{
PORTC|=(1<<3);
}
if (pauza==64)
{
PORTC&=~(1<<3);
pauza=0;
}
}
void Program_4()
{
if (pauza==10)
{
PORTC|=(1<<0);
}
if (pauza==20)
{
PORTC|=(1<<1);
}
if (pauza==30)
{
PORTC|=(1<<2);
}
if (pauza==40)
{
PORTC|=(1<<3);
}
if (pauza==50)
{
PORTC&=~(1<<0);
}
if (pauza==60)
{
PORTC&=~(1<<0);
}
if (pauza==70)
{
PORTC&=~(1<<1);
}
if (pauza==80)
{
PORTC&=~(1<<2);
}
if (pauza==90)
{
PORTC&=~(1<<3);
pauza=0;
}
}
void Program_3()
{
if (pauza==10)
{
PORTC|=(1<<0);
PORTC|=(1<<2);
}
if (pauza==15)
{
PORTC&=~(1<<0);
PORTC&=~(1<<2);
}
if (pauza==16)
{
PORTC|=(1<<1);
PORTC|=(1<<3);
}
if (pauza==21)
{
PORTC&=~((1<<1)|(1<<3));
pauza=0;
}
}
void Program_2()
{
if (pauza==1)
{
PORTC|=(1<<0);
}
if (pauza==10)
{
PORTC&=~(1<<0);
}
if (pauza==11)
{
PORTC|=(1<<1);
}
if (pauza==19)
{
PORTC&=~(1<<1);
}
if (pauza==20)
{
PORTC|=(1<<2);
}
if (pauza==29)
{
PORTC&=~(1<<2);
}
if (pauza==30)
{
PORTC|=(1<<3);
}
if (pauza==39)
{
PORTC&=~(1<<3);
pauza=0;
}
}
void Program_1()
{
if (pauza==0)
{
PORTC|=(1<<0);
}
if (pauza==10)
{
PORTC&=~(1<<0);
}
if (pauza==11)
{
PORTC|=(1<<1);
}
if (pauza==21)
{
PORTC&=~(1<<1);
}
if (pauza==22)
{
PORTC|=(1<<2);
}
if (pauza==32)
{
PORTC&=~(1<<2);
}
if (pauza==33)
{
PORTC|=(1<<3);
}
if (pauza==43)
{
PORTC&=~(1<<3);
}
if (pauza==44)
{
PORTC|=(1<<2);
}
if (pauza==54)
{
PORTC&=~(1<<2);
}
if (pauza==55)
{
PORTC|=(1<<1);
}
if (pauza==65)
{
PORTC&=~(1<<1);
pauza=0;
}
}
void nastroyki()
{
DDRB=0xFF;
PORTB=0x00;
DDRC=0xFF;
PORTC=0x00;
DDRD=0x00;
PORTD=0xFF;
GICR=(1<<INT1)|(1<<INT0);//регистр подключения INT1.INT0(PORTB3.PORTB2)в режиме прерывания
MCUCR=(0<<ISC11) | (0<<ISC10) | (0<<ISC01) | (0<<ISC00);//регистр срабатывания прерывания по лог 0 INT1.INT0
GIFR=(1<<INTF1) | (1<<INTF0);//флаги об оканчания прерывания (регистр)выставлен в лог 1
OCR2=250;//когда пдключаем вход OCR2 счёт идёт на этот вход
TCCR0|=(1<<CS02)|(0<<CS01)|(1<<CS00);
TCNT0=2;
TCNT2=0;//счетный регистр
TIMSK|=(1<<OCIE2) | (0<<TOIE2) | (0<<TICIE1) | (0<<OCIE1A) | (0<<OCIE1B) | (0<<TOIE1) | (0<<TOIE0);//регистр маски прерываний он уст 1 прерывание по сравнению
//ASSR=0<<AS2;
TCCR2|=(1<<WGM21)|(1<<CS22) | (0<<CS21) | (1<<CS20);//регистр управления 0 и2 биты установлены в лог 1 f/1023 частота работы таймера f-частота работы AVR
TIFR|=(1<<OCF2)|(0<=или > знаки сравнения то нужно запрещать прерывания и по окончанию программы разрешать прерывания
asm(«cli»);-запрещать
asm(«sei»);-разрешать
для переключения программ «+» используется кнопка SB1 «-» кнопка SB2lдля отключения используется кнопка RESET
все эти кнопки используются в прерывании в цикле прерывании ISR при этом счётчик выставляется в нули для надёжного переключения программ
16 программа возращяет в 1 прогамму программы расположены с низу вверх задействован порт со светодиодами PORTC мечты иногда осуществляются .
*/
каждая из программ работает в отдельности.работа по таймеру .
Написана программа в AS 7
протеус не эмулирует дребезг кнопок
спасибо за подсказку и извените меня за нетактичность .Я эту программу пересмотрел и нашёл лишний ноль в частоте.и IN1 уже регулирует скорость герлянды регистром OCR2 я электрик и мне это интересно учился и учусь сам методом проб и ошибок спасибо вам за информацию за «кирпичики здание я хочу построить сам»
Можно совет уже не один вечер бьюсь над этой программой.Как сделать опрос кнопки против дребезга контактов.Один программист мне порекомендовал не применять прерывание но как же тогда менять эффекты?Как в прерывании я могу устранить дребезг контактов или это нужно прописывать в основном цикле.
я обычно опрашиваю в прерывании по таймеру.
не могли бы показать пример или ссылку дать.Извените за назойливость.А можна отказаться от прерывания по кнопке? если есть такая возможность .То каким образом это можно реализовать?
я же вам ответил что проверяйте в прерывании от таймера, просто читайте состояние кнопки и все. как настроить в 5 уроке.
int i = 0;
interrupt [EXT_INT0] void ext_int0_isr(void)
{
if(!PINB.1){i++;}
}
void main(void)
{
while (i==1)
{
PORTB.2=1;
};
while (i==2)
{
PORTB.2=0;
};
}
подскажите почему не работает?
спасибо, я сам разобрался
Подскажите пожалуйста почему при переходе от while(i==1) к while(i==2) на PORTB.2 так и остаётся лог.1 и цикл прокручивается до конца а не сразу переходит к следующему.
while (i==1)
{ if(m==3){PORTB.2=1;}
else{PORTB.2=0;}
break;
};
while (i==2)
{
if(s==6){PORTB.3=1;}
else{PORTB.3=0;}
break;
};
очевидно потому что м=3
Почему при включении выключении питания срабатывает кнопка
возможно стоит фьюзами выставить задержку при старте