CodeVision AVR в вопросах и ответах

Обсуждаем контроллеры компании Atmel.
Аватара пользователя
avreal
Опытный кот
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение avreal »

В языке С это делается так:

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

    union {
        unsigned char in;
        struct {
            unsigned char b0:1;
            unsigned char b1:1;
            unsigned char b2:1;
            unsigned char b3:1;
            unsigned char b4:1;
            unsigned char b5:1;
            unsigned char b6:1;
            unsigned char b7:1;
        } b;
    } u;

  u.b.b0 = 1;
  PORTB = u.in;
В зависимости от компилятора может быть возможно не именовать структуру

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

    union {
        unsigned char in;
        struct {
            unsigned char b0:1;
            unsigned char b1:1;
            unsigned char b2:1;
            unsigned char b3:1;
            unsigned char b4:1;
            unsigned char b5:1;
            unsigned char b6:1;
            unsigned char b7:1;
        } ;
    } u;

  u.b0 = 1;
  PORTB = u.in;
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Аватара пользователя
ELcat
Друг Кота
Сообщения: 3258
Зарегистрирован: Вт май 19, 2009 09:27:30
Откуда: Украина

Re: CodeVision AVR в вопросах и ответах

Сообщение ELcat »

evgeniy66 писал(а):
ELcat писал(а):Дайте кто-нибудь, пожалуйста, ссылку на скачку CodeVisionAVR 2.04.4а с таблеткой желательно одним файлом, замахался искать. Или какую-нибудь другую версию, но чтоб с библиотеками поддержки SD FAT (Чена). Спасибо!

Ну вот например: http://rutracker.org/forum/viewtopic.php?t=2703149

Спасибо, но чёт не получается.
Аватара пользователя
aam
Собутыльник Кота
Сообщения: 2994
Зарегистрирован: Сб фев 20, 2010 14:00:12
Откуда: Москва

Re: CodeVision AVR в вопросах и ответах

Сообщение aam »

Еще один вопрос:
Допустим, я объявил макрос для перевода напряжения в милливольтах в значения АЦП:

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

#define Ku 2
#define U_OFFSET 800
#define U_REF 2500

#define VOLTAGE_mV(U) (1024*Ku*(U-U_OFFSET)/U_REF)
...


Дальше я пишу:

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

if(adc=VOLTAGE_mV(1000))
...


У меня что компилятор в прошивку операции деления и умножения напихает? Или препроцессор сначала вычислит все выражения с константами, заменит их на числа, а потом передаст результат компилятору?
Кароче, из-за такого удобства код не пострадает? (Ну очень не хочется ,чтобы в проге деления с умножениями там всякие выполнядись все время)

