воскресенье, 26 октября 2014 г.

Реле времени на полевом транзисторе.

Простое реле времени (или простое реле времени для начинающих 2) на биполярном транзисторе не сложно в изготовлении но на таком реле нельзя получить большие задержки. Длительность задержки определяет RC-цепь состоящая (для реле времени да биполярном транзисторе) из конденсатора, резистора в цепи базы и перехода база-эмиттер транзистора. Чем больше ёмкость конденсатора тем больше задержка. Чем больше суммарное сопротивление резистора в цепи базы и перехода база-эмиттер тем больше задержка. Увеличить сопротивление перехода база-эмиттер, для получения большой задержки, нельзя т.к. это неизменный параметр используемого транзистора. Сопротивление резистора в цепи базы нельзя увеличивать до бесконечности т.к. транзистору для открытия требуется ток, как минимум, в h21э меньший чем ток для необходимый для включения реле. Если например для включения реле требуется 100мА, h21э=100 то для открытия транзистора требуется ток базы Iб=1мА. Для открытия полевого транзистора с изолированным затвором большой ток не требуется, в данном случае можно даже пренебречь этим током и считать что ток для открытия такого транзистора не требуется. Полевой транзистор с изолированным затвором управляется напряжением поэтому можно использовать RC цепь с любым сопротивлением и следовательно делать любые задержки. Рассмотрим схему:
Рисунок 1 - Реле времени на полевом транзисторе

Эта схема похожа на схему с биполярным транзистором из предыдущей стати только здесь вместо биполярного транзистора n-MOSFET (n канальный полевой транзистор с изолированным затвором (и индуцированным каналом)) и добавлен резистор (R1) для разряда конденсатора C1. Резистор R3 не обязателен:
Рисунок 2 - Реле времени на полевом транзисторе без R3

Полевые транзисторы с изолированным затвором могут быть испорчены статическим электричеством поэтому с ними нужно обращаться аккуратно: стараться не касаться вывода затвора руками и заряженными предметами, по возможности заземлять вывод затвора и т.д. 

Процесс проверки транзистора и готового устройства показан на видео:
Т.к. на параметры RC цепи пренебрежимо мало влияют параметры транзистора то расчёт длительности задержки осуществить достаточно несложно. В данной схеме на длительность задержки по прежнему влияет длительность удерживания кнопки и чем меньше сопротивление резистора R2 тем слабее это влияние, но не стоит забывать о том что этот резистор нужен для ограничения тока в момент замыкания контактов кнопки, если его сопротивление сделать слишком низким или заменить перемычкой то при нажатии на кнопку может выйти из строя блок питания или сработать его защита от к.з. (если она есть), контакты кнопки могут приплавиться друг к другу, к тому же данный резистор ограничивает ток при установке резистором R1 минимального сопротивления. Резистор R2 также понижает напряжение (UCmax) до которого заряжается конденсатор C1, при нажатой кнопке SB1, что приводит к уменьшению длительности задержки. Если сопротивление резистора R2 низкое то на длительность задержки оно влияет незначительно. На длительность задержки влияет напряжение на затворе относительно истока при котором транзистор закрывается (далее напряжение закрытия). Для расчёта длительности задержки можно воспользоваться программой: 

R1=
R2=
C1=
Напряжение питания = В
Напряжение закрытия= В (3.8 для IRF620)

Задержка t=
UCmax=В

КАРТА БЛОГА (содержание)

суббота, 25 октября 2014 г.

Простое реле времени для начинающих 2.

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

