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

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Аватара пользователя
menzoda
Вымогатель припоя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

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

Сообщение menzoda »

Но в даташите же все прямым текстом написано!
Реклама
Аватара пользователя
blackx
Говорящий с текстолитом
Сообщения: 1518
Зарегистрирован: Пт дек 28, 2012 21:56:46
Откуда: St. Petersburg

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

Сообщение blackx »

Как это относится к C/C++?

Если интересует как с этой микросхемы получить данные, изучайте фиг. 3 и 4 в даташите.
Изображение only pure true norwegian blackx Изображение
Реклама
Аватара пользователя
DX168B
Друг Кота
Сообщения: 4468
Зарегистрирован: Вс янв 24, 2010 19:19:52
Откуда: Главный Улей России (Moscow)
Контактная информация:

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

Сообщение DX168B »

Есть небольшой вопрос по Си.
Как-то решил облегчить себе жизнь в одном проекте. Суть была в том, чтобы передать параметры из устройства на комп и с компа в устройство.
Всю конфигурацию устройства хранил в структуре, так удобнее работать:

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


typedef struct
{
     uint16_t sign;
     uint8_t param_1;
     uint16_t param_2;
     uint8_t param_3;
     uint16_t param_4;
     uint8_t param_5;
     uint8_t param_6;
     uint16_t param_7;
     uint32_t crc32;
}
cfg;
 

На самом девайсе все ОК. Пишу структуру напрямую в EEPROM и читаю от туда тоже без всяких проблем. (Камень - AtMega32)

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

     cfg config;
     ....
     EEPROMWrite((uint8_t*)&config, sizeof(config));
     EEPROMRead((uint8_t*)&config, sizeof(config));
     ConfigCheckCRC32(&config); // = true То есть Все ОК.
     ......

Копирую эту структуру в код в Visual Studio 2008
(код в компе)

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

     bcount = BMSIReceive(buff); // Принимаю пакет
     ParsePack(buff, bcount, (unsigned char*)&config, sizeof(config)); // Распаковываю данные
     ConfigCheckCRC32(&config); // = false. То есть жопа.

Код в камне:

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

     BMSISend(buff, (BuildPack(buff, (uint8_t*)&config, cmd, addr)));

После недолгих раздумий перетасовал переменные в структуре (как в девайсе, так и в Windows)

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

typedef struct
{
     uint16_t sign;
     uint16_t param_2;
     uint16_t param_4;
     uint16_t param_7;

     uint8_t param_1;
     uint8_t param_3;
     uint8_t param_5;
     uint8_t param_6;

     uint32_t crc32;
}cfg;


После этого все заработало. (Предположения были на счет перестановки переменных компилятором в физической памяти. В других функциях ошибок небыло.)
То есть: Я использовал структуру как обычный массив. Упаковал его(массив) в пакет и отправил компу.
В компе указателю на структуру передавался адрес начала массива.

Следовательно вопрос: Хоть это и сработало, но стоит ли так делать? (Отправлять структуру как массив)
Насколько это переносимо между архитектурами с разной разрядностью? На сколько это надежно?
I am DX168B and this is my favourite forum on internet!
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

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

Сообщение Kavka »

DX168B, это связано с выравниванием и "упаковкой" элементов структуры. В таких случаях надо чтобы компиляторы генерировали одинаковый код (раскладку, layout) структур.
В gcc (и для AVR в том числе) упаковка и выравнивание, скорее всего, производиться на 1. Можно принудительно указать с помощью опции компилятору -fpack-struct=1.
Соответственно и для Visual Studio вам надо аналогичные настройки сделать. Можно только для отдельной структуры, т.к. на x86 отсутствие выравнивания вообще может сильно замедлить работу программы.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
DX168B
Друг Кота
Сообщения: 4468
Зарегистрирован: Вс янв 24, 2010 19:19:52
Откуда: Главный Улей России (Moscow)
Контактная информация:

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

