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

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Apparatchik писал(а):почему так происходит
во-первых, у вас 2 разных выражения, отсюда и разный объем при использовании одного и другого:
Apparatchik писал(а):   return (value / 16) * 10 + (value % 16);
// return (value >> 4) * 10 + (value & 0x0F);
во-вторых, если функция объявлена static и используется только в одном месте, она почти со 100% гарантией будет компилятором (оптимизатором) проинлайнена в коде. т.к. в этом случае нет накладных расходов на передачу параметров и возврат результата, это сокращает объем кода.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Держит паяльник хвостом
Аватара пользователя
Сообщения: 908
Зарегистрирован: Вс май 23, 2010 13:55:42
Откуда: Украина, Александрия

Сообщение Apparatchik »

ARV писал(а):во-первых, у вас 2 разных выражения, отсюда и разный объем при использовании одного и другого:
В другом компиляторе (для STM32) эти выражения дают одинаковый по размеру код, вот я и подумал что оптимизатор их должен привести к одному и тому же. Если она static ведь оптимизатор дает одинаковый размер.
«И всё-таки она вертится!»
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Apparatchik писал(а):вот я и подумал что оптимизатор их должен привести к одному и тому же
неисповедимы пути оптимизатора... смените версию avr-gcc и наверняка сможете получить еще один вариант...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

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

Сообщение WiseLord »

Таки да. У меня, например, что деление на 16, что сдвиг на 4 генерирует абсолютно одинаковый ассемблерный код. Причём сдвиг там даже не используется - вместо сдвига на 4 там просто swap байта:
Спойлер

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

uint8_t bcd2bin(uint8_t value)
{
    return (value >> 4) * 10 + (value & 0x0F);
    //return (value / 16) * 10 + (value % 16);
}

mov	r25, r24
swap	r25
andi	r25, 0x0F	; 15
andi	r24, 0x0F	; 15

ldi	r18, 0x0A	; 10
mul	r25, r18
add	r24, r0
eor	r1, r1
ret
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 353
Зарегистрирован: Вс янв 19, 2014 22:41:55

Сообщение Siarzhuk »

Apparatchik писал(а):При таком коде занимает 88 байт флеша, если же раскоментировать строку со здвигом и закоментировать с делениями - 104 байта.
А вы сохрание asm выхлоп компилятора для обеих вариантов и сравните в каком-нибудь двухпанельном diff-e - сразу покажет, что там оптимизатор не так понял. Попробуйте сравнить варианты с частями выражения - до '+' и после него.
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)
Реклама
Прорезались зубы
Аватара пользователя
Сообщения: 211
Зарегистрирован: Пт окт 21, 2011 14:39:31

Сообщение FeCat »

Можно ли sizeof применять к одной из размерностей массива?
Реклама
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 353
Зарегистрирован: Вс янв 19, 2014 22:41:55

Сообщение Siarzhuk »

FeCat писал(а):Можно ли sizeof применять к одной из размерностей массива?

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

  int aaa[2][3][4] = { 0 };
  int z = sizeof(aaa);
  int z1 = sizeof(aaa[0]);
  int z2 = sizeof(aaa[0][0]);
  int z3 = sizeof(aaa[0][0][0]);
  _tprintf(_T("%d %d %d %d "), z, z1, z2, z3);
96 48 16 4
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Или, чуть доработав:

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

    int aaa[6][7][8];
    int z0 = sizeof(aaa);
    int z1 = sizeof(aaa[0]);
    int z2 = sizeof(aaa[0][0]);
    int z3 = sizeof(aaa[0][0][0]);

    printf("%d %d %d \n", z0/z1, z1/z2, z2/z3);
6 7 8
Контактная информация:
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 353
Зарегистрирован: Вс янв 19, 2014 22:41:55

Сообщение Siarzhuk »

[quote="WiseLord"]Или, чуть доработав:[/code]
:) Да, совершенству нет предела:

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

 
#ifndef _countof
#define _countof(__a) (sizeof(__a) / sizeof(*__a))
#ednif

_tprintf(_T("%d %d %d"),  _countof(aaa), _countof(aaa[0]), _countof(aaa[0][0]));
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)
Прорезались зубы
Аватара пользователя
Сообщения: 211
Зарегистрирован: Пт окт 21, 2011 14:39:31

Сообщение FeCat »

Огромное спасибо!
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

Появился не совсем понятный мне момент.
Код:

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

