Страница 1 из 4

Вопросы по языку СИ

Добавлено: Вт май 06, 2014 23:47:25
uwrtey
Всем привет. Недавно взялся за АРМ.
До этого учился писать на асме для AVR.
Столкнувшись с Си понял, что жизнь непростая штука :))

я пользуюсь учебником по СИ http://vg.ucoz.ru/load/raznoe/kniga_uch ... /17-1-0-51 авторы которой Брайн Керниган и Денис Рич
и кратким руководством http://dfe.petrsu.ru/koi/posob/c/c.htm

Но у меня все равно остается куча вопросов

С вашего позволения я буду задавать их тут

1) столкнулся я с составными операциями
например мне до сих пор не понятна операция |=
единственное, что я про нее знаю - это то, что она выполняется справа налево..

вот пример кода где я ее использовал:

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

RCC->AHB1ENR |= 0b00000000000000000000000000001000;  //RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
Этим кусочком кода я включил тактирование порта Д в микрокотроллере стм32ф4
что означает эта операция?
программа нормально работает если просто оставить там знак равенства...
Но почему используют именно такую операцию? И при каких обстоятельствах один только знак равенства не сканает ?
сразу оговорюсь - я написал бинарное значение непросто так, а для того, что-бы улучшить читабельность кода...


2) а вот тут я использовал SPL

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

int main(void)
{
        // Тактирование порта "Д"
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

        // Настраиваем порты
        GPIO_InitTypeDef  ledinit;  // создаем структуру

        ledinit.GPIO_Mode = GPIO_Mode_OUT;  // направление - выход
        ledinit.GPIO_OType = GPIO_OType_PP;  // Двухтактный выход
        ledinit.GPIO_PuPd = GPIO_PuPd_NOPULL;  // Без подтяжки
        ledinit.GPIO_Speed = GPIO_Speed_2MHz;  // Скорость низкая
        ledinit.GPIO_Pin = (GPIO_Pin_13 | GPIO_Pin_12 | GPIO_Pin_14 | GPIO_Pin_15); // Светодиод LD3 на 12, 13, 14 и 15-ом выводе



        GPIO_Init(GPIOD, &ledinit);  // Функция, выполняющая настройку портов
тут мне не понятно почему нужно записывать AND в строчке

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

GPIO_Init(GPIOD, &ledinit);  // Функция, выполняющая настройку портов
Буду всем ответившим очень признателен... Жаль что на радиокоте нет обучалки по ARM на языке СИ. В свое время обучалка по AVR мне очень помогла...

Re: Мелкие вопросы по языку СИ

Добавлено: Ср май 07, 2014 00:11:19
Pavel_1978
Это Указатель на структуру. Смотри раздел соответсвующий в K&R или например тут:
http://lord-n.narod.ru/download/books/w ... C/main.htm

я этим в основном пользуюсь.

А Си он хоть для АРМ хоть для ПК один.
Для AVR ты на чем писал? И какую сейчас IDE используешь?

Re: Мелкие вопросы по языку СИ

Добавлено: Ср май 07, 2014 08:10:34
oleg110592
1)
Битовое ИЛИ может использоваться для установки битов. Любой бит, установленный в любом операнде, вызывает установку соответствующего бита в другом операнде. Например, в результате операции 128 | 3 получаем
10000000 128 в двоичном представлении
00000011 3 в двоичном представлении
| -------------- битовое ИЛИ
10000011 результат
2)
Существуют две операции, которые имеют отношение к работе с указателями. Этими операциями являются:
операция взятия адреса (адресация) &;
операция взятия значения по адресу (косвенная адресация или разыменование) *.
int a, *p;

p = &a; // Переменной p присваивается адрес переменной a
*p = 0; // Значение по адресу, находящемуся в переменной p (т.е. значение переменной а), становится равным 0

предыдущая ссылка в виде файла chm (Compressed HTML Help): http://rghost.ru/35521348

Re: Мелкие вопросы по языку СИ

Добавлено: Ср май 07, 2014 09:15:32
ARV
uwrtey писал(а):например мне до сих пор не понятна операция |=
единственное, что я про нее знаю - это то, что она выполняется справа налево..
запись a |= b; абсолютно эквивалентна по всем параметрам записи a = a | b;
это просто две разные формы записи одного и того же, что тут может быть непонятного?

Re: Мелкие вопросы по языку СИ

