Pull to refresh

Простой электронный самописец

Reading time 6 min
Views 39K

Сначала была идея

На работе (работаю в медицине) пыхтят и мучаются два электромеханических самописца ну и я вместе с ними: тушь, механика – знаете ли неприятно. Как то раз в мою голову забрела идея: а почему бы не заменить два задыхающихся от старости самописца простой системой сбора данных состоящей из контроллера АЦП и ПК (пусть даже слабенького и старенького) с соответствующим программным обеспечением с возможностью вывода на принтер? И тут понеслось в голове и закружилось…

Лирика

Так как кроме идеи у меня ничего не имелось: ни опыта, ни особых познаний в схемотехнике и электронике, пришлось перелопатить изрядное количество литературы и пошарить по просторам сети. Также проект предполагался бюджетным, и поэтому пришлось освоить метод ЛУТ, научиться травить платы, сверлить и паять – о чем нисколько не жалею. Таким образом я прошел некоторый, пусть небольшой, путь — путь проб и ошибок, привожу некоторые наблюдения, сделанные мной в процессе, может, кто-то сравнит их со своими и согласится, а может и не согласится:
  • быстрого старта, как такого, не получится, не стоит строить иллюзии — придется попотеть;
  • эмуляторы типа Proteus на первых порах лучше не использовать, гораздо полезнее экспериментировать на реальном железе, потрогать рукам, попробовать на вкус и на зуб. Для простейшей отладки достаточно UART;
  • монтажные платы – брр, предпочитаю ЛУТ + хлорное железо+сверловка, получается чуть дольше, но дает четкое понимание того, что ты делаешь;
  • советую не увлекаться монтажом smd-корпусов и «минитюаризацией» монтажных плат — это достаточно сложно для новичка, иногда бывает проще заново развести плату в «увеличенном масшабе» с простым навесным монтажом (опять же полезнее для понимания).


О теории АЦП и первой попытке

После некоторых изысканий выяснилось, что реализовать задуманную идею можно в нескольких вариантах. Простейшие решения приведены в книжке Патрика Гелля(см.подвал), там же разъясняются азы аналого-цифрового преобразования сигнала. Привожу типичную схему, взятую оттуда:
В основе схемы – микросхема АЦП. Взаимодействие с ПК реализуется на программном уровне путем формирования управляющих последовательностей импульсов на модемных линиях интерфейса RS-232 ПК. Данное обстоятельство ограничивает скорость передачи данных и увеличивает вероятность ошибки передачи. Точность измерения определяется разрядностью АЦП (в данном случае 8 разрядов), точностью подводимого к АЦП опорного напряжения (здесь используется ИОН LT 1009 CZ). Скорость оцифрования сигнала зависит от времени преобразования АЦП и опять же от точности организации интерфейса разработчиком. Собственно, данная реализация была моим первым боевым опытом (см. фото ниже), но вскоре меня разочаровала, так как чувствовал потребность в более изящном решении. Управляющая программа(драйвер) была написана под DOS на паскале.
Подобные схемы, не смотря на свою жизнеспособность, ввиду указанных недостатков практически не применяются, микросхемы АЦП обычно используются вместе с микроконтроллером, который уже организует передачу данных на аппаратном уровне, попутно выполняя какие-либо операции управления, либо примитивной обработки данных. Хорошим примером такого решения может служить вот такая схемка на основе микроконтроллера AVR:

В основе схемы лежит микроконтроллер Atmega8, микросхема сопряжения с USB FT232BM, микросхема АЦП AD7876, ИОН — REF195GP. На входе — дифференциатор на базе операционного усилителя приводит сигнал на входе к диапазону 0-5В (опорное напряжение АЦП). Аналого-цифровое преобразование сигнала осуществляет микросхема АЦП AD7876 и передает данные по интерфейсу SPI в микроконтроллер, который, в свою очередь, «выкидывает» результат в usb-порт посредством UART и микросхемы сопряжения FT232BM.
В рамках моей задачи мне нужно задействовать 4 канала АЦП. Привлекательной возможностью выглядит использование встроенного АЦП микроконтроллера с коммутируемым входом, что позволит отказаться от использования внешней микросхемы АЦП и обеспечить нужное количество каналов — дешевое и простое решение. Включать дифференциатор в схему нет необходимости, так как амплитуда сигнала на каждом из входов не превышает 2-2,5 В.

