Лабораторный блок питания с управлением от микроконтроллера

<<<  NEW >>> :четвёртая версия БП 

<<<  NEW >>> : вторая версия БП 

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

Вступление

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

Поиск подходящих конструкций, которые бы удовлетворяли всем моим требованиям, на просторах интернета и публикациях в журналах не принесла результата, либо они были маломощные, либо крайне неудобные. Поэтому за дело пришлось взяться самому.

Были сформулированы следующие требования к будущему блоку питания:

1. напряжение от 0 до 50 В.

2. максимальный ток нагрузки   до 5 А.

3. установка защиты по превышению тока от 0 до 5А.

4. удобство эксплуатации.

5. удобство ремонта и регулировки.

      6. возможность использования базового микроконтроллерного модуля в других конструкциях, путем изменения конфигурации в сервисном режиме.

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

 

блок-схема

 

Рис.1 Блок-схема блока питания

 

 

Блок - схема (рис.1) состоит из четырех блоков:

 

1. первичный источник предназначен для гальванической развязки от питающей сети и понижения напряжения  для регулятора. В зависимости от примененного первичного источника (импульсный блок или трансформатор с секционной вторичной обмоткой) используются разные подпрограммы микроконтроллера (об этом будет описано ниже).

2. регулятор -  собственно основная силовая аналоговая часть, которая осуществляет регулирование напряжения и тока в зависимости от параметров установленных микроконтроллером, а также обеспечивает компенсацию падения напряжения на токоизмерительном резисторе.

3. МИКРОКОНТРОЛЛЕР (МК) - обеспечивает управление всей этой системой, сбор данных о текущих значениях - напряжении на выходе блока, потребляемый ток нагрузкой. Индикация напряжения, тока и текущем состоянии блока, установка конфигурации, индикация превышения тока нагрузки сверх установленных значений. Запоминание последних установленных параметров.

4. УПРАВЛЕНИЕ И ИНДИКАЦИЯ - то что мы видим и то чем мы управляем. Управление производится  всего двумя органами управления, это энкодер с кнопкой, и просто кнопка.

 

Микроконтроллер  

 

   Проблемы выбора микроконтроллера передо мной не стояла, исходя из поставленной задачи выбор пал на микроконтроллер фирмы Atmel  AVR Mega8, по той простой причине - что в этой микросхеме есть все, что душе угодно. Немаловажным фактором послужило и то, что корпус этого МК имеет небольшое число выводов.  

Концепция новых скоростных микроконтроллеров была разработана группой разработчиков исследовательского центра ATMEL в Норвегии, инициалы которых затем сформировали марку AVR. Первые микроконтроллеры AVR AT90S1200 появились в середине 1997 г.и быстро снискали расположение потребителей.

AVR-архитектура, на основе которой построены микроконтроллеры семейства AT90S, объединяет мощный гарвардский RISC-процессор с раздельным доступом к памяти программ и данных, 32 регистра общего назначения, каждый из которых может работать как регистр- аккумулятор, и развитую систему команд фиксированной 16-бит длины. Большинство команд выполняются за один машинный такт с одновременным исполнением текущей и выборкой следующей команды, что обеспечивает производительность до 1 MIPS на каждый МГц тактовой частоты.

32 регистра общего назначения образуют регистровый файл быстрого доступа, где каждый регистр напрямую связан с АЛУ. За один такт из регистрового файла выбираются два операнда, выполняется операция, и результат возвращается в регистровый файл. АЛУ поддерживает арифметические и логические операции с регистрами, между регистром и константой или непосредственно с регистром.

Регистровый файл также доступен как часть памяти данных. 6 из 32-х регистров могут использоваться как три 16-разрядных регистра-указателя для косвенной адресации. Старшие микроконтроллеры семейства AVR имеют в составе АЛУ аппаратный умножитель.

Базовый набор команд AVR содержит 120 инструкций. Инструкции битовых операций включают инструкции установки, очистки и тестирования битов.

Все микроконтроллеры AVR имеют встроенную FLASH ROM с возможностью внутрисхемного программирования через последовательный 4-проводной интерфейс.

Периферия МК AVR включает: таймеры-счётчики, широтно-импульсные модуляторы, поддержку внешних прерываний, аналоговые компараторы, 10-разрядный 8-канальный АЦП, параллельные порты (от 3 до 48 линий ввода и вывода), интерфейсы UART и SPI, сторожевой таймер и устройство сброса по включению питания. Все эти качества превращают AVR-микроконтроллеры в мощный инструмент для построения современных, высокопроизводительных и экономичных контроллеров различного назначения.

Отличительные особенности:          

●8-разрядный высокопроизводительный AVR микроконтроллер с малым потреблением 

●Прогрессивная RISC архитектура

●130 высокопроизводительных команд, большинство команд выполняется за один тактовый цикл  

●32 8-разрядных рабочих регистра общего назначения  

●Полностью статическая работа  