По поводу поста выше - а объединения со структурами не утяжеляют прошивку? Я в своей программе ввел массив регистров флагов (каждый элемент массива -флаги для соответствующего канала) и устанавливал/сбрасывал флаги в каждом элементе с помощью макросов побитовыми логическими операциями (union'ы в голову как-то не пришли). Вот теперь думаю - что оптимальнее? С точки зрения быстродействия?
Вопрос про массив OCR'ов остается!!!
stanik
Родился
Сообщения: 10
Зарегистрирован: Чт июл 23, 2009 16:59:18
Откуда: Perm
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение stanik »

avreal писал(а):В языке С это делается так:

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

    union {
        unsigned char in;
        struct {
            unsigned char b0:1;
            unsigned char b1:1;
            unsigned char b2:1;
            unsigned char b3:1;
            unsigned char b4:1;
            unsigned char b5:1;
            unsigned char b6:1;
            unsigned char b7:1;
        } b;
    } u;

  u.b.b0 = 1;
  PORTB = u.in;
В зависимости от компилятора может быть возможно не именовать структуру

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

    union {
        unsigned char in;
        struct {
            unsigned char b0:1;
            unsigned char b1:1;
            unsigned char b2:1;
            unsigned char b3:1;
            unsigned char b4:1;
            unsigned char b5:1;
            unsigned char b6:1;
            unsigned char b7:1;
        } ;
    } u;

  u.b0 = 1;
  PORTB = u.in;


CodeVisionAVR 1.25.9
Ругается........ :(
Vze
Аватара пользователя
AlexFisher
Мучитель микросхем
Сообщения: 493
Зарегистрирован: Вт апр 21, 2009 13:31:27
Откуда: Санкт-Петербург
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение AlexFisher »

aam писал(а):Еще один вопрос:
Допустим, я объявил макрос для перевода напряжения в милливольтах в значения АЦП:
...

У меня что компилятор в прошивку операции деления и умножения напихает? Или препроцессор сначала вычислит все выражения с константами, заменит их на числа, а потом передаст результат компилятору?


Обязательно напихает :) Избавиться, по крайней мере, от деления, можно, если подобрать константу, которая в знаменателе, как степень двойки. Тогда компилятор просто сделает побитовый сдвиг и "напихает" только умножение, а оно гораздо короче деления.
[i]Да здравствует всё то, благодаря чему мы не смотря ни на что![/i]
Аватара пользователя
aam
Собутыльник Кота
Сообщения: 2994
Зарегистрирован: Сб фев 20, 2010 14:00:12
Откуда: Москва

Re: CodeVision AVR в вопросах и ответах

Сообщение aam »

А если в выражении перемножаются (или делятся) константы, компилятор разве не посчитает результат, прежде чем пихнуть все это в прогу?
Аватара пользователя
AlexFisher
Мучитель микросхем
Сообщения: 493
Зарегистрирован: Вт апр 21, 2009 13:31:27
Откуда: Санкт-Петербург
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение AlexFisher »

Если у Вас в выражении U - это константа, то он так и сделает. :) Иначе - он не сможет упростить выражение (я не смог, там же вычитание в скобках! )
[i]Да здравствует всё то, благодаря чему мы не смотря ни на что![/i]
Аватара пользователя
aam
Собутыльник Кота
Сообщения: 2994
Зарегистрирован: Сб фев 20, 2010 14:00:12
Откуда: Москва

Re: CodeVision AVR в вопросах и ответах

Сообщение aam »

Все "буквы" там константы. Смысл в том, что мне в процессе написания проги влом все время пересчитывать на калькуляторе вольты в значения АЦП, да и не наглядно это - все время забываешь, сколько вольт в конкретной строчке указано.
Вопрос лишь в том, будет ли в коде обычное число или там будет выражение, состоящее только из констант, которое проц будет впустую считать, хотя на момент написания проги результат этого выражения был известен.
Аватара пользователя
AlexFisher
Мучитель микросхем
Сообщения: 493
Зарегистрирован: Вт апр 21, 2009 13:31:27
Откуда: Санкт-Петербург
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение AlexFisher »

И выражение рекомендую переделать:
f(U)=(U-Uo)*Ko*105/256
Смотрите за типами данных и порядком вычисления в выражении!
первое - чтобы не переполнилось, второе - чтобы точность не потерять.

Если всё - константы, то препроцессор их посчитает и поставит одно число. Просто у Вас по тексту отсутствует #define U, поэтоиу я посчитал ее за переменную. В том виде, как у Вас - должно поучиться одно число.
[i]Да здравствует всё то, благодаря чему мы не смотря ни на что![/i]
Аватара пользователя
aam
Собутыльник Кота
Сообщения: 2994
Зарегистрирован: Сб фев 20, 2010 14:00:12
Откуда: Москва

Re: CodeVision AVR в вопросах и ответах

Сообщение aam »

Я что-то не понял насчет типов данных и порядка вычислений... Если это все считает препроцессор (или компилятор?), то какая разница какие там типы и порядок - результат один и тот же будет все равно.
U не определено с помощью define, но оно подставляется в виде числа (а не переменной) при вызове макроса:
if(adc==VOLTAGE_mV(1000))
...
т. е. в прошивке будет написано:
if(adc==163)
...
или
if(adc==163.84)
...
или
if(adc==1024*2*(1000-800)/2500)
...
?
Аватара пользователя
AlexFisher
Мучитель микросхем
Сообщения: 493
Зарегистрирован: Вт апр 21, 2009 13:31:27
Откуда: Санкт-Петербург
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение AlexFisher »

