Всем доброго дня! Сегодня мы продолжим обсуждать работу с графическим дисплеем и на очереди у нас Touch Screen.
В этой статье я не буду рассказывать про устройство дисплея и про то, как работает контроллер touch screen'а. Сегодня рассмотрим библиотеку для работы с ним, а также конкретный пример, чтобы увидеть результат наших трудов. В общем, данная статья будет продолжением предыдущей: вот она.
Время традиционной вставки: поскольку компания STMicroelectronics прекратила поддержку библиотеки SPL, которая использовалась в этом курсе, я создал новый, посвященный работе уже с новыми инструментами, так что буду рад видеть вас там - STM32CubeMx. Кроме того, вот глобальная рубрика по STM32, а также небольшая подборка на смежную тему из нового курса:
- Подключение дисплея на базе ST7735 к микроконтроллеру STM32.
- Дисплей на базе ST7735 и STM32. Вывод изображения.
- Дисплей на базе контроллера SSD1306. Библиотека для STM32.
- STM32 и семисегментный индикатор. Динамическая индикация.
Итак, для обмена данными с контроллером дисплея мы будем использовать интерфейс SPI, соответственно, необходимо его проинициализировать:
void TouchInit(void) { GPIO_InitTypeDef GPIO_InitStruct; SPI_InitTypeDef SPI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init (GPIOA, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init (GPIOA, &GPIO_InitStruct); RCC_APB2PeriphClockCmd (RCC_APB2Periph_SPI1, ENABLE); SPI_Cmd (SPI1, DISABLE); SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init (SPI1, &SPI_InitStructure); SPI_CalculateCRC(SPI1, DISABLE); SPI_Cmd (SPI1, ENABLE); SPI_SSOutputCmd (SPI1, DISABLE); SPI_NSSInternalSoftwareConfig (SPI1, SPI_NSSInternalSoft_Set); GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Pin = TOUCH_CS_PIN; GPIO_Init(TOUCH_CS_PORT, &GPIO_InitStruct); T_DCS(); GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; GPIO_Init (GPIOB, &GPIO_InitStruct); diffX = diffY = 0; dispSizeX = dispSizeY = 0; }
Как видите, за всю конфигурацию в библиотеке отвечает функция TouchInit(). В принципе, тут все понятно, настраиваем нужные выводы микроконтроллера, включаем тактирование, ну и, конечно, задаем параметры обмена данными по SPI.
Но на этом подготовка к работе с дисплеем не заканчивается. Вторым шагом является калибровка параметров touch screen'а. За это отвечает функция TouchCalibrate(). Ее полный код я приводить не буду, ссылка на скачивание полной библиотеки и готового примера будет в конце статьи, все можно будет увидеть в исходниках )
Итак, все настроено и готово к работе. Осталось обсудить основную функцию, с помощью которой мы и будем работать с LCD. И это функция:
bool TouchReadXY(uint16_t *px, uint16_t *py, bool isReadCorrected);
Эта функция позволит нам узнать координаты точки касания дисплея, с которыми мы уже в дальнейшем будем работать. Для получения этих данных необходимо передать в функцию адреса переменных, в которых будут сохранены координаты x и y. С обсуждением на этом заканчиваем, давайте переходить к практическому примеру. Вот полный код функции main():
int main(void) { initPeriph(); initFSMC(); initLCD(); delay(10000); LCD_FillScr(0xFFFF); delay(100); LCD_SetOrient(Orientation_Portrait); delay(100); TouchInit(); TouchSetScreenSize(240, 320); TouchCalibrate(); LCD_FillScr(0xFFFF); while(1) { TouchReadXY(&X, &Y, true); LCD_PutPixel(X, Y, 0x0000); } }
Давайте разберемся, что тут происходит.
Для начала вызываем функции инициализации дисплея, которые мы обсуждали в предыдущей статье. Следом за ними функции конфигурации touch screen'а. Кроме того, вызываем функцию TouchSetScreenSize() с параметрами, соответствующими размерам нашего дисплея. Эти данные нужны для работы драйвера. А в бесконечном цикле реализуем что-то вроде рисовалки - считываем координаты касания и в этом месте рисуем точку. Таким образом, проводя пальцем по дисплею можно рисовать линии, фигуры и т. д.
Результат работы нашей программы:
На этом на сегодня заканчиваем, еще раз большое спасибо mishadesh за материалы и за работу над графической библиотекой! В завершение как и обещал привожу проект для работы с touch screen'ом, а также напоминаю контакты автора библиотеки:
- Проект - Touch_Project
- Skype - mishadesh
- E-Mail - mishadesh@gmail.com
Чтобы минимизировать количество ошибочных пикселей, попробуйте медианный фильтр. Суть проста: считываете n показаний тачскрина в массив, сортируете его(по возрастанию или убыванию без разницы) и берете средний элемент, если n - нечетное, или среднее арифметическое 2х средних элементов, если n - четное. Таким образом вы отсекаете цифровые шумы. Сам делал похожую рисовалку, так вот с использованием этого фильтра результат стал намного лучше.
у меня не стояла цель делать рисовалку. Я делаю кнопочный интерфейс, а там прецизионная точность не нужна
нужна, будешь нажимать на одну кнопку, а нажмется соседняя... или вообще хз где..
Как сделать чтобы каждый раз не калибровать, а использовать готовые коэффициенты.
Посмотри под отладчиком, какие коэффициенты получаются при калибровке и забей их константами.
Я сейчас занимаюсь прикручиванием внешней памяти как раз чтобы хранить такую сервисную информацию. Константы в следующем проекте будут уже во flash памяти.