Страница 156 из 386

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

Добавлено: Пт май 31, 2013 07:44:46
menzoda
Но в даташите же все прямым текстом написано!

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

Добавлено: Пт май 31, 2013 16:18:25
blackx
Как это относится к C/C++?

Если интересует как с этой микросхемы получить данные, изучайте фиг. 3 и 4 в даташите.

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

Добавлено: Вс июн 02, 2013 16:49:00
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;
После этого все заработало. (Предположения были на счет перестановки переменных компилятором в физической памяти. В других функциях ошибок небыло.)
То есть: Я использовал структуру как обычный массив. Упаковал его(массив) в пакет и отправил компу.
В компе указателю на структуру передавался адрес начала массива.

Следовательно вопрос: Хоть это и сработало, но стоит ли так делать? (Отправлять структуру как массив)
Насколько это переносимо между архитектурами с разной разрядностью? На сколько это надежно?

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

Добавлено: Вс июн 02, 2013 17:20:36
Kavka
DX168B, это связано с выравниванием и "упаковкой" элементов структуры. В таких случаях надо чтобы компиляторы генерировали одинаковый код (раскладку, layout) структур.
В gcc (и для AVR в том числе) упаковка и выравнивание, скорее всего, производиться на 1. Можно принудительно указать с помощью опции компилятору -fpack-struct=1.
Соответственно и для Visual Studio вам надо аналогичные настройки сделать. Можно только для отдельной структуры, т.к. на x86 отсутствие выравнивания вообще может сильно замедлить работу программы.

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

Добавлено: Вс июн 02, 2013 18:05:13
DX168B
ОК. Понятно.

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

Добавлено: Вс июн 02, 2013 18:11:46
blackx
Добавлю, что в gcc по умолчанию упаковка идет с выравниванием по тому количеству байт, которое занимает соответствующий тип. Например, вот тут

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


struct data {
uint8_t id;
uint32_t address;
};

После переменной id в памяти будут расположены еще три неиспользованных байта. В итоге структура будет занимать не 5, а 8 байт. Когда вы переставили поля структуры, вы, по сути, избавились от всех таких "дырок". Вообще при любом упорядоченном расположении полей от самых больших по размеру к самым маленьким (типа int32_t > int16_t > int8_t) дырки образовываться не будут.

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

Добавлено: Вс июн 02, 2013 18:42:28
DX168B
Почему-то мне тоже так показалось (по поводу "дыр" в структурах) Все дело в том, что при отладке я заметил, что компилятор переставил переменные местами.
В итоге, в полях структуры были неправильные данные. Ну и соответственно чексумма не проходила.
Впредь буду знать, как еще можно сэкономить память и учитывать эти тонкости. :)

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

Добавлено: Пн июн 03, 2013 01:36:19
Cheba
А вот переставлять переменные внутри структуры местами компилятор категорически не имеет права.

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

Например читать здесь и здесь

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

Добавлено: Пн июн 03, 2013 09:52:10
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)

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

Добавлено: Пн июн 03, 2013 10:47:27
DX168B
ОК. Спасибо. :beer: Вопросы все отпали.
Подробнее мне надо было читать доки. :oops:

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

Добавлено: Чт июн 06, 2013 16:01:48
М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).

Я не понимаю чего-то очевидного? Подскажите, пожалуйста в очередной раз :)

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

Добавлено: Чт июн 06, 2013 16:11:53
shads
Входные данные порта читаются не через PORTC а через PINC.
Тут про работу порта почитай http://easyelectronics.ru/avr-uchebnyj- ... yvoda.html

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

Добавлено: Чт июн 06, 2013 16:13:39
Мikа
То есть b=PINC будет значить, взять все биты и этой команды будет достаточно? ТОгда до кучи ещё спрошу, как правильно прочитать какой-то отдельный бит? Большое спасибо!

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

Добавлено: Чт июн 06, 2013 16:20:53
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;

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

Добавлено: Чт июн 06, 2013 16:33:06
shads
И кстати работа с энкодером не так проста как кажется..... а у тебя как я понял - именно энкодер......

http://radiokot.ru/forum/viewtopic.php? ... ncPrevPrev
Тут (почти в конце) процедурка от ЛИ которая может обрабатывать данные энкодера

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

Добавлено: Чт июн 06, 2013 16:56:14
ut1wpr
shads писал(а):Тут (почти в конце) процедурка от ЛИ которая может обрабатывать данные энкодера
Неоднократно мной проверенная... Применял во многих проектах.

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

Добавлено: Чт июн 06, 2013 20:33:04
Мikа
Я посмотрел в Википедии что такое энкодер. Да, что-то вроде этого, но не так замудрено. У него 3 провода. Схема примерно такая:

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

Методом тыка установиЛ, что при единичном смещении (как бы один полный щёлк) происходит замыкание или размыкание ключей. В результате a и b подключаются или отключаются от c. Разница в направлении вращения сказывается очередностью вклдчений и выключений кнопок a и b.

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

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

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

Добавлено: Чт июн 06, 2013 23:21:07
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: ?

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

Добавлено: Пт июн 07, 2013 00:13:16
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; , то начинается такая - же байда. Если её не добавлять, то опрос АЦП производится только один раз, при включении.