Теперь конденсатор постоянно подключён к базе. После нажатия на кнопку SB1 конденсатор C1 начнёт заряжаться через резистор R1, транзистор VT1 в первый момент времени после нажатия на кнопку будет закрыт, после того как конденсатор С1 зарядится, до некоторого напряжения, откроется транзистор VT1, после этого конденсатор будет продолжать заряжаться до тех пор пока кнопка не будет отпущена. Если сопротивление резистора R1 будет достаточно низким то это произойдёт достаточно быстро для того чтобы этого не было заметно и показалось что транзистор открывается и включает реле сразу после нажатия на кнопку. После отпускания кнопки конденсатор будет некоторое время (время задержки) разряжаться через R2 и базу VT1 удерживая транзистор VT1 в открытом состоянии, через обмотку реле K1 будет протекать ток и контакты K1.1 этого реле будут замкнуты в течении времени задержки. Время при котором контакты замкнуты = времени задержки + (время удерживания кнопки - время заряда конденсатора до открытия транзистора на столько чтобы контакты K1.1 замкнулись). Время задержки - это время в течении которого конденсатор разряжается до напряжения (для данной схемы примерно 0.68В) при котором происходит разъединение контактов K1.1. Т.к. сопротивление база-эмиттер изменяется при изменении напряжения то рассчитать точное время задержки очень непросто но можно попытаться (программа для расчёта времени заряда/разряда конденсатора на странице: RC-цепь.). Если Сопротивление резистора R1 будет достаточно высоким то можно регулировать длительность задержки изменением длительности удерживания кнопки (ещё один плюс данной схеме по сравнению с предыдущей). Время задержки в данной схеме примерно 25с но его можно увеличить увеличением ёмкости конденсатора C1.

КАРТА БЛОГА (содержание)

суббота, 18 октября 2014 г.

Простое реле времени для начинающих.

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

Мультиметром можно определить активное сопротивление обмотки реле:
Отношение напряжения питания к активному сопротивлению обмотки не должно быть больше максимального тока коллектора Iкmax используемого транзистора (для КТ315 Iкmax=100мА=0.1А). Мультиметром можно, также как и диод, проверить транзистор:

После проверки деталей можно собирать устройство по схеме:
Рисунок 1 - Реле времени
Принцип работы схемы прост:
Когда переключатель S1 находится в положении "заряд" (см. рисунок 1) конденсатор С1 заряжается через резистор R1 (сопротивление этого резистора не должно быть слишком низким). Если при заряженном конденсаторе C1 переключатель перевести в положение "вкл." (см. рисунок 1) то этот конденсатор будет разряжаться через резистор R2 и базу транзистора VT1. При разряде конденсатора контакты реле будут замкнуты до тех пор пока ток коллектора не станет достаточно низким для того чтобы произошло разъединение контактов.

КАРТА БЛОГА (содержание)

воскресенье, 12 октября 2014 г.

Ввод через usb.

Предыдущие статьи:
Включение светодиода через usb.
usb светофор.
Управление шаговыми двигателями через USB порт.
В этой статье рассмотрим пример передачи информации от микроконтроллера компьютеру через USB порт. Для передачи состояния кнопки можно использовать схему:
Рисунок 1 - Ввод через usb

