📜 ⬆️ ⬇️

A simple oscilloscope for 1 day

Hello!
Well, I have no money for a normal oscilloscope (and a normal camera). So do not fight much.
But there were 500 rubles per screen and a simple 8-bit microcontroller.

A short description under the cut.


It all started with the fact that I had a graphical LCD screen WG12864B from WINSTAR in my hands. 128x64 pixels, monochrome. I have never worked with them, it was interesting to understand it (I like to dig into datasheets, especially on the Cortex M4 controllers of 1,400 pages).

The control turned out to be very simple, it seemed to me easier than the control of character LCD screens. The main initial difficulty arose only in the fact that the screen is divided into 2 independent parts 64x64, each of which is controlled by its own controller. I will not write about management, there are a lot of different articles and libraries on the Internet.
')
Duck here. I brought the picture, I was glad, showed my mother. What to do next, sort of figured out the screen, then drawing pictures is already boring. I decided to make an oscilloscope, because I do not have it, and probably will not be there for a long time. And then I immediately remembered one function of this screen, the "Starting Line of the Display." It serves as a memory offset, so to speak. If you store a pixel at the point (0,0) and make a start line, for example, 5, the point will be visible on the screen 5 lines horizontally. It seemed to me a solution to the problem of image shift instead of redrawing it.

I decided that I would move one half of the screen along with the image of the signal, and the second one would show different information: voltage and all that.
The logic is simple. Erase the line (the old point that wants to crawl to the right when shifting more than 64 points), build the point equivalent to the voltage, move the image 1 pixel to the left. The effect of the connected points was first thought to be done through the Brezenham algorithm, but then I thought that we were shifting only 1 pixel and the lines would be vertical.

Amplitude value is determined by the formula:
amp = 63- (8-bit value from the ADC) shifted by 2 digits to the right;

I did all this in an infinite loop, I started it, and ... I did not see anything. Added a delay of 100ms and got the image that is visible in the video. When reducing the delay, the image becomes indistinct. Then I felt sad, because signals with a frequency above 10 Hz become completely indistinguishable. This is all due to the screen shift method. If you erase the screen and record information in blocks, rather than pixels, as I did, the image quality will greatly improve and speed up the rendering. But to do it was, honestly, reluctant, especially in the session. And I left everything as it is.

At the bottom of the screen, I drew a timeline, signed a segment. The voltage scale had to be done on the lower screen, since it is difficult to make a non-moving scale on the shifting screen, all the more so that it can be seen normally.

Here is a picture to make it easier to navigate:
image

At the moment we have 3 volts. Who cares, the sine did on the DAC MK Cortex M4 with a period of slightly more than 3 seconds. The screen shows that a couple of values ​​did not count at the peak.

Doot. And the place is still left and I added a couple of digital channels. They work on interruptions and a little bit faster than analog, since it is a bit different way: they displayed the signal from left to right, erased it, displayed it again. Here you can view the digital signal with a frequency of less than 50 Hertz. For example, check the performance of some slow interface. Very slow :)

In general, all told. Suggestions and feedback in the comments. Just don’t throw a balagan, better buy me an oscilloscope)
Happiness to all.

UPDATE1: Thank you all for the criticism, after the session I will try to take the program and the hardware more seriously, relying on your comments.

