Форум myROBOT.ru » Лаборатория » Алгоритмы » Индикатор на двух светодиодах о повышенных/заниженных оборотах

Страниц (3): « 1 [2] 3 »
 

16. nestandart - 14 Ноября, 2013 - 23:27:07 - перейти к сообщению
Насколько я знаю , функция прерывания запускается по сигналу внешнего прерывания (нажатие кнопки).

Но для того чтобы сделать действие только с пятого нажатия можно в этой функции считать срабатывания , +1 к определенной переменной и при определенном значении переменной запустить ваши действия в функции прерывания.

т.е.
{
v++;
if(v>=5)
{
digitelWrite(13,!digitalRead(13));//инвертируем 13 пин (светодиод)
v=0;//обнуляем переменную

}
17. Alex_och - 14 Ноября, 2013 - 23:54:46 - перейти к сообщению
На пятый раз понятно - это количество
А 5 раз в секунду - частота.

Вот как ему сказать - кнопка нажата с частотой 5 раз/с - гори
6 раз/с - не гори
Понимаю, что с такой частотой не каждый нажмет кнопку, цифры то можно поменять.
18. Петр Киселев - 16 Ноября, 2013 - 06:50:30 - перейти к сообщению
Alex_och пишет:
Вот как ему сказать - кнопка нажата с частотой 5 раз/с - гори
6 раз/с - не гори


А применить счетчик не пробовал? На выходы счетчика поставить логику, которая выдавала сигнал при достижения счетчиком состояния 0101. Потом счетчик сбрасывается и все начинается сначала.
19. Роботов - 16 Ноября, 2013 - 14:58:18 - перейти к сообщению
Надо измерять длительность периода нажатия.
Например, при частоте нажатия 5 раз в секунду, период будут составлять 200 мс, а при нажатии 6 раз в секунду около 167 мс.
Измеряйте длительность таймером, и делов-то)))
20. Alex_och - 17 Ноября, 2013 - 12:49:48 - перейти к сообщению
Я подозревал, что надо конечно и таймер использовать и без прерываний тоже наверно не обойтись. Просто я не знаю как это правильно описывать в программе. С таймерами и прерываниями еще не рабртал. Вот и хочу разобраться на нужном мне примере
21. Alex_och - 17 Ноября, 2013 - 17:06:25 - перейти к сообщению
Вот в инете нашел код измерителя частоты
http://radioparty.ru/index.php/p...requency-meter-1

Описание "Чтобы измерить частоту сигнала необходимо подсчитать количество импульсов, поступающих на вход микроконтроллера, за единицу времени. Для этого в нашей программе используем два типа перерывания: прерывание по переполнению таймера T0 и внешнее прерывание по изменению сигнала на входе INT0. Количество поступающих на вход сигналов будем подсчитывать за время - 1 секунда. Восьмибитный таймер T0 будет работать с частотой 1MHz, для этого включим предделитель на 8. Обработчик прерывания по переполнению таймера вызывается 4000 раз в секунду, при этом переменная counter увеличивает свое значение на единицу. Как только эта переменная станет равна 4000, т.е. пройдет 1 секунда, на дисплей уйдет информация о переменной edgecounter, затем обе переменные обнуляются. Все это происходит уже в главном цикле. Переменная edgecounter увеличивает свое значение на единицу каждый раз когда на входе INT0 происходит смена фронта сигнала, т.е. поступает 1 импульс."

ВОТ требуху с lcd можно выкинуть с кода и дописать под светодиоды.
Кто что скажет???

// Измерение частоты сигнала с помощью микроконтроллеров AVR. Простой частотомер.
#include<avr/io.h>
#include<avr/interrupt.h>
#include<util/delay.h>

volatile unsigned int edgecounter = 0, counter = 0;

// Обработчик прерывания по переполнению Т0, вызывается 4000 раз в секунду
ISR(TIMER0_OVF_vect)
{
TCNT0 = 6; // Счетчик Т0 начинает считать с 6, т.к. 1MHz/(256-6) = 4000Hz
counter++;
}
// Обработчик внешнего прерывания
ISR(INT0_vect)
{
edgecounter++;
}

