В Siemens C75 и ME75 применялись два типа дисплеев, один с зеленым текстолитом и названием LPH9157-2, а другой с темно-желтым текстолитом. Так вот, у меня дисплей с зеленым текстолитом его и будем использовать.
Итак, фото подключаемого дисплея.
Имя дисплея LPH9157-2
Подключать будем к STM32F103C8. На мой взгляд, отличный камень для подобных опытов. В сети есть статья Особенности работы с дисплеем LPH9157-2 автора Igoryosha, эта статья сделана на основе микроконтроллеров AVR, автор написал там библиотеку для работы с дисплеем, но данное решение мне не подходило из-за низкой скорости работы микроконтроллеров AVR. В итоге я решил портировать данную библиотеку на STM32, тем самым повысив скорость работы с дисплеем.
В чем же заключалось портирование?
Для начала я переписал библиотеку с использованием программного SPI. Потом переделал с использованием аппаратного SPI.
Рассмотрим порт с программным SPI:
Создаем новый проект в среде разработки CoIDE. Можно конечно использовать и другие среды разработки для STM32, но при их использовании могут быть проблемы при компиляции данного кода. Подключаем заголовочные файлы
#include #include #include #include #include "stm32f10x.h" #include "stm32f10x_conf.h"
Далее конфигурируем порт, к которому будет подключен дисплей
//#define LCD_CS Выбор чипа //#define LCD_RESET Сброс //#define LCD_RS CD - тип передаваемых данных //#define LCD_CLK Синхронизация //#define LCD_DATA Данные Тут записали в пины порта логический ноль #define LCD_CS0 GPIOB->BRR = 1<<0; #define LCD_RESET0 GPIOB->BRR = 1<<1; #define LCD_RS0 GPIOB->BRR = 1<<12; #define LCD_CLK0 GPIOB->BRR = 1<<13; #define LCD_DATA0 GPIOB->BRR = 1<<14; А тут записали в пины порта логическую единицу #define LCD_CS1 GPIOB->BSRR = 1<<0; #define LCD_RESET1 GPIOB->BSRR = 1<<1; #define LCD_RS1 GPIOB->BSRR = 1<<12; #define LCD_CLK1 GPIOB->BSRR = 1<<13; #define LCD_DATA1 GPIOB->BSRR = 1<<14;
Ножки для подключения дисплея можно использовать с любых портов.
Далее идут константы цветов, данных и команд, все как у автора.
Теперь конфигурируем периферию:
Таймер для задержки
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; TIM2->PSC = 8000-1; TIM2->CR1 = TIM_CR1_OPM;
Порт для дисплея
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //включить тактирование порта GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_12| GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //выход общего назначения симметричный GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//максимальная частота выходного сигнала GPIO_Init(GPIOB, &GPIO_InitStructure);//вызов функции инициализации
Перепишем теперь функции передачи команд/данных и инициализации с учетом выше заданных констант:
Функции передачи команд/данных:
void Send_to_lcd (unsigned char RS, unsigned char data) { LCD_CLK0; LCD_DATA0; if ((RS_old != RS) || (!RS_old && !RS)) //проверяем старое значение RS (если поступают одни команды то дергаем CS) { LCD_CS1; if(RS) LCD_RS1 else LCD_RS0; LCD_CS0; } LCD_DATA0; if ((data & 128) == 128) LCD_DATA1; LCD_CLK1; LCD_CLK0; LCD_DATA0; if ((data & 64) == 64) LCD_DATA1; LCD_CLK1; LCD_CLK0; LCD_DATA0; if ((data & 32) == 32) LCD_DATA1; LCD_CLK1; LCD_CLK0; LCD_DATA0; if ((data & 16) ==16) LCD_DATA1; LCD_CLK1; LCD_CLK0; LCD_DATA0; if ((data & 8) == 8) LCD_DATA1; LCD_CLK1; LCD_CLK0; LCD_DATA0; if ((data & 4) == 4) LCD_DATA1; LCD_CLK1; LCD_CLK0; LCD_DATA0; if ((data & 2) == 2) LCD_DATA1; LCD_CLK1; LCD_CLK0; LCD_DATA0; if ((data & 1) == 1) LCD_DATA1; LCD_CLK1; LCD_CLK0; RS_old=RS; //запоминаю значение RS LCD_DATA0; }
Функция инициализации:
void LCD_init(void) { LCD_RESET0; delay_ms(1000); LCD_RESET1; delay_ms(1000); Send_to_lcd(0, 0x01); //Программный сброс Send_to_lcd(0, 0x36); Send_to_lcd(1, 0x00); Send_to_lcd(0, 0x11); //Выход из спящего режима delay_ms(200); Send_to_lcd(0, 0x3a); //Установка цветовой палитры #ifdef _8_BIT_COLOR Send_to_lcd(1, 0x02); //Байт на пиксель 256 цветов #else Send_to_lcd(1, 0x05); //Два байта на пиксель 65536 цветов #endif delay_ms(200); Send_to_lcd(0, 0x29); //Включение дисплея }
В остальные функции для работы с дисплеем тоже были внесены изменения того же типа что и выше, так что здесь их рассматривать нет смысла. В принципе с программным SPI наверно все, так как основная идея порта ясна.
Теперь разберемся с аппаратным SPI.
Для работы с аппаратным SPI нужно его сконфигурировать, но об этом будет речь чуть ниже.
Здесь все также как и выше только при конфигурации порта для дисплея берем 3 ноги с порта и еще 2 с SPI.
Подключаем к проекту
#include
, и переходим к настройке пинов порта для дисплея. Это оставляем как есть:
#define LCD_CS0 GPIOB->BRR = 1<<0; #define LCD_RESET0 GPIOB->BRR = 1<<1; #define LCD_RS0 GPIOB->BRR = 1<<12; #define LCD_CS1 GPIOB->BSRR = 1<<0; #define LCD_RESET1 GPIOB->BSRR = 1<<1; #define LCD_RS1 GPIOB->BSRR = 1<<12;
Далее значит, настраиваем пины SPI:
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; //включить тактирование альтернативных функций RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //включить тактирование порта А RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE); //вывод управления SS: выход двухтактный, общего назначения,50MHz GPIOA->CRL |= GPIO_CRL_MODE4; // GPIOA->CRL &= ~GPIO_CRL_CNF4; // GPIOA->BSRR = GPIO_BSRR_BS4; // //вывод SCK: выход двухтактный, альтернативная функция, 50MHz GPIOA->CRL |= GPIO_CRL_MODE5; // GPIOA->CRL &= ~GPIO_CRL_CNF5; // GPIOA->CRL |= GPIO_CRL_CNF5_1; // //вывод MISO: вход цифровой с подтягивающим резистором, подтяжка к плюсу GPIOA->CRL &= ~GPIO_CRL_MODE6; // GPIOA->CRL &= ~GPIO_CRL_CNF6; // GPIOA->CRL |= GPIO_CRL_CNF6_1; // GPIOA->BSRR = GPIO_BSRR_BS6; // //вывод MOSI: выход двухтактный, альтернативная функция, 50MHz GPIOA->CRL |= GPIO_CRL_MODE7; // GPIOA->CRL &= ~GPIO_CRL_CNF7; // GPIOA->CRL |= GPIO_CRL_CNF7_1; // RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
Теперь настраиваем SPI:
SPI_StructInit(&spi); spi.SPI_Direction = SPI_Direction_2Lines_FullDuplex; spi.SPI_Mode = SPI_Mode_Master; spi.SPI_DataSize = SPI_DataSize_8b; spi.SPI_CPOL = SPI_CPOL_Low; spi.SPI_CPHA = SPI_CPHA_2Edge; spi.SPI_NSS = SPI_NSS_Soft; spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; spi.SPI_FirstBit = SPI_FirstBit_MSB; spi.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &spi);
Описание настроек SPI можно глянуть в интернете, поэтому здесь приводить не буду.
Функция передачи данных по SPI:
uint8_t Send_to_lcd (uint8_t data) { SPI1->DR = data; while (!(SPI1->SR & SPI_SR_RXNE)); return (SPI1->DR); }
Дальше используем эту функцию за место той, что была в программном SPI.
Теперь по поводу схемы:
Дисплей я подключал на прямую к портам микроконтроллера, питание дисплея 2.9вольт. Если не будет работать дисплей, замерьте напряжение после стабилитрона, оно должно быть строго 2.9 вольт. Если оно ниже, как было у меня то нужно поставить конденсатор электролитический на пару сотен мкФ (я ставил 220мкФ). Питание подсветки 12 вольт. Схему приводить нет смысла, так как у меня конкретно своя макетная плата с отладочной платой, так что разумнее будет исходить из того что у Вас за плата с МК.
Картинка работающего дисплея:
Тестовые проекты в среде программирования CoIDE прикреплены ниже. В них портированы не все функции, которые были изначально на AVR. Если Вам понадобятся остальные функции, то Вы можете их с легкостью портировать, так как, там все просто.
Список радиоэлементов
Обозначение | Тип | Номинал | Количество | Примечание | Магазин | Мой блокнот |
---|---|---|---|---|---|---|
МК STM32 | STM32F103C8 | 1 | Поиск в магазине Отрон | |||
LCD-дисплей | Siemens C75, ME75 | 1 | Поиск в магазине Отрон | |||
Стабилитрон | 2.9 Вольт | 1 | Поиск в магазине Отрон | |||
Скачать список элементов (PDF)
- spihrd.rar (221 Кб)
- lcd c75.rar (157 Кб)
Комментарии (7) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация
Дисплейчик этот: MI0177J2T-1.
while (!(SPI1->SR & SPI_SR_RXNE));