●Производительность приближается к 16 MIPS (при тактовой частоте 16 МГц)  

●Встроенный 2-цикловый перемножитель  

●Энергонезависимая память программ и данных  

●4 -256 Кбайт внутрисистемно программируемой Flash памяти  

●Обеспечивает 1000 циклов стирания/записи  

●Дополнительный сектор загрузочных кодов с независимыми битами блокировки  

●Внутрисистемное программирование встроенной программой загрузки  

●Обеспечен режим одновременного чтения/записи (Read-While-Write)  

●512 байт EEPROM  

●Обеспечивает 100000 циклов стирания/записи  

●1 Кбайт встроенной SRAM  

●Программируемая блокировка, обеспечивающая защиту программных средств пользователя  

  • возможность программирования непосредственно в системе через последовательные интерфейсы SPI и JTAG;
  • разнообразные способы синхронизации: встроенный RС-генератор с внутренней или внешней времязадающей RС-цепочкой, встроенный генератор с внешним кварцевым или пьезокерамическим резонатором, внешний сигнал синхронизации;
  • двухканальный генератор ШИМ - сигнала регулируемой разрядности (один из режимов работы 16-битных таймеров/счетчиков). Разрешение формируемого сигнала может составлять от 1 до12 бит;
  • многоканальный 10-битный АЦП последовательного приближения, имеющий как несимметричные, так и дифференциальные входы;
  • последовательный синхронный интерфейс SPI.
  • очень низкая стоимость.

Тем не менее, выбор микроконтроллера (и не только его) для своей микропроцессорной системы является очень ответственным делом. Оно может быть некритично для какой ни будь радиолюбительской установки - плюс минус сто рублей не деньги, но если вам придется работать на «дядю» который все считает, и при предоставлении готового изделия вы выйдите из бюджета, то вы можете сильно потерять в деньгах. Быстродействие микроконтроллера , каким бы он шустрым не был, часто сводится на нет медленной периферией, индикаторы, дисплеи, датчики, исполнительные механизмы, сервоприводы -   требуют для своей работы определенные протоколы обмена информацией, которые, обычно, очень медленные(по сравнению с тактовой частотой МК). И в подпрограммы обслуживания этих устройств вводятся различные задержки, притормаживающие(и весьма) работу всей системы. Поэтому быстрые МК нужны в основном, если для  работы всей системы требуется производить много вычислений, по результатам которых происходит то или иное действие

Регулятор

   Схема стабилизатора напряжения и тока представлена на рис. 2, там же находится и микроконтроллер U3. к регулятору предъявляются особые требования, он должен обеспечивать регулировку напряжения и тока в широких пределах, обеспечивать защиту питаемого устройства.  

схема

 

  Рис. 2

Схемотехника не отличается излишествами, но показала в процессе эксплуатации высокую надежность.  Работу регулятора напряжения рассмотрим на примере рис.3.

Рис.3

Рис.3

Силовой элемент регулятора выполнен на p-канальном полевом транзисторе Q1, трбования предъявляемые к этому транзистору простые - максимальное напряжение должно быть хотя бы в полтора раза выше напряжения питания, максимальный ток минимум в два раза больше максимального тока нагрузки и сопротивление открытого канала(чем меньше, тем лучше). сопротивление открытого канала легко уменьшить соединив параллельно два, три транзистора без всяких выравнивающих резисторов и  индуктивностей - это не импульсный регулятор.

Регулировка напряжения происходит   изменением напряжения на затворе транзистора Q1 за счет приоткрывания транзистора Q2. когда  Q2 закрыт напряжение на затворе Q1 равно напряжению питания и транзистор закрыт. Усилитель ошибки, выполненный на ОУ U1.А сравнивает напряжение на выходе стабилизатора  посредством делителя напряжения R4, R1, коэффициент деления которого равен отношению выходного напряжения к опорному, в данном случае 1:10, т.е. при выходном напряжении 50 В опорное должно быть 50 : 10 = 5 В. Разница между опорным напряжением и напряжением полученному с делителя усиливается усилителем и подается на затвор Q2. Таким образом, компенсируется повышение напряжение на выходе стабилизатора, пока напряжения на входах 2 и 3 не уравняются. Изменяя величину опорного напряжения от 0 до 5 В можно менять напряжение на выходе стабилизатора. Резисторы R5,  R8 и конденсатор С2 образуют интегратор, преобразующий импульсы ШИМ в постоянное напряжение. В схеме на рис. 2 присутствует отрицательное напряжение -2.5 В , оно необходимо для того, чтобы обеспечить нулевое напряжение на выходе стабилизатора. Особенности схемотехники операционных усилителей состоит в том, что невозможно получить нулевое напряжение на выходе ОУ если отрицательный вывод питания подключен к земле, и соответственно на выходе стабилизатора появляется напряжение достигающее 500 - 700 мВ.

            Стабилизатор тока выполнен на ОУ U2.А ,U2.В, напряжение с датчика тока R5 усиливается  ОУ U2.В с коэффициентом усиления равным 10, с выхода этого усилителя напряжение приходит на вход АЦП1 микроконтроллера и на вход усилителя ошибки U2.А, на второй вход которого подается сигнал ШИМ тока с микроконтроллера, в случае превышения напряжения с датчика тока напряжения с ШИМ ОУ U2.А переводит стабилизатор напряжения в режим стабилизатора тока уменьшая через диод D1 напряжение на затворе Q2, уменьшая тем самым напряжение на выходе блока питания до тех пор пока потребляемый нагрузкой ток не сравняется с током установленным микроконтроллером.