UPDATE2: Here is the code for the atmel studio for the ATMega168 microcontroller, which contains procedures for working with a graphic screen, the handling of timer interrupts and digital inputs.
View code
#include <avr/io.h> #define F_CPU 8000000 #include <util/delay.h> #include <avr/interrupt.h> #define ClearBit(reg, bit) reg &= (~(1<<(bit))) #define SetBit(reg, bit) reg |= (1<<(bit)) #define nCS1 0 #define nCS2 1 #define NRST 4 #define DI 5 #define E 4 #define RW 5 #define clrcs PORTD|=(1<<nCS1)|(1<<nCS2) #define setcs1 PORTD&=~(1<<nCS1) #define setcs2 PORTD&=~(1<<nCS2) #define sete PORTD|=(1<<E) #define clre PORTD&=~(1<<E) #define setdi PORTC|=(1<<DI) #define clrdi PORTC&=~(1<<DI) #define setrst PORTC&=~(1<<NRST) #define clrrst PORTC|=(1<<NRST) #define setrw PORTD|=(1<<RW) #define clrrw PORTD&=~(1<<RW) void sendbyte(char b) { PORTB=b; sete; _delay_us(1); clre; _delay_us(5); } void SetXY(int x,int y,int c) { char h=PIND; if (c&0x1) setcs1; if (c&0x2) setcs2; clrdi; sendbyte(0xB8+x); sendbyte(0X40+y); PORTD=h; } void initglcd() { _delay_ms(50); clrdi; clrcs; setrst; _delay_us(10); clrrst; setcs1; setcs2; sendbyte(0xC0); sendbyte(0x3F); SetXY(0,0,3); } void sendi(char b,char c) { if (c&0x1) setcs1; if (c&0x2) setcs2; setdi; sendbyte(b); clrdi; clrcs; } unsigned char readbyte(char c) { setdi; setrw; if (c&0x1) setcs1; if (c&0x2) setcs2; DDRB=0x00; _delay_us(1); sete; _delay_us(1); clre; _delay_us(5); sete; _delay_us(1); unsigned char x=PINB; clre; DDRB=0xff; clrcs; clrdi; clrrw; return x; } void clearglcd(char c) { for(int j=0; j<=7;j++){ SetXY(j,0,3); for(int i=0;i<=63;i++)sendi(0x00,c); } SetXY(0,0,3); } void fillglcd(char c) { for(int j=0; j<=7;j++){ SetXY(j,0,3); for(int i=0;i<=63;i++)sendi(0xff,c); } SetXY(0,0,3); } void putpixel(char x, char y) { cli(); if (x<64) { SetXY(y/8,x,1); unsigned char t=readbyte(1); SetXY(y/8,x,1); sendi(t|(1<<(y%8)),1); } else { SetXY(y/8,x-64,2); unsigned char t=readbyte(2); SetXY(y/8,x-64,2); sendi(t|(1<<(y%8)),2); } sei(); } void clearpixel(char x, char y) { cli(); if (x<64) { SetXY(y/8,x,1); unsigned char t=readbyte(1); SetXY(y/8,x,1); sendi(t&(~(1<<(y%8))),1); } else { SetXY(y/8,x-64,2); unsigned char t=readbyte(2); SetXY(y/8,x-64,2); sendi(t&~((1<<(y%8))),2); } sei(); } int ff=63; int hh=0; int asd=0; int asd1=0; int pred=0; int pred1=0; int oldd=63; int oldd1=63; ISR(TIMER0_OVF_vect) { hh++; if (hh==2) { hh=0; if (ff==0) { ff=63; oldd=63; oldd1=63; for(int k=0;k<=63;k++) clearpixel(100,k); for(int k=0;k<=63;k++) clearpixel(101,k); for(int k=0;k<=63;k++) clearpixel(102,k); for(int k=0;k<=63;k++) clearpixel(103,k); for(int k=0;k<=63;k++) clearpixel(104,k); for(int k=0;k<=63;k++) clearpixel(105,k); for(int k=0;k<=63;k++) clearpixel(115,k); for(int k=0;k<=63;k++) clearpixel(116,k); for(int k=0;k<=63;k++) clearpixel(117,k); for(int k=0;k<=63;k++) clearpixel(118,k); for(int k=0;k<=63;k++) clearpixel(119,k); for(int k=0;k<=63;k++) clearpixel(120,k); } else ff--; if (asd==1) { if (pred==0) { if (ff<oldd)for(int k=oldd;k>=ff;k--) putpixel(100,k); putpixel(101,ff); putpixel(102,ff); putpixel(103,ff); putpixel(104,ff); putpixel(105,ff); pred=asd; oldd=ff; } } else { if (pred==1) { if (ff<oldd) for(int k=oldd;k>=ff;k--) putpixel(105,k); putpixel(101,ff); putpixel(102,ff); putpixel(103,ff); putpixel(104,ff); putpixel(100,ff); pred=asd; oldd=ff; } } if (asd1==1) { if (pred1==0) { if (ff<oldd1)for(int k=oldd1;k>=ff;k--) putpixel(115,k); putpixel(116,ff); putpixel(117,ff); putpixel(118,ff); putpixel(119,ff); putpixel(120,ff); pred1=asd1; oldd1=ff; } } else { if (pred1==1) { if (ff<oldd1) for(int k=oldd1;k>=ff;k--) putpixel(120,k); putpixel(116,ff); putpixel(117,ff); putpixel(118,ff); putpixel(119,ff); putpixel(115,ff); pred1=asd1; oldd1=ff; } } } } ISR(INT0_vect) { if (PIND&0x04) { asd=1; } else { asd=0; } } ISR(INT1_vect) { if (PIND&0x08) { asd1=1; } else { asd1=0; } } int main(void) { DDRC=0x3C; DDRD=0x33; DDRB=0xff; PORTD=0x00; initglcd(); clearglcd(1); for (int j=0;j<=127;j++) for(int i=0;i<=63;i++) putpixel(j,i); for (int j=0;j<=127;j++) for(int i=0;i<=63;i++) clearpixel(j,i); ADCSRA|=(1<<ADEN)|(0<<ADIE)|(1<<ADSC)|(1<<ADATE)|(1<<ADPS0); ADMUX=0x60; for(int k=0;k<=63;k++) putpixel(66,k); //OX putpixel(65,56); putpixel(67,56); putpixel(65,46); putpixel(67,46); putpixel(65,36); putpixel(67,36); putpixel(65,26); putpixel(67,26); putpixel(65,16); putpixel(67,16); putpixel(65,6); putpixel(67,6); for(int k=6;k<=56;k++) putpixel(84,k); //OY putpixel(83,56); putpixel(85,56); putpixel(83,46); putpixel(85,46); putpixel(83,36); putpixel(85,36); putpixel(83,26); putpixel(85,26); putpixel(83,16); putpixel(85,16); putpixel(83,6); putpixel(85,6); putpixel(87,56); //0 putpixel(88,57); putpixel(88,55); putpixel(89,57); putpixel(89,55); putpixel(90,57); putpixel(90,55); putpixel(91,56); putpixel(87,46); //1 putpixel(88,46); putpixel(89,46); putpixel(90,46); putpixel(91,46); putpixel(88,47); putpixel(87,36); //2 putpixel(87,37); putpixel(87,35); putpixel(88,35); putpixel(89,35); putpixel(89,36); putpixel(89,37); putpixel(90,37); putpixel(91,37); putpixel(91,36); putpixel(91,35); putpixel(87,27); //3 putpixel(87,26); putpixel(87,25); putpixel(88,25); putpixel(89,25); putpixel(89,26); putpixel(89,27); putpixel(90,25); putpixel(91,25); putpixel(91,26); putpixel(91,27); putpixel(87,17); //4 putpixel(87,15); putpixel(88,17); putpixel(88,15); putpixel(89,17); putpixel(89,15); putpixel(89,16); putpixel(90,15); putpixel(91,15); putpixel(87,6); //5 putpixel(87,7); putpixel(87,5); putpixel(88,7); putpixel(89,5); putpixel(89,6); putpixel(89,7); putpixel(90,5); putpixel(91,7); putpixel(91,6); putpixel(91,5); putpixel(68,53); //1 putpixel(69,53); putpixel(70,53); putpixel(71,53); putpixel(72,53); putpixel(69,54); putpixel(68,48); //s putpixel(68,50); putpixel(68,49); putpixel(69,51); putpixel(70,50); putpixel(70,49); putpixel(71,48); putpixel(72,49); putpixel(72,50); putpixel(72,51); for(int k=0;k<=63;k++) putpixel(95,k); for(int k=0;k<=63;k++) putpixel(94,k); for(int k=0;k<=63;k++) putpixel(111,k); putpixel(110,35); putpixel(112,35); putpixel(110,63); putpixel(112,63); putpixel(110,7); putpixel(112,7); EICRA=0x05; EIMSK=0x03; TIMSK0=0x01; TCCR0B=0x04; sei(); unsigned char i=0; int x=0; int y=0; bool b=0; unsigned char old,news,news2; unsigned char adcc; old=63; while(1){ for(int k=0;k<=63;k++) clearpixel(k,y); for(int k=56;k>=6;k--) clearpixel(80,k); for(int k=56;k>=6;k--) clearpixel(81,k); adcc=ADCH; news=63-adcc*64/255; news2=adcc*50/255; for(int k=56;k>=56-news2;k--) putpixel(80,k); for(int k=56;k>=56-news2;k--) putpixel(81,k); if (news<=old) for(int h=old;h>=news;h--) putpixel(h,y); else for(int h=old;h<=news;h++) putpixel(h,y); old=news; y--; if (++x==4) {PORTC^=0x08; x=0;} if (x%2==1) PORTC^=0x04; if (y<0) y=63; setcs1; sendbyte(0xC0+i); if (i==0) i=63; else i--; _delay_ms(97); } } 

Source: https://habr.com/ru/post/165611/


All Articles