sergo80zxc, ключевое слово static добавьте к переменным i, k. Или объявите их глобально. В противном случае их значение после выхода из функции не сохраняется и они всегда равны 0 при входе в прерывание.
if (PINB & (1 << PB0)) // Если нулевой разряд порта D установлен, то выполняется (Код1). В противном случае, выполняется (Код2).
{
k++; // (Код1) пин PB0 установлен(кнопка не нажата) прибавим 1 к переменной счетчику
} else {
i++; // (Код2) пин PB0 сброшен(кнопка нажата) прибавим 1 к переменной счетчику
}
//----------
if (i >= 3) // если счетчик больше или равен 3 то, кнопка нажата была при всех опросах,
{
if (k >= 3) {
PORTB ^= (1 << PB1); // инвертируем состояние пина PB1
i = 0; //
k = 0; //
}
}
Не так. Подумайте. Кнопка у вас не нажата большую часть времени. Каждое перепонение таймера у вас k будет увеличиваться. И в итоге переполняться и начинать с 0. В итоге нажатие будет отрабатываться случайно. В большинстве случаев будет так - нажали кнопки и пока еще держите, индикатор переключается. Как только отпупустили - индикатор переключился назад.
Надо как-то так:
if (!(PINB & (1 << PB0)) && i < 3) // Если нулевой разряд порта D установлен, то выполняется (Код1). В противном случае, выполняется (Код2). Усл. i < 3 нужно, чтобы i не переполнялся пока кнопка нажата.
i++; // (Код2) пин PB0 сброшен(кнопка нажата) прибавим 1 к переменной счетчику
//----------
if (i >= 3) // если счетчик больше или равен 3 то, кнопка нажата была при всех опросах,
{
if (PINB & (1 << PB0))
k++; // (Код1) пин PB0 установлен(кнопка не нажата) прибавим 1 к переменной счетчику
if (k >= 3) {
PORTB ^= (1 << PB1); // инвертируем состояние пина PB1
i = 0; //
k = 0; //
}
}
[uquote="ARV",url="/forum/viewtopic.php?p=3827489#p3827489"]не всегда нужно, а когда положено правилами. а то постоянно вижу, как при въезде на круговое движение поворот показывают, а при съезде - нет.[/uquote]
Вот. Это как раз тот случай когда рефлексы не закреплены.)
Добавлено after 6 minutes 37 seconds:
Особенно это важно в некоторых видах спорта. Зачастую взади едущий вообще ничего не видит и без твоих сигналов/знаков для него это будет просто катастрофа.)
ау товарищи сишные коты, где я ошибся? переменные пробовал после майна объявлять не помогает, ругается студия, что мол не используются эти переменные в главной программе
Последний раз редактировалось sergo80zxc Ср апр 15, 2020 08:22:34, всего редактировалось 1 раз.
не, не после майна, а перед прерываниями, после инклюдов и дефайнов
Для тех, кто не учил магию мир полон физики
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
[uquote="sergo80zxc",url="/forum/viewtopic.php?p=3827563#p3827563"]ау товарищи сишные коты, где я ошибся? переменные пробовал после майна объявлять не помогает, ругается студия, что мол не используются эти переменные в главной программе[/uquote]
Я же написал - допишите static к ним просто.
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1200000 UL
int main(void) {
DDRB = 0b11111110; // бит РВ0 конфигурируем как вход
PORTB = 0b00000001; // входы подтянем
TIMSK0 = 0b00000010; //бит РВ1(TOIE0) устанавливаем в 1, разрешения прерывания по переполнению таймера /счетчика Т0
TCCR0A = 0b00000000; //биты РВ0(WGM00) и РВ1(WGM01) сбрасываем в 0, настройка режима Normal
TCCR0B = 0b00000011; //настраиваем предделитель на 64 (биты CS02=0,CS01=1,CS00=1) , бит В3(WGM02) сбрасываем в 0,настройка режима Normal
GTCCR = 0b00000001; //бит РВ0(PSR10) устанавливаем в 1, Сброс предделителя TO (сбрасываем пред. в конце настроек)
sei(); //Разрешить прерывания
while (1) {
//Основной цикл программы, он пуст, так как вся работа в прерывании
}
}
ISR(TIM0_OVF_vect) //обработчик прерывания по таймеру Т0
{
static volatile int i = 0; // объявляем переменную счетчик и обнуляем ее
static volatile int k = 0; // объявляем переменную счетчик и обнуляем ее
if (!(PINB & (1 << PB0)) && i < 3) // Если нулевой разряд порта D установлен, то выполняется (Код1). В противном случае, выполняется (Код2). Усл. i < 3 нужно, чтобы i не переполнялся пока кнопка нажата.
i++; // (Код2) пин PB0 сброшен(кнопка нажата) прибавим 1 к переменной счетчику
//----------
if (i >= 3) // если счетчик больше или равен 3 то, кнопка нажата была при всех опросах,
{
if (PINB & (1 << PB0))
k++; // (Код1) пин PB0 установлен(кнопка не нажата) прибавим 1 к переменной счетчику
if (k >= 3) {
PORTB ^= (1 << PB1); // инвертируем состояние пина PB1
i = 0; //
k = 0; //
}
}
}
/*
*
* АТИНИ13
*пример настройки прерывания по таймеру Т0
*
*
*
*грамотно организована программа мигания светодиода на прерывании, не расходует основные ресурсы МК в
*
*
*
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1200000UL
volatile int i = 0; // объявляем переменную счетчик и обнуляем ее
volatile int k = 0; // объявляем переменную счетчик и обнуляем ее
int main(void)
{
DDRB = 0b11111110; // бит РВ0 конфигурируем как вход
PORTB = 0b00000001; // входы подтянем
TIMSK0 = 0b00000010; //бит РВ1(TOIE0) устанавливаем в 1, разрешения прерывания по переполнению таймера /счетчика Т0
TCCR0A = 0b00000000; //биты РВ0(WGM00) и РВ1(WGM01) сбрасываем в 0, настройка режима Normal
TCCR0B = 0b00000011; //настраиваем предделитель на 64 (биты CS02=0,CS01=1,CS00=1) , бит В3(WGM02) сбрасываем в 0,настройка режима Normal
GTCCR = 0b00000001; //бит РВ0(PSR10) устанавливаем в 1, Сброс предделителя TO (сбрасываем пред. в конце настроек)
sei(); //Разрешить прерывания
while(1)
{
//Основной цикл программы, он пуст, так как вся работа в прерывании
}
}
//-------------------------------------------------------------------------------------------------------------------------------------------
ISR(TIM0_OVF_vect) //обработчик прерывания по таймеру Т0
{
if (i>10) // проверяем счетчик , если он больше 10 то мы обнулим его
{
i = 0; // обнуляем счетчик
}
if (k>10) // проверяем счетчик , если он больше 10 то мы обнулим его
{
k = 0; // обнуляем счетчик
}
//----------------------------------------------------------------------------------------------------------------------------------------------
if (PINB & (1<<PB0)) // Если нулевой разряд порта D установлен, то выполняется (Код1). В противном случае, выполняется (Код2).
{
k++; // (Код1) пин PB0 установлен(кнопка не нажата) прибавим 1 к переменной счетчику
}
else
{
i++; // (Код2) пин PB0 сброшен(кнопка нажата) прибавим 1 к переменной счетчику
}
//----------------------------------------------------------------------------------------------------------------------------------------------
if (i>=3 ) // если счетчик i больше или равен 3 то, кнопка была нажата при 3 опросах подряд
{
if (k>=3 ) // тогда проверяем была ли она отпущена 3 раза подряд
{
PORTB ^= (1<<PB1); // да была отпущена и мы инвертируем состояние пина PB1
i = 0; // обнуляем счетчик
k = 0; // обнуляем счетчик
}
}
}
Добавлено after 3 minutes 28 seconds:
NStorm а ваш код работает без сбоев
[uquote="sergo80zxc",url="/forum/viewtopic.php?p=3827614#p3827614"]NStorm а ваш код работает без сбоев[/uquote]
Я вам даже выше объяснил и расписал почему )
Добавлено after 2 minutes 5 seconds:
[uquote="ARV",url="/forum/viewtopic.php?p=3827608#p3827608"]статик можно и не обнулять, обнулится и так. даже нужно не обнулять, если памяти программ мало.[/uquote]
Да = 0 у integer ничего не значит на самом деле. Оно и так 0 изначально. Статик или нет, тут значения не имеет. На память никак не повлияет. Я код ТС копи-пастил просто.
Добавлено after 4 minutes 37 seconds:
Хотите глобальные - легко. Только недопускайте переполнения:
Спойлер
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1200000 UL
volatile int i, k; // объявляем переменные счеткиков. = 0 можно не писать, переменные всегда инициализируются нулем если не указано иное.
int main(void) {
DDRB = 0b11111110; // бит РВ0 конфигурируем как вход
PORTB = 0b00000001; // входы подтянем
TIMSK0 = 0b00000010; //бит РВ1(TOIE0) устанавливаем в 1, разрешения прерывания по переполнению таймера /счетчика Т0
TCCR0A = 0b00000000; //биты РВ0(WGM00) и РВ1(WGM01) сбрасываем в 0, настройка режима Normal
TCCR0B = 0b00000011; //настраиваем предделитель на 64 (биты CS02=0,CS01=1,CS00=1) , бит В3(WGM02) сбрасываем в 0,настройка режима Normal
GTCCR = 0b00000001; //бит РВ0(PSR10) устанавливаем в 1, Сброс предделителя TO (сбрасываем пред. в конце настроек)
sei(); //Разрешить прерывания
while (1) {
//Основной цикл программы, он пуст, так как вся работа в прерывании
}
}
ISR(TIM0_OVF_vect) //обработчик прерывания по таймеру Т0
{
if (!(PINB & (1 << PB0)) && i < 3) // Если нулевой разряд порта D установлен, то выполняется (Код1). В противном случае, выполняется (Код2). Усл. i < 3 нужно, чтобы i не переполнялся пока кнопка нажата.
i++; // (Код2) пин PB0 сброшен(кнопка нажата) прибавим 1 к переменной счетчику
//----------
if (i >= 3) // если счетчик больше или равен 3 то, кнопка нажата была при всех опросах,
{
if (PINB & (1 << PB0))
k++; // (Код1) пин PB0 установлен(кнопка не нажата) прибавим 1 к переменной счетчику
if (k >= 3) {
PORTB ^= (1 << PB1); // инвертируем состояние пина PB1
i = 0; //
k = 0; //
}
}
}
А ваш код работает нестабильно, потому что обнуляются у вас переменные по достижению 11 вне зависимости от нажатия кнопки. В итоге и работает код со сбоем. Обнулять надо только тогда, когда отработали нужное вам действие. А чтобы не переполнялась - надо лишь добавить условие увеличивать переменную только если они ниже некоего нужного значения.
NStorm писал(а):Да = 0 у integer ничего не значит на самом деле. Оно и так 0 изначально. Статик или нет, тут значения не имеет. На память никак не повлияет. Я код ТС копи-пастил просто.
конкретно "тут", т.е. для локальных переменных, еще как имеет! обнуляться автоматически тут будет только static.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
if (!(PINB & (1 << PB0)) && i < 3) // Если нулевой разряд порта D НЕ установлен (т.е. кнопка нажата, на пине лог. 0), И ЕСЛИ i меньше 3, то увеличиваем i на 1 (i++).
i++;
На асме это было 2 условных перехода. На C это еще можно расписать так:
//тини13
//
//прога NStorm, вкл и выкл нагрузки тактовой кнопкой через таймер
//все четко работает, чуть упростил форму записи
//
//
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1200000 UL
volatile int i= 0, k= 0; // объявляем переменные счеткиков. i-счетчик нажатой кнопки, k-счетчик отпущеной кнопки
int main(void)
{
DDRB = 0b11111110; // бит РВ0 конфигурируем как вход
PORTB = 0b00000001; // входы подтянем
TIMSK0 = 0b00000010; // бит РВ1(TOIE0) устанавливаем в 1, разрешения прерывания по переполнению таймера /счетчика Т0
TCCR0A = 0b00000000; // биты РВ0(WGM00) и РВ1(WGM01) сбрасываем в 0, настройка режима Normal
TCCR0B = 0b00000011; // настраиваем предделитель на 64 (биты CS02=0,CS01=1,CS00=1),бит В3(WGM02) сбрасываем в 0,режим Normal
GTCCR = 0b00000001; // бит РВ0(PSR10) устанавливаем в 1, Сброс предделителя TO (сбрасываем пред. в конце настроек)
sei(); // Разрешить прерывания
while (1)
{ // Основной цикл программы, он пуст, так как вся работа в прерывании
}
}
ISR(TIM0_OVF_vect) // обработчик прерывания по таймеру Т0
{
//-------- Проверка разряда на наличие логического нуля (сброса) с if--------
if (~PINB & (1 << PB0)) // Если нулевой разряд порта В сброшен (т.е. кнопка нажата, на пине лог. 0) выполняется КОД1.
{
if (i < 254) // КОД1. И ЕСЛИ i меньше 254, то увеличиваем i на 1 (i++) (это условие от переполнения счетчика i )
{
i++;
} // то есть счетчик может доходить до 254. (i < 254) то есть 253 максимальное число возможное в
} // этом условии и постинкремент +1 = 254
if (i >= 5) // если счетчик равен 5 то, кнопка нажата была при всех опросах, то ловим отпускание
{
if (PINB & (1 << PB0)) // ----------- Проверка разряда на наличие логической единицы (установки) с if
{ // Если 0 разряд порта PВ установлен (единица), то выполняется Код1, если нет , то Код2
if (k < 254) // И ЕСЛИ k меньше 254, то увеличиваем k на 1 (i++) (это условие от переполнения счетчика k )
{
k++; // (Код1) пин PB0 установлен(кнопка не нажата) прибавим 1 к переменной счетчику
if (k > 5) // если насчитали больше 5 не нажатых состояний, то считаем , что кнопку отпустили
{
PORTB ^= (1 << PB1); // инвертируем состояние пина PB1
i = 0; // обнуляем счетчик
k = 0; // обнуляем счетчик
}
}
}
}
}
Руки бы отрывать за такую писанину. Программа должна быть максимально простой, а у вас на..еверчено на ровном месте. Прерывание обязательно нужно использовать?
volatile int i= 0, k= 0; - int по-умолчанию 16-битные. Да еще и со знаком. Нет смысла считать 16-битные переменные там, где они не бывает больше 255.
volatile unsigned char i= 0, k= 0; - вот такие переменные тогда уж. unsigned - беззнаковая, char - 1 байтовая (8 битная) переменная. Т.е.. от 0 до 255.
OKF хотелось бы увидеть версию профессионала если можно) думаю для всех ассемблирщиков желающих перейти на си это будет очень интересно и важно (только на таймере без делай если можно)
//тини13
//
//прога NStorm, вкл и выкл нагрузки тактовой кнопкой через таймер
//все четко работает, чуть упростил форму записи
//тут дефайнами называем пины кнопку и светодиод
//
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1200000 UL
#define key PB0 // пин В0 теперь зовется key
#define LED PB1 // пин В1 порта В зовется LED
volatile unsigned char i= 0, k= 0; // объявляем переменные счеткиков. i-счетчик нажатой кнопки, k-счетчик отпущеной кнопки
//-------------------------------------------------------------------------------------------------------------------------------------------
int main(void)
{
DDRB = 0b11111110; // бит РВ0 конфигурируем как вход
PORTB = 0b00000001; // входы подтянем
TIMSK0 = 0b00000010; // бит РВ1(TOIE0) устанавливаем в 1, разрешения прерывания по переполнению таймера /счетчика Т0
TCCR0A = 0b00000000; // биты РВ0(WGM00) и РВ1(WGM01) сбрасываем в 0, настройка режима Normal
TCCR0B = 0b00000011; // настраиваем предделитель на 64 (биты CS02=0,CS01=1,CS00=1),бит В3(WGM02) сбрасываем в 0,режим Normal
GTCCR = 0b00000001; // бит РВ0(PSR10) устанавливаем в 1, Сброс предделителя TO (сбрасываем пред. в конце настроек)
sei(); // Разрешить прерывания
while (1)
{ // Основной цикл программы, он пуст, так как вся работа в прерывании
}
}
//-------------------------------------------------------------------------------------------------------------------------------------------
ISR(TIM0_OVF_vect) // обработчик прерывания по таймеру Т0
{
//-------- Проверка разряда на наличие логического нуля (сброса) с if--------
if (~PINB & (1 << key)) // Если нулевой разряд порта В сброшен (т.е. кнопка нажата, на пине лог. 0) выполняется КОД1.
{
if (i < 254) // КОД1. И ЕСЛИ i меньше 254, то увеличиваем i на 1 (i++) (это условие от переполнения счетчика i )
{
i++;
} // то есть счетчик может доходить до 254. (i < 254) то есть 253 максимальное число возможное в
} // этом условии и постинкремент +1 = 254
//--------------------------------------------------------------------------------------------------------------------------------------
if (i >= 5) // если счетчик равен 5 то, кнопка нажата была при всех опросах, то ловим отпускание
{
if (PINB & (1 << key)) // ----------- Проверка разряда на наличие логической единицы (установки) с if
{ // Если 0 разряд порта PВ установлен (единица), то выполняется Код1, если нет , то Код2
if (k < 254) // И ЕСЛИ k меньше 254, то увеличиваем k на 1 (i++) (это условие от переполнения счетчика k )
{
k++; // (Код1) пин PB0 установлен(кнопка не нажата) прибавим 1 к переменной счетчику
if (k > 5) // если насчитали больше 5 не нажатых состояний, то считаем , что кнопку отпустили
{
PORTB ^= (1 << LED); // инвертируем состояние пина PB1
i = 0; // обнуляем счетчик
k = 0; // обнуляем счетчик
}
}
}
}
}
OKF я писал на делай выше, но встретил на форуме мнения товарищей по опытнее меня, которые справедливо как я думаю заметили, с делай не очень профессионально и забивает основной цикл программ мк, они объяснили, что опросы кнопок лучше делать на таймерах, а мк загрузить чем то полезным, если задач у мк больше, чем опрос кнопок, то эти делай будут тормозить основную программу. обычно ж надо опросить кнопки, вывести на дисплей параметры, замерить показания датчиков