Добавлено: Ср май 07, 2014 09:25:31
uwrtey
Pavel_1978 писал(а):Для AVR ты на чем писал? И какую сейчас IDE используешь?
я писал на Ассемблере
сейчас для ARM использую кокос
oleg110592 писал(а):Битовое ИЛИ может использоваться для установки битов. Любой бит, установленный в любом операнде, вызывает установку соответствующего бита в другом операнде
ага, я знаю что такое побитовое "или"
я только не могу понять почему тут используется связка двух операций сразу "|" и "="

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

RCC->AHB1ENR |= 0b00000000000000000000000000001000;
Я сначала подумал, что в первую очередь производится операция ИЛИ между числом находящимся в AHB1ENR и числом 0b00000000000000000000000000001000
а затем результат складывается в AHB1ENR ..
А потом я прочитал в учебнике по СИ, что связка "|=" выполняется справа налево.. вот и начал тупить.....
Видимо справа налево выполняются не операции, а результат самих операнд.... :)
запись a |= b; абсолютно эквивалентна по всем параметрам записи a = a | b;
это просто две разные формы записи одного и того же, что тут может быть непонятного?
ну вот так и есть...

По второму пункту все понятно...

Всем огромное спасибо ! :beer:

П.С. скачал файл .chm, но он у меня не открывается...

********************************************************************************************

разрешите я задам еще один вопрос:

при использовании SPL получается код вида:

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

        // Включаем тактирование порта Д
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

        // Настраиваем порты
        GPIO_InitTypeDef  ledinit;  // создаем структуру

        ledinit.GPIO_Mode = GPIO_Mode_OUT;  // направление - выход
        ledinit.GPIO_OType = GPIO_OType_PP;  // Двухтактный выход
        ledinit.GPIO_PuPd = GPIO_PuPd_NOPULL;  // Без подтяжки
        ledinit.GPIO_Speed = GPIO_Speed_2MHz;  // Скорость низкая
        ledinit.GPIO_Pin = (GPIO_Pin_13 | GPIO_Pin_12 | GPIO_Pin_14 | GPIO_Pin_15); // Светодиод LD3 на 12, 13, 14 и 15-ом выводе

        GPIO_Init(GPIOD, &ledinit);  // Функция, выполняющая настройку портов
не буду все подробно расспрашивать, спрошу только на примере частоты тактирования.
Если я правильно понимаю, то этим кодом я заставлю дрыгаться весь порт на частоте 2 мегагерца.
А как же мне быть если я захочу дрыгать на этой частоте только те ножки которые мне надо, а другие на другой частоте или в обще оставить их в покое ?

Хотел новый вопрос написать в новом сообщении, но тут недавно выговор получил от Starichok51, что типа так не делается - по этому налепил его сюда-же....

Re: Мелкие вопросы по языку СИ

Добавлено: Ср май 07, 2014 11:07:39
amv2000
uwrtey писал(а): А как же мне быть если я захочу дрыгать на этой частоте только те ножки которые мне надо, а другие на другой частоте или в обще оставить их в покое ?
Ну так Вы же указываете какие выводы настраиваете

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

ledinit.GPIO_Pin = (GPIO_Pin_13 | GPIO_Pin_12 | GPIO_Pin_14 | GPIO_Pin_15); // Светодиод LD3 на 12, 13, 14 и 15-ом выводе

Re: Мелкие вопросы по языку СИ

Добавлено: Ср май 07, 2014 12:09:04
HHIMERA
uwrtey писал(а): Если я правильно понимаю, то этим кодом я заставлю дрыгаться весь порт на частоте 2 мегагерца.
А как же мне быть если я захочу дрыгать на этой частоте только те ножки которые мне надо, а другие на другой частоте или в обще оставить их в покое ?
Ничего там дрыгаться не будет... И никакого отношения к настройке тактирования это не имеет... Это всего лишь настройка максимальной скорости нарастания выходного сигнала на пине... Делается это для возможности снижения ЭМИ МК... если это существенно для девайса...
Т.е. если установить скорость нарастания для пина с 2МГц максимум, то дрыгнуть этой ногой с частотой 15МГц уже не получится... из-за затяжных фронтов... следовательно, для 15МГц уже нужно устанавливать более высокую скорость нарастания пина...

Re: Мелкие вопросы по языку СИ

Добавлено: Ср май 07, 2014 14:40:15
uwrtey
HHIMERA писал(а):Ничего там дрыгаться не будет
да это то я знаю. вопрос был в другом.
Я выше привел код. Дак вот - мне интересно там на 2 мегагерца настроен весь порт? или те пины которые я указал ?