#define     __IO    volatile             /*!< Defines 'read / write' permissions

__INLINE void FlashWord16Prog(uint32_t flash_addr, uint16_t data)
{    
 ...
/* (2) Perform the data write (half-word) at the desired address */
  *(__IO uint16_t*)(flash_addr) = data; /* (2) */
 ...
}
Значение flash_adr приводится к указателю на тип (volatile uint16_t*), затем происходит доступ записи по этому адресу.
Я хочу понять как распутывается эта запись.
Допустим имеем

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

volatile uint16_t *ptr;
*ptr = data;
ptr++;
Что здесь происходит?
а) работа(инкремент) с указателем-переменной как с volatile
б) копирование данных по адресу ptr с отключенной оптимизацией компилятора.
Вымогатель припоя
Аватара пользователя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Сообщение menzoda »

uk8amk писал(а):Что здесь происходит?
Ничего сложного. Значение data копируется в 16-битную ячейку памяти, на которую указывает ptr. Затем, инкремент смещает указатель так чтобы он указывал на следующую 16-битную ячейку. Ключевое слово volatile гарантирует, что запись в ячейку произойдет именно в этом месте (это так, по простому).
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

ОК, тогда ещё вопрос.
Указатели поддерживают работу с адресной арифметикой.
Для асинхронной модификации(подпрограмма прерывания) обычных типов данных и передачи этих данных в основную программу их объявляют с квалификатором volatile.
Если я в таком случае декларирую volatile указатель, то будет ли это означать что адресная арифметика также не будет подвергаться оптимизации?
Вымогатель припоя
Аватара пользователя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Сообщение menzoda »

Да

Добавлено
На самом деле не совсем. См. мой ответ ниже.
Последний раз редактировалось menzoda Вс ноя 06, 2016 10:47:50, всего редактировалось 1 раз.
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

Спасибо
Вымогатель припоя
Аватара пользователя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Сообщение menzoda »

Я немного соврал.

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

volatile int *ptr

это указатель на переменную, которая трактуется как volatile. А в случае

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

int * volatile ptr

сам указатель трактуется как volatile. Если сделать вот так

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

volatile int *ptr;
ptr++;
...
*ptr = data;
то компилятор на свое усмотрение может и применить некие оптимизации инкремента. Например, решить, что это можно и попозже посчитать, а не в данном месте. При этом доступ к ячейке будет volatile. Но если сделать вот так

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

int * volatile ptr;
ptr++;
то тогда он уже будет обязан инкрементировать здесь и сейчас. При этом доступ к ячейке будет не volatile. Ну а чтобы совсем связать его руки, то можно сделать вот так:

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

volatile int* volatile ptr;
ptr++;
*ptr = data;
Тогда и доступ к самому указателю будет volatile, и к ячейке на которую он указывает.
Встал на лапы
Аватара пользователя
Сообщения: 129
Зарегистрирован: Вт сен 23, 2008 14:29:06
Откуда: Ukraine

Сообщение roma1984 »

Здраствуйте! Подскажите новичку в сфере программирования про АЦП, точней как измерить значения на 4 входах. Сижу, курю примеры и уроки, но так и не понял что к чему.
В протеусе код написанный в АВР студии сипит ошибками.
Надо перевести этот рабочий код с среди ардуино в нормальный код на си для АВР студии
Спойлерfloat Upin1=0.0;
float Upin2=0.0;
float Upin3=0.0;
float Upin4=0.0;
float Ipin=0.0;
float U1=0.0;
float U2=0.0;
float U3=0.0;
float U4=0.0;
void setup() {
pinMode(0,INPUT);
pinMode(1,INPUT);
pinMode(2,INPUT);
pinMode(3,INPUT);
pinMode(4,INPUT);
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
digitalWrite(9,HIGH);//пин заряда
digitalWrite(10,HIGH);// соответствие пину 8 в протеусе - пин разряда (8 пин =пину 10)
}

