С-код двоичного счетчика для pic16f877a

Я пытаюсь написать код для двоичного счетчика вверх/вниз. Задача состоит в том, чтобы зажечь 8 светодиодов (счетчик вверх), а затем изменить порядок свечения (счетчик вниз). Я пытаюсь создать массив светодиодов в своем коде, но я не знаю, как это сделать. Всякий раз, когда я использую PORTB [i], я получаю и требуется указатель ошибки, и если я использую PORTB.i, я также получаю сообщение об ошибке, как я получаю доступ к светодиодам, подключенным к portb? Это мой первый опыт работы с микроконтроллерами в целом, и я был бы очень признателен за вашу помощь. Вот мой код:

char LED_Direction at TRISB;
void main() {
int i;
LED_Direction=0x00;
PORTB=0x00;
//sbit LED_Array [8] = {PORTB.0,PORTB.1,PORTB.2,PORTB.3,PORTB.4,PORTB.5,PORTB.6,PORTB.7};
    while(1)
   {
      for (i=0; i<8; i++)
      {
          //LED_Array [i] = 1;
          PORTB[i]=1;
          Delay_ms(1000);
          //LED_Array [i] = 0;
          PORTB.i=1;
      }
      for (i=7; i>-1; i--)
      {
          //LED_Array [i] = 1;
          PORTB.i=1;
          Delay_ms(1000);
          PORTB.i=0;
          //LED_Array [i] = 0;
      }
    }
}
А вопрос?
Всякий раз, когда я использую PORTB[i], я получаю указатель ошибки, и если я использую PORTB.i, я также получаю сообщение об ошибке, как я могу получить доступ к светодиодам, подключенным к portb? @PlasmaHH
Какой компилятор вы используете?
Я использую mikroC PRO для PIC v.6.4.0 @DanLaks

Ответы (3)

PORTB не является ни структурой, ни массивом (или указателем).
Каждый бит в значении, которое вы ему присваиваете, напрямую соответствует выводу.
Ваша строка кода в начале main(), которая гласит: «PORTB=0x00;» это правильный способ присваивать значения PORTB.
Если вы хотите, чтобы младший бит был высоким, а остальные — низкими, установите его в 0x01 (0b00000001).
Если вы хотите, чтобы самый старший бит был старшим, а остальные — низкими, вам нужно значение 0x80 (0b10000000).
0x55 (0b01010101) или 0xAA (0b10101010) будут устанавливать чередование высоких и низких битов.
Вы также можете использовать битовый сдвиг для установки определенного бита, поэтому (1 << 3) установит 3-й бит и так далее.

PORTB действует как целое число (int). Когда вы пишете в PORTB, вы записываете все 8 бит одновременно. Вы можете использовать только квадратные скобки (var[i]) с массивами и поля (var.fieldname) со структурами. Вы не можете использовать переменную в имени поля.

Чтобы установить и очистить биты, используйте побитовые операторы C:

PORTB |= (1 << 4);    //Set bit 4
PORTB &= ~(1 << 6);   //Clear bit 6
PORTB = 0x03;         //Set bits 0 and 1, clear all others

Они позволяют использовать переменную:

PORTB |= (1 << i);    //Set bit i
PORTB &= ~(1 << i);   //Clear bit i

Есть и другие способы сделать то, что вы хотите, но это самый простой.

Ваш код, кажется, включает один светодиод за раз, переходя от B0 к B7 и обратно. Если вы хотите создать реальный двоичный счетчик, вы можете сделать что-то вроде этого:

unsigned long i;

while (1)
{
    for (i = 0; i < 256; i++)
    {
        PORTB = i;
        Delay_ms(1000);
    }
}

На более поздних PIC лучше использовать LATB вместо PORTB.

ОБНОВЛЕНИЕ. Основное правило для побитовых операторов заключается в том, что вы выполняете ИЛИ с 1 для установки битов, И с 0 для очистки битов и XOR с 1 для переключения битов. Побитовые операции, которые я использовал выше, работают следующим образом:

PORTB |= (1 << 4);  //Set bit 4

эквивалентно:

PORTB = PORTB | (1 << 4);  //Set bit 4

(1 << 4) равно 00010000. В десятичном виде это 1 2 4 , или 16. В шестнадцатеричном формате это 0x10. Оператор ИЛИ (|) выполняет операцию ИЛИ каждого бита в PORTB с соответствующим битом в (1 << 4). Например, если в PORTB установлен только первый бит, вы получите:

  00000010   PORTB