При таком способе получения информации о потребляемом токе возникает одна проблема - несоответствие индицируемым микроконтроллером данных о выходном напряжении. Это можно решить, введя в программу обслуживания коррекцию в виде вычитания из значения фактического значения выходного напряжения данных о потребляемом на данный момент времени тока. Как показано на примере:

.

.

 

 I_real2 = I_real / 10

 U_real_lcd = U_real - I_real2

.

.

 

где  I_real измеренное значение тока, U_real измеренное значение напряжения, а U_real_lcd  выводится на дисплей.

 Но у меня остался незадействованным один операционный усилитель U1.В, который я решил использовать в   устройстве под названием  - компенсатор падения напряжения на датчике тока. На примере, показанном на рис. 4, покажу как работает это устройство. ОУ U1.В представляет собой инвертирующий усилитель с отрицательной обратной связью и коэффициентом усиления равным 1, работающий в качестве нижнего звена делителя напряжения и автоматически вычитает из выходного напряжения значение падения напряжения на токоизмерительном резисторе.

Рис. 4

По другому говоря, ОУ U1.В представляет собой «виртуальную» землю для делителя напряжения, проводимость  которой изменяется в зависимости от напряжения на резисторе R5. На рисунке (картинка из симулятора PROTEUS) видно, что напряжение на средней точке делителя напряжения равно опорному напряжению.

На следующем рисунке показан узел управления и индикации. В качестве дисплея, я использовал LCD индикатор   фирмы Santai, больших размеров - ширина индикатора 150 мм, 20 символов на 2 строки. Просто мне хотелось сделать устройство красивым и удобным.

Основным органом управления служит валкодер  (энкодер), с кнопкой на валу на нажатие.

Дополнительная кнопка служит для ускорения энкодера, а также для перехода в сервисный режим, если удерживать её при включении питания в течении 3 сек.

рис. 5 схема управления и индикации.

Первичный источник питания, представляет собой импульсный двухтактный преобразователь напряжения с управлением через оптрон.  на оптрон  подается напряжение взятое с регулятора на  рис.2  с транзистора Q1 плюс 3 вольта, таким образом напряжение на выходе источника питания всегда примерно на 5 вольт выше выходного напряжения стабилизатора - увеличивается напряжение на выходе, автоматически увеличивается напряжение  на выходе ИБП, и наоборот. Как происходит регулирование видно на приведенном рисунке рис.7. (R1 = 100...220 om).

 

Рис 6

 Рис.7

 

 

Схема   первичного источника типовая, поэтому ограничусь кратким описанием. На микросхеме TL494 собран генератор, ШИМ регулятор, усилители ошибки, схема управления «мертвым временем» , схема мягкого пуска, драйвер управления выходными транзисторами. На микросхеме DA2 IR2113 собран драйвер управления верхним и нижним плечами полумостового преобразователя, верхний драйвер запитывается по бустрепной схеме. Q1 и Q2 - транзисторы полумостового инвертора, трансформатор - он и в Африке трансформатор, я использовал готовый, от блока питания большого LCD телевизора, использовав обе половинки обмотки как одну (в два раза увеличив напряжение). DA3 и маленький трансформатор TV3, с обвязкой взяты  там же, используется как источник напряжения 20 В для питания ИБП. Далее выпрямитель и конденсаторы фильтра. Оптрон 1 используется как защитный, от превышения напряжения (на холостом ходу, без оптронов блок выдает 63 В), назначение второго оптрона, я описал выше.

Возможно применение и обычного трансформатора для  питания, вторичную обмотку нужно разделить на секции по 9 вольт, и подключать с помощью реле соответствующие секции. Если не делить на секции, а подавать все напряжение на вход стабилизатора - то не хватит никаких радиаторов (зимой можно экономить на отоплении), рассеиваемая мощность может достигать 250 Вт. В программе микроконтроллера предусмотрена возможность разбиения полного входного напряжения на 6 секций (подпрограмма diapason), информация в двоичном коде выводится на выводы микроконтроллера В3,В4,В5, которые можно дешифровать любым дешифратором и управлять им соответствующим реле.

 

управляющая программа

 

 

Этап 1. «Техническое задание». Задача этапа - определение и выработка исходных данных, необходимых для создания программы:

1. измерение выходных значений;

2. установка значений U и  I;

3. запоминание последних значений при выключении питания;

4. максимально удобный интерфейс;

5. возможность удобного  ремонта;

6. что ни будь еще по ходу дела.

 

Этап 2. собственно программирование.

Я не являюсь сторонником какого либо языка программирования, они все в той или иной степени хороши, как говорится «на вкус и цвет товарищей нет». Каждый волен выбирать то, что ему хорошо, правда, без знания ассемблера оптимизированную программу написать затруднительно.  Критические места программы, в особенности обработка прерываний, драйверы для периферии - лучше (на мой взгляд) писать на ассемблере.

            Для этого проекта я писал программу на языке BASIC, и только подпрограммы обслуживания прерывания для энкодера были написаны на Ассемблере. Скомпилированный текст получился довольно компактным, критический просмотр в дизассемблере не выявил «страшных» огрехов.

Программу писал в программной среде BASCOM-AVR, к тому же там есть довольно неплохой   симулятор (на нем довольно сносно можно симулировать подпрограммы).

Не нужно беспокоится о том, что Bascom дает некомпактный код. Размер кода полностью соответствует классу компиляторов с языков высокого уровня. Уступает только CodeVision на малых проектах, а с другими компиляторами Си успешно конкурирует. Bascom особенно хорош в больших проектах, когда мелочная оптимизация уже не приносит заметного выигрыша, а важнее структурированность исходного текста.

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

- похожие программы оформлять в подпрограммы. Различия формировать ветвлением и дроблением участков;

 

- применять простые конструкции, минимум вложенности (от вложенности код становится еще больше). Лучше больше ветвится по тексту программы, чем применять вложенные проверки условий. Чем длиннее текст и применяются более мелкие операторы, тем короче код и он быстрее работает;

- программы прерывания писать на ассемблере, осуществляя минимум действий. Запрещать автоматически сохранять регистры;

- применять больше переменных (на каждый чих свою, обычно ресурсов хватает), чтобы было меньше "заморочек", чтобы не вспоминать лишний раз о возможности одновременного использования;

- применять конструкцию On ... Goto с таблицей переходов даже избыточной, а не любимую многими Select Case;

- применять табличные методы установки и выбора параметров  Lookup(offset,Table);

- программа должна быть построена таким образом, чтобы обращение к каждому элементу периферии встречалось в программе только один раз;

- также как и задание числовых данных нужно делать один раз.

Не рекомендуется применять экзотические методы передачи параметров (через стек).

Просто советы:

- не вставлять Return внутрь закрытых конструкций (типа if.. do.. for..) , а применять переход Goto на выходную метку;

- не располагать переменные (Single, массивы и строковые) на границе страниц памяти. Поступать так - скомпилировать и посмотреть. При необходимости определить распределение памяти для Single и String самостоятельно вручную

 или набить промежутки на границе страниц пустыми неиспользуемыми переменными;

- не забывать один оператор  - одно действие (это не Си).

            Совет начинающим программистам о том, как написать программу, работающую в режиме реального времени, чтобы измеряла, управляла, да еще и что-то показывала одновременно, в этом ничего сложного нет. Есть несколько способов как это сделать. Можно использовать прерывания от внутренних таймеров,   внешних прерываний, но самый простой (хотя и не самый оптимальный) и применимый для многих приложений - это использовать цикл из подпрограмм. Например:

 

Do

Call U_i_metr                                                          'измерение тока и напряж

Call Diapason                                                           'вычисление номера реле

Call Akseler                                                             'подпрограмма коэф ускорения енкод

Call Knob                                                                 'обработка кнопки энкодера

Call U_i_set                                                              'вывод ШИМ на регулятор

Call Isobra                                                               ' вывод изображения

Loop

 End

 

Каждая подпрограмма может вызывать другие подпрограммы.

Главный недостаток этого метода заключается в том, что потратив  кучу времени на выполнение этого цикла,  мы просто пропустим момент нажатия кнопки. Другими словами, кнопка будет нажата и уже отпущена к тому моменту, как программа дойдет до процедуры проверки PinС.2, да при этом если мы хотим использовать энкодер - мы просто не дождемся результатов от его работы. Очевидно, что нам нужен другой способ проверить нажатую кнопку, независимо от хода выполнения других процедур.

В этом случае нам поможет прерывание. Прерывания изменяют нормальный ход выполнения программы и заставляют МК реагировать на внешние события так же, как и на внутренние. Нам достаточно немного изменить код, добавив в начале программы строку, разрешающую

Config Int1 = Falling                                           'INT1 - по заднему фронту

Config Int0 = Low Level                                     'INT0 - по низкому уовню

 

и конфигурирующую  прерывания и написать подпрограмму обработки прерываний, которая бы устанавливала или изменяла определенные значения переменных.

 

