Удаленный мониторинг за датчиками на Maple mini
- Войдите на сайт для отправки комментариев
Есть 2 устройства по контролю влажности. http://arduino.ru/forum/proekty/kontrol-vlazhnosti-podvala-arduino-pro-mini
Данная ветка описывает устройство которое "принимает" данные с удаленных блоков по радиоканалу и выводит на экран. Планируется подключать несколько устройств (как минимум два осушителя, тепловой насос и 2-3 удаленных термометра).
1. Выбор элементной базы.
В качестве контроллера решил использовать maple mini на stm32f103. По сравнению с "классической" ардуиной одни сплошные плюсы:
- частота 72 мегагерца
- 32 бита
- 120 кбайт для программ (загрузчик перешил на неродной) и 20 кбайт озу
- на любую ножку можно повесить прерывание
- 12 ацп с приличной частотой, 2 spi и т.д
Минус для меня один нет eeprom и трудность перехода.
2. Среда разработки
Пишу в стандартой ide ардуино 1.6.1 (можно ставить и 1.6.4 НО ОБЯЗАТЕЛЬНО доставить для DUE софт, там компилятор для arm). Дальше доставляем "спец" софт из проекта http://www.stm32duino.com/
качать от сюда https://github.com/rogerclarkmelbourne/Arduino_STM32
читать http://www.stm32duino.com/ и https://github.com/rogerclarkmelbourne/Arduino_STM32/wiki
3. Программа
Выкладываю исходные тексты программы. Это ранняя альфа. Подключено три экрана - информационный и два осушителя. Хотел прикрутить энкодер но с ним переодически зависает эуран (конфликт дисплея и радиомодуля), пока ограничился кнопкой, нажатие на которую меняет экран.
Пока борюсь с косяками, но связь и вывод работает.
4. Конструктив.
Корпус напечатан на 3Д принтере (нижняя часть склеена из двух частей). Очень удобно, все отверстия сразу сделаны, только заусецы счистить и можно использовать. Получилось достаточно компактно. Вся электроника кроме входных цепей распаена на макетке, проводом . В качестве резервного питания использую литевый аккумулятор 18650, с блоком зарядки. Обычно устройство питается от 5 вольт. Автономно дережет часов 10-15.
исходники:
1. stm32_server.ino
#pragma GCC optimize ("-Os")
//#pragma pack(push, 1) // выравнивание по одному байту ????????
//#define DEMO // Признак демонстрации - данные с датчиков генерятся рандом другие интервалы
#define VERSION "Version: 0.361 alpha 19/09/15" // Текущая версия
#define SPI_16BIT
#define SPI_MODE_DMA 1
#define SPEED_UP 1 // Enables extra calculations in the circles routine to use fastVLine and fastHLine, only in DMA mode.
#include <SPI.h> // в зависимости от платформы используется разная библиотека
#include "Ucglib.h" // адаптирована для Maple mini
#include "rusFont.h" // русские фонты
#include "nRF24L01.h" // не требует адаптации
#include "RF24.h" // адаптирована для Maple mini
#include <libmaple/iwdg.h> // Сторожевой таймер
#include <libmaple/adc.h> // АЦП
#define DSB_ALL_IRQ asm volatile("cpsid i"); // запретить все прерывания
#define ENB_ALL_IRQ asm volatile("cpsie i"); // разрешить все прерывания
// Что куда припаяно
#define NRF24_CE_PIN 3
#define NRF24_CSN_PIN 7
#define NRF24_IRQ_PIN PB10 // прерывание радио
#define TFT_CD_PIN 12
#define TFT_CS_PIN 13
#define TFT_RST_PIN 14 // сброс дисплея
#define LED_PIN PB1 // светодиод на плате
#define PIN_A 10 // энкодер канал А
#define PIN_B 9 // энкодер канал B
#define PIN_SW 8 // энкодер Кнопка
// Аппаратный SPI на дисплей ILI9341 и NRF24
Ucglib_ILI9341_18x240x320_HWSPI ucg(/*cd=*/TFT_CD_PIN , /*cs=*/ TFT_CS_PIN, /*reset=*/ TFT_RST_PIN); // Дисплей
RF24 radio(NRF24_CE_PIN, NRF24_CSN_PIN); // радиомодуль
#define NRF24_CHANEL 100
#define NUM_SCREEN 2+1 // Число экранов + 1 стартовый
int err_count=-1; // статистика по пропущенным пакетам -1 признак первого старта
// энкодер
volatile uint8_t enc=0;
volatile int newpos=0;
bool packet_ready=false; // true поступили новые данные
bool change_screen=false; // true сменился экран
//bool signalStrength;
byte last_error=100; // Предыдущая ошибка<packet.error
// Проверка радио по прерываниям от радиомодуля
void check_radio(void);
void setup(){
pinMode(PB1, OUTPUT); // Светодиод
pinMode(NRF24_IRQ_PIN, INPUT); // Прерывание
pinMode(PIN_A, INPUT);
pinMode(PIN_B, INPUT);
pinMode(PIN_SW, INPUT);
digitalWrite(PIN_A, HIGH); // turn on pullup resistor
digitalWrite(PIN_B, HIGH); // turn on pullup resistor
iwdg_init(IWDG_PRE_256, 1250); // init an 8 second wd timer
// Настройка радиомодуля
radio.begin();
radio.setDataRate(RF24_250KBPS); // выбор скорости RF24_250KBPS RF24_1MBPS RF24_2MBPS
radio.setPALevel(RF24_PA_MAX); // выходная мощность передатчика
radio.setChannel(NRF24_CHANEL); // тут установка канала
radio.setCRCLength(RF24_CRC_16); // использовать контрольную сумму в 16 бит
radio.setAutoAck(true); // включить аппаратное потверждение
// radio.enableDynamicPayloads(); // разрешить Dynamic Payloads
// radio.enableAckPayload(); // разрешить AckPayload
radio.setRetries(50,10); // Количество повторов и пауза между повторами
// Рекомендуют первые 2-4 байта адреса устанавливать в E7 или 18 он проще детектируется чипом
radio.openWritingPipe(0xE7E7E7E7D2LL); // передатчик
radio.openReadingPipe(1,0xE7E7E7E7E1LL); // приемник
radio.startListening();
reset_ili9341();
start_screen();
attachInterrupt(NRF24_IRQ_PIN, check_radio, FALLING); // Прикрепление прерывания радио
// attachInterrupt(PIN_A, updateEncoder, CHANGE); // Прикрепление прерывания энкодер
// attachInterrupt(PIN_B, updateEncoder, CHANGE); // Прикрепление прерывания энкодер
attachInterrupt(PIN_SW, scanKey, FALLING);
}
void scanKey()
{
int oldpos=newpos;
byte key=digitalRead(PIN_SW);
if (key==0) newpos++;
if (newpos>=NUM_SCREEN) newpos=0;
if (oldpos!=newpos) change_screen=true; // только когда было изменение
}
void updateEncoder() //адаптировано на деление на 2 и диапазон по количеству экранов
{
int oldpos=newpos;
uint8_t newenc=2*digitalRead(PIN_B)+digitalRead(PIN_A); //берем 2 бита входов и сдвигаем в позицию 0,1
uint8_t temp=enc ^ newenc; //побитовое исключающее или
// if (temp == 0b01)
// if (enc==0b00 || enc==0b11) newpos++; else newpos--;
// else
if(temp == 0b10)
if (enc==0b00 || enc==0b11) newpos--; else newpos++;
enc=newenc;
if (newpos<0) newpos=NUM_SCREEN-1;
if (newpos>=NUM_SCREEN) newpos=0;
if (oldpos!=newpos) change_screen=true; // только когда было изменение
}
void loop()
{
if (change_screen==true) // Смена экрана
{ DSB_ALL_IRQ;
change_screen=false;
packet_ready=true;
ucg.clearScreen();
switch (newpos) { // по положению Энкодера
case 0: // стартовый экран
start_screen();
break;
case 1: // осушитель ID 0x21
dry_static(0);
dry_data(0);
break;
case 2: // осушитель ID 0x22
dry_static(1);
dry_data(1);
break;
default: newpos=0;
}
ENB_ALL_IRQ;
}
if (packet_ready==true) // Есть не обработанные данные - надо нарисовать
{
packet_ready=false;
DSB_ALL_IRQ;
switch (newpos) { // по положению Энкодера
case 0: // стартовый экран
// start_screen();
break;
case 1: // осушитель ID 0x21
dry_update(0);
break;
case 2: // осушитель ID 0x21
dry_update(1);
break;
default: newpos=0;
}
ENB_ALL_IRQ;
digitalWrite(PB1,HIGH);
delay(5);
digitalWrite(PB1,LOW) ;
}
iwdg_feed(); // Сброс сторожевого таймера
delay(100); // без этого квитанции не приходят
}
// Вывод float с одним десятичным знаком в координаты x y // для экономии места
void print_floatXY(int x,int y, float v)
{
ucg.setPrintPos(x,y);
ucg.print(v,2);
ucg.print(" "); // Стереть хвост от предыдущего числа
}
// Вывод строки константы в координаты x y // для экономии места
void print_StrXY(int x,int y, const __FlashStringHelper* b)
{
ucg.setPrintPos(x,y);
ucg.print(b);
}
char hex(byte x) // Функия для вывода в hex
{
if(x >= 0 && x <= 9 ) return (char)(x + '0');
else return (char)('a'+x-10);
}
void check_radio(void) // ПРИЕМ ПАКЕТА Прерывание для проверки радио
{
uint8_t buf[33]; // Буффер для чтения 32+1
byte pipe = 0;
while(radio.available(&pipe) ) // читаем весь буфер до 3 посылок
{
packet_ready=true; // есть не обработанные данные
radio.read(&buf, sizeof(buf)); // Читаем в промежуточный буффер, далее анализируем 1 байт id
if ((buf[0]&0xf0)==0x20) dry_get_data(buf); // анализ по ID тип устройства ОСУШИТЕЛЬ
}
/*
if ( radio.available(&pipe) ) {
radio.read(&buf, sizeof(buf)); // Читаем в промежуточный буффер, далее анализируем 1 байт id
if ((buf[0]&0xf0)==0x20) dry_get_data(buf); // анализ по ID тип устройства ОСУШИТЕЛЬ
}
*/
}
// Очистка экрана
bool reset_ili9341(void)
{
pinMode(TFT_RST_PIN, OUTPUT); // Сброс дисплея сигнал активным является LOW
digitalWrite(TFT_RST_PIN, LOW);
delay(100);
digitalWrite(TFT_RST_PIN, HIGH);
// Дисплей
ucg.begin(UCG_FONT_MODE_TRANSPARENT);
ucg.setFont(my14x10rus);
ucg.setRotate90();
// ucg.setRotate270();
ucg.clearScreen();
}
bool start_screen(void)
{
// Заголовок
ucg.setColor(0, 0, 180); //
ucg.drawBox(0, 0, 320-1, 23);
ucg.setColor(250, 250, 250);
ucg.setFontMode(UCG_FONT_MODE_TRANSPARENT);
// ucg.setPrintPos(2,19);
// ucg.print(newpos);
print_StrXY(2+12,19,F("Удаленный мониторинг"));
ucg.setColor(255, 255, 0);
print_StrXY(2,22+18*1,F("1. Температура блока градусы: "));
ucg.print((1750.0-(read_VDDA()))/4.3+25.0);
print_StrXY(2,22+18*2,F("2. Канал NRF24l01+: "));
ucg.print(NRF24_CHANEL);
print_StrXY(2,22+18*3,F("3. Число внешних устройств: "));
ucg.print(NUM_SCREEN-1);
ucg.setColor(250,80,80);
print_StrXY(2,22+18*11,F(VERSION));
}
// Чтение опорного напряжения
uint16 read_VDDA(void)
{
adc_reg_map *regs = ADC1->regs;
// 3. Set the TSVREFE bit in the ADC control register 2 (ADC_CR2) to wake up the
// temperature sensor from power down mode. Do this first 'cause according to
// the Datasheet section 5.3.21 it takes from 4 to 10 uS to power up the sensor.
regs->CR2 |= ADC_CR2_TSEREFE;
// 1. Select the ADCx_IN16 input channel.
regs->SQR1 = 0; // set regular channel sequence length to 1
regs->SQR3 = 0b10000; // select channel 16
// 2. Select a sample time of 17.1 μs
// per gbulmer: set channel 16 sample time to 239.5 cycles
// 239.5 cycles of the ADC clock (72MHz/6=12MHz) is over 17.1us (about 20us), but no smaller
// sample time exceeds 17.1us.
regs->SMPR1 = (0b111 << (3*6));
// 4. Start the ADC conversion by setting the ADON bit (or by external trigger).
// note by virture of bit 11 being zero returns right aligned results.
// Aparently we also need SWSTART - tdc
regs->CR2 |= (ADC_CR2_SWSTART | ADC_CR2_ADON);
// wait for conversion to complete
while (!(regs->SR & ADC_SR_EOC)) ;
// 5. Read the resulting VSENSE data in the ADC data register
return (uint16)(regs->DR & ADC_DR_DATA);
}
2. dry_control.ino
// Функции для осушителя подвала
// Все функции имеют на входе в качестве параметра номер датчика
// Мои макросы
#define MOTOR_BIT 0 // бит мотора в packet_0x20.flags
#define HEAT_BIT 1 // бит калорифера в packet_0x20.flags
#define ABS_H_BIT 2 // бит калорифера в packet_0x20.flags
#define MODE_BIT 5 // первый бит режима в packet_0x20.flags
#define FLAG_ABS_H_ON packet_0x20[ID].flags |= (1<<ABS_H_BIT) // бит ABS_H_BIT установить в 1
#define FLAG_ABS_H_OFF packet_0x20[ID].flags &= ~(1<<ABS_H_BIT) // бит ABS_H_BIT установить в 0
#define FLAG_ABS_H_CHECK packet_0x20[ID].flags & (1<<ABS_H_BIT) // бит ABS_H_BIT проверить на 1
#define FLAG_MOTOR_ON packet_0x20[ID].flags |= (1<<MOTOR_BIT) // бит мотора установить в 1
#define FLAG_MOTOR_OFF packet_0x20[ID].flags &= ~(1<<MOTOR_BIT) // бит мотора установить в 0
#define FLAG_MOTOR_CHECK packet_0x20[ID].flags & (1<<MOTOR_BIT) // бит мотора проверить на 1
#define FLAG_HEAT_ON packet_0x20[ID].flags |= (1<<HEAT_BIT) // бит калорифера установить в 1
#define FLAG_HEAT_OFF packet_0x20[ID].flags &= ~(1<<HEAT_BIT) // бит калорифера установить в 0
#define FLAG_HEAT_CHECK packet_0x20[ID].flags & (1<<HEAT_BIT) // бит калорифера проверить на 1
#define NUM_SAMPLES 10 // Число усреднений измерений датчика
#define TIME_SCAN_SENSOR 3000 // Время опроса датчиков мсек
#define TIME_PRINT_CHART 300000 // Время вывода точки графика мсек
#define TIME_HOUR 3600000 // Число мсек в часе
#define NUM_DRY 2 // число осушителей id 0x21 0x22
// Пакет передаваемый, используется также для хранения результатов.
struct type_packet_0x20_NRF24 // Версия 2.4!! адаптация для stm32 Структура передаваемого пакета 32 байта - 32 максимум
{
byte id=0x00; // Идентификатор типа устройства - старшие 4 бита, вторые (младшие) 4 бита серийный номер устройства
byte DHT_error; // Ошибка разряды: 0-1 первый датчик (00-ок) 2-3 второй датчик (00-ок) 4 - радиоканал
int16_t tOut=-500,tIn=500; // Текущие температуры в сотых градуса !!! место экономим
uint16_t absHOut=123,absHIn=123; // Абсолютные влажности в сотых грамма на м*3 !!! место экономим
uint16_t relHOut=123,relHIn=123; // Относительные влажности сотых процента !!! место экономим
uint8_t flags=0x00; // байт флагов
// 0 бит - мотор включен/выключен
// 1 бит - нагреватель включен/выключен
// 2 бит -[1 - dH_min задается в сотых грамма на м*3] [0 - dH_min заадется в ДЕСЯТЫХ процента от absHIn]
// 3 4 - пока пусто
// 5-7 - номер настройки = settingRAM.mode до 8 настроек, надо передавать, что бы на приемнике восстановить
uint8_t dH_min; // Порог включения вентилятора по РАЗНИЦЕ абсолютной влажности в сотых грамма на м*3 или в ДЕСЯТЫХ % см flags:2
uint8_t T_min; // Порог выключения вентилятора по температуре в ДЕСЯТЫХ долях градуса, только положительные значения
uint8_t count=0; // циклический счетчик отправленных пакетов нужен что бы на приемнике проверять качество связи
char note[14] = "NONE"; // Примечание не более 13 байт + 0 байт Русские буквы в два раза меньше т.к. UTF-8
} packet_0x20[NUM_DRY];
// Cтруктура для графиков
struct type_chart_dry
{
byte tOutChart[120];
byte tInChart[120];
byte absHOutChart[120];
byte absHInChart[120];
byte posChart=0; // Позиция в массиве графиков - начало вывода от 0 до 120-1
byte TimeChart=0; // Время до вывода очередной точки на график.
bool ChartMotor=false; // Признак работы мотора во время интервала графика если мотор был включен на любое время то на графике фон меняется в этом месте
bool ChartHeat=false; // Признак работы нагревателя во время интервала графика если нагреватель был включен на любое время (даже одно измерение) то на графике фон меняется в этом месте
bool CoolData=false; // Признак наличия свежих данных, что бы лишний раз не выводить на экран одно и тоже
} chart_dry[NUM_DRY];
void dry_static(uint8_t ID) // Печать статической картинки
{ int i;
// Заголовок
ucg.setColor(0, 0, 180); //
ucg.drawBox(0, 0, 320-1, 23);
ucg.setColor(250, 250, 250);
ucg.setFontMode(UCG_FONT_MODE_TRANSPARENT);
ucg.setPrintPos(2,19);
ucg.print(newpos);
print_StrXY(2+12,19,F(".ОСУШИТЕЛЬ ID: 0x"));
ucg.print( hex(packet_0x20[ID].id >> 4));
ucg.print( hex(packet_0x20[ID].id&0x0f));
// Таблица для данных
ucg.setColor(0, 200, 0);
ucg.drawHLine(0,25,320-1);
ucg.drawHLine(0,25+23*1,320-1);
ucg.drawHLine(0,25+23*2,320-1);
ucg.drawHLine(0,25+23*3,320-1);
ucg.drawHLine(0,25+23*4,320-1);
ucg.drawVLine(200-4,25,24+23*3);
ucg.drawVLine(260,25,24+23*3);
// Заголовки таблиц
ucg.setColor(255, 255, 0);
// В зависимости от id разные надписи - привязка местоположения блока к ID
// print_StrXY(180+30-9,25+0+18,F(LABEL));
ucg.setPrintPos(1,25+0+18);
ucg.print(F("N/потери"));
print_StrXY(250+20,25+0+18,F("Улица"));
print_StrXY(0,25+23*1+18,F("Температура градусы C"));
print_StrXY(0,25+23*2+18,F("Относительная влаж. %"));
print_StrXY(0,25+23*3+18,F("Абсолют. влаж. г/м*3"));
// Графики
ucg.setColor(210, 210, 210);
print_StrXY(10,135+0,F("Температура"));
print_StrXY(20+154,135+0,F("Абс. влажность"));
// надписи на графиках
print_StrXY(128,154,F("+20"));
print_StrXY(135,194,F("0"));
print_StrXY(128,233,F("-20"));
print_StrXY(296,164,F("15"));
print_StrXY(296,194,F("10"));
print_StrXY(296,223,F("5"));
// Горизонтальная шкала по часам
// ucg.setColor(255, 255, 0);
for(i=0;i<=120;i=i+12)
{
ucg.drawPixel(4+i,239);
ucg.drawPixel(4+i,238);
ucg.drawPixel(167+i,239);
ucg.drawPixel(167+i,238);
}
}
void dry_data(uint8_t ID) // Печать панели статуса Значки на статус панели
{
// Заголовок
ucg.setColor(0, 0, 180); //
ucg.drawBox(168, 0, 320-1, 23);
ucg.setColor(250, 250, 250);
ucg.setFontMode(UCG_FONT_MODE_TRANSPARENT);
// print_StrXY(2,19,F("ОСУШИТЕЛЬ ID: 0x"));
ucg.setPrintPos(168,19);
ucg.print( hex(packet_0x20[ID].id >> 4));
ucg.print( hex(packet_0x20[ID].id&0x0f));
ucg.setFontMode(UCG_FONT_MODE_SOLID);
ucg.setPrintPos(100,19+24);
ucg.print(" ");
ucg.setPrintPos(100,19+24);
ucg.print(packet_0x20[ID].count);
ucg.print("/");
ucg.print(err_count);
// ucg.print(" >>");
// ucg.print(signalStrength);
// 1. печать ошибки чтения датчиков
// if (packet_0x20.error!=last_error) // если статус ошибки поменялся то надо вывести если нет то не выводим - экономия время и нет мерцания
{
last_error=packet_0x20[ID].DHT_error;
ucg.setColor(0, 0, 200); // Сначала стереть
ucg.drawBox(290, 0, 30, 18);
ucg.setPrintPos(290,18);
ucg.setFontMode(UCG_FONT_MODE_TRANSPARENT);
if (packet_0x20[ID].DHT_error>0) { ucg.setColor(240, 0, 0); ucg.print(packet_0x20[ID].DHT_error); }
else { ucg.setColor(200, 240, 0); ucg.print(F("ok")); }
}
// 2. Признак включения мотора
if (FLAG_MOTOR_CHECK) ucg.setColor(0, 240, 0);
else ucg.setColor(0, 40, 0);
ucg.drawBox(290-25, 5, 14, 14);
// Печать значений для дома
ucg.setFontMode(UCG_FONT_MODE_SOLID);
ucg.setColor(255, 255, 0);
// В зависимости от id разные надписи - привязка местоположения блока к ID
ucg.setPrintPos(180+30-9,25+0+18);
ucg.print(packet_0x20[ID].note);
ucg.setColor(250, 0, 100); // Цвет ДОМА
print_floatXY(200+0,25+23*1+18,((float)packet_0x20[ID].tIn)/100);
print_floatXY(200+0,25+23*2+18,((float)packet_0x20[ID].relHIn)/100);
print_floatXY(200+0,25+23*3+18,((float)packet_0x20[ID].absHIn)/100);
ucg.setColor(0, 250, 100); // Цвет УЛИЦЫ
print_floatXY(260+4,25+23*1+18,((float)packet_0x20[ID].tOut)/100);
print_floatXY(260+6,25+23*2+18,((float)packet_0x20[ID].relHOut)/100);
print_floatXY(260+6,25+23*3+18,((float)packet_0x20[ID].absHOut)/100);
// График
if (chart_dry[ID].TimeChart==0) dry_chart(ID); // когда выводится график на экран
}
// Печать графика на экране, добавляется одна точка и график сдвигается
void dry_chart(uint8_t ID)
{
byte i,x=0;
uint8_t tmp;
// if ((long)((long)chart_dry[ID].TimeChart*TIME_SCAN_SENSOR*NUM_SAMPLES)<(long)TIME_PRINT_CHART) return; // график еще рано выводить
for(i=0;i<120;i++) // График слева на право
{
// Вычислить координаты текущей точки x в кольцевом буфере. Изменяются от 0 до 120-1
if (chart_dry[ID].posChart<i) x=120+chart_dry[ID].posChart-i; else x=chart_dry[ID].posChart-i;
// нарисовать фон в зависимости от статуса мотора
if (chart_dry[ID].tInChart[x]>=0x80) ucg.setColor(0, 60, 90); // Мотор был ключен - бледно синий
else if (chart_dry[ID].tOutChart[x]>=0x80) ucg.setColor(90, 60, 0); // Нагреватель был ключен - бледно желтый
else ucg.setColor(0, 0, 0); // все выключено
ucg.drawVLine(5+120-i,237-100,100);
ucg.drawVLine(5+120-i+162,237-100,100);
ucg.setColor(180, 180, 180);
if (i%5==0) // Пунктирные линии графика
{
ucg.drawPixel(5+120-i,236-10-1);
ucg.drawPixel(5+120-i,236-50-1);
ucg.drawPixel(5+120-i,236-90-1);
ucg.drawPixel(5+120-i+162,236-25-1);
ucg.drawPixel(5+120-i+162,236-50-1);
ucg.drawPixel(5+120-i+162,236-75-1);
}
// Вывести новую точку
tmp=chart_dry[ID].tInChart[x]&0x7f; // Отбросить старший разряд - признак включения мотора
if ((tmp==0)||(tmp==100)) ucg.setColor(255, 255, 255); else ucg.setColor(255, 100, 100);
ucg.drawPixel(5+120-i,236-tmp);
tmp=chart_dry[ID].tOutChart[x]&0x7f; // Отбросить старший разряд - признак включения калорифера
if ((tmp==0) || (tmp==100)) ucg.setColor(255, 255, 255); else ucg.setColor(100, 255, 100);
ucg.drawPixel(5+120-i,236-tmp);
if (chart_dry[ID].absHInChart[x]==100) ucg.setColor(255, 255, 255); else ucg.setColor(255, 100, 100);
ucg.drawPixel(5+120-i+162,236-chart_dry[ID].absHInChart[x]);
if (chart_dry[ID].absHOutChart[x]==100) ucg.setColor(255, 255, 255); else ucg.setColor(100, 255, 100);
ucg.drawPixel(5+120-i+162,236-chart_dry[ID].absHOutChart[x]);
}
// if (chart_dry[ID].posChart<120-1) chart_dry[ID].posChart++; else chart_dry[ID].posChart=0; // Изменили положение в буфере и Замкнули буфер
}
// Получение данных это все в прерывании быстренько надо
bool dry_get_data(uint8_t *buf)
{
uint8_t ID;
if (buf[0]==0x21) ID=0;
if (buf[0]==0x22) ID=1;
memcpy(&packet_0x20[ID],buf,sizeof(type_packet_0x20_NRF24)); // скопировать из буфера в структуру
chart_dry[ID].CoolData=true; // Получены свежие данные
// Рисуем графики в памяти, а когда потребуется быстро выводим.
chart_dry[ID].TimeChart++;
if ((long)((long)chart_dry[ID].TimeChart*TIME_SCAN_SENSOR*NUM_SAMPLES)>=(long)TIME_PRINT_CHART) // проверка не пора ли добавлять точку на график
{
// Работаем через кольцевой буфер
// Добавить новую точку в кольцевой буфер
// Температура в доме. диапазон -25 . . . +25 растягиваем на 100 точек
if (packet_0x20[ID].tIn<=-2500) chart_dry[ID].tInChart[chart_dry[ID].posChart]=0; // Если температура меньше -25 то округляем до -25
else if (packet_0x20[ID].tIn>=2500) chart_dry[ID].tInChart[chart_dry[ID].posChart]=100-1; // Если температура больше 25 то округляем до 25
else chart_dry[ID].tInChart[chart_dry[ID].posChart]=(packet_0x20[ID].tIn+2500)/50; // внутри -25...+25 растягиваем в два раза
if (chart_dry[ID].ChartMotor==true) chart_dry[ID].tInChart[chart_dry[ID].posChart]|=0x80; // Признак включения мотора- старший бит в 1 - цвет фона на графике меняется
chart_dry[ID].ChartMotor=false;
// Температура на улице. диапазон -25 . . . +25 растягиваем на 100 точек
if (packet_0x20[ID].tOut<=-2500) chart_dry[ID].tOutChart[chart_dry[ID].posChart]=0; // Если температура меньше -25 то округляем до -25
else if (packet_0x20[ID].tOut>=2500) chart_dry[ID].tOutChart[chart_dry[ID].posChart]=100-1; // Если температура больше 25 то округляем до 25
else chart_dry[ID].tOutChart[chart_dry[ID].posChart]=(packet_0x20[ID].tOut+2500)/50; // внутри -25...+25 растягиваем в два раза
if (chart_dry[ID].ChartHeat==true) chart_dry[ID].tOutChart[chart_dry[ID].posChart]|=0x80; // Признак включения нагревателя- старший бит в 1 - цвет фона на графике меняется
chart_dry[ID].ChartHeat=false;
// Абсолютная влажность в доме диапазон от 0 до 20 грамм на кубометр, растягиваем на 100 точек
if (packet_0x20[ID].absHIn>=2000) chart_dry[ID].absHInChart[chart_dry[ID].posChart]=100-1;
else chart_dry[ID].absHInChart[chart_dry[ID].posChart]=packet_0x20[ID].absHIn/20; // внутри 0...20 растягиваем в пять раз в сотых % по этому делем не на 100 а на 20
// Абсолютная влажность на улицу диапазон от 0 до 20 грамм на кубометр, растягиваем на 100 точек
if (packet_0x20[ID].absHOut>=2000) chart_dry[ID].absHOutChart[chart_dry[ID].posChart]=100-1;
else chart_dry[ID].absHOutChart[chart_dry[ID].posChart]=packet_0x20[ID].absHOut/20; // внутри 0...20 растягиваем в пять раз, в сотых % по этому делем не на 100 а на 20
if (chart_dry[ID].posChart<120-1) chart_dry[ID].posChart++; else chart_dry[ID].posChart=0; // Изменили положение в буфере и Замкнули буфер
chart_dry[ID].TimeChart=0; // Сдвиг графика и вывод новой точки сброс счетчика
// dry_chart(ID);
}
}
void dry_update(uint8_t ID)
{
if (chart_dry[ID].CoolData==true)
{
dry_data(ID);
chart_dry[ID].CoolData=false;
}
}
3. rusFont.h
// Русский шрифт 10х14 ------------------------------------------------------
const ucg_fntpgm_uint8_t my14x10rus[4157] UCG_SECTION(".progmem.my14x10") = {
0,11,15,0,255,14,3,35,6,248,32,255,0,15,255,14,
0,0,0,0,8,0,0,2,14,14,4,1,0,64,192,192,
192,192,192,192,192,192,128,0,64,192,128,6,5,5,7,0,
9,68,204,204,204,136,10,14,28,11,0,0,8,128,8,128,
17,0,17,0,127,192,17,0,17,0,34,0,34,0,255,128,
34,0,34,0,68,0,68,0,9,14,28,10,0,0,8,0,
8,0,59,128,123,0,200,0,200,0,232,0,107,0,11,128,
9,128,9,128,111,0,238,0,8,0,8,14,14,9,0,0,
97,179,214,102,12,12,24,24,48,48,102,107,205,134,9,14,
28,10,0,0,56,0,124,0,108,0,108,0,108,0,56,0,
56,128,109,128,199,0,194,0,199,0,237,128,124,128,56,0,
2,5,5,3,0,10,128,192,192,192,64,5,14,14,6,0,
0,24,48,96,96,192,192,192,192,192,192,96,96,48,24,5,
14,14,6,0,0,192,96,48,48,24,24,24,24,24,24,56,
48,96,192,7,7,7,8,0,4,146,214,124,16,124,214,146,
8,10,10,10,0,1,8,24,24,24,127,254,24,24,24,16,
4,6,6,5,0,0,112,96,96,64,192,192,8,2,2,9,
0,5,127,254,3,3,3,4,0,0,224,160,224,8,14,14,
9,0,0,3,3,6,6,12,12,24,24,48,48,96,96,192,
192,9,14,28,10,0,0,62,0,127,0,227,128,197,128,197,
128,197,128,201,128,201,128,209,128,209,128,209,128,227,128,127,
0,62,0,9,14,28,10,0,0,12,0,28,0,60,0,124,
0,8,0,4,0,12,0,12,0,8,0,4,0,12,0,12,
0,127,128,255,128,9,14,28,10,0,0,126,0,255,0,195,
128,193,128,1,128,3,128,63,0,126,0,224,0,192,0,192,
0,192,0,223,128,191,0,9,14,28,10,0,0,126,0,255,
0,195,128,1,128,1,128,3,0,58,0,119,0,3,128,1,
128,1,128,3,128,255,0,126,0,9,14,28,10,0,0,2,
0,6,0,14,0,30,0,62,0,118,0,230,0,198,0,251,
128,247,0,6,0,6,0,6,0,4,0,9,14,28,10,0,
0,127,128,127,128,96,0,96,0,96,0,110,0,111,0,3,
128,1,128,1,128,1,128,195,0,255,0,124,0,9,14,28,
10,0,0,31,0,127,0,96,0,192,0,192,0,192,0,222,
0,223,0,195,128,193,128,193,128,227,0,127,0,60,0,9,
14,28,10,0,0,127,128,255,128,0,0,3,0,3,0,6,
0,6,0,12,0,12,0,24,0,24,0,48,0,48,0,32,
0,9,14,28,10,0,0,58,0,119,0,227,128,193,128,193,
128,99,0,54,0,111,0,227,128,193,128,193,128,227,128,119,
0,46,0,9,14,28,10,0,0,60,0,255,0,231,0,195,
128,193,128,193,128,225,128,253,128,125,128,1,128,3,128,7,
0,127,0,252,0,3,11,11,4,0,2,224,160,224,0,0,
0,0,0,224,160,224,4,13,13,5,0,0,112,80,112,0,
0,0,0,0,112,80,112,96,192,9,11,22,10,0,1,1,
128,3,128,15,0,28,0,120,0,224,0,120,0,28,0,15,
0,3,128,1,128,9,6,12,10,0,4,127,128,255,0,0,
0,0,0,127,128,255,0,9,11,22,10,0,1,192,0,224,
0,120,0,60,0,15,0,3,128,15,0,60,0,120,0,224,
0,192,0,8,14,14,9,0,0,116,238,135,3,3,6,14,
56,48,48,0,0,48,48,9,11,22,10,0,1,62,0,65,
0,128,128,154,128,166,128,162,128,162,128,166,128,155,0,64,
0,63,128,9,14,28,10,0,0,252,0,254,0,199,0,195,
128,193,128,193,128,193,128,253,128,253,128,193,128,193,128,193,
128,193,128,129,0,9,14,28,10,0,0,94,0,223,0,195,
128,193,128,193,128,195,128,255,0,255,0,195,128,193,128,193,
128,195,128,223,0,190,0,9,14,28,10,0,0,14,0,63,
0,115,128,97,128,192,0,192,0,192,0,192,0,192,0,192,
0,96,0,112,0,63,128,15,0,9,14,28,10,0,0,238,
0,111,0,99,128,97,128,97,128,97,128,97,128,97,128,97,
128,97,128,97,128,99,128,111,0,238,0,9,14,28,10,0,
0,95,128,223,0,192,0,192,0,192,0,192,0,223,0,222,
0,192,0,192,0,192,0,192,0,223,128,191,0,9,14,28,
10,0,0,95,128,223,0,192,0,192,0,192,0,192,0,223,
0,222,0,192,0,192,0,192,0,192,0,192,0,128,0,9,
14,28,10,0,0,63,128,127,128,225,128,192,0,192,0,192,
0,192,0,207,128,223,128,193,128,193,128,225,128,127,128,62,
0,9,14,28,10,0,0,129,0,193,128,193,128,193,128,193,
128,193,128,223,128,223,128,193,128,193,128,193,128,193,128,193,
128,64,128,8,14,14,10,1,0,254,127,24,24,24,24,24,
24,24,24,24,24,254,127,9,14,28,10,0,0,31,128,63,
128,1,128,1,128,1,128,1,128,1,128,1,128,1,128,1,
128,1,128,195,128,255,0,62,0,9,14,28,10,0,0,65,
128,195,128,199,0,206,0,220,0,216,0,216,0,216,0,216,
0,220,0,206,0,199,0,195,128,65,128,9,14,28,10,0,
0,64,0,192,0,192,0,192,0,192,0,192,0,192,0,192,
0,192,0,192,0,192,0,192,0,255,128,255,0,9,14,28,
10,0,0,193,128,227,128,247,128,247,128,213,128,193,128,213,
128,221,128,221,128,201,128,193,128,193,128,193,128,129,0,9,
14,28,10,0,0,225,0,225,128,241,128,241,128,249,128,217,
128,221,128,205,128,205,128,197,128,197,128,193,128,193,128,128,
128,9,14,28,10,0,0,46,0,111,0,227,128,193,128,193,
128,193,128,193,128,193,128,193,128,193,128,193,128,227,128,123,
0,58,0,9,14,28,10,0,0,254,0,255,0,195,128,193,
128,193,128,195,128,223,0,222,0,192,0,192,0,192,0,192,
0,192,0,128,0,10,15,30,10,0,255,46,0,111,0,227,
128,193,128,193,128,193,128,193,128,193,128,193,128,193,128,193,
128,227,0,123,128,58,192,0,192,9,14,28,10,0,0,126,
0,255,0,195,128,193,128,193,128,195,128,223,0,220,0,206,
0,199,0,195,128,193,128,193,128,129,0,9,14,28,10,0,
0,62,0,127,0,224,0,192,0,192,0,224,0,118,0,27,
0,3,128,1,128,1,128,3,128,255,128,127,0,9,14,28,
10,0,0,255,0,127,128,0,0,12,0,12,0,12,0,12,
0,12,0,12,0,12,0,12,0,12,0,12,0,4,0,9,
14,28,10,0,0,64,128,193,128,193,128,193,128,193,128,193,
128,193,128,193,128,193,128,193,128,193,128,99,0,127,0,62,
0,9,14,28,10,0,0,227,128,99,0,99,0,99,0,34,
0,54,0,54,0,54,0,20,0,28,0,28,0,28,0,8,
0,8,0,10,14,28,11,0,0,64,64,192,192,192,192,192,
192,192,192,192,192,204,192,204,192,204,192,222,192,222,192,211,
192,193,192,128,192,9,14,28,10,0,0,193,128,193,128,193,
128,99,0,99,0,50,0,56,0,28,0,14,0,103,0,99,
0,193,128,193,128,193,128,10,14,28,10,0,0,192,192,192,
192,97,128,97,128,51,0,63,0,30,0,12,0,8,0,4,
0,12,0,12,0,12,0,8,0,9,14,28,10,0,0,127,
128,255,128,1,128,3,128,7,0,6,0,4,0,16,0,48,
0,112,0,224,0,192,0,255,128,255,0,5,14,14,6,0,
0,248,192,192,192,192,192,192,192,192,192,192,192,192,248,9,
14,28,10,0,0,192,0,96,0,96,0,48,0,48,0,24,
0,24,0,12,0,12,0,6,0,6,0,3,0,3,0,1,
128,5,14,14,6,0,0,248,24,24,24,24,24,24,24,24,
24,24,24,24,248,9,6,12,10,0,8,8,0,28,0,54,
0,99,0,193,128,128,128,10,1,2,10,0,255,255,192,4,
3,3,5,0,12,224,96,48,8,11,11,9,0,0,124,127,
3,3,59,123,227,195,199,255,123,9,13,26,10,0,0,64,
0,192,0,192,0,192,0,192,0,222,0,223,0,195,128,193,
128,193,128,195,0,255,0,222,0,8,11,11,9,0,0,30,
63,115,224,192,192,192,224,240,127,30,9,13,26,10,0,0,
0,128,1,128,1,128,1,128,1,128,61,128,125,128,225,128,
193,128,193,128,227,128,127,128,61,128,8,11,11,9,0,0,
60,126,231,195,195,223,222,192,227,127,62,7,13,13,8,0,
0,62,124,96,96,252,248,96,96,96,96,96,96,32,8,13,
13,9,0,0,63,127,227,195,195,195,227,123,51,3,3,127,
254,8,13,13,9,0,0,64,192,192,192,222,223,195,195,195,
195,195,195,130,2,13,13,3,0,0,64,192,128,64,192,192,
192,192,192,192,192,192,128,5,14,14,6,0,255,16,24,24,
8,48,120,24,24,24,24,24,24,120,240,8,13,13,9,0,
0,64,192,192,198,198,204,216,216,216,204,198,199,131,2,14,
14,3,0,0,64,192,192,192,192,192,192,192,192,192,192,192,
192,128,9,11,22,10,0,0,91,0,219,128,201,128,201,128,
201,128,201,128,201,128,201,128,201,128,193,128,129,0,8,11,
11,9,0,0,94,223,195,195,195,195,195,195,195,195,130,8,
11,11,9,0,0,52,118,227,195,195,195,195,195,227,118,52,
8,11,11,9,0,0,252,254,199,195,199,222,220,192,192,192,
128,9,13,26,9,0,255,63,0,127,0,227,0,195,0,195,
0,195,0,251,0,123,0,3,0,3,0,3,128,3,128,3,
128,7,11,11,8,0,0,92,222,224,224,192,192,192,192,192,
192,128,8,11,11,9,0,0,62,127,192,192,240,102,15,3,
3,254,124,6,13,13,7,0,0,32,96,96,252,248,96,96,
96,96,96,96,124,60,8,11,11,9,0,0,65,195,195,195,
195,195,195,195,227,123,58,8,11,11,9,0,0,129,129,195,
195,102,102,102,36,60,24,24,9,11,22,10,0,0,128,128,
193,128,201,128,201,128,201,128,201,128,193,128,221,128,247,128,
227,128,65,0,8,11,11,9,0,0,195,102,102,52,24,24,
24,52,102,102,195,8,12,12,9,0,255,193,227,99,102,110,
44,12,24,24,48,240,224,8,11,11,9,0,0,127,255,7,
6,12,0,48,96,224,255,254,7,14,14,8,0,0,14,28,
24,24,24,48,224,224,48,24,24,24,28,14,2,16,16,5,
1,255,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
192,192,8,14,14,9,0,0,224,112,24,24,24,12,7,7,
12,24,24,24,112,224,10,5,10,11,0,4,48,192,120,192,
204,192,199,128,195,0,5,13,13,6,0,1,248,136,136,136,
136,136,136,136,136,136,136,136,248,8,11,11,9,0,0,252,
254,199,195,199,222,220,192,192,192,128,8,11,11,9,0,0,
30,63,115,224,192,192,192,224,240,127,30,8,11,11,9,0,
0,127,254,24,24,24,24,24,24,24,24,16,8,12,12,9,
0,255,193,227,99,102,110,44,12,24,24,48,240,224,8,12,
12,9,0,255,126,255,219,219,219,219,90,24,24,24,24,16,
8,11,11,9,0,0,195,102,102,52,24,24,24,52,102,102,
195,8,12,12,9,0,255,132,198,198,198,198,198,198,198,198,
254,255,3,8,11,11,9,0,0,65,195,195,195,231,127,63,
3,3,3,2,8,11,11,9,0,0,130,195,195,211,219,219,
219,219,219,203,255,8,12,12,9,0,255,130,195,195,211,219,
219,219,219,218,200,255,3,8,11,11,9,0,0,192,224,96,
96,108,110,103,99,103,126,124,8,11,11,9,0,0,130,195,
195,195,219,221,207,199,207,253,251,8,11,11,9,0,0,64,
192,192,192,220,222,199,195,199,254,252,8,11,11,9,0,0,
124,254,198,3,27,59,3,3,6,254,120,9,11,22,10,0,
0,71,0,207,128,205,128,205,128,221,128,221,128,205,128,205,
128,205,128,207,128,135,0,8,11,11,9,0,0,63,127,227,
195,227,123,59,51,51,115,226,9,14,28,10,0,0,252,0,
254,0,199,0,195,128,193,128,193,128,193,128,253,128,253,128,
193,128,193,128,193,128,193,128,129,0,9,14,28,10,0,0,
223,128,223,0,192,0,192,0,192,0,192,0,222,0,223,0,
195,128,193,128,193,128,195,128,255,0,254,0,9,14,28,10,
0,0,94,0,223,0,195,128,193,128,193,128,195,128,255,0,
255,0,195,128,193,128,193,128,195,128,223,0,190,0,9,14,
28,10,0,0,223,0,223,128,192,0,192,0,192,0,192,0,
192,0,192,0,192,0,192,0,192,0,192,0,192,0,128,0,
9,14,28,10,0,0,11,0,27,0,59,0,115,0,99,0,
99,0,99,0,99,0,99,0,99,0,123,0,251,128,193,128,
193,128,9,14,28,10,0,0,95,128,223,0,192,0,192,0,
192,0,192,0,223,0,222,0,192,0,192,0,192,0,192,0,
223,128,191,0,10,14,28,11,0,0,64,64,192,192,196,192,
204,192,204,192,109,128,109,128,109,128,109,128,204,192,204,192,
204,192,200,192,128,128,9,14,28,10,0,0,122,0,251,0,
131,128,1,128,1,128,3,0,58,0,123,0,3,128,1,128,
1,128,131,128,251,0,120,0,9,14,28,10,0,0,67,128,
195,128,199,128,199,128,199,128,205,128,205,128,205,128,217,128,
217,128,217,128,209,128,209,128,193,0,9,14,28,10,0,0,
91,128,219,128,215,128,199,128,199,128,205,128,205,128,205,128,
217,128,217,128,217,128,209,128,209,128,193,0,9,14,28,10,
0,0,65,128,195,128,199,0,206,0,220,0,216,0,216,0,
216,0,216,0,220,0,206,0,199,0,195,128,65,128,9,14,
28,10,0,0,220,0,222,0,199,0,195,128,193,128,193,128,
193,128,193,128,193,128,193,128,193,128,193,128,193,128,193,128,
9,14,28,10,0,0,193,128,227,128,247,128,247,128,213,128,
193,128,213,128,221,128,221,128,201,128,193,128,193,128,193,128,
129,0,9,14,28,10,0,0,129,0,193,128,193,128,193,128,
193,128,193,128,223,128,223,128,193,128,193,128,193,128,193,128,
193,128,64,128,9,14,28,10,0,0,46,0,111,0,227,128,
193,128,193,128,193,128,193,128,193,128,193,128,193,128,193,128,
227,128,123,0,58,0,9,14,28,10,0,0,223,128,223,128,
193,128,193,128,193,128,193,128,193,128,193,128,193,128,193,128,
193,128,193,128,193,128,129,0,9,14,28,10,0,0,254,0,
255,0,195,128,193,128,193,128,195,128,223,0,222,0,192,0,
192,0,192,0,192,0,192,0,128,0,9,14,28,10,0,0,
14,0,63,0,115,128,97,128,192,0,192,0,192,0,192,0,
192,0,192,0,96,0,112,0,63,128,15,0,9,14,28,10,
0,0,255,0,127,128,0,0,12,0,12,0,12,0,12,0,
12,0,12,0,12,0,12,0,12,0,12,0,4,0,9,14,
28,10,0,0,129,0,193,128,193,128,193,128,193,128,125,128,
61,128,1,128,1,128,1,128,193,128,225,128,127,0,62,0,
10,14,28,11,0,0,63,0,127,128,237,192,204,192,204,192,
237,192,109,128,45,0,12,0,12,0,12,0,12,0,12,0,
4,0,9,14,28,10,0,0,193,128,193,128,193,128,99,0,
99,0,50,0,56,0,28,0,14,0,103,0,99,0,193,128,
193,128,193,128,10,15,30,10,0,255,130,0,195,0,195,0,
195,0,195,0,195,0,195,0,195,0,195,0,195,0,195,0,
195,0,223,0,223,128,1,192,9,14,28,10,0,0,129,0,
193,128,193,128,193,128,193,128,193,128,225,128,125,128,61,128,
1,128,1,128,1,128,1,128,0,128,10,14,28,11,0,0,
128,128,192,192,192,192,192,192,200,192,204,192,204,192,204,192,
204,192,204,192,196,192,192,64,223,128,95,192,11,15,30,11,
0,255,128,128,192,192,192,192,192,192,200,192,204,192,204,192,
204,192,204,192,204,192,196,192,192,64,223,128,95,192,0,224,
9,14,28,10,0,0,224,0,224,0,96,0,96,0,96,0,
96,0,110,0,111,0,99,128,97,128,97,128,99,128,127,0,
62,0,10,14,28,11,0,0,128,128,192,192,192,192,192,192,
192,192,192,192,220,192,222,192,199,64,195,64,195,64,199,64,
254,192,124,192,9,14,28,10,0,0,128,0,192,0,192,0,
192,0,192,0,192,0,222,0,223,0,195,128,193,128,193,128,
195,128,255,0,254,0,9,14,28,10,0,0,62,0,127,0,
227,128,193,128,193,128,1,128,29,128,29,128,1,128,1,128,
193,128,227,128,127,0,62,0,10,14,28,11,0,0,71,0,
207,128,221,192,216,192,216,192,216,192,248,192,248,192,216,192,
216,192,216,192,221,192,207,128,135,0,9,14,28,10,0,0,
63,128,127,128,225,128,193,128,193,128,225,128,125,128,61,128,
29,128,57,128,113,128,225,128,193,128,129,0,8,11,11,9,
0,0,124,127,3,3,59,123,227,195,199,255,123,8,11,11,
9,0,0,7,31,56,112,102,207,195,195,231,126,60,8,11,
11,9,0,0,92,222,198,198,220,222,195,195,199,222,188,8,
11,11,9,0,0,254,255,192,192,192,192,192,192,192,192,128,
10,11,22,11,0,0,31,128,31,128,25,128,49,128,49,128,
49,128,1,128,127,192,255,192,192,192,192,192,8,11,11,9,
0,0,60,126,231,195,195,223,222,192,227,127,62,9,11,22,
10,0,0,64,128,201,128,201,128,107,0,54,0,54,0,107,
0,201,128,201,128,201,128,129,0,8,11,11,9,0,0,116,
246,195,7,126,62,6,3,7,254,124,8,11,11,9,0,0,
65,195,195,199,207,223,219,211,195,195,130,8,11,11,9,0,
0,89,219,211,199,207,223,219,211,195,195,130,8,11,11,9,
0,0,71,207,204,220,216,216,216,220,206,199,67,8,11,11,
9,0,0,27,59,115,227,195,195,195,195,195,195,195,9,11,
22,10,0,0,65,0,227,128,247,128,247,128,213,128,213,128,
213,128,213,128,193,128,193,128,129,0,8,11,11,9,0,0,
65,195,195,251,251,195,195,195,195,195,130,8,11,11,9,0,
0,52,118,227,195,195,195,195,195,227,118,52,8,11,11,9,
0,0,95,223,195,195,195,195,195,195,195,195,130,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255};
Изображение устройства и конструктив