void loop() {
//делаем замер напряжения падения на транзисторах пин PA4
Ipin=analogRead(4);
Ipin=(Ipin*5)/1023.0;
//делаем замер напряжения на входах
Upin1=analogRead(0);
Upin1=(Upin1*5)/1023;//вход PA0
Upin2=analogRead(1);
Upin2=(Upin2*5)/1023;//вход PА1
Upin3=analogRead(2);
Upin3=(Upin3*5)/1023.0;//вход PA2
Upin4=analogRead(3);
Upin4=(Upin4*5)/1023.0;//вход PA3
//вычисляем напряжение на аккумуляторах
U1=Upin1/(51/78.00);
U2=Upin2/(51/171.00);
U3=Upin3/(51/251.00);
U4=Upin4/(51/351.00);
if (U4>U3)
{
U4=U4-U3;
}
if (U3>U2)
{
U3=U3-U2;
}
if (U2>U1)
{
U2=U2-U1;
}
//защита от переразряда
if ((U1<3)||(U2<3)||(U3<3)||(U4<3))
{
digitalWrite(10, LOW);
}
else
{
digitalWrite(10, HIGH);
}
//защита от перезаряда
if ((U1>4.2)||(U2>4.2)||(U3>4.2)||(U4>4.2))
{
digitalWrite(9, LOW);
}
//защита от КЗ
// if (Ipin>4)
// {
// digitalWrite(9, LOW);
// digitalWrite(10, LOW);
// }
}
Мой код, или бред :))
Первий Вариант
Спойлер#include <avr/io.h>
#include <avr/delay.h>
float Upin1, Upin2, Upin3, Upin4, Ipin, U1, U2, U3, U4;
int main(void)
{
Upin1, Upin2, Upin3, Upin4, Ipin, U1, U2, U3, U4=0;

DDRA=0x00;
DDRB=0x7;
void ADC_init()
{
ADMUX=0x00; // Настройки канала PА0 опорноє Vcc 0b00000000
ADCSRA=0x83; // 0b10000011 ADEN=1, ADSC=0, ADATE=0, ADIF=0, ADIE=0, предделитель на 8 частота АЦП 125 кГц ADPS2=0 ADPS1=1 ADPS0=1
}

//функция получает в качестве аргумента номер канала и возвращает значение на входе
unsigned int ADC_result(unsigned char adc_input)
{
ADMUX=adc_input | (ADMUX & 0x00);
_delay_us(10); //задержка для стабилизации входного напряжения
ADCSRA |= 0x40; //ADSC = 1. Запуск преобразования (в режиме однократного преобразования)
while((ADCSRA & 0x10)==0); //ждем, пока АЦП закончит преобразование (ADIF = 0)
ADCSRA|=0x10; //ADIF= 1 преобразование закончено
return ADCW; //ADCW - содержит ADCH и ADCL как нам нужно
}

while(1)
{
Upin1=ADC_result(0)*0.0048875855327468;
Upin2=ADC_result(1)*0.0048875855327468;
Upin3=ADC_result(2)*0.0048875855327468;
Upin4=ADC_result(3)*0.0048875855327468;
Ipin=ADC_result(4)*0.0048875855327468;
}
}
Второй Вариант
Спойлер#include <avr/io.h>
#include <avr/delay.h>
float Upin1, Upin2, Upin3, Upin4, Ipin, U1, U2, U3, U4;
int main(void)
{
Upin1, Upin2, Upin3, Upin4, Ipin, U1, U2, U3, U4 =0;

DDRA=0x00;
DDRB=0x7;

ADMUX=0x00; // Настройки канала PА0 опорноє Vcc 0b00000000
ADCSRA=0x83; // 0b10000011 ADEN=1, ADSC=0, ADATE=0, ADIF=0, ADIE=0, предделитель на 8 частота АЦП 125 кГц ADPS2=0 ADPS1=1 ADPS0=1

while(1)
{
ADMUX |= 0x00; //выставляем канал PA0
_delay_us(30); //задержка для стабилизации
ADCSRA |= 0x40; //ADSC = 1. Запуск преобразования (в режиме однократного преобразования)
while((ADCSRA & 0x10)==0); //Ждём флаг окончания измерения
ADCSRA|=0x10; //ADIF= 1 преобразование закончено
Upin1=ADCH;

ADMUX |= 0x01; //выставляем канал PA1
_delay_us(30); //задержка для стабилизации
ADCSRA |= 0x40;//ADSC = 1. Запуск преобразования (в режиме однократного преобразования)
while((ADCSRA & 0x10)==0); //Ждём флаг окончания измерения
ADCSRA|=0x10; //ADIF= 1 преобразование закончено
Upin2=ADCH;

ADMUX |= 0x02; //выставляем канал PA2
_delay_us(30); //задержка для стабилизации
ADCSRA |= 0x40;//ADSC = 1. Запуск преобразования (в режиме однократного преобразования)
while((ADCSRA & 0x10)==0); //Ждём флаг окончания измерения
ADCSRA|=0x10; //ADIF= 1 преобразование закончено
Upin3=ADCH;

ADMUX |= 0x03; //выставляем канал PA3
_delay_us(30); //задержка для стабилизации
ADCSRA |= 0x40;//ADSC = 1. Запуск преобразования (в режиме однократного преобразования)
while((ADCSRA & 0x10)==0); //Ждём флаг окончания измерения
ADCSRA|=0x10; //ADIF= 1 преобразование закончено
Upin4=ADCH;

ADMUX |= 0x04; //выставляем канал PA4
_delay_us(30); //задержка для стабилизации
ADCSRA |= 0x40; //ADSC = 1. Запуск преобразования (в режиме однократного преобразования)
while((ADCSRA & 0x10)==0); //Ждём флаг окончания измерения
ADCSRA|=0x10; //ADIF= 1 преобразование закончено
Ipin=ADCH;
}
}
Контактная информация:
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

