Янв 152012
 

В предыдущей статье был рассмотрен порядок настройки ЖК индикатора, установленного на плате. Теперь возникла необходимость иметь в распоряжении таблицу символов, чтобы можно было в коде программы использовать буквенно-цифровые или строковые значения для вывода на индикатор. Порядок нумерации сегментов индикатора совсем не соответствует порядку битов LCD контроллера, такова разводка платы. Поэтому создать таблицу символов, а потом двигать их в нужные разряды индикатора не такая уж легкая задача. Тут для каждого знакоместа придется менять битовую маску, делать какой-то алгоритм пересчета. Поэтому под эту задачу были использованы стандартные библиотеки для работы с LCD.

В стандартном наборе библиотек для STM32L152 идут библиотечные файлы
stm32l1xx_lcd.h
и
stm32l1xx_lcd.c.
Эти файлы были подключены к проекту без изменений. В них расположены макросы для настроек индикатора, а также функция записи значений в ячейки памяти, отведенные под данные для LCD. Также были использованы библиотечные файлы из демонстрационной программы для STM32L-DISCOVERY
stm32l_discovery_lcd.h
и
stm32l_discovery_lcd.c.
Здесь как раз и определены массивы значений для букв и цифр (алфавит, естественно, латинский). А также функция, конвертирующая числа из этого массива в другие значения, которые зависят от того, в какую позицию индикатора символ нужно вывести. А вот из этих двух файлов пришлось вырезать все ненужное. Причиной было то, что возникает много переходов из функции в функцию, раскиданных по разным файлам, и если все функции оставить в библиотеках, то придется подключать к данному проекту множество других файлов, иначе без них просто не компилируется проект. А такая прорва файлов вовсе и не нужна для такой небольшой задачи. В итоге функциональность библиотек была урезана до следующих функций:

  • Вывод одиночных символов в нужную позицию индикатора
  • Вывод строковых констант
  • Очистка дисплея

Настройки проекта.
Шаблон проекта был взят отсюда STM32L-DISCOVERY. Подключаем LCD. В конфигурацию были внесены некоторы изменения. Во-первых, в секции C/C++ Compiler->Preprocessor в поле Defined symbols были добавлены вот такие строки:

STM32L15XXB_128K 
USE_FULL_ASSERT 
USE_STDPERIPH_DRIVER 

Я их скопировал туда из настроек демонстрационного проекта для STM32L-DISCOVERY. Без первой строки работать будет, а вот вторая и третья нужны обязательно. Без них у меня компилятор выдавал ошибки, спотыкаясь на строках assert_param() в библиотечных файлах.

Также, для корректной обработки этих функций (assert_param()) в конец файла main.c был добавлен следующий код

#ifdef  USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{ 
  while (1)
  {
  }
}
#endif

Функции инициализации портов и LCD из main.c были убраны в отдельный файл lcd_gpio_init.c, а объявление этих функций в заголовочный файл lcd_gpio_init.h. В итоге получилось 4 новых файла для проекта, не входящих в набор стандартных библиотек

  • stm32l_discovery_lcd_new.h
  • stm32l_discovery_lcd_new.c (эти 2 файла — "урезанные" библиотеки из демопрограммы)
  • lcd_gpio_init.h
  • lcd_gpio_init.c (эти два выполняют начальную инициализацию портов и LCD)

Их я убрал в отдельную папку Utilities в общем каталоге проекта. В итоге пришлось добавить пути для поиска файлов на вкладке настроек проекта C/C++ Compiler -> Preprocessor.

Список путей к библиотечным файлам проекта получился таким:

$PROJ_DIR$..LibrariesCMSISCM3DeviceSupportSTSTM32L1xxstartupiar

$PROJ_DIR$..LibrariesSTM32L1xx_StdPeriph_Driverinc

$PROJ_DIR$..LibrariesSTM32L1xx_StdPeriph_Driversrc

$PROJ_DIR$..LibrariesCMSISCM3DeviceSupportSTSTM32L1xx

$PROJ_DIR$..Utilities

После этого настройки проекта можно сохранить.

Далее необходимо подключить нужные файлы к проекту. В начале main.c подключаем новые заголовочные файлы:

#include "stm32l1xx.h" 
#include "lcd_gpio_init.h" 
#include "stm32l_discovery_lcd_new.h" 

Затем подключаем "си" файлы библиотек — Project -> Add Files, из папки Utilities это файлы

stm32l_discovery_lcd_new.c

и

lcd_gpio_init.c,

и из папки стандартных библиотек Libraries файл stm32l1xx_lcd.c.

Код программы.

#include "stm32l1xx.h"
#include "lcd_gpio_init.h"
#include "stm32l_discovery_lcd_new.h"

int main()
{
  gpio_init();  //Настройка портов ввода/вывода под работу с LCD
  lcd_init();   //Здесь конфигурируем LCD контроллер 
  LCD_GLASS_WriteChar("8", POINT_ON, COLUMN_OFF, 1); //Следующие 6 строк выводят символы поочередно в позиции 1-6 индикатора
  LCD_GLASS_WriteChar("0", POINT_OFF, COLUMN_OFF, 2);
  LCD_GLASS_WriteChar(" ", POINT_OFF, COLUMN_OFF, 3);
  LCD_GLASS_WriteChar("M", POINT_OFF, COLUMN_OFF, 4); 
  LCD_GLASS_WriteChar("H", POINT_OFF, COLUMN_OFF, 5);
  LCD_GLASS_WriteChar("Z", POINT_OFF, COLUMN_OFF, 6);
  //LCD_GLASS_DisplayString("ABCDEF"); //Эта функция выводит сразу всю строку (если ее раскомментировать, тогда необходимо закомментировать предыдущие 6 строк посимвольного вывода)
  //LCD_GLASS_Clear(); //Очистка дисплея
while(1);
}

