[uquote="VladislavS",url="/forum/viewtopic.php?p=4009662#p4009662"]но что мешает ей писать во внешнюю?[/uquote]
Ничего не мешает как писать во внешнюю EEPROM, так и использовать менее проблемную FRAM
Здоровья всем!
Возможно ли как-то узнать длину (количество элементов) массива, записанного в флеш память? Если со строками все просто, там рулит признак eol, то как разобраться с числовыми массивами?
MOHCTEP, нет, нельзя. Когда передают указатель на данные (не важно где - в RAM или FLASH), передают другим аргументом и их длину, если она не фиксирована как-то заранее. Пусть тот, кто пишет у вас данные во флэш, пишет еще и их размер сначала.
Всем привет!
Подскажите, пжлст, что обозначают вот эти строки:
(void) USART->SR;
(void) USART->DR;
собственно SR и DR я понимаю, что это регистры модуля ЮАРТ. объединённые в структуру.
Меня интересует именно смысл этой конструкции с void-ом вначале, и что она делает.
Перед этими строками идет включение тактирования ЮАРТа, после них -- обнуление регистров. Тут вопросов нет.
Hand-Maker, прочитает их во временный регистр (не сохраняя дальше никуда). Смысл в том, чтобы обратиться к этому регистру. С некоторыми регистрами аппаратно что-то происходит от того, что их читают, и иногда это надо делать. Чтение DR/SR там вроде сбрасывает что-то... точно не помню, смотреть лениво.
[uquote="Hand-Maker",url="/forum/viewtopic.php?p=4020368#p4020368"]Подскажите, пжлст, что обозначают вот эти строки:[/uquote]Если почитать RM, то там будет написано, что последовательное чтение регистров SR и DR очищает статусы порта. Когда есть сомнения, что делает код, то хорошо подсматривать в листинг.
Ну раз неожиданно, то видимо NO
А так видимо потому что в знаковых целых отрицательный минимум на 1 больше по модулю, чем максимум. Получаем abs(INT_MIN) = 0 из-за переполнения? Отправляю пост и иду проверять )
Добавлено after 5 minutes 51 second:
Проверил. От части я прав. Вернется NO, но abs(INT_MIN) будет не 0, а неизменно -2147483648, забыл что у abs возвращаемое значение тоже знаковое. Ну понятно, это результат работы abs просто, где оно в данном случае оборачивается просто "по кругу" на данном числе.
Есть регистр CRC32->DI32. Он 16 разрядный, но я хочу данные ему скармливать побайтно. Как это написать?
(uint8_t) (CRC32->DI32) = *ptr++; - даёт ошибку "expression must be a modifiable lvalue".
Давеча экспериментировал со стартапом. Заметил, что GCC распознаёт паттерны копирования и установки памяти и заменяет их вызовами memcpy и memset. Вот эти два варианта после компиляции дают одинаковый результат.
И в обоих случаях это будет побайтовое копирование, причём и при оптимизации на скорость. Что, по меньшей мере, странно. Чтобы уговорить компилятор быстро пословно скопировать надо volatile расставить.
сделал часы с датчиком BME280
все работает как я хотел, НО зависает все (то есть на экране часы, температура, давление, влажность написаны, но не изменяются и на кнопки не реагирует) питание отключишь все работает дальше и часы не сбиваются правильно идут.
могут час или пять , полдня работать , а потом опять зависнуть. самое большое полтора суток отработали.
ардуино менял. мне кажется в коде накосячил... может кто глянет свежим глазом что не так! Спойлер//--------------Kлавиатура,------------------------------------------------------------
#define BUTTON_1 2 // Пин клавиши 1
#define BUTTON_2 3 // Пин клавиши 2
#define BUTTON_3 4 // Пин клавиши 3
//-------------------------------------------------------------
int hour,minute,second; //
int year,month,day,dayOfWeek; //
//------------------------------------------------Подключаем библиотеки внешние и в наших закладках-------------------------------------------------------
#include <Wire.h> // Подключаем библиотеку I2C
#include "rtc.h" // Подключаем нашу библиотеку часов
#include <EEPROM.h> // Импортируем бмблиотеку
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define SEALEVELPRESSURE_HPA (133)
Adafruit_BME280 bme; // I2C
#define BME280_ADDRESS (0x77)
#include <LCD_1602_RUS.h> // подключаем библиотеку LCD_1602_RUS
LCD_1602_RUS lcd(0x27,20,4); // присваиваем имя LCD для дисплея
int h1,h0,m1,m0,s1,s0; // h1 - десятки часов, h0 - еденицы часов и так далее,
int d1, d0, mn1, mn0, day_0,day_1,day_2,month_0,month_1,month_2, sec; // d1 - десятки дней, d0 - еденицы дней и так далее...
float bme_Pressure;
float bme_Humidity;
float bme_temp, bme_temp_0,bme_temp_1,bme_temp_2;// Переменная температуры
int flag=0;
int mode=0; // моде - режим вывода на экран,
uint32_t startTime; // какая то задержка 0,025 сек
int setMode=0;
int key=0; // в зависимости от нажатых клавиш принимает значение 0, 1, 2, 3 - по номерам кнопок
int keyOld=0; // старое значение нажатой клавиши
int keySpeed=0; // переменная задает скорость повтора нажатых клавиш
unsigned long now; // переменная для счетчиков реального времени
unsigned long nov; // переменная для счетчиков гошения экрана по времени
const int timerMenu=30000; // время (в мс) перед автоматическим выходом из режима настроек
static unsigned long oldMillis = 0;
bool status;
status = bme.begin();
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
lcd.setCursor(0,2); lcd.print("НЕТ BME280");
while (1);
}
// Получаем данные из EEPROM
EEPROM.get(0, day_0); EEPROM.get(5, month_0); EEPROM.get(10,bme_temp_0);
EEPROM.get(15,day_1); EEPROM.get(20,month_1); EEPROM.get(25,bme_temp_1);
EEPROM.get(30,day_2); EEPROM.get(35,month_2); EEPROM.get(40,bme_temp_2);
//================= void LOOP=======================
void loop(){
startTime=millis();
if (millis()-nov>2) {
getRTCDateTime();
h1=hour/10; // десятки часов
h0=hour%10; // еденицы часов
d1=day/10; // десятки дней
d0=day%10; // еденицы дней
m1=minute/10; // десятки минут
m0=minute%10; // еденицы минут
s1=second/10; // десятки секунд
s0=second%10; // еденицы секунд
}
if ((millis()-now>50000) && flag==0) {
mode=0; lcd.clear(); lcd.noBacklight();flag=1; //погасить свет экрана/показывать время тем.давл.влаж.
now=millis();
}
if (millis()-nov>5000 || second == 00) { //обращаться к датчику BME280 каждые пять сек.
bme_temp = bme.readTemperature();
bme_Pressure = bme.readPressure()/133.3;
bme_Humidity = bme.readHumidity();
nov=millis();
}
if(analogRead(0)<720){ //если попало питание запомнить в память
EEPROM.put(0, day_0);EEPROM.put(5, month_0);EEPROM.put(10, bme_temp_0); // Записать значение
EEPROM.put(15,day_1);EEPROM.put(20,month_1);EEPROM.put(25,bme_temp_1); // Записать значение
EEPROM.put(30,day_2);EEPROM.put(35,month_2);EEPROM.put(40,bme_temp_2); // Записать значение
lcd.clear(); Serial.println("ЗАПИСЬ");lcd.print("ЗАПИСЬ");
delay(1500);
}delay(2); //чтобы отдахнул I2C
if (mode==0){ //если экран показывает время тем.давл.влаж.
klav();disp_time(); //кнопки/обновить экран время тем.давл.влаж.
if(key==2||key==3){
now = millis(); lcd.clear();
while (millis()-now<5){
klav();
if(key==2||key==3)
lcd.clear(); mode=1; //вкл подсветку/ экран температур сегодняшнее, вчерашнее,позовчерашнее
}
key=0;
}
//------------------------------------
if(key==1){
now=millis(); lcd.clear(); // сбарсываем переменную счета таймера в (миллис)
if (millis()-now<2000){ // запускаем таймер на 2 секунду
klav();
if(key==1){
lcd.clear(); setMode=1; setUp();
}
else{
lcd.clear(); mode=1;
}
}
key=0;
}
}
//==============
if (mode==1){
klav();eeprom_lcd();
if (key==1){
now=millis(); lcd.clear(); // сбарсываем переменную счета таймера в (миллис)
while(millis()-now<5){
klav();
if(key == 1)
lcd.clear(); mode=0;
}
key=0;
}
if(key==2||key==3){
now = millis(); lcd.clear();
while (millis()-now<5){
klav();
if(key==2||key==3)
lcd.clear(); mode=0;
}
key=0;
}
}
}
//------------------------------------------------ ПРОЦЕДУРА ОПРОСА КЛАВИШ (кнопок)-----------------------------------------------------------------------
void klav(){
key=0; //
if(digitalRead(BUTTON_1)==LOW) key=1; // опрашиваем клавишу 1 и если нажата переменной присваиваем 1
if(digitalRead(BUTTON_2)==LOW) key=2; // тоже самое для клавиши 2
if(digitalRead(BUTTON_3)==LOW) key=3; // тоже длч клавиши 3, при чем если нажаты все одновременно - результат будет 3
if(key!=0){ lcd.backlight(); now = millis(); flag=0; // есил клавиши нажаты ,очищаем экран .включаем свет
delay(keySpeed<8? 200:20); // устанавливаем паузу между между опросами
keySpeed++; // эта переменная ружна для того что бы через 8 циклов уменьшить паузу между опрасами с 200 до 20
} //
if(key!=keyOld) keySpeed=0; // если была смена клавиш то флаг скорости опросов сбрасываем в 0
keyOld=key; // в переменную предыдущего состояния клавиш записываем текущее состояние клавиш
}
//-----------------------------------------------------------------------
void setUp(){
delay(500);
now = millis(); lcd.clear(); // сбарсываем переменную счета таймера в (миллис)
while (millis()-now < timerMenu){ // запускаем таймер
switch(setMode){
case 1: setUp_year(); lcd.setCursor(0,1);lcd.print("ГОД "); break;
case 2: setUp_month(); lcd.setCursor(0,1);lcd.print("МЕСЯЦ "); break;
case 3: setUp_day(); lcd.setCursor(0,1);lcd.print("ДЕНЬ "); break;
case 4: setUp_dayOfWeek();lcd.setCursor(0,1);lcd.print("НЕДЕЛЯ "); break;
case 5: setUp_hour(); lcd.setCursor(0,1);lcd.print("ЧАС "); break;
case 6: setUp_minute(); lcd.setCursor(0,1);lcd.print("МИНУТА "); break;
case 7: setUp_second(); lcd.setCursor(0,1);lcd.print("СЕКУНДЫ"); break;
case 8: return;
}
klav(); // Опрашиваем клавиши 0- не нажаты, 1-3 клавиши нажат
if(key == 1){ // если нажата
setMode++; // если нажата кнопка 1, то выходим из подпрограмы
if(setMode > mode=0;
}
}
mode=0;
}
//--------------------------------------------------------------------------------------
void setUp_second(){
now = millis(); lcd.clear(); // сбарсываем переменную счета таймера в (миллис)
while (millis()-now < timerMenu){ // запускаем таймер автовыхода из подпрограмы, если мы сейчас в позии секунд то таймер увеличиваем на 60 секунд
getRTCDateTime(); // считываем данные часы, минуты, секунды
lcd.setCursor(0,1);lcd.print("СЕКУНДЫ ");lcd.print(second);//высвечиваем секунды
klav(); // Опрашиваем клавиши 0- не нажаты, 1-3 клавиши нажаты
if(key == 1){ lcd.clear(); // если нажата кнопка 1, то выходим из подпрограмы
setMode = 8;return;
}
if(key == 2 || key == 3 ){ // если нажата кнопка 2,3
now = millis(); lcd.clear(); // сбрасывае счетчик автовыхода из подпрограмы
if (second > 30){
minute++; second=0;
}
setRTCDateTime();
}
if(key == 2 || key == 3){ // если нажата кнопка 3,2
now = millis();
if (second < 30){
second=0;
}
setRTCDateTime();
}
}
}
//============
void setUp_minute(){
now = millis(); lcd.clear(); // сбарсываем переменную счета таймера в (миллис)
while (millis()-now < timerMenu){ // запускаем таймер автовыхода из подпрограмы,
getRTCDateTime(); // считываем данные часы, минуты, секунды
lcd.setCursor(0,1);lcd.print("МИНУТЫ ");lcd.print(minute);
klav(); // Опрашиваем клавиши 0- не нажаты, 1-3 клавиши нажаты
if(key == 1){ // если нажата кнопка 1, то выходим из подпрограмы
lcd.clear(); setMode = 7;return;
}
if(key == 2){ // если нажата кнопка 2, то переходим к следующей позиции установки
now = millis(); lcd.clear(); // сбрасывае счетчик автовыхода из подпрограмы
if (minute < 60){
minute++; if (minute==60)minute=0;
}
setRTCDateTime();}
if(key == 3){ // если нажата кнопка 3, то меняеме значение переменной отображаемой в данной позиции
now = millis(); lcd.clear();
if (minute >-1){
minute--; if (minute==-1)minute=59;
}
setRTCDateTime();
}
}
}
//============
void setUp_hour(){
now = millis(); lcd.clear(); // сбарсываем переменную счета таймера в (миллис)
while (millis()-now < timerMenu){ // запускаем таймер автовыхода из подпрограмы,
getRTCDateTime(); // считываем данные часы, минуты, секунды
lcd.setCursor(0,1);lcd.print("ЧАС ");lcd.print(hour);
klav(); // Опрашиваем клавиши 0- не нажаты, 1-3 клавиши нажаты
if(key == 1){ // если нажата кнопка 1, то выходим из подпрограмы
lcd.clear(); setMode = 6;return;
}
if(key == 2){ // если нажата кнопка 2, то переходим к следующей позиции установки
now = millis(); lcd.clear(); // сбрасывае счетчик автовыхода из подпрограмы
if (hour < 24){
hour++; if (hour==24)hour=0;
}
setRTCDateTime();}
if(key == 3){ // если нажата кнопка 3, то меняеме значение переменной отображаемой в данной позиции
now = millis(); lcd.clear();
if (hour >-1){
hour--; if (hour==-1)hour=23;
}
setRTCDateTime();
}
}
}
//---------------------------------------------------------------------------------------
void setUp_dayOfWeek(){ //
now = millis(); lcd.clear(); // сбарсываем переменную счета таймера в (миллис)
while (millis()-now < timerMenu){ // запускаем таймер автовыхода из подпрограмы, если мы сейчас в позии секунд то таймер увеличиваем на 60 секунд
getRTCDateTime(); // считываем данные часы, минуты, секунды
switch(dayOfWeek){
case 0:lcd.setCursor(0,1);lcd.print("ДЕНЬ НЕДЕЛИ");lcd.setCursor(0,2);lcd.print("ПОНЕДЕЛЬНИК");
break;
case 1:lcd.setCursor(0,1);lcd.print("ДЕНЬ НЕДЕЛИ");lcd.setCursor(0,2);lcd.print("ВТОРНИК ");
break;
case 2:lcd.setCursor(0,1);lcd.print("ДЕНЬ НЕДЕЛИ");lcd.setCursor(0,2);lcd.print("СРЕДА ");
break;
case 3:lcd.setCursor(0,1);lcd.print("ДЕНЬ НЕДЕЛИ");lcd.setCursor(0,2);lcd.print("ЧЕТВЕРГ ");
break;
case 4:lcd.setCursor(0,1);lcd.print("ДЕНЬ НЕДЕЛИ");lcd.setCursor(0,2);lcd.print("ПЯТНИЦА ");
break;
case 5:lcd.setCursor(0,1);lcd.print("ДЕНЬ НЕДЕЛИ");lcd.setCursor(0,2);lcd.print("СУББОТА ");
break;
case 6:lcd.setCursor(0,1);lcd.print("ДЕНЬ НЕДЕЛИ");lcd.setCursor(0,2);lcd.print("ВОСКРЕСЕНЬЕ");
break;
}
klav(); // Опрашиваем клавиши 0- не нажаты, 1-3 клавиши нажаты
if(key == 1){ // если нажата кнопка 1, то выходим из подпрограмы
lcd.clear(); setMode = 5;return; //
}
if(key == 2){ // если нажата кнопка 2, то переходим к следующей позиции установки
now = millis(); lcd.clear(); // сбрасывае счетчик автовыхода из подпрограмы
if (dayOfWeek < 7){
dayOfWeek++;if (dayOfWeek==7)dayOfWeek=0;
}
setRTCDateTime();
} //
if(key == 3){ // если нажата кнопка 3, то меняеме значение переменной отображаемой в данной позиции
now = millis(); lcd.clear();
if (dayOfWeek > -1){
dayOfWeek--;if (dayOfWeek==-1)dayOfWeek=6;
}
setRTCDateTime(); //запись в РТС
}
}
}
//---------------------------------------------------------------------------------------
void setUp_month(){ //
now = millis(); lcd.clear(); // сбарсываем переменную счета таймера в (миллис)
while (millis()-now < timerMenu){ // запускаем таймер автовыхода из подпрограмы,
getRTCDateTime(); // считываем данные часы, минуты, секунды
lcd.setCursor(0,1);lcd.print("МЕСЯЦ");
lcd.setCursor(0,2);
if (month==1) {lcd.print("ЯНВАРЬ");}
if (month==2) {lcd.print("ФЕВРАЛЬ");}
if (month==3) {lcd.print("МАРТ");}
if (month==4) {lcd.print("АПРЕЛЬ");}
if (month==5) {lcd.print("МАЙ");}
if (month==6) {lcd.print("ИЮНЬ");}
if (month==7) {lcd.print("ИЮЛЬ");}
if (month==8) {lcd.print("АВГУСТ");}
if (month==9) {lcd.print("СЕНТЯБРЬ");}
if (month==10) {lcd.print("ОКТЯБРЬ");}
if (month==11) {lcd.print("НОЯБРЬ");}
if (month==12) {lcd.print("ДЕКАБРЬ");}
klav(); // Опрашиваем клавиши 0- не нажаты, 1-3 клавиши нажаты
if(key == 1){ // если нажата кнопка 1, то выходим из подпрограмы
lcd.clear(); setMode = 3;return;
}
if(key == 2){ // если нажата кнопка 2, то переходим к следующей позиции установки
now = millis(); lcd.clear(); // сбрасывае счетчик автовыхода из подпрограмы
if (13 > month ){
month++; if (month==13)month=1;
}
setRTCDateTime();
}
if(key == 3){ // если нажата кнопка 3, то меняеме значение переменной отображаемой в данной позиции
now = millis(); lcd.clear();
if (month >0 ){
month--; if (month==0)month=12;
}
setRTCDateTime();
}
}
}
//------------------------------------------------------------------------------------
void setUp_day(){
now = millis(); lcd.clear(); // сбарсываем переменную счета таймера в (миллис)
while (millis()-now < timerMenu){ // запускаем таймер автовыхода из подпрограмы, если мы сейчас в позии секунд то таймер увеличиваем на 60 секунд
getRTCDateTime(); // считываем данные часы, минуты, секунды
lcd.setCursor(0,1);lcd.print("ДЕНЬ ");lcd.print(day);
klav(); // Опрашиваем клавиши 0- не нажаты, 1-3 клавиши нажаты
if(key == 1){ // если нажата кнопка 1, то выходим из подпрограмы
lcd.clear(); setMode = 4;return;
}
if(key == 2){ // если нажата кнопка 2,
now = millis(); lcd.clear(); // сбрасывае счетчик автовыхода из подпрограмы
if (day < 32){
day++; if (day==32)day=1;
setRTCDateTime();}
} //
if(key == 3){ // если нажата кнопка 3,
now = millis(); lcd.clear();
if (0 < day){
day--; if (day==0)day=31;
}
setRTCDateTime();
}
}
}
//-----------------------------------------------------------------------
void setUp_year(){
now = millis(); lcd.clear(); // сбарсываем переменную счета таймера в (миллис)
while (millis()-now < timerMenu){ // запускаем таймер автовыхода из подпрограмы, если мы сейчас в позии секунд то таймер увеличиваем на 60 секунд
getRTCDateTime(); // считываем данные часы, минуты, секунды
lcd.setCursor(0,1);lcd.print("ГОД ");lcd.print(year);
klav(); // Опрашиваем клавиши 0- не нажаты, 1-3 клавиши нажаты
if(key == 1){ // если нажата кнопка 1, то выходим из подпрограмы
lcd.clear(); setMode = 2;return;
}
if(key == 2){ // если нажата кнопка 2, то переходим к следующей позиции установки
now = millis(); lcd.clear(); // сбрасывае счетчик автовыхода из подпрограмы
if (year < 2100){
year++;
setRTCDateTime();}
} //
if(key == 3){ // если нажата кнопка 3, то меняеме значение переменной отображаемой в данной позиции
now = millis(); lcd.clear();
if (2020 < year){
year--;
}
setRTCDateTime();
}
}
}
lcd.setCursor(10,0);
if (d1>0){lcd.print(d1);lcd.print(d0);}
else {lcd.print(" ");lcd.print(d0);}
// lcd.print(day);
lcd.print(" ");
switch (dayOfWeek) {
case 0:
lcd.print("Пн");
break;
case 1:
lcd.print("Вт");
break;
case 2:
lcd.print("Ср");
break;
case 3:
lcd.print("Чт");
break;
case 4:
lcd.print("Пт");
break;
case 5:
lcd.print("Сб");
break;
case 6:
lcd.print("Вс");
break;
case 7:dayOfWeek=0;setRTCDateTime();
break;
ну зависает часы с датчиком ВМЕ280 хоть ты тресни...
скажите, а у меня датчик через провод (витая пара UTP 2х2х0,5 ) 3 метра подключен к ардуине, может из за этого виснуть?
или может все незадействованные ноги ардуино посадить на минус, чтобы не ловили помехи какие-нибудь
или подключить к земле, - используя параметр INPUT_PULLUP?
блоки питания менял и 5 вольтовый был , и сейчас 7,5 вольтовый через кренку, конденсатор 2200мкф, 0,1мкф стоит от какой-то тв приставки, все одно виснет...
посоветуйте , что еще бы можно сделать.