Я, конечно, может и не прав, но мне кажется, что препроцессор выдаст компилятору if(adc==163.84)
Но если adc - целое, то в регистры будет занесено 163 для сравнения (смотрел по листингу ассемблерного кода, сгенеренного CV), то есть все будет правильно.

Так что пишите и смотрите листинги.
[i]Да здравствует всё то, благодаря чему мы не смотря ни на что![/i]
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение ARV »

aam писал(а):Я что-то не понял насчет типов данных и порядка вычислений... Если это все считает препроцессор (или компилятор?), то какая разница какие там типы и порядок - результат один и тот же будет все равно.
U не определено с помощью define, но оно подставляется в виде числа (а не переменной) при вызове макроса:
if(adc==VOLTAGE_mV(1000))
...
т. е. в прошивке будет написано:
if(adc==163)
...
или
if(adc==163.84)
...
или
if(adc==1024*2*(1000-800)/2500)
...
?

разница будет и весьма существенная.
препроцессор - это всего лишь автоматический текстовый редактор, который выполняет поиск и замену текста. поэтому к компилятору попадет строчка if(adc==1024*2*(1000-800)/2500), и никакая иная. затем компилятор начент во время компиляции вычислять все, чтот можно: в данном случае можно вычислить все выражение, т.к. все величины - константы. стандарт Си говорит, что вычисления должны быть сделаны, а порядок вычисления не определяется. чисто математически нет разницы, будет ли первым сделано вычисление 1024*2 или 2*(1000-800) или (1000-800)/2500, однако, результат в каждом случае будет немножко разным получаться.
если первым будет вычислено (1000-800)/2500, то мы получим (1000-800)/2500 == 0, т.к. деление целочисленное. разумеется, все прочие умножения нуля будут бесполезны - всегда получим ноль.
если первым будет вычислено 1024*2*(1000-800), то получим 1024*2*(1000-800) == 2048*200 == 409600, что в int никогда не вместится, а вместится только 16 младших бит, т.е. 1024*2*(1000-800) окажется равным 16384. далее это число будет поделено на 2500 и в итоге мы получим 6.
как видите, все варианты дают НЕПРАВИЛЬНЫЙ результат, точнее, результат правильный с точки зрения компилятора, но совсем НЕ ОЖИДАЕМЫЙ программистом (ожидается то 163,84, ну в крайнем случае 163).

удивлены? а все абсолютно в соответствии с языком Си, освоить который вы все никак не хотите... я устал уже твердить, что ВСЕ ЧИСЛА В ВЫРАЖЕНИЯХ СЧИТАЮТСЯ int-ами, если не указано иное!!! поэтому просто запись 2*2 будет понята как умножение двух 16-битных чисел со знаком, и умножение 2000*2000 тоже самое, и, как это ни странно, 100000 тоже будет воспринято как 16-битное - с соответствующим усечением старших битов!!!!

поэтому всегда следует думать о том, какие числа используются в выражении, какой размер (т.е. тип) будет иметь результат вычислений и избегать только что рассмотренных подвохов.

P.S. я предполагаю, что компилятор не станет вычислять выражение справа налево, как я допустил в первом варианте рассуждений. однако, на 100% я в этом не уверен - скорее всего - ДА, но может быть - и НЕТ :)))
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
ValBag
Потрогал лапой паяльник
Сообщения: 326
Зарегистрирован: Сб сен 06, 2008 12:56:13

Re: CodeVision AVR в вопросах и ответах

Сообщение ValBag »

ELcat писал(а):Дайте кто-нибудь, пожалуйста, ссылку на скачку CodeVisionAVR 2.04.4а с таблеткой!
Почту в ЛС.
Аватара пользователя
AlexFisher
Мучитель микросхем
Сообщения: 493
Зарегистрирован: Вт апр 21, 2009 13:31:27
Откуда: Санкт-Петербург
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение AlexFisher »

Ну и развели же мы здесь полемику...
Да, всегда нужно смотреть, в каком порядке выполняются действия! НО!
Я взял, набросал проект и получил следующее:

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

// Declare your global variables here
#define Ku 2
#define U_OFFSET 800
#define U_REF 2500