//Здесь обрабатывается неудачный результат функций assert_param() из стандартных библиотек
#ifdef  USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{ 
  while (1)
  {
  }
}
#endif

Итак, в начале функции main() вызываются функции конфигурации портов и контроллера LCD (как уже упоминал, я эти функции убрал в отдельный файл lcd_gpio_init.c). Более подробно порядок настройки описан ЗДЕСЬ.

Следующие 6 строк поочередно выводят символы в 6 позиций индикатора. Каждая команда выводит всего один символ в заданную позицию. Эта функция в общем виде

void LCD_GLASS_WriteChar(uint8_t* ch, bool point, bool column,uint8_t position);

требует задать следующие параметры:

  • uint8_t* ch — сюда пишем букву или цифру. Кстати, нормально отображаются только прописные буквы, некоторые строчные получаются некрасиво, либо преобразутся в прописную. Но тут символы все же отображаются не матрицей точек, поэтому не все строчные буквы можно сформировать нормально.
  • bool point — отвечает за отображение точки после символа. POINT_ON — точка отображается, POINT_OFF — точки нет.
  • bool column — двоеточие после символа. Варианты аналогичны, как и с точкой: COLUMN_ON или COLUMN_OFF.
  • uint8_t position — позиция вывода символа на дисплее, число от 1 до 6.

Эта функция в библиотеке довольно большая, она еще и конвертирует заданный символ, подгоняя его значение под схему подключения индикатора и в зависимости от позиции вывода.

Следующая функция пока закомментирована

//LCD_GLASS_DisplayString("ABCDEF"); 


Она выводит на дисплей сразу строковую константу. Общий вид этой функции в библиотечном файле такой:

void LCD_GLASS_DisplayString(uint8_t* ptr); 

Раскомментировав ее, не забудьте наоборот закомментировать предыдущие 6 строк с поочередным выводом символов. Хотя ничего страшного и не произойдет, просто информация на дисплее поменяется очень быстро, поскольку временных задержек между выводом символов нет. В принципе эта функция просто разбивает строку на отдельные символы, а затем передает их значения в ту же функцию LCD_GLASS_WriteChar(), которая поочередно выводит символы этой строковой константы.

И последняя функция

LCD_GLASS_Clear(); 

производит очистку дисплея.

Все нужные процедуры, такие как ожидание флагов готовности, запрос на обновление дисплея и т.д. уже прописаны в коде библиотек.

По ссылке можно загрузить архив с текстом программы и библиотеками -> Проект управления LCD с помощью стандартных библиотек

Другие статьи:

  6 Responses to “STM32L-DISCOVERY. Стандартные библиотеки для LCD.”

  1. Спасибо автору за познавательный материал. Но хочу немного добавить на основе опыта общения с линейкой STM32F. Проверки USE_FULL_ASSERT могут значительно тормозить приложение, если будут производиться при каждом вызове функции. К тому же, при корректном вводе параметров они просто излишни. Поэтому в stm32f10x_conf.h дифайн этой проверки даже изначально закомментирован. И, соответственно, просто не вызываются.
    А разрешение на использование стандартных библиотек определено строкой /*#define USE_STDPERIPH_DRIVER*/ в файле stm32f10x.h, достаточно только раскомментировать.
    Предполагаю, что в STM32L примерно аналогично.

  2. Спасибо, не знал. Когда столкнулся с вызовом проверок, проблему просто решил готовым способом.

    • Все действительно точно так же. Попробовал в файле stm32l1xx.h раскомментировать строку /*#define USE_STDPERIPH_DRIVER*/, тогда уже по условию подключается файл stm32l1xx_conf.h. А там вызов проверок зависит от того, задали ли мы USE_FULL_ASSERT или нет. И так же дефайн изначально закомментирован.
      Также можно USE_STDPERIPH_DRIVER и в настройках проекта прописать как я сделал, тогда в файле stm32l1xx.h можно не расскоментировать эту строку. USE_FULL_ASSERT и все что с этим связано можно исключить, если проверки не нужны. Проверил, при любом варианте, теперь вызов проверок в коде просто перепрыгивает. Ну а в этом примере они действительно и не нужны. Спасибо Mihail_IRK, я честно говоря, на это внимания и не обращал.

  3. просто я предпочитаю поменьше трогать препроцессор, чтобы в настройках глаза не разбегались ))))))))
    а настраивать, где это возможно, готовыми дифайнами, чтобы поменьше от себя изменений вносить
    но это, повторяю, исключительно моё личное предпочтение )))))))

  4. Видно автор пожадничал. В прилагаемом архиве нет файлов stm32l_discovery_lcd_new.h и stm32l_discovery_lcd_new.c (эти 2 файла — «урезанные» библиотеки из демопрограммы).