Симуляция микроконтроллеров PICSim.js

PIC (Peripheral Interface Controller) - серия микроконтроллеров, имеющих гарвардскую архитектуру и производимых компанией Microchip. Под маркой PIC выпускаются 8 (PIC10/12/16/18), 16 (PIC24, dsPIC30, dsPIC33F) и 32-битные PIC32 микроконтроллеры. PIC10 линейка отличается низкой стоимостью за счёт ограниченного набора периферии (обычно АЦП и ШИМ) и невысокой производительности. В свою очередь PIC32 на данный момент является флагманом компании Microchip на рынке микроконтроллеров, обладая наиболее высокой производительностью и наиболее продвинутой периферией на борту. Ниже изображена блок-схема микроконтроллера PIC16F648. В принципе за исключением количества портов ввода-вывода PORTA, PORTB... и набора периферийных модулей Timer, CCP1... этот рисунок у большинства современных PIC16 будет идентичен.

screenshot

Микроконтроллеры PIC16 имеют очень эффективный набор команд - всего 35. Большинство выполняются за один цикл, в некоторых случаях (условные переходы) 2. Для выполнения одного цикла требуется 4 периода тактовой частоты. Несмотря на небольшой набор команд на их основе можно реализовать любую логику или если выражаться по-умному то такой набор команд является полным по Тьюрингу. На каком языке бы ни была написана программа для PIC16 микроконтроллера, после компиляции она будет представлена определённой последовательностью различных команд из 35. Скачать C-компилятор xc8 можно c сайта Microchip.

hex | picsim.js

/*
  xc8 --chip=16f648A blink.c
*/

// http://microchip.wikidot.com/faq:26
// The delay amount must be a constant (cannot be a variable).
#define _XTAL_FREQ 5e4 // 50 kHz

#include <xc.h>

#pragma config WDTE = OFF

int main() {

  RB0 = 0;             // RB0 initial value
  TRISB = 0xFF-1;      // RB0 as Output PIN

  while(42)
  {
    RB0 = 1;           // LED ON
    __delay_ms(1000);  // 1 Second Delay
    RB0 = 0;           // LED OFF
    __delay_ms(1000);  // 1 Second Delay
  }
  return 0;
}

Макрос #define _XTAL_FREQ 1e6 нужен компилятору для расчёта __delay_ms. При старте микроконтроллера все порты ввода-вывода настроены на вход, а чтобы мигать лампочкой RB0 должен работать на выход поэтому TRISB = 0xFF-1. Далее бесконечных цикл - переключение, временная задержка. На выходах RA1-RA3 подтягивающие резисторы, поэтому лампочки такие зелёные.

Если не полениться и взглянуть на blink.asm файл (ассемблерный листинг), сгенерированный компилятором xc8 рядом с blink.hex, то можно увидеть команды типа bcf, movlw и т.д. которые собственно и входят в те 35, упомянутых ранее.

screenshot

Следующая сложная программа уже взаимодействует с пользователем посредством кнопок RA1-RA3. Каждая кнопка сигнализирует о нажатии своей комбинацией светодиодов на PORTB.

hex | picsim.js

/*
  xc8 --chip=16f648A buttons.c
*/

#include <xc.h>
#include <stdbool.h>

#pragma config WDTE = OFF

int main() {

  PORTB = TRISB = 0;

  while(true) {
    if (!RA1) {
      RB0 = true;
    } else if (!RA2) {
      RB0 = RB1 = true;
    } else if (!RA3) {
      RB0 = RB1 = RB2 = true;
    } else if (!RA4) {
      RB0 = RB1 = RB2 = RB3 = true;
    } else {
      PORTB = 0;
    }
  }

  return 0;
}

Данный код не будет одинаково корректно функционировать в широком диапазоне тактовых частот т.к. не содержит зависимостей от __delay-подобных функций.

Особое внимание стоит обратить на выражение типа PORTB=TRISB=0; - здесь присваивание идёт справа налево, то есть в приближении этот код аналогичен TRISB=0; /* что сейчас на выходе PORTB ? */ PORTB=TRISB; /* вот сейчас точно 0 */, но не лучше ли сделать так TRISB=PORTB=0;, что аналогично PORTB=0;TRISB=PORTB; ? Проблема последнего выражения в том, что PORTB это не обычный регистр, а порт ввода-вывода и может давать на чтение значение, отличное от записанного. Из этого всего следует, что самый простой и надёжный способ это инициализировать порты ввода вывода явно: PORTB=0;TRISB=0;. Хотя в режиме симуляции ничего «сгореть» не может, поэтому PORTB=TRISB=0; тоже можно :)

screenshot

Далее ШИМ.

P.S. Таблица периферийных модулей реализованных в симуляторе PICSim.

links

social