Pull to refresh

Специалист-экспресс

Reading time10 min
Views134K
Вы помните свой первый компьютер? Я помню. Это был ZX совместимый ПК Спектр. Это было в 89 году. Не знаю точно, купил тогда его отец или поменял на что-то, но в доме появился ПК, и все началось. Именно на нем я написал свои первые программы и освоил Бейсик. Потом, когда я был в 7-9 классах, были еще ПК-01 Львов и Вектор 06Ц.

В 11 классе была попытка собрать Орион-128. После школы я уехал учиться в Томск, и все что успел сделать на тот момент — это просверлить отверстия и нарисовать краской дорожки. До травления платы так дело и не дошло. Уже в ВУЗе у меня появились PC совместимые ПК и старые компьютеры стали в общем то не нужными. Но затея собрать свой собственный ПК продолжала летать в воздухе почти 14 лет. Затею подогревал спор с отцом времен сборки Ориона. Видимо для мотивации меня на сборку, он говорил, что у меня не получится его собрать.

Осенью 2014 года, собирая очередную конструкцию на Arduino, задумался, а нельзя ли собрать на ней тот же Орион-128, ну или что попроще, Радио-86РК например. Обдумывая эту идею, решился воплотить давнюю школьную мечту — ПК, собранный своими силами. Сказано — будет сделано. Уверенности придали видеоролики Алексея Морозова по ремонту старых компьютеров и статьи на различных форумах посвященных ретро-ПК. На этих форумах сидели люди, которые постоянно собирали ретро ПК.

И я начал искать подходящую схему, без дефицитных деталей — в идеале, только мелкая логика, процессор и порт ввода-вывода. Сначала присматривался к ПК Ленинград, но не смог найти в городе Z80, а на заказ было долго ждать. В итоге остановился на схеме ПК Специалист-экспресс. Схема, я думаю, идеальна для новичка, так как содержит минимум деталей, и проста в сборке и наладке.

Очень качественная схема нашлась на сайте www.spetsialist-mx.ru, перерисовал ее человек с ником Fifan, за что ему огромное спасибо.

Следующий вопрос — делать печатную плату по ЛУТ технологии, или окунуться в прошлое, и собрать ее навесным монтажом, с использованием провода МГТФ, как это делало большинство любителей в 80е годы. Так как основная идея была именно собрать устройство, а не найти ему большое практическое применение, ввиду низкой производительности, то остановился на втором варианте.

Все детали для сборки обошлись примерно в 4000 тенге (около 1000 рублей). Все микросхемы решил сажать в панельки.



В первый день собрал тактовый генератор и счетчики. Пайка МГТФ-ом оказалась очень проста. Кто то пишет в интернете, что нужно чистить концы, я же просто откусывал провод кусачками, после чего наносил на кончик небольшое количество канифоли и грел паяльником с капелькой олова. Оплетка при этом сползала примерно на 0.5 мм, этого как раз достаточно, чтобы его припаять.

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

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



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

К тому моменту я познакомился с Алексеем Морозовым (VINXRU) и Андреем Анищеко. Алексей помог разобраться с выводами процессора. Забегая вперед скажу, что ребята очень много помогали в процессе постройки и отладки ПК. За это Вам большое спасибо!

На этот момент компьютер имел практически законченный вид.



Руки чесались скорее включить его. Поэтому, как только припаял стабилизаторы, решить проверить формирование -5 Вольт. Для этого установил в панельки микросхемы тактового генератора, счетчиков и инвертора на 155ЛА3. Включил питание, и вот они, честные -5.6 Вольт на ножке микропроцессора! Радости в тот день не было предела.



Только один момент заставил задуматься — стабилизатор 7805 (даже посаженный на радиатор) разогревался так, что к нему нельзя было прикоснуться. И это только 4 микросхемы в цепи питания.