Я адапитровал под stm32 две библиотеки радиомодуля и дисплея. Их надо ставить в среду Arduino. Библиотеки идут для arm и avr. При компиляции для arm надо убедится сто библиотека SPI берется из паки arm а не avr
К сожалению на форум нельзя выкладывать zip архивы. Поэтому буду описывать что менял или выкладывать измененные файлы.
1. Для радио модуля используется библиотека TMRh20s ссылки: http://tmrh20.blogspot.ru/ и https://github.com/TMRh20
1. Исправления в модуле RF24.cpp для работы maple mini Было в функции void RF24::csn(bool mode)
_SPI.setBitOrder(MSBFIRST);
_SPI.setDataMode(SPI_MODE0);
_SPI.setClockDivider(SPI_CLOCK_DIV2); // Понизить частоту !!!!!
#endif
#if !defined (SOFTSPI)
_SPI.setBitOrder(MSBFIRST);
_SPI.setDataMode(SPI_MODE0);
_SPI.setClockDivider(SPI_CLOCK_DIV4); // Чип не успевал понизил частоту в два раза
#endif
// --- STM32 ------
#define _BV(x) (1<<(x))
#define printf_P printf
Начинать работу надо с компиляции blink (после установки софта https://github.com/rogerclarkmelbourne/Arduino_STM32)
В исходнике поменять ногу 13 на PB1. Если сетодиод начнет мигать, значит кроскомпиляция на arm настроена и загрука кода в модуль успешна. Только ТОГДА надо начинать компилить мои исходники и доставлять библиотеки, иначе не разберетесь.
pav2000, можете загрузить архив на яндекс диск или дропбокс?
классно получилось)
но вот по корпусу есть предложения на будущее
1. внешний вид. фаски скругления и т.д. не стоит забывать. винты заменить напирмер на такие, только наверно без насечек, и такие там есть
http://ru.aliexpress.com/item/Carbon-Steel-50Pcs-Bag-M3-8mm-Countersunk-Hexagon-Socket-Inside-Black-Head-Screws/32309356123.html?spm=2114.03020208.3.1.Zo5vtt&ws_ab_test=201526_1,201527_3_10_71_9_72_73_74_75_11_12,201409_2
да и цвет пластика применить другой например
2. ручку применять готовую, стоит копейки
http://ru.aliexpress.com/item/New-1PCS-Adjustable-6mm-Knurled-Shaft-Potentiometer-Volume-Control-Rotary-Knob/2034811612.html?spm=2114.03020208.3.38.y1Jjlo&ws_ab_test=201526_1,201527_3_71_72_73_74_75,201409_2
3. выключатель
http://ru.aliexpress.com/item/High-Quality-Snap-In-Rocker-LED-Indicator-Switch-3-Pin-On-Off-12V-Red/32435791706.html?spm=2114.03020208.3.69.wvIsrJ&ws_ab_test=201526_1,201527_3_71_72_73_74_75,201409_2
http://ru.aliexpress.com/item/2015-Hot-5-x-AC-250V-3A-2-Pin-ON-OFF-I-O-SPST-Snap-in/32374495371.html?spm=2114.03020208.3.2.wvIsrJ&ws_ab_test=201526_1,201527_3_71_72_73_74_75,201409_2
и наверно не стоит слишком много цветов на дисплее применять. даже темно синий на белом фоне прекранно выклядить будет, да и к корпусу больше подходить
ну это мое мнение
хотя к твоему корпусу лучше белые выключатели
http://ru.aliexpress.com/item/Audew-2015-Brand-New-2-Pins-Way-Round-ON-O...
http://ru.aliexpress.com/item/Free-Delivery-Rocker-Rocker-switch-3A-high...
На каком 3д принтере этот корпус печатался? Есть желание освоить печать...Но всему свое время...
В качестве резервного питания использую литевый аккумулятор 18650, с блоком зарядки. Обычно устройство питается от 5 вольт. Автономно дережет часов 10-15.
Если запрограммировать отключение подсветки экрана, или поставить кнопку и т.д. То можно значительно увеличить время автономной работы... По даташиту потребление на 1группу светодиодов подсветки идет 15-20мА, а их там от 2х до 4х групп ( ! 80мА), в зависимости от размера дисплея...
А расскажите немного подробней про организацию загрузки в maple.
Есть следующее - maple mini на stm32f103 внешне один в один Ваш, WindowsXP и свежайший arduino-1.6.5-r5. Добавляем в последний поддержку Duo - он выкачивает, ставит без замечаний. В папке, где проекты, делаем новую папку hardware, в неё распаковываем Arduino_STM32-master. Приступаем к драйверам и облом - install_drivers.bat ругается ехе-шники не запускаются, видно требуют Win7 или выше. Ладно, обратимся к первоисточнику, качаем libusb-win32-bin-1.2.6.0 - становится, теперь при подключении контролера в диспетчере устройств есть вкладка libusb, а в ней MapleDFU корректно стоит. Запускаем ардуино, выбираем плату Maple mini и версию Bootloader - Original. Пытаемся собрать и залить пустой проект, собирается, но не заливается, обнаруживается отсутствие драйвера порта - успешно ставим драйвер MapleSerial (ранее его не спрашивало и порта небыло). Теперь картина такая - после подключения (или ребута) контроллера наблюдается кратковременное , быстрое мигание светодиода на нем (ну bootloader работает) , затем медленное мигание (запустился залитый китайцами скетч) затем через гдето секунду все гаснет. Винда во время этих дел меняет драйвера - сразу запускает DFU, затем он исчезает и стартует MapleSerial, на нем и успокаивается. Это нормальное поведение, у Вас так же?
Аналогично ведет себя при попытке собрать и залить пустой проект, в сообщениях имеем
Изменена опция сборки, пересобираем все
Usb порт maple mini функционирует в двух режимах программирования (dfu) и эмуляции последовательного порта (serial).
Переключение между режимами работает у меня не четко. Есть возможность принудительного перевода в режим программирования. У платы есть две кнопки. Нажимаете на сброс а потом другую кнопку (та которая ближе к узкому краю платы) очень быстро. У меня это получается не с первого раза. Светодиод будет мигать бесконечно (добейтесь этого). Это режим программирования. Скейч должен залится. Светодиод погаснет.
У меня под убунту порт платы чаще переводится в режим программирования и очень трудно перевести в режим последовательного порта. Под вин хр и 7 я очень часто пользуюсь принудительным режимом который описан выше. А режим последовательного порта почти всегда доступен.
Понял, спасибо, буду бодатся дальше. Всетаки 72МГц по цене 16-и того стоят )))
Очередная версия кода.
Основные изменения:
1. Перешол на другую графическую библиотеку Adafruit_GFX_AS (идет в поставке с https://github.com/rogerclarkmelbourne/Arduino_STM32)
2. Русифицировал ее (спасибо arduinec http://arduino.ru/forum/programmirovanie/rusifikatsiya-biblioteki-adafruit-gfx-i-vyvod-russkikh-bukv-na-displei-v-kodi) использовал его функция (кажется доработал) и встроенный шрифт. Адаптировал для Adafruit_GFX_AS. Скорость возрасла на порядок, перерисовка экрана почти не замета - используется spi через DMA. Очень нравится (+ еще 2 кбайта кода уменьшилось)
3. Adafruit_GFX_AS позволяет использовать несколько шрифтов. Разработал шрифт 8*16 и заменил стандартный Font16. 224 символа кодировка 1251 (из UTF8 перевожу через функцию см п.2)
Заменить Font16.c
// Font size 2 #include "Font32.h" //#include <avr/pgmspace.h> #ifdef __AVR__ #include <avr/io.h> #include <avr/pgmspace.h> #else #define PROGMEM #endif PROGMEM const unsigned char widtbl_f16[224] = // character width table { 5, 2, 6, 9, 7, 9, 9, 2, // char 32 - 39 4, 4, 7, 8, 3, 5, 2, 8, // char 40 - 47 8, 8, 8, 8, 8, 8, 8, 8, // char 48 - 55 8, 8, 2, 3, 8, 8, 8, 7, // char 56 - 63 9, 8, 8, 8, 8, 0, 8, 8, // char 64 - 71 8, 6, 8, 8, 8, 8, 8, 8, // char 72 - 79 8, 8, 9, 8, 8, 8, 8, 9, // char 80 - 87 8, 9, 8, 4, 8, 4, 9, 9, // char 88 - 95 4, 8, 8, 8, 8, 0, 7, 8, // char 96 - 103 8, 8, 5, 8, 7, 8, 8, 8, // char 104 - 111 8, 8, 7, 8, 7, 8, 8, 9, // char 112 - 119 8, 8, 8, 6, 2, 6, 8, 0, // char 120 - 127 9, 8, 3, 6, 7, 8, 8, 8, // char 128 - 135 8, 9, 9, 4, 9, 8, 9, 8, // char 136 - 143 9, 3, 3, 7, 7, 6, 9, 9, // char 144 - 151 0, 9, 9, 4, 9, 8, 9, 7, // char 152 - 159 8, 0, 8, 8, 6, 8, 2, 7, // char 160 - 167 8, 9, 8, 8, 8, 5, 9, 6, // char 168 - 175 5, 8, 6, 8, 6, 9, 8, 2, // char 176 - 183 8, 9, 8, 8, 5, 8, 8, 8, // char 184 - 191 8, 8, 8, 8, 9, 8, 9, 8, // char 192 - 199 8, 8, 8, 9, 8, 8, 8, 8, // char 200 - 207 8, 8, 8, 9, 8, 8, 9, 8, // char 208 - 215 8, 9, 9, 9, 8, 7, 9, 8, // char 216 - 223 8, 8, 8, 6, 9, 8, 9, 7, // char 224 - 231 8, 8, 8, 9, 8, 8, 8, 8, // char 232 - 239 8, 8, 6, 8, 8, 8, 9, 8, // char 240 - 247 8, 9, 9, 9, 8, 7, 9, 8 // char 248 - 255 }; // Row format, MSB left PROGMEM const unsigned char chr_f16_20[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_21[16] = // 1 byte per row { 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, // row 1 - 11 0x00, 0xC0, 0xC0, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_22[16] = // 1 byte per row { 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_23[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x0D, 0x80, 0x09, 0x80, 0x19, 0x80, 0x7F, 0x80, // row 1 - 6 0x7F, 0x80, 0x13, 0x00, 0x33, 0x00, 0xFF, 0x80, 0xFF, 0x80, 0x26, 0x00, // row 7 - 12 0x66, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_24[16] = // 1 byte per row { 0x00, 0x00, 0x10, 0x10, 0x7C, 0xFC, 0xD0, 0xF0, 0x7C, 0x1E, 0x16, // row 1 - 11 0x96, 0xFE, 0x7C, 0x10, 0x10 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_25[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, // row 1 - 6 0x71, 0x80, 0x06, 0x00, 0x38, 0x00, 0xC7, 0x00, 0x08, 0x80, 0x08, 0x80, // row 7 - 12 0x08, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_26[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x7E, 0x00, 0x62, 0x00, 0x60, 0x00, // row 1 - 6 0x30, 0x00, 0x78, 0x00, 0x5D, 0x80, 0xCD, 0x80, 0xC7, 0x80, 0xE7, 0x00, // row 7 - 12 0x7F, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_27[16] = // 1 byte per row { 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_28[16] = // 1 byte per row { 0x00, 0x00, 0x30, 0x60, 0x60, 0x60, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // row 1 - 11 0xC0, 0x60, 0x60, 0x60, 0x30 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_29[16] = // 1 byte per row { 0x00, 0x00, 0xC0, 0x60, 0x60, 0x20, 0x30, 0x30, 0x30, 0x30, 0x30, // row 1 - 11 0x30, 0x60, 0x60, 0x60, 0xC0 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_2A[16] = // 1 byte per row { 0x00, 0x00, 0x10, 0x10, 0xD6, 0x7C, 0x7C, 0xD6, 0x10, 0x10, 0x00, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_2B[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, // row 1 - 11 0x18, 0x18, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_2C[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row 1 - 11 0x60, 0x60, 0x60, 0x60, 0xC0 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_2D[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_2E[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row 1 - 11 0xC0, 0xC0, 0xC0, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_2F[16] = // 1 byte per row { 0x00, 0x00, 0x03, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x18, 0x18, 0x30, // row 1 - 11 0x30, 0x60, 0x60, 0xC0, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_30[16] = // 1 byte per row { 0x00, 0x00, 0x3C, 0x7E, 0x67, 0xC3, 0xC3, 0xDB, 0xDB, 0xC3, 0xC3, // row 1 - 11 0x66, 0x7E, 0x3C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_31[16] = // 1 byte per row { 0x00, 0x00, 0x38, 0x78, 0x58, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // row 1 - 11 0x18, 0xFF, 0xFF, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_32[16] = // 1 byte per row { 0x00, 0x00, 0x7C, 0xFE, 0x83, 0x03, 0x03, 0x06, 0x0C, 0x18, 0x30, // row 1 - 11 0x60, 0xFF, 0xFF, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_33[16] = // 1 byte per row { 0x00, 0x00, 0x7C, 0xFE, 0x83, 0x03, 0x03, 0x3E, 0x3E, 0x07, 0x03, // row 1 - 11 0x83, 0xFF, 0x7C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_34[16] = // 1 byte per row { 0x00, 0x00, 0x0E, 0x0E, 0x1E, 0x36, 0x26, 0x66, 0xC6, 0xFF, 0xFF, // row 1 - 11 0x06, 0x06, 0x06, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_35[16] = // 1 byte per row { 0x00, 0x00, 0xFE, 0xFE, 0xC0, 0xC0, 0xFC, 0xFE, 0x87, 0x03, 0x03, // row 1 - 11 0x87, 0xFE, 0x7C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_36[16] = // 1 byte per row { 0x00, 0x00, 0x3C, 0x7E, 0x62, 0xC0, 0xDC, 0xFE, 0xE7, 0xC3, 0xC3, // row 1 - 11 0xE7, 0x7E, 0x3C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_37[16] = // 1 byte per row { 0x00, 0x00, 0xFF, 0xFF, 0x07, 0x06, 0x0E, 0x0C, 0x0C, 0x18, 0x18, // row 1 - 11 0x30, 0x30, 0x60, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_38[16] = // 1 byte per row { 0x00, 0x00, 0x3C, 0x7E, 0xC3, 0xC3, 0xC3, 0x7E, 0x7E, 0xC3, 0xC3, // row 1 - 11 0xC3, 0xFF, 0x3C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_39[16] = // 1 byte per row { 0x00, 0x00, 0x3C, 0x7E, 0xE7, 0xC3, 0xC3, 0xE7, 0x7F, 0x3B, 0x03, // row 1 - 11 0x46, 0x7E, 0x3C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_3A[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0x00, 0x00, // row 1 - 11 0xC0, 0xC0, 0xC0, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_3B[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x60, 0x00, 0x00, // row 1 - 11 0x60, 0x60, 0x60, 0x60, 0xC0 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_3C[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0F, 0x3C, 0xE0, 0xE0, 0x3C, // row 1 - 11 0x0F, 0x01, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_3D[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, // row 1 - 11 0xFF, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_3E[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xF0, 0x3C, 0x07, 0x07, 0x3C, // row 1 - 11 0xF0, 0x80, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_3F[16] = // 1 byte per row { 0x00, 0x00, 0x7C, 0xFE, 0x86, 0x06, 0x0C, 0x1C, 0x30, 0x30, 0x30, // row 1 - 11 0x00, 0x30, 0x30, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_40[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x3F, 0x00, 0x73, 0x80, // row 1 - 6 0xE1, 0x80, 0xCF, 0x80, 0xDF, 0x80, 0xD9, 0x80, 0xDF, 0x80, 0xCF, 0x80, // row 7 - 12 0x60, 0x00, 0x71, 0x00, 0x3F, 0x80, 0x1F, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_41[16] = // 1 byte per row { 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x3C, 0x66, 0x66, 0x7E, 0x7E, // row 1 - 11 0x66, 0xE7, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_42[16] = // 1 byte per row { 0x00, 0x00, 0xFE, 0xFF, 0xC3, 0xC3, 0xC3, 0xFE, 0xFE, 0xC3, 0xC3, // row 1 - 11 0xC3, 0xFF, 0xFE, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_43[16] = // 1 byte per row { 0x00, 0x00, 0x1E, 0x7F, 0x61, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // row 1 - 11 0x61, 0x7F, 0x1E, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_44[16] = // 1 byte per row { 0x00, 0x00, 0xF8, 0xFE, 0xC6, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, // row 1 - 11 0xC6, 0xFE, 0xF8, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_45[1] = { 0 }; // empty character PROGMEM const unsigned char chr_f16_46[16] = // 1 byte per row { 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFE, 0xFE, 0xC0, 0xC0, // row 1 - 11 0xC0, 0xC0, 0xC0, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_47[16] = // 1 byte per row { 0x00, 0x00, 0x1E, 0x7F, 0x61, 0xC0, 0xC0, 0xC0, 0xCF, 0xCF, 0xC3, // row 1 - 11 0x63, 0x7F, 0x1E, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_48[16] = // 1 byte per row { 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xC3, 0xC3, // row 1 - 11 0xC3, 0xC3, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_49[16] = // 1 byte per row { 0x00, 0x00, 0xFC, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // row 1 - 11 0x30, 0xFC, 0xFC, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_4A[16] = // 1 byte per row { 0x00, 0x00, 0x1F, 0x1F, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // row 1 - 11 0x83, 0xFF, 0x7C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_4B[16] = // 1 byte per row { 0x00, 0x00, 0xC7, 0xCE, 0xCC, 0xD8, 0xF8, 0xF8, 0xF8, 0xCC, 0xCE, // row 1 - 11 0xC6, 0xC7, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_4C[16] = // 1 byte per row { 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // row 1 - 11 0xC0, 0xFF, 0xFF, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_4D[16] = // 1 byte per row { 0x00, 0x00, 0xE7, 0xE7, 0xE7, 0xFF, 0xFF, 0xDB, 0xDB, 0xDB, 0xC3, // row 1 - 11 0xC3, 0xC3, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_4E[16] = // 1 byte per row { 0x00, 0x00, 0xE3, 0xE3, 0xE3, 0xF3, 0xD3, 0xDB, 0xDB, 0xCB, 0xCF, // row 1 - 11 0xC7, 0xC7, 0xC7, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_4F[16] = // 1 byte per row { 0x00, 0x00, 0x3C, 0x7E, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, // row 1 - 11 0x66, 0x7E, 0x3C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_50[16] = // 1 byte per row { 0x00, 0x00, 0xFC, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF, 0xFC, 0xC0, 0xC0, // row 1 - 11 0xC0, 0xC0, 0xC0, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_51[16] = // 1 byte per row { 0x00, 0x00, 0x3C, 0x7E, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, // row 1 - 11 0x67, 0x7E, 0x3C, 0x06, 0x02 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_52[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0xFF, 0x00, 0xC3, 0x00, 0xC3, 0x00, // row 1 - 6 0xC3, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xCE, 0x00, 0xC7, 0x00, 0xC3, 0x00, // row 7 - 12 0xC3, 0x00, 0xC3, 0x80, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_53[16] = // 1 byte per row { 0x00, 0x00, 0x3C, 0x7E, 0xC2, 0xC0, 0xE0, 0x7C, 0x3E, 0x07, 0x03, // row 1 - 11 0x83, 0xFF, 0x7C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_54[16] = // 1 byte per row { 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // row 1 - 11 0x18, 0x18, 0x18, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_55[16] = // 1 byte per row { 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, // row 1 - 11 0xE7, 0x7E, 0x3C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_56[16] = // 1 byte per row { 0x00, 0x00, 0xC3, 0xE7, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, // row 1 - 11 0x3C, 0x3C, 0x3C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_57[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0xC0, 0x80, 0xC0, 0x80, 0xC0, 0x80, 0xCC, 0x80, // row 1 - 6 0x6D, 0x80, 0x6D, 0x80, 0x6D, 0x80, 0x6D, 0x80, 0x73, 0x80, 0x73, 0x80, // row 7 - 12 0x73, 0x80, 0x73, 0x80, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_58[16] = // 1 byte per row { 0x00, 0x00, 0xE7, 0x66, 0x6E, 0x3C, 0x3C, 0x18, 0x18, 0x3C, 0x3C, // row 1 - 11 0x66, 0x66, 0xE7, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_59[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0xE1, 0x80, 0x61, 0x80, 0x73, 0x80, 0x33, 0x00, // row 1 - 6 0x3F, 0x00, 0x1E, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, // row 7 - 12 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_5A[16] = // 1 byte per row { 0x00, 0x00, 0xFF, 0xFF, 0x07, 0x0E, 0x0C, 0x1C, 0x38, 0x30, 0x70, // row 1 - 11 0xE0, 0xFF, 0xFF, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_5B[16] = // 1 byte per row { 0x00, 0x00, 0xF0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // row 1 - 11 0xC0, 0xC0, 0xC0, 0xC0, 0xF0 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_5C[16] = // 1 byte per row { 0x00, 0x00, 0xC0, 0x40, 0x60, 0x20, 0x30, 0x10, 0x18, 0x08, 0x0C, // row 1 - 11 0x04, 0x06, 0x02, 0x03, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_5D[16] = // 1 byte per row { 0x00, 0x00, 0xF0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // row 1 - 11 0x30, 0x30, 0x30, 0x30, 0xF0 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_5E[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x3E, 0x00, 0x77, 0x00, 0xE3, 0x80, // row 1 - 6 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row 7 - 12 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_5F[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row 1 - 6 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row 7 - 12 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_60[16] = // 1 byte per row { 0x00, 0xC0, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_61[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7F, 0x43, 0x1F, 0x7F, 0xE3, // row 1 - 11 0xC7, 0xFF, 0x7B, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_62[16] = // 1 byte per row { 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xDC, 0xFE, 0xE7, 0xC3, 0xC3, 0xC3, // row 1 - 11 0xE7, 0xFE, 0xDC, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_63[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7F, 0xE1, 0xC0, 0xC0, 0xC0, // row 1 - 11 0xE1, 0x7F, 0x3E, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_64[16] = // 1 byte per row { 0x00, 0x00, 0x03, 0x03, 0x03, 0x3B, 0x7F, 0xE7, 0xC3, 0xC3, 0xC3, // row 1 - 11 0xE7, 0x7F, 0x3B, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_65[1] = { 0 }; // empty character PROGMEM const unsigned char chr_f16_66[16] = // 1 byte per row { 0x00, 0x00, 0x1E, 0x3E, 0x30, 0xFE, 0xFE, 0x30, 0x30, 0x30, 0x30, // row 1 - 11 0x30, 0x30, 0x30, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_67[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x7F, 0xE7, 0xC3, 0xC3, 0xC3, // row 1 - 11 0xE7, 0x7F, 0x3B, 0x43, 0x7F // row 12 - 16 }; PROGMEM const unsigned char chr_f16_68[16] = // 1 byte per row { 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xDE, 0xFF, 0xE3, 0xC3, 0xC3, 0xC3, // row 1 - 11 0xC3, 0xC3, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_69[16] = // 1 byte per row { 0x00, 0x18, 0x18, 0x18, 0x00, 0x78, 0x78, 0x18, 0x18, 0x18, 0x18, // row 1 - 11 0x18, 0xFF, 0xFF, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_6A[16] = // 1 byte per row { 0x00, 0x18, 0x18, 0x18, 0x00, 0x78, 0x78, 0x18, 0x18, 0x18, 0x18, // row 1 - 11 0x18, 0x18, 0x18, 0x18, 0xF8 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_6B[16] = // 1 byte per row { 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xCE, 0xDC, 0xD8, 0xF0, 0xF8, 0xDC, // row 1 - 11 0xCC, 0xC6, 0xC7, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_6C[16] = // 1 byte per row { 0x00, 0x00, 0xF0, 0xF0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // row 1 - 11 0x30, 0x3E, 0x1E, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_6D[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xDB, 0xDB, 0xDB, 0xDB, // row 1 - 11 0xDB, 0xDB, 0xDB, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_6E[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xFF, 0xE3, 0xC3, 0xC3, 0xC3, // row 1 - 11 0xC3, 0xC3, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_6F[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0xE7, 0xC3, 0xC3, 0xC3, // row 1 - 11 0xE7, 0x7E, 0x3C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_70[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xFE, 0xE7, 0xC3, 0xC3, 0xC3, // row 1 - 11 0xE7, 0xFE, 0xDC, 0xC0, 0xC0 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_71[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x7F, 0xE7, 0xC3, 0xC3, 0xC3, // row 1 - 11 0xE7, 0x7F, 0x3B, 0x03, 0x03 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_72[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xFE, 0xE0, 0xC0, 0xC0, 0xC0, // row 1 - 11 0xC0, 0xC0, 0xC0, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_73[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFF, 0xC1, 0xFC, 0x7E, 0x07, // row 1 - 11 0x83, 0xFF, 0x7E, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_74[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x30, 0x30, 0xFE, 0xFE, 0x30, 0x30, 0x30, 0x30, // row 1 - 11 0x30, 0x3E, 0x1E, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_75[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, // row 1 - 11 0xC7, 0xFF, 0x7B, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_76[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xE7, 0x66, 0x66, 0x66, 0x3C, // row 1 - 11 0x3C, 0x3C, 0x18, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_77[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x80, // row 1 - 6 0xC0, 0x80, 0xCC, 0x80, 0x4C, 0x80, 0x6D, 0x80, 0x7F, 0x80, 0x73, 0x80, // row 7 - 12 0x33, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_78[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x66, 0x3C, 0x3C, 0x18, 0x3C, // row 1 - 11 0x3C, 0x66, 0xE7, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_79[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x67, 0x66, 0x76, 0x3E, 0x3C, // row 1 - 11 0x1C, 0x1C, 0x18, 0x18, 0x70 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_7A[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x06, 0x0C, 0x18, 0x30, // row 1 - 11 0x60, 0xFF, 0xFF, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_7B[16] = // 1 byte per row { 0x00, 0x00, 0x1C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xC0, 0x30, // row 1 - 11 0x30, 0x30, 0x30, 0x30, 0x30 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_7C[16] = // 1 byte per row { 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // row 1 - 11 0xC0, 0xC0, 0xC0, 0xC0, 0xC0 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_7D[16] = // 1 byte per row { 0x00, 0x00, 0xE0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x0C, 0x30, // row 1 - 11 0x30, 0x30, 0x30, 0x30, 0x30 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_7E[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0xFF, 0x8E, 0x00, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_7F[1] = { 0 }; // empty character PROGMEM const unsigned char chr_f16_80[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, // row 1 - 6 0x77, 0x00, 0x7F, 0x80, 0x73, 0x80, 0x71, 0x80, 0x71, 0x80, 0x71, 0x80, // row 7 - 12 0x71, 0x80, 0x71, 0x80, 0x01, 0x80, 0x03, 0x80 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_81[16] = // 1 byte per row { 0x18, 0x00, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // row 1 - 11 0xC0, 0xC0, 0xC0, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_82[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row 1 - 11 0x60, 0x60, 0x60, 0x60, 0xC0 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_83[16] = // 1 byte per row { 0x00, 0x0C, 0x18, 0x30, 0x00, 0xFC, 0xFC, 0xC0, 0xC0, 0xC0, 0xC0, // row 1 - 11 0xC0, 0xC0, 0xC0, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_84[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row 1 - 11 0x66, 0x66, 0x66, 0x66, 0xCC // row 12 - 16 }; PROGMEM const unsigned char chr_f16_85[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row 1 - 11 0xDB, 0xDB, 0xDB, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_86[16] = // 1 byte per row { 0x00, 0x00, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0x18, // row 1 - 11 0x18, 0x18, 0x18, 0x18, 0x18 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_87[16] = // 1 byte per row { 0x00, 0x00, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0x18, // row 1 - 11 0xFF, 0xFF, 0x18, 0x18, 0x18 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_88[16] = // 1 byte per row { 0x00, 0x00, 0x0E, 0x3F, 0x31, 0x70, 0x60, 0xFC, 0x60, 0xF8, 0x60, // row 1 - 11 0x31, 0x3F, 0x1E, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_89[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x90, 0x00, 0x90, 0x00, 0x63, 0x00, // row 1 - 6 0x0C, 0x00, 0x30, 0x00, 0xE0, 0x00, 0x80, 0x00, 0x63, 0x00, 0x94, 0x80, // row 7 - 12 0x94, 0x80, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_8A[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x24, 0x00, 0x24, 0x00, // row 1 - 6 0x24, 0x00, 0x27, 0x00, 0x27, 0x80, 0x24, 0x80, 0x64, 0x80, 0x65, 0x80, // row 7 - 12 0xE7, 0x80, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_8B[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 0x60, 0xC0, 0x60, // row 1 - 11 0x30, 0x10, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_8C[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0xC4, 0x00, 0xC4, 0x00, 0xC4, 0x00, 0xC4, 0x00, // row 1 - 6 0xC4, 0x00, 0xFF, 0x00, 0xFF, 0x80, 0xC4, 0x80, 0xC4, 0x80, 0xC5, 0x80, // row 7 - 12 0xC7, 0x80, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_8D[16] = // 1 byte per row { 0x18, 0x00, 0xC7, 0xCE, 0xCC, 0xD8, 0xF8, 0xF8, 0xF8, 0xCC, 0xCE, // row 1 - 11 0xC6, 0xC7, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_8E[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, // row 1 - 6 0x77, 0x00, 0x7F, 0x80, 0x73, 0x80, 0x71, 0x80, 0x71, 0x80, 0x71, 0x80, // row 7 - 12 0x71, 0x80, 0x71, 0x80, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_8F[16] = // 1 byte per row { 0x00, 0x00, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, // row 1 - 11 0xC7, 0xFF, 0xFF, 0x18, 0x18 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_90[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0xFE, 0x00, // row 1 - 6 0xFE, 0x00, 0x70, 0x00, 0x7F, 0x00, 0x7F, 0x80, 0x71, 0x80, 0x71, 0x80, // row 7 - 12 0x71, 0x80, 0x73, 0x80, 0x03, 0x00, 0x07, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_91[16] = // 1 byte per row { 0x00, 0x00, 0x60, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_92[16] = // 1 byte per row { 0x00, 0x00, 0x60, 0x60, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_93[16] = // 1 byte per row { 0x00, 0x00, 0x66, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00, 0x00, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_94[16] = // 1 byte per row { 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0xCC, 0x00, 0x00, 0x00, 0x00, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_95[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xFC, 0xFC, 0xFC, 0xFC, 0x78, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_96[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row 1 - 6 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0x80, 0x00, 0x00, // row 7 - 12 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_97[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row 1 - 6 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0x80, 0x00, 0x00, // row 7 - 12 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_98[1] = { 0 }; // empty character PROGMEM const unsigned char chr_f16_99[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0xED, 0x80, 0x4D, 0x80, 0x4A, 0x80, 0x4A, 0x80, // row 1 - 6 0x48, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row 7 - 12 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_9A[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, // row 1 - 6 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3F, 0x80, 0x2D, 0x80, 0x6C, 0x80, // row 7 - 12 0xEF, 0x80, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_9B[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0x60, 0x30, 0x60, // row 1 - 11 0xC0, 0x80, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_9C[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x00, // row 1 - 6 0xCC, 0x00, 0xCC, 0x00, 0xFC, 0x00, 0xFF, 0x80, 0xCD, 0x80, 0xCC, 0x80, // row 7 - 12 0xCF, 0x80, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_9D[16] = // 1 byte per row { 0x00, 0x06, 0x0C, 0x18, 0x00, 0xCE, 0xDC, 0xD8, 0xF0, 0xF8, 0xDC, // row 1 - 11 0xCC, 0xC6, 0xC7, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_9E[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0xFE, 0x00, // row 1 - 6 0xFE, 0x00, 0x70, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x73, 0x00, 0x73, 0x80, // row 7 - 12 0x73, 0x80, 0x73, 0x80, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_9F[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, // row 1 - 11 0xE6, 0xFE, 0xFE, 0x18, 0x18 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_A0[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // row 1 - 11 0x00, 0x00, 0x00, 0x1B, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_A1[1] = { 0 }; // empty character PROGMEM const unsigned char chr_f16_A2[16] = // 1 byte per row { 0x00, 0x44, 0x38, 0x00, 0x00, 0xE7, 0x67, 0x66, 0x76, 0x3E, 0x3C, // row 1 - 11 0x1C, 0x1C, 0x18, 0x18, 0x70 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_A3[16] = // 1 byte per row { 0x00, 0x00, 0x1F, 0x1F, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // row 1 - 11 0x83, 0xFF, 0x7C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_A4[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x44, 0x44, 0x44, 0x7C, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_A5[16] = // 1 byte per row { 0x03, 0x03, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // row 1 - 11 0xC0, 0xC0, 0xC0, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_A6[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, // row 1 - 11 0xC0, 0xC0, 0xC0, 0xC0, 0xC0 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_A7[16] = // 1 byte per row { 0x00, 0x00, 0x3C, 0x7C, 0x60, 0x70, 0x38, 0xFC, 0xC6, 0xE6, 0x76, // row 1 - 11 0x3C, 0x0E, 0x06, 0x7E, 0x7C // row 12 - 16 }; PROGMEM const unsigned char chr_f16_A8[16] = // 1 byte per row { 0x6C, 0x00, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFE, 0xFE, 0xC0, 0xC0, // row 1 - 11 0xC0, 0xFF, 0xFF, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_A9[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x61, 0x80, 0x5E, 0x80, // row 1 - 6 0xB0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xB0, 0x00, 0x5E, 0x80, 0x61, 0x80, // row 7 - 12 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_AA[16] = // 1 byte per row { 0x00, 0x00, 0x1E, 0x7F, 0x61, 0xC0, 0xC0, 0xFE, 0xFE, 0xC0, 0xE0, // row 1 - 11 0x61, 0x7F, 0x1E, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_AB[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x33, 0x66, 0xCC, 0x66, // row 1 - 11 0x33, 0x11, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_AC[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x03, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_AD[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_AE[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x61, 0x80, 0x7E, 0x80, // row 1 - 6 0xA1, 0x00, 0xA1, 0x00, 0xBE, 0x00, 0xA3, 0x00, 0x61, 0x80, 0x61, 0x80, // row 7 - 12 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_AF[16] = // 1 byte per row { 0xCC, 0x00, 0xFC, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // row 1 - 11 0x30, 0xFC, 0xFC, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_B0[16] = // 1 byte per row { 0x00, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00, 0x00, 0x00, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_B1[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x18, // row 1 - 11 0x18, 0xFF, 0xFF, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_B2[16] = // 1 byte per row { 0x00, 0x00, 0xFC, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // row 1 - 11 0x30, 0xFC, 0xFC, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_B3[16] = // 1 byte per row { 0x00, 0x18, 0x18, 0x18, 0x00, 0x78, 0x78, 0x18, 0x18, 0x18, 0x18, // row 1 - 11 0x18, 0xFF, 0xFF, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_B4[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x0C, 0x0C, 0xFC, 0xFC, 0xC0, 0xC0, 0xC0, 0xC0, // row 1 - 11 0xC0, 0xC0, 0xC0, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_B5[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x00, // row 1 - 6 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, // row 7 - 12 0xFF, 0x80, 0xFD, 0x80, 0xC0, 0x00, 0xC0, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_B6[16] = // 1 byte per row { 0x00, 0x00, 0x3F, 0x7D, 0xFD, 0xFD, 0xFD, 0x7D, 0x1D, 0x05, 0x05, // row 1 - 11 0x05, 0x05, 0x05, 0x05, 0x05 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_B7[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0x00, // row 1 - 11 0x00, 0x00, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_B8[16] = // 1 byte per row { 0x00, 0x00, 0x6C, 0x6C, 0x00, 0x3C, 0x7E, 0xC3, 0xFF, 0xFF, 0xC0, // row 1 - 11 0xE1, 0x7F, 0x3E, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_B9[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x66, 0x00, 0x7C, 0x00, 0x7C, 0x00, // row 1 - 6 0x7C, 0x00, 0x7C, 0x00, 0x7D, 0x80, 0x7D, 0x80, 0x7D, 0x80, 0x6D, 0x80, // row 7 - 12 0xEC, 0x00, 0xCD, 0x80, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_BA[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7F, 0xE1, 0xFE, 0xFE, 0xC0, // row 1 - 11 0xE1, 0x7F, 0x3E, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_BB[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xCC, 0x66, 0x33, 0x66, // row 1 - 11 0xCC, 0x88, 0x00, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_BC[16] = // 1 byte per row { 0x00, 0x18, 0x18, 0x18, 0x00, 0x78, 0x78, 0x18, 0x18, 0x18, 0x18, // row 1 - 11 0x18, 0x18, 0x18, 0x18, 0xF8 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_BD[16] = // 1 byte per row { 0x00, 0x00, 0x3C, 0x7E, 0xC2, 0xC0, 0xE0, 0x7C, 0x3E, 0x07, 0x03, // row 1 - 11 0x83, 0xFF, 0x7C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_BE[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFF, 0xC1, 0xFC, 0x7E, 0x07, // row 1 - 11 0x83, 0xFF, 0x7E, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_BF[16] = // 1 byte per row { 0x00, 0x00, 0x6C, 0x6C, 0x00, 0x78, 0x78, 0x18, 0x18, 0x18, 0x18, // row 1 - 11 0x18, 0xFF, 0xFF, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_C0[16] = // 1 byte per row { 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x3C, 0x66, 0x66, 0x7E, 0x7E, // row 1 - 11 0x66, 0xE7, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_C1[16] = // 1 byte per row { 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFC, 0xFF, 0xC3, 0xC3, // row 1 - 11 0xC3, 0xFF, 0xFC, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_C2[16] = // 1 byte per row { 0x00, 0x00, 0xFE, 0xFF, 0xC3, 0xC3, 0xC3, 0xFE, 0xFE, 0xC3, 0xC3, // row 1 - 11 0xC3, 0xFF, 0xFE, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_C3[16] = // 1 byte per row { 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // row 1 - 11 0xC0, 0xC0, 0xC0, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_C4[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x63, 0x00, 0x63, 0x00, // row 1 - 6 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, // row 7 - 12 0xFF, 0x80, 0xFF, 0x80, 0xC1, 0x80, 0xC1, 0x80 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_C5[16] = // 1 byte per row { 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFE, 0xFE, 0xC0, 0xC0, // row 1 - 11 0xC0, 0xFF, 0xFF, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_C6[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0xCC, 0x80, 0x6D, 0x80, 0x6D, 0x80, 0x3F, 0x00, // row 1 - 6 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x7F, 0x80, 0x6D, 0x80, 0x6D, 0x80, // row 7 - 12 0x6D, 0x80, 0xCC, 0x80, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_C7[16] = // 1 byte per row { 0x00, 0x00, 0x7C, 0xFE, 0x83, 0x03, 0x03, 0x3E, 0x3E, 0x07, 0x03, // row 1 - 11 0x83, 0xFF, 0x7C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_C8[16] = // 1 byte per row { 0x00, 0x00, 0xC7, 0xC7, 0xC7, 0xCF, 0xCB, 0xDB, 0xDB, 0xD3, 0xF3, // row 1 - 11 0xE3, 0xE3, 0xE3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_C9[16] = // 1 byte per row { 0x38, 0x00, 0xC7, 0xC7, 0xC7, 0xCF, 0xCB, 0xDB, 0xDB, 0xD3, 0xF3, // row 1 - 11 0xE3, 0xE3, 0xE3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_CA[16] = // 1 byte per row { 0x00, 0x00, 0xC7, 0xCE, 0xCC, 0xD8, 0xF8, 0xF8, 0xF8, 0xCC, 0xCE, // row 1 - 11 0xC6, 0xC7, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_CB[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x3F, 0x80, 0x31, 0x80, 0x31, 0x80, // row 1 - 6 0x31, 0x80, 0x31, 0x80, 0x31, 0x80, 0x31, 0x80, 0x31, 0x80, 0x31, 0x80, // row 7 - 12 0xE1, 0x80, 0xE1, 0x80, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_CC[16] = // 1 byte per row { 0x00, 0x00, 0xE7, 0xE7, 0xE7, 0xFF, 0xFF, 0xDB, 0xDB, 0xDB, 0xC3, // row 1 - 11 0xC3, 0xC3, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_CD[16] = // 1 byte per row { 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xC3, 0xC3, // row 1 - 11 0xC3, 0xC3, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_CE[16] = // 1 byte per row { 0x00, 0x00, 0x3C, 0x7E, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, // row 1 - 11 0x66, 0x7E, 0x3C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_CF[16] = // 1 byte per row { 0x00, 0x00, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, // row 1 - 11 0xC3, 0xC3, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_D0[16] = // 1 byte per row { 0x00, 0x00, 0xFC, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF, 0xFC, 0xC0, 0xC0, // row 1 - 11 0xC0, 0xC0, 0xC0, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_D1[16] = // 1 byte per row { 0x00, 0x00, 0x1E, 0x7F, 0x61, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // row 1 - 11 0x61, 0x7F, 0x1E, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_D2[16] = // 1 byte per row { 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // row 1 - 11 0x18, 0x18, 0x18, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_D3[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0xE1, 0x80, 0x61, 0x80, 0x73, 0x80, 0x33, 0x00, // row 1 - 6 0x3F, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x1C, 0x00, // row 7 - 12 0x78, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_D4[16] = // 1 byte per row { 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x7F, 0xDB, 0xDB, 0xDB, 0xDB, 0x7F, // row 1 - 11 0x7E, 0x3C, 0x18, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_D5[16] = // 1 byte per row { 0x00, 0x00, 0xE7, 0x66, 0x6E, 0x3C, 0x3C, 0x18, 0x18, 0x3C, 0x3C, // row 1 - 11 0x66, 0x66, 0xE7, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_D6[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, // row 1 - 6 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, // row 7 - 12 0xFF, 0x80, 0xFF, 0x80, 0x01, 0x80, 0x01, 0x80 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_D7[16] = // 1 byte per row { 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0x7B, 0x03, 0x03, // row 1 - 11 0x03, 0x03, 0x03, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_D8[16] = // 1 byte per row { 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, // row 1 - 11 0xDB, 0xFF, 0xFF, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_D9[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0xDB, 0x00, 0xDB, 0x00, 0xDB, 0x00, 0xDB, 0x00, // row 1 - 6 0xDB, 0x00, 0xDB, 0x00, 0xDB, 0x00, 0xDB, 0x00, 0xDB, 0x00, 0xDB, 0x00, // row 7 - 12 0xFF, 0x80, 0xFF, 0x80, 0x01, 0x80, 0x01, 0x80 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_DA[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x30, 0x00, 0x30, 0x00, // row 1 - 6 0x30, 0x00, 0x3F, 0x00, 0x3F, 0x80, 0x31, 0x80, 0x31, 0x80, 0x31, 0x80, // row 7 - 12 0x3F, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_DB[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0xC1, 0x80, 0xC1, 0x80, 0xC1, 0x80, 0xC1, 0x80, // row 1 - 6 0xC1, 0x80, 0xF9, 0x80, 0xFD, 0x80, 0xCD, 0x80, 0xCD, 0x80, 0xCD, 0x80, // row 7 - 12 0xFD, 0x80, 0xF9, 0x80, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_DC[16] = // 1 byte per row { 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFC, 0xFE, 0xC3, 0xC3, // row 1 - 11 0xC3, 0xFE, 0xFC, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_DD[16] = // 1 byte per row { 0x00, 0x00, 0x78, 0xFC, 0x8E, 0x06, 0x06, 0x7E, 0x7E, 0x06, 0x06, // row 1 - 11 0x8E, 0xFC, 0xF8, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_DE[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0xC7, 0x00, 0xCF, 0x00, 0xC9, 0x80, 0xD9, 0x80, // row 1 - 6 0xD9, 0x80, 0xF9, 0x80, 0xF9, 0x80, 0xD9, 0x80, 0xD9, 0x80, 0xD9, 0x80, // row 7 - 12 0xCF, 0x00, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_DF[16] = // 1 byte per row { 0x00, 0x00, 0x3F, 0xFF, 0xC3, 0xC3, 0xC3, 0x7F, 0x3F, 0x73, 0x63, // row 1 - 11 0x63, 0xE3, 0xE3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_E0[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7F, 0x43, 0x1F, 0x7F, 0xE3, // row 1 - 11 0xC7, 0xFF, 0x7B, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_E1[16] = // 1 byte per row { 0x00, 0x3C, 0x7E, 0xE0, 0xC0, 0xFC, 0xFE, 0xE7, 0xC3, 0xC3, 0xC3, // row 1 - 11 0xE7, 0x7E, 0x3C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_E2[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xC3, 0xC3, 0xFE, 0xFF, // row 1 - 11 0xC3, 0xFF, 0xFE, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_E3[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0xC0, 0xC0, 0xC0, 0xC0, // row 1 - 11 0xC0, 0xC0, 0xC0, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_E4[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, // row 1 - 6 0x7F, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, // row 7 - 12 0xFF, 0x80, 0xFF, 0x80, 0xC1, 0x80, 0xC1, 0x80 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_E5[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0xC3, 0xFF, 0xFF, 0xC0, // row 1 - 11 0xE1, 0x7F, 0x3E, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_E6[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x80, // row 1 - 6 0x6D, 0x80, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x7F, 0x80, 0x6D, 0x80, // row 7 - 12 0x6D, 0x80, 0xCC, 0x80, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_E7[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xFE, 0x86, 0x06, 0x3C, 0x3C, // row 1 - 11 0x86, 0xFE, 0x7C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_E8[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xC7, 0xCF, 0xCF, 0xDB, 0xF3, // row 1 - 11 0xF3, 0xE3, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_E9[16] = // 1 byte per row { 0x00, 0x44, 0x38, 0x00, 0x00, 0xC3, 0xC7, 0xCF, 0xCF, 0xDB, 0xF3, // row 1 - 11 0xF3, 0xE3, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_EA[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xDC, 0xD8, 0xF0, 0xF8, 0xDC, // row 1 - 11 0xCC, 0xC6, 0xC7, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_EB[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, // row 1 - 6 0x3F, 0x80, 0x31, 0x80, 0x31, 0x80, 0x31, 0x80, 0x31, 0x80, 0x31, 0x80, // row 7 - 12 0xE1, 0x80, 0xE1, 0x80, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_EC[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xE7, 0xE7, 0xFF, 0xFF, 0xDB, // row 1 - 11 0xDB, 0xDB, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_ED[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xC3, // row 1 - 11 0xC3, 0xC3, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_EE[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0xE7, 0xC3, 0xC3, 0xC3, // row 1 - 11 0xE7, 0x7E, 0x3C, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_EF[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, // row 1 - 11 0xC3, 0xC3, 0xC3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_F0[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xFE, 0xE7, 0xC3, 0xC3, 0xC3, // row 1 - 11 0xE7, 0xFE, 0xDC, 0xC0, 0xC0 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_F1[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7F, 0xE1, 0xC0, 0xC0, 0xC0, // row 1 - 11 0xE1, 0x7F, 0x3E, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_F2[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0x30, 0x30, 0x30, 0x30, // row 1 - 11 0x30, 0x30, 0x30, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_F3[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x67, 0x66, 0x76, 0x3E, 0x3C, // row 1 - 11 0x1C, 0x1C, 0x18, 0x18, 0x70 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_F4[16] = // 1 byte per row { 0x00, 0x00, 0x18, 0x18, 0x18, 0x3C, 0x7E, 0xDB, 0xDB, 0xDB, 0xDB, // row 1 - 11 0xDB, 0x7E, 0x3C, 0x18, 0x18 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_F5[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x66, 0x3C, 0x3C, 0x18, 0x3C, // row 1 - 11 0x3C, 0x66, 0xE7, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_F6[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x00, // row 1 - 6 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, // row 7 - 12 0xFF, 0x80, 0xFF, 0x80, 0x01, 0x80, 0x01, 0x80 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_F7[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0x3F, // row 1 - 11 0x03, 0x03, 0x03, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_F8[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, // row 1 - 11 0xDB, 0xFF, 0xFF, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_F9[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0x00, // row 1 - 6 0xDB, 0x00, 0xDB, 0x00, 0xDB, 0x00, 0xDB, 0x00, 0xDB, 0x00, 0xDB, 0x00, // row 7 - 12 0xFF, 0x80, 0xFF, 0x80, 0x01, 0x80, 0x01, 0x80 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_FA[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, // row 1 - 6 0xF8, 0x00, 0x38, 0x00, 0x38, 0x00, 0x3F, 0x00, 0x3B, 0x80, 0x39, 0x80, // row 7 - 12 0x3F, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_FB[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x80, // row 1 - 6 0xE1, 0x80, 0xE1, 0x80, 0xE1, 0x80, 0xFD, 0x80, 0xED, 0x80, 0xED, 0x80, // row 7 - 12 0xFD, 0x80, 0xF9, 0x80, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_FC[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0xFF, // row 1 - 11 0xC3, 0xFF, 0xFE, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_FD[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xFC, 0x8E, 0x06, 0x7E, 0x06, // row 1 - 11 0x0E, 0xFE, 0xFC, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char chr_f16_FE[32] = // 2 bytes per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, // row 1 - 6 0xCF, 0x00, 0xD9, 0x80, 0xD9, 0x80, 0xF9, 0x80, 0xF9, 0x80, 0xD9, 0x80, // row 7 - 12 0xDF, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00 // row 13 - 16 }; PROGMEM const unsigned char chr_f16_FF[16] = // 1 byte per row { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x7F, 0x63, 0x7F, 0x3F, 0x3B, // row 1 - 11 0x73, 0x63, 0xE3, 0x00, 0x00 // row 12 - 16 }; PROGMEM const unsigned char * chrtbl_f16[224] = // character pointer table { chr_f16_20, chr_f16_21, chr_f16_22, chr_f16_23, chr_f16_24, chr_f16_25, chr_f16_26, chr_f16_27, chr_f16_28, chr_f16_29, chr_f16_2A, chr_f16_2B, chr_f16_2C, chr_f16_2D, chr_f16_2E, chr_f16_2F, chr_f16_30, chr_f16_31, chr_f16_32, chr_f16_33, chr_f16_34, chr_f16_35, chr_f16_36, chr_f16_37, chr_f16_38, chr_f16_39, chr_f16_3A, chr_f16_3B, chr_f16_3C, chr_f16_3D, chr_f16_3E, chr_f16_3F, chr_f16_40, chr_f16_41, chr_f16_42, chr_f16_43, chr_f16_44, chr_f16_45, chr_f16_46, chr_f16_47, chr_f16_48, chr_f16_49, chr_f16_4A, chr_f16_4B, chr_f16_4C, chr_f16_4D, chr_f16_4E, chr_f16_4F, chr_f16_50, chr_f16_51, chr_f16_52, chr_f16_53, chr_f16_54, chr_f16_55, chr_f16_56, chr_f16_57, chr_f16_58, chr_f16_59, chr_f16_5A, chr_f16_5B, chr_f16_5C, chr_f16_5D, chr_f16_5E, chr_f16_5F, chr_f16_60, chr_f16_61, chr_f16_62, chr_f16_63, chr_f16_64, chr_f16_65, chr_f16_66, chr_f16_67, chr_f16_68, chr_f16_69, chr_f16_6A, chr_f16_6B, chr_f16_6C, chr_f16_6D, chr_f16_6E, chr_f16_6F, chr_f16_70, chr_f16_71, chr_f16_72, chr_f16_73, chr_f16_74, chr_f16_75, chr_f16_76, chr_f16_77, chr_f16_78, chr_f16_79, chr_f16_7A, chr_f16_7B, chr_f16_7C, chr_f16_7D, chr_f16_7E, chr_f16_7F, chr_f16_80, chr_f16_81, chr_f16_82, chr_f16_83, chr_f16_84, chr_f16_85, chr_f16_86, chr_f16_87, chr_f16_88, chr_f16_89, chr_f16_8A, chr_f16_8B, chr_f16_8C, chr_f16_8D, chr_f16_8E, chr_f16_8F, chr_f16_90, chr_f16_91, chr_f16_92, chr_f16_93, chr_f16_94, chr_f16_95, chr_f16_96, chr_f16_97, chr_f16_98, chr_f16_99, chr_f16_9A, chr_f16_9B, chr_f16_9C, chr_f16_9D, chr_f16_9E, chr_f16_9F, chr_f16_A0, chr_f16_A1, chr_f16_A2, chr_f16_A3, chr_f16_A4, chr_f16_A5, chr_f16_A6, chr_f16_A7, chr_f16_A8, chr_f16_A9, chr_f16_AA, chr_f16_AB, chr_f16_AC, chr_f16_AD, chr_f16_AE, chr_f16_AF, chr_f16_B0, chr_f16_B1, chr_f16_B2, chr_f16_B3, chr_f16_B4, chr_f16_B5, chr_f16_B6, chr_f16_B7, chr_f16_B8, chr_f16_B9, chr_f16_BA, chr_f16_BB, chr_f16_BC, chr_f16_BD, chr_f16_BE, chr_f16_BF, chr_f16_C0, chr_f16_C1, chr_f16_C2, chr_f16_C3, chr_f16_C4, chr_f16_C5, chr_f16_C6, chr_f16_C7, chr_f16_C8, chr_f16_C9, chr_f16_CA, chr_f16_CB, chr_f16_CC, chr_f16_CD, chr_f16_CE, chr_f16_CF, chr_f16_D0, chr_f16_D1, chr_f16_D2, chr_f16_D3, chr_f16_D4, chr_f16_D5, chr_f16_D6, chr_f16_D7, chr_f16_D8, chr_f16_D9, chr_f16_DA, chr_f16_DB, chr_f16_DC, chr_f16_DD, chr_f16_DE, chr_f16_DF, chr_f16_E0, chr_f16_E1, chr_f16_E2, chr_f16_E3, chr_f16_E4, chr_f16_E5, chr_f16_E6, chr_f16_E7, chr_f16_E8, chr_f16_E9, chr_f16_EA, chr_f16_EB, chr_f16_EC, chr_f16_ED, chr_f16_EE, chr_f16_EF, chr_f16_F0, chr_f16_F1, chr_f16_F2, chr_f16_F3, chr_f16_F4, chr_f16_F5, chr_f16_F6, chr_f16_F7, chr_f16_F8, chr_f16_F9, chr_f16_FA, chr_f16_FB, chr_f16_FC, chr_f16_FD, chr_f16_FE, chr_f16_FF };Заменить Font16.h
4. Откопал на чипе stm32 RTC (часы реального времени). Надо только часовой кварц припаять -))). Запустил часики. Теперь блок в кватанции в ответ на полученную информацию отсылает текущее время. На удаленнных блоках часы реализуются легко. Часы правда не с первого раза получились, но в конце концов запустились как надо.
Проект название поменялось на stm32_server_GFX
Файл stm32_server_GFX.ino
Файл dry_control.ino
// Функции для осушителя подвала // Все функции имеют на входе в качестве параметра номер датчика // Мои макросы #define MOTOR_BIT 0 // бит мотора в packet_0x20.flags #define HEAT_BIT 1 // бит калорифера в packet_0x20.flags #define ABS_H_BIT 2 // бит калорифера в packet_0x20.flags #define MODE_BIT 5 // первый бит режима в packet_0x20.flags #define FLAG_ABS_H_ON packet_0x20[ID].flags |= (1<<ABS_H_BIT) // бит ABS_H_BIT установить в 1 #define FLAG_ABS_H_OFF packet_0x20[ID].flags &= ~(1<<ABS_H_BIT) // бит ABS_H_BIT установить в 0 #define FLAG_ABS_H_CHECK packet_0x20[ID].flags & (1<<ABS_H_BIT) // бит ABS_H_BIT проверить на 1 #define FLAG_MOTOR_ON packet_0x20[ID].flags |= (1<<MOTOR_BIT) // бит мотора установить в 1 #define FLAG_MOTOR_OFF packet_0x20[ID].flags &= ~(1<<MOTOR_BIT) // бит мотора установить в 0 #define FLAG_MOTOR_CHECK packet_0x20[ID].flags & (1<<MOTOR_BIT) // бит мотора проверить на 1 #define FLAG_HEAT_ON packet_0x20[ID].flags |= (1<<HEAT_BIT) // бит калорифера установить в 1 #define FLAG_HEAT_OFF packet_0x20[ID].flags &= ~(1<<HEAT_BIT) // бит калорифера установить в 0 #define FLAG_HEAT_CHECK packet_0x20[ID].flags & (1<<HEAT_BIT) // бит калорифера проверить на 1 #define NUM_SAMPLES 10 // Число усреднений измерений датчика #define TIME_SCAN_SENSOR 3000 // Время опроса датчиков мсек #define TIME_PRINT_CHART 300000 // Время вывода точки графика мсек #define TIME_HOUR 3600000 // Число мсек в часе #define NUM_DRY 2 // число осушителей id 0x21 0x22 // Пакет передаваемый, используется также для хранения результатов. struct type_packet_0x20_NRF24 // Версия 2.4!! адаптация для stm32 Структура передаваемого пакета 32 байта - 32 максимум { byte id=0x00; // Идентификатор типа устройства - старшие 4 бита, вторые (младшие) 4 бита серийный номер устройства byte DHT_error; // Ошибка разряды: 0-1 первый датчик (00-ок) 2-3 второй датчик (00-ок) 4 - радиоканал int16_t tOut=-500,tIn=500; // Текущие температуры в сотых градуса !!! место экономим uint16_t absHOut=123,absHIn=123; // Абсолютные влажности в сотых грамма на м*3 !!! место экономим uint16_t relHOut=123,relHIn=123; // Относительные влажности сотых процента !!! место экономим uint8_t flags=0x00; // байт флагов // 0 бит - мотор включен/выключен // 1 бит - нагреватель включен/выключен // 2 бит -[1 - dH_min задается в сотых грамма на м*3] [0 - dH_min заадется в ДЕСЯТЫХ процента от absHIn] // 3 4 - пока пусто // 5-7 - номер настройки = settingRAM.mode до 8 настроек, надо передавать, что бы на приемнике восстановить uint8_t dH_min; // Порог включения вентилятора по РАЗНИЦЕ абсолютной влажности в сотых грамма на м*3 или в ДЕСЯТЫХ % см flags:2 uint8_t T_min; // Порог выключения вентилятора по температуре в ДЕСЯТЫХ долях градуса, только положительные значения uint8_t count=0; // циклический счетчик отправленных пакетов нужен что бы на приемнике проверять качество связи char note[14] = "NONE"; // Примечание не более 13 байт + 0 байт Русские буквы в два раза меньше т.к. UTF-8 } packet_0x20[NUM_DRY]; // Cтруктура для графиков struct type_chart_dry { byte tOutChart[120]; byte tInChart[120]; byte absHOutChart[120]; byte absHInChart[120]; byte posChart=0; // Позиция в массиве графиков - начало вывода от 0 до 120-1 byte TimeChart=0; // Время до вывода очередной точки на график. bool ChartMotor=false; // Признак работы мотора во время интервала графика если мотор был включен на любое время то на графике фон меняется в этом месте bool ChartHeat=false; // Признак работы нагревателя во время интервала графика если нагреватель был включен на любое время (даже одно измерение) то на графике фон меняется в этом месте bool CoolData=false; // Признак наличия свежих данных, что бы лишний раз не выводить на экран одно и тоже } chart_dry[NUM_DRY]; void dry_static(uint8_t ID) // Печать статической картинки { int i; // Заголовок tft.fillRect(0, 0, 320-1, 20, ILI9341_BLUE); tft.setTextColor(ILI9341_WHITE); tft.drawString(int2str(newpos),2,2,2); tft.drawString(utf8rus(".ОСУШИТЕЛЬ ID: 0x",OutputBuf),13,2,2); tft.drawChar(hex(packet_0x20[ID].id >> 4),149,2,2); tft.drawChar(hex(packet_0x20[ID].id&0x0f),159,2,2); // Таблица для данных tft.drawFastHLine(0,25,320-1,ILI9341_GREEN); tft.drawFastHLine(0,25+23*1,320-1,ILI9341_GREEN); tft.drawFastHLine(0,25+23*2,320-1,ILI9341_GREEN); tft.drawFastHLine(0,25+23*3,320-1,ILI9341_GREEN); tft.drawFastHLine(0,25+23*4,320-1,ILI9341_GREEN); tft.drawFastVLine(200-4,25,24+23*3, ILI9341_GREEN); tft.drawFastVLine(260,25,24+23*3, ILI9341_GREEN); // Заголовки таблиц // В зависимости от id разные надписи - привязка местоположения блока к ID tft.setTextColor(ILI9341_RED); // tft.drawString(utf8rus(packet_0x20[ID].note,OutputBuf),180+30-9,28+23*0,2); tft.setTextColor(ILI9341_GREEN); tft.drawString(utf8rus("Улица",OutputBuf),250+20,28+23*0,2); tft.setTextColor(ILI9341_YELLOW); tft.drawString(utf8rus("N/потери",OutputBuf),0,28+23*0,2); tft.drawString(utf8rus("Температура градусы C\xB0",OutputBuf),0,28+23*1,2); tft.drawString(utf8rus("Относительная влаж. %",OutputBuf),0,28+23*2,2); tft.drawString(utf8rus("Абсолют. влаж. г/м*3",OutputBuf),0,28+23*3,2); // Графики tft.setTextColor(ILI9341_WHITE); print_StrXY(10,125+0,utf8rus("Температура",OutputBuf)); print_StrXY(20+154,125+0,utf8rus("Абс. влажность",OutputBuf)); // надписи на графиках print_StrXY(128,140,"+20"); print_StrXY(135,180,"0"); print_StrXY(128,220,"-20"); print_StrXY(296,150,"15"); print_StrXY(296,180,"10"); print_StrXY(296,210,"5"); // Горизонтальная шкала по часам for(i=0;i<=120;i=i+12) { tft.drawPixel(4+i,239,ILI9341_DGRAY); tft.drawPixel(4+i,238,ILI9341_DGRAY); tft.drawPixel(167+i,239,ILI9341_DGRAY); tft.drawPixel(167+i,238,ILI9341_DGRAY); } } void dry_data(uint8_t ID) // Печать панели статуса Значки на статус панели { // Заголовок // 1. печать ошибки чтения датчиков if (packet_0x20[ID].DHT_error!=last_error) // если статус ошибки поменялся то надо вывести если нет то не выводим - экономия время и нет мерцания { last_error=packet_0x20[ID].DHT_error; tft.fillRect(290, 0, 30, 18, ILI9341_BLUE); // if (packet_0x20[ID].DHT_error>0) { tft.setTextColor(ILI9341_RED); tft.drawNumber(packet_0x20[ID].DHT_error,290,2,2); } // else { tft.setTextColor(ILI9341_GREEN); tft.drawString(utf8rus(" ok ",OutputBuf),290,2,2); } if (packet_0x20[ID].DHT_error>0) { tft.setTextColor(ILI9341_RED); tft.drawString(int2str(packet_0x20[ID].DHT_error),290,2,2); } else { tft.setTextColor(ILI9341_GREEN); tft.drawString(utf8rus(" ok ",OutputBuf),290,2,2); } } // 2. Признак включения мотора if (FLAG_MOTOR_CHECK) tft.fillRect(290-25, 3, 12, 12, ILI9341_GREEN); else tft.fillRect(290-25, 3, 12, 12, ILI9341_BLACK); // Печать значений для дома tft.setTextColor(ILI9341_RED); tft.fillRect(200+0,28+23*0,50, 18, ILI9341_BLACK); tft.drawString(utf8rus(packet_0x20[ID].note,OutputBuf),180+30-9,28+23*0,2); tft.fillRect(200+0,28+23*1,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x20[ID].tIn/100.0,2),200+0,28+23*1,2); tft.fillRect(200+0,28+23*2,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x20[ID].relHIn/100.0,2),200+0,28+23*2,2); tft.fillRect(200+0,28+23*3,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x20[ID].absHIn/100.0,2),200+0,28+23*3,2); tft.setTextColor(ILI9341_GREEN); tft.fillRect(260+6,28+23*1,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x20[ID].tOut/100.0,2),260+6,28+23*1,2); tft.fillRect(260+6,28+23*2,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x20[ID].relHOut/100.0,2),260+6,28+23*2,2); tft.fillRect(260+6,28+23*3,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x20[ID].absHOut/100.0,2),260+6,28+23*3,2); // График if (chart_dry[ID].TimeChart==0) dry_chart(ID); // когда выводится график на экран } // Печать графика на экране, добавляется одна точка и график сдвигается void dry_chart(uint8_t ID) { byte i,x=0; uint8_t tmp; // if ((long)((long)chart_dry[ID].TimeChart*TIME_SCAN_SENSOR*NUM_SAMPLES)<(long)TIME_PRINT_CHART) return; // график еще рано выводить for(i=0;i<120;i++) // График слева на право { // Вычислить координаты текущей точки x в кольцевом буфере. Изменяются от 0 до 120-1 if (chart_dry[ID].posChart<i) x=120+chart_dry[ID].posChart-i; else x=chart_dry[ID].posChart-i; // нарисовать фон в зависимости от статуса мотора if (chart_dry[ID].tInChart[x]>=0x80) { tft.drawFastVLine(5+120-i,237-100,100, tft.color565(0, 60, 9)); tft.drawFastVLine(5+120-i+162,237-100,100, tft.color565(0, 60, 9));} // Мотор был ключен - бледно синий else if (chart_dry[ID].tOutChart[x]>=0x80) { tft.drawFastVLine(5+120-i,237-100,100, tft.color565(90, 60, 0)); tft.drawFastVLine(5+120-i+162,237-100,100, tft.color565(90, 60, 0));}// Нагреватель был ключен - бледно желтый else { tft.drawFastVLine(5+120-i,237-100,100, ILI9341_BLACK); tft.drawFastVLine(5+120-i+162,237-100,100, ILI9341_BLACK); }// ucg.setColor(0, 0, 0); // все выключено if (i%5==0) // Пунктирные линии графика { tft.drawPixel(5+120-i,236-10-1,ILI9341_DGRAY); tft.drawPixel(5+120-i,236-50-1,ILI9341_DGRAY); tft.drawPixel(5+120-i,236-90-1,ILI9341_DGRAY); tft.drawPixel(5+120-i+162,236-25-1,ILI9341_DGRAY); tft.drawPixel(5+120-i+162,236-50-1,ILI9341_DGRAY); tft.drawPixel(5+120-i+162,236-75-1,ILI9341_DGRAY); } // Вывести новую точку tmp=chart_dry[ID].tInChart[x]&0x7f; // Отбросить старший разряд - признак включения мотора if ((tmp==0)||(tmp==100)) tft.drawPixel(5+120-i,236-tmp,ILI9341_WHITE); else tft.drawPixel(5+120-i,236-tmp,ILI9341_RED);//ucg.setColor(255, 255, 255); else ucg.setColor(255, 100, 100); tmp=chart_dry[ID].tOutChart[x]&0x7f; // Отбросить старший разряд - признак включения калорифера if ((tmp==0) || (tmp==100)) tft.drawPixel(5+120-i,236-tmp,ILI9341_WHITE); else tft.drawPixel(5+120-i,236-tmp,ILI9341_GREEN);//ucg.setColor(255, 255, 255); else ucg.setColor(100, 255, 100); if (chart_dry[ID].absHInChart[x]==100) tft.drawPixel(5+120-i+162,236-chart_dry[ID].absHInChart[x],ILI9341_WHITE); else tft.drawPixel(5+120-i+162,236-chart_dry[ID].absHInChart[x],ILI9341_RED);//ucg.setColor(255, 255, 255); else ucg.setColor(255, 100, 100); if (chart_dry[ID].absHOutChart[x]==100) tft.drawPixel(5+120-i+162,236-chart_dry[ID].absHOutChart[x],ILI9341_WHITE); else tft.drawPixel(5+120-i+162,236-chart_dry[ID].absHOutChart[x],ILI9341_GREEN);//ucg.setColor(255, 255, 255); else ucg.setColor(100, 255, 100); } // if (chart_dry[ID].posChart<120-1) chart_dry[ID].posChart++; else chart_dry[ID].posChart=0; // Изменили положение в буфере и Замкнули буфер } // Получение данных это все в прерывании быстренько надо bool dry_get_data(uint8_t *OutputBuf) { uint8_t ID; if (OutputBuf[0]==0x21) ID=0; if (OutputBuf[0]==0x22) ID=1; memcpy(&packet_0x20[ID],OutputBuf,sizeof(type_packet_0x20_NRF24)); // скопировать из буфера в структуру chart_dry[ID].CoolData=true; // Получены свежие данные // Рисуем графики в памяти, а когда потребуется быстро выводим. chart_dry[ID].TimeChart++; if ((long)((long)chart_dry[ID].TimeChart*TIME_SCAN_SENSOR*NUM_SAMPLES)>=(long)TIME_PRINT_CHART) // проверка не пора ли добавлять точку на график { // Работаем через кольцевой буфер // Добавить новую точку в кольцевой буфер // Температура в доме. диапазон -25 . . . +25 растягиваем на 100 точек if (packet_0x20[ID].tIn<=-2500) chart_dry[ID].tInChart[chart_dry[ID].posChart]=0; // Если температура меньше -25 то округляем до -25 else if (packet_0x20[ID].tIn>=2500) chart_dry[ID].tInChart[chart_dry[ID].posChart]=100-1; // Если температура больше 25 то округляем до 25 else chart_dry[ID].tInChart[chart_dry[ID].posChart]=(packet_0x20[ID].tIn+2500)/50; // внутри -25...+25 растягиваем в два раза if (chart_dry[ID].ChartMotor==true) chart_dry[ID].tInChart[chart_dry[ID].posChart]|=0x80; // Признак включения мотора- старший бит в 1 - цвет фона на графике меняется chart_dry[ID].ChartMotor=false; // Температура на улице. диапазон -25 . . . +25 растягиваем на 100 точек if (packet_0x20[ID].tOut<=-2500) chart_dry[ID].tOutChart[chart_dry[ID].posChart]=0; // Если температура меньше -25 то округляем до -25 else if (packet_0x20[ID].tOut>=2500) chart_dry[ID].tOutChart[chart_dry[ID].posChart]=100-1; // Если температура больше 25 то округляем до 25 else chart_dry[ID].tOutChart[chart_dry[ID].posChart]=(packet_0x20[ID].tOut+2500)/50; // внутри -25...+25 растягиваем в два раза if (chart_dry[ID].ChartHeat==true) chart_dry[ID].tOutChart[chart_dry[ID].posChart]|=0x80; // Признак включения нагревателя- старший бит в 1 - цвет фона на графике меняется chart_dry[ID].ChartHeat=false; // Абсолютная влажность в доме диапазон от 0 до 20 грамм на кубометр, растягиваем на 100 точек if (packet_0x20[ID].absHIn>=2000) chart_dry[ID].absHInChart[chart_dry[ID].posChart]=100-1; else chart_dry[ID].absHInChart[chart_dry[ID].posChart]=packet_0x20[ID].absHIn/20; // внутри 0...20 растягиваем в пять раз в сотых % по этому делем не на 100 а на 20 // Абсолютная влажность на улицу диапазон от 0 до 20 грамм на кубометр, растягиваем на 100 точек if (packet_0x20[ID].absHOut>=2000) chart_dry[ID].absHOutChart[chart_dry[ID].posChart]=100-1; else chart_dry[ID].absHOutChart[chart_dry[ID].posChart]=packet_0x20[ID].absHOut/20; // внутри 0...20 растягиваем в пять раз, в сотых % по этому делем не на 100 а на 20 if (chart_dry[ID].posChart<120-1) chart_dry[ID].posChart++; else chart_dry[ID].posChart=0; // Изменили положение в буфере и Замкнули буфер chart_dry[ID].TimeChart=0; // Сдвиг графика и вывод новой точки сброс счетчика // dry_chart(ID); } } void dry_update(uint8_t ID) { if (chart_dry[ID].CoolData==true) { dry_data(ID); chart_dry[ID].CoolData=false; } }Проект продолжает развиваться только на stm32, Больше не будет поддерживаться двух платфор avr и stm32 одновременно.
Очередная модификация кода. Основные изменения:
1. Добавлен экран по контролю тепловым насосом. Данные передаются но пока графики не выводятся.
2. В рамках развития проекта сделал автономный датчик температуры и давления (на ВМ180 и pro mini) питание от одной литиевой батереи 1/2 АА 3.6 вольта. Ток потребления в режиме power_down около 40 мкА. Передача данных раз в 5 минут по nrf24 (будет отдельный пост). Теперь головной блок выводит информацию с этих датчиков. Возможно подключение до 3 шт.
3. Не значительная опитмизация кода.
Код stm32_server_GFX.ino (основной блок без особенностьей переферии)
/* Описание 1. Часы реального времени. Необходимые аппаратные доработки: 1.1 Надо припаять батарейку 3 вольта на ноги bat (M20 pin 3 "+") и gnd (J2 pin 2 "-") 1.2 Припаять часовой кварц 32.768 к цифровым ногам 13 и 12 (М20 pin 4 и 5) Эти ноги после этого использовать НЕЛЬЗЯ!!! */ #pragma GCC optimize ("-Os") //#pragma pack(push, 1) // выравнивание по одному байту ???????? //#define DEMO // Признак демонстрации - данные с датчиков генерятся рандом другие интервалы #define VERSION "Version: 0.51 alpha 28/11/15" // Текущая версия #define SPI_16BIT #define SPI_MODE_DMA 1 #define SPEED_UP 1 // Enables extra calculations in the circles routine to use fastVLine and fastHLine, only in DMA mode. #include <itoa.h> #include <SPI.h> // в зависимости от платформы используется разная библиотека #include "Adafruit_GFX_AS.h" #include "Adafruit_ILI9341_STM.h" #include "nRF24L01.h" // не требует адаптации #include "RF24.h" // адаптирована для Maple mini #include <RTClock.h> RTClock rt (RTCSEL_LSE); // используется внешний часовой кварц uint32 tt; #include "stmTime.h" // Time library - https://github.com/PaulStoffregen/Time #define TZ "UTC+3" // Часовой пояс #include <libmaple/iwdg.h> // Сторожевой таймер #include <libmaple/adc.h> // АЦП #define DSB_ALL_IRQ asm volatile("cpsid i"); // запретить все прерывания #define ENB_ALL_IRQ asm volatile("cpsie i"); // разрешить все прерывания // Что куда припаяно #define NRF24_CE_PIN 3 #define NRF24_CSN_PIN 7 #define NRF24_IRQ_PIN PB10 // прерывание радио #define TFT_DC_PIN 11 // 12 старая нога #define TFT_CS_PIN 10 // 13 старая нога #define TFT_RST_PIN 14 // сброс дисплея #define LED_PIN PB1 // светодиод на плате #define PIN_A 2 // энкодер канал А #define PIN_B 9 // энкодер канал B #define PIN_SW 8 // энкодер Кнопка // Аппаратный SPI на дисплей ILI9341 и NRF24 // Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS_PIN, TFT_DC_PIN); RF24 radio(NRF24_CE_PIN, NRF24_CSN_PIN); // радиомодуль #define NRF24_CHANEL 100 #define NUM_SCREEN 4+1 // Число экранов + 1 стартовый // Цвета дополнительные #define ILI9341_GRAY 0xBDF7 // Light Gray #define ILI9341_DGRAY 0x7BEF // Dark Gray #define ILI9341_ORANGE 0xFBE0 // Orange #define ILI9341_BROWN 0x79E0 // Brown #define ILI9341_PINK 0xF81F // Pink int err_count=-1; // статистика по пропущенным пакетам -1 признак первого старта // энкодер volatile uint8_t enc=0; volatile int newpos=0; bool packet_ready=false; // true поступили новые данные bool change_screen=false; // true сменился экран int last_min=-1; // для вывода часов char OutputBuf[100]; // буффер используется для вывода на экран (туда кладут результат различных преобразований перед выводом) //bool signalStrength; byte last_error=100; // Предыдущая ошибка<packet.error // Проверка радио по прерываниям от радиомодуля void check_radio(void); void setup(){ pinMode(PB1, OUTPUT); // Светодиод pinMode(NRF24_IRQ_PIN, INPUT); // Прерывание pinMode(PIN_A, INPUT); pinMode(PIN_B, INPUT); pinMode(PIN_SW, INPUT); digitalWrite(PIN_A, HIGH); // turn on pullup resistor digitalWrite(PIN_B, HIGH); // turn on pullup resistor iwdg_init(IWDG_PRE_256, 1250); // init an 8 second wd timer // Настройка радиомодуля radio.begin(); radio.setDataRate(RF24_250KBPS); // выбор скорости RF24_250KBPS RF24_1MBPS RF24_2MBPS radio.setPALevel(RF24_PA_MAX); // выходная мощность передатчика radio.setChannel(NRF24_CHANEL); // тут установка канала radio.setCRCLength(RF24_CRC_16); // использовать контрольную сумму в 16 бит radio.setAutoAck(true); // включить аппаратное потверждение // radio.enableDynamicPayloads(); // разрешить Dynamic Payloads radio.enableAckPayload(); // разрешить AckPayload - ответ с полезной информацией radio.setRetries(50,10); // Количество повторов и пауза между повторами // Рекомендуют первые 2-4 байта адреса устанавливать в E7 или 18 он проще детектируется чипом radio.openWritingPipe(0xE7E7E7E7D2LL); // передатчик radio.openReadingPipe(1,0xE7E7E7E7E1LL); // приемник radio.startListening(); reset_ili9341(); start_screen(); attachInterrupt(NRF24_IRQ_PIN, check_radio, FALLING); // Прикрепление прерывания радио // attachInterrupt(PIN_A, updateEncoder, CHANGE); // Прикрепление прерывания энкодер // attachInterrupt(PIN_B, updateEncoder, CHANGE); // Прикрепление прерывания энкодер attachInterrupt(PIN_SW, scanKey, FALLING); rtc_set_prescaler_load(0x7fff); // установка делителя для часов // setCurrentTime(); // Установка времени rt.attachSecondsInterrupt(show_time); } void setCurrentTime() // становка заданного времени один раз загружается а потом отключается { setTime(14,46,20,28,11,2015); time_t t = now(); rt.setTime(t); } void scanKey() { int oldpos=newpos; byte key=digitalRead(PIN_SW); if (key==0) newpos++; if (newpos>=NUM_SCREEN) newpos=0; if (oldpos!=newpos) change_screen=true; // только когда было изменение } void updateEncoder() //адаптировано на деление на 2 и диапазон по количеству экранов { int oldpos=newpos; uint8_t newenc=2*digitalRead(PIN_B)+digitalRead(PIN_A); //берем 2 бита входов и сдвигаем в позицию 0,1 uint8_t temp=enc ^ newenc; //побитовое исключающее или if (temp == 0b01) if (enc==0b00 || enc==0b11) newpos++; else newpos--; else if(temp == 0b10) if (enc==0b00 || enc==0b11) newpos--; else newpos++; enc=newenc; if (newpos<0) newpos=NUM_SCREEN-1; if (newpos>=NUM_SCREEN) newpos=0; if (oldpos!=newpos) change_screen=true; // только когда было изменение } void loop() { if (change_screen==true) // Смена экрана { DSB_ALL_IRQ; change_screen=false; packet_ready=true; // ucg.clearScreen(); tft.fillScreen(ILI9341_BLACK); switch (newpos) { // по положению Энкодера case 0: // стартовый экран start_screen(); break; case 1: // осушитель ID 0x21 dry_static(0); dry_data(0); dry_chart(0); break; case 2: // осушитель ID 0x22 dry_static(1); dry_data(1); dry_chart(1); // dry_update(1); break; case 3: // датчики ID 0x30 temp_static(0); temp_data(0); temp_chart(0); break; case 4: // осушитель ID 0x10 heatpump_static(1); break; default: newpos=0; } ENB_ALL_IRQ; last_min=-1; } if (packet_ready==true) // Есть не обработанные данные - надо нарисовать { packet_ready=false; DSB_ALL_IRQ; switch (newpos) { // по положению Энкодера case 0: // стартовый экран // start_screen(); break; case 1: // осушитель ID 0x21 dry_update(0); // dry_chart(0); break; case 2: // осушитель ID 0x21 dry_update(1); // dry_chart(1); break; case 3: // датчики ID 0x31 32 33 temp_update(0); temp_update(1); temp_update(2); break; default: newpos=0; } ENB_ALL_IRQ; digitalWrite(PB1,HIGH); delay(5); digitalWrite(PB1,LOW) ; } iwdg_feed(); // Сброс сторожевого таймера delay(100); // без этого квитанции не приходят tt = rt.getTime(); } // Вывод строки константы в координаты x y маленьким шрифтом void print_StrXY(int x,int y, char* b) { tft.setCursor(x, y); tft.println(b); } char hex(byte x) // Функия для вывода в hex { if(x >= 0 && x <= 9 ) return (char)(x + '0'); else return (char)('a'+x-10); } void check_radio(void) // ПРИЕМ ПАКЕТА Прерывание для проверки радио { uint8_t buf[33]; // Буффер для чтения 32+1 byte pipe = 0; while(radio.available(&pipe) ) // читаем весь буфер до 3 посылок { packet_ready=true; // есть не обработанные данные radio.writeAckPayload(1, &tt, sizeof(tt) ); // подготавливаем ответ с времением - передаем текущее время в удаленный блок radio.read(&buf, sizeof(buf)); // Читаем в промежуточный буффер, далее анализируем 1 байт id if ((buf[0]&0xf0)==0x20) dry_get_data(buf); // анализ по ID тип устройства ОСУШИТЕЛЬ if ((buf[0]&0xf0)==0x30) temp_get_data(buf); // анализ по ID тип устройства РадиоДатчик } } // Очистка экрана bool reset_ili9341(void) { pinMode(TFT_RST_PIN, OUTPUT); // Сброс дисплея сигнал активным является LOW digitalWrite(TFT_RST_PIN, LOW); delay(100); digitalWrite(TFT_RST_PIN, HIGH); // Дисплей tft.begin(); tft.setRotation(1); tft.fillScreen(ILI9341_BLACK); } bool start_screen(void) { // Заголовок tft.fillRect(0, 0, 320-1, 20, ILI9341_BLUE); tft.setTextColor(ILI9341_WHITE); tft.drawString(utf8rus("Удаленный мониторинг",OutputBuf),1,1,2); tft.setTextColor(ILI9341_YELLOW); tft.drawString(utf8rus("1. Температура блока градусы: ",OutputBuf),2,2+18*1,2); tft.drawString(ftoa(OutputBuf, (1750.0-(read_VDDA()))/4.3+25.0,2),280,2+18*1,2); tft.drawString(utf8rus("2. Канал NRF24l01+:",OutputBuf),2,2+18*2,2); tft.drawString(int2str(NRF24_CHANEL),280,2+18*2,2); tft.drawString(utf8rus("3. Число внешних устройств:",OutputBuf),2,2+18*3,2); tft.drawString(int2str(NUM_SCREEN-1),280,2+18*3,2); tft.drawString(utf8rus("4. Напряжение питания В:",OutputBuf),2,2+18*4,2); // tft.drawString(int2str(NUM_SCREEN-1),280,2+18*4,2); tft.setTextColor(ILI9341_RED); print_StrXY(2,240-10,VERSION); } // Чтение опорного напряжения uint16 read_VDDA(void) { adc_reg_map *regs = ADC1->regs; // 3. Set the TSVREFE bit in the ADC control register 2 (ADC_CR2) to wake up the // temperature sensor from power down mode. Do this first 'cause according to // the Datasheet section 5.3.21 it takes from 4 to 10 uS to power up the sensor. regs->CR2 |= ADC_CR2_TSEREFE; // 1. Select the ADCx_IN16 input channel. regs->SQR1 = 0; // set regular channel sequence length to 1 regs->SQR3 = 0b10000; // select channel 16 // 2. Select a sample time of 17.1 μs // per gbulmer: set channel 16 sample time to 239.5 cycles // 239.5 cycles of the ADC clock (72MHz/6=12MHz) is over 17.1us (about 20us), but no smaller // sample time exceeds 17.1us. regs->SMPR1 = (0b111 << (3*6)); // 4. Start the ADC conversion by setting the ADON bit (or by external trigger). // note by virture of bit 11 being zero returns right aligned results. // Aparently we also need SWSTART - tdc regs->CR2 |= (ADC_CR2_SWSTART | ADC_CR2_ADON); // wait for conversion to complete while (!(regs->SR & ADC_SR_EOC)) ; // 5. Read the resulting VSENSE data in the ADC data register return (uint16)(regs->DR & ADC_DR_DATA); } // Показ времени по секундным прерываниям void show_time() { byte temp; char t[6]; if (last_min!=minute(tt)) // выводим только изменение - т.е. раз в минуту { last_min=minute(tt); // Быстро формируем строку со временем а потом выводим temp=hour(tt); if (temp<10) t[0]=48; else t[0]=temp/10+48; // код "0" 48 t[1]=temp%10+48; t[2]=58; // ":" temp=minute(tt); if (temp<10) t[3]=48; else t[3]=temp/10+48; t[4]=temp%10+48; t[5]=0; // Конец строки tft.setTextColor(ILI9341_YELLOW); switch (newpos) { // в зависимости от экрана case 0: // стартовый экран tft.fillRect(275, 0, 45, 18, ILI9341_BLUE); tft.drawString(t,275,1,2); break; case 1: // осушитель ID 0x21 case 2: // осушитель ID 0x22 tft.fillRect(210, 0, 45, 18, ILI9341_BLUE); tft.drawString(t,210,1,2); break; case 3: // Датчики ID 0x30 case 4: // Тепловой насос tft.fillRect(275, 0, 45, 18, ILI9341_BLUE); tft.drawString(t,275,1,2); } } } // Перевод кодировки из UTF8 в 1251 char* utf8rus(String source, char* buf) { int i,k,j; unsigned char n; char m[2] = { '0', '\0' }; k = source.length(); i = 0; j=0; while (i < k) { n = source[i]; i++; if (n >= 0xC0) { switch (n) { case 0xD0: { n = source[i]; i++; if (n == 0x81) { n = 0xA8; break; } if (n >= 0x90 && n <= 0xBF) n = n + 0x30; break; } case 0xD1: { n = source[i]; i++; if (n == 0x91) { n = 0xB8; break; } if (n >= 0x80 && n <= 0x8F) n = n + 0x70; break; } } } buf[j]=n; j++; } buf[j]=0; // окончание строки return buf; } // int to str - для уменьшения кода char _int2str[7]; char* int2str( register int i ) { register unsigned char L = 1; register char c; register boolean m = false; register char b; // lower-byte of i // negative if ( i < 0 ) { _int2str[ 0 ] = '-'; i = -i; } else L = 0; // ten-thousands if( i > 9999 ) { c = i < 20000 ? 1 : i < 30000 ? 2 : 3; _int2str[ L++ ] = c + 48; i -= c * 10000; m = true; } // thousands if( i > 999 ) { c = i < 5000 ? ( i < 3000 ? ( i < 2000 ? 1 : 2 ) : i < 4000 ? 3 : 4 ) : i < 8000 ? ( i < 6000 ? 5 : i < 7000 ? 6 : 7 ) : i < 9000 ? 8 : 9; _int2str[ L++ ] = c + 48; i -= c * 1000; m = true; } else if( m ) _int2str[ L++ ] = '0'; // hundreds if( i > 99 ) { c = i < 500 ? ( i < 300 ? ( i < 200 ? 1 : 2 ) : i < 400 ? 3 : 4 ) : i < 800 ? ( i < 600 ? 5 : i < 700 ? 6 : 7 ) : i < 900 ? 8 : 9; _int2str[ L++ ] = c + 48; i -= c * 100; m = true; } else if( m ) _int2str[ L++ ] = '0'; // decades (check on lower byte to optimize code) b = char( i ); if( b > 9 ) { c = b < 50 ? ( b < 30 ? ( b < 20 ? 1 : 2 ) : b < 40 ? 3 : 4 ) : b < 80 ? ( i < 60 ? 5 : i < 70 ? 6 : 7 ) : i < 90 ? 8 : 9; _int2str[ L++ ] = c + 48; b -= c * 10; m = true; } else if( m ) _int2str[ L++ ] = '0'; // last digit _int2str[ L++ ] = b + 48; // null terminator _int2str[ L ] = 0; return _int2str; } // Float to String - экономим место char *ftoa(char *a, double f, int precision) { long p[] = {0,10,100,1000,10000,100000,1000000,10000000,100000000}; char *ret = a; long heiltal = (long)f; itoa(heiltal, a, 10); while (*a != '\0') a++; *a++ = '.'; long desimal = abs((long)((f - heiltal) * p[precision])); itoa(desimal, a, 10); return ret; }Файл dry_control.ino (Контроль влажности подвала http://arduino.ru/forum/proekty/kontrol-vlazhnosti-podvala-arduino-pro-mini)
//======================================================================= // Осушитель подвала //======================================================================= // Все функции имеют на входе в качестве параметра номер датчика // Мои макросы #define MOTOR_BIT 0 // бит мотора в packet_0x20.flags #define HEAT_BIT 1 // бит калорифера в packet_0x20.flags #define ABS_H_BIT 2 // бит калорифера в packet_0x20.flags #define MODE_BIT 5 // первый бит режима в packet_0x20.flags #define FLAG_ABS_H_ON packet_0x20[ID].flags |= (1<<ABS_H_BIT) // бит ABS_H_BIT установить в 1 #define FLAG_ABS_H_OFF packet_0x20[ID].flags &= ~(1<<ABS_H_BIT) // бит ABS_H_BIT установить в 0 #define FLAG_ABS_H_CHECK packet_0x20[ID].flags & (1<<ABS_H_BIT) // бит ABS_H_BIT проверить на 1 #define FLAG_MOTOR_ON packet_0x20[ID].flags |= (1<<MOTOR_BIT) // бит мотора установить в 1 #define FLAG_MOTOR_OFF packet_0x20[ID].flags &= ~(1<<MOTOR_BIT) // бит мотора установить в 0 #define FLAG_MOTOR_CHECK packet_0x20[ID].flags & (1<<MOTOR_BIT) // бит мотора проверить на 1 #define FLAG_HEAT_ON packet_0x20[ID].flags |= (1<<HEAT_BIT) // бит калорифера установить в 1 #define FLAG_HEAT_OFF packet_0x20[ID].flags &= ~(1<<HEAT_BIT) // бит калорифера установить в 0 #define FLAG_HEAT_CHECK packet_0x20[ID].flags & (1<<HEAT_BIT) // бит калорифера проверить на 1 #define NUM_SAMPLES 10 // Число усреднений измерений датчика #define TIME_SCAN_SENSOR 3000 // Время опроса датчиков мсек #define TIME_PRINT_CHART 300000 // Время вывода точки графика мсек #define TIME_HOUR 3600000 // Число мсек в часе #define NUM_DRY 2 // число осушителей id 0x21 0x22 // Пакет передаваемый, используется также для хранения результатов. struct type_packet_0x20_NRF24 // Версия 2.4!! адаптация для stm32 Структура передаваемого пакета 32 байта - 32 максимум { byte id=0x00; // Идентификатор типа устройства - старшие 4 бита, вторые (младшие) 4 бита серийный номер устройства byte DHT_error; // Ошибка разряды: 0-1 первый датчик (00-ок) 2-3 второй датчик (00-ок) 4 - радиоканал int16_t tOut=-500,tIn=500; // Текущие температуры в сотых градуса !!! место экономим uint16_t absHOut=123,absHIn=123; // Абсолютные влажности в сотых грамма на м*3 !!! место экономим uint16_t relHOut=123,relHIn=123; // Относительные влажности сотых процента !!! место экономим uint8_t flags=0x00; // байт флагов // 0 бит - мотор включен/выключен // 1 бит - нагреватель включен/выключен // 2 бит -[1 - dH_min задается в сотых грамма на м*3] [0 - dH_min заадется в ДЕСЯТЫХ процента от absHIn] // 3 4 - пока пусто // 5-7 - номер настройки = settingRAM.mode до 8 настроек, надо передавать, что бы на приемнике восстановить uint8_t dH_min; // Порог включения вентилятора по РАЗНИЦЕ абсолютной влажности в сотых грамма на м*3 или в ДЕСЯТЫХ % см flags:2 uint8_t T_min; // Порог выключения вентилятора по температуре в ДЕСЯТЫХ долях градуса, только положительные значения uint8_t count=0; // циклический счетчик отправленных пакетов нужен что бы на приемнике проверять качество связи char note[14] = "NONE"; // Примечание не более 13 байт + 0 байт Русские буквы в два раза меньше т.к. UTF-8 } packet_0x20[NUM_DRY]; // Cтруктура для графиков struct type_chart_dry { byte tOutChart[120]; byte tInChart[120]; byte absHOutChart[120]; byte absHInChart[120]; byte posChart=0; // Позиция в массиве графиков - начало вывода от 0 до 120-1 byte TimeChart=0; // Время до вывода очередной точки на график. bool ChartMotor=false; // Признак работы мотора во время интервала графика если мотор был включен на любое время то на графике фон меняется в этом месте bool ChartHeat=false; // Признак работы нагревателя во время интервала графика если нагреватель был включен на любое время (даже одно измерение) то на графике фон меняется в этом месте bool CoolData=false; // Признак наличия свежих данных, что бы лишний раз не выводить на экран одно и тоже } chart_dry[NUM_DRY]; void dry_static(uint8_t ID) // Печать статической картинки { int i; // Заголовок tft.fillRect(0, 0, 320-1, 20, ILI9341_BLUE); tft.setTextColor(ILI9341_WHITE); tft.drawString(int2str(newpos),2,2,2); tft.drawString(utf8rus(".ОСУШИТЕЛЬ ID: 0x",OutputBuf),13,2,2); tft.drawChar(hex(packet_0x20[ID].id >> 4),149,2,2); tft.drawChar(hex(packet_0x20[ID].id&0x0f),159,2,2); // Таблица для данных tft.drawFastHLine(0,25,320-1,ILI9341_GREEN); tft.drawFastHLine(0,25+23*1,320-1,ILI9341_GREEN); tft.drawFastHLine(0,25+23*2,320-1,ILI9341_GREEN); tft.drawFastHLine(0,25+23*3,320-1,ILI9341_GREEN); tft.drawFastHLine(0,25+23*4,320-1,ILI9341_GREEN); tft.drawFastVLine(200-4,25,24+23*3, ILI9341_GREEN); tft.drawFastVLine(260,25,24+23*3, ILI9341_GREEN); // Заголовки таблиц // В зависимости от id разные надписи - привязка местоположения блока к ID tft.setTextColor(ILI9341_RED); // tft.drawString(utf8rus(packet_0x20[ID].note,OutputBuf),180+30-9,28+23*0,2); tft.setTextColor(ILI9341_GREEN); tft.drawString(utf8rus("Улица",OutputBuf),250+20,28+23*0,2); tft.setTextColor(ILI9341_YELLOW); tft.drawString(utf8rus("N/потери",OutputBuf),0,28+23*0,2); tft.drawString(utf8rus("Температура градусы C\xB0",OutputBuf),0,28+23*1,2); tft.drawString(utf8rus("Относительная влаж. %",OutputBuf),0,28+23*2,2); tft.drawString(utf8rus("Абсолют. влаж. г/м*3",OutputBuf),0,28+23*3,2); // Графики tft.setTextColor(ILI9341_WHITE); print_StrXY(10,125+0,utf8rus("Температура C\xB0",OutputBuf)); print_StrXY(20+154,125+0,utf8rus("Абс. влажность",OutputBuf)); // надписи на графиках print_StrXY(128,140,"+20"); print_StrXY(135,180,"0"); print_StrXY(128,220,"-20"); print_StrXY(296,150,"15"); print_StrXY(296,180,"10"); print_StrXY(296,210,"5"); // Горизонтальная шкала по часам for(i=0;i<=120;i=i+12) { tft.drawPixel(4+i,239,ILI9341_DGRAY); tft.drawPixel(4+i,238,ILI9341_DGRAY); tft.drawPixel(167+i,239,ILI9341_DGRAY); tft.drawPixel(167+i,238,ILI9341_DGRAY); } } void dry_data(uint8_t ID) // Печать панели статуса Значки на статус панели { // Заголовок // 1. печать ошибки чтения датчиков if (packet_0x20[ID].DHT_error!=last_error) // если статус ошибки поменялся то надо вывести если нет то не выводим - экономия время и нет мерцания { last_error=packet_0x20[ID].DHT_error; tft.fillRect(290, 0, 30, 18, ILI9341_BLUE); if (packet_0x20[ID].DHT_error>0) { tft.setTextColor(ILI9341_RED); tft.drawString(int2str(packet_0x20[ID].DHT_error),290,2,2); } else { tft.setTextColor(ILI9341_GREEN); tft.drawString(utf8rus(" ok ",OutputBuf),290,2,2); } } // 2. Признак включения мотора if (FLAG_MOTOR_CHECK) tft.fillRect(290-25, 3, 12, 12, ILI9341_GREEN); else tft.fillRect(290-25, 3, 12, 12, ILI9341_BLACK); // Печать значений для дома tft.setTextColor(ILI9341_RED); tft.fillRect(200+0,28+23*0,50, 18, ILI9341_BLACK); tft.drawString(utf8rus(packet_0x20[ID].note,OutputBuf),180+30-9,28+23*0,2); tft.fillRect(200+0,28+23*1,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x20[ID].tIn/100.0,2),200+0,28+23*1,2); tft.fillRect(200+0,28+23*2,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x20[ID].relHIn/100.0,2),200+0,28+23*2,2); tft.fillRect(200+0,28+23*3,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x20[ID].absHIn/100.0,2),200+0,28+23*3,2); tft.setTextColor(ILI9341_GREEN); tft.fillRect(260+6,28+23*1,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x20[ID].tOut/100.0,2),260+6,28+23*1,2); tft.fillRect(260+6,28+23*2,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x20[ID].relHOut/100.0,2),260+6,28+23*2,2); tft.fillRect(260+6,28+23*3,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x20[ID].absHOut/100.0,2),260+6,28+23*3,2); // График if (chart_dry[ID].TimeChart==0) dry_chart(ID); // когда выводится график на экран } // Печать графика на экране, добавляется одна точка и график сдвигается void dry_chart(uint8_t ID) { byte i,x=0; uint8_t tmp; // if ((long)((long)chart_dry[ID].TimeChart*TIME_SCAN_SENSOR*NUM_SAMPLES)<(long)TIME_PRINT_CHART) return; // график еще рано выводить for(i=0;i<120;i++) // График слева на право { // Вычислить координаты текущей точки x в кольцевом буфере. Изменяются от 0 до 120-1 if (chart_dry[ID].posChart<i) x=120+chart_dry[ID].posChart-i; else x=chart_dry[ID].posChart-i; // нарисовать фон в зависимости от статуса мотора if (chart_dry[ID].tInChart[x]>=0x80) { tft.drawFastVLine(5+120-i,237-100,100, tft.color565(0, 60, 9)); tft.drawFastVLine(5+120-i+162,237-100,100, tft.color565(0, 60, 9));} // Мотор был ключен - бледно синий else if (chart_dry[ID].tOutChart[x]>=0x80) { tft.drawFastVLine(5+120-i,237-100,100, tft.color565(90, 60, 0)); tft.drawFastVLine(5+120-i+162,237-100,100, tft.color565(90, 60, 0));}// Нагреватель был ключен - бледно желтый else { tft.drawFastVLine(5+120-i,237-100,100, ILI9341_BLACK); tft.drawFastVLine(5+120-i+162,237-100,100, ILI9341_BLACK); }// ucg.setColor(0, 0, 0); // все выключено if (i%5==0) // Пунктирные линии графика { tft.drawPixel(5+120-i,236-10-1,ILI9341_DGRAY); tft.drawPixel(5+120-i,236-50-1,ILI9341_DGRAY); tft.drawPixel(5+120-i,236-90-1,ILI9341_DGRAY); tft.drawPixel(5+120-i+162,236-25-1,ILI9341_DGRAY); tft.drawPixel(5+120-i+162,236-50-1,ILI9341_DGRAY); tft.drawPixel(5+120-i+162,236-75-1,ILI9341_DGRAY); } // Вывести новую точку tmp=chart_dry[ID].tInChart[x]&0x7f; // Отбросить старший разряд - признак включения мотора if ((tmp==0)||(tmp==100)) tft.drawPixel(5+120-i,236-tmp,ILI9341_WHITE); else tft.drawPixel(5+120-i,236-tmp,ILI9341_RED);//ucg.setColor(255, 255, 255); else ucg.setColor(255, 100, 100); tmp=chart_dry[ID].tOutChart[x]&0x7f; // Отбросить старший разряд - признак включения калорифера if ((tmp==0) || (tmp==100)) tft.drawPixel(5+120-i,236-tmp,ILI9341_WHITE); else tft.drawPixel(5+120-i,236-tmp,ILI9341_GREEN);//ucg.setColor(255, 255, 255); else ucg.setColor(100, 255, 100); if (chart_dry[ID].absHInChart[x]==100) tft.drawPixel(5+120-i+162,236-chart_dry[ID].absHInChart[x],ILI9341_WHITE); else tft.drawPixel(5+120-i+162,236-chart_dry[ID].absHInChart[x],ILI9341_RED);//ucg.setColor(255, 255, 255); else ucg.setColor(255, 100, 100); if (chart_dry[ID].absHOutChart[x]==100) tft.drawPixel(5+120-i+162,236-chart_dry[ID].absHOutChart[x],ILI9341_WHITE); else tft.drawPixel(5+120-i+162,236-chart_dry[ID].absHOutChart[x],ILI9341_GREEN);//ucg.setColor(255, 255, 255); else ucg.setColor(100, 255, 100); } // if (chart_dry[ID].posChart<120-1) chart_dry[ID].posChart++; else chart_dry[ID].posChart=0; // Изменили положение в буфере и Замкнули буфер } // Получение данных это все в прерывании быстренько надо bool dry_get_data(uint8_t *OutputBuf) { uint8_t ID; if (OutputBuf[0]==0x21) ID=0; if (OutputBuf[0]==0x22) ID=1; memcpy(&packet_0x20[ID],OutputBuf,sizeof(type_packet_0x20_NRF24)); // скопировать из буфера в структуру chart_dry[ID].CoolData=true; // Получены свежие данные // Рисуем графики в памяти, а когда потребуется быстро выводим. chart_dry[ID].TimeChart++; if ((long)((long)chart_dry[ID].TimeChart*TIME_SCAN_SENSOR*NUM_SAMPLES)>=(long)TIME_PRINT_CHART) // проверка не пора ли добавлять точку на график { // Работаем через кольцевой буфер // Добавить новую точку в кольцевой буфер // Температура в доме. диапазон -25 . . . +25 растягиваем на 100 точек if (packet_0x20[ID].tIn<=-2500) chart_dry[ID].tInChart[chart_dry[ID].posChart]=0; // Если температура меньше -25 то округляем до -25 else if (packet_0x20[ID].tIn>=2500) chart_dry[ID].tInChart[chart_dry[ID].posChart]=100-1; // Если температура больше 25 то округляем до 25 else chart_dry[ID].tInChart[chart_dry[ID].posChart]=(packet_0x20[ID].tIn+2500)/50; // внутри -25...+25 растягиваем в два раза if (chart_dry[ID].ChartMotor==true) chart_dry[ID].tInChart[chart_dry[ID].posChart]|=0x80; // Признак включения мотора- старший бит в 1 - цвет фона на графике меняется chart_dry[ID].ChartMotor=false; // Температура на улице. диапазон -25 . . . +25 растягиваем на 100 точек if (packet_0x20[ID].tOut<=-2500) chart_dry[ID].tOutChart[chart_dry[ID].posChart]=0; // Если температура меньше -25 то округляем до -25 else if (packet_0x20[ID].tOut>=2500) chart_dry[ID].tOutChart[chart_dry[ID].posChart]=100-1; // Если температура больше 25 то округляем до 25 else chart_dry[ID].tOutChart[chart_dry[ID].posChart]=(packet_0x20[ID].tOut+2500)/50; // внутри -25...+25 растягиваем в два раза if (chart_dry[ID].ChartHeat==true) chart_dry[ID].tOutChart[chart_dry[ID].posChart]|=0x80; // Признак включения нагревателя- старший бит в 1 - цвет фона на графике меняется chart_dry[ID].ChartHeat=false; // Абсолютная влажность в доме диапазон от 0 до 20 грамм на кубометр, растягиваем на 100 точек if (packet_0x20[ID].absHIn>=2000) chart_dry[ID].absHInChart[chart_dry[ID].posChart]=100-1; else chart_dry[ID].absHInChart[chart_dry[ID].posChart]=packet_0x20[ID].absHIn/20; // внутри 0...20 растягиваем в пять раз в сотых % по этому делем не на 100 а на 20 // Абсолютная влажность на улицу диапазон от 0 до 20 грамм на кубометр, растягиваем на 100 точек if (packet_0x20[ID].absHOut>=2000) chart_dry[ID].absHOutChart[chart_dry[ID].posChart]=100-1; else chart_dry[ID].absHOutChart[chart_dry[ID].posChart]=packet_0x20[ID].absHOut/20; // внутри 0...20 растягиваем в пять раз, в сотых % по этому делем не на 100 а на 20 if (chart_dry[ID].posChart<120-1) chart_dry[ID].posChart++; else chart_dry[ID].posChart=0; // Изменили положение в буфере и Замкнули буфер chart_dry[ID].TimeChart=0; // Сдвиг графика и вывод новой точки сброс счетчика // dry_chart(ID); } } void dry_update(uint8_t ID) { if (chart_dry[ID].CoolData==true) { dry_data(ID); chart_dry[ID].CoolData=false; } }Файл sensor_NRF24.inо (батарейные датчики http://arduino.ru/forum/proekty/batareinyi-radio-datchik-temperatury-na-...)
//======================================================================= // Удаленные датчики температуры влажности и давления //======================================================================= // Все функции имеют на входе в качестве параметра номер датчика #define NUM_SENS 3 // Пакет передаваемый, используется также для хранения УСРЕДНЕННЫХ результатов. struct type_packet_0x30_NRF24 // Версия 1.1!! адаптация для stm32 Структура передаваемого пакета 32 байта - 32 максимум { byte id=0x00; // Идентификатор типа устройства - старшие 4 бита, вторые (младшие) 4 бита серийный номер устройства byte error=0; // Ошибка блока, пока резерв uint16_t Vcc; // Напряжение батареи Милливольты!!!!! int16_t Temp; // Температура датчика сотые градуса uint16_t relH; // Относительная влажность датчика сотые % uint16_t absH; // Абсолютная влажность датчика сотые грамма на куб uint16_t P; // Давление резерв uint16_t count=0; // Циклический счетчик пакетов 2 байта хватит на долго - около 3000 часов char ver[5] ; // Версия прошивки не более 4 байт + "0" символ char note[13] = "none"; // Примечание не более 12 байт + "0" байт Русские буквы в два раза меньше т.к. UTF-8 } packet_0x30[NUM_SENS]; // Cтруктура для графиков struct type_chart_temp { byte Chart1[120]; byte Chart2[120]; byte posChart=0; // Позиция в массиве графиков - начало вывода от 0 до 120-1 bool CoolData=false; // Признак наличия свежих данных, что бы лишний раз не выводить на экран одно и тоже } chart_temp[NUM_SENS]; void temp_static(uint8_t ID) // Печать статической картинки { int i; // Заголовок tft.fillRect(0, 0, 320-1, 20, ILI9341_BLUE); tft.setTextColor(ILI9341_WHITE); tft.drawString(int2str(newpos),2,2,2); tft.drawString(utf8rus(".УДАЛЕННЫЕ ДАТЧИКИ NRF24 ",OutputBuf),13,2,2); // tft.drawChar(hex(packet_0x30[ID].id >> 4),169,2,2); // tft.drawChar(hex(packet_0x30[ID].id&0x0f),179,2,2); // Таблица для данных tft.drawFastHLine(0,20,320-1,ILI9341_GREEN); tft.drawFastHLine(0,20+20*1,320-1,ILI9341_GREEN); tft.drawFastHLine(0,20+20*2,320-1,ILI9341_GREEN); tft.drawFastHLine(0,20+20*3,320-1,ILI9341_GREEN); tft.drawFastHLine(0,20+20*4,320-1,ILI9341_GREEN); tft.drawFastHLine(0,20+20*5,320-1,ILI9341_GREEN); tft.drawFastVLine(140-4,20,20*5, ILI9341_GREEN); tft.drawFastVLine(200-4,20,20*5, ILI9341_GREEN); tft.drawFastVLine(260,20,20*5, ILI9341_GREEN); // Заголовки таблиц // В зависимости от id разные надписи - привязка местоположения блока к ID // tft.setTextColor(ILI9341_GREEN); // tft.drawString(utf8rus("Улица",OutputBuf),250+20,22+20*0,2); tft.setTextColor(ILI9341_YELLOW); tft.drawString(utf8rus("Параметр",OutputBuf),0,22+20*0,2); tft.drawString(utf8rus("Температура C\xB0",OutputBuf),0,22+20*1,2); tft.drawString(utf8rus("Влажность %",OutputBuf),0,22+20*2,2); tft.drawString(utf8rus("Давление mbar",OutputBuf),0,22+20*3,2); tft.drawString(utf8rus("Питание В",OutputBuf),0,22+20*4,2); // Графики tft.setTextColor(ILI9341_WHITE); print_StrXY(10,125+0,utf8rus("Температура C\xB0",OutputBuf)); print_StrXY(20+154,125+0,utf8rus("Давление mbar",OutputBuf)); // надписи на графиках print_StrXY(128,140,"+20"); print_StrXY(135,180,"0"); print_StrXY(128,220,"-20"); print_StrXY(295,150,"1035"); print_StrXY(295,180,"1010"); print_StrXY(295,210,"985"); // Горизонтальная шкала по часам for(i=0;i<=120;i=i+12) { tft.drawPixel(4+i,239,ILI9341_DGRAY); tft.drawPixel(4+i,238,ILI9341_DGRAY); tft.drawPixel(167+i,239,ILI9341_DGRAY); tft.drawPixel(167+i,238,ILI9341_DGRAY); } } // Получение данных это все в прерывании быстренько надо bool temp_get_data(uint8_t *OutputBuf) { uint8_t ID; if (OutputBuf[0]==0x31) ID=0; if (OutputBuf[0]==0x32) ID=1; if (OutputBuf[0]==0x33) ID=2; chart_temp[ID].CoolData=true; // Получены свежие данные memcpy(&packet_0x30[ID],OutputBuf,sizeof(type_packet_0x30_NRF24)); // скопировать из буфера в структуру // Работаем через кольцевой буфер // Добавить новую точку в кольцевой буфер // Температура датчика. диапазон -25 . . . +25 растягиваем на 100 точек if (packet_0x30[ID].Temp<=-2500) chart_temp[ID].Chart1[chart_temp[ID].posChart]=0; // Если температура меньше -25 то округляем до -25 else if (packet_0x30[ID].Temp>=2500) chart_temp[ID].Chart1[chart_temp[ID].posChart]=100-1; // Если температура больше 25 то округляем до 25 else chart_temp[ID].Chart1[chart_temp[ID].posChart]=(packet_0x30[ID].Temp+2500)/50; // внутри -25...+25 растягиваем в два раза // Давление. диапазон 960 . . . 1060 растягиваем на 100 точек if (OutputBuf,packet_0x30[ID].P<=960) chart_temp[ID].Chart2[chart_temp[ID].posChart]=0; // Если 960 округляем 960 else if (OutputBuf,packet_0x30[ID].P>=1060) chart_temp[ID].Chart2[chart_temp[ID].posChart]=100-1; // Если температура больше 1060 то округляем до 1060 else chart_temp[ID].Chart2[chart_temp[ID].posChart]=packet_0x30[ID].P-960; // внутри 960-1060 100 точек if (chart_temp[ID].posChart<120-1) chart_temp[ID].posChart++; else chart_temp[ID].posChart=0; // Изменили положение в буфере и Замкнули буфер } void temp_update(uint8_t ID) { if (chart_temp[ID].CoolData==true) { temp_data(ID); chart_temp[ID].CoolData=false; } } void temp_data(uint8_t ID) // Печать значений датчика { switch (ID) { case 0: // ID0x31 tft.setTextColor(ILI9341_RED); tft.fillRect(140-1,22+20*0,50, 18, ILI9341_BLACK); tft.drawString(utf8rus(packet_0x30[ID].note,OutputBuf),140-1,22+20*0,2); tft.fillRect(140-1,22+20*1,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x30[ID].Temp/100.0,2),140-1,22+20*1,2); tft.fillRect(140-1,22+20*2,50, 18, ILI9341_BLACK); tft.drawString(" ---",140-1,22+20*2,2); tft.fillRect(140-1,22+20*3,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x30[ID].P,2),140-1,22+20*3,2); tft.fillRect(140-1,22+20*4,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x30[ID].Vcc/1000.0,2),140-1,22+20*4,2); break; case 1: tft.setTextColor(ILI9341_BLUE); tft.fillRect(200-1,22+20*0,50, 18, ILI9341_BLACK); tft.drawString(utf8rus(packet_0x30[ID].note,OutputBuf),200-1,22+20*0,2); tft.fillRect(200-1,22+20*1,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x30[ID].Temp/100.0,2),200-1,22+20*1,2); tft.fillRect(200-1,22+20*2,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x30[ID].relH/100.0,2),200-1,22+20*2,2); tft.fillRect(200-1,22+20*3,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x30[ID].P,2),200-1,22+20*3,2); tft.fillRect(200-1,22+20*4,50, 18, ILI9341_BLACK); tft.drawString(ftoa(OutputBuf,packet_0x30[ID].Vcc/1000.0,2),200-1,22+20*4,2); break; case 2: break; } // График temp_chart(ID); // когда выводится график на экран } // Печать графика на экране, добавляется одна точка и график сдвигается void temp_chart(uint8_t ID) { byte i,x=0; uint8_t tmp; for(i=0;i<120;i++) // График слева на право { // Вычислить координаты текущей точки x в кольцевом буфере. Изменяются от 0 до 120-1 if (chart_temp[ID].posChart<i) x=120+chart_temp[ID].posChart-i; else x=chart_temp[ID].posChart-i; // Фон tft.drawFastVLine(5+120-i,237-100,100, ILI9341_BLACK); tft.drawFastVLine(5+120-i+162,237-100,100, ILI9341_BLACK); if (i%5==0) // Пунктирные линии графика { tft.drawPixel(5+120-i,236-10-1,ILI9341_DGRAY); tft.drawPixel(5+120-i,236-50-1,ILI9341_DGRAY); tft.drawPixel(5+120-i,236-90-1,ILI9341_DGRAY); tft.drawPixel(5+120-i+162,236-25-1,ILI9341_DGRAY); tft.drawPixel(5+120-i+162,236-50-1,ILI9341_DGRAY); tft.drawPixel(5+120-i+162,236-75-1,ILI9341_DGRAY); } // Вывести новую точку if ((chart_temp[ID].Chart1[x]==0)||(chart_temp[ID].Chart1[x]==100)) tft.drawPixel(5+120-i,236-chart_temp[ID].Chart1[x],ILI9341_WHITE); else tft.drawPixel(5+120-i,236-chart_temp[ID].Chart1[x],ILI9341_RED); if ((chart_temp[ID].Chart2[x]==0)||(chart_temp[ID].Chart2[x]==100)) tft.drawPixel(5+120-i+162,236-chart_temp[ID].Chart2[x],ILI9341_WHITE); else tft.drawPixel(5+120-i+162,236-chart_temp[ID].Chart2[x],ILI9341_RED); } }Файл heatpump.ino (Контроль за тепловым насосом http://arduino.ru/forum/proekty/kontrol-za-teplovym-nasosom-na-arduino-uno)
//======================================================================= // Тепловой насос //======================================================================= // Все функции имеют на входе в качестве параметра номер датчика #define NUM_HEATPUMP 1 // число тепловых насосов // Пакет передаваемый, используется также для хранения результатов. struct type_packet_0x10_NRF24 // Версия 2.0!! адаптация для stm32 Структура передаваемого пакета 32 байта - 32 максимум { byte id=0x00; // Идентификатор типа устройства - старшие 4 бита, вторые (младшие) 4 бита серийный номер устройства byte error; // Ошибка теплового насоса int16_t tOut1=-5000,tIn1=-5000; // Текущие температуры ТП в сотых градуса !!! место экономим int16_t PowerFloor=0; // Мощность теплого пола вт int16_t tOut2=-5000,tIn2=-5000; // Текущие температуры ГК в сотых градуса !!! место экономим int16_t PowerLand=0; // Мощность геоконтура вт int16_t I,U,P; // Ток в сотых ампера, напряжение в сотых вольта, мощность в вт. // uint8_t count=0; // циклический счетчик отправленных пакетов нужен что бы на приемнике проверять качество связи char note[12] = "Heat pump"; // Примечание не более 11 байт + 0 байт Русские буквы в два раза меньше т.к. UTF-8 } packet_0x10[NUM_HEATPUMP]; // Cтруктура для графиков struct type_chart_heatpump { byte tOut2Chart[120]; // Подача теплого пола byte tIn2Chart[120]; // Обратка теплого пола byte HeatChart[120]; // Мощность теплого пола byte Power[120]; // Потребляемая мощность ТН byte COP[120]; // Коэффициент преобразования byte posChart=0; // Позиция в массиве графиков - начало вывода от 0 до 120-1 byte TimeChart=0; // Время до вывода очередной точки на график. bool ChartPump=false; // Признак работы ТН во время интервала графика если ТН был включен на любое время то на графике фон меняется в этом месте bool CoolData=false; // Признак наличия свежих данных, что бы лишний раз не выводить на экран одно и тоже } chart_heatpump[NUM_DRY]; void heatpump_static(uint8_t ID) // Печать статической картинки { int i; // Заголовок tft.fillRect(0, 0, 320-1, 20*2, ILI9341_BLUE); tft.setTextColor(ILI9341_WHITE); tft.drawString(int2str(newpos),2,2,2); tft.drawString(utf8rus(".ТЕПЛОВОЙ НАСОС ID: 0x",OutputBuf),13,2,2); tft.drawChar(hex(packet_0x20[ID].id >> 4),189,2,2); tft.drawChar(hex(packet_0x20[ID].id&0x0f),199,2,2); // Таблица для данных /* tft.drawFastHLine(0,25,320-1,ILI9341_GREEN); tft.drawFastHLine(0,25+23*1,320-1,ILI9341_GREEN); tft.drawFastHLine(0,25+23*2,320-1,ILI9341_GREEN); tft.drawFastHLine(0,25+23*3,320-1,ILI9341_GREEN); tft.drawFastHLine(0,25+23*4,320-1,ILI9341_GREEN); */ tft.drawFastVLine(140+30-11,41,1+16*5, ILI9341_GREEN); tft.drawFastVLine(220+18 ,41,1+16*5, ILI9341_GREEN); tft.drawFastHLine(0,42+16*5,320-1,ILI9341_GREEN); tft.drawString(utf8rus("Энергия P=12.5 кВт, U=220 В, A=12.5 А",OutputBuf),0,21,2); // Заголовки таблиц tft.setTextColor(ILI9341_RED); tft.drawString(utf8rus("Тепл. пол",OutputBuf),140+30-9,41+16*0,2); tft.setTextColor(ILI9341_BLUE); tft.drawString(utf8rus("Геоконтур",OutputBuf),220+20,41+16*0,2); tft.setTextColor(ILI9341_YELLOW); tft.drawString(utf8rus("СОР: ",OutputBuf),0,41+16*0,2); tft.drawString(utf8rus("Подача градусы C\xB0",OutputBuf),0,41+16*1,2); tft.drawString(utf8rus("Обратка градусы C\xB0",OutputBuf),0,41+16*2,2); tft.drawString(utf8rus("Поток. м*3/ч",OutputBuf),0,41+16*3,2); tft.drawString(utf8rus("Мощность. кВт",OutputBuf),0,41+16*4,2); // Графики tft.setTextColor(ILI9341_WHITE); print_StrXY(10,125+0,utf8rus("Температура",OutputBuf)); print_StrXY(20+154,125+0,utf8rus("Мощность",OutputBuf)); // надписи на графиках print_StrXY(128,140,"+20"); print_StrXY(135,180,"0"); print_StrXY(128,220,"-20"); print_StrXY(296,150,"15"); print_StrXY(296,180,"10"); print_StrXY(296,210,"5"); // Горизонтальная шкала по часам for(i=0;i<=120;i=i+12) { tft.drawPixel(4+i,239,ILI9341_DGRAY); tft.drawPixel(4+i,238,ILI9341_DGRAY); tft.drawPixel(167+i,239,ILI9341_DGRAY); tft.drawPixel(167+i,238,ILI9341_DGRAY); } }Файлы фонтов не менялись.
Сейчас провожу исследования по изменению питания, что бы увеличить время работы от аккумулятора.
Добрый день!
Подскажите пожалуйста, может кто сталкивался, maple mini после выключения питания сбрасывает часы реального времени.
Батарейку подключил плюсом к Vbat минусом на землю....
Добрый день! Подскажите где взять библиотеки для проекта. У меня при компиляции ругается на неверная библиотека limaple.
вот тут подробнее с картинками о том как запустить stm32 в arduino ide - blue pill
C stm32 я разобрался blink прошил работает, а когда проект компилирую то в конце ошибка неверная библиотека.
Подскажите не выводится не один идентификатор устройства все 0х00 ,как будто ничего не подключено . А часы на осушитель передаются.