Схема моего девайса

Контроллер АЦП строится на микроконтроллере AVR Atmega8. МК обладает достаточным количеством ножек для того чтобы подключить 4 канала АЦП, сигнальные светодиоды, плату сопряжения с ПК. В схеме используется внешний ИОН L1009CZ. Плата сопряжения с ПК через интерфейс RS-232 основана на микросхеме MAX232 и обособлена от основного модуля, при необходимости может быть заменена на плату с FT232 на борту для сопряжения через USB, либо с любым bluetooth-модулем (типа BTM-222, HC-04) для коммуникации через blootooth интерфейс. На рисунке ниже представлена принципиальная схема разрабатываемого устройства:

Схема питания стандартная – на базе линейного стабилизатора 78L05, присутствует сигнальный светодиод HL1. Принципиальная схема нарисована с помощью sPlan, разводка платы — в Sprint Layout. В конце технологической цепочки — ЛУТ+травление+сверловка+пайка получаем:

Вид снизу:


Программная часть

Для кодинга использовал AVRStudio+WinAVR(AVR-GCC) под Windows, альтернатива для Linux – Eclipse + AVR-GCC. Пробовал CodeVisionAVR — неплох для начала, имеет встроенный генератор кода, ограничение по объему кода 2 кБ.
Прошивка работает по следующему алгоритму:
  • инициализация: функции — UART_init, ADC_init, LED_init;
  • последовательный опрос каналов в бесконечном цикле по прерыванию и передача данных через UART на com-порт ПК.

В целях отладки по тексту рассованы тестовые сообщения. Переключение канала опроса подсвечивается соответствующим светодиодом. При инициализации все 4 светодиода мигают одновременно. Для того чтобы переключение светодиодов было заметно глазу намеренно поставил задержки.

/* WinAVR version...
   Chip: ATmega8
   Memory Model: SMALL
   Data Stack Size: 256 bytes
   Clock frequency: 4.0000 MHz

   PCO - PC3 - Channels */

// ATmega8 I/O register definitions
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdio.h>

#define ADC_VREF_TYPE 0x40
#define ADC_CH1_MUX 0x1
#define ADC_CH2_MUX 0x2
#define ADC_CH3_MUX 0x3

// Counter of channel's changes
uint8_t i = 0;
void LED_init(void){
	printf("Led initialization....\r\n");
    char j = 0;

    DDRD|= (1<<DDD7);
    DDRB|= ((1<<DDB0)|(1<<DDB1)|(1<<DDB2));

    for(j=0;j<5;j++)
    {
        PORTD|=(1<<PD7);
        PORTB|=(1<<PB0)|(1<<PB1)|(1<<PB2);
        _delay_ms(600);
        PORTB&= ~((1<<PB0)|(1<<PB1)|(1<<PB2));
        PORTD&= ~(1<<PD7);
        _delay_ms(600);
    }
}

//Sending of single char
static int my_putchar(char c, FILE *stream){

	while((UCSRA&(1<<UDRE)) == 0);
	UDR = c;
	return 0;
}

void myUART_init(void){
    // USART initialization
    // Communication Parameters: 8 Data, 1 Stop, No Parity
    // USART Receiver: Off
    // USART Transmitter: On
    // USART Mode: Asynchronous
    // USART Baud rate: 9600
    UCSRA=0x00;
    UCSRB=0x08;
    UCSRC=0x86;
    UBRRH=0x00;
    UBRRL=0x19; 

    //Redirection of stdout
    static FILE mystdout = FDEV_SETUP_STREAM(my_putchar, NULL, _FDEV_SETUP_WRITE);
    stdout = &mystdout;

    printf("UART initialization....\r\n");
}