Второй вариант стабилизации не отличался оригинальностью. Я лишь посадил параллельно 2 корпуса 7805 на больший радиатор. Греться они начали меньше, но все равно прикоснуться к ним через 10 минут работы было невозможно. Это обстоятельство заставило купить внешний блок питания на +5В (4А) и +12В (1А). После этого проблемы с питанием больше не возникали, кроме этого, наличие напряжения на 12В позволило отказаться от стабилизатора 7812.

После того, как вся схема была собрана, осталось записать в ПЗУ Загрузчик и Монитор. Это оказалось не так просто, как казалось ранее.

У меня не было программатора. Я начал было собрать ручной программатор, но еще раз взглянув на код Загрузчика и Монитора, решил оставить эту гиблую затею, хотя в 80е многие шли именно этим путем. Найти программатор столь древних ПЗУ в Алматы не удалось, а заказывать, и потерять месяц, не хотелось. Поэтому начал экспериментировать с Arduino. Сначала спаял шилд, и научился читать содержимое ПЗУ. Обе микросхемы не были пустыми. И судя по коду, это скорее всего были прошивки от АОНов. Возникла еще одна проблема — их надо стереть. В школьном возрасте отец постоянно говорил мне что нельзя чтобы на кристалл ПЗУ попадал свет, они от этого стираются. Я положил обе ПЗУ на несколько дней на Солнце. На выходных снова проверил содержимое — ни стерлось ни бита информации.

Сообщения на форумах, а так же Алексей Морозов говорили о двух способах стирания — это внутренняя колба от ДРЛ лампы с дросселем, выделяющая большое количество вредного озона, и УФ бактерицидная медицинская лампа. Стирание ДРЛ-кой занимает около 3х часов, УФ лампой минут 15. Недолго думая, купил ОУФК-09-1, тем более дома были простуженные, и кварцевание помещения было бы кстати. Обе микросхемки были очищены за 10 минут. Теперь надо как то научить шилд писать в ПЗУ. На это ушло еще немного времени. Изначально планировал сделать программку-программатор на Visual Basic с пересылкой данных в Ардуинку через COM порт, но походив с этой мыслью день-два, решил упростить схему, а именно подключить к Ардуинке SD карту, на которой бы размещалась необходимая прошивка, а на шилде было бы 2 кнопки — Чтение и Запись. Ход исполнения программы выводился в COM порт и отображался бы на ПК в мониторе порта.

В итоге получился такой шилд:



Прошил в ПЗУ Загрузчик и Монитор, которые так же нашлись на сайте Fifan-a. Включил питание, и компьютер не заработал. Ну этого стоило ожидать. К тому моменту уже был найден частотомер, и быстро выяснилось, что не верно формируется сигнал RAS, его частота должна была быть около 2 мГц, а было то 6, то 4. Перепаивание панельки от ИР12 дало свои результаты, сигнал начал формироваться верно. На эту проблему ушло около недели. Но изображения все еще не было.

По совету Андрея прошил в ПЗУ тестовую программу, и из динамика начали доноситься звуки. Это означало, что процессор, буферы, ПЗУ и порт ввода-вывода работали правильно.

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



Подозрения пали на мультиплексоры. Но как бы я их не переставлял, изображение не менялось. Прозвонка платы тестером так же ничего не давала — все соединения были на месте. Потратив еще несколько дней на эту проблему и перебрав еще пару вариантов (подбор конденсаторов в цепях делителей и SYNC процессора), я нашел причину — все же имел место непропай одного контакта в мультиплексоре. Изображение пошло, но с помехами в виде вертикальных линий, кроме этого 2 ОЗУ светились как неисправные.



Перестановка микросхем местами результата не дала, значит еще один непропай. Так и оказалось. Питание на них отсутствовало. Видимо расплавил припой, когда допаивал сглаживающие конденсаторы.

После этого картинка стала такой, какой и должна была быть. Тест программа показывала что все в норме — изображение формируется, ОЗУ в норме.



Следующий шаг — клавиатура. Проще всего было бы взять клавиатуру с интерфейсом PS/2 и через AVR контроллер подключить ее. Но походив с этой идеей до конца рабочей недели решил собирать клавиатуру по оригинальной схеме. В итоге окончательный вид ПК получился таким:



И вид со стороны монтажа:



Осталось поставить его в человеческий корпус, и переделать разъем клавиатуры (идея с 25 ногим разъемом оказалась громоздкой, поэтому не очень удачной) и буду считать, что сборка завершена. Компьютер займет место на полке рядом со старыми ZX-Spectrum, ПК01-Львов, Вектор-06Ц и Микрошей, который мне недавно подарили, и который требует небольшого ремонта.

С одной стороны грустно, что одной давней мечтой стало меньше, но с другой на то они и нужны, чтобы сбывались. Еще грустно, что отец не дожил до того момента, когда проиграл спор.

Вывод? Чешутся, или когда то чесались руки — дерзайте, оно того стоит!

Приложение 1. Программатор
Схема программатора приведена на рисунке


Я не пытался сделать универсальный программатор, под разные типы ПЗУ (хотя это сделать просто), так же я не пытался сделать оптимальным код прошивки. Задачи этого шилда — прочесть и записать ПЗУ, и он с ними справляется.
В качестве источника питания на 25В я использовал универсальный блок питания для ноутбука. Он выдает напряжения от 12 до 24 Вольт, при входящем напряжении 12В или 110-220В. 24 В для записи оказалось достаточно.
Arduino Mega подключается через USB к компьютеру. В составе среды разработки Arduino есть утилита — Монитор порта. В ней будет отображаться весь процесс работы программатора.
Код программы для записи в ПЗУ должен быть сохранен в корневой папке SD карты под именем code.hex.
После включения питания, программатор предлагает ввести команду — Чтение или Запись.
Пример чтения данных из ПЗУ (записан Монитор)


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

Исходный текст программы
#include <SD.h>

int nMode = 0; //0-ожидание команды, 1-чтение, 2-запись

void WriteByte(int adr, int data){  

  int i;
  String sAdr, sData;
  
  // чтение
  digitalWrite(42, LOW);
  pinMode(24, OUTPUT);
  pinMode(25, OUTPUT);
  pinMode(26, OUTPUT);
  pinMode(27, OUTPUT);
  pinMode(28, OUTPUT);
  pinMode(29, OUTPUT);
  pinMode(30, OUTPUT);
  pinMode(31, OUTPUT);

  // сформируем строку адреса и данных
  sAdr = "";
  sData = "";
  for (i = sizeof(adr) * 8 - 1; i >= 0; --i)
  {
     sAdr = sAdr + (String)((adr >> i) & 1);
  }  
  for (i = sizeof(data) * 8 - 1; i >= 0; --i)
  {
     sData = sData + (String)((data >> i) & 1);
  }  

  // выберем адрес
  if (sAdr.substring(15) == "1")
    digitalWrite(39, HIGH);
  else 
    digitalWrite(39, LOW);
  if (sAdr.substring(14, 15) == "1")
    digitalWrite(38, HIGH);
  else 
    digitalWrite(38, LOW);    
  if (sAdr.substring(13, 14) == "1")
    digitalWrite(37, HIGH);
  else 
    digitalWrite(37, LOW);    
  if (sAdr.substring(12, 13) == "1")
    digitalWrite(36, HIGH);
  else 
    digitalWrite(36, LOW);    
  if (sAdr.substring(11, 12) == "1")
    digitalWrite(35, HIGH);
  else 
    digitalWrite(35, LOW);    
  if (sAdr.substring(10, 11) == "1")
    digitalWrite(34, HIGH);
  else 
    digitalWrite(34, LOW);    
  if (sAdr.substring(9, 10) == "1")
    digitalWrite(33, HIGH);
  else 
    digitalWrite(33, LOW);    
  if (sAdr.substring(8, 9) == "1")
    digitalWrite(32, HIGH);
  else 
    digitalWrite(32, LOW);    
  if (sAdr.substring(7, 8) == "1")
    digitalWrite(43, HIGH);
  else 
    digitalWrite(43, LOW);    
  if (sAdr.substring(6, 7) == "1")
    digitalWrite(41, HIGH);
  else 
    digitalWrite(41, LOW);    
  if (sAdr.substring(5, 6) == "1")
    digitalWrite(40, HIGH);
  else 
    digitalWrite(40, LOW);    

  // установим значение байта
  if (sData.substring(15) == "1")
    digitalWrite(24, HIGH);
  else 
    digitalWrite(24, LOW);
  if (sData.substring(14, 15) == "1")
    digitalWrite(25, HIGH);
  else 
    digitalWrite(25, LOW);    
  if (sData.substring(13, 14) == "1")
    digitalWrite(26, HIGH);
  else 
    digitalWrite(26, LOW);    
  if (sData.substring(12, 13) == "1")
    digitalWrite(27, HIGH);
  else 
    digitalWrite(27, LOW);    
  if (sData.substring(11, 12) == "1")
    digitalWrite(28, HIGH);
  else 
    digitalWrite(28, LOW);    
  if (sData.substring(10, 11) == "1")
    digitalWrite(29, HIGH);
  else 
    digitalWrite(29, LOW);    
  if (sData.substring(9, 10) == "1")
    digitalWrite(30, HIGH);
  else 
    digitalWrite(30, LOW);    
  if (sData.substring(8, 9) == "1")
    digitalWrite(31, HIGH);
  else 
    digitalWrite(31, LOW);    

  // подождем 10мс для выбора адреса
  delay(10);
  
  //запись
  digitalWrite(42, HIGH);
  digitalWrite(44, HIGH);
  delay(60); // задерживаем высокий уровень на 60мс для записи данных
  digitalWrite(44, LOW);
  digitalWrite(42, LOW);
}

