Наш магазин на eBay Наш магазин на AliExpress Наш канал в telegram

Управляющая программа для контроллера генератора прямоугольных импульсов

Представленная в этой статье программа написана для микроконтроллера, управляющего генератором прямоугольных импульсов. Основные функции, выполняемые программой: 1) обмен данными с компьютером по последовательному интерфейсу; 2) настройка необходимым образом и включение встроенного в микроконтроллер модуля ШИМ; 3) работа с EEPROM.

Для обмена информацией между контроллером и ПК подходит любая терминалка, умеющая работать в hex-режиме, например, RH_Com — программа, специально разработанная нами для работы с COM-портом (прогу и исходники можно найти здесь).

Теперь по пунктам:

  1. Конфигурационная информация, посылаемая с компьютера, состоит из трёх байт. Первый байт содержит командные биты, биты, определяющие коэффициент деления предделителя TMR2, а также 2 младших бита длительности импульса. Он имеет следующий формат: старший бит — стирание EEPROM (если старший бит установлен в 1, то будет выполнено стирание информации из EEPROM), 6-й бит — запись в EEPROM (если этот бит установлен в 1, то будет выполнена запись принятой конфигурационной информации в EEPROM), 5-й и 4-й биты — младшие биты длительности импульса, 3-й и 2-й биты — биты, определяющие коэффициент деления предделителя TMR2, 1-й и 0-й биты не используются и могут быть любыми.

    Второй байт содержит 8 бит, определяющих период ШИМ.

    Третий байт содержит старшие 8 бит длительности импульса.

    Кроме того, управляющая программа посылает назад в терминалку диагностические сообщения о выполнении некоторых действий, например, сразу после старта она посылает сообщение "Start", при записи полученных данных — "Save" и т.д.

  2. Настройка ШИМ. Настройка ШИМ выполняется следующим образом:

    а) В регистр PR2 (банк 1, смещение 12h) загружается период импульса;

    б) В регистр CCPR1L (банк 0, смещение 15h) загружаются старшие 8 бит длительности импульса, а в регистр CCP1CON (банк 0, смещение 17h) загружаются младшие 2 бита длительности импульса {5-й и 4-й биты};

    в) В регистр T2CON (банк 0, смещение 12h) загружаются настройки предделителя {1-й и 0-й биты}, и там же включается сам таймер {бит 2 устанавливается в 1}.

    Коэффициент предделителя TMR2 в зависимости от настроек: 00 — 1:1, 01 — 1:4, 1x — 1:16.

    г) 3-й и 2-й биты регистра CCP1CON (банк 0, смещение 17h) устанавливаются в 1.

    Кроме этого, для работы вывода RB3/CCP1 в качестве выхода ШИМ, — бит направления TRISB{3} должен быть сброшен в ноль.

    Период и длительность импульса генератора определяются по следующим формулам:

    T=(PR2+1)*4*Tosc*коэффиц.преддел.TMR2

    tи=CCPR1L:CCP1CON{5,4}*Tosc*коэффиц.преддел.TMR2,

    где Tosc — тактовая частота контроллера.

  3. Работа с EEPROM заключается в следующем: а) при включении питания, контроллер загружает конфигурацию из EEPROM (если она там есть); б) запись/стирание EEPROM в зависимости от состояния в принятой конфигурации командных битов.

    Для того, чтобы не мучится с вычислениями, на традиционном уже C++ Builder 6 была написана прога, вычисляющая искомые три байта конфигурации контроллера по введённым параметрам генератора. Опять же традиционно, отдаю с исходниками: прога + исходники.

Итак, алгоритм работы управляющей программы:

Алгоритм работы программы генератора прямоугольных импульсов
Алгоритм работы программы генератора прямоугольных импульсов

Здесь представлены только алгоритмы основной программы и подпрограммы обработки прерывания, поскольку алгоритм настройки и включения ШИМ достаточно подробно описан выше, а алгоритмы работы с EEPROM и UART стандартны и ранее уже не раз описывались на сайте.

Текст программы под катом

 list    p = 16f628a
 __config 2110h
;*** Переменные ******************************************
   CBLOCK 0x20     ; Начальный адрес блока пользовательской памяти
      Rbyte        ; Принятый байт
      Byte_Counter ; Счётчик
   ENDC