void ADC_init(void){
    // ADC initialization
    // ADC Voltage Reference: AREF pin
    // ADC High Speed Mode: Off
    // ADC Auto Trigger Source: None
    // Select ADC input 0
    printf("ADC initialization....\r\n");
    ADMUX=ADC_VREF_TYPE;
    ADCSRA=0x8E;
}
// ADC interrupt service routine
ISR(ADC_vect){
	// Here is sending data in RS-232
	printf("I'am in interrupt...\r\n");
 	uint16_t data = ADCL;
    data+= (ADCH<<8);
 	printf("Ch_%u=%u\r\n",i,data);

 	//Control of ADMUX's state
 	uint8_t pr = ADMUX;
 	printf("ADMUX = %u\r\n",pr);
 	data = 0;

    if (i == 3)
 	    {
 	    	i = 0;
 	    	ADMUX&= ~ADC_CH3_MUX;

 	    	PORTB&= ~(1<<PB2);
 	    	PORTD|=(1<<PD7);

 	    	//Change of channel
 	    	data = ADMUX;
 	    	printf("3to0,ADMUX = %u\r\n",data);
 	    	data=0;

 	    	_delay_ms(25);
 	    }
    else
    	{

    		if (i == 0)
    			{

    				ADMUX|= ADC_CH1_MUX;

    				PORTD&= ~(1<<PD7);
    				PORTB|= (1<<PB0);

    				//Change of channel
    				data = ADMUX;
    				printf("0to1,ADMUX = %u\r\n",data);
    				data=0;
    			}

    		if (i == 1)
    			{

    				ADMUX&= ~ADC_CH1_MUX;
    				ADMUX|= ADC_CH2_MUX;

    				PORTB&= ~(1<<PB0);
    				PORTB|= (1<<PB1);

    				//Change of channel
    				data = ADMUX;
    				printf("1to2,ADMUX = %u\r\n",data);
    				data=0;
    			}

    		if (i == 2)
    			{

    				ADMUX&= ~ADC_CH2_MUX;
    				ADMUX|= ADC_CH3_MUX;

    				PORTB&= ~(1<<PB1);
    				PORTB|= (1<<PB2);

    				//Change of channel
    				data = ADMUX;
    				printf("2to3,ADMUX = %u\r\n",data);
    				data=0;
    			}

    		i++;
    		_delay_ms(25);
    	}

    // Start a new AD conversion
    ADCSRA|=0x40;

};

int main(void)
{
   	myUART_init();
    ADC_init();
    LED_init();
    printf("I'am in main...\r\n");
    // Global enable interrupts
    sei();
    // Start the first AD conversion
    ADCSRA|=0x40;
    while (1);
}


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

Программатор

Для прошивки применялся простейший программатор STK200, причем разводку платы пришлось делать самому, чтобы облегчить пайку. Прошивал avrdude. Пробовал avreal – отличная альтернатива, трудностей также не возникло.



Наконец-то – работает!

После отладки кода, нескольких циклов стирания/записи МК девайс ожил и заморгал светодиодами к моей огромной радости.

На ПК использовал текстовый терминал для работы с COM-портом. В сети их навалом, при желании можно и самому написать, например, используя QT + QSerialDevice(замечательная библиотечка для работы с com-портами, написанная нашим соотечественником Денисом Шиенковым), или как тут.

В заключение

В планах осталось только написание ПО для ПК. Вообще-то уже пишу, используя в связке QT+QSerialDevice+QWT, и скоро, скоро, чувствую, поползут мои графики по дисплею. А еще подумываю о том, чтобы реализовать аппаратную часть на МК серии STM32F, взяв за основу упоминаемую уже на хабре STM32VLDISCOVERY — хочется освоить новое железо.

Полезная литература

Помогут переварить все вышенаписанное книги:
П. Хоровиц, У. Хилл. “Искусство схемотехники” — классическая вещь;
Патрик Гелль. Как превратить персональный компьютер в измерительный комплекс — упоминалась выше.
Tags:
Hubs:
+112
Comments 60
Comments Comments 60

Articles