Int0_enable:

  $asm

    Push R31                                                'сохраним регистры

    In R31 , Sreg

    Push R31

    Ldi R31 , &HFF                                          'Yesyes:

    Sts { edat1 } , R31                                     'поставить признак "НОВЫЕ ДАННЫЕ кнопки"

    Pop R31                                                 'восстановим регистры

    Out Sreg , R31

    Pop R31

  $end Asm

Gifr = 64                                                   'сотрем дребезговое прерыв 0 из  рг Gifr

Return

 

Например, эта подпрограмма, написанная на Ассемблере, при наступлении события присваивает значение переменной edat1 значение FF в шестнадцатеричном виде, другая подпрограмма которая использует эту переменную, будет «знать» что произошло нажатие на кнопку подключенную к порту D2, причем чем быстрее было обработано прерывание - тем меньшее влияние оно окажет на исполняемую программу, поэтому еще раз повторюсь, что подобные подпрограммы должны писаться на Ассемблере, и желательно не производить никаких вычислений, только присваивать какие либо значения переменным, так сказать просто «поднять флаг», подпрограмма основного цикла или «тела» программы сама разберется,  что с этими данными делать (с вашей помощью конечно). И никогда не используйте прерывание в прерывании, они просто не будут выполнены, так как прерывания в микроконтроллере AVR, во время обработки прерывания - запрещены. В этой конкретной подпрограмме не используется никаких программных способов подавления дребезга, в этом уже нет необходимости - событие уже произошло, а многократные воздействия на вход прерывания(AVR их запоминает), после завершения подпрограммы, удаляются записью в регистр Gifr единицы в соответствующий бит.

            Следующая подпрограмма обслуживает прерывание от энкодера. Алгоритм программы построен на особенности энкодера перекрывания фаз Замкнутого и разомкнутого состояний. Если настроить прерывание микроконтроллера на срабатывание по заднему фронту импульса, 

 

 

микроконтроллер, при наступлении события вызвавшего прерывание, перейдет к подпрограмме, которая, определит в каком положении находится вал энкодера в момент прерывания, просто проверив 0 или 1 на соответствующем выводе микроконтроллера Pind , 4 и подпрограмма установит соответствующие флаги, направление влево  rotdat=FF,  если вправо  rotdat=00, и установит флаг новые данные  энкодера  endat=FF, который сбросит подпрограмма обслуживания энкодера. В этой подпрограмме использована  процедура подавления дребезга контактов, которая представляет собой подпрограмму задержки, и проверки ложного срабатывания энкодера.

 

' направление влево  rotdat=FF,  если вправо  rotdat=00

' новые данные  энкодера  endat=FF

 

Int1_int:

$asm

    Push R31                                                   'сохраним регистры

    In R31 , Sreg

    Push R31

 '---------

    Ldi R31 , 30                                               'ПОСТОЯНАЯ ИНТЕГРИРОВАНИЯ

Delayy:                                                         'подпрограмма подавления дребезга

    Sbic Pind , 3

    Rjmp delayy1                                            'ЕСЛИ НА НОЖКЕ "1"

    Dec R31                                                     'ПОКА НЕ ОБНУЛИЛСЯ СЧЕТЧИК ЖДЕМ

    Brne delayy                                               'УСТАНОВЛЕНИЯ НИЗКОГО УРОВНЯ

    Rjmp Int0_2

'-----

Delayy1:

    Inc R31                                                     'УВЕЛИЧИВАЕМ СЧЕТЧИК

    Cpi R31 , 60                                             'ЕСЛИ   "1" УСТАНОВЛЕНА СЛИШКОМ ДОЛГО

    Brne konec                                              'НА ВЫХОД

    Rjmp delayy                                            'конец подпрограммы подавления дребезга

Int0_2:

'ОБРАБОТКА ИЗМЕНЕНИЯ УРОВНЯ

'---------

    Sbis Pind , 4                                           'ОПРЕДЕЛИМ НАПРАВЛЕНИЕ ВРАЩЕНИЯ

    Rjmp Int0_3                                           ' если на  Pind , 4  = 0,  то вправо                                         

'---------

'ВРАЩЕНИЯ ВЛЕВО (FF)                      'флаг НАПРАВЛЕНИЕ ВРАЩЕНИЯ FF left

    Ldi R31 , &HFF

    Sts { rotdat } , R31

    Rjmp Int0_4

'---------

Int0_3:                                                     'флаг НАПРАВЛЕНИЕ ВРАЩЕНИЯ 00 riht

'ВРАЩЕНИЯ ВПРАВО (00) запишем в R31 00 и присвоим переменной rotdat содержимое ‘R31

    Ldi R31 , &H00

    Sts { rotdat } , R31

Int0_4:

    Ldi R31 , &HFF

    Sts { Endat } , R31                          'поставить признак "НОВЫЕ ДАННЫЕ ЕНКОДЕРА"

'---------

Konec:

    Pop R31                                                 'восстановим регистры

    Out Sreg , R31

    Pop R31

