Форум РадиоКот https://radiokot.ru/forum/ |
|
STM32 сенсорные кнопки https://radiokot.ru/forum/viewtopic.php?f=59&t=98613 |
Страница 1 из 1 |
Автор: | GARMIN [ Чт дек 26, 2013 14:34:12 ] |
Заголовок сообщения: | STM32 сенсорные кнопки |
Делаю я тут клавиатуру для прибора. И грустно мне стало использовать мембранную клавиатуру, когда в моём микропроцессоре есть нативный контроллер сенсорных кнопок. Информации по этому вопросу довольно мало. С одной стороны, есть библиотека от ST. Но она громоздкая и для моих задач излишняя. С другой стороны, есть возможность прямо работать с регистрами контроллера. Нашёл в сети маленький примерчик, и на его основе делаю свой интерфейс. Выкладываю наработки. Условия: работа во FreeRTOS, процессор STM32F051. Код пока не проверен, так как плата с сенсорными кнопками в процессе изготовления. Инициализация: Код: void __inline vInit_TSC (void) { // включаю тактирование блока сенсорных кнопок RCC->AHBENR |= RCC_AHBENR_TSEN | RCC_AHBENR_GPIOAEN; // настройка портов IO GPIOA->MODER |= GPIO_MODER_MODER4_1; // PA4 - вход кнопки GPIOA->OTYPER &= ~GPIO_OTYPER_OT_4; // пин PA4 - пуш пулл GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR4; // скорость пина 50 МГц GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR4; // пин без подтяжки GPIOA->MODER |= GPIO_MODER_MODER5_1; // PA5 - вход кнопки GPIOA->OTYPER &= ~GPIO_OTYPER_OT_5; // пин PA5 - пуш пулл GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR5; // скорость пина 50 МГц GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR5; // пин без подтяжки GPIOA->MODER |= GPIO_MODER_MODER6_1; // PA6 - вход кнопки GPIOA->OTYPER &= ~GPIO_OTYPER_OT_6; // пин PA6 - пуш пулл GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6; // скорость пина 50 МГц GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR6; // пин без подтяжки GPIOA->MODER |= GPIO_MODER_MODER7_1; // PA7 - вход конденсатора GPIOA->OTYPER |= GPIO_OTYPER_OT_7; // пин PA7 - открытый сток GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7; // скорость пина 50 МГц GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR7; // пин без подтяжки GPIOB->MODER |= GPIO_MODER_MODER11_1; // PB11 - вход кнопки GPIOA->OTYPER &= ~GPIO_OTYPER_OT_11; // пин PB11 - пуш пулл GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR11; // скорость пина 50 МГц GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR11; // пин без подтяжки GPIOB->MODER |= GPIO_MODER_MODER12_1; // PB12 - вход кнопки GPIOA->OTYPER &= ~GPIO_OTYPER_OT_12; // пин PB12 - пуш пулл GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR12; // скорость пина 50 МГц GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR12; // пин без подтяжки GPIOB->MODER |= GPIO_MODER_MODER13_1; // PB13 - вход кнопки GPIOA->OTYPER &= ~GPIO_OTYPER_OT_13; // пин PB13 - пуш пулл GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR13; // скорость пина 50 МГц GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR13; // пин без подтяжки GPIOB->MODER |= GPIO_MODER_MODER14_1; // PB14 - вход конденсатора GPIOA->OTYPER |= GPIO_OTYPER_OT_14; // пин PB14 - открытый сток GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR14; // скорость пина 50 МГц GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR14; // пин без подтяжки GPIOA->AFR[0] |= GPIO_AFRL_AFRL4 & (GPIO_AF_AF3 << 16); // PA4 - слайдер 1 GPIOA->AFR[0] |= GPIO_AFRL_AFRL5 & (GPIO_AF_AF3 << 20); // PA5 - слайдер 2 GPIOA->AFR[0] |= GPIO_AFRL_AFRL6 & (GPIO_AF_AF3 << 24); // PA6 - слайдер 3 GPIOA->AFR[0] |= GPIO_AFRL_AFRL7 & (GPIO_AF_AF3 << 28); // PA7 - конденсатор GPIOB->AFR[1] |= GPIO_AFRH_AFRH3 & (GPIO_AF_AF3 << 12); // PB11 - кнопка BACK GPIOB->AFR[1] |= GPIO_AFRH_AFRH4 & (GPIO_AF_AF3 << 16); // PB12 - кнопка STOP GPIOB->AFR[1] |= GPIO_AFRH_AFRH5 & (GPIO_AF_AF3 << 20); // PB13 - кнопка ENTER GPIOB->AFR[1] |= GPIO_AFRH_AFRH6 & (GPIO_AF_AF3 << 24); // PB14 - конденсатор // настройка контроллера сенсорных кнопок TSC->CR = (1 << TSC_CR_TSCE); // разрешить контроллер TSC->CR = (2 << TSC_CR_CTPH) | (6 << TSC_CR_CTPL) | (9 << TSC_CR_SSD) | (0 << TSC_CR_SSE) | (1 << TSC_CR_SSPSC) | (0 << TSC_CR_PGPSC) | (TSC_CR_MCV_16383 << TSC_CR_MCV) | (0 << TSC_CR_IODEF) | (0 << TSC_CR_SYNCPOL) | (0 << TSC_CR_AM) | (0 << TSC_CR_START) | (1 << TSC_CR_TSCE); TSC->IER = (1 << TSC_IER_EOAIE) // прерывание по окончании измерения | (1 << TSC_IER_MCEIE); // прерывание по переполнению TSC->IOSCR = TSC_IOSCR_G2_IO4 // конденсатор PA7 (G2_IO4) | TSC_IOSCR_G6_IO4; // конденсатор PB14 (G6_IO4) TSC->IOCCR = TSC_IOCCR_G2_IO1 // кнопка PA4 | TSC_IOCCR_G6_IO1; // кнопка PB11 // | TSC_IOCCR_G2_IO2 // кнопка PA5 // | TSC_IOCCR_G2_IO3 // кнопка PA6 // | TSC_IOCCR_G6_IO1 // кнопка PB11 // | TSC_IOCCR_G6_IO2 // кнопка PB12 // TSC_IOCCR_G6_IO3; // кнопка PB13 // в процессе измерения учавствует только одна кнопка из группы TSC->IOGCSR = TSC_IOGCSR_G2E // разрешить группу 2 | TSC_IOGCSR_G6E; // разрешить группу 6 } Я использовал 6 кнопок в двух группах. Видно по комментариям. В обработчике прерывании я измеряю емкость всех кнопок, а затем передаю массив на обработку: Код: /* Программа обработчика прерывания контроллера TS Запускается снаружи установкой бита TSC->CR |= (1 << TSC_CR_START); и при конфигурации разрешения первых кнопок в группах Программа измеряет значения ёмкости всех шести кнопок в двух группах и выдаёт результат в массиве. Значение ёмкости = 0 определяет ошибку измерения Результат передаётся через очередь RTOS в обработчик клавиатуры */ void TS_IRQHandler (void) { portBASE_TYPE xWoken = pdFALSE; Tsense *point_t = &t; if ((TSC->ISR & TSC_ISR_MCEF) // переполнение счётчика { t.Cap[0][t.Position] = 0; // записали ошибку измерения t.Cap[1][t.Position] = 0; TSC->ICR = TSC_ICR_MCEIC | TSC_ICR_EOAIC; // снять флаг переполнения и окончания } else { t.Cap[0][t.Position] = *TS_Group[0]; // прочитали значение ёмкости t.Cap[1][t.Position] = *TS_Group[1]; TSC->ICR = TSC_ICR_EOAIC; // снять флаг окончания } if (++t.Position < TS_MAX_NUM_PIN) // если измерили не все кнопки, продолжить { TSC->IOCCR = TS_Mask_Channel[0][t.Position] | TS_Mask_Channel[0][t.Position]; // определить маску следующих кнопок TSC->CR |= (1 << TSC_CR_START); // запустить измерение следующих кнопок t.EndMeasure = 0; // сбросить флаг окончания } else // если измерение окончено, передать структуру { t.Position = 0; // подготовить указатель t.EndMeasure = 1; // выставить флаг окончания xQueueSendToBackFromISR (g.xTS_Queue, &oint_t, &xWoken); portYIELD_FROM_ISR (xWoken); } } Структура данных кнопок: Код: typedef struct Tsense { int Cap [TS_MAX_NUM_GROUP][TS_MAX_NUM_PIN]; // массив значений ёмкости кнопок int Position; // номер кнопки int EndMeasure; // флаг окончания измерения }Tsense; extern Tsense t; // массив указателей на регистры счётчиков групп const __IO uint32_t *TS_Group [TS_MAX_NUM_GROUP] = { &TSC->IOGXCR[1], &TSC->IOGXCR[5] }; // массив масок разрешения кнопок в группе const uint32_t TS_Mask_Channel [TS_MAX_NUM_GROUP] [TS_MAX_NUM_PIN] = { TSC_IOCCR_G2_IO1, TSC_IOCCR_G2_IO2, TSC_IOCCR_G2_IO3, TSC_IOCCR_G6_IO1, TSC_IOCCR_G6_IO2, TSC_IOCCR_G6_IO1 }; И, наконец, главный цикл программы. Здесь пока рыба, а будет обработка Код: /* Задача обработки значений сенсорных кнопок */ void vTsense (void *pvParameters) { int i, j; Tsense *Sense; int TSC_min [TS_MAX_NUM_GROUP][TS_MAX_NUM_PIN]; int TSC_max [TS_MAX_NUM_GROUP][TS_MAX_NUM_PIN]; vInit_TSC (); // обнулить данные в структуре кнопок for (i = 0; i < TS_MAX_NUM_GROUP; i++) { for (j = 0; j < TS_MAX_NUM_PIN; j++) { TSC_max[i][j] = t.Cap[i][j] = 0; TSC_min[i][j] = 16384; // максимальное значение } } t.Position = t.EndMeasure = 0; // начальные значения указателей for ( ; ; ) { vTaskDelay (200); TSC->CR |= (1 << TSC_CR_START); // запустить измерение // из очереди получаем указатель на структуру ёмкостей, ждём до посинения xQueueReceive (g.xTS_Queue, &Sense, portMAX_DELAY); if (t.EndMeasure) // для случая небесконечного ожидания { t.EndMeasure = 0; vTSCompareminmax (&Sense->Cap[0][0], TSC_min, TSC_max); // для начала просто выведу значение емкости } } } Я выкладываю этот код скорее для того, чтобы самому лучше разобраться в процессе, но если кому интересно, пишите свои соображения. Если кто заметит явные косяки, откликнитесь. Также интересны способы постобработки для получения статуса нажатых кнопок и использования слайдера. |
Автор: | coredumped [ Чт дек 26, 2013 18:05:13 ] |
Заголовок сообщения: | Re: STM32 сенсорные кнопки |
Дружище, очень интересен Ваш проект! Я делал touch клавиатуру на AT42QT2160, результат получился неплохой - работало через оргстекло 2мм. Пришлось немного повозиться с платой. Пишите все, что накопаете, интересно не столько программное решение, как ньюансы трассировки платы, а также материал и толщина панели. Просто у меня есть готовое решение, но хочется сделать "все-в-одном" - контроллер клавиатуры и LCD дисплея. Заранее спасибо. |
Автор: | GARMIN [ Пн дек 30, 2013 22:57:26 ] |
Заголовок сообщения: | Re: STM32 сенсорные кнопки |
Немного результатов. Всё запустилось. Наступал на грабли. Как свои по невнимательности, так и послушался глупых советов от STM. Сенсорные кнопки уверенно работают через стеклотекстолит 1,5мм со шлейфом 20 см на шилд Дискавери. Показания счётчиков плывут от времени по причине нестабильности конденсаторов и геометрии шлейфа. Применил фильтрацию сигналов - всё отлично заработало. Пока реализован вариант с отдельными кнопками. Вторым этапом буду мучить слайдер - хочу получить данные в виде линейного указателя 0-100% |
Автор: | coredumped [ Пт янв 03, 2014 16:43:45 ] |
Заголовок сообщения: | Re: STM32 сенсорные кнопки |
Спасибо за опыт! |
Автор: | evilbob [ Пт апр 11, 2014 11:45:56 ] |
Заголовок сообщения: | Re: STM32 сенсорные кнопки |
А можно взглянуть на саму схему? |
Автор: | GARMIN [ Вт апр 15, 2014 17:52:01 ] |
Заголовок сообщения: | Re: STM32 сенсорные кнопки |
evilbob писал(а): А можно взглянуть на саму схему? Схема из даташита, там два конденсатора и резисторы на ножках. |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |