Я тут призадумался...
А можно сделать так чтобы при нажатии кнопки менялась пауза (при этом работая с делеем без таймера ), дело в том что если в скобки _deley_ms() ставишь переменную, то компилятор начинает материться, если задаешь значение например U через дефаин то все работает, но менять значения U уже нельзя

. Значит нужно изучать таймеры??
у функции _delay_ms() есть один ядреный недостаток: процессор крутится в этой функции и никак не может узнать, что-же там с кнопками.
итак рекомендую:
1) разобрать прерывания: для начала повесить прерывание на кнопку, чтобы обработчик заставил переключить светодиод, при этом в основной программе главный цикл пустой.
2) разобраться с дребезгом, чтобы одно нажатие было одним нажатием.
3) завести таймер: переключать светодиод по прерыванию от таймера.
для целевого количества миганий, для подсчета количества уже мигнутых ... нужно позаводить глобальных переменных.
хорошо, на счет делея вроде понял, но а что с этой проблемой делать
Andrey 2004 пишет:Проблема в том что у меня или получается бесконечный цикл (при первом нажатии кнопки цикл замыкается и не реагирует на дальнейшие нажатия);
Или получается сделать все это при помощи For где я действительно могу менять переменную i
,но при этом светодиод мигает до тех пор пока не достигнет значения переменной i а затем гаснет до следующего нажатия кнопки.
Здесь я не знаю о чем и думать, вроде все операторы более менее знаю, а подходящего варианта не нашел .
тут надо конкретно вашу программу смотреть - собственно даже не операторы, а алгоритм.
и да, теперь вы переходите на следующий уровень: от написания операторов к программированию (переход от быдлокодера к программисту).
подозреваю, что в бесконечном цикле крутится по причине того, что внутри цикла в принципе не опрашивает кнопку.
CODE:#define F_CPU 8000000UL //16MHz
#include <avr/io.h>
#include <util/delay.h>
#define l 10
volatile unsigned char i;
volatile unsigned char p;
int main(void) {
DDRB = 0xFF;
PORTB = 0x00;
DDRD=0x00;
PORTD=0xFF;
i=0;
while(1)
{
if (PIND & (1<<1))
{
_delay_ms(5);
if (PIND & (1<<1))
{
while (PIND & (1<<1)) {}
i++;
_delay_ms(10);
}
}
for(int p=0;p<i;p++)
{
PORTB=0b00000010;
_delay_ms(50);
PORTB=0b00000000;
_delay_ms(50);
}
}
}
Вот код от которого я "пляшу"
(Добавление)
сейчас скину свои неудачные варианты
(Добавление)
В принципе все мои попытки сводятся к одному соединить фор который может считать кол во
миганий и ваил который зацикливает что либо.Вот один из моих "кодов":
CODE:#define F_CPU 8000000UL //16MHz
#include <avr/io.h>
#include <util/delay.h>
#define l 10
volatile unsigned char i;
volatile unsigned char p;
int main(void) {
DDRB = 0xFF;
PORTB = 0x00;
DDRD=0x00;
PORTD=0xFF;
i=0;
while(1)
{
if (PIND & (1<<1))
{
_delay_ms(5);
if (PIND & (1<<1))
{
while (PIND & (1<<1)) {}
i++;
_delay_ms(10);
}
}
while (PIND & (1<<1))
{
for (p=0;p<i;p++)
{
PORTB=0b00000010;
_delay_ms(50);
PORTB=0b00000000;
_delay_ms(50);
if (PIND & (1<<1))
{
i++;
}
_delay_ms(200);
}
}
}
}
В первом случае у вас происходит проверка нажатия кнопки, после отпускания фиксируется факт нажатия и только тогда программа продолжает работать дальше.
Есть еще нюанс: в процессе мигания светодиодом (в цикле p=0;p<i;p++) проверка кнопки не происходит, то есть нужно нажать и держать пока не промигается.
Во втором случае чуть хуже: вы проверяете нажатие кнопки, после отпускания фиксируется факт нажатия и только тогда программа продолжает работать дальше. (пока как в первом случае)
А дальше, через 10 мс, в случае нажатой кнопки вы начинаете мигать, иначе снова проверять нажатие фиксировать. В общем чтобы начать мигать надо отпустить кнопку и за 10 мс успеть обратно нажать. Рекомендую перевести эту задачу на другую кнопку.
Благодарю за помощь!!!
Но мне кажется, что для решения моей последней задачи нужно изучить прерывания.
Тогда без лишних мучений можно будет написать этот код правильно.
Все сделал программу при помощи прерывания вот что получилось:
CODE:#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
volatile unsigned char i;
volatile unsigned char p;
ISR(INT1_vect)
{
i++;
_delay_ms(30);
}
int main(void)
{
DDRB |=(1<<1);
PORTB &=~(1<<1);
DDRD &=~(1<<3);
PORTD |=(1<<3);
i=0;
GICR |=(1<<7);// Разрешаем прерывание INT1
MCUCR =0b00000010;// Генерация сигнала при низком уровне на ножке PD3
sei();//Разрешить прерывания
while(1)
{
_delay_ms(50);
for(p=0;p<i;p++)
{
PORTB|=(1<<1);
_delay_ms(15);
PORTB &=~(1<<1);
_delay_ms(15);
}
}
}
Что смутило, у меня при попадании в "прерывание" процессор не просто "проходит" по коду
единожды, а выполняет этот код в течении некоторого времени. Таким образом, когда я в цикл прерывания писал просто " i++;" без задержки, процессор при первом нажатии кнопки PD3 присваивал переменной "i" не "1",а "41".
Так и должно быть??
Так и должно быть??
Это и есть дребезг контактов.
41 раз переколбасилась кнопка (контачит-не контачит) -> прерывание 41 раз вызвалось и отработало.
задержка и есть решение этой проблемы, на мой взгляд оптимальное, только я еще после задержки перепроверяю, что юзер всё еще держит кнопку, а не это помеха проскочила.
Мда... Про то что здесь может быть дребезг я и забыл.
Сейчас сижу балуюсь с внешними прерываниями, и вдруг понимаю что мне их не хватает,
в смысле не "их" а их количества

