Обсуждаем контроллеры компании Atmel.
Ответить

(?) Небольшой вопрос по С

Ср авг 01, 2012 14:21:10

Здравствуйте, уважаемые коты!

Простите за вопрос не совсем по теме контроллеров, но по близкой...

Скажите, почему не работает следующий код:

Код:

PORTD = 0b11000011;
tmp=0;

while(1){
  tmp++;
  if (tmp>3)tmp=0;
  PORTD = PORTD & (0b11000011 | (1<<(2+tmp)) );
}


В теории это должно вызвать "бегущий огонь" диодов, подключенных к portd.2-portd.5, не трогая остальные выводы...
На практике творится что попало.

Либо, подскажите другой способ, пожалуйста.
Только просьба, тупой перебор битов порта не предлагать. Нужно именно по формуле, смещая огонек в зависимости от значения tmp...

PS: Компилятор CVAVR
PPS: Не знаю, важно ли это, но PORTD = PORTD & (0b11000011 | (1<<(2+tmp)) ); вызывается из прерывания таймера.

Re: (?) Небольшой вопрос по С

Ср авг 01, 2012 14:40:04

Код:
int main()
{
  unsigned char tmp=0;
  DDRD = 0b00111100;
  while(1)
  {
    tmp++;
    if (tmp>3)tmp=0;
    PORTD = 0b00111100 ^ (1<<(2+tmp));
    _delay_ms(1000);
  }
}

Вот. Как-то так.
Последний раз редактировалось romazan Ср авг 01, 2012 14:50:39, всего редактировалось 1 раз.

Re: (?) Небольшой вопрос по С

Ср авг 01, 2012 14:46:37

2romazan:
Тогда уж
Код:
PORTD = 0b00111100 ^ (1<<(2+tmp));

Re: (?) Небольшой вопрос по С

Ср авг 01, 2012 14:49:51

согласен, забыл :kill: :))

Re: (?) Небольшой вопрос по С

Ср авг 01, 2012 14:56:38

Johnson писал(а):Либо, подскажите другой способ, пожалуйста.
Попробуйте что-то вроде:
Код:
...
unsigned char mask;
...
for (;;)
  for (mask = 0b00000100; mask <= 0b00100000; mask <<= 1)
  {
    PORTD |= mask; // включить
    pause(); // сделать паузу, чтобы зафиксировать текущую позицию
    PORTD &= ~mask; // погасить
  }

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

Re: (?) Небольшой вопрос по С

Ср авг 01, 2012 15:07:32

PORTD = 0b00111100 ^ (1<<(2+tmp));

Не пойдет по одному из требований - необходимо, чтоб ноги 0,1,6,7 не изменили текущего состояния.


PORTD &= ~mask;

А вот над этим уже можно подумать, спасибо!

PS: мне не нужен конкретно бегущий огонь, паузы и всё такое.
Просто в своем примере я упростил код для понимания.
Мне нужно управлять ногами 2-5 в зависимости от значения переменной (сдвигать бит на значение переменной, но относительно второго бита порта, но не больше 5-го бита включительно).
В схеме даже диодов нет...

Re: (?) Небольшой вопрос по С

Ср авг 01, 2012 15:17:15

Всё, разобрался... Вопрос отменяется, спасибо большое всем, кто откликнулся!

Код:
PORTD = (PORTD & 0b11000011) | (1<<2+tmp2);

Затупил в логике, нудо было сначала обнулить нужные биты, а потом уже ИЛИ по маске производить.
А я производил И по маске, ничтоже сумнящийся, что в порте будут лог1 на нужных битах :)

PS: Можно даже подправить так на всякий случай, чтоб эта единица за пределы не вышла по ошибке...:
PORTD = (PORTD & 0b11000011) | ((1<<2+tmp2) & 0b00111100);

Re: (?) Небольшой вопрос по С

Ср авг 01, 2012 15:26:37

Johnson писал(а):Мне нужно управлять ногами 2-5 в зависимости от значения переменной (сдвигать бит на значение переменной, но относительно второго бита порта, но не больше 5-го бита включительно).
Тогда такой небольшой джентльменский набор:
Код:
static uint8_t mask(uint8_t n)
{
  return ((1 << (n+2)) & 0b00111100);
}

void bit_set(uint8_t n)
{
  PORTD |= mask(n);
}

void bit_clear(uint8_t n)
{
  PORTD &= ~mask(n);
}
Тип uint8_t определить самостоятельно, если не поддерживается вашим компилятором.

Re: (?) Небольшой вопрос по С

Ср авг 01, 2012 15:33:03

Спасибо большое, пригодится!