Сообщение DX168B »

ОК. Понятно.
I am DX168B and this is my favourite forum on internet!
Реклама
Аватара пользователя
blackx
Говорящий с текстолитом
Сообщения: 1518
Зарегистрирован: Пт дек 28, 2012 21:56:46
Откуда: St. Petersburg

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

Сообщение blackx »

Добавлю, что в gcc по умолчанию упаковка идет с выравниванием по тому количеству байт, которое занимает соответствующий тип. Например, вот тут

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


struct data {
uint8_t id;
uint32_t address;
};



После переменной id в памяти будут расположены еще три неиспользованных байта. В итоге структура будет занимать не 5, а 8 байт. Когда вы переставили поля структуры, вы, по сути, избавились от всех таких "дырок". Вообще при любом упорядоченном расположении полей от самых больших по размеру к самым маленьким (типа int32_t > int16_t > int8_t) дырки образовываться не будут.
Изображение only pure true norwegian blackx Изображение
Реклама
Аватара пользователя
DX168B
Друг Кота
Сообщения: 4468
Зарегистрирован: Вс янв 24, 2010 19:19:52
Откуда: Главный Улей России (Moscow)
Контактная информация:

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

Сообщение DX168B »

Почему-то мне тоже так показалось (по поводу "дыр" в структурах) Все дело в том, что при отладке я заметил, что компилятор переставил переменные местами.
В итоге, в полях структуры были неправильные данные. Ну и соответственно чексумма не проходила.
Впредь буду знать, как еще можно сэкономить память и учитывать эти тонкости. :)
I am DX168B and this is my favourite forum on internet!
Cheba
Мучитель микросхем
Сообщения: 447
Зарегистрирован: Ср сен 26, 2012 14:12:47
Откуда: Київ

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

Сообщение Cheba »

А вот переставлять переменные внутри структуры местами компилятор категорически не имеет права.

PS а про выравнивание гуглить по словам struct alignment

Например читать здесь и здесь
Аватара пользователя
urry
Сверлит текстолит когтями
Сообщения: 1262
Зарегистрирован: Пн дек 08, 2008 10:58:48
Откуда: Винница
Контактная информация:

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

Сообщение urry »

Как бы чуть дополняя последнего докладчика (последняя ссылка ) - живой код для вижуал

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

#pragma pack(push,1)// выравнивание по 1 байту
typedef   struct sSingleMassPacket
{
   unsigned char cMarker;
   unsigned char cLenH;
   unsigned char cLenL;
   unsigned char cSend;
   unsigned char cFrame;
   unsigned char cAddr[10];
   unsigned int iData;
   sSingleMassPacket()// инициализация при создании
   {
      cMarker=0x7E;
      cLenH=0;
      cLenL=0x10;
      cSend=0x10;
      cFrame=0;
      cAddr[0]=cAddr[1]=cAddr[2]=cAddr[3]=cAddr[4]=cAddr[5]=0;
      cAddr[6]=cAddr[7]=cAddr[8]=0xFF;
      cAddr[9]=0xFE;
      iData=0;
   }
}sSingleMassPacket;
#pragma pack(pop)
Аватара пользователя
DX168B
Друг Кота
Сообщения: 4468
Зарегистрирован: Вс янв 24, 2010 19:19:52
Откуда: Главный Улей России (Moscow)
Контактная информация:

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

Сообщение DX168B »

ОК. Спасибо. :beer: Вопросы все отпали.
Подробнее мне надо было читать доки. :oops:
I am DX168B and this is my favourite forum on internet!
Аватара пользователя
Мikа
Потрогал лапой паяльник
Сообщения: 343
Зарегистрирован: Пн апр 01, 2013 15:13:40
Откуда: Москва

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

Сообщение Мikа »

Добрый день :) Или уже вечер :)

На сей раз я вот с чем пришёл. Взял из клавиатуры прокручивающийся ролик (как на мышке). Собрал схемку.