;-----------------------------
   CBLOCK 0x30     ; Блок принятых данных
      Regim        ; режим работы          30h
                   ; 7 - стир-е EEPROM, 6 - запись в EEPROM,
                   ; 5,4 - младшие биты длит-ти, 3,2 - преддел.
      Period       ; период                31h
      Dlit_imp     ; длит-ть импульса 32h  , старшие 8 бит длительности
   ENDC
;*** Константы / Адреса регистров *************************
Baudrate equ  .12  ; скорость 19200
;---------------------------------------------------------
STATUS   equ  03h  ; Регистр выбора банка
PORTA    equ  05h  ; Порт А
PORTB    equ  06h  ; Порт В
TRISA    equ  05h  ; Конфигурация порта А (банк 1)
TRISB    equ  06h  ; Конфигурация порта В (банк 1)
CMCON    equ  1Fh  ; Управление компараторами
INTCON   equ  0Bh  ; Управление прерываниями
;---------------------------------------------------------
PR2      equ  12h  ; период Т2 (период ШИМ) (банк 1)
CCPR1L   equ  15h  ; старшие 8 бит длительности импульса
CCP1CON  equ  17h  ; биты 5,4 - младшие биты длит.имп-са, биты 3,2=1 - ШИМ режим
T2CON    equ  12h  ; настр-ка предд-ля и вкл-е TMR2
;---------------------------------------------------------
FSR      equ  04h  ; регистр адреса при косвенной адресации
INDF     equ  0h   ; регистр косвенной адресации
EEADR    equ  1Bh  ; адрес EEPROM
EECON1   equ  1Ch  ; управляющий регистр для работы c EEPROM
EECON2   equ  1Dh  ; управляющий регистр для работы c EEPROM
EEDATA   equ  1Ah  ; регистр данных из/в EEPROM
;-------Регистры передатчика и приемника----------------------
TXREG    equ  19h  ; буфер передатчика
RCREG    equ  1Ah  ; буфер приемника
PIR1     equ  0Ch  ; регистр флагов передатчика
PIE1     equ  0Ch  ; регистр разрешения/запрета прерываний передатчика
TXSTA    equ  18h  ; конфигурация передатчика (1-й банк)
RCSTA    equ  18h  ; конфигурация приемника
SPBRG    equ  19h  ; настройка скорости
;********************************************************
 
           org 0
      goto start
;********************************************************
;*** ОБРАБОТКА ПРЕРЫВАНИЯ *******************************
           org 4
prog  btfss  PIR1,5  ; если 5-й бит PIR1 = 1, - в буфер пришли данные
      goto exit
;--- Принимаем данные --------------------
      call   zagruzka2
;--- Проверяем, надо ли стирать EEPROM ---
      btfsc  Regim,7    ; если 7-й бит Regim=1, то надо стирать EEPROM
      call   clear_data
;------ Проверяем, надо ли записывать принятую инфу в EEPROM ---
      btfsc  Regim,6    ; если 6-й бит Regim=1, то надо писать в EEPROM
      call   save_data
      call   start_shim ; загружаем новые данные в ШИМ
exit  retfie
;***** Конец обработчика прерывания *********************
;********************************************************
;******** НАЧАЛЬНАЯ ИНИЦИАЛИЗАЦИЯ ***********************
;--- Настройка портов --------------------
start movlw  .7
      movwf  CMCON     ; выключить компараторы
      clrf   PORTA     ; инициализация защелок порта А
      clrf   PORTB     ; инициализация защелок порта В
      bsf    STATUS,5  ; Перейти в 1-й банк
      movlw  .32       ; Записать конф-ю порта A в аккум-р (W).  .32=00100000
      movwf  TRISA     ; Скопировать конф-ю порта А из W в регистр TrisA
      movlw  .6        ; Записать конф-ю порта В в аккум-р (W).  .6=00000110
      movwf  TRISB     ; Скопировать конф-ю порта B из W в регистр TrisB.
      bcf    STATUS,5  ; Перейти в 0-й банк
;--- Настройка приемо-передатчика --------
      bsf    STATUS,5     ; перейти в первый банк
      movlw  Baudrate     ; загрузить устанавливаемую скорость в аккумулятор
      movwf  SPBRG        ; установить скорость
      movlw  b'00100100'  ; 8-разрядные данные, включить передачу,
      movwf  TXSTA        ; высокоскоростной асинхронный режим
      bcf    PIE1, 4      ; запретить прерывания от передатчика USART (TXIE=0)
      bsf    PIE1, 5      ; разрешить прерывания от приемника USART   (RCIE=1)
      bcf    STATUS,5     ; перейти в нулевой банк
      movlw  b'10000000'  ; 8-разрядные данные, выключить прием,
      movwf  RCSTA        ; включить модуль USART
