Ну раз неожиданно, то видимо 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".
Качественное и безопасное устройство, работающее от аккумулятора, должно учитывать его физические и химические свойства, профили заряда и разряда, их изменение во времени и под влиянием различных условий, таких как температура и ток нагрузки. Мы расскажем о литий-ионных аккумуляторных батареях EVE и нескольких решениях от различных китайских компаний, рекомендуемых для разработок приложений с использованием этих АКБ. Представленные в статье китайские аналоги помогут заменить продукцию западных брендов с оптимизацией цены без потери качества.
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
Давеча экспериментировал со стартапом. Заметил, что GCC распознаёт паттерны копирования и установки памяти и заменяет их вызовами memcpy и memset. Вот эти два варианта после компиляции дают одинаковый результат.
И в обоих случаях это будет побайтовое копирование, причём и при оптимизации на скорость. Что, по меньшей мере, странно. Чтобы уговорить компилятор быстро пословно скопировать надо volatile расставить.
сделал часы с датчиком BME280 все работает как я хотел, НО зависает все (то есть на экране часы, температура, давление, влажность написаны, но не изменяются и на кнопки не реагирует) питание отключишь все работает дальше и часы не сбиваются правильно идут. могут час или пять , полдня работать , а потом опять зависнуть. самое большое полтора суток отработали. ардуино менял. мне кажется в коде накосячил... может кто глянет свежим глазом что не так! Спойлер//----------,---------- #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мкф стоит от какой-то тв приставки, все одно виснет... посоветуйте , что еще бы можно сделать.
Всем здрасте. До этого программировал avr в Flowcode. Я новичок в Си, месяц читаю и в большинстве всё понятно. НО, откуда берут какой #include в каком случае, как например для задержки времени _delay_us надо включить <avr/delay.h>, но нигде не говорят где и в каком случае подключать другие файлы библиотеки и какие переменные/имена использовать из той библиотеки. К примеру хочу I2C, какой #include< > мне для этого нужен и какие имена из него использовать и т.д.?
// считаем входы if(++entry >= IND_RPT){ entry = 0; // каждые 2 мс two_ms++; // смена разряда scr++; if(++pos >= POS_CNT){ pos = 0; scr = screen; } regs.word = _BV(11+pos); } // готовим один из двух символов для вывода regs.word &= 0xf800; regs.word |= digs[scr->symbol[entry >= scr->bright]];
// выдача в сдвиговые регистры через SPI SPDR = regs.bytes[1]; while(bit_is_clear(SPSR, SPIF)); SPDR = regs.bytes[0]; while(bit_is_clear(SPSR, SPIF)); // строб для защелкивания данных PORTB |= LOAD_PIN; PORTB &= ~LOAD_PIN; }
вот такой код для динамической индикации. каждые 2 мс происходит смена разряда, а каждый заход в обработчик происходит обновление символов (символов два, сначала выводится один, а когда количество входов превысит заданное значение - другой, таким образом реализована "плавная" смена символов).
так вот, код этот РАБОТАЕТ. но, если внимательно посмотреть на него, а именно на структуру regs, то станет понятно, что работать он НЕ ДОЛЖЕН: структура локальная, значит, содержимое её при каждом новом входе не определено, а значит, строка после комментария "готовим один из двух символов для вывода" не имеет смысла - подавлять часть разрядов поля структуры для того, чтобы сохранить биты управления разрядом индикатора, нет смысла - там неизвестно что может быть! кстати, некоторые версии компилятора avr-gcc предупреждают, что переменная тут может быть не проинициализирована, некоторые этот факт игнорируют, но при оптимизации -O3 код работает после компиляции любой версией (проверял 4 разных, от 4.хх.хх до 10.хх.хх). и еще кстати, при -Os код не работает так же независимо от версии компилятора.
казалось бы, в чем беда? делаем структуру static и... и код НЕ РАБОТАЕТ!!!!!!!! то есть когда от прерывания к прерыванию я сохраняю состояние структуры, т.е. значение битов, управляющих разрядами индикатора, это не только не делает нерабочий код рабочим, но и полностью рушит индикацию!
может кто-нибудь пояснить, что происходит?!
да, структура regs такая:
Код:
typedef union{ uint8_t bytes[2]; // 2 байта для выдачи в регистры uint16_t word; } regs_t;
идея индикации следующая: старшие 5 битов в regs.word задают номер светящегося разряда индикатора, а остальные - выводимый символ (для ГРИ это 1 бит в нужном разряде). потом эти 16 бит выдаются побайтно в регистры 74HC595 и управляют индикаторами.
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
То, что код работает, хотя и не должен - можно сослаться на "везение" в том смысле, что regs всегда попадает на один и тот же определённый адрес при определённом уровне оптимизации.
А вот то, что код не работает в случае static - да, более странно. Но не может ли быть так, что доступ к "статической" структуре получается с точки зрения ассемблера более длинным, что в итоге является той каплей, что прерывание не успевает выполниться за нужное время?
Я о том, что два while() внутри прерывания при передаче по SPI могут быть "впритирку" ко времени между вызовами сосбственно прерываний.
Но не может ли быть так, что доступ к "статической" структуре получается с точки зрения ассемблера более длинным, что в итоге является той каплей, что прерывание не успевает выполниться за нужное время?
да, но что в таком случае может происходить? только то, что основной цикл станет выполняться очень медленно, а динамическая индикация продолжится, хоть и с некоторыми артефактами вроде разной яркости разрядов.
у меня же происходит вообще странное: во всех разрядах начинают "призрачно" дублироваться цифры соседних, т.е. в кажом разряде светится правильная цифра наиболее ярко, и слегка просвечивают цифры, которые на всех остальных. будто у меня команда, маскирующая "символьную" часть структуры, не выполняет свою задачу...
самое-то главное: что делать-то? проблему я вычислил случайно, когда стал пытаться добиться выключения разряда вообще - стоит что-то в обработчик добавить, и начинаются проблемы. писать обработчик на ассемблере очень не хочется - отвык уже.
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
только то, что основной цикл станет выполняться очень медленно, а динамическая индикация продолжится, хоть и с некоторыми артефактами вроде разной яркости разрядов. у меня же происходит вообще странное: во всех разрядах начинают "призрачно" дублироваться цифры соседних, т.е. в кажом разряде светится правильная цифра наиболее ярко, и слегка просвечивают цифры, которые на всех остальных. будто у меня команда, маскирующая "символьную" часть структуры, не выполняет свою задачу...
Что тут непонятного? regs.word |= digs[scr->symbol[entry >= scr->bright]]; выполняется в каждом ISR. Не знаю что такое digs, предположу что оно хранит младшие 11 бит. Тогда эти 11 бит будут верными при каждом вызове ISR. Если эти 11 бит - карта сегментов, то она всегда будет правильной передаваться в SPI. А старшие 5 бит (позиция?) будут неправильными. И то - если других прерываний нет, то место занимаемое в стеке regs может оказаться неразрушенным (и сохраниться от момента последней правильной записи старших 5 бит). Тогда и позиция будет передаваться правильная. Но иногда (когда содержимое regs трётся в стеке другой процедурой), то позиция будет неправильная (при правильных сегментах). А значит и будет наблюдаться - в основном правильное отображение, но иногда символы будут попадать в неправильные случайные позиции. Это будет редко, поэтому светится они там будут слабо.
PS: Ожидание завершения передачи по SPI в while() внутри ISR - это конечно верх быдлокодинга... Если конечно там (в МК) имеется FIFO глубиной >= 2 байта и while() ожидает не завершения передачи, а завершения записи в FIFO, то тогда - нормально.
а вы посмотрите внимательно: regs.word &= 0xf800; regs.word |= digs[scr->symbol[entry >= scr->bright]]; младшие 11 бит в каждом прерывании меняются, а старшие 5 - только каждое 62 прерывание. то есть так должно быть, если regs будет static. вопрос не в том, почему без static работает (хоть это и странно, но вполне логичное объяснение вы сами и дали), вопрос в том, почему со static не работает?! ведь благодаря static старшие биты сохраняются не из-за случая в стеке/памяти, а абсолютно однозначно! то есть должно быть лучше, а по факту - становится хуже. как это объясните?
jcxz писал(а):
Ожидание завершения передачи по SPI в while() внутри ISR - это конечно верх быдлокодинга
SPI работает на частоте вдвое меньше тактовой, т.е. передача 1 байта требует 16 тактов - пока исполнится код, организующий ожидание, пройдет половина этого интервала. вам известны более красивые способы отправки двух байт с последующей дрыгоножной выдачей строба на классическом AVR? посоветуйте, я всегда готов учиться хорошему. а грубить я умею и сам.
чисто теоретически вывод в регистры можно делать в главном цикле, а в прерывании обойтись классическими флагами, но, боюсь, это приведет к гораздо большим проблемам с индкацией...
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
У вас структура regs определяется каждый раз при запуске прерывания и имеет в качестве данных мусор (что вы и написали). А первое присвоение происходит в условии if. А если условие ложное то структура не заполниться и строки
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 22
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения