Различные проекты на платформе Arduino.
суббота, 22 сентября 2012 г.
Проекты на ATMega8
Проекты на АТMega8.
Простые проекты для изучения одного из самых простых и массовых микроконтроллеров.
Для работы вам понадобится как минимум CodeVision AVR2.04.4a и Proteus 7.2 SP6. Если желаете поработать с "железом", вам понадобится и программатор. Советую вот такой - легко собирается, хорошо работает. Единственная проблема с первоначальной прошивкой ATMega8, это можно сделать либо через порт LPT - 5-provodov-avr, либо купить "зашитый" микроконтроллер, я брал здесь.
Светофор №1.
Простейший светофор на одно направление не требует для создания больших усилий и навыков. Схема собирается за несколько минут. Резисторы подбираются исходя из используемых светодиодов (номинал 470 Ом указан для "советских" АЛ307), следует заметить, что на схеме вывод AVCC подключен к питанию, если его не подключить на реальном микроконтроллере независимо от использования встроенного АЦП (аналого-цифрового преобразователя), то можно вывести микросхему из строя (справедливо для любых контроллеров серии Mega)!!!
Исходный код настолько простой, что я его представлю прямо здесь. Этот код для Си я нашёл в интернете и немного подправил, однако, любой программист скажет вам, что этот код является бестолковым (далее я опишу, как именно требуется писать такие программы), но зато - простым, наглядным и рабочим.
/*****************************************************
Chip type : ATmega8Program type : Application
AVR Core Clock frequency: 1.000000 MHz
Memory model : Small
Data Stack size : 256
*****************************************************/
#include <mega8.h>
#include <delay.h>void main(void)
{
// Port B initialization
PORTB=0x00;
DDRB=0x00;
// Port C initialization
PORTC=0x00;
DDRC=0x00;
// Port D initialization
PORTD=0x00;
DDRD=0x07;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
MCUCR=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
while (1) {
PORTD.2=1; //зеленый загорается
delay_ms(8000); //горит 8 секунд
PORTD.2=0; //Выключаем зеленый
delay_ms(500); //Ждем пол секунды
PORTD.2=1; //Включаем зеленый
delay_ms(500); //Ждем полсекунды
PORTD.2=0; //Выключаем зеленый
delay_ms(500); //Ждем полсекунды
PORTD.2=1; //Включаем зеленый
/*delay_ms(500);//Ждем полсекунды
PORTD.2=0; //Выключаем зеленый
delay_ms(500); //Ждем полсекунды
PORTD.2=1; //Включаем зеленый
delay_ms(500); //Ждем полсекунды*/
PORTD.1=1; //Включаем жёлтый
PORTD.2=0; //Выключаем зеленый
delay_ms(3000); //Ждем 3 секунды
PORTD.0=1; //Включаем красный
PORTD.1=0; //выключаем жёлтый
delay_ms(9000); //на 9 секунд
PORTD.1=1; //включаем жёлтый к красному
delay_ms(3000); //ждем 3 секунды
PORTD.0=0; //Выключаем красный
PORTD.1=0; //и жёлтый
};
}
Код можно ещё несколько сократить, если учесть, что по умолчанию практически все порты и регистры ATMega8 инициализированы в 0. Теперь для начинающих некоторые пояснения:
#include <mega8.h>
#include <delay.h>
Это так называемые заголовочные файлы, в них написаны процедуры, которые мы применим из других файлов. Например, процедура delay_ms(X), которая определяет задержку в миллисекундах, была написана другим человеком и содержится в файле delay.с (на самом деле всё может быть не совсем так, или совсем не так, - процедуры может содержать объектный файл типа *.obj, *.asm), а правила её применения описаны в файле delay.h, который мы подключаем.
DDRB=0x00;
Зарезервированные имена, обозначающие регистры порта контроллера (его ножки сгруппированные байтом - по 8, каждый бит регистра порта соответствует своей ножке) и регистры направления обмена порта (0-вход, 1-выход)
Например, запись DDRB.5=1 означает что ножка PB5 контроллера настроена на выход, и при записи PORTB.5=0 или =1, на данной ножке получим 0 (0...0.8 Вольта) или 1 (4...5 Вольт). Разумеется, можно и сразу целиком присвоить значение порту: PORTB=0xFF, т.е. все ножки порта PB равны 1.
while(1) {expression};
представляет собой бесконечный цикл, так как 1=TRUE.
Светофор №2.
Чтобы получить светофор на два направления, надо модифицировать схему светофора №1:
и код светофора №1:
/*****************************************************
Chip type : ATmega8
Program type : Application
AVR Core Clock frequency: 1.000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 256
*****************************************************/
#include <mega8.h>
#include <delay.h>
void main(void)
{
// Port B initialization
PORTB=0x00;
DDRB=0x00;
// Port C initialization
PORTC=0x00;
DDRC=0x00;
// Port D initialization
PORTD=0x00;
DDRD=0b00111111;
ACSR=0x80;
SFIOR=0x00;
while (1)
{
PORTD.2=1; //зеленый1 загорается Z1
PORTD.3=1; //красный2 загорается K2
delay_ms(8000); //зеленый1 горит 8 секунд
PORTD.2=0; //выключаем зеленый1 ZM1
delay_ms(500); //ждем пол секунды
PORTD.2=1; //включаем зеленый1
delay_ms(500); //ждем полсекунды
PORTD.2=0; //выключаем зеленый1
delay_ms(500); //ждем полсекунды
PORTD.2=1; //включаем зеленый1
delay_ms(500); //ждем полсекунды
PORTD.1=1; //включаем оранжевый1 J1 K2+J2
PORTD.4=1; //включаем оранжевый2
PORTD.2=0; //выключаем зеленый1
delay_ms(2000); //ждем 2 секунды
PORTD.0=1; //включаем красный1 K1
PORTD.5=1; //включаем зеленый2 Z2
PORTD.1=0; //выключаем оранжевый1
PORTD.4=0; //выключаем оранжевый2
PORTD.3=0; //выключаем красный2
delay_ms(8000); //ждём 8 секунд
PORTD.5=0; //выключаем зеленый2 ZM2
delay_ms(500); //ждем полсекунды
PORTD.5=1; //включаем зеленый2
delay_ms(500); //ждем полсекунды
PORTD.5=0; //выключаем зеленый2
delay_ms(500); //ждем полсекунды
PORTD.5=1; //включаем зеленый2
delay_ms(500); //ждем полсекунды
PORTD.1=1; //включаем оранжевый1 к красному1 K1+J1
PORTD.4=1; //включаем оранжевый2 J2
PORTD.5=0; //выключаем зеленый2
delay_ms(2000); //ждем 2 секунды
PORTD.0=0; //Выключаем красный1
PORTD.1=0; //и оранжевый1
PORTD.4=0; //и оранжевый2
};
}
комментарии по коду:
DDRD=0b00111111; //0b(b7)(b6)(b5)(b4)(b3)(b2)(b1)(b0)
справа битовое(двоичное) представление числа в котором слева - самый старший разряд, его же можно было записать в десятичном ( DDRD=63;) или в шестнадцатиричном виде ( DDRD=0x3F;).
void main(void)
main главная процедура, с неё начинается выполнение программы, void означает буквально ничего (нулевой тип), вместо void можно подставить (signed или unsigned) int, long; float, double и так далее (и даже указатель на другую переменную, о чём будет рассказано позже). Причём замена void на какой-либо тип в первой позиции обозначает что данная конструкция - функция, а не процедура, и может возвращать значение, т.о. она должна быть дополнена внутри словом return.
int fun(void) {
int a=10;
return(a);
}
все изменения производились согласно диаграмме работы:
Диаграмма работы светофора на два направления с мигающим зелёным сигналом. Данная диаграмма взята также с просторов интернета, и по-моему: миганий зелёного сигнала должно быть больше.
Светофор №3.
В примерах №1 и №2 было указано на несколько "прямолобое" применение кода, которое позволительно для небольших программ, однако не может быть применено из-за расточительности ресурсами в больших приложениях.
Для упрощения и сокращения кода в технологических применениях программисты обычно используют автоматы. Автомат является упрощённой и достаточной моделью процесса. Например, всю работу светофора можно разбить на некоторое конечное число состояний, которые будут повторятся с некоторым периодом. Для представления автомата потребуется программный счётчик состояний и дешифратор состояний. Светофор №3, который состоит из транспортного светофора на 4 направления, 4-х пешеходных светофоров, 1-го железнодорожного для переезда, 1-го мигающего пешеходного, было бы проблематично создать без автомата.
Код без обработки пешеходных и ж/д светофоров приведен ниже. Несложно понять что процедуры типа
void SetRedT1(void) //Транспортный светофор1 включить красный D3
{
ptc|=0x01;
}
устанавливают либо стирают отдельные биты.
В главном цикле значение счётчика i постоянно увеличивается пока не достигнет 48.
i++;
При этом счётчик обнуляется.
if (i==48) {i=0;}; // 24c=0.5*48
В цикле постоянно происходит сравнение значения счётчика с константами, и производится работа с портами. Хоть данный код и более совершенный, чем предыдущие два, но он также более подходит для наглядности чем для работы. Профессионалы чаще всего не используют наборы отдельных операций сравнения, а пользуются операторами switch-case, или вовсе записывают заранее рассчитанные данные в массивы - пользуются готовой таблицей:
flash unsigned char sw[N]={
//G1Y1R1G2Y2R2 XX
0b10000100, //1 Х периодов горят Зелёный1 и Красный2
0b10000100, //2
...
0b00000100, // Х периодов Зелёный1 мигает,
0b10000100, //
...
0b01001100, //K-1 Зелёный1 гаснет, загораются Жёлтый1 и Жёлтый2
0b00110000, //K Загорается Красный1, загорается Зелёный1, гаснут Жёлтый2 и Красный2
...
0b01101000 //N
};
while (1)
{
i++;
if (i==48) {i=0;}; // 24c=0.5*48 - цикл
PORTC=(sw[i]>>x) | mask;
PORTD=(sw[i]>>x) | mask;
delay_ms(500);
};
}
Разумеется, выражения (sw[i]>>x) | mask описаны условно, всё зависит от положения информации о сигналах в константе sw.
/*****************************************************
Chip type : ATmega8
Program type : Application
AVR Core Clock frequency: 1.000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 256
*****************************************************/
#include <mega8.h>
#include <delay.h>
unsigned char ptb=0;
unsigned char ptc=0;
unsigned char ptd=0;
void SetRedT1() //Транспортный светофор1 включить красный D3
{
ptc|=0x01;
}
void ResetRedT1() //Транспортный светофор1 выключить красный D3
{
ptc&=~0x01;
}
void SetYelT1() //Транспортный светофор1 включить жёлтый D2
{
ptc|=0x02;
}
void ResetYelT1() //Транспортный светофор1 выключить жёлтый D2
{
ptc&=~0x02;
}
void SetGrnT1() //Транспортный светофор1 включить зелёный D1
{
ptc|=0x04;
}
void ResetGrnT1() //Транспортный светофор1 выключить зелёный D1
{
ptc&=~0x04;
}
void SetRedT2() //Транспортный светофор2 включить красный D6
{
ptc|=0x08;
}
void ResetRedT2() //Транспортный светофор2 выключить красный D6
{
ptc&=~0x08;
}
void SetYelT2() //Транспортный светофор2 включить жёлтый D5
{
ptc|=0x10;
}
void ResetYelT2() //Транспортный светофор2 выключить жёлтый D5
{
ptc&=~0x10;
}
void SetGrnT2() //Транспортный светофор2 включить зелёный D4
{
ptc|=0x20;
}
void ResetGrnT2() //Транспортный светофор2 выключить зелёный D4
{
ptc&=~0x20;
}
void SetRedT3() //Транспортный светофор3 включить красный D9
{
ptd|=0x01;
}
void ResetRedT3() //Транспортный светофор3 выключить красный D9
{
ptd&=~0x01;
}
void SetYelT3() //Транспортный светофор3 включить жёлтый D8
{
ptd|=0x02;
}
void ResetYelT3() //Транспортный светофор3 выключить жёлтый D8
{
ptd&=~0x02;
}
void SetGrnT3() //Транспортный светофор3 включить зелёный D7
{
ptd|=0x04;
}
void ResetGrnT3() //Транспортный светофор3 выключить зелёный D7
{
ptd&=~0x04;
}
void SetRedT4() //Транспортный светофор2 включить красный D12
{
ptd|=0x08;
}
void ResetRedT4() //Транспортный светофор2 выключить красный D12
{
ptd&=~0x08;
}
void SetYelT4() //Транспортный светофор2 включить жёлтый D11
{
ptd|=0x10;
}
void ResetYelT4() //Транспортный светофор2 выключить жёлтый D11
{
ptd&=~0x10;
}
void SetGrnT4() //Транспортный светофор2 включить зелёный D10
{
ptd|=0x20;
}
void ResetGrnT4() //Транспортный светофор2 выключить зелёный D10
{
ptd&=~0x20;
}
// Declare your global variables here
void main(void)
{
unsigned char i=0;
PORTB=0x00;
DDRB=0xFF;
PORTC=0x00;
DDRC=0xFF;
PORTD=0x00;
DDRD=0xFF;
ACSR=0x80;
while (1)
{
if (i==0) {ResetYelT1();ResetRedT1();SetGrnT1();
ResetYelT2();SetRedT2();
ResetYelT3();ResetRedT3();SetGrnT3();
ResetYelT4();SetRedT4();
}; //0s
if (i==16) {ResetGrnT1();
ResetGrnT3();
}; //8s
if (i==17) {SetGrnT1();
SetGrnT3();
};
if (i==18) {ResetGrnT1();
ResetGrnT3();
};
if (i==19) {SetGrnT1();
SetGrnT3();
};
if (i==20) {ResetGrnT1();SetYelT1();
SetYelT2();
ResetGrnT3();SetYelT3();
SetYelT4();
}; //10s
if (i==24) {ResetYelT1();SetRedT1();
ResetYelT2();ResetRedT2();SetGrnT2();
ResetYelT3();SetRedT3();
ResetYelT4();ResetRedT4();SetGrnT4();
}; //12s
if (i==40) {ResetGrnT2();
ResetGrnT4();
}; //20s
if (i==41) {SetGrnT2();
SetGrnT4();
};
if (i==42) {ResetGrnT2();
ResetGrnT4();
}; //21s
if (i==43) {SetGrnT2();
SetGrnT4();
};
if (i==44) {SetYelT1();
ResetGrnT2();SetYelT2();
SetYelT3();
ResetGrnT4();SetYelT4();
}; //22s
i++;
if (i==48) {i=0;}; // 24c=0.5*48 - цикл
//PORTB=ptb;
PORTC=ptc;
PORTD=ptd;
delay_ms(500);
};
}
Столбчатый индикатор.
Если в предыдущих примерах использовались цифровые ресурсы микроконтроллера, то данный пример использует аналоговые - АЦП. Аналого-цифровой преобразователь предназначен для дискретных преобразований аналогового сигнала в цифровой код с определённой частотой дискретизации. Для начинающих скажу лишь, что максимальная скорость оцифровки ограничена.
Столбчатый индикатор отображает входное напряжение в виде столбца светящихся сегментов (или просто отдельных излучателей), что очень полезно для всяких индикаторов, примерами могут являться столбчатые индикаторы уровня записи (ИУЗ).
Код программы приведен ниже:
/*****************************************************
Chip type : ATmega8
Program type : Application
AVR Core Clock frequency: 4.000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 256
*****************************************************/
#include <mega8.h>
#include <delay.h>
#define ADC_VREF_TYPE 0x40 //5V Vcc + C 4.7uF AREF
//PD0 LED1
//PD1 LED2
//PD2 LED3
//PD3 LED4
//PD4 LED5
//PD5 LED6
//PD6 LED7
//PD7 LED8
//PB0 LED9
//PB1 LED10
//PB2 LED11
//PB3 LED12
//PB4 LED13
//PB5 LED14
//PC4 LED15
//PC5 LED16
const
unsigned char PD[17]=
{
0b00000000, //0
0b00000001, //1
0b00000011, //2
0b00000111, //3
0b00001111, //4
0b00011111, //5
0b00111111, //6
0b01111111, //7
0b11111111, //8
//_____________
0b11111111, //9
0b11111111, //10
0b11111111, //11
0b11111111, //12
0b11111111, //13
0b11111111, //14
0b11111111, //15
0b11111111 //16
};
unsigned char PB[17]=
{
0b00000000, //0
0b00000000, //1
0b00000000, //2
0b00000000, //3
0b00000000, //4
0b00000000, //5
0b00000000, //6
0b00000000, //7
0b00000000, //8
//_____________
0b00000001, //9
0b00000011, //10
0b00000111, //11
0b00001111, //12
0b00011111, //13
0b00111111, //14
//_____________
0b00111111, //15
0b00111111 //16
};
// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}
void ADC_init()
{
// ADC initialization
// ADC Clock frequency: 125.000 kHz
// ADC Voltage Reference: Vcc, cap. on AREF
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x85;
}
void Decode(int signal)
{
PORTD=PD[signal];
PORTB=PB[signal];
if (signal==15) {PORTC |= 0b00010000;PORTC &= 0b11011111;}
else if (signal==16) {PORTC |= 0b00110000;}
else {PORTC &= 0b11001111;}
}
void SetupIO ()
{
// Input/Output Ports initialization
PORTB=0b00000000;
DDRB= 0b00111111;
PORTC=0b00001100;
DDRC= 0b00110000; //PC0,PC1 = ADC0,ADC1, PC2,PC3 setup pins with PUP
PORTD=0x00;
DDRD=0xFF;
}
void main(void)
{
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
SetupIO();
ADC_init();
while (1)
{
Decode(read_adc(0)*0.049*0.32);
delay_ms(100);
};
}
Практически все приёмы, используемые в данном коде, были рассмотрены выше. Единственно хотелось бы отметить расширенную конструкцию с оператором if:
if () {} //если (условие соблюдается) то { }
else if () {} //иначе если (условие соблюдается) то { }
else {} //иначе { }
и выражение read_adc(0)*0.049*0.32
дело в том, что АЦП выдаёт свои значения по шкале 0-1023 (2^10), что соответствует шкале 0-5 вольт (т.к. опорное напряжение 5 вольт), а нам нужно получить сначала вольты, а потом перевести в количество сегментов. 1024*0.049*0.32=16 т.е. вся шкала АЦП, это 16 сегментов.
Число 0.049 взято кратным числу 5 вольт /1024 отсчёта =0.0048828 (~10 отсчётов АЦП), а потом домножено на 0.32 экспериментальным методом, чтобы получить зажигание последнего сегмента при нужном входном напряжении.
Последовательный порт.
А теперь предлагаю окунуться в мир интерфейсов. Самый простой и широко используемый до недавних пор последовательный протокол RS232, хоть и считается устаревшим, но всё ещё входит в состав выпускаемых современных микроконтроллеров - и не в количестве одного, как правило теперь их не менее 4-х. Также, многие устройства, всё еще используют данный интерфейс (например, некоторые экраны VFD NoritakeItron, медленные устройства для производств и т.п.). Данный пример позволяет оценить, насколько легко и просто настроить и использовать RS232 (USART) в микроконтроллерах.
Ниже приведен код, который осуществляет передачу символа 0.
/*****************************************************
Chip type : ATmega8
Program type : Application
AVR Core Clock frequency: 1.000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 256
*****************************************************/
#include <mega8.h>
// Standard Input/Output functions
//#include <stdio.h>
#define BAUDRATE 57600
#define BaudValue ((11059200UL/(BAUDRATE*16UL))-1)
void USART_Transmit(unsigned char data)
{
//{while ( !(UCSRA & (1<<UDRE)) ); //Ожидание опустошения буфера приема
UDR = data;
while( !(UCSRA & (1<<UDRE)) );
//UDR = data; //Начало передачи данных
}
void USART_init(void)
{
UBRRH = BaudValue >> 8;
UBRRL = BaudValue & 0xFF;
//
UCSRB=(1<<RXEN)|(1<<TXEN);
DDRD=0x02;
UCSRC = ( 1<<URSEL ) | ( 3<<UCSZ0 );
//UCSRA = (1<<U2X_Value);
}
void main(void)
{
ACSR=0x80;
SFIOR=0x00;
USART_init();
while (1) {USART_Transmit(0x30);};
}
Учтите, что Proteus не поддерживает эмуляцию UCSRC (установка параметров связи порта), поэтому установите частоту генератора 3500000, а в терминале поставьте следующие параметры:
Ниже приведен код, который осуществляет передачу символа 0.
/*****************************************************
Chip type : ATmega8
Program type : Application
AVR Core Clock frequency: 1.000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 256
*****************************************************/
#include <mega8.h>
// Standard Input/Output functions
//#include <stdio.h>
#define BAUDRATE 57600
#define BaudValue ((11059200UL/(BAUDRATE*16UL))-1)
void USART_Transmit(unsigned char data)
{
//{while ( !(UCSRA & (1<<UDRE)) ); //Ожидание опустошения буфера приема
UDR = data;
while( !(UCSRA & (1<<UDRE)) );
//UDR = data; //Начало передачи данных
}
void USART_init(void)
{
UBRRH = BaudValue >> 8;
UBRRL = BaudValue & 0xFF;
//
UCSRB=(1<<RXEN)|(1<<TXEN);
DDRD=0x02;
UCSRC = ( 1<<URSEL ) | ( 3<<UCSZ0 );
//UCSRA = (1<<U2X_Value);
}
void main(void)
{
ACSR=0x80;
SFIOR=0x00;
USART_init();
while (1) {USART_Transmit(0x30);};
}
Учтите, что Proteus не поддерживает эмуляцию UCSRC (установка параметров связи порта), поэтому установите частоту генератора 3500000, а в терминале поставьте следующие параметры:
суббота, 8 сентября 2012 г.
Детектор скрытой проводки
Привет всем.
Проводка вещь важная, и делать ремонт надо всегда аккуратно, вешаешь ли ты полку или делаешь шкаф-купе, или просто картину надо "примостить". Беда в том что проводка в наших домах в большинстве случаев, несмотря на все ГОСТы и т.д., "лежит как ей угодно" (или тому, кто её делал), иногда даже под углом 45 градусов (чтобы сэкономить несколько граммов меди или алюминия) и выяснить, как именно она проложена без экстрасенса порой не представляется возможным. Но выход всё-таки есть - воспользоваться детектором проводки. Что же такое - детектор проводки? Это прибор который улавливает на антенну электрическое или магнитное поле (или электромагнитные волны) проводника находящегося под напряжением (или подключенному к фазному проводу).
В интернете полно схем таких приборов, основанных на КМОП логике (К176ЛЕ5, К561ЛН1, К561ЛЕ5 и даже на счётчиках CD4017). Все эти схемы имеют ужасные недостатки: реагируют на любые частоты, кроме нужной (даже на мобильный телефон), могут быть легко повреждены статическим электричеством (особенно К176ЛЕ5 , которая не имеет защиты от ESD) и не позволяют производить регулировку "на ходу" в широких пределах, что часто необходимо при работе (проводка может быть расположена на разной глубине, и напряжение, а значит сила электро-магнитного поля может существенно колебаться в разных случаях.
На мой взгляд, для входной цепи детектора проводки идеален ОУ, т.к. он имеет приемлемые свойства и достаточно хорошую защиту от наводок, меньше логики боится ESD, и позволяет производить т.н. резонансное усиление, т.е. каскад на ОУ как правило содержит ещё и фильтр.
После долгих поисков с пристрастием я остановил свой выбор на схеме с ОУ К140УД1208 отсюда http://tehpoisk.ru/articles/schemiskatskrat. Это достаточно качественный и экономичный программируемый операционный усилитель для мобильных применений. Схема приведена на Рис.1:
Проводка вещь важная, и делать ремонт надо всегда аккуратно, вешаешь ли ты полку или делаешь шкаф-купе, или просто картину надо "примостить". Беда в том что проводка в наших домах в большинстве случаев, несмотря на все ГОСТы и т.д., "лежит как ей угодно" (или тому, кто её делал), иногда даже под углом 45 градусов (чтобы сэкономить несколько граммов меди или алюминия) и выяснить, как именно она проложена без экстрасенса порой не представляется возможным. Но выход всё-таки есть - воспользоваться детектором проводки. Что же такое - детектор проводки? Это прибор который улавливает на антенну электрическое или магнитное поле (или электромагнитные волны) проводника находящегося под напряжением (или подключенному к фазному проводу).
В интернете полно схем таких приборов, основанных на КМОП логике (К176ЛЕ5, К561ЛН1, К561ЛЕ5 и даже на счётчиках CD4017). Все эти схемы имеют ужасные недостатки: реагируют на любые частоты, кроме нужной (даже на мобильный телефон), могут быть легко повреждены статическим электричеством (особенно К176ЛЕ5 , которая не имеет защиты от ESD) и не позволяют производить регулировку "на ходу" в широких пределах, что часто необходимо при работе (проводка может быть расположена на разной глубине, и напряжение, а значит сила электро-магнитного поля может существенно колебаться в разных случаях.
На мой взгляд, для входной цепи детектора проводки идеален ОУ, т.к. он имеет приемлемые свойства и достаточно хорошую защиту от наводок, меньше логики боится ESD, и позволяет производить т.н. резонансное усиление, т.е. каскад на ОУ как правило содержит ещё и фильтр.
После долгих поисков с пристрастием я остановил свой выбор на схеме с ОУ К140УД1208 отсюда http://tehpoisk.ru/articles/schemiskatskrat. Это достаточно качественный и экономичный программируемый операционный усилитель для мобильных применений. Схема приведена на Рис.1:
Рис.1 - Искатель скрытой проводки на КР140УД1208 со световой и звуковой индикацией
После некоторых раздумий удалил правую часть схемы как ненужную и неэкономную в плане применения элементов логики.
Рис.2 -
Искатель скрытой проводки на КР140УД1208
Вот так-то лучше, - подумал я и собрал схему (слева на макетке).
Но...Оказалось что по свечению светодиода не совсем просто определить (измерить) максимум поля от провода, вернее - то место, где находится сам провод. Зона, где светодиод из-за своей нелинейности светится практически одинаково, довольно-таки большая (сантиметра 3...5), с помощью ручки "чувствительность" и карандаша (водим по стене и рисуем метки) это более-менее можно устранить, но работать (особенно когда тебя ждут километры проводки) не совсем удобно, поэтому возникла идея добавить к этому творению столбчатый индикатор (вольтметр) на A227D (отечественный аналог К1003ПП1) или на микроконтроллере ATTiny15L http://radiokot.ru/circuit/audio/other/14/, которую я нашёл в интернете и тут же подправил "под свои нужды":
Рис.3 - Индикатор уровня сигнала на ATTiny15L (доработка, автор - Робин ван Aрем)
В этой схеме рекомендую также не забывать ставить конденсаторы 100нФ по питанию.
Однако, её я так и не собрал-в моих запасах "Тиньки" не обнаружилось. Решил я по-народному на ATMega8 собрать.
На беду мне под руку попался немецкий индикатор VQC10, и вот что получилось.
По-быстрому на макетке соорудил схему.
Это она же в протеусе (за неимением модели VQC10 - заменил рассыпучкой)
Вид на самодельный AVR910.
Это то, что я планировал отображать на дисплее.
Продолжение следует...
Подписаться на:
Сообщения (Atom)