Вопросы по С/С++ (СИ)
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Любая задержка - это именно задержка. То есть, останавливает всю программу. А будучи помещена в теле цикла - сделает это N раз, соответственно.
Если нужно, чтобы выполняла действие, как только пришло время - задержка тут не нужна. Нужно именно что-то вроде if (пришло время что-то сделать) { делаем что-то }. Без каких-либо задержек.
Если нужно, чтобы выполняла действие, как только пришло время - задержка тут не нужна. Нужно именно что-то вроде if (пришло время что-то сделать) { делаем что-то }. Без каких-либо задержек.
- Serzh2000
- Опытный кот
- Сообщения: 867
- Зарегистрирован: Пт фев 27, 2015 12:00:53
- Откуда: Рязанская область
Re: Вопросы по С/С++ (СИ)
Код: Выделить всё
int q = 0;
1начало
2...
3...
4 if (millis() % 75==0) {
5 q++ ;
6 ...
7 refreshAll(); // вывод на экран
8 if (q < 12) { q=0;}
9 }
10...
11...
12 конец- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Да, что-то вроде. Цикл не нужен. За один вызов этого кода эта "частичная" отрисовка должна отработать только один раз. А уже на следующем вызове функции, значение q будет уже другое и отрисовано будет уже по-другому. Естественно, q должна быть либо глобальной, либо статической переменной, чтобы сохранять значение между вызовами этого кода.
P.S. Только if (q < 12) { q=0;} - неправильное условие - всегда будет на 0 выходить.
Опять же, условие if (millis() % 75==0) не очень корректное. Потому что именно в эту (одну из 75) миллисекунду, когда остаток от деления на 75 равен нулю, очень велик шанс, что будет выполняться код совсем где-то в другом месте, так что, пока программа придёт к этому месту, всё уже поменяется, и это условие не выполнится.
Лучше значение, возвращаемое millis(), запомнить (например, в переменной oldMillis). А затем, когда снова программа придёт к этому месту, проверить, сколько прошло времени. То есть, что-то вроде.
Тогда это "что-то" будет делаться не чаще раза в 75мс. А если где-то что-то подвиснет на пару миллисекунд в другом месте, то всё равно выполнится. Пусть, не через ровно 75, а на пару миллисекунд больше - некритично.
P.S. Только if (q < 12) { q=0;} - неправильное условие - всегда будет на 0 выходить.
Опять же, условие if (millis() % 75==0) не очень корректное. Потому что именно в эту (одну из 75) миллисекунду, когда остаток от деления на 75 равен нулю, очень велик шанс, что будет выполняться код совсем где-то в другом месте, так что, пока программа придёт к этому месту, всё уже поменяется, и это условие не выполнится.
Лучше значение, возвращаемое millis(), запомнить (например, в переменной oldMillis). А затем, когда снова программа придёт к этому месту, проверить, сколько прошло времени. То есть, что-то вроде.
Код: Выделить всё
static unsigned long oldMillis = 0;
...
unsigned long now = millis();
if (now - oldMIllis >= 75) {
// делаем что-то;
oldMillis = now;
}- Serzh2000
- Опытный кот
- Сообщения: 867
- Зарегистрирован: Пт фев 27, 2015 12:00:53
- Откуда: Рязанская область
Re: Вопросы по С/С++ (СИ)
что то стало получаться, спасибо.
программа перестала тормозить
буду думать дальше.
программа перестала тормозить
буду думать дальше.
Re: Вопросы по С/С++ (СИ)
Есть данные разной байтовой величины и знака. Необходимо сложить их побайтово в буферный массив и отправить в воздух. Оформил это дело в структуру и при попытке записи ее в буфер, 7 студия выдает ворнинг и мессагу, при чем - через раз. Бывает, что и спокойно откомпилирует. Как это дело побороть, подскажите пожалуйста.
Код: Выделить всё
struct payload_t{
uint8_t a;
uint32_t b;
int16_t c;
uint8_t d;
uint8_t e;
uint8_t f;
} payload;
//************
void tx_data(){
TX_send(&payload, sizeof(payload));
...
}
//************
void TX_send(uint8_t* buf, uint8_t len){
...
_write(W_TX_PAYLOAD, buf, len);
...
}Message expected 'uint8_t *' but argument is of type 'struct payload_t *'
Warning passing argument 1 of 'TX_send' from incompatible pointer type
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Привести аргумент к типу, который требует функция TX_send:
Либо объявить эту функцию иначе, подразумевая, что в неё может быть передан любой тип указателя:
Код: Выделить всё
TX_send((uint8_t*)&payload, sizeof(payload));Код: Выделить всё
void TX_send(void* buf, uint8_t len);Re: Вопросы по С/С++ (СИ)
WiseLord, Спасибо! Ваш 1 вариант убрал "ругань". Не пойму никак сакральную суть этих указателей...
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Функция ожидает указатель на беззнаковый байт, а Вы подсовываете её указатель на структуру. Хотя по сути значение обоих этих указателей (адрес) одно и то же, но для C это разные типы данных.
Почему это важно... ну, например, если для указателя p сделать p++ (увеличить адрес), то если это указатель на uint8_t, то получится прыжок на 1 байт, а для указателя на структуру выйдет прыжок на размер структуры.
Почему это важно... ну, например, если для указателя p сделать p++ (увеличить адрес), то если это указатель на uint8_t, то получится прыжок на 1 байт, а для указателя на структуру выйдет прыжок на размер структуры.
Re: Вопросы по С/С++ (СИ)
Ёшкин коот!
Вот функция записи байта/байт.
Получается, что с предыдущим (ошибочным) вызовом, строка "spi_byte(*buf++);" перескакивала через len байт в каждой итерации?
Вот функция записи байта/байт.
Код: Выделить всё
void _write(uint8_t reg, uint8_t* buf, uint8_t len){
CS_LOW;
spi_byte((reg & REGISTER_MASK) | W_REGISTER);
while(len--){
spi_byte(*buf++);
}
CS_HIGH;
}- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Нет. Внутри этой функции указатель в любом случае будет прыгать на sizeof(uint8_t), и что там снаружи передано - она не знает.
Предупреждение возникает снаружи, когда пытаетесь скормить функции не тот указатель. Несмотря на это, внутри оно будет работать правильно в любом случае.
Ах да, ещё у Вас есть один момент, связанный с выравниванием структур, который скорее всего даёт некорректный результат.
У этой структуры sizeof будет, думаю, 16. Ну, или 13, до конца не уверен, надо проверять.
P.S. Проверил - да, sizeof(payload) равен 16
Предупреждение возникает снаружи, когда пытаетесь скормить функции не тот указатель. Несмотря на это, внутри оно будет работать правильно в любом случае.
Ах да, ещё у Вас есть один момент, связанный с выравниванием структур, который скорее всего даёт некорректный результат.
Код: Выделить всё
struct payload_t{
uint8_t a;
uint32_t b;
int16_t c;
uint8_t d;
uint8_t e;
uint8_t f;
} payload;P.S. Проверил - да, sizeof(payload) равен 16
Re: Вопросы по С/С++ (СИ)
WiseLord,
Опять спасибо!
Но что такое "выравнивание структур"? Я полагал, что структура резервирует неразрывную область в памяти, при объявлении, = своему размеру? И у меня sizeof(payload) показывает 10 байт. Как так?
Но что такое "выравнивание структур"? Я полагал, что структура резервирует неразрывную область в памяти, при объявлении, = своему размеру? И у меня sizeof(payload) показывает 10 байт. Как так?
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Я вот тоже никак не могу понять, как вышло 16 или 13...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Легко:
Я был только не уверен насчёт последних 3 байтов.
Технически, 10 байт (без дополнительных телодвижений) может быть только если где-то в опциях компилятора стоит принудительная упаковка структур. Что технически даёт не самый оптимальный код.
Вот, например, на PC:

P.S. На STM32:

Если нужно гарантировано получить 10 байтов, объявлять структуру нужно с атрибутом __attribute__((packed))
Неплохая статья на тему (если быстро погуглить): https://tproger.ru/translations/art-of- ... e-packing/
Код: Выделить всё
struct payload_t{
// -----------------------------------------------------
uint8_t a; // 1 байт
// дырка 3 байта - выравнивание до 4
// -----------------------------------------------------
uint32_t b; // 4 байта
// -----------------------------------------------------
int16_t c; // 2 байта
uint8_t d; // 1 байт
uint8_t e; // 1 байт
// -----------------------------------------------------
uint8_t f; // 1 байт
// дырка 3 байта - выравнивание до 4
} payload;Где показывает?MOHCTEP писал(а):И у меня sizeof(payload) показывает 10 байт. Как так?
Технически, 10 байт (без дополнительных телодвижений) может быть только если где-то в опциях компилятора стоит принудительная упаковка структур. Что технически даёт не самый оптимальный код.
Вот, например, на PC:
P.S. На STM32:
Если нужно гарантировано получить 10 байтов, объявлять структуру нужно с атрибутом __attribute__((packed))
Неплохая статья на тему (если быстро погуглить): https://tproger.ru/translations/art-of- ... e-packing/
Re: Вопросы по С/С++ (СИ)
А, понятно теперь.
Видимо, это напрямую связано с разрядностью процессора/контроллера? Вы работаете в 64/32 разрядной ОС, оттого и область там = 4 байтам. Надеюсь у 8-ми битных АВР такой "засады" не будет?
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Возможно, и не будет. Хотя и не уверен. Есть у меня подозрение, что там выравнивание может быть по 16 байтам, и тогда можно 12 байт для этой структуры получить. Но точно сказать не берусь.
P.S. Проверил - да, на ATmega32 получается 10 байт.
P.S. Проверил - да, на ATmega32 получается 10 байт.
Re: Вопросы по С/С++ (СИ)
WiseLord, спасибо большое за помощь!
И за удовольствие от общения. Вы умеете подавать информацию лаконично и в то же время объемно и очень доступно.
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
хм... я всё время был уверен, что выравнивание делается для всех полей струткуры, занимающих меньше байт, чем разрядность платформы. а вы пишите, что первый байт выравнивается до 4, а последние три - нет, и 16-битное поле на 2 не выравнивается до 4-х...WiseLord писал(а):Код: Выделить всё
struct payload_t{ // ---------- uint8_t a; // 1 байт // дырка 3 байта - выравнивание до 4 // ---------- uint32_t b; // 4 байта // ---------- int16_t c; // 2 байта uint8_t d; // 1 байт uint8_t e; // 1 байт // ---------- uint8_t f; // 1 байт // дырка 3 байта - выравнивание до 4 } payload;
чего я не понимаю?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Однобайтные поля не выравниваются, двухбайтные выравниваются по границам чётных адресов, четырёхбайтные - по границам адресов, кратных 4.
Там пару сообщений назад я ссылку на неплохой перевод размещал.
Там пару сообщений назад я ссылку на неплохой перевод размещал.
- Serzh2000
- Опытный кот
- Сообщения: 867
- Зарегистрирован: Пт фев 27, 2015 12:00:53
- Откуда: Рязанская область
Re: Вопросы по С/С++ (СИ)
больше программу не тормозит цикл убрали его
тепер другая напасть
начинается отрисовка цифры от начала до конца, потом примерно через 5 сек от середины до конца, потом самый конет отрисовывается и опять от начало до конца...
else showDigit(s0, 28, dig3x7s); // s0 - номер строки в масиве dig3x7s (смотрим вкладку "fonts.h")
if (s1 != lasts1) showDigit( s1 * 12 + shag, 24, dig3x7q); //24- позиция экрана с которой начинать печать
else showDigit(s1, 24, dig3x7s); //24- позиция экрана с которой начинать печать
if (m0 != lastm0) showDigit( m0 * 12 + shag, 17, dig4x8q); // dig3x7q - указатель на масив данных (смотрим вкладку "fonts.h")
else showDigit(m0, 17, dig4x8); // dig4x8 - указатель на масив данных (смотрим вкладку "fonts.h")
if (m1 != lastm1) showDigit( m1 * 12 + shag, 12, dig4x8q); // (m1 != lastm1)- проверяем изменилась цифра или нет
else showDigit(m1, 12, dig4x8);
if (h0 != lasth0) showDigit( h0 * 12 + shag, 5, dig4x8q);
else showDigit(h0, 5, dig4x8);
if (h1>0){
if (h1 != lasth1)showDigit( h1 * 12 + shag, 0, dig4x8q);
else showDigit(h1, 0, dig4x8);}
refreshAll(); // обновляем экран после каждой строки
unsigned long now = millis();
if (now - oldMillis >= 75) {
shag++;
Serial.print(now - oldMillis);
oldMillis = now;
}
if (shag >= 12) { shag=0; lasth1 = h1; lasth0 = h0; lastm1 = m1; lastm0 = m0; lasts1 = s1; lasts0 = s0;} // для того чтобы знать изменилась цифра или нет
}
посмотрите может скажите куда "грести"?
тепер другая напасть
начинается отрисовка цифры от начала до конца, потом примерно через 5 сек от середины до конца, потом самый конет отрисовывается и опять от начало до конца...
Спойлер
if (s0 != lasts0){showDigit( s0 * 12 + shag, 28, dig3x7q);} // s0 * 12 + q - номер строки в масиве dig3x7q (смотрим вкладку "fonts.h")else showDigit(s0, 28, dig3x7s); // s0 - номер строки в масиве dig3x7s (смотрим вкладку "fonts.h")
if (s1 != lasts1) showDigit( s1 * 12 + shag, 24, dig3x7q); //24- позиция экрана с которой начинать печать
else showDigit(s1, 24, dig3x7s); //24- позиция экрана с которой начинать печать
if (m0 != lastm0) showDigit( m0 * 12 + shag, 17, dig4x8q); // dig3x7q - указатель на масив данных (смотрим вкладку "fonts.h")
else showDigit(m0, 17, dig4x8); // dig4x8 - указатель на масив данных (смотрим вкладку "fonts.h")
if (m1 != lastm1) showDigit( m1 * 12 + shag, 12, dig4x8q); // (m1 != lastm1)- проверяем изменилась цифра или нет
else showDigit(m1, 12, dig4x8);
if (h0 != lasth0) showDigit( h0 * 12 + shag, 5, dig4x8q);
else showDigit(h0, 5, dig4x8);
if (h1>0){
if (h1 != lasth1)showDigit( h1 * 12 + shag, 0, dig4x8q);
else showDigit(h1, 0, dig4x8);}
refreshAll(); // обновляем экран после каждой строки
unsigned long now = millis();
if (now - oldMillis >= 75) {
shag++;
Serial.print(now - oldMillis);
oldMillis = now;
}
if (shag >= 12) { shag=0; lasth1 = h1; lasth0 = h0; lastm1 = m1; lastm0 = m0; lasts1 = s1; lasts0 = s0;} // для того чтобы знать изменилась цифра или нет
}
посмотрите может скажите куда "грести"?
- Вложения
-
- chernjvik.zip
- (42.36 КБ) 105 скачиваний
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Думаю, это из-за того, что вся эта анимация отрисовки занимает не ровно секунду (75ms * 12).
В итоге фаза отрисовки постоянно сползает.
Нужно сделать так, чтобы на каждой новой секунде принудительно сбрасывалось oldMillis = now; shag = 0.
В итоге фаза отрисовки постоянно сползает.
Нужно сделать так, чтобы на каждой новой секунде принудительно сбрасывалось oldMillis = now; shag = 0.