#define VOLTAGE_mV(U) (1024*Ku*(U-U_OFFSET)/U_REF)
int adc;

...

adc=100;
if(adc==VOLTAGE_mV(1000))      // Place your code here
  adc=0;

...


Получил листинг:

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

;►►►     129 adc=100;
       LDI  R30,LOW(100)
       LDI  R31,HIGH(100)
       MOVW R2,R30
;►►►     130 if(adc==VOLTAGE_mV(1000))      // Place your code here
       LDI  R30,LOW(163)
       LDI  R31,HIGH(163)
       CP   R30,R2
       CPC  R31,R3
       BRNE _0x3
;►►►     131   adc=0;
       CLR  R2
       CLR  R3
;►►►     132
;►►►     133 while (1)
_0x3:


Как видим, компилятор, не смотря ни на что, дал правильный результат :)
[i]Да здравствует всё то, благодаря чему мы не смотря ни на что![/i]
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение ARV »

ваша проблема в том, что вы свято верите в CVAVR, который не соответствует (и не стремится соответствовать) стандарту Си!!! поэтому ваш НЕПРАВИЛЬНЫЙ код НЕ БУДЕТ РАБОТАТЬ после компиляции другими компиляторами. В частности, WinAVR в строгом соответствии с описанным мною дает результат 6, а не 163.

главное, что ПРАВИЛЬНО написанный код будет ОДИНАКОВО ВЕРНО работать во всех компиляторах, а вот ваш НЕПРАВИЛЬНЫЙ будет работать только в CVAVR. именно за это все программисты не уважают CVAVR.

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

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

Re: CodeVision AVR в вопросах и ответах

Сообщение ARV »

avreal писал(а):В языке С это делается так:

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

    union {
        unsigned char in;
        struct {
            unsigned char b0:1;
            unsigned char b1:1;
            unsigned char b2:1;
            unsigned char b3:1;
            unsigned char b4:1;
            unsigned char b5:1;
            unsigned char b6:1;
            unsigned char b7:1;
        } b;
    } u;

 
только сейчас заметил: в обычном Си нет битовых полей... они введены как расширение GCC...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
AlexFisher
Мучитель микросхем
Сообщения: 493
Зарегистрирован: Вт апр 21, 2009 13:31:27
Откуда: Санкт-Петербург
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение AlexFisher »

ARV писал(а):
зря вы не хотите учиться правильно писать программы.


Поддерживаю!
То, что я написал - я сделал только ради проверки. Сам так никогда не пишу. Предпочитаю сам вычислять константы, не доверяя это препроцессору. Для ясности в ремарке пишу формулу. Кроме всего, препроцессор всегда отбрасывает дробную часть, а я, когда считаю, могу пользоваться правилами округления. :idea:
Кот я ленивый, поэтому константы заставляю считать Excel :)
[i]Да здравствует всё то, благодаря чему мы не смотря ни на что![/i]
Аватара пользователя
avreal
Опытный кот
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение avreal »

ARV писал(а):только сейчас заметил: в обычном Си нет битовых полей... они введены как расширение GCC...
Да ну... K&R по друкой нет, вот из C89:
3.5.2 Type specifiers
...
3.5.2.1 Structure and union specifiers
Syntax
...
struct-declarator:
declarator
declarator<opt> : constant-expression
...
Constraints
A structure or union shall not contain a member with incomplete or function type. Hence it shall not contain an instance of itself (but may contain a pointer to an instance of itself). The expression that specifies the width of a bit-field shall be an integral constant expression that has nonnegative value that shall not exceed the number of bits in an ordinary object of compatible type. If the value is zero, the declaration shall have no declarator.
...
Semantics
...
A member of a structure or union may have any object type. In addition, a member may be declared to consist of a specified number of bits (including a sign bit, if any). Such a member is called a bit-field ;/50/ its width is preceded by a colon. A bit-field may have type int , unsigned int , or signed int . Whether the high-order bit position of a ``plain'' int bit-field is treated as a sign bit is implementation-defined. A bit-field is interpreted as an integral type consisting of the specified number of bits.

В C99 это сидит в 6.7.2 Type specifiers