Нельзя внутри одной функии(main) создавать другие ф-ции(ADC_init и др.).

Нельзя писать так Upin1, Upin2, Upin3, Upin4, Ipin, U1, U2, U3, U4 =0;
Но можно писать так U2= U3= U4 =0;
Встал на лапы
Аватара пользователя
Сообщения: 129
Зарегистрирован: Вт сен 23, 2008 14:29:06
Откуда: Ukraine

Сообщение roma1984 »

Переделал
Спойлер#include <avr/io.h>
#include <util/delay.h>
# define F_CPU 1000000UL
float Upin1, Upin2, Upin3, Upin4, Ipin, U1, U2, U3, U4;

void ADC_init()
{
ADMUX=0x00; // Настройки канала PА0 опорноє Vcc 0b00000000
ADCSRA=0x83; // 0b10000011 ADEN=1, ADSC=0, ADATE=0, ADIF=0, ADIE=0, предделитель на 8 частота АЦП 125 кГц ADPS2=0 ADPS1=1 ADPS0=1
}

//функция получает в качестве аргумента номер канала и возвращает значение на входе
unsigned int ADC_result(unsigned char adc_input)
{
ADMUX=adc_input | (ADMUX & 0x00);
_delay_us(10); //задержка для стабилизации входного напряжения
ADCSRA |= 0x40; //ADSC = 1. Запуск преобразования (в режиме однократного преобразования)
while((ADCSRA & 0x10)==0); //ждем, пока АЦП закончит преобразование (ADIF = 0)
ADCSRA|=0x10; //ADIF= 1 преобразование закончено
return ADCW; //ADCW - содержит ADCH и ADCL как нам нужно
}

int main(void)
{
Upin1=0; Upin2=0; Upin3=0; Upin4=0; Ipin=0; U1=0; U2=0; U3=0; U4=0;

DDRA=0x00;
DDRB=0x7;

while(1)
{
//Upin1=ADC_result(0)*0.0048875855327468;
//Upin2=ADC_result(1)*0.0048875855327468;
//Upin3=ADC_result(2)*0.0048875855327468;
//Upin4=ADC_result(3)*0.0048875855327468;
//Ipin=ADC_result(4)*0.0048875855327468;
}
}
Все нормально, ошибок в протеусе нет, но когда раскоментирую
//Upin1=ADC_result(0)*0.0048876;
//Upin2=ADC_result(1)*0.0048876;
//Upin3=ADC_result(2)*0.0048876;
//Upin4=ADC_result(3)*0.0048876;
//Ipin=ADC_result(4)*0.0048876;
в протеусе появляются ошибки (PC=0x00CA. [AVR MEMORY] Writing to memory location 0x0171 outside of memory size 0x0160. [U2]
), ругается на память,
и когда компилиш
Warning
"Compiler optimizations disabled; functions from <util/delay.h>
"F_CPU not defined for <util/delay.h>"

Понял. Оптимизацию включил а строку # define F_CPU 1000000UL надо било поставить перед #include <util/delay.h>
Последний раз редактировалось roma1984 Вс ноя 06, 2016 18:41:04, всего редактировалось 1 раз.
Контактная информация:
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

roma1984 писал(а):Warning
"Compiler optimizations disabled; functions from <util/delay.h>
"F_CPU not defined for <util/delay.h>"
ну так включите оптимизацию и определите константу F_CPU для всего проекта, как полагается - всех делов-то!
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Ответить

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