$end Asm

'Gifr = 128                                                  'сотрем дребезговое прерыв 1 из  рг Gifr

Return

 

Вообще в подпрограммах прерывания я не люблю использовать задержки, но тут не было выбора - энкодер без подавления дребезга работал нестабильно. Можно использовать специальные микросхемы вроде этой.

 

 

 

Подпрограмма обслуживания энкодера:

           

Sub Rotary()

Local X As Word

      If Endat = 0 Then                                     ' Endat =0 на выход

      Goto Ennd

      End If

    If Rotdat <> 0 Then                                     'проверка направления

         X = Limite - Itog_encod1

         If X < 30 Then                                     'проверка конца диапазона

         Koef = 1                                           '

         End If

           If Itog_encod1 => Limite Then                    ' проверка условия

            Goto Ennd1                                      'макс значения енкодера

            Else                                            'для  Uвх = 50В  - 1023

            Itog_encod1 = Itog_encod1 + Koef                'вправо то   +  Koef

           End If                              'koef - ускоритеь енкодера        '2 или 20

    Else

          If Itog_encod1 < 30 Then                          'проверка конца диапазона

          Koef = 1                                          '

          End If

         If Itog_encod1 = 0 Then                            ' проверка условия

           Goto Ennd1                                       'мин значения енкодера

         Else

          Itog_encod1 = Itog_encod1 - Koef                  ' влево то   -  Koef

          End If

    End If

    Ennd1:

    Endat = 0

    Ennd:

End Sub

 

Подпрограмма обработки данных энкодера использует две, изменяемые подпрограммой прерывания от энкодера, переменные. Endat - то что появились новые данные, если 0 - то данные не изменились и можно смело выходить из подпрограммы, если FF - то начинаем работать.   Rotdat - направление вращения вала энкодера, если 0 то влево, и будем вычитать из переменной   Itog_encod1 переменную Koef  которая в свою очередь зависит от трех факторов - нажата ли кнопка С2 (проверяется подпрограммой Knob), находится ли переменная Itog_encod1 близко к крайним своим значениям. переменную Itog_encod1 в свою очередь используют подпрограммы U_i_set и Eewrite. Если Rotdat = FF значит будем прибавлять.

Насчет того сколько переменных использовать и как, тоже не стоит задумываться - канули в лету времена когда ресурсы микроконтроллеров были на вес золота (на самом деле дороже), объем оперативной памяти был настолько мал, что буквально приходилось извращаться ,используя очень ограниченное число переменных. Сейчас ресурсов хватает с лихвой, и поэтому назначайте каждой переменной свое имя, во - первых не запутаетесь, а во вторых легче программировать.

            Ну обработка обработкой, а мне нужно делать то ради чего я все задумал, то есть регулировать и смотреть что получилось.  для начала нужно измерить напряжение на выходе блока питания и потребляемый нагрузкой ток. Для этого в микроконтроллере есть многоканальный аналого-цифровой преобразователь последовательного приближения разрядностью 10 бит. В mege8 этих каналов 6 (для корпуса TQFP32 - 8 каналов). Опорное напряжение для АЦП устанавливается программно. Я использую опорное напряжение от питающего напряжения 5 в. Длительность одного цикла преобразования составляет 13 тактов, и максимальная точность преобразования зависит от тактовой частоты АЦП в пределах 50 - 200 КГц, установив соответствующие биты регистра ADCSR.  BASCOM-AVR при установленном параметре Prescaler = Auto в строке конфигурации АЦП, автоматически подбирает коэффициент в зависимости от тактовой частоты микроконтроллера, чтобы  тактовая частота АЦП находилась в указанных пределах.

 

 $crystal = 8000000

 

Строка инициализации АЦП

Config Adc = Single , Prescaler = Auto , Reference = Avcc

 

Подпрограмма чтения данных из ацп.

 

Sub U_i_metr()

    U_real = Getadc(0)

    I_real = Getadc(1)

    Z_real = Getadc(4)

      'здес проверка превышения тока нагрузки и вкл светодиода

       If I_real => Iset_word Then

       Set Portc.3

       Porog = "Over"                                       'переменная для индикации

       Else

       Reset Portc.3

       Porog = "    "

       End If

End Sub

 

В этой подпрограмме происходит считывание аналоговых данных с портов С0, С1, С3 для передачи данных в подпрограмму индикации данных Izobra,  а также сравнение реальных данных на токоизмерительном резисторе и установленного значения и в случае превышения тока включить светодиод Portc.3, и установить переменную Porog = "Over"  для дисплея.                                    

Кстати переменная Z_real используется для вывода на дисплей напряжения стабилизации стабилитрона подключаемого к измерительным выводам на передней панели.       Вывод информации на символьный LCD дисплей в программе BASCOM-AVR, происходит при помощи библиотек (весьма эффективных), и поэтому очень просто. Нужно только вначале программы указать какой дисплей будет использоваться и к каким портам микроконтроллера будет  подключен.