Полный текст программы для микроконтроллера приведен в статье управление шаговыми двигателями через USB порт. Рассмотрим участок кода для передачи информации на компьютер:
if(rq->bRequest == CUSTOM_RQ_GET_STATUS){
            static uchar dataBuffer[1];     /* buffer must stay valid when usbFunctionSetup returns */
//отослать состояние 3го бита порта D

if(!(PIND & (1< {
dataBuffer[0] = 0;
}
else
{
dataBuffer[0] = 1;
}

usbMsgPtr = dataBuffer;         /* tell the driver which data to return */
            return 1;                       /* tell the driver to send 1 byte */
        }

Код может быть не понятен но нетрудно догадаться что передаваемый байт записывается в переменную usbMsgPtr. Из строки:
if(rq->bRequest == CUSTOM_RQ_GET_STATUS)
понятно что для передачи информации на ПК на микроконтроллер с этого ПК приходит запрос:
CUSTOM_RQ_GET_STATUS
Рассмотрим теперь код для ПК:

#include windows.h
#include stdio.h
#include stdlib.h
#include usb.h        /* this is libusb */
#include stdbool.h  //булева библиотека
#include GL/gl.h
#include GL/glext.h
#include GL/glu.h
#include "opendevice.h" /* common code moved to separate module */
#include "../firmware/requests.h"   /* custom request numbers */
#include "../firmware/usbconfig.h"  /* device's VID/PID and names */
#define USB_CFG_VENDOR_NAME     'e','l','e','c','t','e','.','b','l','o','g','s','p','o','t','.','c','o','m'
#define USB_CFG_VENDOR_NAME_LEN 19
#define USB_CFG_DEVICE_NAME     'm','y','u','s','b','d','e','v','i','c','e'
#define USB_CFG_DEVICE_NAME_LEN 11
#define NUMBER_TRANGLE     30
int i=0;
int j=0;

HDC hdc;
HGLRC hrc;

usb_dev_handle      *handle = NULL;
const unsigned char rawVid[2] = {USB_CFG_VENDOR_ID}, rawPid[2] = {USB_CFG_DEVICE_ID};
char                vendor[] = {USB_CFG_VENDOR_NAME, 0}, product[] = {USB_CFG_DEVICE_NAME, 0};
char                buffer[4];
int                  vid, pid;

// Enable OpenGL
void EnableOpenGL( HWND hWnd, HDC * hDC, HGLRC * hRC )
{
  PIXELFORMATDESCRIPTOR pfd;
  int iFormat;

  // get the device context (DC)
  *hDC = GetDC( hWnd );

  // set the pixel format for the DC
  ZeroMemory( &pfd, sizeof( pfd ) );
  pfd.nSize = sizeof( pfd );
  pfd.nVersion = 1;
  pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
  pfd.iPixelType = PFD_TYPE_RGBA;
  pfd.cColorBits = 24;
  pfd.cDepthBits = 16;
  pfd.iLayerType = PFD_MAIN_PLANE;
  iFormat = ChoosePixelFormat( *hDC, &pfd );
  SetPixelFormat( *hDC, iFormat, &pfd );

  // create and enable the render context (RC)
  *hRC = wglCreateContext( *hDC );
  wglMakeCurrent( *hDC, *hRC );
}

// Disable OpenGL
void DisableOpenGL( HWND hWnd, HDC hDC, HGLRC hRC )
{
  wglMakeCurrent( NULL, NULL );
  wglDeleteContext( hRC );
  ReleaseDC( hWnd, hDC );
}
/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
char szClassName[ ] = "WindowsApp";

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nFunsterStil)

{

BOOL bQuit = FALSE;
float coords_trangles[NUMBER_TRANGLE];
float dcoords_trangles[NUMBER_TRANGLE];
float angles_trangles[NUMBER_TRANGLE];
float dangles_trangles[NUMBER_TRANGLE];

for (i=0;iNUMBER_TRANGLE;i++)
{
coords_trangles[i]=0;
dcoords_trangles[i]=0;
angles_trangles[i]=0;
dangles_trangles[i]=0;
}

    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */
    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);
    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default color as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;
    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "Windows App",       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           800,                 /* The programs width */
           600,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

usb_init();

// compute VID/PID from usbconfig.h so that there is a central source of information
    vid = rawVid[1] * 256 + rawVid[0];
    pid = rawPid[1] * 256 + rawPid[0];

    if(usbOpenDevice(&handle, vid, vendor, pid, product, NULL, NULL, NULL) != 0){
MessageBox(hwnd, "Could not find USB device\n","error", 0);
        exit(1);
    }
else
{
MessageBox(hwnd, "Find USB device done!\n","Done!", 0);
}

    ShowWindow (hwnd, nFunsterStil);
EnableOpenGL( hwnd, &hdc, &hrc );

while (!bQuit)
{
if (PeekMessage(&messages, NULL, 0, 0, PM_REMOVE))
{
// handle or dispatch messages
if (messages.message == WM_QUIT)
            {
              bQuit = TRUE;
            }
else
            {
              TranslateMessage(&messages);
              DispatchMessage(&messages);
            }
}
else
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);

usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CUSTOM_RQ_GET_STATUS,0,0, buffer, sizeof(buffer), 5000);
if(buffer[0]==0)
{

SetWindowText(hwnd, "Button on");
}
else
{
SetWindowText(hwnd, "Button off");
}

for(i=0;iNUMBER_TRANGLE/3;i++)
{
if(buffer[0]==0)
{
coords_trangles[i*3]=0.0f;
coords_trangles[i*3+1]=0.0f;
coords_trangles[i*3+2]=0.0f;

dcoords_trangles[i*3]=((float)rand())/(100*(float) RAND_MAX)-((float)rand())/(100*(float) RAND_MAX);
dcoords_trangles[i*3+1]=((float)rand())/(100*(float) RAND_MAX)-((float)rand())/(100*(float) RAND_MAX);
dangles_trangles[i*3+2]=((float)rand())/((float) RAND_MAX)-((float)rand())/((float) RAND_MAX);
}

glPushMatrix();
glTranslatef(coords_trangles[i*3],coords_trangles[i*3+1],coords_trangles[i*3+2]);
glRotatef(angles_trangles[i*3+2], 0.0f, 0.0f, 1.0f);
glBegin(GL_TRIANGLES);
glColor3f( 1.0f, 0.0f, 0.0f ); glVertex2f( 0.0f, 0.20f );
glColor3f( 0.0f, 1.0f, 0.0f ); glVertex2f( 0.287f, -0.25f );
glColor3f( 0.0f, 0.0f, 1.0f ); glVertex2f( -0.287f, -0.25f );
glEnd();
glPopMatrix();

coords_trangles[i*3]+=dcoords_trangles[i*3];
coords_trangles[i*3+1]+=dcoords_trangles[i*3+1];
coords_trangles[i*3+2]+=dcoords_trangles[i*3+2];

angles_trangles[i*3+2]+=dangles_trangles[i*3+2];

dcoords_trangles[i*3]*=0.9965f;
dcoords_trangles[i*3+1]*=0.9965f;

}
SwapBuffers( hdc );
}
}

