STM32F407 Урок 03. Работаем с OLED I2C дисплеем SSD 1306.
Добрый день, уважаемые читатели. Сегодня мы подключим недорогой OLED дисплей по шине I2C к нашему контроллеру и выведем на него время и температуру со встроенного в кристалл МК датчика. Цена индикатора 0,9'' колеблется около 100 рублей с шиной I2C и разрешением 128x32 монохром, чуть дороже 128x64, скоростной интерфейс SPI тоже прибавит к стоимости 30% и до нескольких тысяч за экран размером более 2''. Цветную 3'' экзотику я даже не рассматриваю, пока в здравом уме.
Как всегда, выберем в CubeMX наш кристалл, обязательно включим режим отладки, выберем резонаторы, частоту работы кристалла и тактирование RTC LSE от кварца 32768Гц. При желании можете включить USB как виртуальный COM и светодиоды для контроля прохождения проблемных точек кода, настройку можете посмотреть в обзоре и первом уроке. Включим первый канал I2C в Fast Mode :
Для I2C1 включим ДМА и прерывания :
Выберем имя для нашего проекта myicOLED, запускаем Atollic и дальше начнем разбираться с дисплеем. Советую сразу "правильно" программировать - создадим свою библиотеку, которую будем потом подключать к своим проектам. В левом окне раскроем папку Src нашего проекта и в меню выберем File->Source File, введем имя нашей библиотеки ic1306.c аналогично создадим File->Header File с именем ic1306.h. Последний перенесем из папки Src в Inc, откроем для редактирования и пропишем там между #define ic1306_H_ и #endif /* ic1306_H_ */ следующие строки :
#ifndef ic1306_H_
#define ic1306_H_
#ifndef SSD1306_I2C_ADDR
#define SSD1306_I2C_ADDR 0x78
//#define SSD1306_I2C_ADDR 0x7A
#endif
void display_init (uint8_t contrast, uint8_t bright);
#endif /* 1306_H_ */
Где SSD1306_I2C_ADDR 0x78 адрес моего дисплея, если не будет придавать признаков жизни - попробуйте другой, в отличие от Arduino необходимо сдвинуть на 1бит влево, далее задана ширина и высота и определена функция инициализации с параметрами контрасность, яркость.
В файле ic1306.c начнем создавать наши функции, вначале приинклудим main, хэдер нашей библиотеки и выбранного канала I2C дисплея :
#include "main.h"
#include <ic1306.h>
extern I2C_HandleTypeDef hi2c1;
Затем напишем функцию пересылки в наш дисплей 2-ух байт :
ssd1306_I2C_Write(uint8_t address, uint8_t reg, uint8_t data) {
uint8_t dt[2];
dt[0] = reg;
dt[1] = data;
HAL_I2C_Master_Transmit(&hi2c1, address, dt, 2,50);
}
С помощью нее сделаем определение записи команд и данных :
/* Write command */
#define SSD1306_WRITECOMMAND(command) ssd1306_I2C_Write(SSD1306_I2C_ADDR, 0x00, (command))
/* Write data */
#define SSD1306_WRITEDATA(data) ssd1306_I2C_Write(SSD1306_I2C_ADDR, 0x40, (data))
Функция инициализации цельнотянута, с небольшими измененниями из какой-то ардуинной библиотеки :
void display_init (uint8_t contrast, uint8_t bright)
{
SSD1306_WRITECOMMAND(0xAE); //display off
SSD1306_WRITECOMMAND(0xC8); //Set COM Output Scan Direction
SSD1306_WRITECOMMAND(0x00); //---set low column address
SSD1306_WRITECOMMAND(0x10); //---set high column address
SSD1306_WRITECOMMAND(0x40); //--set start line address
SSD1306_WRITECOMMAND(0x81); //--set contrast control register
SSD1306_WRITECOMMAND(contrast);
SSD1306_WRITECOMMAND(0xA1); //--set segment re-map 0 to 127
SSD1306_WRITECOMMAND(0xA6); //--set normal display
SSD1306_WRITECOMMAND(0xA8); //--set multiplex ratio(1 to 64)
SSD1306_WRITECOMMAND(0x3F); //
SSD1306_WRITECOMMAND(0xA4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
SSD1306_WRITECOMMAND(0xD3); //-set display offset
SSD1306_WRITECOMMAND(0x00); //-not offset
SSD1306_WRITECOMMAND(0xD5); //--set display clock divide ratio/oscillator frequency
SSD1306_WRITECOMMAND(0xF0); //--set divide ratio
SSD1306_WRITECOMMAND(0xD9); //--set pre-charge period
SSD1306_WRITECOMMAND(bright); //
SSD1306_WRITECOMMAND(0xDA); //--set com pins hardware configuration
SSD1306_WRITECOMMAND(0x12);
SSD1306_WRITECOMMAND(0xDB); //--set vcomh
SSD1306_WRITECOMMAND(0x20); //0x20,0.77xVcc
SSD1306_WRITECOMMAND(0x8D); //--set DC-DC enable
SSD1306_WRITECOMMAND(0x14); //
SSD1306_WRITECOMMAND(0xAF); //--turn on SSD1306 panel
}
В главной программе main.c прописываем хэдер нашей библиотеки :
/* USER CODE BEGIN Includes */
#include <ic1306.h>
/* USER CODE END Includes */
В бесконечном цикле поставим задержку а до нее инициализацию дисплея :
/* USER CODE BEGIN 2 */
display_init (0x30,0x22);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_Delay(500);
/* USER CODE END WHILE */
В функции display_init(contrast, bright); контраст может быть от 0 до 255, яркость разбита на два полубайта, комбинации 0xX0 0x0X недопустимы, для понимания работы дисплея и дальнейших функций вывода изображения советую почитать статью на Датагоре Визуализация для микроконтроллера. Часть 1. OLED дисплей 0.96" (128х64) на SSD1306 и переведенный на русский даташит SSD1306 на Microsin.net.
На экране увидите графические узоры типа таких :
Функция очистки в библиотеке ic1306.c будет выглядеть так :
void display_clear(uint8_t start, uint8_t stop)
{ uint32_t *adrclear;
uint32_t timer,timec;
uint8_t dt[128+1];
adrclear=&dt;
for(uint8_t i=0;i<32;i++)
{*adrclear++=0;}
dt[128]=0;
dt[0]=0x40;
for (uint8_t m = start; m <= stop; m++) {
SSD1306_WRITECOMMAND(0x20);
SSD1306_WRITECOMMAND(0x01);
SSD1306_WRITECOMMAND(0x21);
SSD1306_WRITECOMMAND(0);
SSD1306_WRITECOMMAND(127);
SSD1306_WRITECOMMAND(0x22);
SSD1306_WRITECOMMAND(m);
SSD1306_WRITECOMMAND(m);
HAL_I2C_Master_Transmit_DMA(&hi2c1, SSD1306_I2C_ADDR, dt, 128+1);
timec=HAL_GetTick();
timer=timec+50;
while ((HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)&&(timec<timer))
{timec=HAL_GetTick();}
}
}
Не забываем описать прототип в ic1306.h :
void display_clear (uint8_t start, uint8_t stop);
В ней мы очищаем буфер на одну строку + управляющий байт, устанавливаем режим адресации столбцов с 0 по 127, строк одна - текущая и в цикле строки от start до stop, будут заполнены 0x00 через пересылку массива в режиме DMA. В цикле ждем пока канал I2C освободится или не произойдет timeout (50ms) после этого переходим к пересылке следующей строки. В main.c для очистки всего дисплея, с 0 по 7 строку, дописываем :
/* USER CODE BEGIN 2 */
display_init (50,0x11);
display_clear(0,7);
/* USER CODE END 2 */
Теперь добавим в ic1306.c функцию вывода текста, шрифт высотой 16 и шириной 12 пикселей самому рисовать было лень, искал долго в разных проектах, вот что накопал :
Font16x12
uint8_t MediumFont[] = // Шрифт MediumFont
{ //
0x0C,0x10,0x20,0x5F, // ширина символов (12), высота символов (16), код первого символа (32), количество символов (95)
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 001) 0x20=032 пробел
0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0x67,0x00,0x00,0x00,0x00,0x00, // 002) 0x21=033 !
0x00,0x00,0x00,0x16,0x0E,0x00,0x00,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 003) 0x22=034 "
0x00,0x00,0x60,0xE0,0xF8,0x7E,0x6E,0xE0,0xF8,0x7E,0x6E,0x00,0x00,0x76,0x7E,0x1F,0x07,0x76,0x7E,0x1F,0x07,0x06,0x00,0x00, // 004) 0x23=035 #
0x00,0x78,0xFC,0xCE,0x86,0xFF,0xFF,0x86,0x9E,0x1C,0x18,0x00,0x00,0x18,0x38,0x79,0x61,0xFF,0xFF,0x61,0x73,0x3F,0x1E,0x00, // 005) 0x24=036 $
0x00,0x3C,0x7E,0x66,0x7E,0xBC,0xE0,0x78,0x1E,0x06,0x00,0x00,0x00,0x00,0x60,0x78,0x1E,0x07,0x3D,0x7E,0x66,0x7E,0x3C,0x00, // 006) 0x25=037 %
0x00,0x00,0x00,0x80,0x80,0xFC,0xFE,0xE6,0xE6,0x7E,0x3C,0x00,0x00,0x1E,0x3F,0x73,0x61,0x61,0x71,0x7F,0x3F,0x7C,0x6C,0x00, // 007) 0x26=038 &
0x00,0x00,0x00,0x00,0x00,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 008) 0x27=039 '
0x00,0x00,0x00,0x00,0xF0,0xFC,0x0E,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x3F,0x70,0xC0,0x00,0x00,0x00,0x00, // 009) 0x28=040 (
0x00,0x00,0x00,0x00,0x03,0x0E,0xFC,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x70,0x3F,0x0F,0x00,0x00,0x00,0x00, // 010) 0x29=041 )
0x00,0x00,0x00,0x08,0x78,0x3C,0x3C,0x78,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 011) 0x2A=042 *
0x00,0x00,0x80,0x80,0x80,0xF0,0xF0,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x0F,0x0F,0x01,0x01,0x01,0x00,0x00, // 012) 0x2B=043 +
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xB0,0x70,0x00,0x00,0x00,0x00,0x00, // 013) 0x2C=044 ,
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00, // 014) 0x2D=045 -
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x00, // 015) 0x2E=046 .
0x00,0x00,0x00,0x00,0x00,0x80,0xE0,0x78,0x1E,0x06,0x00,0x00,0x00,0x00,0x60,0x78,0x1E,0x07,0x01,0x00,0x00,0x00,0x00,0x00, // 016) 0x2F=047 /
//
0x00,0xF8,0xFC,0x0E,0x06,0x06,0x06,0x06,0x0E,0xFC,0xF8,0x00,0x00,0x1F,0x3F,0x70,0x60,0x60,0x60,0x60,0x70,0x3F,0x1F,0x00, // 017) 0x30=048 0
0x00,0x00,0x00,0x30,0x38,0x1C,0xFE,0xFE,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x7F,0x7F,0x60,0x00,0x00,0x00, // 018) 0x31=049 1
0x00,0x18,0x1C,0x1E,0x06,0x06,0x06,0x86,0xCE,0xFC,0x78,0x00,0x00,0x78,0x7C,0x7E,0x66,0x67,0x63,0x63,0x61,0x70,0x70,0x00, // 019) 0x32=050 2
0x00,0x0E,0x0E,0x06,0x06,0xC6,0xE6,0xF6,0xFE,0x9E,0x0E,0x00,0x00,0x18,0x38,0x78,0x60,0x60,0x60,0x60,0x71,0x3F,0x1F,0x00, // 020) 0x33=051 3
0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0xFE,0xFE,0x06,0x00,0x00,0x07,0x07,0x07,0x06,0x06,0x06,0x66,0x7F,0x7F,0x66,0x00, // 021) 0x34=052 4
0x00,0xFE,0xFE,0xE6,0x66,0x66,0x66,0x66,0xE6,0xCE,0x8E,0x00,0x00,0x18,0x38,0x78,0x60,0x60,0x60,0x60,0x70,0x3F,0x1F,0x00, // 022) 0x35=053 5
0x00,0xF8,0xFC,0xCE,0xC6,0xC6,0xC6,0xC6,0xDE,0x9C,0x18,0x00,0x00,0x1F,0x3F,0x71,0x60,0x60,0x60,0x60,0x71,0x3F,0x1F,0x00, // 023) 0x36=054 6
0x00,0x1E,0x1E,0x06,0x06,0x06,0x06,0x86,0xE6,0x7E,0x1E,0x00,0x00,0x00,0x00,0x00,0x60,0x78,0x1E,0x07,0x01,0x00,0x00,0x00, // 024) 0x37=055 7
0x00,0x78,0xFC,0xCE,0x86,0x86,0x86,0x86,0xCE,0xFC,0x78,0x00,0x00,0x1E,0x3F,0x73,0x61,0x61,0x61,0x61,0x73,0x3F,0x1E,0x00, // 025) 0x38=056 8
0x00,0xF8,0xFC,0x8E,0x06,0x06,0x06,0x06,0x8E,0xFC,0xF8,0x00,0x00,0x18,0x39,0x7B,0x63,0x63,0x63,0x63,0x73,0x3F,0x1F,0x00, // 026) 0x39=057 9
0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00,0x00, // 027) 0x3A=058 :
0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2C,0x1C,0x00,0x00,0x00,0x00,0x00, // 028) 0x3B=059 ;
0x00,0x00,0x80,0xC0,0xC0,0xE0,0x60,0x70,0x30,0x30,0x00,0x00,0x00,0x00,0x01,0x03,0x03,0x07,0x06,0x0E,0x0C,0x0C,0x00,0x00, // 029) 0x3C=060 <
0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x00,0x00, // 030) 0x3D=061 =
0x00,0x00,0x30,0x30,0x70,0x60,0xE0,0xC0,0xC0,0x80,0x00,0x00,0x00,0x00,0x0C,0x0C,0x0E,0x06,0x07,0x03,0x03,0x01,0x00,0x00, // 031) 0x3E=062 >
0x00,0x18,0x1C,0x1E,0x06,0x06,0x86,0x86,0xCE,0xFC,0x78,0x00,0x00,0x00,0x00,0x00,0x6E,0x6F,0x03,0x01,0x01,0x00,0x00,0x00, // 032) 0x3F=063 ?
//
0x00,0xF8,0xFC,0x0E,0xE6,0xF6,0x36,0xF6,0xF6,0x0E,0xFC,0xF8,0x00,0x1F,0x3F,0x70,0x67,0x6F,0x6C,0x6F,0x67,0x6C,0x2F,0x07, // 033) 0x40=064 @
0x00,0x00,0xF0,0xFC,0x1E,0x06,0x06,0x06,0xFE,0xFE,0x06,0x00,0x00,0x60,0x7F,0x7F,0x63,0x03,0x03,0x63,0x7F,0x7F,0x60,0x00, // 034) 0x41=065 A
0x00,0x06,0xFE,0xFE,0x86,0x86,0x86,0x86,0xCE,0xFC,0x78,0x00,0x00,0x60,0x7F,0x7F,0x61,0x61,0x61,0x61,0x73,0x3F,0x1E,0x00, // 035) 0x42=066 B
0x00,0xF8,0xFC,0x0E,0x06,0x06,0x06,0x06,0x1E,0x1C,0x18,0x00,0x00,0x1F,0x3F,0x70,0x60,0x60,0x60,0x60,0x78,0x38,0x18,0x00, // 036) 0x43=067 C
0x00,0x06,0xFE,0xFE,0x06,0x06,0x06,0x06,0x0E,0xFC,0xF8,0x00,0x00,0x60,0x7F,0x7F,0x60,0x60,0x60,0x60,0x70,0x3F,0x1F,0x00, // 037) 0x44=068 D
0x00,0x06,0xFE,0xFE,0x86,0x86,0x86,0xC6,0xC6,0x0E,0x0E,0x00,0x00,0x60,0x7F,0x7F,0x61,0x61,0x61,0x63,0x63,0x70,0x70,0x00, // 038) 0x45=069 E
0x00,0x06,0xFE,0xFE,0x86,0x86,0xC6,0xC6,0x06,0x0E,0x0E,0x00,0x00,0x60,0x7F,0x7F,0x61,0x01,0x03,0x03,0x00,0x00,0x00,0x00, // 039) 0x46=070 F
0x00,0xF8,0xFC,0x0E,0x06,0x06,0x06,0x06,0x1E,0x1C,0x18,0x00,0x00,0x1F,0x3F,0x70,0x60,0x60,0x63,0x63,0x73,0x3F,0x1F,0x00, // 040) 0x47=071 G
0x00,0x06,0xFE,0xFE,0x86,0x80,0x80,0x86,0xFE,0xFE,0x06,0x00,0x00,0x60,0x7F,0x7F,0x61,0x01,0x01,0x61,0x7F,0x7F,0x60,0x00, // 041) 0x48=072 H
0x00,0x00,0x00,0x00,0x06,0xFE,0xFE,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x7F,0x7F,0x60,0x00,0x00,0x00,0x00, // 042) 0x49=073 I
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0xFE,0xFE,0x06,0x00,0x00,0x00,0x18,0x38,0x78,0x60,0x60,0x70,0x3F,0x1F,0x00,0x00, // 043) 0x4A=074 J
0x00,0x06,0xFE,0xFE,0x86,0x80,0xC0,0xF6,0x7E,0x1E,0x06,0x00,0x00,0x60,0x7F,0x7F,0x61,0x01,0x03,0x6F,0x7E,0x78,0x60,0x00, // 044) 0x4B=075 K
0x00,0x06,0xFE,0xFE,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x7F,0x7F,0x60,0x60,0x60,0x60,0x60,0x70,0x70,0x00, // 045) 0x4C=076 L
0x00,0x06,0xFE,0xFE,0x78,0xE0,0xE0,0x78,0xFE,0xFE,0x06,0x00,0x00,0x60,0x7F,0x7F,0x60,0x01,0x01,0x60,0x7F,0x7F,0x60,0x00, // 046) 0x4D=077 M
0x00,0x06,0xFE,0xFE,0x78,0xE0,0x80,0x06,0xFE,0xFE,0x06,0x00,0x00,0x60,0x7F,0x7F,0x60,0x01,0x07,0x1E,0x7F,0x7F,0x60,0x00, // 047) 0x4E=078 N
0x00,0xF8,0xFC,0x0E,0x06,0x06,0x06,0x06,0x0E,0xFC,0xF8,0x00,0x00,0x1F,0x3F,0x70,0x60,0x60,0x60,0x60,0x70,0x3F,0x1F,0x00, // 048) 0x4F=079 O
//
0x00,0x06,0xFE,0xFE,0x06,0x06,0x06,0x06,0x8E,0xFC,0xF8,0x00,0x00,0x60,0x7F,0x7F,0x63,0x03,0x03,0x03,0x03,0x01,0x00,0x00, // 049) 0x50=080 P
0x00,0xF8,0xFC,0x0E,0x06,0x06,0x06,0x06,0x0E,0xFC,0xF8,0x00,0x00,0x1F,0x3F,0x70,0x60,0x60,0x6C,0x7C,0x38,0x7F,0x6F,0x00, // 050) 0x51=081 Q
0x00,0x06,0xFE,0xFE,0x06,0x06,0x06,0x06,0x8E,0xFC,0xF8,0x00,0x00,0x60,0x7F,0x7F,0x63,0x03,0x03,0x6F,0x7F,0x79,0x60,0x00, // 051) 0x52=082 R
0x00,0x78,0xFC,0xCE,0x86,0x86,0x86,0x86,0x9E,0x1C,0x18,0x00,0x00,0x18,0x38,0x79,0x61,0x61,0x61,0x61,0x73,0x3F,0x1E,0x00, // 052) 0x53=083 S
0x00,0x0E,0x0E,0x06,0x06,0xFE,0xFE,0x06,0x06,0x0E,0x0E,0x00,0x00,0x00,0x00,0x00,0x60,0x7F,0x7F,0x60,0x00,0x00,0x00,0x00, // 053) 0x54=084 T
0x00,0x06,0xFE,0xFE,0x06,0x00,0x00,0x06,0xFE,0xFE,0x06,0x00,0x00,0x00,0x1F,0x3F,0x70,0x60,0x60,0x70,0x3F,0x1F,0x00,0x00, // 054) 0x55=085 U
0x00,0x06,0xFE,0xFE,0x06,0x00,0x00,0x06,0xFE,0xFE,0x06,0x00,0x00,0x00,0x03,0x0F,0x3E,0x78,0x78,0x3E,0x0F,0x03,0x00,0x00, // 055) 0x56=086 V
0x00,0x06,0xFE,0xFE,0x06,0x80,0x80,0x06,0xFE,0xFE,0x06,0x00,0x00,0x00,0x1F,0x7F,0x78,0x1F,0x1F,0x78,0x7F,0x1F,0x00,0x00, // 056) 0x57=087 W
0x00,0x06,0x1E,0x7E,0xF6,0xC0,0xC0,0xF6,0x7E,0x1E,0x06,0x00,0x00,0x60,0x78,0x7E,0x6F,0x03,0x03,0x6F,0x7E,0x78,0x60,0x00, // 057) 0x58=088 X
0x00,0x06,0x7E,0xFE,0xC6,0x00,0x00,0xC6,0xFE,0x7E,0x06,0x00,0x00,0x00,0x00,0x01,0x63,0x7F,0x7F,0x63,0x01,0x00,0x00,0x00, // 058) 0x59=089 Y
0x00,0x0E,0x0E,0x06,0x06,0x86,0xC6,0xE6,0x76,0x3E,0x1E,0x00,0x00,0x78,0x7C,0x6E,0x67,0x63,0x61,0x60,0x60,0x70,0x70,0x00, // 059) 0x5A=090 Z
0x00,0x00,0x00,0x00,0xFF,0xFF,0x03,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xC0,0xC0,0xC0,0x00,0x00,0x00, // 060) 0x5B=091 [
0x00,0x00,0x06,0x1E,0x78,0xE0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x07,0x1E,0x78,0x60,0x00,0x00, // 061) 0x5C=092 обратный слеш
0x00,0x00,0x00,0x03,0x03,0x03,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xC0,0xFF,0xFF,0x00,0x00,0x00,0x00, // 062) 0x5D=093 ]
0x00,0x00,0x00,0x30,0x3C,0x1E,0x1E,0x3C,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 063) 0x5E=094 ^
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00, // 064) 0x5F=095 _
//
0x00,0x00,0x00,0x00,0x00,0x0E,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 065) 0x60=096 `
0x00,0xC0,0xE0,0x70,0x30,0x30,0x30,0x70,0xE0,0xC0,0x00,0x00,0x00,0x1C,0x3E,0x77,0x63,0x63,0x63,0x33,0x7F,0x7F,0x60,0x00, // 066) 0x61=097 a
0x00,0x06,0xFE,0xFE,0x66,0x30,0x30,0x30,0x70,0xE0,0xC0,0x00,0x00,0x60,0x7F,0x7F,0x30,0x60,0x60,0x60,0x70,0x3F,0x1F,0x00, // 067) 0x62=098 b
0x00,0xC0,0xE0,0x70,0x30,0x30,0x30,0x30,0xF0,0xE0,0xC0,0x00,0x00,0x1F,0x3F,0x70,0x60,0x60,0x60,0x60,0x78,0x38,0x18,0x00, // 068) 0x63=099 c
0x00,0xC0,0xE0,0x70,0x30,0x30,0x30,0x66,0xFE,0xFE,0x06,0x00,0x00,0x1F,0x3F,0x70,0x60,0x60,0x60,0x30,0x7F,0x7F,0x60,0x00, // 069) 0x64=100 d
0x00,0xC0,0xE0,0x70,0x30,0x30,0x30,0x30,0x70,0xE0,0xC0,0x00,0x00,0x1F,0x3F,0x76,0x66,0x66,0x66,0x66,0x76,0x37,0x17,0x00, // 070) 0x65=101 e
0x00,0x00,0x00,0x60,0xFC,0xFE,0x66,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x7F,0x00,0x00,0x00,0x00,0x00,0x00, // 071) 0x66=102 f
0x00,0xC0,0xE0,0x70,0x30,0x30,0x30,0x60,0xF0,0xF0,0x30,0x00,0x00,0x33,0x77,0xEE,0xCC,0xCC,0xCC,0xEE,0x7F,0x3F,0x00,0x00, // 072) 0x67=103 g
0x00,0x06,0xFE,0xFE,0x66,0x30,0x30,0x70,0xE0,0xC0,0x00,0x00,0x00,0x60,0x7F,0x7F,0x60,0x00,0x00,0x60,0x7F,0x7F,0x60,0x00, // 073) 0x68=104 h
0x00,0x00,0x00,0x00,0x30,0xF6,0xF6,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x7F,0x7F,0x60,0x00,0x00,0x00,0x00, // 074) 0x69=105 i
0x00,0x00,0x00,0x00,0x00,0x30,0xF6,0xF6,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x7F,0x3F,0x00,0x00,0x00,0x00, // 075) 0x6A=106 j
0x00,0x06,0xFE,0xFE,0x06,0x80,0xF0,0xF0,0x70,0x30,0x30,0x00,0x00,0x60,0x7F,0x7F,0x63,0x07,0x0F,0x7C,0x78,0x70,0x60,0x00, // 076) 0x6B=107 k
0x00,0x00,0x00,0x00,0x06,0xFE,0xFE,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x7F,0x7F,0x60,0x00,0x00,0x00,0x00, // 077) 0x6C=108 l
0x30,0xF0,0xE0,0x30,0x30,0xF0,0xE0,0x30,0x30,0xF0,0xE0,0x00,0x60,0x7F,0x7F,0x60,0x00,0x7F,0x7F,0x00,0x60,0x7F,0x7F,0x60, // 078) 0x6D=109 m
0x00,0x30,0xF0,0xF0,0x60,0x30,0x30,0x70,0xE0,0xC0,0x00,0x00,0x00,0x60,0x7F,0x7F,0x60,0x00,0x00,0x60,0x7F,0x7F,0x60,0x00, // 079) 0x6E=110 n
0x00,0xC0,0xE0,0x70,0x30,0x30,0x30,0x30,0x70,0xE0,0xC0,0x00,0x00,0x1F,0x3F,0x70,0x60,0x60,0x60,0x60,0x70,0x3F,0x1F,0x00, // 080) 0x6F=111 o
//
0x00,0x30,0xF0,0xF0,0x60,0x30,0x30,0x30,0x70,0xE0,0xC0,0x00,0x00,0xC0,0xFF,0xFF,0xD8,0x30,0x30,0x30,0x38,0x1F,0x0F,0x00, // 081) 0x70=112 p
0x00,0xC0,0xE0,0x70,0x30,0x30,0x30,0x60,0xF0,0xF0,0x30,0x00,0x00,0x0F,0x1F,0x38,0x30,0x30,0x30,0xD8,0xFF,0xFF,0xC0,0x00, // 082) 0x71=113 q
0x00,0x00,0x30,0xF0,0xF0,0x60,0x30,0x30,0x70,0x60,0x00,0x00,0x00,0x00,0x60,0x7F,0x7F,0x60,0x00,0x00,0x00,0x00,0x00,0x00, // 083) 0x72=114 r
0x00,0xE0,0xF0,0x30,0x30,0x30,0x30,0x30,0x70,0x70,0x60,0x00,0x00,0x19,0x3B,0x7B,0x63,0x63,0x63,0x63,0x77,0x3E,0x1C,0x00, // 084) 0x73=115 s
0x00,0x00,0x00,0x30,0xFE,0xFE,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x7F,0x60,0x60,0x00,0x00,0x00,0x00, // 085) 0x74=116 t
0x00,0x30,0xF0,0xF0,0x30,0x00,0x00,0x30,0xF0,0xF0,0x30,0x00,0x00,0x00,0x1F,0x3F,0x70,0x60,0x60,0x30,0x7F,0x7F,0x60,0x00, // 086) 0x75=117 u
0x00,0x30,0xF0,0xF0,0x30,0x00,0x00,0x30,0xF0,0xF0,0x30,0x00,0x00,0x00,0x00,0x07,0x1F,0x78,0x78,0x1F,0x07,0x00,0x00,0x00, // 087) 0x76=118 v
0x30,0xF0,0xF0,0x30,0x00,0x00,0x00,0x00,0x30,0xF0,0xF0,0x30,0x00,0x03,0x1F,0x7C,0x70,0x1E,0x1E,0x70,0x7C,0x1F,0x03,0x00, // 088) 0x77=119 w
0x00,0x00,0x30,0x70,0xF0,0x80,0x80,0xF0,0x70,0x30,0x00,0x00,0x00,0x00,0x60,0x70,0x7D,0x0F,0x0F,0x7D,0x70,0x60,0x00,0x00, // 089) 0x78=120 x
0x00,0x00,0x30,0xF0,0xC0,0x00,0x00,0xC0,0xF0,0x30,0x00,0x00,0x00,0x00,0x60,0x60,0x73,0x3F,0x0F,0x03,0x00,0x00,0x00,0x00, // 090) 0x79=121 y
0x00,0x00,0x70,0x70,0x30,0x30,0xB0,0xF0,0xF0,0x70,0x00,0x00,0x00,0x00,0x78,0x7C,0x6E,0x67,0x63,0x61,0x70,0x70,0x00,0x00, // 091) 0x7A=122 z
0x00,0x00,0x80,0xC0,0xFC,0x7E,0x07,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x3F,0x7E,0xE0,0xC0,0xC0,0x00,0x00,0x00, // 092) 0x7B=123 {
0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x7F,0x00,0x00,0x00,0x00,0x00, // 093) 0x7C=124 |
0x00,0x00,0x00,0x03,0x03,0x07,0x7E,0xFC,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xE0,0x7E,0x3F,0x03,0x01,0x00,0x00, // 094) 0x7D=125 }
0x00,0x80,0xC0,0xC0,0xC0,0xC0,0x80,0x00,0x00,0x80,0x80,0x00,0x00,0x01,0x01,0x00,0x00,0x01,0x03,0x03,0x03,0x03,0x01,0x00, // 095) 0x7E=126 ~
//
0 // В таблице имеется (0) пустых интервалов. См. шрифты с Русскими символами.
};
Запихнем его в бибилиотеку ic1306.c до фунции печати одной строки, которая для этого фонта будет такая :
void display_MediumPrint(uint8_t posx, uint8_t posy, uint8_t *str)
{uint8_t dt[256+1];
uint32_t timer,timec;
uint16_t posfont, posscr;
uint32_t *adrclear;
adrclear=&dt;
uint8_t code;
code=*str++;
for(uint8_t i=0;i<64;i++)
{ *adrclear++=0; }
dt[256]=0;
SSD1306_WRITECOMMAND(0x20);
SSD1306_WRITECOMMAND(0x00);
SSD1306_WRITECOMMAND(0x21);
SSD1306_WRITECOMMAND(0);
SSD1306_WRITECOMMAND(127);
SSD1306_WRITECOMMAND(0x22);
SSD1306_WRITECOMMAND(posy);
SSD1306_WRITECOMMAND(posy+1);
posscr=posx*12;
while (code>31)
{posfont=4+24*(code-32);
for(uint8_t i = 0; i <12; i++)
{ dt[i+1+posscr]=MediumFont[i+posfont];
dt[i+1+128+posscr]=MediumFont[i+12+posfont]; }
code=*str++;
posscr+=12;
if (posscr>127) break;
}
dt[0] = 0x40;
HAL_I2C_Master_Transmit_DMA(&hi2c1, SSD1306_I2C_ADDR, dt, 256+1);
timec=HAL_GetTick();
timer=timec+50;
while ((HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)&&(timec<timer))
{timec=HAL_GetTick();}
}
Здесь мы очищаем буфер на 2 строки дисплея - ведь фонт у нас 16 точек высотой. Настраиваем вывод в дисплей с 0 по 127 столбец и две строки по высоте от 0 по 6 строку дисплея. Формируем массив букв строк из шрифта и перебрасывем его в дисплей. В файле ic1306.h не забываем описать прототип :
void display_MediumPrint(uint8_t posx, uint8_t posy,uint8_t *str);
В main.c напишем приветствие :
/* USER CODE BEGIN 2 */
display_init (50,0x22);
display_clear(0,7);
display_MediumPrint(3,1,"Hello,");
display_MediumPrint(3,4,"Hubr!");
/* USER CODE END 2 */
Полюбуемся приветствием :
Основа нашей библиотеки готова, теперь настроим в CubeMX режим RTC :
Настройки делителя оставим такими для кварца 32768 и установим текущую дату и время:
Если вы хотите поподробней прочитать про часовой таймер - вот отличная статья на русском,определим в main.c две глобальных структуры :
/* USER CODE BEGIN PV */
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef DateToUpdate = {0};
/* USER CODE END PV */
В бесконечном цикле прописываем вывод текущего времени и даты :
/* USER CODE BEGIN WHILE */
char trans_str[64] = {0,};
while (1)
{
HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN); // RTC_FORMAT_BIN , RTC_FORMAT_BCD
snprintf(trans_str, 63, " %02d:%02d:%02d\n", sTime.Hours, sTime.Minutes, sTime.Seconds);
display_MediumPrint(0,1,trans_str);
HAL_RTC_GetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN);
snprintf(trans_str, 63, "%d-%02d-20%d\n", DateToUpdate.Date, DateToUpdate.Month, DateToUpdate.Year);
display_MediumPrint(0,4,trans_str);
HAL_Delay(1000);
/* USER CODE END WHILE */
Смотрим как методично тикают часики :
Теперь вернемся опять в CubeMX, из меню Analog активируем температурный датчик подключеный на ADC1 канал 16 :
Настроим режим Regular чтения c АЦП :
Более подробно про АЦП и режимах его работы вы можете почитать здесь. В цикле будем выводить время, считанное с АЦП значение и преобразуем его в температуру, используя только целочисленные значения :
/* USER CODE BEGIN WHILE */
char trans_str[64] = {0,};
int32_t ts = 0;
while (1)
{
HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN); // RTC_FORMAT_BIN , RTC_FORMAT_BCD
snprintf(trans_str, 63, " %02d:%02d:%02d\n", sTime.Hours, sTime.Minutes, sTime.Seconds);
display_MediumPrint(0,0,trans_str);
HAL_RTC_GetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN);
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100);
ts = HAL_ADC_GetValue(&hadc1);
snprintf(trans_str, 63, "Ts %d\n", ts);
display_MediumPrint(2,3,trans_str);
//temp = (Vtemp -tV_25)/tSlope + 25; (Vtemp-0,76V)/2,5mV
snprintf(trans_str, 63, "Temp %d\n",(ts*33-31130)/102+25);
display_MediumPrint(2,6,trans_str);
HAL_Delay(1000);
/* USER CODE END WHILE */
Вы можете заметить, что мы читаем, но не выводим дату - это фича HAL серии STMF4 - без получения даты значение времени не обновляется. Любуемся температурой, как то многовато для кристалла, на STM32F103 было вполовину меньше :
Вот мы и изучили основы работы с OLED 1306, в разделе Файлы вы можете скачать архив библиотеки там же файл с используемым шрифтом, если вам нужен русский или другого размера. В следующем уроке поработаем с SD картой, потом с Flash W25Q16, SPI TFT дисплеем и в зависимости от настроения LAN или еще чем-то, рад выслушать ваши пожелания.
Адрес для контактов : imax9@narod.ru
Если вам понравились мои работы и вы желаете поддержать сайт - сделайте дотацию.
При копировании статьи – обязательна ссылка на авторство и источник. Без разрешения автора копирование запрещено.
© Максим Ильин 2020г.