В 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: выход 2-хтактный, общего назначения,50MHz
GPIOA->CRL |= GPIO_CRL_MODE4; //
GPIOA->CRL &= ~GPIO_CRL_CNF4; //
GPIOA->BSRR = GPIO_BSRR_BS4; //
//вывод SCK: выход 2-хтактный, альтернативная функция, 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: выход 2-хтактный, альтернативная функция, 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. Если Вам понадобятся остальные функции, то Вы можете их с легкостью портировать, потому что, там все просто.
Список радиоэлементовОбозначение
Тип
Номинал
Количество
ПримечаниеМагазинМой блокнот
МК STM32STM32F103C81
LCD-дисплейSiemens C75, ME751
Стабилитрон2.9 Вольт1
Добавить все
Скачать список элементов (PDF)
Прикрепленные файлы:
- spihrd.rar (221 Кб)
- lcd c75.rar (157 Кб)