;--- Загрузка данных из EEPROM в ОЗУ -----
      call   zagruzka
;--- Включение ШИМ, если есть данные -----
      movlw  0FFh
      xorwf  Regim,0
      btfss  STATUS,2     ; если Regim равно FF - пропустить
      call   start_shim   ; запускаем ШИМ
;--- Включить приёмник и разрешить прерывания от него ---
      bsf    RCSTA,4      ; включаем приемник
      movlw  b'11000000'  ; GIE, PEIE - прерывания от периферии и глобальные
      iorwf  INTCON,1
;*** РАБОТА *********************************************
cikl  nop
      goto cikl
;********************************************************
;*** ПРОЦЕДУРЫ ******************************************
;*** ЗАГРУЗКА ИЗ EEPROM в ОЗУ ***************************
;--- Загружаем данные
zagruzka
      bsf    STATUS,5     ; переходим в первый банк
      movlw  .0
      movwf  EEADR        ; читаем нулевой байт из EEPROM
      bsf    EECON1,0     ; чтение
      movf   EEDATA,0     ; запись прочитанного байта в аккумулятор
      bcf    STATUS,5     ; Перейти в 0-й банк
      movwf  Regim        ; сохранение прочитанного байта в Regim
      bsf    STATUS,5     ; переходим в первый банк
      incf   EEADR,1      ; читаем первый байт из EEPROM
      bsf    EECON1,0     ; чтение
      movf   EEDATA,0     ; запись прочитанного байта в аккумулятор
      bcf    STATUS,5     ; Перейти в 0-й банк
      movwf  Period       ; сохранение прочитанного байта в Period
      bsf    STATUS,5     ; переходим в первый банк
      incf   EEADR,1      ; читаем первый байт из EEPROM
      bsf    EECON1,0     ; чтение
      movf   EEDATA,0     ; запись прочитанного байта в аккумулятор
      bcf    STATUS,5     ; Перейти в 0-й банк
      movwf  Dlit_imp     ; сохранение прочитанного байта в Dlit_imp
;--- Пишем "Load "
      movlw  4Ch          ; шлём "L"
      call   send_byte
      movlw  6Fh          ; шлём "o"
      call   send_byte
      movlw  61h          ; шлём "a"
      call   send_byte
      movlw  64h          ; шлём "d"
      call   send_byte
      movlw  20h          ; шлём " "
      call   send_byte
      return
;*** ПОСЫЛКА БАЙТА В ПОРТ *********************
send_byte
      movwf  TXREG   ; шлём байт из аккумулятора
      nop
wait_tr
      btfss  PIR1,4  ; ждём пока данные уйдут в порт (сразу после загрузки
      goto   wait_tr ; TXREG бит проверять нельзя - может не успеть устан-ся)
      return
;*** Приём данных в ОЗУ ***********************
zagruzka2
      movf   RCREG,0    ; читаем буфер приемника в аккумулятор
      movwf  Regim      ; и сохраняем в Size
wait_msg1
      btfss  PIR1,5
      goto   wait_msg1  ; ждём приёма второго байта
      movf   RCREG,0    ; читаем принятый байт в аккумулятор
      movwf  Period     ; и сохраняем в Period
wait_msg2
      btfss  PIR1,5
      goto   wait_msg2  ; ждём приёма третьего байта
      movf   RCREG,0    ; читаем принятый байт в аккумулятор
      movwf  Dlit_imp   ; и сохраняем в Dlit_imp
;--- пишем "Read" ---
      movlw  52h        ; шлём "R"
      call   send_byte
      movlw  65h        ; шлём "e"
      call   send_byte
      movlw  61h        ; шлём "a"
      call   send_byte
      movlw  64h        ; шлём "d"
      call   send_byte
      movlw  20h        ; шлём " "
      call   send_byte
      return
;*** Сохранение данных в EEPROM ***************
;--- Сохраняем данные ---
save_data
      movlw  Regim          ; адрес начала записываемого буфера
      movwf  FSR
      movlw  .3             ; кол-во записываемых байт
      movwf  Byte_Counter
      bsf    STATUS,5       ; переходим в первый банк
      clrf   EEADR          ; установить адрес для записи в EEPROM
      bcf    STATUS,5