Re: Мелкие вопросы по языку СИ

Добавлено: Ср май 07, 2014 16:27:04
oleg110592
да "те пины которые я указал"
СпойлерИзображение

Re: Мелкие вопросы по языку СИ

Добавлено: Ср май 07, 2014 17:19:49
uwrtey
А-а, ну тогда понятно...

Re: Мелкие вопросы по языку СИ

Добавлено: Чт май 29, 2014 20:29:53
optima
Ребята подскажите, предполагаю это делается логическим сдвигом. или есть более удобные способы?

имеется массив const uint8_t moimassiv[] и имеется переменная uint32_t per;
нужно взять из массива четыре значения допустим 0x01, 0x02, 0x03, 0x04 и положить в переменную чтобы она предстала в таком виде 0x01020304

В Си не силен, поэтому прошу помощи как удобнее это реализовать?

Re: Мелкие вопросы по языку СИ

Добавлено: Чт май 29, 2014 22:24:58
uk8amk
проще всего реализовать через указатель:

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

uint8_t *ptr8;
ptr8 = (uint8_t*) per;

ptr8[3]=0x04;
ptr8[2]=0x03;
ptr8[1]=0x02;
ptr8[0]=0x01;
В итоге per=0x1020304

Возможно также сделать через union.

Re: Мелкие вопросы по языку СИ

Добавлено: Чт май 29, 2014 22:37:29
HHIMERA
"Что это было?"(С)

Для Cortex...
Если одно-два значения то проще так...

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

per = __REV(*(__IO uint32_t *)((uint32_t)&(moimassiv) + 0));

per = __REV(*(__IO uint32_t *)((uint32_t)&(moimassiv) + 4));
А если больше, то как-то так...

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

const uint8_t moimassiv[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
uint32_t *pp;
uint32_t per;

..................
..................

pp = (uint32_t*)moimassiv;

...........

per = __REV(*pp++);


Re: Мелкие вопросы по языку СИ

Добавлено: Пт май 30, 2014 01:04:11
Myp3ik
Можно и сдвигами, но способ выше намного лучше.

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

uint32_t data = (uint32_t)(((uint32_t)moimassiv[0] << 24) | ((uint32_t)moimassiv[1] << 16) | ((uint32_t)moimassiv[2] << 8) | ((uint32_t)moimassiv[3]));

Re: Мелкие вопросы по языку СИ

Добавлено: Пт май 30, 2014 01:41:07
HHIMERA
Myp3ik писал(а):Можно и сдвигами
Да если честно...
имеется массив const uint8_t moimassiv[] и имеется переменная uint32_t per;
Проще с помощью редактора... Notepad++, например... перегнать массив в uint32_t и не мучаться...

Re: Мелкие вопросы по языку СИ

Добавлено: Пт май 30, 2014 05:15:46
optima
Спасибо всем откликнувшимся! сегодня попробую.
HHIMERA писал(а): Проще с помощью редактора... Notepad++, например... перегнать массив в uint32_t и не мучаться...
я уже думал об этом но мне из него нужно получать и int32 и int8 а массив я так полагаю может быть только одномерным!
Разве что сделать два массива!

Re: Мелкие вопросы по языку СИ

Добавлено: Пт май 30, 2014 06:31:26
optima
Еще разок спасибо! подошло это

per = __REV(*(__IO uint32_t *)((uint32_t)&(moimassiv) + 0));

А что обозначает вот эта запись __REV

Re: Мелкие вопросы по языку СИ

Добавлено: Пт май 30, 2014 08:25:23
oleg110592
__REV http://www.keil.com/support/man/docs/ar ... AEEGCE.htm
для 16 пиков тоже применял через указатели - работало, для eeprom правда, типа так:

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

*((unsigned char*)&per + 0) = moimassiv[0];
*((unsigned char*)&per + 1) = moimassiv[1];
*((unsigned char*)&per + 2) = moimassiv[2];
*((unsigned char*)&per + 3) = moimassiv[3];

Re: Мелкие вопросы по языку СИ

Добавлено: Пт май 30, 2014 13:50:46
Myp3ik
optima, __REV меняет порядок байт в слове. Без него вместо нужных 0x01020304 получим 0x04030201

Re: Мелкие вопросы по языку СИ

Добавлено: Пт май 30, 2014 14:12:46
optima
ОК! Спасибо.