Новичок
Регистрация: 23.07.2014
Сообщений: 1
Репутация: 10
![]() |
Здравствуйте, уважаемые посетители форума.
Я начинающий радиолюбитель, не так давно начал изучать микроконтроллеры AVR. Хотелось бы, чтобы Вы помогли с написанием исходника на Си... А вопрос, состоит в следующем - как написать программу устройства управления светодиодами (реле) при помощи одной кнопки, при нажатии на которую, светодиод (реле), подключённый к выходу микроконтроллера, будет менять своё состояние на противоположное. Конечно, эта задача легко решается при помощи обычного D —триггера, но всё же мне важно, как это сделать на микроконтроллере - программно… P.S. -Среда разработки - Atmel Studio 6. -Микроконтроллер - ATMega8. -Среда тестирования - Proteus ISIS 7. (схема в Протеусе - во вложении)
Последний раз редактировалось Александр Трунов; 23.07.2014 в 18:28.
|
||
Оценка
|
Новичок
Регистрация: 30.09.2013
Сообщений: 2
Репутация: 10
![]() |
простой опрос пинов и тригерная обработка. так конечно работать будет но это неправильно, желательно использовать прерывания, если задача требует мгновенной реакции. Для использования прерываний, читайте даташит. думаю вам пока что, надо тренироваться с ардуинкой.
Код:
//Изменение состояния светодиода в момент нажатия на кнопку: /* * atmega8_keys.c * * Created: 24.07.2014 16:00:00 * Author: Grigoriev Alexander */ #define F_CPU 1000000UL // 1 MHz #define LED_1 PD1 #define LED_2 PD0 #define KN1 PB0 #define KN2 PB1 #define LED_ON(LED) {sbi(DDRD, LED); sbi(PORTD, LED);} #define LED_OFF(LED) {sbi(DDRD, LED); cbi(PORTD, LED);} #include <avr/io.h> #include <compat/deprecated.h> #include <util/delay.h> int pkn1, pkn2; void init(); void delay_ms(int count) { while(count--) { _delay_ms(10); } } void init(){ // DDRD |= (1<<LED_1)|(1<<LED_2); //output sbi(DDRD,LED_2); //OUTPUT sbi(DDRD,LED_2); //OUTPUT cbi(PORTD,LED_1); // TO GND cbi(PORTD,LED_2); // TO GND cbi(DDRB,KN1); //input cbi(DDRB,KN2); //INPUT sbi(PORTB,KN1); //pullup TO vcc sbi(PORTB,KN2); //pullup TO vcc } int main(void) { init(); while(1){ if bit_is_clear(PINB,KN1) { _delay_ms(50); if bit_is_clear(PINB,KN1) pkn1=!pkn1; } if bit_is_clear(PINB,KN2) { _delay_ms(50); if bit_is_clear(PINB,KN2) pkn2=!pkn2; } if (pkn1) LED_ON(LED_1) else LED_OFF(LED_1); if (pkn2) LED_ON(LED_2) else LED_OFF(LED_2); } } |
||
Оценка
|
Специалист
Регистрация: 22.09.2010
Адрес: г. Донецк
Сообщений: 873
Репутация: 381
![]() ![]() ![]() ![]() |
Цитата:
Код:
... void delay_ms(int count) { while(count--) { _delay_ms(10); } } ... while(1){ if bit_is_clear(PINB,KN1) { _delay_ms(50); if bit_is_clear(PINB,KN1) pkn1=!pkn1; } if bit_is_clear(PINB,KN2) { _delay_ms(50); if bit_is_clear(PINB,KN2) pkn2=!pkn2; } if (pkn1) LED_ON(LED_1) else LED_OFF(LED_1); if (pkn2) LED_ON(LED_2) else LED_OFF(LED_2); } } При нажатии и удержании кнопки событие будет отработано много раз с каким-то периодом. При удержании двух кнопок результат непредсказуем и/или реакция затянется. При удержании одной и нажатии второй аналогично. Неудачный пример. Такой код лучше использовать в упомянутом обработчике внешних прерываний, сторонясь _delay, когда есть возможность отследить фронт. С _delay правильно так: Код:
#include <avr/io.h> #include <util/delay.h> int main(void) { uint8_t button0_event = 0x00; uint8_t button1_event = 0x00; PORTB |= _BV(PB0)|_BV(PB1); // Подтяжка DDRB &= ~(_BV(PB0)|_BV(PB1)); // Входы PORTD |= _BV(PD0)|_BV(PD1); DDRD |= _BV(PD0)|_BV(PD1); // Выходы while(1) { if(button0_event == 0x00) // Если предыдущее нажатие отработано и нажата кнопка 0 if(!(PINB & _BV(PB0))) { _delay_ms(20); // Антидребезг if(!(PINB & _BV(PB0))) // Если по-прежнему нажата { PORTD ^= _BV(PD0); // Меняем состояние выхода button0_event = 0x01; // Отметка о выполнении } } if(button1_event == 0x00) // Аналогично if(!(PINB & _BV(PB1))) { _delay_ms(20); if(!(PINB & _BV(PB1))) { PORTD ^= _BV(PD1); button1_event = 0x01; } } if(PINB & _BV(PB0)) // Если кнопка 0 или 1 не нажата - постоянно сбрасываем флаг button0_event = 0x00; // Это исключает многократную отработку условий выше пока кнопка удерживается if(PINB & _BV(PB1)) button1_event = 0x00; } }
Последний раз редактировалось antonydublin; 24.07.2014 в 19:58.
|
||
Оценка
|
Новичок
Регистрация: 30.09.2013
Сообщений: 2
Репутация: 10
![]() |
Цитата:
Alexanderik, Ваша программа не верна при таком подходе.
При нажатии и удержании кнопки событие будет отработано много раз с каким-то периодом. При удержании двух кнопок результат непредсказуем и/или реакция затянется. При удержании одной и нажатии второй аналогично. Неудачный пример. Такой код лучше использовать в упомянутом обработчике внешних прерываний, сторонясь _delay, когда есть возможность отследить фронт. С _delay правильно так: Код:
#include <avr/io.h> #include <util/delay.h> int main(void) { uint8_t button0_event = 0x00; uint8_t button1_event = 0x00; PORTB |= _BV(PB0)|_BV(PB1); // Подтяжка DDRB &= ~(_BV(PB0)|_BV(PB1)); // Входы PORTD |= _BV(PD0)|_BV(PD1); DDRD |= _BV(PD0)|_BV(PD1); // Выходы while(1) { if(button0_event == 0x00) // Если предыдущее нажатие отработано и нажата кнопка 0 if(!(PINB & _BV(PB0))) { _delay_ms(20); // Антидребезг if(!(PINB & _BV(PB0))) // Если по-прежнему нажата { PORTD ^= _BV(PD0); // Меняем состояние выхода button0_event = 0x01; // Отметка о выполнении } } if(button1_event == 0x00) // Аналогично if(!(PINB & _BV(PB1))) { _delay_ms(20); if(!(PINB & _BV(PB1))) { PORTD ^= _BV(PD1); button1_event = 0x01; } } if(PINB & _BV(PB0)) // Если кнопка 0 или 1 не нажата - постоянно сбрасываем флаг button0_event = 0x00; // Это исключает многократную отработку условий выше пока кнопка удерживается if(PINB & _BV(PB1)) button1_event = 0x00; } } ![]() ну по моему вопрошавшему все-равно. дополняю... ШПАК. magnet:?xt=urn:btih:JXO2YVF6MG5472Y4SZGL5PRQLU57DR YA magnet:?xt=urn:btih:QD2CKCZABMKYIWTKCOHU5ZW2KZ5W47 KL |
||
Оценка
|
Знаток
Регистрация: 12.10.2009
Адрес: Тольятти
Сообщений: 231
Репутация: 87
![]() |
С помощью D-триггера легко делается генератор случайных чисел.
В принципе, программная и аппаратная обработка должны делать одно и то же, поэтому программирование, по большому счету, есть упаковка схемных узлов в виде программы. Давайте посмотрим, как сделать аппаратно, чтобы кнопка меняла состояние триггера. Нужно сигнал от кнопки подать на интегратор (ФНЧ), который бы убрал все быстрые изменения состояний (дребезг контактов). Затем сигнал подается на триггер Шмитта с гистерезисом, на выходе которого получается сигнал с прямоугольными фронтами. И затем - счетчик-делитель на 2. В МК параллельность аналоговых процессов заменяется на последовательное выполнение разных участков программы многократно, отчего складывается впечатление, что они выполняются одновременно. Кроме того, независимость обработки особенно важных событий достигается применением внешних прерываний, но для некритичных по времени задач это необязательно, можно организовать периодический опрос внешнего сигнала. В итоге, от порта с кнопкой имеем ряд единиц и нулей, соответствующий состоянию контактов кнопки. Делаем программный интегратор. Он должен, наподобие RC-цепочки ФНЧ, медленно увеличиваться, когда на входе 1, и медленно уменьшаться, когда 0. Далее, он должен быть ограничен двумя значениями "снизу" и "сверху", потому что команда увеличения/уменьшения работает всегда и получается "перехлест" через 0. Аналог гистерезиса можно организовать путем прибавления и вычитания небольшого фиксированного числа по достижению границ. Ну, а деление на 2 выполняется простым инкрементом и использованием младшего разряда в качестве результата. Я советую подходить к задаче именно так, системно. Это позволяет избежать путаницы с условными ветвлениями. Вообще, программа опроса клавиатуры у меня всегда получается самая запутанная и сложная. Весь остальной код я пишу прямо в редакторе, а опрос клавиш всегда приходится сначала рисовать в виде блок-схемы с квадратиками и стрелочками. |
||
Оценка
|
Обратная связь РадиоЛоцман Вверх |