zapis movf   INDF,0         ; читаем байт из буфера
      bsf    STATUS,5
      movwf  EEDATA         ; помещаем его на запись
      bsf    EECON1, 2      ; WREN=1 - разрешаем запись
      movlw  55h
      movwf  EECON2
      movlw  0AAh
      movwf  EECON2
      bsf    EECON1,1       ; WR=1 - пишем
      bcf    STATUS,5
wait_end
      btfss  PIR1,7         ; если EEIF=1 - запись окончена
      goto   wait_end
      bcf    PIR1,7         ; сбросить флаг
      bsf    STATUS,5       ; в первый банк
      incf   EEADR,1        ; увеличить адрес EEPROM
      bcf    STATUS,5       ; в нулевой банк
      incf   FSR,1          ; увеличить адрес буфера
      decfsz Byte_Counter,1 ; если записали все байты - проп.след.команду
      goto   zapis
;--- Пишем "Save " ---
      movlw  53h          ; шлём "S"
      call   send_byte
      movlw  61h          ; шлём "a"
      call   send_byte
      movlw  76h          ; шлём "v"
      call   send_byte
      movlw  65h          ; шлём "e"
      call   send_byte
      movlw  20h          ; шлём " "
      call   send_byte
      return
;*** Стирание EEPROM **********************************
;--- Пишем в стираемые ячейки FF ---
clear_data
      movlw  .3
      movwf  Byte_Counter   ; кол-во стираемых байт
      bsf    STATUS,5       ; переходим в первый банк
      clrf   EEADR          ; установить адрес для записи в EEPROM
      bcf    STATUS,5
clear bsf    STATUS,5
      movlw  0FFh
      movwf  EEDATA         ; помещаем на запись FFh
      bsf    EECON1, 2      ; WREN=1 - разрешаем запись
      movlw  55h
      movwf  EECON2
      movlw  0AAh
      movwf  EECON2
      bsf    EECON1,1       ; WR=1 - пишем
      incf   EEADR,1        ; увеличить адрес EEPROM
      bcf    STATUS,5
wait_clear
      btfss  PIR1,7         ; если EEIF=1 - запись окончена
      goto   wait_clear
      bcf    PIR1,7         ; сбросить флаг
      decfsz Byte_Counter,1 ; если записали все байты - проп.след.команду
      goto   clear
;--- Пишем "Clear " ---
      movlw  43h          ; шлём "C"
      call   send_byte
      movlw  6Ch          ; шлём "l"
      call   send_byte
      movlw  65h          ; шлём "e"
      call   send_byte
      movlw  61h          ; шлём "a"
      call   send_byte
      movlw  72h          ; шлём "r"
      call   send_byte
      movlw  20h          ; шлём " "
      call   send_byte
      return
;*** Включение ШИМ ************************************
start_shim
      movf   Period,0       ; прочитать период ШИМ в аккумулятор
      bsf    STATUS,5       ; перейти в первый банк
      movwf  PR2            ; загрузить период в PR2
      bcf    STATUS,5       ; вернуться в нулевой банк
      movf   Dlit_imp,0
      movwf  CCPR1L         ; загрузить старшие 8 бит
      movf   Regim,0
      andlw  b'00110000'    ; выделить 5-й и 4-й биты длительности импульса
      iorwf  CCP1CON,1      ; загрузить их в CCP1CON
      movf   Regim,0
      andlw  b'00001100'    ; выделить коэфф. предд-ля (3,2-й биты рег.Regim)
      movwf  Byte_Counter   ; загрузить полученное значение в Byte_counter
      rrf    Byte_Counter,1 ; сдвинуть вправо на 1 бит
      bsf    Byte_Counter,3 ; поднять 3-й бит
      rrf    Byte_Counter,0 ; сдвинуть ещё на один бит вправо и загрузить в W
      movwf  T2CON          ; настроить предделитель и включить таймер
      movlw  b'00001100'
      iorwf  CCP1CON,1      ; включить ШИМ
;--- Пишем "Enable "---
      movlw  45h          ; шлём "E"
      call   send_byte
      movlw  6Eh          ; шлём "n"
      call   send_byte
      movlw  61h          ; шлём "a"
      call   send_byte
      movlw  62h          ; шлём "b"
      call   send_byte
      movlw  6Ch          ; шлём "l"
      call   send_byte
      movlw  65h          ; шлём "e"
      call   send_byte
      movlw  20h          ; шлём " "
      call   send_byte
      return
 
 end
;---------------------------------------------------------

[свернуть]

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

Скачать готовую прошивку и asm-файл

Добавить комментарий