ATmega32. Через этот ролик на ноги PC0 и PC1 при его покручивании чередуется +5в или 0.

Всё это затеяно для того, чтобы приобрести мало-мальский опыт в чтении портов.

И тут начинается непонятное.

DDRC=0b00000000;
Я объявляю 2 переменные:

int a=1;
int b=0;

После чего, в переменную а читается порт С:

a=PORTC; - правильно же?
это делается для того, чтобы знать, что происходит в порте при инициализации.

Далее (уже в цикле мэйн), я загружаю PORTC в b:

b=PORTB; - тоже, вроде бы, всё верно.

Далее идёт самое интересное.

if (a==b)
прибавлять выводимое на индикатор число на 1.
else
уменьшать выводимое на индикатор число на 1.

Теперь немного итогов. Изначально a и b не равны. a=0, b=1. Поэтому, если бы порт не читался, число бы уменьшалось. Но оно увеличивается, следовательно, a и b равны.

Далее, по идее, когда я кручу ролик, значение в порту меняется. Меняются его младшие 2 бита.
a остаётся таким, каким оно было в последний раз после команды a=PORTC.
Но b уже будет другим, тк загрузит в себя обновлённое значение PORTC.

Следовательно, a!=b и должен выполняться кусок else. Но этого не происходит. Опрос и вывод нового числа происходит через 1 сек.

Еще делал 2 эксперимента. Выводил на 7мисегментный индикатор напрямую порт С. Он показывает, что все биты равны 0.
Если обращаюсь через матрицу (то есть вывожу элемент, с номером порт С, он тоже показывает 0).

Я не понимаю чего-то очевидного? Подскажите, пожалуйста в очередной раз :)
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

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

Сообщение shads »

Входные данные порта читаются не через PORTC а через PINC.
Тут про работу порта почитай http://easyelectronics.ru/avr-uchebnyj- ... yvoda.html
Последний раз редактировалось shads Чт июн 06, 2013 16:14:37, всего редактировалось 1 раз.
Аватара пользователя
Мikа
Потрогал лапой паяльник
Сообщения: 343
Зарегистрирован: Пн апр 01, 2013 15:13:40
Откуда: Москва

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

Сообщение Мikа »

То есть b=PINC будет значить, взять все биты и этой команды будет достаточно? ТОгда до кучи ещё спрошу, как правильно прочитать какой-то отдельный бит? Большое спасибо!
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

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

Сообщение shads »

Тут помоему чуть нагляднее про работу порта http://atsoftware.gb7.ru/blog/2013/04/a ... ортами-io/

Мikа писал(а):То есть b=PINC будет значить, взять все биты и этой команды будет достаточно? ТОгда до кучи ещё спрошу, как правильно прочитать какой-то отдельный бит? Большое спасибо!
Проверка бита 0 порта С:

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

if (PINC & (1<<0))
  придем сюда если значение бита равно 1;
else
  придем сюда если значение бита равно 0;


Проверка бита 7 порта C:

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

if (PINC & (1<<7))
  придем сюда если значение бита равно 1;
else
  придем сюда если значение бита равно 0;
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

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

Сообщение shads »

И кстати работа с энкодером не так проста как кажется..... а у тебя как я понял - именно энкодер......

viewtopic.php?f=20&t=76027&hilit=EncPrevPrev
Тут (почти в конце) процедурка от ЛИ которая может обрабатывать данные энкодера
ut1wpr
Вымогатель припоя
Сообщения: 581
Зарегистрирован: Ср янв 05, 2011 10:03:18

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

Сообщение ut1wpr »

shads писал(а):Тут (почти в конце) процедурка от ЛИ которая может обрабатывать данные энкодера
Неоднократно мной проверенная... Применял во многих проектах.
С уважением,
Виктор.
Аватара пользователя
Мikа
Потрогал лапой паяльник
Сообщения: 343
Зарегистрирован: Пн апр 01, 2013 15:13:40
Откуда: Москва

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

