Удаленный мониторинг за датчиками на 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
Заменить Font16.h
4. Откопал на чипе stm32 RTC (часы реального времени). Надо только часовой кварц припаять -))). Запустил часики. Теперь блок в кватанции в ответ на полученную информацию отсылает текущее время. На удаленнных блоках часы реализуются легко. Часы правда не с первого раза получились, но в конце концов запустились как надо.
Проект название поменялось на stm32_server_GFX
Файл stm32_server_GFX.ino
Файл dry_control.ino
Проект продолжает развиваться только на stm32, Больше не будет поддерживаться двух платфор avr и stm32 одновременно.
Очередная модификация кода. Основные изменения:
1. Добавлен экран по контролю тепловым насосом. Данные передаются но пока графики не выводятся.
2. В рамках развития проекта сделал автономный датчик температуры и давления (на ВМ180 и pro mini) питание от одной литиевой батереи 1/2 АА 3.6 вольта. Ток потребления в режиме power_down около 40 мкА. Передача данных раз в 5 минут по nrf24 (будет отдельный пост). Теперь головной блок выводит информацию с этих датчиков. Возможно подключение до 3 шт.
3. Не значительная опитмизация кода.
Код stm32_server_GFX.ino (основной блок без особенностьей переферии)
Файл dry_control.ino (Контроль влажности подвала http://arduino.ru/forum/proekty/kontrol-vlazhnosti-podvala-arduino-pro-mini)
Файл sensor_NRF24.inо (батарейные датчики http://arduino.ru/forum/proekty/batareinyi-radio-datchik-temperatury-na-...)
Файл heatpump.ino (Контроль за тепловым насосом http://arduino.ru/forum/proekty/kontrol-za-teplovym-nasosom-na-arduino-uno)
Файлы фонтов не менялись.
Сейчас провожу исследования по изменению питания, что бы увеличить время работы от аккумулятора.
Добрый день!
Подскажите пожалуйста, может кто сталкивался, maple mini после выключения питания сбрасывает часы реального времени.
Батарейку подключил плюсом к Vbat минусом на землю....
Добрый день! Подскажите где взять библиотеки для проекта. У меня при компиляции ругается на неверная библиотека limaple.
вот тут подробнее с картинками о том как запустить stm32 в arduino ide - blue pill
C stm32 я разобрался blink прошил работает, а когда проект компилирую то в конце ошибка неверная библиотека.
Подскажите не выводится не один идентификатор устройства все 0х00 ,как будто ничего не подключено . А часы на осушитель передаются.