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

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2309
Зарегистрирован: Пт июл 17, 2009 07:34:07
Откуда: Свердловская обл.

Сообщение 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 мне очень помогла...
не зная броду не лезь к вольтмоду
Реклама
Опытный кот
Аватара пользователя
Сообщения: 830
Зарегистрирован: Пт ноя 16, 2007 11:21:37

Сообщение Pavel_1978 »

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

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

А Си он хоть для АРМ хоть для ПК один.
Для AVR ты на чем писал? И какую сейчас IDE используешь?
Реклама
Друг Кота
Аватара пользователя
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Сообщение 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
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18783
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

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

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2309
Зарегистрирован: Пт июл 17, 2009 07:34:07
Откуда: Свердловская обл.

Сообщение 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, что типа так не делается - по этому налепил его сюда-же....
не зная броду не лезь к вольтмоду
Реклама
Опытный кот
Аватара пользователя
Сообщения: 725
Зарегистрирован: Вт апр 26, 2011 13:58:36
Откуда: Ростовская область

Сообщение amv2000 »

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

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

ledinit.GPIO_Pin = (GPIO_Pin_13 | GPIO_Pin_12 | GPIO_Pin_14 | GPIO_Pin_15); // Светодиод LD3 на 12, 13, 14 и 15-ом выводе
Реклама
Друг Кота
Сообщения: 4583
Зарегистрирован: Вс дек 05, 2010 06:10:34
Откуда: ЮВ

Сообщение HHIMERA »

uwrtey писал(а): Если я правильно понимаю, то этим кодом я заставлю дрыгаться весь порт на частоте 2 мегагерца.
А как же мне быть если я захочу дрыгать на этой частоте только те ножки которые мне надо, а другие на другой частоте или в обще оставить их в покое ?
Ничего там дрыгаться не будет... И никакого отношения к настройке тактирования это не имеет... Это всего лишь настройка максимальной скорости нарастания выходного сигнала на пине... Делается это для возможности снижения ЭМИ МК... если это существенно для девайса...
Т.е. если установить скорость нарастания для пина с 2МГц максимум, то дрыгнуть этой ногой с частотой 15МГц уже не получится... из-за затяжных фронтов... следовательно, для 15МГц уже нужно устанавливать более высокую скорость нарастания пина...
"Я не даю готовых решений, я заставляю думать!"(С)
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2309
Зарегистрирован: Пт июл 17, 2009 07:34:07
Откуда: Свердловская обл.

Сообщение uwrtey »

HHIMERA писал(а):Ничего там дрыгаться не будет
да это то я знаю. вопрос был в другом.
Я выше привел код. Дак вот - мне интересно там на 2 мегагерца настроен весь порт? или те пины которые я указал ?
не зная броду не лезь к вольтмоду
Друг Кота
Аватара пользователя
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Сообщение oleg110592 »

да "те пины которые я указал"
СпойлерИзображение
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2309
Зарегистрирован: Пт июл 17, 2009 07:34:07
Откуда: Свердловская обл.

Сообщение uwrtey »

А-а, ну тогда понятно...
не зная броду не лезь к вольтмоду
Прорезались зубы
Аватара пользователя
Сообщения: 232
Зарегистрирован: Вт май 08, 2012 10:42:29

Сообщение optima »

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

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

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

Сообщение uk8amk »

проще всего реализовать через указатель:

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

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

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

Возможно также сделать через union.
Друг Кота
Сообщения: 4583
Зарегистрирован: Вс дек 05, 2010 06:10:34
Откуда: ЮВ

Сообщение 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++);

"Я не даю готовых решений, я заставляю думать!"(С)
Мучитель микросхем
Аватара пользователя
Сообщения: 450
Зарегистрирован: Вс янв 09, 2011 23:05:37
Откуда: СССР

Сообщение 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]));
Иван Сусанин - первый полупроводник :solder:
Друг Кота
Сообщения: 4583
Зарегистрирован: Вс дек 05, 2010 06:10:34
Откуда: ЮВ

Сообщение HHIMERA »

Myp3ik писал(а):Можно и сдвигами
Да если честно...
имеется массив const uint8_t moimassiv[] и имеется переменная uint32_t per;
Проще с помощью редактора... Notepad++, например... перегнать массив в uint32_t и не мучаться...
"Я не даю готовых решений, я заставляю думать!"(С)
Прорезались зубы
Аватара пользователя
Сообщения: 232
Зарегистрирован: Вт май 08, 2012 10:42:29

Сообщение optima »

Спасибо всем откликнувшимся! сегодня попробую.
HHIMERA писал(а): Проще с помощью редактора... Notepad++, например... перегнать массив в uint32_t и не мучаться...
я уже думал об этом но мне из него нужно получать и int32 и int8 а массив я так полагаю может быть только одномерным!
Разве что сделать два массива!
Прорезались зубы
Аватара пользователя
Сообщения: 232
Зарегистрирован: Вт май 08, 2012 10:42:29

Сообщение optima »

Еще разок спасибо! подошло это

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

А что обозначает вот эта запись __REV
Друг Кота
Аватара пользователя
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Сообщение 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];
Мучитель микросхем
Аватара пользователя
Сообщения: 450
Зарегистрирован: Вс янв 09, 2011 23:05:37
Откуда: СССР

Сообщение Myp3ik »

optima, __REV меняет порядок байт в слове. Без него вместо нужных 0x01020304 получим 0x04030201
Иван Сусанин - первый полупроводник :solder:
Прорезались зубы
Аватара пользователя
Сообщения: 232
Зарегистрирован: Вт май 08, 2012 10:42:29

Сообщение optima »

ОК! Спасибо.
Ответить

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