Введение
Написал библиотеку для опроса кнопок.
Особенности библиотеки:
• предназначена для AVR
• работает с компиляторами GCC, IAR, CodeVision
• позволяет опрашивать до 32 цифровых входов
• имеет программную защиту от дребезга контактов
• распознает нажатие, удержание, отпускание и двойное нажатие на кнопку
• позволяет индивидуально задавать активный уровень и обрабатываемые события
• зафиксированные события сохраняются в кольцевом буфере
• позволяет отключать неиспользуемые функции
• легко интегрируется в готовый проект
Состав библиотеки
buttons.h - заголовочный файл библиотеки, в котором задаются настройки
buttons.c - файл реализация функций
Подключение к проекту
1. Копируем все файлы в папку проекта.
2. Подключаем buttons.c к проекту.
3. Инклюдим заголовочный файл buttons.h к сишному файлу, в котором будут использоваться функции библиотеки.
4. Настраиваем конфигурацию и подключения в файле buttons.h
5. Прописываем в код вызов функций библиотеки.
Настройка библиотеки
Настройка конфигурации состоит из следующий шагов.
1. Задаем количество кнопок. Эта настройка может принимать значения от 1 до 32.
#define BUT_AMOUNT 4
2. Задаем сколько циклов опроса должна удерживаться кнопка, чтобы она считалась нажатой. Число должно быть меньше BUT_COUNT_HELD (смотри ниже).
#define BUT_COUNT_THR 10
3. Задаем количество циклов опроса, в течении которых должно произойти второе нажатие на кнопку, чтобы было зафиксировано событие "двойной клик". Желательно задавать это значение до 250, если задать выше, код будет занимать больше памяти. Если эта функция не используется, настройку можно пропустить.
#define BUT_COUNT_THR_2 100
4. Задаем количество циклов опроса, в течении которых должна удерживаться кнопка, чтобы было зафиксировано событие "длительное удержание". По сути - это время удержания кнопки. Желательно задавать это значение до 250, если задать выше, код будет требовать больше RAM и Flash памяти. Значение должно быть больше BUT_COUNT_THR (смотри выше).
#define BUT_COUNT_HELD 250
5. Задаем размер буфера событий. Его значение должно быть кратно степени двойки (2, 4, 8, 16...).
#define BUT_SIZE_BUF 8
6. Задаем тип опроса.
0 - полный опрос. За один вызов функции BUT_Poll() выполняется один цикл опроса всех кнопок. 1 - циклический опрос. За один вызов BUT_Poll() выполняется один цикл опроса одной кнопки. Если кнопок мало, задавайте 0.
#define BUT_POLL_ROTATION 0
7. Задаем события, которые будут регистрироваться. 0 - событие не регистрируется, 1 - событие будет регистрироваться, если задана индивидуальная настройка кнопки. Библиотека может регистрировать следующие события:
• нажатие на кнопку
• удержание кнопки
• отпускание кнопки после короткого удержания
• отпускание кнопки после длительного удержания
• быстрое двойное нажатие на кнопку
Исключив ненужные события, можно сэкономить немного памяти и времени микроконтроллера.
#define BUT_PRESSED_EN 1
#define BUT_HELD_EN 1
#define BUT_RELEASED_EN 1
#define BUT_RELEASE_LONG_EN 1
#define BUT_DOUBLE_CLICK_EN 1
8. Если нужно, задаем коды кнопок. Эти коды будут сохранятся в буфере событий, когда зафиксировано соответствующее событие. Коды могут принимать значения от 1 до 255. Можно задать всем событиям одинаковый код.
#define BUT_PRESSED_CODE 1
#define BUT_HELD_CODE 2
#define BUT_RELEASED_CODE 3
#define BUT_RELEASED_LONG_CODE 4
#define BUT_DOUBLE_CLICK_CODE 5
9. Задаем конфигурацию кнопок. Конфигурация кнопки включает в себя:
• Идентификационный номер - BUT_N_ID. Где N - это число от 1 до 32. Задается по порядку - 1, 2, 3 ... 32. Без пропусков!
• Порт направления - BUT_N_DDRX
• Порт подтягивающих резисторов - BUT_N_PORTX
• Порт состояния пина микроконтроллера - BUT_N_PINX
• Номер пина микроконтроллера - BUT_N_PIN
• Активный уровень кнопки - BUT_N_LEV. Если кнопка замыкается на землю - активный уровень 0. Если она замыкается на плюс питания - активный уровень 1.
• Активация pull-up резистора - BUT_N_PULL. 0 - не включать, 1 - включать подтягивающий резистор.
• Список регистрируемых событий - BUT_N_EVEN. Это события, которые будут заноситься в буфер, если они разрешены глобальными настройками. Задаются в скобках через оператор побитового ИЛИ. Список событий такой - BUT_EV_PRESSED, BUT_EV_HELD, BUT_EV_RELEASED, BUT_EV_RELEASED_LONG, BUT_EV_DOUBLE_CLICK ,BUT_EV_ALL.
Пример настройки кнопки, подключенной к 0 выводу порта C. Кнопка замыкает вывод на землю, включен подтягивающий резистор и регистрируются события "отпускание кнопки" и "длительное удержание".
#define BUT_1_ID 1
#define BUT_1_DDRX DDRC
#define BUT_1_PORTX PORTC
#define BUT_1_PINX PINC
#define BUT_1_PIN 0
#define BUT_1_LEV 0
#define BUT_1_PULL 1
#define BUT_1_EVENT (BUT_EV_HELD |BUT_EV_RELEASED)
Использование библиотеки
Библиотека содержит три пользовательские функции.
void BUT_Init(void) - инициализирует внутренние переменные, настраивает кнопки. Эту функцию нужно вызывать в начале main`a.
void BUT_Poll(void) - выполняет опрос кнопок. Функция должна вызываться с периодом от 1 до нескольких десятков миллисекунд. Лучше не "совать" ее в прерывание, а вызывать ее из основного цикла программы.
В зависимости от настройки BUT_POLL_ROTATION, функция может выполнять опрос всех кнопок за раз или по одной кнопке за вызов. Если используется циклический опрос, то частота опроса кнопок будет в N раз меньше частоты вызова функции BUT_Poll(), где N - количество кнопок. Это нужно учитывать при задании настроек BUT_COUNT_THR, BUT_COUNT_THR_2, BUT_COUNT_HELD.
uint8_t BUT_GetBut(void) - возвращает событие из буфера. Функцию нужно вызывать два раза. Первый раз - возвращается код кнопки, второй раз - код события. Если буфер пустой, функция возвращает 0.
Пример использования:
...
uint8_t but = 0;
uint8_t code = 0;
int main( void )
{
BUT_Init();
...
__enable_interrupt();
while(1){
delay_ms(2);
/*опрос кнопок*/
BUT_Poll();
/*проверка буфера*/
but = BUT_GetBut();
/*если зафиксировано событие*/
if (but){
/*берем код события*/
code = BUT_GetBut();
/*обрабатываем but и code*/
....
}
}
return 0;
}
Файлы
buttons-lib.rar - библиотека опроса кнопок для AVR
Писал для себя. Не проверена на 100%. Поставляется как есть.
Comments
У мея есть вопрос. Какой самый оптимальный алгоритм опроса кнопок в диспетчере задач? То есть запускаем задачу опроса кнопок раз, допустим в 100 миллисекунд, а дальше что? Если нажата, перезапускаем снова себя же через, ну, скажем, 50 миллисекунд (защита от дребезга) и если кнопка уже нажата или отжата делаем выводы, ставить флаг нажатой кнопки или еще нет, когда и где сбрасывать этот флаг? Прерывания использовать нельзя. Подскажите толковый алгоритм, пожалуйста.
Если важно, какой диспетчер - то http://andromega.narod.ru/publics.html
"Компактный диспетчер для встроенных систем"
Code:
//#include <stdio.h>
#define F_CPU 8000000UL
#include <util/delay.h>
#include <avr/interrupt.h>
//#include <stdint.h>
#include <button/buttons.h.h>
uint8_t but = 0;
uint8_t code = 0;
int main( void )
{
BUT_Init();
DDRB=0x0e; //Инициализация портов, OC1A,OC1B,OC2 - выходы
sei();//__enable_interrupt();
while(1){
_delay_ms(2);
/*опрос кнопок*/
BUT_Poll();
/*проверка буфера*/
but = BUT_GetBut();
/*если зафиксировано событие*/
if (but){
/*берем код события*/
code = BUT_GetBut();
if (code == 1)
{
PORTB = (1<<PB1)|(0<<PB2)|(0<<PB3);
}
else if (code == 2)
{
PORTB = (0<<PB1)|(1<<PB2)|(0<<PB3);
}
else if (code == 3)
{
PORTB = (0<<PB1)|(0<<PB2)|(1<<PB3);
}
}
}
return 0;
}
в чем проблема может быть?
Code:
#include <button/buttons.h.h>
#include <avr/io.h>
Например, 6? )) И что тогда будет при
head &= (BUT_SIZE_BUF - 1);
Quote: Можно заменить на "кратно" на "равно"
Инклуд прописал, сишный файл в проект добавил, адрес компилятору указал.
Error 3 'PORTC' undeclared (first use in this function) C:\Users\Dmitry\Desktop\avrstud\FF\FF\buttons.c 255 3 FF
Error 4 'PINC' undeclared (first use in this function) C:\Us ers\Dmitry\Desk top\avrstud\FF\ FF\buttons.c 39 6 1 FF
активного уровня в настройках*/
#define _TestBit1(var, bit) ((var) & (1
#define _TestBit(var, bit, lev) _TestBit##lev(var, bit)
#define TestBitLev(var, bit, lev) _TestBit(var, bit, lev)
_TestBit##lev(var, bit) как это работает
www.kit-e.ru/articles/circuit/2006_11_164.php
Может у него и правильней, но для тех, кто занимается программировани ем в бытовых целях (это я про себя :) ) изучать всю теорию КА смысла нет. Здесь же все просто, понятно и доходчиво объяснено с реальными примерами, за что автору низкий поклон.
В общем, как говорится, каждый выбирает для себя...
1 - Ничего заумного нет.
2 - КА решают самую главную проблему - псевдопараллель ность процессов.
Пользуюсь Atmel Studio 7.0
Судя по тому, что получается, код библиотеки не выполняется вообще. Такой вывод делаю из того, что даже подтяжка на ножке не включается.
Думаю, что накосячил в пункте 2. Подключаем buttons.c к проекту.
В Solution Explorer я кликаю правой кнопкой по названию проекта, далее Add -> Existing Item - >Buttons.c, который лежит в папке, в которой лежит main.c, то есть исходный файл проекта. Я не правильно понял, как подключать файл?
#define BUT_PRESSED_COD E 0
#define BUT_HELD_CODE 2
#define BUT_RELEASED_CO DE 3
#define BUT_RELEASED_LO NG_CODE 4
#define BUT_DOUBLE_CLIC K_CODE 1
Так, получается кнопку приделать к PF0, но не PF4, PF6...
but = BUT_GetBut();
Error: a value of type 'const void' can't be assigned to an entity of type 'uint8_t'
В чем может быть причина? Спасибо.
RSS feed for comments to this post