usb_close(handle);
DisableOpenGL( hwnd, hdc, hrc );
    return messages.wParam;
}

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                
    {
        case WM_DESTROY:
            PostQuitMessage (0);    
        break;
        default:                    
            return DefWindowProc (hwnd, message, wParam, lParam);
    }
    return 0;
}

Приём байта осуществляет функция:
usb_control_msg
Рассмотрим пример использования этой функции для передачи:
usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, CUSTOM_RQ_SET_STATUS, out_conditions[dt_count], 0, buffer, sizeof(buffer), 5000);
Четвёртым параметром является передаваемая информация, шестым-буфер для приёма информации, седьмым- размер этого буфера.
Для приёма информации нужно изменить второй и третий параметры:
usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CUSTOM_RQ_GET_STATUS,0,0, buffer, sizeof(buffer), 5000);
Для того чтобы использовать OpenGL пришлось внести изменения в Makefile.
строку:
USBLIBS = -L"c:/Program Files/LibUSB-Win32/lib/gcc" -lusb
заменить на (т.е. немного дописать):
USBLIBS = -L"c:/Program Files/LibUSB-Win32/lib/gcc" -lusb -lopengl32 -lglu32 -mwindows
и в папку
c:/Program Files/LibUSB-Win32/lib/gcc
добавить файлы:
libopengl32.a
libglu32.a
Также необходимо добавить заголовочные файлы:
#include GL/gl.h
#include GL/glext.h
#include GL/glu.h


И добавить эти заголовочные файлы в папку GL (в папке include (в папке MinGW)) если их там нет.
Скачать программу для микроконтроллера можно по ссылке:https://yadi.sk/d/EJJiYBuRbxEXB
Программу для ПК по ссылке:https://yadi.sk/d/ZDdoRYtObxEfe


КАРТА БЛОГА (содержание)

Подходящие микроконтроллеры ATmega8a-pu (можно заказать по ссылке).

воскресенье, 5 октября 2014 г.

Управление шаговыми двигателями через USB порт.