gcc-шное (и не только, у IAR тоже есть) расширение — это разрешение использовать типы short и char для битовых полей с соответствующим уменьшением занимаемого размера. Иначе даже для

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

struct {
    unsigned foo : 1;
} foo;
sizeof(foo) == sizeof(unsigned int), что иногда просто жалко, а иногда откровенно нежелательно.
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Аватара пользователя
aam
Собутыльник Кота
Сообщения: 2994
Зарегистрирован: Сб фев 20, 2010 14:00:12
Откуда: Москва

Re: CodeVision AVR в вопросах и ответах

Сообщение aam »

Кароче написал такой код:

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

#define R_CS     500UL      //Сопротивление датчика тока (мОм)
#define U_REF    2500UL      //Опорное напряжение АЦП (мВ)
#define U_OFFSET 800UL      //Смещение диапазона измерения АЦП
#define K_U      2UL      //Коэффициент усидения предусилителя
#define U_LIM    1000UL     //Максимальное напряжение


//Перевод тока (в мА) в значения АЦП
#define CURRENT_mA(I) (1024*I*R_CS/(1000*U_REF))

//Перевод напряжения (мВ) в значения АЦП
#define VOLTAGE_mV(U) (1024*K_U*(U-U_OFFSET)/U_REF)

// Declare your global variables here

void main(void)
{
// Declare your local variables here

unsigned int adc;
unsigned int I;

adc=VOLTAGE_mV(2000); //Напряжение
I=CURRENT_mA(840);    //Ток
....
}


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

Вот что выдает компилятор:
                 ; 0000 0036 adc=VOLTAGE_mV(2000); //Напряжение
                 ;   adc -> R16,R17
                 ;   I -> R18,R19
                +
00005f ed07     +LDI R16 , LOW ( 983 )
000060 e013     +LDI R17 , HIGH ( 983 )
                    __GETWRN 16,17,983
                 ; 0000 0037 I=CURRENT_mA(840);    //Ток
                +
000061 ea2c     +LDI R18 , LOW ( 172 )
000062 e030     +LDI R19 , HIGH ( 172 )
                    __GETWRN 18,19,172


После всех констант в #define я поставил UL, т. е. unsigned long. Тем не менее, 4 байтное целое компилятор в прошивку не запузырил)) Но это CVAVR...
ARV, такой код соответствует спецификации языка Си? И что будет генерить "правильный" компилятор по такому сишнику?
Аватара пользователя
avreal
Опытный кот
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение avreal »

А он и не должен был в прошивку заносить. Выражение константное, он должен был внутри себя вычислять в unsigned long, а потом результат усечь до тех 16 бит, которые реально нужны.
В стандарте есть такое понятие, как abstract machine - абстрактная машина. Оптимизатор может сокращать вычисления, если он сразу видит результат во время компиляции, но он обязан этот результат подать таким, каким его вычислила бы та машина, работая «строго как написано» в исходнике (с учётом требуемых языком преобразований к int меньших типов).
Поэтому если в #define написаны «просто константы», то компилятор обязан сделать вид, что производились реальные вычисления в реальных регистрах размера int и результат потом записан в переменную unsigned int. Если в таких реальных int-вычислениях по дороге были бы переполнения, он обязан их смоделировать.
Если констаты имеют суффикс UL, то компилятор в вражениях должен рядом стоящие величины перевести в unsigned long, произвести эти вычисления и занести результат (усекая его) в Вашу переменную.

Если бы в выражении затесалась переменная unsigned, то в случае с «просто константами» вычисления должны производиться в unsigned, усечения при переполнении производиться на каждом этапе.
В случае с UL-константами unsigned-переменная должна быть приведена к unsigned long, все вычисления произведены в unsigned long и усечение производиться только в конце перед занесением в unsigned-переменную.

Строго следование этим правилам усложняет работу оптимизатора, зато потом все полностью совместиме со стандартом компиляторы дают одинаковый результат.

Что-то я сегодня недельную норму тут выполнил, пора и дело делать. Врочем, понедельник у меня входной, в отлчие от субботы.
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Ответить

Вернуться в «AVR»