czwartek, 30 marca 2017

Mikrofonowanie kondensatorów ceramicznych w oscyloskopie


Drgania mechaniczne przenoszone z konstrukcji oscyloskopu na kondensatory ceramiczne wewnątrz oscyloskopu powoduja zmiane pojemnosci kondensatora. Powoduje to zmiane wartosci napiec na kondensatorach i widoczny sygnal na ekranie oscyloskopu.
Problem dla roznych oscyloskopow jest pokazany w filmiku ponizej. 


Mi nie udało się wyzwolić oscyloskopu na tym sygnale niestety. Nie jest on zbyt podatny na stukanie w obudowę. Jedynie małą wartość sygnału udało mi się zarejestrować w trybie scan, kiedy bezpośrednio ostro tłukłem w BNC.

środa, 29 marca 2017

Prosta biblioteka do obsługi sterownika LCD HD44780 dla mikrokontrolerów PIC



Z braku dobrze działających i prostych w użyciu bibliotek postanowiłem napisać swoją, jak najprostszą w pisaniu i użyciu.

Poniżej umieściłem zestaw funkcji z biblioteki. Działa ona w 4-bitowym interfejsie z odczytem flagi BF. Można podpiąć RW wyświetlacza do masy i wtedy trzeba zastąpić funkcję busy opóźnieniem około 50us.

void BUS_set(unsigned char dataToSet){
    LCD_DATA4_LAT = (dataToSet & ( 1 << 0 )) >> 0;  
    LCD_DATA5_LAT = (dataToSet & ( 1 << 1 )) >> 1;   
    LCD_DATA6_LAT = (dataToSet & ( 1 << 2 )) >> 2;   
    LCD_DATA7_LAT = (dataToSet & ( 1 << 3 )) >> 3;   
}

void BUS_write(unsigned char dataToWrite){
LCD_RW_LAT = LOW;

LCD_E_LAT = HIGH;
BUS_set(dataToWrite >> 4);
LCD_E_LAT = LOW;

LCD_E_LAT = HIGH;
BUS_set(dataToWrite);
LCD_E_LAT = LOW;

while(LCD_busy());

}

void LCD_command(unsigned char commandToWrite){
LCD_RS_LAT = LOW;
BUS_write(commandToWrite);
}

void LCD_data(unsigned char dataToWrite)
{
LCD_RS_LAT = HIGH;
BUS_write(dataToWrite);
}

void LCD_text(char * text)
{
while(*text)
LCD_data(*text++);
}

void LCD_fills(unsigned char j)
{
while(j > 0){
LCD_data(0xFF);
j--;
}
}

void LCD_clear(void)
{
LCD_command(0x01);
delay(2);
}

void LCD_home(void)
{
LCD_command(0x02);
delay(2);

}

void LCD_pos(unsigned char row, unsigned char position)
{
    if(row == 0){
        LCD_command(0x80);
        while(position > 0){
            LCD_command(0x14);
            position--;
        }
    } else {
        LCD_command(0xC0);
        while(position > 0){
            LCD_command(0x14);
            position--;
        }
    }
}

void LCD_int(unsigned long  tmp){
char buffer[16]; 
sprintf(buffer,"%ld", tmp);
LCD_text(buffer);

}

void LCD_float(double  tmp){
char buffer[16]; 
sprintf(buffer,"%.3f", tmp);
LCD_text(buffer);
}


void LCD_initalize(void)
{
LCD_RW_DIR = OUTPUT;
LCD_E_DIR = OUTPUT;
LCD_RS_DIR = OUTPUT;
LCD_BUS_OUTPUT;
delay(15); 
LCD_RW_LAT = LOW;
LCD_RS_LAT = LOW;
LCD_E_LAT = HIGH;

for(unsigned char i = 0; i < 3; i++)
  {
  LCD_E_LAT = HIGH;
  BUS_set(0x03);
  LCD_E_LAT = LOW;
  delay(5);
  }

  LCD_E_LAT = HIGH;
  BUS_set(0x02);
  LCD_E_LAT = LOW;
  delay(1);


   LCD_command(40);
   LCD_command(1);
   delay(2);

   LCD_command(12);
   LCD_command(1);
   delay(5);
}

unsigned char LCD_busy(){
LCD_BUS_INPUT;
LCD_RW_LAT = HIGH;
LCD_RS_LAT = LOW;
unsigned char bf = LCD_DATA7_REA;
LCD_RW_LAT = LOW;
LCD_RS_LAT = LOW;
LCD_BUS_OUTPUT;
return bf;
}

Przekładnik prądowy z filtra przeciwzakłóceniowego



Nawinąłem na otwierany rdzeń ferrytowy 300 zwojów najcieńszego drutu nawojowego jakiego znalazłem.


Po podłączeniu lutownicy ok 40W i rezystora próbkującego na oscyloskopie pokazał mi się sygnał o Vpp około 30mV. Odpowiednio zmieniając rezystor na wyjściu przekładnika możnaby otrzymać żądaną zależność pomiędzy prądem a napięciem na wyjściu przekładnika. 







piątek, 24 marca 2017

Sprzężenie pojemnościowe - bezprzewodowy przesył energii elektrycznej




Podłączyłem pod płytkę MPLAB Xpress dwie elektrody zrobione z folii aluminiowej przyklejonej do plastikowej folii. Na nie położyłem dwie następne elektrody, podłączone bezpośrednio do diody LED. Na piny z podłączonymi elektrodami piściłem sygnał różnicowy prostokątny o częstotliwości niecałych 2MHz. Jakaś moc przepływała do diody bo jak widać się świeciła, jednak aby przesłać jej więcej należałoby zwiększyć częstotliwość sygnału aby przypominał on bardziej sinusoidę a nie prostkąt. Taśmy były po to potrzebne żeby zwiększyć nieco siłę nacisku elektrod.





Mini przetworniczka 3V na 12V

Schemat z noty katalogowej MC34063. Cewka dobrana oscyloskopem.



Pomysł na przekształtnik symetryczny podwyższający

Pomysł na wykonanie symetrycznego zasilacza np. do opampów +/- 12V np z akumulatorka Li-ion.


Zegar binarny




Zegar wykonałem na mikrokontrolerze PIC12F1840 i rejestrach szeregowych sterujących diodami. Poszczególne kolumny diod wyświetlają cyfry. Całość jest taktowana eksperymentalnie kwarcem 16MHz zamiast 32kHz. Schemat poniżej.




Płytka wykonana chałupniczo, jak najszybciej i bez pomyślunku niestety bo wypadałoby dodać parę rzeczy.







Program zegara jest bardzo prosty, konfiguracja IO i peryferiów mikrokontrolera została graficznie wykonana w MCC a reszta napisana przez mnie. Poniżej zawartość pliku main.c Nawet nie chciało mi sie konfigurować sprzętowego SPI do sterowania rejestrem więc zbitbangowałem go funkcją podobną do shiftOut z arduino. W godzinach od 21-7 rano zegar świeci około 10% mocy z jaką świeci w ciągu dnia. Brzydko to jest dość napisane ale mój czas jest zbyt cenny żeby marnować go na poprawianie głupiego zegarka 



#include "mcc_generated_files/mcc.h"

char setting = 0;
char ms = 0;
char s = 0;
char m = 0;
char h = 0;
char b1, b2;
void shiftOut(char val)
{
 
    for (char i = 0; i < 8; i++)  {
     
     
        LATA0 = !!(val & (1 << (7 - i)));
        SCK_SetHigh();
        SCK_SetLow();
       
    }
}
void shift(char byte1, char byte2){
     nSS_SetLow();
     
        shiftOut(byte1);
        shiftOut(byte2);
     
        nSS_SetHigh();
}
void checkTime(){
    if(ms > 9){ ms = 0; s++;}
    if(s > 59){ s = 0; m++; }
    if(m > 59){ m = 0; h++; }
    if(h > 23){ h = 0; m = 0; s = 0; ms = 0;}
   
}
void timer0interrupt(){
    ms++;
    checkTime();
}
void delay(unsigned int mss){
    while(mss > 1){
        __delay_ms(1);
        mss--;
    }
}
void prepareBuffer(){
   
     char h10, h1, m10, m1;
   
    h10 = h / 10;
        h1 = h % 10;
        m10 = m /10;
        m1 = m % 10;
     
        if(m10 & (1<<0)) b2 = b2 | (1<<0); else b2 &= ~(1<<0);
        if(m10 & (1<<1)) b2 = b2 | (1<<1); else b2 &= ~(1<<1);
        if(m10 & (1<<2)) b2 = b2 | (1<<2); else b2 &= ~(1<<2);
       
        if(m1 & (1<<0)) b2 = b2 | (1<<3); else b2 &= ~(1<<3);
        if(m1 & (1<<1)) b2 = b2 | (1<<4); else b2 &= ~(1<<4);
        if(m1 & (1<<2)) b2 = b2 | (1<<5); else b2 &= ~(1<<5);
        if(m1 & (1<<3)) b2 = b2 | (1<<6); else b2 &= ~(1<<6);
       
        if(h10 & (1<<0)) b1 = b1 | (1<<0); else b1 &= ~(1<<0);
        if(h10 & (1<<1)) b1 = b1 | (1<<1); else b1 &= ~(1<<1);
       
        if(h1 & (1<<0)) b1 = b1 | (1<<2); else b1 &= ~(1<<2);
        if(h1 & (1<<1)) b1 = b1 | (1<<3); else b1 &= ~(1<<3);
        if(h1 & (1<<2)) b1 = b1 | (1<<4); else b1 &= ~(1<<4);
        if(h1 & (1<<3)) b1 = b1 | (1<<5); else b1 &= ~(1<<5);
       
}
void buttonHandler(){
    if(BUTTON_GetValue() == 0){
        unsigned int cnt = 0;
        while(BUTTON_GetValue() == 0){
            __delay_ms(1);
            cnt++;
            if(cnt > 3500){
                shift(0xFF, 0xFF);
            }
        }
       
        if(cnt > 3500){
            if(setting == 1) setting = 0; else setting = 1;
        } else
            if(cnt < 1500 && cnt > 100){
               
       INTERRUPT_GlobalInterruptDisable();
       prepareBuffer();
       shift(b2, b1);
       delay(10);
       if(setting == 0){
           s = 0;
           ms = 0;
        h++;
        if(h > 23) h = 0;
       } else {
           s = 0;
           ms = 0;
         m++;
        if(m > 59) m = 0;
       }
        prepareBuffer();
       shift(b2, b1);
       delay(200);
       
       
        INTERRUPT_GlobalInterruptEnable();
   
            }
    }
}

void main(void)
{
 
    SYSTEM_Initialize();
TMR1_SetInterruptHandler(&timer0interrupt);
INTERRUPT_GlobalInterruptEnable();
INTERRUPT_PeripheralInterruptEnable();
   
   
 

    while (1)
    {
     
     
       
       prepareBuffer();
     
      if(s % 2 == 1) b2 = b2 | (1<<7); else b2 &= ~(1<<7);
      if(setting == 1) b1 &= ~(1<<7); else  b1 |= (1<<7);
      if(setting == 0) b1 &= ~(1<<6); else  b1 |= (1<<6);  
   
       if(h < 7 || h > 21){
           b2 &= ~(1<<7);
           if(s % 2 == 1) b1 &= ~(1<<7); else  b1 |= (1<<7);
       }
     
       buttonHandler();
     
       if(h < 7 || h > 21){
       shift(0x00,0x00);
       __delay_us(90);
        shift(b2, b1);
        __delay_us(10);
        shift(0x00,0x00);
       
       } else {
           shift(b2, b1);
       }
       
    }
}






Zegar na wyświetlaczu 7 segmentowym


Projekt został wykonany na mikrokontrolerze PIC i rejestrze szeregowym używanym do sterowania katodami zegara. Schemat zegara jest widoczny poniżej.


Płytkę wykonywałem i projektowałem jak najszybciej i bez zbędnych, dodatkowych elementów takich jak papier kredowy :) wystarczy gazeta. Płytka wyszła beznadziejna ale działała a to najważniejsze.




Program do mikrokontrolera pisałęm w MPLABie, też jak najszybciej i na odwał. Głównie zależało mi na tym aby działał. Do konfiguracji mikrokontrolera użyłem Microchip Code Configurator.

Miałem dorzucić jeszcze zmianę jasności zależnie od oświetlenia zewnętrznego ale wyświetlacz jest wystarczająco ciemny przez nieco za duże oporniki w stosunku do jego jakości ;)

#include "mcc_generated_files/mcc.h"
unsigned int s = 0;
unsigned int m = 0;
unsigned int h = 0;
char check_flag = 1;


char digits[10];
char number[4];

void checkTime(){
    if(check_flag == 1){
    if(s > 59){ s = 0; m++; }
    if(m > 59){ m = 0; h++; }
    if(h > 23){ h = 0; m = 0; s = 0;}
    }
}
void timer_int(){
   
    s++;
    checkTime();
   
   
}
void numbersToDisplay(unsigned int value, unsigned int value2){
   
  char digit = value % 10;
  number[3] = digits[digit];
  value /= 10;
  digit = value % 10;
  number[2] = digits[digit];
  value /= 10;
 
 
  digit = value2 % 10;
  number[1] = digits[digit];
  value2 /= 10;
 
  digit = value2 % 10;
  number[0] = digits[digit];
  value2 /= 10;
 
}

