LED индикатор загруженности ЦП

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

Эта статья является логическим продолжением для применения кода, описанного в третьем видеоуроке о mikroPascal.

Исходя из того, что у меня нет лазерного принтера (ЛУТ отпадает), 2-хъядерный процессор и один светодиод стоит примерно 0.8 гривны, было решено делать 3 строки светодиодов по 10  штук в каждой. Две — под индикацию загрузки процессора, и оставшаяся под память или третье ядро (не сталкивался, но слышал).

Основная информация об устройстве:

  • Напряжение питания: 5 V
  • Потребляемый ток: < 50 mA 
  • Частота обновления данных: 0,5
  • Теперь можно перейти к схеме. 

    Как видите, она достаточно простая. Основа схемы — микроконтроллер ATmega8 (в корпусе DIP-28). Общее количество деталей — 40 шт., из них : светодиодов — 31, транзисторов — 5, остальное микроконтроллер и обвязка генератора.

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

    Таким способом мне удалось «уложиться» в два порта МК (PORTB — 6 пин, PORTC — 5 пин). Можно было конечно использовать сдвиговые регистры, но это повлекло бы за собой усложнение программы, а так же занятое место на плате. По-этому решил обойтись без них. 

    На схеме нет токоограничительных резисторов (применительно к светодиодам), потому что они работают в импульсном режиме. Я использовал светодиоды красного, желтого и белого цветов. Красный и желтый — ЦП, белый же для дополнительной строки.

    После всех манипуляций со схемой, взялся за разводку печатной платы. Вот тут то и был зарыт кирпич….Если схема была набросана минут за 5 то с платой пришлось возитсья около получаса. В итоге она получилась 2-хсторонней. 

    Как видите, разводка платы не самая простая. В этом виновата прежде всего динамическая индикация. Из-за нее пришлось часть проводников перенести на обратную сторону платы, а так же использовать большое количество переходных отверстий (в основном  для подключения светодиодов). Но, тем не менее эту плату возможно сделать и без ЛУТа. И последнее относительно платы — я использовал текстолит толщиной 0,5 мм, потому что другого с 2-хсторонним покрытием в наличии не оказалось.

    Рассмотрев аппаратную часть можно перейти к программной.

    Программу для МК я как всегда писал в среде mikroPascal for AVR (v 6.01). Так как в микропаскале нет библиотеки для микроконтроллера Atmega8, которая позволяет работать с USB, то выбор пал на UART. Но потому что последний видеоурок по mikroPascal был про прерывания, то решил и сюда их всунуть. И вот что в итоге получилось:

    program iCPU_t;

    uses AADL;

    var dat:array [0..2] of byte;
    rec,i,c,enbl:byte;
    rcit,rci,ti:integer;

    const pc: array [0..10] of byte = (31,30,28,24,16,0,30,28,24,16,0); //Объявляем константы
    const pb0: array [0..10] of byte = (0,254,254,254,254,254,253,253,253,253,253); //Они будут использоваться, как вы уже поняли из
    const pb1: array [0..10] of byte = (0,251,251,251,251,251,247,247,247,247,247); //из названий, для отправки заданных значений
    const pb2: array [0..10] of byte = (0,239,239,239,239,239,223,223,223,223,223); //в порт.

    procedure usart_c(); iv IVT_ADDR_USART__RXC; //Функция, которая вызывается по прерыванию UART
    begin //(если в буфере приема есть данные).
    rec:=UART_Read(); //
    if rec=47 then enbl:=1; //Тут мы ищем нужные нам символы, и сразу их
    if enbl=1 then inc(enbl) else //переводим.
    if enbl=2 then begin //
    case rec of //
    48: rec:=0;
    49: rec:=1;
    50: rec:=2;
    51: rec:=3;
    52: rec:=4;
    53: rec:=5;
    54: rec:=6;
    55: rec:=7;
    56: rec:=8;
    57: rec:=9;
    end;
    ti:=rec;
    inc(i);
    case i of
    1: rci:=ti*10;
    2: rci:=rci+(ti);
    end;
    if i>=2 then begin i:=0; enbl:=0; end;
    end;
    end;

    begin
    Uart1_init(9600); //Инициализация UART

    UCSRB.B7:=1; //Прерывание по приему данных UART
    SREG_I_bit:=1; //Разрешаем прерывания

    DDRC:=0xFF;
    DDRB:=0xFF;
    DDD7_bit:=1;

    PORTD7_bit:=0;

    for c:=0 to 2 do dat[c]:=0;

    While TRUE do begin
    rcit:=rci;
    if (rcit>30) and (rcit<40) then dat[2]:=rcit-30; //Присваиваем значение различным
    if (rcit>20) and (rcit<30) then dat[1]:=rcit-20; //элементам массива dat, в зависимости от того,
    if (rcit>10) and (rcit<20) then dat[0]:=rcit-10; //какому ядру они соответствуют.
    for c:=0 to 2 do begin
    case c of
    0: if dat[c]<=5 then begin //Дальше обеспечиваем индикацию.
    PORTC:=pc[dat[c]];
    PORTB:=pb0[dat[c]];
    delay_ms(1);
    end else begin
    PORTC:=pc[5];
    PORTB:=pb0[dat[c]-5];
    delay_ms(1);
    PORTC:=pc[dat[c]];
    PORTB:=pb0[dat[c]];
    delay_ms(1);
    end;
    1: if dat[c]<=5 then begin
    PORTC:=pc[dat[c]];
    PORTB:=pb1[dat[c]];
    delay_ms(1);
    end else begin
    PORTC:=pc[5];
    PORTB:=pb1[dat[c]-5];
    delay_ms(1);
    PORTC:=pc[dat[c]];
    PORTB:=pb1[dat[c]];
    delay_ms(1);
    end;
    2: if dat[c]<=5 then begin
    PORTC:=pc[dat[c]];
    PORTB:=pb2[dat[c]];
    delay_ms(1);
    end else begin
    PORTC:=pc[5];
    PORTB:=pb2[dat[c]-5];
    delay_ms(1);
    PORTC:=pc[dat[c]];
    PORTB:=pb2[dat[c]];
    delay_ms(1);
    end;
    end;
    end;
    end;
    end.

    В программе тоже ничего сложного нет. Константы в самом начале программы использовались для того, что бы не писать в порт «ручками» каждый раз. В процедуре , вызываемой по прерыванию, используется такой алгоритм:

  • Анализируем принятые данные, если они соответствуют «/», то разрешаем в следующий раз программе пройти дальше.
  • Расшифровываем из ANCII кодировки.
  • Рассчитываем и записываем в переменную
  • Далее, в основном цикле программы мы сначала сопоставляем, к какому ядру относятся полученные данные, а потом их присваиваем соответствующему элементу массива dat. 

    Вот и весь алгоритм программы.

    Если вас интересует, как данные отображаются, то все так же просто:

  • Смотрим, какая строка сейчас должна обновиться.
  • Выбираем из массива dat нужный элемент.
  • Если нужно зажечь пять или меньше светодиодов в строке, то просто оправляем значение в порт. Если же больше пяти (число n), то сначала зажигаем первые пять, а потом то что осталось (n-5). Все это крутится в цикле.
  • Из фузов нужно выставить лишь внешний кварц (8 MHz).

    В Khazama AVR Programmer это выглядит следующим образом:

    Вот и все! Но если у вас нет каких-то деталей, но есть их аналоги…. Светодиоды можно взять любые, подходящие по току и размерам. Микроконтроллер заменить нельзя. Только взять такой же но с любым другим индексом (например, вместо ATmega8 — ATmega8L и т.д.). Транзисторы так же можно взять любые маломощные структуры p-n-p. Я использовал КТ361Г (работают нормально, хотя ещё 1987 г. выпуска 🙂 ). Резисторы — с разбросом от указанного номинала до +/- 20 %.

    И напоследок, о программе для Windows, которая управляет индикацией. Она написана в Delphi xe5 и называется iCPU. 

    Рассчитана на 2 ядра. В настройках выбирается порт, к которому подключено устройство. Возможно использовать как встроенный COM порт (через преобразователь уровней на MAX232), так и через виртуальный COM порт, с использованием переходника на базе PL2303 и подобных. У меня в городе можно купить такой кабель для старых моделей NOKIA.

    Внутри платка, которая с успехом может использоваться как USB-COM переходник.

    Вот несколько фотографий готового устройства.

    Обновление от 20.07.2014:
    Доработал программу, теперь можно выводить на 3-ю строку загруженность памяти. А так же мелкие исправления.

    Обновление от 01.05.2015:

    Полностью переписан код как прошивки для МК, так и программы для Windows. Теперь есть отдельная версия для Windows x64.

    Для МК прошивка писалась в WinAVR (Cpp).

    ВНИМАНИЕ! Старая прошивка + новая версия программы НЕСОВМЕСТИМЫ, как и новая прошивка + старая версия программы.

    При прошивке фузы указывать те же, что и для старой версии, за исключением (выставлять как на скрине):

    .

    Из «нововведений»:

    • Возможность применять «выравнивание» (по левому краю, по центру и по правому краю).
    • Автоматическое отключение индикации через 10с (например, если комп погрузили «в сон»).
    • Теперь есть «тестовый» режим, в котором включаются все светодиоды (например, при первых включениях уст-ва, для выявления неполадок).
    • Если у вас в системе многоядерный процессор, то будут отображаться лишь первые 2 ядра (на уст-ве, в программе будет видно загрузку всех ядер). В противном случае, на уст-ве будут активными лишь 1-я и 3-я строки (1 ядро и память соответственно).

    Так же хочу заметить, что перед первым запуском программы, впишите номер ком порта, к которому подключено устройство, в файл «settings.ini». Он лежит в папке с exe-шником. Иначе, скорее всего, будете через каждые 0.5с получать окна с ошибками!

    В аппаратную часть устройства никакие правки не вносились.

    Немного фотографий:

    Обновление от 16.05.2015:

    Оптимизирован код. Добавлена возможность регулировки яркости (программный ШИМ на таймере T2). Внесены некоторые правки в программу для Windows (теперь, если COM порт выбран неверно (порта с таким номером в системе нет), не будет +100500 окон с ошибками).


    Список радиоэлементовОбозначение
    Тип
    Номинал
    Количество
    ПримечаниеМагазинМой блокнот

    U1
    МК AVR 8-битATmega81
    DIP-28D1-D30
    СветодиодHL-A-3528H308W-S1-1330
    Любые светодиоды 0805, подходящие по токуC1, C2
    Конденсатор27 пФ2
    0805X1
    Кварцевый резонатор8 МГц1
    НизкопрофильныйR2-R6
    Резистор1 кОм5
    0805R1, R7-R10
    Резистор30 кОм5
    0805Q1-Q4
    Транзистор2N37025
    Или КТ361Добавить все

    Скачать список элементов (PDF)

    Прикрепленные файлы:

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

    Ваш адрес email не будет опубликован.