void writeChip() {
  nMode = 0;
  int adr, dat;
  adr = 0;
  // открываем файл только для чтения
  File myFile = SD.open("code.hex");
  if (myFile) {
  
    // читаем файл посимвольно до конца:
    while (adr < 2048 && myFile.available()) {
        dat = myFile.read();
        Serial.print((String)adr+" - "+(String)dat+" - ");
        Serial.println(dat, HEX);
        WriteByte(adr, dat);
        adr++;
    }
    // закрываем файл:
    myFile.close();
  } else {
    // если файл не открылся, сообщает об ошибке:
    Serial.println("No file code.hex found!!!");
  }
}

void readChip() {

int r, i, adr = 0;
String sAdr, sData;

// чтение
  digitalWrite(42, LOW);
  pinMode(24, INPUT);
  pinMode(25, INPUT);
  pinMode(26, INPUT);
  pinMode(27, INPUT);
  pinMode(28, INPUT);
  pinMode(29, INPUT);
  pinMode(30, INPUT);
  pinMode(31, INPUT);
  adr = 0;
  while (adr < 2048) {
    // сформируем строку адреса
    sAdr = "";
    sData = "";
    for (i = sizeof(adr) * 8 - 1; i >= 0; --i)
    {
       sAdr = sAdr + (String)((adr >> i) & 1);
    }  
    
    // выберем адрес
    if (sAdr.substring(15) == "1")
      digitalWrite(39, HIGH);
    else 
      digitalWrite(39, LOW);
    if (sAdr.substring(14, 15) == "1")
      digitalWrite(38, HIGH);
    else 
      digitalWrite(38, LOW);    
    if (sAdr.substring(13, 14) == "1")
      digitalWrite(37, HIGH);
    else 
      digitalWrite(37, LOW);    
    if (sAdr.substring(12, 13) == "1")
      digitalWrite(36, HIGH);
    else 
      digitalWrite(36, LOW);    
    if (sAdr.substring(11, 12) == "1")
      digitalWrite(35, HIGH);
    else 
      digitalWrite(35, LOW);    
    if (sAdr.substring(10, 11) == "1")
      digitalWrite(34, HIGH);
    else 
      digitalWrite(34, LOW);    
    if (sAdr.substring(9, 10) == "1")
      digitalWrite(33, HIGH);
    else 
      digitalWrite(33, LOW);    
    if (sAdr.substring(8, 9) == "1")
      digitalWrite(32, HIGH);
    else 
      digitalWrite(32, LOW);    
    if (sAdr.substring(7, 8) == "1")
      digitalWrite(43, HIGH);
    else 
      digitalWrite(43, LOW);    
    if (sAdr.substring(6, 7) == "1")
      digitalWrite(41, HIGH);
    else 
      digitalWrite(41, LOW);    
    if (sAdr.substring(5, 6) == "1")
      digitalWrite(40, HIGH);
    else 
      digitalWrite(40, LOW);    
  
    // подождем 10мс для выбора адреса и прочтем данные
    delay(10);
    r = 0;
    if (digitalRead(24) == HIGH){
      sData = "1" + sData;
      r = r + pow(2, 0); } 
    else
      sData = "0" + sData; 
    if (digitalRead(25) == HIGH){
      sData = "1" + sData;
      r = r + pow(2, 1); } 
    else
      sData = "0" + sData; 
    if (digitalRead(26) == HIGH){
      sData = "1" + sData;
      r = r + pow(2, 2); } 
    else
      sData = "0" + sData;
    if (digitalRead(27) == HIGH){
      sData = "1" + sData;
      r = r + pow(2, 3); } 
    else
      sData = "0" + sData; 
    if (digitalRead(28) == HIGH){
      sData = "1" + sData;
      r = r + pow(2, 4); } 
    else
      sData = "0" + sData; 
    if (digitalRead(29) == HIGH){
      sData = "1" + sData;
      r = r + pow(2, 5); } 
    else
      sData = "0" + sData; 
    if (digitalRead(30) == HIGH){
      sData = "1" + sData;
      r = r + pow(2, 6); } 
    else
      sData = "0" + sData; 
    if (digitalRead(31) == HIGH){
      sData = "1" + sData;
      r = r + pow(2, 7); } 
    else
      sData = "0" + sData; 
  
    Serial.print(sAdr+" - "); 
    Serial.print(sData+" - ");
    Serial.println(r, HEX);

    adr++; 
  }
  nMode = 0;
}