| 00010000   (1 << 4)
-----------
  00010010   PORTB with bit 4 set

Бит 4 устанавливается без нарушения других битов.

Очистка бита лишь немного сложнее. Начнем с бинарного примера. Если в PORTB установлены биты 2 и 4, и вы хотите очистить бит 2, вам нужно сделать следующее:

  00010100   PORTB
& 11111011   Mask value for clearing bit 2
-----------
  00010000   PORTB with bit 2 cleared

Бит 2 очищается, не нарушая другие биты. Видите, второй операнд почти полностью состоит из единиц? Мы могли бы записать это вручную в шестнадцатеричном виде как 0xFB:

PORTB = PORTB & 0xFB;  //Clear bit 2

Но тогда тот, кто читает код, должен остановиться и подумать о том, какие биты 0xFB очищаются. Мы можем сделать код более понятным, установив для интересующего нас бита значение 2 и инвертировав результат:

~(1 << 2);

который дает:

~ 00000100   (1 << 2)
-----------
  11111011   ~(1 << 2) = Mask value for clearing bit 2

Это более понятно, чем шестнадцатеричное значение:

PORTB = PORTB & ~(1 << 2);  //Clear bit 2

который сокращается до:

PORTB &= ~(1 << 2)  //Clear bit 2

Когда вы устанавливаете или очищаете несколько битов, чаще используют шестнадцатеричные значения вместо записи набора значений со сдвигом. Единственный способ справиться с этим — узнать, как шестнадцатеричный код соотносится с двоичным, что не очень сложно.

Одно важное предостережение заключается в том, что компиляторы C интерпретируют числа как целые числа со знаком. Если int имеет длину всего 16 бит (что часто верно для микроконтроллеров), то что-то вроде этого может дать сбой:

unsigned long a;

a = (1 << 20);  //Needs more than 16 bits -- too big for an int!
                //a could now be equal to zero

Вы можете исправить это, приведя одно из чисел к типу long. Сделайте его беззнаковым, чтобы избежать предупреждений, когда установлен верхний бит:

unsigned long a;

a = (1UL << 20);  //Should now work correctly

Почти всегда лучше использовать uint8_t, uint16_t и uint32_t from вместо собственных типов C, но использование суффикса UL все еще распространено.

Этот PIC, по-видимому, предшествует разделению PORTB/LATB. Для более поздних PIC, у которых есть LATx, это, безусловно, «правильный» вариант для использования.
@AdamHaun, в вашем примере кода для двоичного счетчика есть потенциальная ошибка. Если переменная i является символом без знака (как и должно быть), то сравнение ее с 256 может привести к неожиданному поведению.
@DanLaks Вау, не могу поверить, что пропустил это. Спасибо за исправление!
@AdamHaun - вы можете просто использовать (без знака) int. Стандарт C требует, чтобы int был не менее 16 бит.
@AdamHaun большое спасибо за отличное объяснение. Мне было интересно, хотя об этом выражении PORTB |= (1 << 4); //Set bit 4сдвигает ли оно число 1 на четыре бита влево или результат с предыдущим значением для PORTB? я тоже в замешательствеPORTB &= ~(1 << 6)
У меня также есть еще один вопрос относительно этой части: You can only use square brackets (var[i]) with arrays, and fields (var.fieldname) with structures. я называл sbit RED_LED at PORTC.B5;конкретный светодиод, и мне было интересно, чем он отличается? @АдамХаун
@Nemo Я ответил на твой первый вопрос. Я вернусь за другим позже.
@Nemo sbit не является стандартным C, это расширение компилятора.
char LED_Direction at TRISB;
void main()
{
    int i;
    LED_Direction=0x00;
    PORTB=0x00;
    //sbit LED_Array [8] = {PORTB.0,PORTB.1,PORTB.2,PORTB.3,PORTB.4,PORTB.5,PORTB.6,PORTB.7};
    while(1)
   {
      for (i=0; i<8; i++)
      {
          PORTB = 1 << i;
          Delay_ms(1000);
      }
      for (i=7; i>-1; i--)
      {
          PORTB = 1 << i;
          Delay_ms(1000);
      }
      PORTB = 0;
    }
}
Лучшим ответом будет описание того, почему вы изменили то, что вы изменили, вместо того, чтобы просто дать окончательное решение для OP.
Согласен, но я думал, что это неявно. Вы видите, что изменилось...