Config Lcd = 20 * 2

Config Lcdpin = Pin , Db4 = Portb.6 , Db5 = Portb.7 , Db6 = Portd.5 , Db7 = Portd.6 , E = Portd.7 , Rs = Portb.0

.

   Cls

   Cursor Off

   Lcd "     »oє ѕёїaЅёЗ     "                              'эти кракозяблы - по русски

    Locate 2 , 1                                                   'означают "блок питания"

   Lcd "     VER. 2.07      "

   Wait 3

   Cls

Так как эта программа не умеет выводить текст на дисплей на русском языке, я использовал специальную маленькую программку rus-lcd 20*2

Она подготавливает данные для Ассемблера, BASCOMa и подходит для AVR Studio. Строка текста правда выглядит совсем нечитабельно, но на дисплее, так как нужно.

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

.

.

Call Raschet(u_real_lcd , U_real , Perem1)

Call Raschet(i_real_lcd , I_real , Perem2)

Call Raschet(i_set_lcd , Iset_word , Perem2)

Call Raschet(z_real_lcd , Z_real , Perem1)

.

.

подпрограммой Raschet

 

  Sub Raschet(i As Single , P As Word , S As Single)       'подпрограмма приведения

  I = P * S                                                 ' данных к удобовоспроизводимому

  End Sub                                                   'виду

 

Выводимые на дисплей данные зависят от того, в каком режиме находится блок питания,

На данном примере программа находится в режиме установки максимального тока, показывает текущее значение напряжения и данные по максимальному значению тока

.

.

.

  If Knopka = 2 Then                                                                             'установка тока

     Locate 1 , 1

     Lcd " U  - " ; Fusing(u_real_lcd , "##.#") ; Vprobel ; "   "          ' U нормал

     Locate 2 , 1

     Lcd "Iset- " ; Fusing(i_set_lcd , "#.##") ; "  A  SET   "                ' Iset

  End If

.

 

Так это выглядит на дисплее.

            После установки всех значений (устанавливаются одной ручкой - повернул нажал, нажал повернул, на все уходит несколько секунд) все установленные данные запоминаются во внутренней EEPROM . с помощью подпрограммы Eewrite, она последовательно записывает старший младший байты слова, разделяя его с помощью оператора Eedata_h = High(eetmp) и Eedata_l = Low(eetmp)  и записываем в память по соответствующем адресам .                                   

 

Sub Eewrite()

 Eedata_h = High(eetmp)

 Eedata_l = Low(eetmp)                                      ' раскалываем слово на два байта

 Writeeeprom Eedata_h , Eeadr                               'и пишем в еепром

 Incr Eeadr                                                 ''

 Writeeeprom Eedata_l , Eeadr

End Sub

 

Соответственно подпрограмма чтения из ЕЕПРОМ, считанные побайтно данные, потом соединяются в одно слово, умножая старший байт на FF  (сдвигаем на 8 разрядов) и складываем с младшим байтом.

 

Sub Eeread()

 Readeeprom Eedata_h , Eeadr                                ' чтение старшего байта

 Incr Eeadr                                                 ' изменяем адресс

 Readeeprom Eedata_l , Eeadr                                ' чтение младшего байта

  Eetmp = Eedata_h * 256                                    ' из 2 х байт делаем слово

  Eetmp = Eetmp + Eedata_l                                  ''

 

Здесь переменной  Eetmp присваивается значение 1023 (dec) , потому что в чистой памяти это значение будет равно 65535 (dec) и будет больше значений, которыми оперирует  программа.

   If Eetmp => 1023 Then                                    'инициализ при чистой еепром

   Eetmp = 1023                                             ''

   End If

End Sub

 

Запомненные данные считываются из EEPROM всякий раз при включении питания. После считывания каждого слова увеличиваем адрес и читаем следующее слово. До заполнения всех переменных.

 

Call Eeread()                                              'здесь вызов процедур чтения из памяти

 Uset_word = Eetmp                                          'последнего состояние  при выключении

 Pwm1b = Uset_word                                          'питания  и данных после серв режима

 Incr Eeadr

 Call Eeread()

 Iset_word = Eetmp

 Pwm1a = Iset_word

 Incr Eeadr

 Call Eeread()

 Pulstrans = Eetmp

 Incr Eeadr

 Call Eeread()

 Usetmax = Eetmp

 Incr Eeadr

 Call Eeread()

 Isetmax = Eetmp

 

Подпрограмма Diapason просто сравнивает текущее значение напряжения со значением в каждом диапазоне и устанавливает на выходах МК - B3, B4, B5 соответствующее значение в двоичном коде. В режиме работы с импульсным блоком питания не участвует в работе.

Строка конфигурации таймера для работы режиме  ШИМ, установка разрядности ШИМ  и коэффициент деления предварительного делителя.

 