void setup() {
  nMode = 0;
  Serial.begin(9600);
  pinMode(4, INPUT);
  pinMode(5, INPUT);
  pinMode(53, OUTPUT);
  if (!SD.begin(53)) {
    Serial.println("Card failed, or not present");
    return;
  }
  Serial.println("start...");
  pinMode(44, OUTPUT);
  digitalWrite(44, LOW);
  pinMode(42, OUTPUT);
  digitalWrite(42, LOW);  
  pinMode(39, OUTPUT);
  pinMode(38, OUTPUT);
  pinMode(37, OUTPUT);
  pinMode(36, OUTPUT);
  pinMode(35, OUTPUT);
  pinMode(34, OUTPUT);
  pinMode(33, OUTPUT);
  pinMode(32, OUTPUT);
  pinMode(43, OUTPUT);
  pinMode(41, OUTPUT);
  pinMode(40, OUTPUT);
  Serial.println("Init...done!");
  Serial.println("Waiting command...");
}
 
void loop() {
  if (digitalRead(4) == LOW && nMode == 0){
    delay(20); // защита от дребезга контактов
    if (digitalRead(4) == LOW && nMode == 0){
      Serial.println("Start writing chip...");
      nMode = 2;  
      writeChip();
      Serial.println("Writing complete!!!");
      delay(5000);
    }
  }

  if (digitalRead(5) == LOW && nMode == 0){
    delay(20); // защита от дребезга контактов
    if (digitalRead(5) == LOW && nMode == 0){
      Serial.println("Start reading chip...");
      nMode = 1;
      readChip();
      Serial.println("Reading complete!!!");
      delay(5000);
    }
  }  
  delay(100);
}


Tags:
Hubs:
Total votes 136: ↑133 and ↓3+130
Comments92

Articles