Итоговое устройство
Итоговый код:
Спойлер
/**
******************************************************************************
* @file : main.c
* @author : Auto-generated by STM32CubeIDE
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#include <stdint.h>
#include "f103c8t6.h"
#include "stdlib.h"
#include "f103st7735.h"
#include "stm32f10x.h"
#include "pumper.h"
#include "f103rtc.h"
#if !defined(__SOFT_FP__) && defined(__ARM_FP)
#warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif
unsigned char startFontSize = 0;
unsigned char lineCFGtext = 0;
int main(void) {
if (ClockInit() == 0) SystemCoreClock = 72000000UL;
f103initPC13led();
f103initTIM4();
f103st7735init();
f1InitPumpGpio();
f103st7735fillScreen(ST7735_BLACK);
f103st7735printString((const unsigned char *) "Start!", ST7735_WHITE, ST7735_BLACK, startFontSize, 0, lineCFGtext * fontSizeY[startFontSize]);
++lineCFGtext;
f103st7735printUInt(SystemCoreClock, ST7735_RED, ST7735_WHITE, startFontSize, 0, lineCFGtext * fontSizeY[startFontSize]);
++lineCFGtext;
f103initRTC();
// -- manual set date time current
/*currentDateTime.tm_mday = 18; // 1-31
currentDateTime.tm_mon = 7; // 0-11
currentDateTime.tm_year = 2023 - 1900; // since 1900 year
currentDateTime.tm_hour = 10; // 0-23
currentDateTime.tm_min = 19; // 0-59
currentDateTime.tm_sec = 30; // 0-60
currentDateTime.tm_wday = 4; // 0-6 since Sunday
setCurrentDateTime(¤tDateTime);*/
// -- read RTC
getCurrentDateTime(¤tDateTime);
f103st7735printString((const unsigned char *) "* ", ST7735_WHITE, ST7735_BLACK, startFontSize, 0, (lineCFGtext+2) * fontSizeY[startFontSize]);
f103st7735printText((const unsigned char *) asctime((tm*)¤tDateTime));
// -- begin
delay_ms(5000UL);
f103st7735fillScreen(ST7735_BLACK);
// -- pumper
initPumper();
// -- start loop --
while (1) {
loopPumper();
// test led PC13 blink
static unsigned long timerBlinkC13 = 0;
static unsigned char ledStat = 0;
if ((millis() - timerBlinkC13) >= 1000UL) {
timerBlinkC13 = millis();
f103setC13led(ledStat = !ledStat);
}
// -- end loop --
}
}
/*
* f103c8t6.h
*
* Created on: Feb 28, 2023
* Author: Andrey
*/
#ifndef F103C8T6_H_
#define F103C8T6_H_
#ifndef count_of
#define count_of(a) (sizeof(a)/sizeof((a)[0]))
#endif
#define bitRead(x, bitPosition) (((x) >> bitPosition) & 1)
extern unsigned long SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
int ClockInit(void);
void f103setC13led(unsigned char AledONOFF);
void f103initPC13led(void);
void f103initTIM4(void);
unsigned long millis(void);
void delay_ms(unsigned long period_ms);
#endif /* F103C8T6_H_ */
/*
* f103c8t6.c
*
* Created on: Feb 28, 2023
* Author: Andrey
*/
#include "stm32f10x.h"
#include "f103c8t6.h"
unsigned long SystemCoreClock = 8000000UL; /*!< System Clock Frequency (Core Clock) */
volatile unsigned long msTicks = 0;
/*http://dimoon.ru/obuchalka/stm32f1/uroki-stm32f103-chast-4-nastroyka-rcc.html?ysclid=leflwcqmz5475683246*/
//Настраиваем тактирование системы от внешнего кварца
//через PLL на саксимально возможных частотах.
//Внешний кварц должен быть на 8МГц
//Возвращает:
// 0 - завершено успешно
// 1 - не запустился кварцевый генератор
// 2 - не запустился PLL
int ClockInit(void) {
__IO int StartUpCounter;
////////////////////////////////////////////////////////////
//Запускаем кварцевый генератор
////////////////////////////////////////////////////////////
RCC->CR |= RCC_CR_HSEON; //Запускаем генератор HSE
//Ждем успешного запуска или окончания тайм-аута
for(StartUpCounter=0; ; StartUpCounter++) {
//Если успешно запустилось, то
//выходим из цикла
if (RCC->CR & RCC_CR_HSERDY) break;
//Если не запустилось, то
//отключаем все, что включили
//и возвращаем ошибку
if (StartUpCounter > 0x1000) {
RCC->CR &= ~RCC_CR_HSEON; //Останавливаем HSE
return 1;
}
}
////////////////////////////////////////////////////////////
//Настраиваем и запускаем PLL
////////////////////////////////////////////////////////////
//Настраиваем PLL
RCC->CFGR |= RCC_CFGR_PLLMULL_0 | RCC_CFGR_PLLMULL_1 | RCC_CFGR_PLLMULL_2; //PLL множитель равен 9 // 0111: PLL input clock x 9
RCC->CFGR |= RCC_CFGR_PLLSRC_HSE; //Тактирование PLL от HSE
RCC->CR |= RCC_CR_PLLON; //Запускаем PLL
//Ждем успешного запуска или окончания тайм-аута
for(StartUpCounter=0; ; StartUpCounter++) {
//Если успешно запустилось, то
//выходим из цикла
if (RCC->CR & RCC_CR_PLLRDY) break;
//Если по каким-то причинам не запустился PLL, то
//отключаем все, что включили
//и возвращаем ошибку
if (StartUpCounter > 0x1000) {
RCC->CR &= ~RCC_CR_HSEON; //Останавливаем HSE
RCC->CR &= ~RCC_CR_PLLON; //Останавливаем PLL
return 2;
}
}
////////////////////////////////////////////////////////////
//Настраиваем FLASH и делители
////////////////////////////////////////////////////////////
//Устанавливаем 2 цикла ожидания для Flash
//так как частота ядра у нас будет 48 MHz < SYSCLK <= 72 MHz
FLASH->ACR |= FLASH_ACR_LATENCY_1; // 010 Two wait states, if 48 MHz < SYSCLK ≤ 72 MHz
//Делители
RCC->CFGR &= ~RCC_CFGR_PPRE2; //Делитель шины APB2 отключен // 0xx: HCLK not divided
RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; //Делитель нишы APB1 равен 2 // 100: HCLK divided by 2
RCC->CFGR &= ~RCC_CFGR_HPRE; //Делитель AHB отключен // 0xxx: SYSCLK not divided
RCC->CFGR &= ~RCC_CFGR_SW; //Переключаемся на работу от PLL // 10: PLL selected as system clock
RCC->CFGR |= RCC_CFGR_SW_1; //Переключаемся на работу от PLL // 10: PLL selected as system clock
//Ждем, пока переключимся
while(!(RCC->CFGR & RCC_CFGR_SWS_1));
//После того, как переключились на
//внешний источник такирования
//отключаем внутренний RC-генератор
//для экономии энергии
//RCC->CR &= ~RCC_CR_HSION; // При отключенном HSI Или его частоте выше 24 МГц не работает запись/стирание FLASH пользовательской памяти!!!
//Настройка и переклбючение сисемы
//на внешний кварцевый генератор
//и PLL запершилось успехом.
//Выходим
return 0;
}
void f103setC13led(unsigned char AledONOFF) {
if (AledONOFF) GPIOC->BSRR |= GPIO_BSRR_BR13; // PC13 LOW
else GPIOC->BSRR |= GPIO_BSRR_BS13; // PC13 HIGH
}
void f103initPC13led(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // GPIO port C
GPIOC->CRH &= ~GPIO_CRH_MODE13; // 00: Input mode (reset state)
GPIOC->CRH |= GPIO_CRH_MODE13_0; // 01: Output mode, max speed 10 MHz.
GPIOC->CRH &= ~GPIO_CRH_CNF13; // 00: General purpose output push-pull
f103setC13led(0);
}
extern "C" void TIM4_IRQHandler(void) {
TIM4->SR &= ~TIM_SR_UIF;
++msTicks;
}
void f103initTIM4(void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; // clock Timer4 ON
TIM4->SR = 0;
TIM4->CNT = 0;
TIM4->PSC = (SystemCoreClock / 2 / 1000000) - 1; // делитель
TIM4->ARR = 1999; // значение перезагрузки -> 1 msec
TIM4->DIER |= TIM_DIER_UIE;
NVIC_EnableIRQ (TIM4_IRQn);
TIM4->CR1 |= TIM_CR1_CEN; // включаем счётчик
TIM4->SR &= ~TIM_SR_UIF;
}
unsigned long millis(void) {
return msTicks;
}
void delay_ms(unsigned long period_ms) {
unsigned long startTimer = millis();
while ((millis() - startTimer) < period_ms);
}
Спойлер
/*
* f103rtc.h
*
* Created on: Aug 15, 2023
* Author: seleznev_a
*/
#ifndef F103RTC_H_
#define F103RTC_H_
#include <time.h>
void f103initRTC(void);
extern struct tm currentDateTime;
void getCurrentDateTime(struct tm * outTm);
void setCurrentDateTime(struct tm * outTm);
#endif /* F103RTC_H_ */
/*
* f103rtc.cpp
*
* Created on: Aug 15, 2023
* Author: seleznev_a
*
* +http://uc.org.ru/node/30?ysclid=lldq32k6ys131101849
*
*/
#include "f103rtc.h"
#include "stm32f10x.h"
#include "f103st7735.h"
#include <time.h>
struct tm currentDateTime;
void f103initRTC(void) {
if ((RCC->BDCR & RCC_BDCR_RTCEN) != RCC_BDCR_RTCEN) { //Проверка работы часов, если не включены, то инициализировать
RCC->APB1ENR |= RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN; //Включить тактирование PWR и Backup
PWR->CR |= PWR_CR_DBP; //Разрешить доступ к Backup области
RCC->BDCR |= RCC_BDCR_BDRST; //Сбросить Backup область
RCC->BDCR &= ~RCC_BDCR_BDRST;
RCC->BDCR |= RCC_BDCR_RTCSEL_LSE; //Выбрать LSE источник (кварц 32768)
RCC->BDCR |= RCC_BDCR_LSEON; //Включить LSE
while ((RCC->BDCR & RCC_BDCR_LSEON) != RCC_BDCR_LSEON){} //Дождаться включения
BKP->RTCCR |= 3; //калибровка RTC
while (!(RTC->CRL & RTC_CRL_RTOFF)); //проверить закончены ли изменения регистров RTC
RTC->CRL |= RTC_CRL_CNF; //Разрешить Запись в регистры RTC
RTC->PRLL = 0x7FFF; //Настроит делитель на 32768 (32767+1)
//BKP->RTCCR |= BKP_RTCCR_CCO; //Включение вывода Temper
RTC->CRL &= ~RTC_CRL_CNF; //Запретить запись в регистры RTC
RCC->BDCR |= RCC_BDCR_RTCEN; // и подать тактирование
while (!(RTC->CRL & RTC_CRL_RTOFF)); //Дождаться окончания записи
RTC->CRL &= (uint16_t)~RTC_CRL_RSF; //Синхронизировать RTC
while((RTC->CRL & RTC_CRL_RSF) != RTC_CRL_RSF){} //Дождаться синхронизации
PWR->CR &= ~PWR_CR_DBP; //запретить доступ к Backup области
}
}
unsigned long RTC_GetCounter(void) { //Получить значение счетчика
return (unsigned long)((RTC->CNTH << 16) | RTC->CNTL);
}
void RTC_SetCounter(unsigned long count) { //Записать новое значение счетчика
RCC->APB1ENR |= RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN; //включить тактирование PWR и Backup
PWR->CR |= PWR_CR_DBP; //разрешить доступ к Backup области
while (!(RTC->CRL & RTC_CRL_RTOFF)); //проверить закончены ли изменения регистров RTC
RTC->CRL |= RTC_CRL_CNF; //Разрешить Запись в регистры RTC
RTC->CNTH = count>>16; //записать новое значение счетного регистра
RTC->CNTL = count;
RTC->CRL &= ~RTC_CRL_CNF; //Запретить запись в регистры RTC
while (!(RTC->CRL & RTC_CRL_RTOFF)); //Дождаться окончания записи
PWR->CR &= ~PWR_CR_DBP; //запретить доступ к Backup области
}
void getCurrentDateTime(struct tm * outTm) {
time_t rawtime = (time_t)RTC_GetCounter();
localtime_r(&rawtime, outTm);
}
void setCurrentDateTime(struct tm * outTm) {
RTC_SetCounter((unsigned long)mktime(outTm));
}
/*
* f103flash.h
*
* Created on: 28 февр. 2023 г.
* Author: Andrey
*/
#ifndef F103FLASH_H_
#define F103FLASH_H_
#define NVIC_VectTab_FLASH ((unsigned long)0x08000000) // начало флэша
#define FLASH_PAGE_SIZE ((unsigned long)128) // CHF32F103C8T6 -> 128 // размер одной страницы // размер страницы памяти для большинства МК серии STM32F103 составляет 1Kb, за исключением микроконтроллеров линейки HD и CL (Connectivity Line), в которых она равна двум килобайтам
#define NUM_PAGE_EEPROM_BEGIN ((unsigned long)256) // с какой страницы памяти будем писать свои данные // 256*128=0x8000->0x8008000
#define FIRMWARE_PAGE_OFFSET ((unsigned long)NUM_PAGE_EEPROM_BEGIN*FLASH_PAGE_SIZE) // смещение в байтах, с которого будем писать свои данные
void FLASH_fill_page(uint32_t Value);
void FLASH_write_param(unsigned short numParam, uint32_t paramValue);
unsigned long FLASH_read_param(unsigned short numParam);
#endif /* F103FLASH_H_ */
/*
* f103flash.c
*
* Created on: 28 февр. 2023 г.
* Author: Andrey
*/
#include "stm32f10x.h"
#include "f103flash.h"
/*https://smartmode.info/stm32/13-stm32-flash*/
/*https://easystm32.ru/for-beginners/38-flash-stm32/*/
/*http://we.easyelectronics.ru/STM32/programmirovanie-flash.html?ysclid=leo3iva1x048263658*/
unsigned long FLASH_read(uint32_t address) {
return (*(__IO uint32_t*) address);
}
#define FLASH_KEY1 ((uint32_t)0x45670123)
#define FLASH_KEY2 ((uint32_t)0xCDEF89AB)
void FLASH_Unlock(void) {
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
}
void FLASH_Lock() {
FLASH->CR |= FLASH_CR_LOCK;
}
void FLASH_ErasePage(unsigned long inAdr) {
FLASH->CR |= FLASH_CR_PER; //Устанавливаем бит стирания одной страницы
FLASH->AR = inAdr; // Задаем её адрес
FLASH->CR |= FLASH_CR_STRT; // Запускаем стирание
while ((FLASH->SR & FLASH_SR_BSY) != 0 ); // Wait end of eraze
FLASH->CR &= ~FLASH_CR_PER; //Сбрасываем бит обратно
}
void FLASH_fill_page(uint32_t Value) {
uint32_t pageAdr = NVIC_VectTab_FLASH + FIRMWARE_PAGE_OFFSET; // Адрес страницы памяти
FLASH_Unlock(); // Разблокируем память для записи
FLASH_ErasePage(pageAdr); // Очистим страницу памяти
FLASH->CR |= FLASH_CR_PG; //Разрешаем программирование флеша
for(unsigned short i = 0; i < (FLASH_PAGE_SIZE/4); ++i) {
unsigned long inValue = Value;
while ((FLASH->SR & FLASH_SR_BSY) != 0 );
*(__IO uint16_t*)pageAdr = (uint16_t)inValue; //Пишем младшие 2 бата
while ((FLASH->SR & FLASH_SR_BSY) != 0 );
pageAdr += 2;
inValue>>=16;
*(__IO uint16_t*)pageAdr = (uint16_t)inValue; //Пишем старшие 2 байта
while ((FLASH->SR & FLASH_SR_BSY) != 0 );
pageAdr += 2;
}
FLASH->CR &= ~FLASH_CR_PG; //Запрещаем программирование флеша
FLASH_Lock();
}
void FLASH_write_param(unsigned short numParam, uint32_t paramValue) {
uint32_t pageAdr = NVIC_VectTab_FLASH + FIRMWARE_PAGE_OFFSET; // Адрес страницы памяти
numParam %= FLASH_PAGE_SIZE/4; // номер параметра не может превысить число 4х байтовых слов в странице
unsigned long dataPage[FLASH_PAGE_SIZE/4]; // место куда сохраним текущую страницу
for(unsigned short i = 0; i < (FLASH_PAGE_SIZE/4); ++i) dataPage[i] = FLASH_read(pageAdr + i * 4);
dataPage[numParam] = paramValue;
FLASH_Unlock(); // Разблокируем память для записи
FLASH_ErasePage(pageAdr); // Очистим страницу памяти
FLASH->CR |= FLASH_CR_PG; //Разрешаем программирование флеша
for(unsigned short i = 0; i < (FLASH_PAGE_SIZE/4); ++i) {
unsigned long inValue = dataPage[i];
while ((FLASH->SR & FLASH_SR_BSY) != 0 );
*(__IO uint16_t*)pageAdr = (uint16_t)inValue; //Пишем младшие 2 бата
while ((FLASH->SR & FLASH_SR_BSY) != 0 );
pageAdr += 2;
inValue>>=16;
*(__IO uint16_t*)pageAdr = (uint16_t)inValue; //Пишем старшие 2 байта
while ((FLASH->SR & FLASH_SR_BSY) != 0 );
pageAdr += 2;
}
FLASH->CR &= ~FLASH_CR_PG; //Запрещаем программирование флеша
FLASH_Lock();
}
unsigned long FLASH_read_param(unsigned short numParam) {
uint32_t pageAdr = NVIC_VectTab_FLASH + FIRMWARE_PAGE_OFFSET; // Адрес страницы памяти
numParam %= FLASH_PAGE_SIZE/4; // номер параметра не может превысить число 4х байтовых слов в странице
return FLASH_read(pageAdr + numParam * 4);
}
Спойлер
/*
* f103st7735.h
*
* Created on: 6 июн. 2023 г.
* Author: seleznev_a
*
* ST7735 pins -> STM32F103C8T6 pins
* 1 GND -> GND
* 2 VCC -> 3.3 V
* 3 SCK -> PA5 SCK SPI1
* 4 SDA -> PA7 MOSI SPI1
* 5 RES -> PB1
* 6 RS(A0) -> PB10
* 7 CS -> PB11
* 8 LEDA -> 3.3 V
*
*/
#ifndef F103ST7735_H_
#define F103ST7735_H_
/*
* https://count-zero.ru/2022/display/#10
*/
#define st7735sizeX 128
#define st7735sizeY 160
// some flags for initR() :(
#define INITR_GREENTAB 0x00
#define INITR_REDTAB 0x01
#define INITR_BLACKTAB 0x02
#define INITR_18GREENTAB INITR_GREENTAB
#define INITR_18REDTAB INITR_REDTAB
#define INITR_18BLACKTAB INITR_BLACKTAB
#define INITR_144GREENTAB 0x01
#define INITR_MINI160x80 0x04
#define INITR_HALLOWING 0x05
// Some register settings
#define ST7735_MADCTL_BGR 0x08
#define ST7735_MADCTL_MH 0x04
#define ST7735_FRMCTR1 0xB1
#define ST7735_FRMCTR2 0xB2
#define ST7735_FRMCTR3 0xB3
#define ST7735_INVCTR 0xB4
#define ST7735_DISSET5 0xB6
#define ST7735_PWCTR1 0xC0
#define ST7735_PWCTR2 0xC1
#define ST7735_PWCTR3 0xC2
#define ST7735_PWCTR4 0xC3
#define ST7735_PWCTR5 0xC4
#define ST7735_VMCTR1 0xC5
#define ST7735_PWCTR6 0xFC
#define ST7735_GMCTRP1 0xE0
#define ST7735_GMCTRN1 0xE1
// Some ready-made 16-bit ('565') color settings:
#define ST7735_BLACK ST77XX_BLACK
#define ST7735_WHITE ST77XX_WHITE
#define ST7735_RED ST77XX_RED
#define ST7735_GREEN ST77XX_GREEN
#define ST7735_BLUE ST77XX_BLUE
#define ST7735_CYAN ST77XX_CYAN
#define ST7735_MAGENTA ST77XX_MAGENTA
#define ST7735_YELLOW ST77XX_YELLOW
#define ST7735_ORANGE ST77XX_ORANGE
#define ST_CMD_DELAY 0x80 // special signifier for command lists
#define ST77XX_NOP 0x00
#define ST77XX_SWRESET 0x01
#define ST77XX_RDDID 0x04
#define ST77XX_RDDST 0x09
#define ST77XX_SLPIN 0x10
#define ST77XX_SLPOUT 0x11
#define ST77XX_PTLON 0x12
#define ST77XX_NORON 0x13
#define ST77XX_INVOFF 0x20
#define ST77XX_INVON 0x21
#define ST77XX_DISPOFF 0x28
#define ST77XX_DISPON 0x29
#define ST77XX_CASET 0x2A
#define ST77XX_RASET 0x2B
#define ST77XX_RAMWR 0x2C
#define ST77XX_RAMRD 0x2E
#define ST77XX_PTLAR 0x30
#define ST77XX_TEOFF 0x34
#define ST77XX_TEON 0x35
#define ST77XX_MADCTL 0x36
#define ST77XX_COLMOD 0x3A
#define ST77XX_MADCTL_MY 0x80
#define ST77XX_MADCTL_MX 0x40
#define ST77XX_MADCTL_MV 0x20
#define ST77XX_MADCTL_ML 0x10
#define ST77XX_MADCTL_RGB 0x00
#define ST77XX_RDID1 0xDA
#define ST77XX_RDID2 0xDB
#define ST77XX_RDID3 0xDC
#define ST77XX_RDID4 0xDD
// Some ready-made 16-bit ('565') color settings:
#define ST77XX_BLACK 0x0000
#define ST77XX_WHITE 0xFFFF
#define ST77XX_RED 0xF800
#define ST77XX_GREEN 0x07E0
#define ST77XX_BLUE 0x001F
#define ST77XX_CYAN 0x07FF
#define ST77XX_MAGENTA 0xF81F
#define ST77XX_YELLOW 0xFFE0
#define ST77XX_ORANGE 0xFC00
void f103st7735init(void);
void f103st7735fillScreen(uint16_t value);
void f103st7735fillRect(uint16_t value, unsigned short x0, unsigned short y0, unsigned short x1, unsigned short y1);
void f103st7735showRect(unsigned short * dataPoint, unsigned short x0, unsigned short y0, unsigned short x1, unsigned short y1);
void f103st7735printOneChar(unsigned char inChar, unsigned short colChar, unsigned short colBackground, unsigned char sizeChar, unsigned char xChar, unsigned char yChar);
void f103st7735printString(const unsigned char * inStr, unsigned short colChar, unsigned short colBackground, unsigned char sizeChar, unsigned char xChar, unsigned char yChar);
void f103st7735printUInt(unsigned long inVal, unsigned short colChar, unsigned short colBackground, unsigned char sizeChar, unsigned char xChar, unsigned char yChar);
void f103st7735printHEX(unsigned long inVal, unsigned short colChar, unsigned short colBackground, unsigned char sizeChar, unsigned char xChar, unsigned char yChar);
void f103st7735printText(const unsigned char * inText);
#define fontWsize0 8
#define fontHsize0 8
#define fontWsize1 (fontWsize0+fontWsize0/2) // 12
#define fontHsize1 (fontHsize0*2) // 16
#define fontWsize2 (fontWsize1+fontWsize1/2) // 18
#define fontHsize2 (fontHsize1+fontHsize0) // 24
#define fontWsize3 (fontWsize2+fontWsize1/2) //24
#define fontHsize3 (fontHsize2+fontHsize0) // 32
extern unsigned char fontSizeX[4];
extern unsigned char fontSizeY[4];
#endif /* F103ST7735_H_ */
/*
* f103st7735.c
*
* Created on: 6 июн. 2023 г.
* Author: seleznev_a
*
* ST7735 pins -> STM32F103C8T6 pins
* 1 GND -> GND
* 2 VCC -> 3.3 V
* 3 SCK -> PA5 SCK SPI1
* 4 SDA -> PA7 MOSI SPI1
* 5 RES -> PB1
* 6 RS(A0) -> PB10
* 7 CS -> PB11
* 8 LEDA -> 3.3 V
*
*/
#include "stm32f10x.h"
#include "f103c8t6.h"
#include "f103st7735.h"
#include <stdlib.h>
#include <string.h>
/*
* FR08x08.c
*
* Created on: 25 нояб. 2021 г.
* Author: http://forum.easyelectronics.ru/viewtopic.php?f=9&t=18271
*/
const unsigned char frus08x08[256][8] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E},
{0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E},
{0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00},
{0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00},
{0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x7C, 0x38, 0x7C},
{0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C},
{0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00},
{0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF},
{0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00},
{0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF},
{0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78},
{0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18},
{0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0},
{0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0},
{0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99},
{0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00},
{0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00},
{0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18},
{0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00},
{0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00},
{0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78},
{0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00},
{0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF},
{0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00},
{0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00},
{0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00},
{0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00},
{0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00},
{0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00},
{0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00},
{0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x60, 0xF0, 0xF0, 0x60, 0x60, 0x00, 0x60, 0x00},
{0xD8, 0xD8, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x6C, 0xFE, 0x6C, 0x6C, 0xFE, 0x6C, 0x00, 0x00},
{0x18, 0x7E, 0xC0, 0x7C, 0x06, 0xFC, 0x18, 0x00},
{0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00},
{0x38, 0x6C, 0x38, 0x6E, 0xDC, 0xCC, 0x76, 0x00},
{0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x30, 0x60, 0xC0, 0xC0, 0xC0, 0x60, 0x30, 0x00},
{0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00},
{0x00, 0xCC, 0x78, 0xFC, 0x78, 0xCC, 0x00, 0x00},
{0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60},
{0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00},
{0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00},
{0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00},
{0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00},
{0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00},
{0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00},
{0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00},
{0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00},
{0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00},
{0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00},
{0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00},
{0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00},
{0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00},
{0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60},
{0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00},
{0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00},
{0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00},
{0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00},
{0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00},
{0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00},
{0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00},
{0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00},
{0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00},
{0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00},
{0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00},
{0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00},
{0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00},
{0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00},
{0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00},
{0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00},
{0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00},
{0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00},
{0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00},
{0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00},
{0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00},
{0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00},
{0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00},
{0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00},
{0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00},
{0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00},
{0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00},
{0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00},
{0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00},
{0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00},
{0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00},
{0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00},
{0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00},
{0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00},
{0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF},
{0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00},
{0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00},
{0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00},
{0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00},
{0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00},
{0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00},
{0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8},
{0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00},
{0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},
{0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78},
{0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00},
{0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00},
{0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00},
{0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00},
{0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00},
{0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0},
{0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E},
{0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00},
{0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00},
{0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00},
{0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00},
{0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00},
{0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00},
{0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00},
{0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8},
{0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00},
{0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00},
{0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00},
{0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00},
{0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00},
{0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00},
{0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00},
{0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00},
{0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00},
{0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6},
{0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00},
{0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00},
{0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00},
{0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00},
{0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00},
{0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00},
{0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00},
{0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00},
{0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00},
{0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00},
{0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00},
{0x7E, 0x81, 0xA5, 0x81, 0xA5, 0x99, 0x81, 0x7E},
{0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00},
{0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00},
{0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00},
{0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00},
{0x00, 0x38, 0x7C, 0x7C, 0x7C, 0x38, 0x00, 0x00},
{0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03},
{0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00},
{0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00},
{0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03},
{0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00},
{0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00},
{0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00},
{0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00},
{0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00},
{0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00},
{0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00},
{0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00},
{0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00},
{0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00},
{0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6},
{0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00},
{0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00},
{0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00},
{0x7E, 0x60, 0x60, 0x7E, 0x60, 0x60, 0x7E, 0x00},
{0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00},
{0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00},
{0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00},
{0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00},
{0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00},
{0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00},
{0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00},
{0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44},
{0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA},
{0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77},
{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
{0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18},
{0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18},
{0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36},
{0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36},
{0x24, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00},
{0x8E, 0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88, 0x00},
{0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36},
{0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36},
{0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00},
{0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00},
{0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18},
{0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00},
{0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00},
{0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00},
{0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00},
{0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6},
{0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00},
{0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00},
{0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00},
{0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00},
{0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00},
{0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00},
{0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00},
{0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00},
{0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00},
{0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00},
{0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00},
{0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00},
{0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00},
{0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00},
{0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00},
{0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00},
{0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00},
{0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03},
{0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00},
{0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00},
{0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03},
{0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00},
{0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00},
{0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00},
{0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00},
{0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00},
{0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00},
{0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00},
{0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00},
{0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00},
{0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00},
{0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6},
{0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00},
{0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00},
{0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00},
{0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00},
{0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00},
{0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00},
{0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00},
{0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00},
{0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00},
{0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00},
{0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00},
{0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00},
{0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00},
{0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00},
{0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x3C, 0x00},
{0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00},
{0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00},
{0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03},
{0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00},
{0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00},
{0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03},
{0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00},
{0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00},
{0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00},
{0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00},
{0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00},
{0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00}};
/************************ (C) COPYRIGHT andycat2013@yandex.ru *****END OF FILE****/
unsigned char fontSizeX[4] = {fontWsize0, fontWsize1, fontWsize2, fontWsize3};
unsigned char fontSizeY[4] = {fontHsize0, fontHsize1, fontHsize2, fontHsize3};
void tftCSenable(void) {GPIOB->BSRR |= GPIO_BSRR_BR11;} // PB11 LOW // говорим slave устройству что начинаем работать
void tftCSdisable(void) {GPIOB->BSRR |= GPIO_BSRR_BS11;} // PB11 HIGH // закончили передачу SPI устройству
unsigned char nextXchar = 0;
unsigned char nextYchar = 0;
unsigned short nextColor = ST77XX_WHITE;
unsigned short nextBack = ST77XX_BLACK;
unsigned char nextSize = 0;
/*
* http://dimoon.ru/obuchalka/stm32f1/programmirovanie-stm32-chast-6-spi.html?ysclid=lik3u6uz6b459087878
*/
void initSPI(void) {
//Включаем тактирование SPI1 и GPIOA
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN | RCC_APB2ENR_IOPAEN;
//Для начала сбрасываем все конфигурационные биты в нули
GPIOA->CRL &= ~(GPIO_CRL_CNF5 | GPIO_CRL_MODE5 | GPIO_CRL_CNF6 | GPIO_CRL_MODE6 | GPIO_CRL_CNF7 | GPIO_CRL_MODE7);
//Настроаиваем
//SCK: MODE5 = 0x03 (11b); CNF5 = 0x02 (10b)
GPIOA->CRL |= GPIO_CRL_CNF5_1 | GPIO_CRL_MODE5;
//MISO: MODE6 = 0x00 (00b); CNF6 = 0x01 (01b)
GPIOA->CRL |= GPIO_CRL_CNF6_0;
//MOSI: MODE7 = 0x03 (11b); CNF7 = 0x02 (10b)
GPIOA->CRL |= GPIO_CRL_CNF7_1 | GPIO_CRL_MODE7;
// Вывод NSS не трогаем, так как не будем его использовать. Далее, настройка SPI:
SPI1->CR1 &= ~SPI_CR1_DFF; //Размер кадра 8 бит
SPI1->CR1 &= ~SPI_CR1_LSBFIRST; //MSB first
SPI1->CR1 |= SPI_CR1_SSM; //Программное управление SS
SPI1->CR1 |= SPI_CR1_SSI; //SS в высоком состоянии
SPI1->CR1 &= ~SPI_CR1_BR; // reset // 0x00 Скорость передачи: F_PCLK/2
//SPI1->CR1 |= SPI_CR1_BR_2; // 0x04 Скорость передачи: F_PCLK/32
SPI1->CR1 |= SPI_CR1_MSTR; //Режим Master (ведущий)
SPI1->CR1 &= ~SPI_CR1_CPOL; //Режим работы SPI: 0
SPI1->CR1 &= ~SPI_CR1_CPHA; //Режим работы SPI: 0
SPI1->CR1 |= SPI_CR1_SPE; //Включаем SPI
}
void f1tftSendCommand(unsigned char cmd) {
GPIOB->BSRR |= GPIO_BSRR_BR10; // PB10 LOW
SPI1->DR = cmd;
while (!(SPI1->SR & SPI_SR_TXE) || (SPI1->SR & SPI_SR_BSY));
}
void f1tftWriteData(unsigned char * buff, unsigned short buff_size) {
GPIOB->BSRR |= GPIO_BSRR_BS10; // PB10 HIGH
for(unsigned short i = 0; i < buff_size; ++i) {
while (!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = *(buff+i);
}
while (!(SPI1->SR & SPI_SR_TXE) || (SPI1->SR & SPI_SR_BSY));
}
void f1tftSetAddrWindow(unsigned short x0, unsigned short y0, unsigned short x1, unsigned short y1) {
static unsigned char pos_data[4];
// column address set
f1tftSendCommand(ST77XX_CASET); // CASET
pos_data[0] = (x0 & 0xFF00) >> 8;
pos_data[1] = x0 & 0x00FF;
pos_data[2] = (x1 & 0xFF00) >> 8;
pos_data[3] = x1 & 0x00FF;
f1tftWriteData((unsigned char *)&pos_data, 4);
// row address set
f1tftSendCommand(ST77XX_RASET); // RASET
pos_data[0] = (y0 & 0xFF00) >> 8;
pos_data[1] = y0 & 0x00FF;
pos_data[2] = (y1 & 0xFF00) >> 8;
pos_data[3] = y1 & 0x00FF;
f1tftWriteData((unsigned char *)&pos_data, 4);
// write to RAM
f1tftSendCommand(ST77XX_RAMWR); // RAMWR
}
void f103st7735fillRect(uint16_t value, unsigned short x0, unsigned short y0, unsigned short x1, unsigned short y1) {
tftCSenable(); // chip select on
f1tftSetAddrWindow(x0, y0, x1, y1);
GPIOB->BSRR |= GPIO_BSRR_BS10; // PB10 HIGH
// 8 bit transfer mode
/*uint8_t c1=value>>8;
uint8_t c2=(uint8_t)value;
for (uint16_t i=0; i < (uint16_t)((x1-x0+1)*(y1-y0+1)); i++) {
while (!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = c1;
while (!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = c2;
}*/
// 16 bit transfer mode
SPI1->CR1 &= ~SPI_CR1_SPE;
SPI1->CR1 |= SPI_CR1_DFF;
SPI1->CR1 |= SPI_CR1_SPE;
for (uint16_t i=0; i < (uint16_t)((x1-x0+1)*(y1-y0+1)); i++) {
while (!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = value;
}
// wait end transfer
while (!(SPI1->SR & SPI_SR_TXE) || (SPI1->SR & SPI_SR_BSY));
// return 8bit transfer mode
SPI1->CR1 &= ~SPI_CR1_SPE;
SPI1->CR1 &= ~SPI_CR1_DFF;
SPI1->CR1 |= SPI_CR1_SPE;
tftCSdisable(); // chip select off
}
void f103st7735showRect(unsigned short * dataPoint, unsigned short x0, unsigned short y0, unsigned short x1, unsigned short y1) {
tftCSenable(); // chip select on
f1tftSetAddrWindow(x0, y0, x1, y1);
GPIOB->BSRR |= GPIO_BSRR_BS10; // PB10 HIGH
// 16 bit transfer mode
SPI1->CR1 &= ~SPI_CR1_SPE;
SPI1->CR1 |= SPI_CR1_DFF;
SPI1->CR1 |= SPI_CR1_SPE;
for (uint16_t i=0; i < (uint16_t)((x1-x0+1)*(y1-y0+1)); i++) {
while (!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = *(dataPoint+i);
}
// wait end transfer
while (!(SPI1->SR & SPI_SR_TXE) || (SPI1->SR & SPI_SR_BSY));
// return 8bit transfer mode
SPI1->CR1 &= ~SPI_CR1_SPE;
SPI1->CR1 &= ~SPI_CR1_DFF;
SPI1->CR1 |= SPI_CR1_SPE;
tftCSdisable(); // chip select off
}
void f103st7735fillScreen(uint16_t value) {
f103st7735fillRect(value, 0, 0, st7735sizeX-1, st7735sizeY-1);
}
void initGpio(void) {
// PB1 - RESET ST7735
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // GPIO port B
GPIOB->CRL &= ~GPIO_CRL_MODE1; // 00: Input mode (reset state)
GPIOB->CRL |= GPIO_CRL_MODE1_0; // 01: Output mode, max speed 10 MHz.
GPIOB->CRL &= ~GPIO_CRL_CNF1; // 00: General purpose output push-pull
// PB10 - RS(A0) ST7735 cmd/data select
GPIOB->CRH &= ~GPIO_CRH_MODE10; // 00: Input mode (reset state)
GPIOB->CRH |= GPIO_CRH_MODE10_0; // 01: Output mode, max speed 10 MHz.
GPIOB->CRH &= ~GPIO_CRH_CNF10; // 00: General purpose output push-pull
// PB11 - CS ST7735
GPIOB->CRH &= ~GPIO_CRH_MODE11; // 00: Input mode (reset state)
GPIOB->CRH |= GPIO_CRH_MODE11_0; // 01: Output mode, max speed 10 MHz.
GPIOB->CRH &= ~GPIO_CRH_CNF11; // 00: General purpose output push-pull
}
void f103st7735init(void) {
initGpio();
tftCSdisable(); // chip select off
initSPI();
// hardware reset
GPIOB->BSRR |= GPIO_BSRR_BR1; // PB1 LOW
delay_ms(10);
GPIOB->BSRR |= GPIO_BSRR_BS1; // PB1 HIGH
delay_ms(10);
// init routine
tftCSenable();
unsigned char dataSend[16];
f1tftSendCommand(ST77XX_SWRESET); // 0x01
delay_ms(150);
f1tftSendCommand(ST77XX_SLPOUT); // 0x11
delay_ms(150);
f1tftSendCommand(ST7735_FRMCTR1); // 0xB1
dataSend[0] = 0x01;
dataSend[1] = 0x2C;
dataSend[2] = 0x2D;
f1tftWriteData((unsigned char *)&dataSend, 3);
f1tftSendCommand(ST7735_FRMCTR2);
dataSend[0] = 0x01;
dataSend[1] = 0x2C;
dataSend[2] = 0x2D;
f1tftWriteData((unsigned char *)&dataSend, 3);
f1tftSendCommand(ST7735_FRMCTR3);
dataSend[0] = 0x01;
dataSend[1] = 0x2C;
dataSend[2] = 0x2D;
dataSend[3] = 0x01;
dataSend[4] = 0x2C;
dataSend[5] = 0x2D;
f1tftWriteData((unsigned char *)&dataSend, 6);
f1tftSendCommand(ST7735_INVCTR);
dataSend[0] = 0x07;
f1tftWriteData((unsigned char *)&dataSend, 1);
f1tftSendCommand(ST7735_PWCTR1);
dataSend[0] = 0xA2;
dataSend[1] = 0x02;
dataSend[2] = 0x84;
f1tftWriteData((unsigned char *)&dataSend, 3);
f1tftSendCommand(ST7735_PWCTR2);
dataSend[0] = 0xC5;
f1tftWriteData((unsigned char *)&dataSend, 1);
f1tftSendCommand(ST7735_PWCTR3);
dataSend[0] = 0x0A;
dataSend[1] = 0x00;
f1tftWriteData((unsigned char *)&dataSend, 2);
f1tftSendCommand(ST7735_PWCTR4);
dataSend[0] = 0x8A;
dataSend[1] = 0x2A;
f1tftWriteData((unsigned char *)&dataSend, 2);
f1tftSendCommand(ST7735_PWCTR5);
dataSend[0] = 0x8A;
dataSend[1] = 0xEE;
f1tftWriteData((unsigned char *)&dataSend, 2);
f1tftSendCommand(ST7735_VMCTR1);
dataSend[0] = 0x0E;
f1tftWriteData((unsigned char *)&dataSend, 1);
f1tftSendCommand(ST77XX_INVOFF);
f1tftSendCommand(ST77XX_MADCTL);
dataSend[0] = 0x00; // rotation 180
//dataSend[0] = 0xC0; // original string
f1tftWriteData((unsigned char *)&dataSend, 1);
f1tftSendCommand(ST77XX_COLMOD);
dataSend[0] = 0x05;
f1tftWriteData((unsigned char *)&dataSend, 1);
f1tftSendCommand(ST7735_GMCTRP1);
dataSend[0] = 0x02;
dataSend[1] = 0x1C;
dataSend[2] = 0x07;
dataSend[3] = 0x12;
dataSend[4] = 0x37;
dataSend[5] = 0x32;
dataSend[6] = 0x29;
dataSend[7] = 0x2D;
dataSend[8] = 0x29;
dataSend[9] = 0x25;
dataSend[10] = 0x2B;
dataSend[11] = 0x39;
dataSend[12] = 0x00;
dataSend[13] = 0x01;
dataSend[14] = 0x03;
dataSend[15] = 0x10;
f1tftWriteData((unsigned char *)&dataSend, 16);
f1tftSendCommand(ST7735_GMCTRN1);
dataSend[0] = 0x03;
dataSend[1] = 0x1D;
dataSend[2] = 0x07;
dataSend[3] = 0x06;
dataSend[4] = 0x2E;
dataSend[5] = 0x2C;
dataSend[6] = 0x29;
dataSend[7] = 0x2D;
dataSend[8] = 0x2E;
dataSend[9] = 0x2E;
dataSend[10] = 0x37;
dataSend[11] = 0x3F;
dataSend[12] = 0x00;
dataSend[13] = 0x00;
dataSend[14] = 0x02;
dataSend[15] = 0x10;
f1tftWriteData((unsigned char *)&dataSend, 16);
f1tftSendCommand(ST77XX_NORON);
delay_ms(10);
f1tftSendCommand(ST77XX_DISPON);
delay_ms(100);
tftCSdisable();
}
void f103st7735printOneChar(unsigned char inChar, unsigned short colChar, unsigned short colBackground, unsigned char sizeChar, unsigned char xChar, unsigned char yChar) {
unsigned char inSize = sizeChar & 0x03; // size 0...3
unsigned short oneCharBuf[fontWsize3 * fontHsize3];
unsigned short locPosInBuf = 0; // абсолютная позиция в буфере где мы формируем картинку
unsigned short outColor;
for(unsigned char lineY = 0; lineY < fontSizeY[0]; ++lineY) { // цикл по строкам шрифта
for(unsigned char bitY = fontSizeX[0]; bitY > 0; --bitY) { // обратный цикл по горизонтальным битам строки шрифта
if (bitRead(frus08x08[inChar][lineY], (bitY-1))) outColor = colChar; else outColor = colBackground;
if (inSize == 0) { // самый маленький шрифт 8 на 8
oneCharBuf[locPosInBuf] = outColor;
++locPosInBuf;
} else { // необходимо масштабирование
unsigned char countHpoints; // количество точек по горизонтали
switch (inSize) {
case 1: {
if (bitRead(bitY, 0)) countHpoints = 1; else countHpoints = 2;
break;
}
case 2: {
if ((bitY == 7) || (bitY == 3)) countHpoints = 3; else countHpoints = 2;
break;
}
default: { // 3 size
countHpoints = 3;
}
}
for (unsigned char v = 0; v < countHpoints; ++v) { // сколько точек надо нарисовать в строке
for (unsigned char h = 0; h < (inSize+1); ++h) { // дублируем вниз точку на нужное количество увеличения шрифта
oneCharBuf[locPosInBuf + h * fontSizeX[inSize]] = outColor;
}
++locPosInBuf;
}
}
}
locPosInBuf += fontSizeX[inSize] * inSize;
}
f103st7735showRect((unsigned short *)&oneCharBuf, xChar, yChar, xChar+fontSizeX[inSize]-1, yChar+fontSizeY[inSize]-1);
nextSize = inSize;
nextColor = colChar;
nextBack = colBackground;
nextXchar = xChar+fontSizeX[inSize];
nextYchar = yChar;
if (nextXchar >= st7735sizeX) {
nextXchar = 0;
nextYchar += fontSizeY[inSize];
if (nextYchar >= st7735sizeY) nextYchar = 0;
}
}
void f103st7735printString(const unsigned char * inStr, unsigned short colChar, unsigned short colBackground, unsigned char sizeChar, unsigned char xChar, unsigned char yChar) {
unsigned char inSize = sizeChar & 0x03; // size 0...3
unsigned char posStr = 0;
unsigned char inChar;
while ((inChar = *(inStr + posStr)) > 0) {
f103st7735printOneChar(inChar, colChar, colBackground, inSize, xChar + fontSizeX[inSize] * posStr, yChar);
++posStr;
}
}
void f103st7735printUInt(unsigned long inVal, unsigned short colChar, unsigned short colBackground, unsigned char sizeChar, unsigned char xChar, unsigned char yChar) {
unsigned char outStr[32];
utoa(inVal, (char *)outStr, 10);
f103st7735printString((unsigned char *)&outStr, colChar, colBackground, sizeChar, xChar, yChar);
}
void f103st7735printHEX(unsigned long inVal, unsigned short colChar, unsigned short colBackground, unsigned char sizeChar, unsigned char xChar, unsigned char yChar) {
unsigned char outStr[32];
utoa(inVal, (char *)outStr, 16);
f103st7735printString((unsigned char *)&outStr, colChar, colBackground, sizeChar, xChar, yChar);
}
void f103st7735printText(const unsigned char * inText) {
unsigned char posStr = 0;
unsigned char inChar;
while ((inChar = *(inText + posStr)) > 0) {
f103st7735printOneChar(inChar, nextColor, nextBack, nextSize, nextXchar, nextYchar);
++posStr;
}
}
Спойлер
/*
* pumper.h
*
* Created on: 13 июн. 2023 г.
* Author: seleznev_a
*
* PB14 - key 1
* PB15 - key 2
* PA11 - relay1
* PA12 - relay2
*
*/
#ifndef PUMPER_H_
#define PUMPER_H_
class ifaceItem { // интерфейс элемента внутри группы, например текущий день недели, или часы полива
private:
protected:
ifaceItem * parentItem;
ifaceItem * childItems[32];
unsigned char noEditItem = 0;
unsigned short currentValue = 0;
unsigned short minValue = 0;
unsigned short maxValue = 1;
unsigned short countChildren = 0;
unsigned long blinkTimer;
unsigned char modeShow = 0; // режим отображения 0-показывается 1+2-моргает
public:
unsigned short posX, posY, sizeX, sizeY, backgroundColor = 0x0000;
void addChild(ifaceItem * newChild) {this->childItems[this->countChildren] = newChild; ++this->countChildren;}
ifaceItem * getChild(unsigned char posChild) {return this->childItems[posChild];}
unsigned char getCountChildren(void) {return this->countChildren;}
void setNoEditedItem(void) {this->noEditItem = 1;}
unsigned char getNoEditedItem(void) {return this->noEditItem;}
unsigned char getValue(void) {return this->currentValue;}
virtual void showItem(void){}; // отобразить элемент
virtual void changeValue() {++this->currentValue; if (this->currentValue > this->maxValue) this->currentValue = this->minValue;} // изменить значение элемента
virtual void blinkItem(); // мигает позиция
virtual void clearItem() {}; // очищается позиция
virtual void setValue(unsigned short inValue) {this->currentValue = inValue;}
};
class baseUnit:public ifaceItem { // группа
private:
protected:
unsigned short iX, iY, itemColor = 0x0000;
unsigned char fontSize;
public:
baseUnit(ifaceItem * itemParent = nullptr, unsigned short pX = 0, unsigned short pY = 0, unsigned short sX = 32, unsigned short sY = 64, unsigned short bColor = 0x00);
virtual void showItem(void) override;
virtual void clearItem(void) override;
};
class baseOneCharValue:public baseUnit { // элемент - один символ
private:
protected:
public:
baseOneCharValue(ifaceItem * itemParent = nullptr, unsigned short pX = 0, unsigned short pY = 0, unsigned char iSize = 0, unsigned short iColor = 0x00, unsigned short mV = 0, unsigned short xV = 1);
virtual void showItem(void) override;
};
class baseNum2digValue:public baseOneCharValue { // элемент - число из двух цифр
private:
protected:
public:
baseNum2digValue(ifaceItem * itemParent = nullptr, unsigned short pX = 0, unsigned short pY = 0, unsigned char iSize = 0, unsigned short iColor = 0x00, unsigned short mV = 0, unsigned short xV = 1):
baseOneCharValue(itemParent, pX, pY, iSize, iColor, mV, xV) {};
virtual void showItem(void) override;
virtual void clearItem(void) override;
};
class baseDictWDayValue:public baseOneCharValue { // элемент - техт из справочника день недели
private:
protected:
unsigned char * textWDay[9] = {(unsigned char *)"Sunday", (unsigned char *)"Monday", (unsigned char *)"Tuesday", (unsigned char *)"Wednesday", (unsigned char *)"Thursday", (unsigned char *)"Friday", (unsigned char *)"Saturday", (unsigned char *)" ", (unsigned char *)"-no set- "};
public:
baseDictWDayValue(ifaceItem * itemParent = nullptr, unsigned short pX = 0, unsigned short pY = 0, unsigned char iSize = 0, unsigned short iColor = 0x00, unsigned short mV = 0, unsigned short xV = 1):
baseOneCharValue(itemParent, pX, pY, iSize, iColor, mV, xV) {};
virtual void showItem(void) override;
virtual void clearItem(void) override;
};
class baseDictMonthValue:public baseOneCharValue { // элемент - техт из справочника месяцы
private:
unsigned char * textMonths[14] = {(unsigned char *)"January ", (unsigned char *)"February ", (unsigned char *)"March ", (unsigned char *)"April ", (unsigned char *)"May ", (unsigned char *)"June ", (unsigned char *)"July ", (unsigned char *)"August ", (unsigned char *)"September", (unsigned char *)"October ", (unsigned char *)"November ", (unsigned char *)"December ", (unsigned char *)" ", (unsigned char *)"-no set- "};
protected:
public:
baseDictMonthValue(ifaceItem * itemParent = nullptr, unsigned short pX = 0, unsigned short pY = 0, unsigned char iSize = 0, unsigned short iColor = 0x00, unsigned short mV = 0, unsigned short xV = 1):
baseOneCharValue(itemParent, pX, pY, iSize, iColor, mV, xV) {};
virtual void showItem(void) override;
virtual void clearItem(void) override;
};
class baseDictPumpDaysValue:public baseDictWDayValue { // элемент - по два символа из дней недели - дни полива, value подсвеченный выбранный день
private:
unsigned char weekDay = 0; // день недели 0...6
unsigned short colorDay = 0x5555; // цвет выбранного дня
unsigned short colorLabel = 0xAAAA; // цвет фона выбранного дня
protected:
public:
baseDictPumpDaysValue(ifaceItem * itemParent = nullptr, unsigned short pX = 0, unsigned short pY = 0, unsigned char iSize = 0, unsigned short iColor = 0x00, unsigned char inDay = 0, unsigned short daColor = 0xAAAA, unsigned short lbColor = 0x5555);
virtual void showItem(void) override;
virtual void clearItem(void) override;
};
class baseNum2digText:public baseNum2digValue { // элемент - число из двух цифр + текст
private:
unsigned char * endText;
protected:
public:
baseNum2digText(ifaceItem * itemParent = nullptr, unsigned short pX = 0, unsigned short pY = 0, unsigned char iSize = 0, unsigned short iColor = 0x00, unsigned char * inText = nullptr, unsigned short mV = 0, unsigned short xV = 1);
virtual void showItem(void) override;
virtual void clearItem(void) override;
};
void loopPumper(void);
void f1InitPumpGpio(void);
void initPumper(void);
#define blinkPeriod 300UL
#define keys_short_press 50UL
#define keys_long_press 2000UL
#define numParamPump1Days 1
#define numParamPump2Days 3
#define numParamTimePump 5
union t_PumpTimePart {
struct {
unsigned char pumpTime[2];
unsigned char pumpPeriod;
};
unsigned long PartPumpTime;
};
union t_PumpDaysPart {
struct {
unsigned char pumpDays[4];
};
unsigned long PartPumpDays;
};
#define currentWDayColor ST7735_MAGENTA
#define currentWDayBack ST7735_BLACK
#define currentWDaySize 0
#define currentDateColor ST7735_GREEN
#define currentDateSize 0
#define currentTimeColor ST7735_YELLOW
#define currentTimeSize 2
#define currentTimeStartX 18
#define pumpBackground ST7735_WHITE
#define pumpDaysColor ST7735_BLACK
#define pumpSelectedDay ST7735_YELLOW
#define pumpSelectedBack ST7735_BLUE
#define pumpDaysSize 0
#define pumpTimeColor ST7735_GREEN
#define pumpTimeSize 2
#define pumpPeriodColor ST7735_ORANGE
#define pumpPeriodBack ST7735_BLUE
#define pumpPeriodSize 2
#endif /* PUMPER_H_ */
/*
* pumper.c
*
* Created on: 13 июн. 2023 г.
* Author: seleznev_a
*/
#include "pumper.h"
#include "stm32f10x.h"
#include <time.h>
#include "f103c8t6.h"
#include "f103st7735.h"
#include "stdlib.h"
#include "f103flash.h"
#include "f103rtc.h"
t_PumpDaysPart saveParamDays1partPump = {0, 0, 1, 0};
t_PumpDaysPart saveParamDays2partPump = {1, 0, 0, 0xFF};
t_PumpTimePart saveParamTime3partPump = {20, 18, 5};
unsigned char devModes = 0; // 1-settings mode
unsigned long unusedDevice; // таймер бездействия пользователя
baseUnit iMainDisplay;
//--current date time
baseUnit iCurrentDateTime((ifaceItem *)&iMainDisplay, 0, 0,
st7735sizeX, fontSizeY[currentWDaySize]+fontSizeY[currentDateSize]+fontSizeY[currentTimeSize], currentWDayBack);
baseDictWDayValue iDayOfWeekCurrentDateTime((ifaceItem *)&iCurrentDateTime, 0, 0,
currentWDaySize, currentWDayColor, 0, 6);
baseNum2digValue iHourTimeCurrentDateTime((ifaceItem *)&iCurrentDateTime, currentTimeStartX,
fontSizeY[currentWDaySize], currentTimeSize, currentTimeColor, 0, 23);
baseOneCharValue iPointTimeCurrentDateTime((ifaceItem *)&iCurrentDateTime, currentTimeStartX + fontSizeX[currentTimeSize] * 2, fontSizeY[currentWDaySize],
currentTimeSize, currentTimeColor);
baseNum2digValue iMinTimeCurrentDateTime((ifaceItem *)&iCurrentDateTime, currentTimeStartX + fontSizeX[currentTimeSize] * 3, fontSizeY[currentWDaySize],
currentTimeSize, currentTimeColor, 0, 59);
baseNum2digValue iMDayCurrentDateTime((ifaceItem *)&iCurrentDateTime, 0, fontSizeY[currentWDaySize]+fontSizeY[currentTimeSize],
currentDateSize, currentDateColor, 1, 31);
baseDictMonthValue iMonthCurrentDateTime((ifaceItem *)&iCurrentDateTime, fontSizeX[currentDateSize] * 3, fontSizeY[currentWDaySize]+fontSizeY[currentTimeSize],
currentDateSize, currentDateColor, 0, 11);
baseNum2digValue iYearCurrentDateTime((ifaceItem *)&iCurrentDateTime, fontSizeX[currentDateSize] * 13, fontSizeY[currentWDaySize]+fontSizeY[currentTimeSize],
currentDateSize, currentDateColor, 23, 30);
//-- pump data
baseUnit iPumperDaysTime((ifaceItem *)&iMainDisplay, 0, fontSizeY[currentWDaySize]+fontSizeY[currentDateSize]+fontSizeY[currentTimeSize],
st7735sizeX, fontSizeY[currentWDaySize]+fontSizeY[currentDateSize]+fontSizeY[currentTimeSize]+fontSizeY[pumpDaysSize]*2+fontSizeY[pumpTimeSize]+fontSizeY[0]*2,
pumpBackground);
baseDictPumpDaysValue i1DayPumper((ifaceItem *)&iPumperDaysTime, fontSizeX[0], fontSizeY[0], pumpDaysSize, pumpDaysColor, 1, pumpSelectedDay, pumpSelectedBack);
baseDictPumpDaysValue i2DayPumper((ifaceItem *)&iPumperDaysTime, fontSizeX[0]+fontSizeX[pumpDaysSize]*4, fontSizeY[0], pumpDaysSize, pumpDaysColor, 2, pumpSelectedDay, pumpSelectedBack);
baseDictPumpDaysValue i3DayPumper((ifaceItem *)&iPumperDaysTime, fontSizeX[0]+fontSizeX[pumpDaysSize]*8, fontSizeY[0], pumpDaysSize, pumpDaysColor, 3, pumpSelectedDay, pumpSelectedBack);
baseDictPumpDaysValue i4DayPumper((ifaceItem *)&iPumperDaysTime, fontSizeX[0]+fontSizeX[pumpDaysSize]*12, fontSizeY[0], pumpDaysSize, pumpDaysColor, 4, pumpSelectedDay, pumpSelectedBack);
baseDictPumpDaysValue i5DayPumper((ifaceItem *)&iPumperDaysTime, fontSizeX[0]+fontSizeX[pumpDaysSize]*2, fontSizeY[0]+fontSizeY[pumpDaysSize], pumpDaysSize, pumpDaysColor, 5, pumpSelectedDay, pumpSelectedBack);
baseDictPumpDaysValue i6DayPumper((ifaceItem *)&iPumperDaysTime, fontSizeX[0]+fontSizeX[pumpDaysSize]*6, fontSizeY[0]+fontSizeY[pumpDaysSize], pumpDaysSize, pumpDaysColor, 6, pumpSelectedDay, pumpSelectedBack);
baseDictPumpDaysValue i0DayPumper((ifaceItem *)&iPumperDaysTime, fontSizeX[0]+fontSizeX[pumpDaysSize]*10, fontSizeY[0]+fontSizeY[pumpDaysSize], pumpDaysSize, pumpDaysColor, 0, pumpSelectedDay, pumpSelectedBack);
baseNum2digValue iHourPumpTime((ifaceItem *)&iPumperDaysTime, currentTimeStartX, fontSizeY[0]+fontSizeY[pumpDaysSize]*2,
pumpTimeSize, pumpTimeColor, 8, 22);
baseOneCharValue iPointPumpTime((ifaceItem *)&iPumperDaysTime, currentTimeStartX + fontSizeX[pumpTimeSize] * 2, fontSizeY[0]+fontSizeY[pumpDaysSize]*2,
pumpTimeSize, pumpTimeColor);
baseNum2digValue iMinPumpTime((ifaceItem *)&iPumperDaysTime, currentTimeStartX + fontSizeX[pumpTimeSize] * 3, fontSizeY[0]+fontSizeY[pumpDaysSize]*2,
pumpTimeSize, pumpTimeColor, 0, 59);
//--period pump
baseUnit iPeriodTime((ifaceItem *)&iMainDisplay, 0,
fontSizeY[currentWDaySize]+fontSizeY[currentDateSize]+fontSizeY[currentTimeSize]+
fontSizeY[pumpDaysSize]*2+fontSizeY[pumpTimeSize]+fontSizeY[0]*2,
st7735sizeX,
fontSizeY[currentWDaySize]+fontSizeY[currentDateSize]+fontSizeY[currentTimeSize]+
fontSizeY[pumpDaysSize]*2+fontSizeY[pumpTimeSize]+fontSizeY[0]*2+
fontSizeY[pumpPeriodSize]+fontSizeY[0]*2,
pumpPeriodBack);
baseNum2digText iPeriodPump((ifaceItem *)&iPeriodTime, 0, fontSizeY[0],
pumpPeriodSize, pumpPeriodColor, (unsigned char *)" min", 5, 40);
baseUnit::baseUnit(ifaceItem * itemParent, unsigned short pX, unsigned short pY, unsigned short sX, unsigned short sY, unsigned short bColor) {
this->countChildren = 0;
this->parentItem = itemParent;
if (itemParent != nullptr) {
this->posX = pX;
this->posY = pY;
this->sizeX = sX;
this->sizeY = sY;
this->backgroundColor = bColor;
this->modeShow = 0;
}
}
void ifaceItem::blinkItem(void) {
if ((millis() - this->blinkTimer) >= blinkPeriod) {
this->blinkTimer = millis();
if ((this->modeShow == 0) || (this->modeShow == 1)) this->clearItem(); else this->showItem();
}
}
void baseUnit::clearItem(void) {
this->modeShow = 2;
f103st7735fillRect(this->backgroundColor, this->posX, this->posY, this->sizeX-1, this->sizeY-1);
}
void baseUnit::showItem(void) {
this->modeShow = 0;
f103st7735fillRect(this->backgroundColor, this->posX, this->posY, this->sizeX-1, this->sizeY-1);
if (this->countChildren) for(unsigned char i=0; i<this->countChildren; ++i) this->childItems[i]->showItem();
}
baseOneCharValue::baseOneCharValue(ifaceItem * itemParent, unsigned short pX, unsigned short pY, unsigned char iSize, unsigned short iColor, unsigned short mV, unsigned short xV) {
this->countChildren = 0;
this->parentItem = itemParent;
this->iX = pX;
this->iY = pY;
this->itemColor = iColor;
this->modeShow = 0;
this->fontSize = iSize;
this->minValue = mV;
this->maxValue = xV;
}
void baseOneCharValue::showItem(void) {
this->modeShow = 0;
f103st7735printOneChar(this->currentValue, this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX, this->parentItem->posY+this->iY);
}
void baseNum2digValue::clearItem(void) {
unsigned short posX = 0;
this->modeShow = 2;
f103st7735printOneChar(' ', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX, this->parentItem->posY+this->iY);
posX += fontSizeX[this->fontSize];
f103st7735printOneChar(' ', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+posX, this->parentItem->posY+this->iY);
}
void baseNum2digValue::showItem(void) {
this->modeShow = 0;
unsigned short posX = 0;
f103st7735printOneChar((this->currentValue/10)+'0', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+posX, this->parentItem->posY+this->iY);
posX += fontSizeX[this->fontSize];
f103st7735printOneChar((this->currentValue%10)+'0', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+posX, this->parentItem->posY+this->iY);
}
void baseDictWDayValue::clearItem(void) {
this->modeShow = 2;
f103st7735printString((unsigned char *)this->textWDay[7], this->itemColor, this->parentItem->backgroundColor,
this->fontSize, this->iX+this->parentItem->posX, this->iY+this->parentItem->posY);
}
void baseDictWDayValue::showItem(void) {
this->modeShow = 0;
f103st7735printString((unsigned char *)this->textWDay[this->currentValue], this->itemColor, this->parentItem->backgroundColor,
this->fontSize, this->iX+this->parentItem->posX, this->iY+this->parentItem->posY);
}
void baseDictMonthValue::clearItem(void) {
this->modeShow = 2;
f103st7735printString((unsigned char *)this->textMonths[12], this->itemColor, this->parentItem->backgroundColor,
this->fontSize, this->iX+this->parentItem->posX, this->iY+this->parentItem->posY);
}
void baseDictMonthValue::showItem(void) {
this->modeShow = 0;
f103st7735printString((unsigned char *)this->textMonths[this->currentValue], this->itemColor, this->parentItem->backgroundColor,
this->fontSize, this->iX+this->parentItem->posX, this->iY+this->parentItem->posY);
}
baseDictPumpDaysValue::baseDictPumpDaysValue(ifaceItem * itemParent, unsigned short pX, unsigned short pY, unsigned char iSize, unsigned short iColor, unsigned char inDay, unsigned short daColor, unsigned short lbColor) {
this->countChildren = 0;
this->parentItem = itemParent;
this->iX = pX;
this->iY = pY;
this->itemColor = iColor;
this->modeShow = 0;
this->fontSize = iSize;
this->weekDay = inDay;
this->colorDay = daColor;
this->colorLabel = lbColor;
}
void baseDictPumpDaysValue::clearItem(void) {
this->modeShow = 2;
if (this->currentValue) {
f103st7735printOneChar(' ', this->colorDay, this->colorLabel, this->fontSize, this->parentItem->posX+this->iX, this->parentItem->posY+this->iY);
f103st7735printOneChar(' ', this->colorDay, this->colorLabel, this->fontSize, this->parentItem->posX+this->iX+fontSizeY[this->fontSize], this->parentItem->posY+this->iY);
} else {
f103st7735printOneChar(' ', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX, this->parentItem->posY+this->iY);
f103st7735printOneChar(' ', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+fontSizeY[this->fontSize], this->parentItem->posY+this->iY);
}
}
void baseDictPumpDaysValue::showItem(void) {
this->modeShow = 0;
if (this->currentValue) {
f103st7735printOneChar((unsigned char)this->textWDay[this->weekDay][0], this->colorDay, this->colorLabel, this->fontSize, this->parentItem->posX+this->iX, this->parentItem->posY+this->iY);
f103st7735printOneChar((unsigned char)this->textWDay[this->weekDay][1], this->colorDay, this->colorLabel, this->fontSize, this->parentItem->posX+this->iX+fontSizeY[this->fontSize], this->parentItem->posY+this->iY);
} else {
f103st7735printOneChar((unsigned char)this->textWDay[this->weekDay][0], this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX, this->parentItem->posY+this->iY);
f103st7735printOneChar((unsigned char)this->textWDay[this->weekDay][1], this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+fontSizeY[this->fontSize], this->parentItem->posY+this->iY);
}
}
baseNum2digText::baseNum2digText(ifaceItem * itemParent, unsigned short pX, unsigned short pY, unsigned char iSize, unsigned short iColor, unsigned char * inText, unsigned short mV, unsigned short xV) {
this->countChildren = 0;
this->parentItem = itemParent;
this->iX = pX;
this->iY = pY;
this->itemColor = iColor;
this->modeShow = 0;
this->fontSize = iSize;
this->endText = inText;
this->minValue = mV;
this->maxValue = xV;
}
void baseNum2digText::clearItem(void) {
unsigned short posX = 0;
this->modeShow = 2;
f103st7735printOneChar(' ', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+posX, this->parentItem->posY+this->iY);
posX += fontSizeX[this->fontSize];
f103st7735printOneChar(' ', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+posX, this->parentItem->posY+this->iY);
posX += fontSizeX[this->fontSize];
f103st7735printString((unsigned char *)" ", this->itemColor, this->parentItem->backgroundColor, this->fontSize, posX, this->parentItem->posY+this->iY);
}
void baseNum2digText::showItem(void) {
this->modeShow = 0;
unsigned short posX = 0;
f103st7735printOneChar((this->currentValue/10)+'0', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+posX, this->parentItem->posY+this->iY);
posX += fontSizeX[this->fontSize];
f103st7735printOneChar((this->currentValue%10)+'0', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+posX, this->parentItem->posY+this->iY);
posX += fontSizeX[this->fontSize];
f103st7735printString((unsigned char *)this->endText, this->itemColor, this->parentItem->backgroundColor, this->fontSize, posX, this->parentItem->posY+this->iY);
}
void fillPumpDaysFromData() {
if (iPumperDaysTime.getCountChildren()) {
if ((iPumperDaysTime.getCountChildren()>7) && (iPumperDaysTime.getCountChildren()<11)) {
i0DayPumper.setValue(saveParamDays1partPump.pumpDays[0]);
i1DayPumper.setValue(saveParamDays1partPump.pumpDays[1]);
i2DayPumper.setValue(saveParamDays1partPump.pumpDays[2]);
i3DayPumper.setValue(saveParamDays1partPump.pumpDays[3]);
i4DayPumper.setValue(saveParamDays2partPump.pumpDays[0]);
i5DayPumper.setValue(saveParamDays2partPump.pumpDays[1]);
i6DayPumper.setValue(saveParamDays2partPump.pumpDays[2]);
iHourPumpTime.setValue(saveParamTime3partPump.pumpTime[0]);
iMinPumpTime.setValue(saveParamTime3partPump.pumpTime[1]);
}
}
}
void initPumper(void) {
//--current date time
iMainDisplay.addChild((ifaceItem *)&iCurrentDateTime);
iCurrentDateTime.addChild((ifaceItem *)&iDayOfWeekCurrentDateTime);
iCurrentDateTime.addChild((ifaceItem *)&iHourTimeCurrentDateTime);
iCurrentDateTime.addChild((ifaceItem *)&iPointTimeCurrentDateTime);
iPointTimeCurrentDateTime.setValue(' ');
iPointTimeCurrentDateTime.setNoEditedItem();
iCurrentDateTime.addChild((ifaceItem *)&iMinTimeCurrentDateTime);
iCurrentDateTime.addChild((ifaceItem *)&iMDayCurrentDateTime);
iCurrentDateTime.addChild((ifaceItem *)&iMonthCurrentDateTime);
iCurrentDateTime.addChild((ifaceItem *)&iYearCurrentDateTime);
//-- pump data
iMainDisplay.addChild((ifaceItem *)&iPumperDaysTime);
iPumperDaysTime.addChild((ifaceItem *)&i0DayPumper);
iPumperDaysTime.addChild((ifaceItem *)&i1DayPumper);
iPumperDaysTime.addChild((ifaceItem *)&i2DayPumper);
iPumperDaysTime.addChild((ifaceItem *)&i3DayPumper);
iPumperDaysTime.addChild((ifaceItem *)&i4DayPumper);
iPumperDaysTime.addChild((ifaceItem *)&i5DayPumper);
iPumperDaysTime.addChild((ifaceItem *)&i6DayPumper);
iPumperDaysTime.addChild((ifaceItem *)&iHourPumpTime);
iPumperDaysTime.addChild((ifaceItem *)&iPointPumpTime);
iPointPumpTime.setValue('.');
iPointPumpTime.setNoEditedItem();
iPumperDaysTime.addChild((ifaceItem *)&iMinPumpTime);
//--period pump
iMainDisplay.addChild((ifaceItem *)&iPeriodTime);
iPeriodTime.addChild((ifaceItem *)&iPeriodPump);
// -- read param from flash
saveParamDays1partPump.PartPumpDays = FLASH_read_param(numParamPump1Days);
saveParamDays2partPump.PartPumpDays = FLASH_read_param(numParamPump2Days);
saveParamTime3partPump.PartPumpTime = FLASH_read_param(numParamTimePump);
}
void relayON(void) {
//GPIOA->BSRR |= GPIO_BSRR_BR12; // PA12 LOW
GPIOA->BSRR |= GPIO_BSRR_BS12; // PA12 HIGH
delay_ms(100UL);
//GPIOA->BSRR |= GPIO_BSRR_BR11; // PA11 LOW
GPIOA->BSRR |= GPIO_BSRR_BS11; // PA11 HIGH
}
void relayOFF(void) {
GPIOA->BSRR |= GPIO_BSRR_BR11; // PA11 LOW
//GPIOA->BSRR |= GPIO_BSRR_BS11; // PA11 HIGH
delay_ms(100UL);
GPIOA->BSRR |= GPIO_BSRR_BR12; // PA12 LOW
//GPIOA->BSRR |= GPIO_BSRR_BS12; // PA12 HIGH
}
void f1InitPumpGpio(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // GPIO port B
// PB14 - key 1
GPIOB->CRH &= ~GPIO_CRH_MODE14; // 00: Input mode (reset state)
GPIOB->CRH &= ~GPIO_CRH_CNF14; // 10: Input with pull-up / pull-down
GPIOB->CRH |= GPIO_CRH_CNF14_1; // 10: Input with pull-up / pull-down
GPIOB->ODR |= GPIO_ODR_ODR14; // Input with pull-up
// PB15 - key 2
GPIOB->CRH &= ~GPIO_CRH_MODE15; // 00: Input mode (reset state)
GPIOB->CRH &= ~GPIO_CRH_CNF15; // 10: Input with pull-up / pull-down
GPIOB->CRH |= GPIO_CRH_CNF15_1; // 10: Input with pull-up / pull-down
GPIOB->ODR |= GPIO_ODR_ODR15; // Input with pull-up
// relay pins OUTPUT
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // GPIO port A
// PA11 - relay1
GPIOA->ODR &= ~GPIO_ODR_ODR11; // PA11 LOW
GPIOA->CRH &= ~GPIO_CRH_MODE11; // 00: Input mode (reset state)
GPIOA->CRH |= GPIO_CRH_MODE11_0; // 01: Output mode, max speed 10 MHz.
GPIOA->CRH &= ~GPIO_CRH_CNF11; // 00: General purpose output push-pull
// PA12 - relay2
GPIOA->ODR &= ~GPIO_ODR_ODR12; // PA12 LOW
GPIOA->CRH &= ~GPIO_CRH_MODE12; // 00: Input mode (reset state)
GPIOA->CRH |= GPIO_CRH_MODE12_0; // 01: Output mode, max speed 10 MHz.
GPIOA->CRH &= ~GPIO_CRH_CNF12; // 00: General purpose output push-pull
// --
relayOFF();
}
void showDateTime(void) {
static unsigned long timerShowDateTime = 59000UL;
static unsigned long timerBlinkSec = 0;
static unsigned char secBlink =0;
if ((millis() - timerShowDateTime) >= 60000UL) {
timerShowDateTime = millis();
getCurrentDateTime((struct tm *)¤tDateTime);
iDayOfWeekCurrentDateTime.setValue(currentDateTime.tm_wday);
iHourTimeCurrentDateTime.setValue(currentDateTime.tm_hour);
iMinTimeCurrentDateTime.setValue(currentDateTime.tm_min);
iMDayCurrentDateTime.setValue(currentDateTime.tm_mday);
iMonthCurrentDateTime.setValue(currentDateTime.tm_mon);
iYearCurrentDateTime.setValue((currentDateTime.tm_year+1900)%100);
iCurrentDateTime.showItem();
} else if ((millis() - timerBlinkSec) >= 1000UL) {
timerBlinkSec = millis();
if (secBlink) {
iPointTimeCurrentDateTime.setValue(':');
secBlink = 0;
} else {
iPointTimeCurrentDateTime.setValue(' ');
secBlink = 1;
}
iPointTimeCurrentDateTime.showItem();
}
}
unsigned char getKey1(void) { // выдает 1 если нажата 1 кнопка
static unsigned char last1Level = 1;
static unsigned char flag1KeysDown = 0;
static unsigned long start1TimeDown;
unsigned char current1Level;
if (GPIOB->IDR & GPIO_IDR_IDR14) current1Level = 1; else current1Level = 0;
if (current1Level != last1Level) { // change level
unusedDevice = millis();
if (current1Level == 0) { // key down
if (flag1KeysDown == 0) { // no timer
flag1KeysDown = 1; // begin timer
start1TimeDown = millis();
}
} else { // key up
if (flag1KeysDown != 0) { // timer started
if ((millis() - start1TimeDown) >= 500UL) { // error press
flag1KeysDown = 0; // stop timer
} else if ((millis() - start1TimeDown) >= keys_short_press) { // short press
flag1KeysDown = 0; // stop timer
last1Level = current1Level; // save current level
return 1;
}
}
}
} else { // level not change
if ((flag1KeysDown != 0) && (current1Level == 0)) { // timer started and key down
if ((millis() - start1TimeDown) >= keys_long_press) { // long press
flag1KeysDown = 0; // stop timer
last1Level = current1Level; // save current level
return 2;
}
} else if (current1Level != 0) { // key up
flag1KeysDown = 0; // reset timer
}
}
last1Level = current1Level; // save current level
return 0;
}
unsigned char getKey2(void) { // выдает 1 если нажата 2 кнопка
static unsigned char last2Level = 1;
static unsigned char flag2KeysDown = 0;
static unsigned long start2TimeDown;
unsigned char current2Level;
if (GPIOB->IDR & GPIO_IDR_IDR15) current2Level = 1; else current2Level = 0;
if (current2Level != last2Level) { // change level
unusedDevice = millis();
if (current2Level == 0) { // key down
if (flag2KeysDown == 0) { // no timer
flag2KeysDown = 1; // begin timer
start2TimeDown = millis();
}
} else { // key up
if (flag2KeysDown != 0) { // timer started
if ((millis() - start2TimeDown) >= 500UL) { // error press
flag2KeysDown = 0; // stop timer
} else if ((millis() - start2TimeDown) >= keys_short_press) { // short press
flag2KeysDown = 0; // stop timer
last2Level = current2Level; // save current level
return 1;
}
}
}
} else { // level not change
if ((flag2KeysDown != 0) && (current2Level == 0)) { // timer started and key down
if ((millis() - start2TimeDown) >= keys_long_press) { // long press
flag2KeysDown = 0; // stop timer
last2Level = current2Level; // save current level
return 2;
}
} else if (current2Level != 0) { // key up
flag2KeysDown = 0; // reset timer
}
}
last2Level = current2Level; // save current level
return 0;
}
void saveDeviceOptions(void) {
// --current date time
currentDateTime.tm_wday = iDayOfWeekCurrentDateTime.getValue();
currentDateTime.tm_hour = iHourTimeCurrentDateTime.getValue();
currentDateTime.tm_min = iMinTimeCurrentDateTime.getValue();
currentDateTime.tm_mday = iMDayCurrentDateTime.getValue();
currentDateTime.tm_mon = iMonthCurrentDateTime.getValue();
currentDateTime.tm_year = iYearCurrentDateTime.getValue() + 100;
// -- save to DS3231
setCurrentDateTime((struct tm *)¤tDateTime);
// -- pump data
saveParamDays1partPump.pumpDays[0] = i0DayPumper.getValue();
saveParamDays1partPump.pumpDays[1] = i1DayPumper.getValue();
saveParamDays1partPump.pumpDays[2] = i2DayPumper.getValue();
saveParamDays1partPump.pumpDays[3] = i3DayPumper.getValue();
saveParamDays2partPump.pumpDays[0] = i4DayPumper.getValue();
saveParamDays2partPump.pumpDays[1] = i5DayPumper.getValue();
saveParamDays2partPump.pumpDays[2] = i6DayPumper.getValue();
saveParamTime3partPump.pumpTime[0] = iHourPumpTime.getValue();
saveParamTime3partPump.pumpTime[1] = iMinPumpTime.getValue();
saveParamTime3partPump.pumpPeriod = iPeriodPump.getValue();
// -- save to flash
FLASH_write_param(numParamPump1Days, saveParamDays1partPump.PartPumpDays);
FLASH_write_param(numParamPump2Days, saveParamDays2partPump.PartPumpDays);
FLASH_write_param(numParamTimePump, saveParamTime3partPump.PartPumpTime);
}
unsigned char controlDevice(void) { // выдать 1 если изменились параметры и их все надо обновить на экране
static unsigned char dataChanged = 0; // 1 если данные менялись
unsigned char data1key = getKey1();
unsigned char data2key = getKey2();
static unsigned char numEditMainUnit = 0; // номер главного модуля который редактируется
static unsigned char enteredSubUnit = 0; // перешли в редактирование значения в модуле
static unsigned char numSubItem = 0; // номер элемента который редактируется
if (!devModes) { // standby mode
dataChanged = 0; // пока данные не менялись
if (data1key) { // enter set mode
devModes = 1; // enter set mode
numEditMainUnit = 0; // номер главного модуля который редактируется
enteredSubUnit = 0; // моргаем пока модулем
}
} else { // settings mode
if ((millis()-unusedDevice) >= 8000UL) { // если кнопки долго не нажимали
if (dataChanged) saveDeviceOptions(); // сохраняем все данные
devModes = 0; // возвращаемся в ждущий режим
return 1; // с обновлением данных
}
if (enteredSubUnit) { // в режиме редактирования элемента
iMainDisplay.getChild(numEditMainUnit)->getChild(numSubItem)->blinkItem(); // моргаем элементом
if (data2key) { // если продолжается нажиматься вторая кнопка
iMainDisplay.getChild(numEditMainUnit)->getChild(numSubItem)->showItem(); // предыдущий элемент просто отобразим
++numSubItem; // будем моргать следующим элементом
if (numSubItem >= iMainDisplay.getChild(numEditMainUnit)->getCountChildren()) numSubItem = 0;
if (iMainDisplay.getChild(numEditMainUnit)->getChild(numSubItem)->getNoEditedItem()) { // если элемент не редактируемый
++numSubItem; // будем моргать следующим элементом
if (numSubItem >= iMainDisplay.getChild(numEditMainUnit)->getCountChildren()) numSubItem = 0;
}
} else {
if (data1key) { // нажалась кнопка 1 - изменить значение
dataChanged = 1;
iMainDisplay.getChild(numEditMainUnit)->getChild(numSubItem)->changeValue();
}
}
} else { // в режиме выбора модуля
iMainDisplay.getChild(numEditMainUnit)->blinkItem(); // моргаем модулем
if (data1key) { // если продолжается нажиматься первая кнопка
iMainDisplay.getChild(numEditMainUnit)->showItem(); // предыдущий модуль просто отобразим
++numEditMainUnit; // будем моргать следующим модулем
if (numEditMainUnit >= iMainDisplay.getCountChildren()) numEditMainUnit = 0;
} else {
if (data2key) { // если нажалась вторая кнопка
iMainDisplay.getChild(numEditMainUnit)->showItem(); // текущий модуль просто отобразим
enteredSubUnit = 1; // перешли в редактирование значения в модуле
numSubItem = 0; // номер элемента который редактируется
}
}
}
}
return 0;
}
unsigned char deviceProcess(void) { // проверка времени запуска и включение реле
if ((saveParamTime3partPump.pumpTime[0] == currentDateTime.tm_hour) &&
(saveParamTime3partPump.pumpTime[1] == currentDateTime.tm_min)) { // время пришло
unsigned char dayON = 0;
if (currentDateTime.tm_wday<4) {
if (saveParamDays1partPump.pumpDays[currentDateTime.tm_wday]) dayON = 1;
} else {
if (saveParamDays2partPump.pumpDays[currentDateTime.tm_wday-4]) dayON = 1;
}
if (dayON) { // и день подошел
unsigned long pumpPeriod = saveParamTime3partPump.pumpPeriod * 60000UL; //by min
if (pumpPeriod >= 3360000UL) return 0; // 56 min MAX
unsigned long timerPumper = millis();
unsigned long timerSec = 0;
f103st7735fillScreen(ST7735_BLACK);
relayON();
unsigned short posX = fontSizeX[0], posY = fontSizeY[0];
while ((millis() - timerPumper) < pumpPeriod) {
if ((millis() - timerSec) >= 1000UL) { // 1 sec
timerSec = millis();
unsigned long minutes = (pumpPeriod - (millis() - timerPumper)) / 60000UL;
unsigned long seconds = ((pumpPeriod - (millis() - timerPumper)) / 1000UL) % 60;
f103st7735printOneChar((minutes/10)+'0', ST7735_GREEN, ST7735_BLACK, 3, posX, posY);
f103st7735printOneChar((minutes%10)+'0', ST7735_GREEN, ST7735_BLACK, 3, posX + fontSizeX[3], posY);
f103st7735printOneChar((seconds/10)+'0', ST7735_GREEN, ST7735_BLACK, 3, posX + fontSizeX[0], posY + fontSizeY[3] + fontSizeY[0]);
f103st7735printOneChar((seconds%10)+'0', ST7735_GREEN, ST7735_BLACK, 3, posX + fontSizeX[3] + fontSizeX[0], posY + fontSizeY[3] + fontSizeY[0]);
}
}
relayOFF();
return 1; // обновим всю картинку при выходе
}
}
return 0;
}
void loopPumper(void) {
static unsigned char needShowPumpDate = 1; // в обычном ждущем режиме один раз показать данные полива при старте железки
if (!devModes) { // standby mode
showDateTime();
if ((needShowPumpDate) || (deviceProcess())) {
needShowPumpDate = 0;
fillPumpDaysFromData();
iPumperDaysTime.showItem();
iPeriodPump.setValue(saveParamTime3partPump.pumpPeriod);
iPeriodTime.showItem();
f103st7735printString((unsigned char *)"Pumper v08.2023", ST7735_WHITE, ST7735_BLACK, 0, 0, st7735sizeY - fontSizeY[0]);
}
}
needShowPumpDate = controlDevice(); // основная работа с кнопками и режимами настройки
}
кшмр.
У меня такие же чувства, но скорее от того что я не умею программировать… ))
в каком плане ?
в программном. Для такой примитивной задачи уж больно на…уеверчено.
ну не, не соглашусь, если выкинуть код инициализации, RTC, флэш памяти, дисплея (предположить что используются библиотеки), то останется только классы/объекты работы с меню → настройка параметров. Т е то, с чего я и начинал данную тему.
Может так и стоило сделать перед тем как выкладывать?
Вообще, начиная с определенного уровня сложности, задавать вопросы на форуме становится почти бессмысленно. Слишком глубоко надо объяснять суть проекта, прежде чем кто-то сможет помочь.
Если выкинуть “не нужное”, код работать не будет.
Про " задавать вопросы на форуме" не понял.
Я задал вопрос в начале темы, получил ответ, написал код, он заработал, профит!
Небольшое уточнение по работе RTC на CH32F103C8T6:
Взял очередрую подопытную плату, запустил ранее работающую программу, оказалось что RTC “тикают” в 60 раз медленнее, возможно виноват данный конкретный экземпляр.
Причем поведение не зависит от подачи напряжения на VBAT, при сбросе/подаче питания все аналогично.
Для исправления, в функции:
void f103initRTC(void) {
if ((RCC->BDCR & RCC_BDCR_RTCEN) != RCC_BDCR_RTCEN) { //Проверка работы часов, если не включены, то инициализировать
RCC->APB1ENR |= RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN; //Включить тактирование PWR и Backup
PWR->CR |= PWR_CR_DBP; //Разрешить доступ к Backup области
RCC->BDCR |= RCC_BDCR_BDRST; //Сбросить Backup область
RCC->BDCR &= ~RCC_BDCR_BDRST;
RCC->BDCR |= RCC_BDCR_RTCSEL_LSE; //Выбрать LSE источник (кварц 32768)
RCC->BDCR |= RCC_BDCR_LSEON; //Включить LSE
while ((RCC->BDCR & RCC_BDCR_LSEON) != RCC_BDCR_LSEON){} //Дождаться включения
BKP->RTCCR |= 3; //калибровка RTC
while (!(RTC->CRL & RTC_CRL_RTOFF)); //проверить закончены ли изменения регистров RTC
RTC->CRL |= RTC_CRL_CNF; //Разрешить Запись в регистры RTC
RTC->PRLH = 0; //Настроит делитель на 32768 (32767+1)
RTC->PRLL = 0x7FFF; //Настроит делитель на 32768 (32767+1)
//BKP->RTCCR |= BKP_RTCCR_CCO; //Включение вывода Temper
RTC->CRL &= ~RTC_CRL_CNF; //Запретить запись в регистры RTC
RCC->BDCR |= RCC_BDCR_RTCEN; // и подать тактирование
while (!(RTC->CRL & RTC_CRL_RTOFF)); //Дождаться окончания записи
RTC->CRL &= (uint16_t)~RTC_CRL_RSF; //Синхронизировать RTC
while((RTC->CRL & RTC_CRL_RSF) != RTC_CRL_RSF){} //Дождаться синхронизации
PWR->CR &= ~PWR_CR_DBP; //запретить доступ к Backup области
}
}
добавил строку
RTC->PRLH = 0;
т.е. обнулить старшую часть регистра делителя RTC от LSE
исправленная функция инициализации RTC, тактирование шины вытащено за условие проверки часов, тактирование RTC поднято выше до записи в него данных.
void f103initRTC(void) {
RCC->APB1ENR |= RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN; //Включить тактирование PWR и Backup
if ((RCC->BDCR & RCC_BDCR_RTCEN) != RCC_BDCR_RTCEN) { //Проверка работы часов, если не включены, то инициализировать
PWR->CR |= PWR_CR_DBP; //Разрешить доступ к Backup области
RCC->BDCR |= RCC_BDCR_BDRST; //Сбросить Backup область
RCC->BDCR &= ~RCC_BDCR_BDRST;
RCC->BDCR |= RCC_BDCR_RTCSEL_LSE; //Выбрать LSE источник (кварц 32768)
RCC->BDCR |= RCC_BDCR_LSEON; //Включить LSE
RCC->BDCR |= RCC_BDCR_RTCEN; // и подать тактирование
while ((RCC->BDCR & RCC_BDCR_LSEON) != RCC_BDCR_LSEON){} //Дождаться включения
BKP->RTCCR |= 3; //калибровка RTC
while (!(RTC->CRL & RTC_CRL_RTOFF)); //проверить закончены ли изменения регистров RTC
RTC->CRL |= RTC_CRL_CNF; //Разрешить Запись в регистры RTC
RTC->PRLH = 0; //Настроит делитель на 32768 (32767+1)
RTC->PRLL = 0x7FFF; //Настроит делитель на 32768 (32767+1)
//BKP->RTCCR |= BKP_RTCCR_CCO; //Включение вывода Temper
RTC->CRL &= ~RTC_CRL_CNF; //Запретить запись в регистры RTC
while (!(RTC->CRL & RTC_CRL_RTOFF)); //Дождаться окончания записи
RTC->CRL &= (uint16_t)~RTC_CRL_RSF; //Синхронизировать RTC
while((RTC->CRL & RTC_CRL_RSF) != RTC_CRL_RSF){}; //Дождаться синхронизации
PWR->CR &= ~PWR_CR_DBP; //запретить доступ к Backup области
}
}