void multiplex(unsigned int times){
  for(int i = 0;i < times;i++){
        ANODE4_SetHigh();
        ANODE3_SetHigh();
        ANODE2_SetHigh();
        ANODE1_SetHigh();
   
       
ANODE1_SetLow();      
LATCH_SetLow();
SPI_Exchange8bit(number[0] & 0b11111110);
LATCH_SetHigh();
__delay_ms(3);
ANODE1_SetHigh();
     

ANODE2_SetLow();      
LATCH_SetLow();
SPI_Exchange8bit(number[1]);
LATCH_SetHigh();
__delay_ms(3);
ANODE2_SetHigh();
 

ANODE3_SetLow();      
LATCH_SetLow();
SPI_Exchange8bit(number[2] );
LATCH_SetHigh();
__delay_ms(3);
ANODE3_SetHigh();
   

ANODE4_SetLow();      
LATCH_SetLow();
SPI_Exchange8bit(number[3]);
LATCH_SetHigh();
__delay_ms(3);
ANODE4_SetHigh();
   
  }
 
}
void driveLEDs(unsigned int periods_number){
        checkTime();
        numbersToDisplay(m,h);
        if(s % 2 == 1) number[2] &= 0b11111110;
        multiplex(periods_number);
   
}
void debug1(unsigned int periods_number){
        //checkTime();
        numbersToDisplay(0,88);
        if(s % 2 == 1) number[2] &= 0b11111110;
        multiplex(periods_number);
   
}
void buttons(){
   
    if(BUTTON1_GetValue() == 0){
        check_flag = 0;
       driveLEDs(5);
        m++;
        if(m > 59) m = 0;
        s = 0;
        driveLEDs(50);
       
       
       
            while(BUTTON1_GetValue() == 0){
           
                m++;
                if(m > 59) m = 0;
                driveLEDs(10);
                 s = 0;
        }
    }
   
    if(BUTTON2_GetValue() == 0){
       check_flag = 0;
       driveLEDs(10);
        h++;
        if(h > 23) h = 0;
        driveLEDs(50);
       
       
       
    }
    check_flag = 1;
}
void lightSensor(){
   
    ADC1_StartConversion(LDR);
    while(ADC1_IsConversionDone() == 0) driveLEDs(1);
    if(ADC1_GetConversionResult() < 716)
    EPWM1_LoadDutyValue(ADC1_GetConversionResult());
}
void main(void)
{
digits[0] = 0b10000001;
digits[1] = 0b11110011;
digits[2] = 0b01001001;
digits[3] = 0b01100001;
digits[4] = 0b00110011;
digits[5] = 0b00100101;
digits[6] = 0b00000101;
digits[7] = 0b11110001;
digits[8] = 0b00000001;
digits[9] = 0b00100001;
SYSTEM_Initialize();
INTERRUPT_GlobalInterruptEnable();
INTERRUPT_PeripheralInterruptEnable();
TMR1_SetInterruptHandler(&timer_int);
TRISC5 = 0;
LATC5 = 0;
//EPWM1_Initialize();
LATC5 = 0;
for(int i = 0;i < 4;i++) number[i] = 0x00;
multiplex(200);
for(int i = 0;i < 4;i++) number[i] = 0xFF;
multiplex(30);
LATC5 = 0;
    while (1)
    {
        //debug1(1);
      driveLEDs(20);
     buttons();
     //lightSensor();
      // EPWM1_LoadDutyValue(100);
     
    }
}










Nuda mnie do tego zmusiła


Przetwornik C/A z drabinki rezystorowej, sterowany licznikiem, który jest kluczowany przez generator sygnału zegarowego na NE555. Wyjściem tego układu jest sygnał trójkątny.

Jest to pewna namiastka generatora DDS (direct digital synthesis - bezpośrednia synteza cyfrowa), gdyby zamiast bramek i licznika dorzucić mikrokontroler, można byłoby uzyskać dowolne kształty funkcji.

Sygnał wysyłany przez NFC w telefonie


Bezpieczniczek

Wysokonapięciowa wkładka bezpiecznikowa "tylko" 40A.