// Функции работы с LCD
#define RS PD0
#define EN PD1
// Функция передачи команды
void lcd_com(unsigned char p)
{
PORTD &= ~(1 << RS); // RS = 0 (запись команд)
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
}
// Функция передачи данных
void lcd_data(unsigned char p)
{
PORTD |= (1 << RS)|(1 << EN); // RS = 1 (запись данных), EN - 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
}

// Функция вывода строки на LCD
void lcd_string(unsigned char command, char *string)
{
lcd_com(0x0C);
lcd_com(command);
while(*string != '\0'Подмигивающий
{
lcd_data(*string);
string++;
}
}

// Функция вывода переменной
void lcd_num_to_str(unsigned int value, unsigned char nDigit)
{
switch(nDigit)
{
case 4: lcd_data((value/1000)+'0'Подмигивающий;
case 3: lcd_data(((value/100)%10)+'0'Подмигивающий;
case 2: lcd_data(((value/10)%10)+'0'Подмигивающий;
case 1: lcd_data((value%10)+'0'Подмигивающий;
}
}
// Функция инициализации LCD
void lcd_init(void)
{
_delay_ms(50); // Ожидание готовности ЖК-модуля

// Конфигурирование четырехразрядного режима
PORTD |= (1 << PD5);
PORTD &= ~(1 << PD4);

// Активизация четырехразрядного режима
PORTD |= (1 << EN);
PORTD &= ~(1 << EN);
_delay_ms(5);

lcd_com(0x28); // шина 4 бит, LCD - 2 строки
lcd_com(0x08); // полное выключение дисплея
lcd_com(0x01); // очистка дисплея
_delay_us(100);
lcd_com(0x06); // сдвиг курсора вправо
lcd_com(0x0C); // включение дисплея, курсор не видим
}

int main(void)
{
PORTD = 0x00; // Настраиваем входы/выходы
DDRD = 0b11110011;

TCCR0 |= (1 << CS01); // Предделитель на 8, частота таймера 1 MHz
TIMSK |= (1 << TOIE0); // Разрешаем прерывание от таймера Т0

GICR |= (1 << INT0); // Разрешаем внешнее прерывание на входе INT0
MCUCR |= (1 << ISC01)|(1 << ISC00); // Внешнее прерывание формируется по переднему фронту

sei(); // Глобально разрешаем прерывания

lcd_init(); // Инициализация дисплея

lcd_com(0x01);
lcd_string(0x80, "Frequency Meter"Подмигивающий;
lcd_string(0xC0, "F = Hz"Подмигивающий;

while(1)
{
// Выводим показания на дисплей
if(counter == 4000)
{
lcd_com(0xC4);
lcd_num_to_str(edgecounter, 4);
counter = 0;
edgecounter = 0;
}
}
}
22. Alex_och - 20 Ноября, 2013 - 15:39:46 - перейти к сообщению
Вопрос решился с помощью автора данного кода выше.

Частота атмеги 8 МГц

#include<avr/io.h>
#include<avr/interrupt.h>
#include<util/delay.h>

volatile unsigned int edgecounter = 0, counter = 0;

// Обработчик прерывания по переполнению Т0, вызывается 4000 раз в секунду
ISR(TIMER0_OVF_vect)
{
TCNT0 = 6; // Счетчик Т0 начинает считать с 6, т.к. 1MHz/(256-6) = 4000Hz
counter++;
}
// Обработчик внешнего прерывания
ISR(INT0_vect)
{
edgecounter++;
}

int main(void)
{
PORTD = 0x00; // Настраиваем входы/выходы
DDRD = 0b11110011;

TCCR0 |= (1 << CS01); // Предделитель на 8, частота таймера 1 MHz
TIMSK |= (1 << TOIE0); // Разрешаем прерывание от таймера Т0

GICR |= (1 << INT0); // Разрешаем внешнее прерывание на входе INT0
MCUCR |= (1 << ISC01)|(1 << ISC00); // Внешнее прерывание формируется по переднему фронту

sei(); // Глобально разрешаем прерывания

while(1)
{
// Выводим показания на дисплей
if(counter == 4000)
{
if(edgecounter < 20) // Если частота меньше 20
PORTD |= (1 << PD0); // Включаем зеленый светодиод
else
PORTD &= ~(1 << PD0); // Выключаем зеленый светодиод

if(edgecounter > 40) // Если частота больше 40
PORTD |= (1 << PD1); // Включаем красный светодиод
else
PORTD &= ~(1 << PD1); // Включаем красный светодиод

counter = 0;
edgecounter = 0;
}
}
}

Всем спасибо, кто отзывался
23. cjA - 21 Ноября, 2013 - 02:09:46 - перейти к сообщению
тебе спасибо, если ответишь
чем отличаютя (В Си я не очень)
%% от %
\\ от \
## от #
@@ от @
&& от &
|| от |
и volatile ot static
24. Роботов - 21 Ноября, 2013 - 11:16:12 - перейти к сообщению
cjA пишет:
&& от &
|| от |

Это я знаю, это логические и арифметические операции Улыбка
25. Alex_och - 21 Ноября, 2013 - 12:50:21 - перейти к сообщению
cjA пишет:
тебе спасибо, если ответишь
чем отличаютя (В Си я не очень)
%% от %
\\ от \
## от #
@@ от @
&& от &
|| от |
и volatile ot static

Судя по времени Вашей регистрации на форуме и количеству сообщений, Вас мало интересует ответ на вопрос :
«чем отличаются (В Си я не очень)
%% от %
\\ от \
## от #
@@ от @
&& от &
|| от |
и volatile ot static»

Подозреваю Вас больше интересует почему в программе написано «volatile unsigned int » , хотя я могу ошибаться.

Но я отвечу на Ваши вопросы.

| побитовое ИЛИ
|| логическое ИЛИ
& побитовое И
&& логическое И

Спецификатор volatile информирует компилятор о том, что данная переменная
Может быть изменена внешними (по отношению к программе) факторами.

Спецификатор volatile сообщает компилятору о том, что значение соответствующей переменной может быть изменено в программе не явным образом. Например, адрес некоторой глобальной переменной может передаваться управляемой прерываниями подпрограмме тактирования, которая обновляет эту переменную с приходом каждого импульса сигнала времени. В такой ситуации содержимое переменной изменяется без использования явно заданных инструкций программы. [C++]


Локальная static-переменная поддерживает свое значение между вызовами функции.

Если к локальной переменной применен модификатор static, то для нее выделяется постоянная область памяти практически также, как и для глобальной переменной. Это
позволяетстатическойпеременнойпо ддерживатьеезначениемеждувызовам ифункций.

(Другими словами, в отличие от обычной локальной переменной, значение static-
переменной не теряется при выходе из функции.) Ключевое различие между статической
локальной и глобальной переменными состоит в том, что статическая локальная переменная известна только блоку, в котором она объявлена. Таким образом, статическую
локальнуюпеременнуювнекоторойстепениможноназватьглобальнойпеременной, которая имеет ограниченную область видимости. [C++]

static-переменная имеет статическое время жизни и "существует" всегда, как и переменная, объявленная "до" main (а та - именуется "глобальной"Подмигивающий. Но вот область видимости static-переменной ограничена: от точки ее объявления до конца блока, в котором она объявлена.
Вторая особенность заключается в моменте инициализации: если глобальные переменные гарантированно инициализируются к моменту первого использования единицы компиляции, в которой они объявлены, то для статической переменной гарантируется только то, что она будет инициализирована в тот момент, когда поток управления первый раз пройдет через точку ее объявления.

Остальные сочетания (%%, %, \\ , \, ##, # @@, @) в моем начальном уровне не встречал и думаю, что они не используются.
26. Vladimir72 - 21 Ноября, 2013 - 13:36:43 - перейти к сообщению
\ обратной косой я переносил строку например:

unsigned char sifra[ ]= {1,2,3,4,5,6,7,8,9,\
10,11,12,13,14,15};

удобно если строка длинная, компилятор понимает, что это одна строка
(Добавление)
Я предлагаю сделать тему хитрости в программировании, где каждый может поделиться своими наработками.
27. elmot - 22 Ноября, 2013 - 02:32:48 - перейти к сообщению
Vladimir72 пишет:
\ обратной косой я переносил строку например:

unsigned char sifra[ ]= {1,2,3,4,5,6,7,8,9,\
10,11,12,13,14,15};

удобно если строка длинная, компилятор понимает, что это одна строка
(Добавление)
Я предлагаю сделать тему хитрости в программировании, где каждый может поделиться своими наработками.


И в чем хитрость? Такая "хитрость" описана в любом учебнике по С.
28. Vladimir72 - 22 Ноября, 2013 - 15:03:24 - перейти к сообщению
я не говорил, что это хитрость, предлагал сделать тему.
(Добавление)
Alex_och пишет:
Остальные сочетания (%%, %, \\ , \, ##, # @@, @) в моем начальном уровне не встречал и думаю, что они не используются.
я привел пример, не какой хитрости нет)))
29. cjA - 23 Ноября, 2013 - 17:54:28 - перейти к сообщению
для датчика наверное нужно геркон взять (не велотренажер какой нибудь?)
Alex_och пишет:
А как сказать МК, что если кнопка была нажата 5 раз в секунду и только тогда выполнить действие (так называемое прерывание)

нужно запустить таймер на определенную частоту (ну вот раз в секунду). И считать внешние прерывания внутри таймера. Если =<4 - красная лампочка, если =>6 - зеленая. Если программа такая простая- не нужен и таймер, в основном цикле считаете прерывания. Но нужно в АврСтудио пощелкать сколько на основной цикл тиков уходит.
30. Alex_och - 23 Ноября, 2013 - 19:26:23 - перейти к сообщению
cjA пишет:
для датчика наверное нужно геркон взять (не велотренажер какой нибудь?)
Alex_och пишет:
А как сказать МК, что если кнопка была нажата 5 раз в секунду и только тогда выполнить действие (так называемое прерывание)

нужно запустить таймер на определенную частоту (ну вот раз в секунду). И считать внешние прерывания внутри таймера. Если =<4 - красная лампочка, если =>6 - зеленая. Если программа такая простая- не нужен и таймер, в основном цикле считаете прерывания. Но нужно в АврСтудио пощелкать сколько на основной цикл тиков уходит.

Нет не велотренажер.
Я выше писал, что хочу сделать для машины девайс, который как бы сигнализировал, что обороты занижены и нужно понизить передачу, обороты завышены - повысить передачу. Сигнал с питания катушки зажигания, но конечно не напрямую.

А разве таймеры тикают не раз в секунду. Я так понял, что тикают раз в секунду, но в эту секунду в зависимости от частоты МК и предделителя в эту секунду происходит определенное число "тиков" - своеобразная частота. Допустим 4000 тиков /с. И от этого плясать с прерываниями. И 0,5 с - 2000 тиков, 2 с - 8000 тиков. Если ошибаюсь поправьте.

"Но нужно в АврСтудио пощелкать сколько на основной цикл тиков уходит" - а об этом поподробней можно?

И еще у меня возникла задача. Второй день ломаю голову. То ли протеус тормозит, то ли что-то не правильно написано. Использую за основу вышеприведенный код изменив while.
Хочу сделать такую штуку. На INTO поступает одиночный сигнал в примерно величиной в 1 секунду - не происходит ни чего, поступает два одиночных сигнала с интервалом в секунду - загорается светодиод. Казалось бы вроде ничего сложного, но в протеусе как-то с запозданием загорается светодиод и то не всегда.
(Добавление)
Ооо, вроде получилось. Обнуление переменных перенес в описание таймера // ISR(TIMER0_OVF_vect) // из while.