Вопросы по С/С++ (СИ)

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Любая задержка - это именно задержка. То есть, останавливает всю программу. А будучи помещена в теле цикла - сделает это N раз, соответственно.

Если нужно, чтобы выполняла действие, как только пришло время - задержка тут не нужна. Нужно именно что-то вроде if (пришло время что-то сделать) { делаем что-то }. Без каких-либо задержек.
Аватара пользователя
Serzh2000
Опытный кот
Сообщения: 867
Зарегистрирован: Пт фев 27, 2015 12:00:53
Откуда: Рязанская область

Re: Вопросы по С/С++ (СИ)

Сообщение Serzh2000 »

Код: Выделить всё

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: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Да, что-то вроде. Цикл не нужен. За один вызов этого кода эта "частичная" отрисовка должна отработать только один раз. А уже на следующем вызове функции, значение q будет уже другое и отрисовано будет уже по-другому. Естественно, q должна быть либо глобальной, либо статической переменной, чтобы сохранять значение между вызовами этого кода.

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;
}
Тогда это "что-то" будет делаться не чаще раза в 75мс. А если где-то что-то подвиснет на пару миллисекунд в другом месте, то всё равно выполнится. Пусть, не через ровно 75, а на пару миллисекунд больше - некритично.
Аватара пользователя
Serzh2000
Опытный кот
Сообщения: 867
Зарегистрирован: Пт фев 27, 2015 12:00:53
Откуда: Рязанская область

Re: Вопросы по С/С++ (СИ)

Сообщение Serzh2000 »

что то стало получаться, спасибо.
программа перестала тормозить
буду думать дальше.
MOHCTEP
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Re: Вопросы по С/С++ (СИ)

Сообщение MOHCTEP »

Есть данные разной байтовой величины и знака. Необходимо сложить их побайтово в буферный массив и отправить в воздух. Оформил это дело в структуру и при попытке записи ее в буфер, 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: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Привести аргумент к типу, который требует функция TX_send:

Код: Выделить всё

TX_send((uint8_t*)&payload, sizeof(payload));
Либо объявить эту функцию иначе, подразумевая, что в неё может быть передан любой тип указателя:

Код: Выделить всё

void TX_send(void* buf, uint8_t len);
MOHCTEP
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Re: Вопросы по С/С++ (СИ)

Сообщение MOHCTEP »

WiseLord, Спасибо! Ваш 1 вариант убрал "ругань". Не пойму никак сакральную суть этих указателей...
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Функция ожидает указатель на беззнаковый байт, а Вы подсовываете её указатель на структуру. Хотя по сути значение обоих этих указателей (адрес) одно и то же, но для C это разные типы данных.

Почему это важно... ну, например, если для указателя p сделать p++ (увеличить адрес), то если это указатель на uint8_t, то получится прыжок на 1 байт, а для указателя на структуру выйдет прыжок на размер структуры.
MOHCTEP
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Re: Вопросы по С/С++ (СИ)

Сообщение MOHCTEP »

Ёшкин коот! :shock:
Вот функция записи байта/байт.

Код: Выделить всё

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;
}
Получается, что с предыдущим (ошибочным) вызовом, строка "spi_byte(*buf++);" перескакивала через len байт в каждой итерации?
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Нет. Внутри этой функции указатель в любом случае будет прыгать на sizeof(uint8_t), и что там снаружи передано - она не знает.

Предупреждение возникает снаружи, когда пытаетесь скормить функции не тот указатель. Несмотря на это, внутри оно будет работать правильно в любом случае.

Ах да, ещё у Вас есть один момент, связанный с выравниванием структур, который скорее всего даёт некорректный результат.

Код: Выделить всё

struct payload_t{
   uint8_t a;
   uint32_t b;
   int16_t c;
   uint8_t d;
   uint8_t e;
   uint8_t f;
} payload;
У этой структуры sizeof будет, думаю, 16. Ну, или 13, до конца не уверен, надо проверять.

P.S. Проверил - да, sizeof(payload) равен 16
MOHCTEP
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Re: Вопросы по С/С++ (СИ)

Сообщение MOHCTEP »

WiseLord, :) Опять спасибо!
Но что такое "выравнивание структур"? Я полагал, что структура резервирует неразрывную область в памяти, при объявлении, = своему размеру? И у меня sizeof(payload) показывает 10 байт. Как так?
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение ARV »

Я вот тоже никак не могу понять, как вышло 16 или 13...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение 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;
Я был только не уверен насчёт последних 3 байтов.
MOHCTEP писал(а):И у меня sizeof(payload) показывает 10 байт. Как так?
Где показывает?

Технически, 10 байт (без дополнительных телодвижений) может быть только если где-то в опциях компилятора стоит принудительная упаковка структур. Что технически даёт не самый оптимальный код.

Вот, например, на PC:

Изображение

P.S. На STM32:

Изображение

Если нужно гарантировано получить 10 байтов, объявлять структуру нужно с атрибутом __attribute__((packed))

Неплохая статья на тему (если быстро погуглить): https://tproger.ru/translations/art-of- ... e-packing/
MOHCTEP
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Re: Вопросы по С/С++ (СИ)

Сообщение MOHCTEP »

А, понятно теперь. :) Видимо, это напрямую связано с разрядностью процессора/контроллера? Вы работаете в 64/32 разрядной ОС, оттого и область там = 4 байтам. Надеюсь у 8-ми битных АВР такой "засады" не будет?
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Возможно, и не будет. Хотя и не уверен. Есть у меня подозрение, что там выравнивание может быть по 16 байтам, и тогда можно 12 байт для этой структуры получить. Но точно сказать не берусь.

P.S. Проверил - да, на ATmega32 получается 10 байт.
MOHCTEP
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Re: Вопросы по С/С++ (СИ)

Сообщение MOHCTEP »

WiseLord, спасибо большое за помощь! :beer: И за удовольствие от общения. Вы умеете подавать информацию лаконично и в то же время объемно и очень доступно.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение ARV »

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;
хм... я всё время был уверен, что выравнивание делается для всех полей струткуры, занимающих меньше байт, чем разрядность платформы. а вы пишите, что первый байт выравнивается до 4, а последние три - нет, и 16-битное поле на 2 не выравнивается до 4-х...
чего я не понимаю?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Однобайтные поля не выравниваются, двухбайтные выравниваются по границам чётных адресов, четырёхбайтные - по границам адресов, кратных 4.

Там пару сообщений назад я ссылку на неплохой перевод размещал.
Аватара пользователя
Serzh2000
Опытный кот
Сообщения: 867
Зарегистрирован: Пт фев 27, 2015 12:00:53
Откуда: Рязанская область

Re: Вопросы по С/С++ (СИ)

Сообщение Serzh2000 »

больше программу не тормозит цикл убрали его :)))

тепер другая напасть
начинается отрисовка цифры от начала до конца, потом примерно через 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: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Думаю, это из-за того, что вся эта анимация отрисовки занимает не ровно секунду (75ms * 12).

В итоге фаза отрисовки постоянно сползает.

Нужно сделать так, чтобы на каждой новой секунде принудительно сбрасывалось oldMillis = now; shag = 0.
Ответить

Вернуться в «Разные вопросы по МК»