Реализация связи ПК с внешним устройством через USB порт сложнее чем такая же реализация через LPT порт (даже не смотря на наличие готовых библиотек (например v-usb и libusb используемых в данном случае как самые простые для начинающих) для написания программ) но использование USB в данном случае всё же предпочтительнее, в первую очередь это связано с распространённостью USB. Информации из предыдущих статей (включение светодиода через usbusb светофор) достаточно для реализации управления шаговыми двигателями через USB, рассмотрим схему:
Рисунок 1 - Управление шаговыми двигателями через USB порт

Последовательно с диодами VD1, VD2 очень желательно поставить предохранитель (например на 500мА) для защиты порта от короткого замыкания.
Шаговые двигатели управляются микроконтроллером через драйверы L293DD. Эти драйверы можно использовать только для маломощных шаговых двигателей каждая обмотка которых потребляет ток не более 600 мА. Для более мощных шаговых двигателей можно применить более мощные драйверы или самодельный драйвер на транзисторах. При управлении маломощными шаговыми двигателями также можно использовать простой способ управления:
Рисунок 2 - Простой способ управления шаговым двигателем

Можно получить большее количество шагов если использовать другой способРанее также упоминалось о том что программу управляющую драйвером лучше хранить в микроконтроллере а на компьютере лучше хранить программу задающую направление и скорость вращения ротора двигателя из за того что на компьютере труднее реализовать точные таймеры для управления двигателем, однако при использовании библиотеки v-usb возникают некоторые трудности с использованием прерываний (они должны иметь более низкий приоритет по сравнению с прерываниями участвующими в связи микроконтроллера с usb) но эти трудности, при желании, легко решаются. Если высокая скорость работы шаговых двигателей не требуется то можно реализовать основную логику работы двигателя (см. рисунок 2) на компьютере к тому же если микроконтроллеру оставить простую задачу вывода на порты принятой информации можно уменьшить объём памяти занимаемой программой в микроконтроллере (для ATmega8 это не критично т.к. реализация связи (при использовании v-usb) занимает не более 2 кб а в ATmega8 всего доступно 8кб) и сократить количество перезаписей программы в микроконтроллер т.к. основная логика всё же в компьютере то экспериментировать со способами управления проще. Программу для микроконтроллера также как и в предыдущий раз будем писать переделывая готовый пример поставляемый вместе с v-usb рассмотрим код:

Для вывода используются: весь порт C, весь порт B, биты 7,6,5 порта D. На всякий случай для ввода (для отправки информации на ПК) используется бит 3 порта D. Биты 0 и 1 порта D не трогаются т.к. они (судя по строкам DBG2(0x02, 0, 0); DBG1(0x01, 0, 0); DBG1(0x50, &rq->bRequest, 1);) используются для связи по UART для отладки. Итого получается можно управлять 3мя шаговыми двигателями, ещё останется 3 бита для управления чем нибудь ещё и один бит на всякий случай для обратной связи. Для управления всем достаточно 2 байт, первый бит первого байта соответствует выводу 28, второй бит первого байта выводу 27, далее аналогично до вывода 23 потом начиная с 19 до 12. Компилируется как обычно (см. пред. статьи) командой make. Пример команды для прошивки hex файла (расположенного в корне диска C) в микроконтроллер через LPT:
avrdude -c stk200 -P lpt1 -p m8 -U lfuse:w:0x9f:m -U hfuse:w:0xc9:m -U flash:w:main.hex
Ещё раз напомню что при прошивке важно правильно установить фюзы, это и является одной из причин реже перепрограммировать микроконтроллер для чего и вынесена основная логика на ПК.
 Код для ПК длинный поэтому приводится не будет но его можно скачать здесь. Напомню что для работы программы использующей libusb необходимо чтобы на компьютере (или другом устройстве) который связывается через USB с микроконтроллером был установлен драйвер фильтра.


  КАРТА БЛОГА (содержание)

Подходящие микроконтроллеры ATmega8a-pu (можно заказать по ссылке).