Да, это переменная в CVAVR значится как unsigned char X;

Re: (?) Небольшой вопрос по С

Ср авг 01, 2012 15:40:47

В кодвижне есть фича можно непосредственно к битам порта обращаться: PORTD.1 PORTD.2 и т.д.
Устанавливать и снимать бит просто PORTD.1 = 1; PORTD.1 = 0;
Учтите что это костыли, в стандарте такого нет, а в кодвижне есть )
Успехов

Re: (?) Небольшой вопрос по С

Ср авг 01, 2012 16:35:13

А почему это костыль обращение к битам??????

а что же такое тогда асмовая комманда

из даташита

Код:
SBI P,b Set Bit in I/O Register I/O(P,b) ← 1 None 2
CBI P,b Clear Bit in I/O Register I/O(P,b) ← 0


а интерпретатор или эту команду ставит или просто логик если нет аткого в ядре..но помоему даж в тине 13 есть


Код:
All ATmega8 I/Os and peripherals are placed in the I/O space. The I/O locations are accessed
by the IN and OUT instructions, transferring data between the 32 general purpose working registers
and the I/O space. I/O Registers within the address range 0x00 - 0x1F are directly bitaccessible
using the SBI and CBI instructions. In these registers, the value of single bits can be
checked by using the SBIS and SBIC instructions.

Re: (?) Небольшой вопрос по С

Чт авг 02, 2012 04:11:50

BCluster, не понимаю, к чему Вы...
Вы мои посты и примеры кода не читали вообще?

Во-первых, проблема уже решена логикой, а не костылями.
Во-вторых, я писал, что меня не устроит решение на побитном обращении...

Re: (?) Небольшой вопрос по С

Чт авг 02, 2012 07:15:14

clawham писал(а):А почему это костыль обращение к битам??????

а что же такое тогда асмовая комманда


Ничего не имею против асмовой команды ) Я говорю к тому, что данное обращение не является стандартным и непереносимо, вот и все :)

Johnson писал(а):Во-первых, проблема уже решена логикой, а не костылями.

Решена и решена, а кому-то может пригодится то о чем я написал. Вы свой ответ уже получили - чего злитесь? :)))

Re: (?) Небольшой вопрос по С

Чт авг 02, 2012 15:21:14

Решил не создавать новую тему...

Скажите, пожалуйста, как можно число (int) преобразовать в строку?

И ещё...
Может быть, у кого-нибудь есть готовый код, который позволит число из переменной вывести большими цифрами на LCD дисплее в нужном месте?
Дисплей WG12232, 122*32, по горизонтали разделен на 4 страницы (строки).
Нужен вывод цифры (а точнее двухзначного числа) на высоту всего дисплея.

Re: (?) Небольшой вопрос по С

Чт авг 02, 2012 15:38:51

Johnson писал(а):Скажите, пожалуйста, как можно число (int) преобразовать в строку?
Нестандартная, но широко распространенная функция:
Код:
void* itoa(int input, char *buffer, int radix)

Re: (?) Небольшой вопрос по С

Чт авг 02, 2012 15:51:21

А пример использования можно?
Не очень представляю, как нужно организовать буфер, и что есть 3й аргумент...

Re: (?) Небольшой вопрос по С

Чт авг 02, 2012 15:55:51

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

Re: (?) Небольшой вопрос по С

Чт авг 02, 2012 16:36:39

А есче можно printf() иcпользовать... или sprintf(). Жрет память программ.

Re: (?) Небольшой вопрос по С

Чт авг 02, 2012 16:38:12

3 аргумент это вроде как база системы счисления... И если я правильно помню он не во всех реализациях есть вообще.
буфер можете сразу по разрядности числа сделать.
Скажем если 2 разряда то
Код:
#define BASE  10
unsigned char buf[3];
unsigned char digit;
itoa ( digit, buf, BASE );
Последний раз редактировалось BCluster Пт авг 03, 2012 08:50:59, всего редактировалось 1 раз.

Re: (?) Небольшой вопрос по С

Чт авг 02, 2012 20:32:37

BCluster писал(а):Скажем если 2 разряда то
Код:
...
unsigned char buf[2];
...
itoa ( digit, buf, BASE );
Классическая реализация от Кернигана/Ритчи дописывает в конец строки еще и '\0'. Вполне вероятно, что остальные делают то же самое (хотя для нестандартной функции наверняка ничего утверждать нельзя). Поэтому для 2-разрядного числа лучше все же заложить буфер длиной не меньше 3 байт, чтобы не наступить на одни из наиболее популярных "сишных" граблей.
Ответить