Сообщение Мikа »

Я посмотрел в Википедии что такое энкодер. Да, что-то вроде этого, но не так замудрено. У него 3 провода. Схема примерно такая:

a......b
|.......|
|.......|
/......./
|.......|
|.......|
|____|
....|
....|
....|
....c

Методом тыка установиЛ, что при единичном смещении (как бы один полный щёлк) происходит замыкание или размыкание ключей. В результате a и b подключаются или отключаются от c. Разница в направлении вращения сказывается очередностью вклдчений и выключений кнопок a и b.
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
ut1wpr
Вымогатель припоя
Сообщения: 581
Зарегистрирован: Ср янв 05, 2011 10:03:18

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

Сообщение ut1wpr »

Мikа писал(а):Я посмотрел в Википедии что такое энкодер. Да, что-то вроде этого, но не так замудрено. У него 3 провода. Схема примерно такая:
Методом тыка установиЛ, что при единичном смещении (как бы один полный щёлк) происходит замыкание или размыкание ключей. В результате a и b подключаются или отключаются от c. Разница в направлении вращения сказывается очередностью вклдчений и выключений кнопок a и b.
Пора уже от определений "полный щелк" переходить к временным диаграммам состояний контактов (в общем случае - сигналов) и их фазовым соотношениям. На уровне "кнопок" далеко не уйдете.
Скажите вот ещё что, есть ли в Си команда, которая выводит весь порт в переменную? Или если я хочу весь код, то надо написать процедурку(или как правильно),к оторая поочередно составит из всех PINxx байт или почти-байт? :D
В Си команд работы с портами НЕТ. Это уже эмбеддеры для себя понапридумывали портов всяких... :)
А если серьезно, пора бы уже что-то и почитать, кроме постов в форуме. Потому как "выводить порт в переменную" - не наш метод.
С уважением,
Виктор.
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

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

Сообщение isx »

Здравствуйте!
Помогите пожалуйста разобратся с АЦП атмеги8. Ранее в WinAVR как-то работал с ним, а щас в цвавре ника не могу сообразить.
Нашёл в качестве примера такой код:

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

#include <mega8.h>

#include <delay.h>

void main(void)
{

DDRB=0b00000001;
PORTB=0x00;

PORTC=0x00;
DDRC=0b00000000;

PORTD=0x00;
DDRD=0x00;

ADCSRA=0b10001110;
ADMUX=01000000;

#asm("sei")

while (1)
      {     
   unsigned int aa;   
  ADCSRA |=0b01000000;
  while ((ADCSRA&0b00010000)==0);
 
     
    if (aa > 500) {PORTB = 0b00000001;}  else {PORTB = 0b00000000;};
     ADCSRA|= 0b00010000;
      }
}

скомпилировал, кинул в протеус, а тот мне

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

while ((ADCSRA&0b00010000)==0);
reference value = 0 выдаёт в логе с ошибками, причём выдаёт многократно т.к. ошибка не фатальная. Что не так то с кодом :dont_know: ?
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

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

Сообщение isx »

Вот сделал с конструктором.

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


#include <mega8.h>

#include <delay.h>

#define ADC_VREF_TYPE 0x40
unsigned int adc_data;
// ADC interrupt service routine
interrupt [ADC_INT] void adc_isr(void)
{

adc_data=ADCW;


}


void main(void)
{

PORTB=0x00;
DDRB=0b00000001;


ADMUX=ADC_VREF_TYPE & 0xf0;
ADCSRA=0x8E;



// Global enable interrupts
#asm("sei")

while (1)
      {
      ADCSRA|=0b01000000;
      if (adc_data < 500) {PORTB = 0b00000001;} else {PORTB = 0b00000000;}   
     
      }
}

Как только добавляю строку ADCSRA|=0b01000000; , то начинается такая - же байда. Если её не добавлять, то опрос АЦП производится только один раз, при включении.
Ответить

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