. А есть помимо INT0 и INT1 другие виды внешних прерываний???
В обработчике можно проводить анализ на тему "что случилось", если не хватает именно ног с прерываниями - тут сложнее.
Если собираетесь просто много кнопок насобирать, то их можно опрашивать по прерыванию от таймера, на 10 ног можно навесить 25 кнопок (5 строк-5столбцов).
Да, пока не хватает именно ног с прерываниями. Можете объяснить как проводить этот анализ?
если именно ног не хватает - не поможет.
Анализ - да всё просто (у пиков 16 - вообще одно прерывание на все случаи жизни) попадаем в обработчик и последовательно осматриваем регистры модулей, ищем кто вызвал.
С кнопками - примерно так:
сработало прерывание на таймер (пусть каждые 100 мс) - проверяем, что там с портом, если нажата кнопка - обрабатываем нажатие.
Если нужно обрабатывать не кнопку - тут сложнее, всё зависит от срочности реакции.
Predator пишет:С кнопками - примерно так:
сработало прерывание на таймер (пусть каждые 100 мс) - проверяем, что там с портом, если нажата кнопка -
Спасибо, понял, наверно так и сделаю.
(Добавление)
Вот сделал программу для семисегментного индикатора:
CODE://-----------------------------***Семисигментный индикатор c массивом***-----------------------------//
# define F_CPU 1000000UL
#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define razriad PORTC
#define chislo PORTB
unsigned int razr1 = 0, razr2 = 0, razr3 = 0, razr4 = 0;
unsigned char LOL;
//----------------------------------------------------------------------------------------//
ISR(TIMER0_OVF_vect)
{
if (LOL == 1) {razriad = 0b00000001; chislo = chisla [razr1];}
if (LOL == 2) {razriad = 0b00000010; chislo = chisla [razr2];}
if (LOL == 3) {razriad = 0b00000100; chislo = chisla [razr3];}
if (LOL == 4) {razriad = 0b00001000; chislo = chisla [razr4];}
LOL++;
if( LOL > 4 ) LOL = 0;
}
int chisla [10]=
{
0b00111111,//0
0b00000110,//1
0b01011011,//2
0b01001111,//3
0b01100110,//4
0b01101101,//5
0b01111101,//6
0b00000111,//7
0b01111111,//8
0b01101111,//9
};
void vse_chislo (unsigned int razbivka_chisla)
{
razr1 = razbivka_chisla/1000;//тысячи
razr2 = razbivka_chisla%1000/100;//сотни
razr3 = razbivka_chisla%100/10;//десятки
razr4 = razbivka_chisla%10;//еденицы
}
int main(void)
{
DDRC=0xFF;
PORTC=0x00;
DDRB=0xFF;
PORTB=0x00;
TCCR0|=(1<<1); TCCR0&= ~ ((1<<0)|(1<<2));
TIMSK|=(1<<0);
TCNT0 = 0;
sei();
//----------------------------------------------------------------------------------------//
razriad=0b00000001;
chislo = 0b00111111;
while(1)
{
vse_chislo (1987);
}
}
Но при компиляции выдает ошибку:
Error 'chisla' undeclared (first use in this function)
При двойном щелчке кидает вот сюда:
CODE:if (LOL == 1) {razriad = 0b00000001; chislo = (сюда)chisla [razr1];}
Что не так ??
CODE:
int chisla [10]=
{
0b00111111,//0
0b00000110,//1
0b01011011,//2
0b01001111,//3
0b01100110,//4
0b01101101,//5
0b01111101,//6
0b00000111,//7
0b01111111,//8
0b01101111,//9
};
перенесите выше, чем
CODE:
ISR(TIMER0_OVF_vect)
{
if (LOL == 1) {razriad = 0b00000001; chislo = chisla [razr1];}
if (LOL == 2) {razriad = 0b00000010; chislo = chisla [razr2];}
if (LOL == 3) {razriad = 0b00000100; chislo = chisla [razr3];}
if (LOL == 4) {razriad = 0b00001000; chislo = chisla [razr4];}
LOL++;
if( LOL > 4 ) LOL = 0;
}
иначе вы сперва используете, потом объявляете. Некоторые компиляторы умеют такое разруливать, но это скорее исключение.