Config Timer1 = Pwm , Pwm = 10 , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down , Prescale = 1

 

            Подпрограмма установки значений для ШИМ:

 

Sub U_i_set()

     If Knopka = 1 Then

     Limite = Usetmax                                       'предельное значние

     Itog_encod1 = Uset_word                                'напряжения

      Call Rotary                                           'вызов энкодера

     Uset_word = Itog_encod1

     Pwm1b = Uset_word                                      'данные для ШИМ

     End If

     If Knopka = 2 Then

     Itog_encod1 = Iset_word

     Limite = Isetmax                                       'предельное значение тока

      Call Rotary                                           'вызов энкодера

     Iset_word = Itog_encod1

     Pwm1a = Iset_word                                      'данные для ШИМ

     End If

End Sub

 

В зависимости от режима работы подпрограмма вызывает подпрограмму Rotary и модифицирует новые данные для установки новых значений таймера и соответственно новых значений на выходах Pwm1a и Pwm1b.

 

Подпрограмма Knob изменяет режимы работы блока питания. Разрешает или запрещает прерывание для энкодера, если прерывание Int1 запрещено - то энкодер не оказывает никакого влияния на работу блока питания и изменение каких либо параметров не производится. Первое нажатие на кнопку энкодера изменяет значение переменной Knopka на единицу, и в зависимости от значения этой переменной можно изменять напряжение или входной ток, если значение переменной Knopka достигнет 3 , подпрограмма вызывает подпрограмму Eewrite и запоминает обновленные значения переменных Uset_word ,  Iset_word. В конце подпрограммы запрещается прерывание энкодера и главная программа переходит в нормальный режим работы.                                 

 

Sub Knob()

    If Edat1 <> 0 Then                                      'проверяем данные прерыв

     Knopka = Knopka + 1                                    ' кнопки измняем значения

     Enable Int1                                            'разр прерыв енкодера

     Else                                                   'если кнопка не нажималась

     Goto Endknob                                           'на выход

    End If

      If Knopka => 3 Then

       Eeadr = 400                                          'здесь вызов процедур

       Eetmp = Uset_word                                    ' записи данных

       Call Eewrite()

       Eetmp = Iset_word

       Incr Eeadr

       Call Eewrite()

 

       Knopka = 0                                           'обнуляем данные кнопка

       Disable Int1                                         'и запрещ прерыване енкодера

      End If

 

  Endknob:

  Edat1 = 0

End Sub

 

На этом завершу краткое описание программы, полный текст которой дан в конце статьи. Сейчас поговорим о том, как перенести написанную программу в микроконтроллер. После того, как вы сохранили проект, нажмите Program->Compile (F7). BASCOM проверит синтаксис, и, если не найдет ни одной серьезной  ошибки, скомпилирует программу и скажет, сколько памяти она займет в МК указанного типа:

 

полученный файл с расширением .HEX можно записать в микроконтроллер. Я программирую микроконтроллер непосредственно в схеме по интерфейсу  SPI. С помощью этого интерфейса можно программировать микроконтроллер непосредственно в схеме, что очень удобно не нужно тратить время на извлечение и установку микросхемы в программатор и обратно. Я использую USB программатор совместимый с AVR910 совместно с утилитой AVRprog, весь процесс программирования занимает несколько секунд.

 

Перед программирование микросхемы нужно правильно установить fuse bits. В сервисной документации информация об этом находится в различных частях довольно толстой книги, и поиск вызывает некоторое затруднение.

Это была одна из сложнейших проблем при работе с контроллерами AVR, особенно когда вы переходите с микроконтроллеров другого типа. Фузи - биты представляют собой низкоуровневое конфигурирование микроконтроллера. Устанавливая или снимая эти биты вы можете полностью изменить режим работы контроллера. Многие годы я был сторонником микроконтроллеров x51, там все было просто.  AVRы во многом отличаются и вы запросто можете вывести из строя ваш контроллер, если не разберётесь с программированием фузи-бит.

По  умолчанию (с завода)  микроконтроллер настроен на работу от внутреннего тактового генератора с тактовой частотой 1 Мгц, с разрешенным режимом программирования через SPI интерфейс, и включенным сторожевым таймером. Мне нужно отключить сторожевой таймер и перевести микроконтроллер на режим работы с тактовой частой 8 Мгц от внутреннего RC генератора. В программе AVRprog это делается просто, ставлю галочки напротив соответствующих значений и выставляю нужные мне функции.

Приложения:

Блок  Питания версия I :

Полный текст программы.. CM. Версия 2

Файлы пршивки.

Печатные платы для SMD компанент.:

 

Блок  Питания версия II :

Программа v2

Программа 2x16  v2

Все в одном флаконе v2

 

2-х канальный вариант от Barykin

Переделана цифровая часть (MEGA32), используется  два стабилизатора.

Программа

Схема

Обсуждение статьи

 

 

    Мамышев Р. (aka RAF65 )