Hlukomer: Rozdiel medzi revíziami
Zo stránky SensorWiki
| Bez shrnutí editace | Bez shrnutí editace | ||
| (39 medziľahlých úprav od rovnakého používateľa nie je zobrazených.) | |||
| Riadok 1: | Riadok 1: | ||
| Záverečný projekt predmetu MIPS / LS2023 - '''Sabadash''' | Záverečný projekt predmetu MIPS / LS2023 - '''Mykyta Sabadash''' | ||
| Riadok 10: | Riadok 10: | ||
| '''Literatúra:'''   | '''Literatúra:'''   | ||
| * [ | * [https://senzor.robotika.sk/sensorwiki/index.php/Acrob_technical_description Dokumentácia k doske Acrob] | ||
| * [https://senzor.robotika.sk/sensorwiki/index.php/A/D_prevodn%C3%ADk A/D prevodnik (mikrofon)] | |||
| * [https://senzor.robotika.sk/sensorwiki/index.php/A/D_prevodn%C3%ADk A/D prevodnik ( | |||
| * [https://senzor.robotika.sk/sensorwiki/index.php/LCD_displej_s_radi%C4%8Dom_HD44780 LCD display] | * [https://senzor.robotika.sk/sensorwiki/index.php/LCD_displej_s_radi%C4%8Dom_HD44780 LCD display] | ||
| Riadok 27: | Riadok 26: | ||
| [[Súbor:MIPS_ADC-Schema02.png|400px|thumb|center|Zapojovaci diagram pre A/D prevodnik.]] | [[Súbor:MIPS_ADC-Schema02.png|400px|thumb|center|Zapojovaci diagram pre A/D prevodnik.]] | ||
| [[Súbor:MSCHM.png|400px|thumb|center|Zapojovaci diagram pre Senzor zvuku.]] | |||
| === Algoritmus a program === | === Algoritmus a program === | ||
| Sme inicializujeme A/D prevodnik, inicializujeme LCD displej a overujeme spravnost ho zapojenia, ked je vsetko v pohode tak displej sa zapne a sa zacnu ukazovat tam data ktore sme tam posleme (ked ze sme tam nieco posleme). | Sme inicializujeme A/D prevodnik, inicializujeme LCD displej a overujeme spravnost ho zapojenia, ked je vsetko v pohode tak displej sa zapne a sa zacnu ukazovat tam data ktore sme tam posleme (ked ze sme tam nieco posleme). | ||
| Riadok 38: | Riadok 37: | ||
| Teraz, zadefinujeme riadok, "vypocitame" hodnotu ktoru chceme vidiet na displeji, a vypiseme to pomocou funkcie "sprintf()". | Teraz, zadefinujeme riadok, "vypocitame" hodnotu ktoru chceme vidiet na displeji, a vypiseme to pomocou funkcie "sprintf()". | ||
| A vypocitame nase Db | |||
| dB = 20 * log10(napatie_senzora / referencne_napatie) | |||
| Kde: | |||
|     * dB je vysledná hodnota v decibeloch | |||
|     * log10 je desiatkovy logaritmus | |||
|     * napatie_senzora je vstupne napätie senzora zvuku (value) | |||
|     * referencne_napatie je referencne napatie senzora (~3.3v) | |||
| A, pre lepsi vyhlad nasho hlukomeru pridame mu stupnicu hluku, ktoru vytvorime z ciernych stvorcekov a "pustych miest" (space key) | A, pre lepsi vyhlad nasho hlukomeru pridame mu stupnicu hluku, ktoru vytvorime z ciernych stvorcekov a "pustych miest" (space key) | ||
| Riadok 59: | Riadok 69: | ||
| <tab name="AVR C-code"><source lang="c++" style="background: LightYellow;"> | <tab name="AVR C-code"><source lang="c++" style="background: LightYellow;"> | ||
| #include <avr/io.h> | #include <avr/io.h> | ||
| #include "adc.h" | |||
| #include "uart.h" | |||
| #include "lcd_ch.h" | |||
| #include <stdio.h> | |||
| #include <avr/interrupt.h> | |||
| #include <util/delay.h> | |||
| #define LCD_CTRL_PORT DDRD | |||
| #define LCD_DATA_PORT DDRB | |||
| #define LCD_CLR               0      /* DB0: clear display                  */ | |||
| #define LCD_HOME              1      /* DB1: return to home position        */ | |||
| #define LCD_RS_pin 2 | |||
| #define LCD_RW_pin 3 | |||
| #define LCD_EN_pin 4 | |||
| #define LCD_D4_pin 1 | |||
| #define LCD_D5_pin 2 | |||
| #define LCD_D6_pin 3 | |||
| #define LCD_D7_pin 4 | |||
| FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); | |||
| int main(void) | int main(void) | ||
| { | { | ||
|  int pocitadlo =0; | |||
|  /* inicializacia a/d prevodnika*/ | |||
|    unsigned int measuredValue; |    unsigned int measuredValue; | ||
|   adc_init();                                          // Init A/D converter | |||
|   uart_init();  | |||
|   stdout =  &uart_stream; | |||
|   /* inicializacia portov - vstupy / vystupy */ | |||
| 	DDRD |= (1<<LCD_EN_pin);	// Pin D4 (Enable)  PORTD  output   | |||
| 	DDRD |= (1<<LCD_RW_pin);	// Pin D3 (RW)      PORTD  output   | |||
| 	DDRD |= (1<<LCD_RS_pin);	// Pin D2 (RS)      PORTD  output   | |||
| 	LCD_DATA_PORT |= (1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin);	// Piny 1,2,3,4, PORTB ako output (Data pre display) | |||
| 	/* displej je spravne pripojeny, mozeme zacat inicializaciu podla datasheetu */ | |||
| 	lcd_init();  // definiciu pozri v -> lcd_ch.h resp. lcd_ch.c | |||
| 	/* po ukonceni inicializacie je displej zapnuty a ak posleme nejake data, tak  | |||
| 	   sa zacnu zobrazovat od prvej pozicie (riadok 0, stlpec 0)               */ | |||
|   void lcd_puts(const char *s) | |||
| 	{ | |||
| 	register unsigned char c; | |||
| 	while((c = *s++))	lcd_data(c); // retazec konci "nulou" | |||
|     } | |||
|    while (1) |    while (1) | ||
|    { |    { | ||
|      / | |||
| 	  lcd_puts("Db  -->  ");                        // vystup co sa vypise na displeji | |||
|     measuredValue = adc_read(4);                        // hodnota ktoru nam 'hovori' a/d prevodnik (mikrofon) | |||
|     printf("%u\n",measuredValue);			// pre serial plot   | |||
|  _delay_ms(100); | |||
|       lcd_command(0x0C);                   // schovat kurzor | |||
| 	  char riadok[]= {"                "};	 | |||
|         int value = measuredValue - 350;   // premenna, ktorej hodnotu by sme chceli zobrazit na LCD (350 podla toho ze | |||
| 	                                   // je to akoby nulova velicina nasho 'kvalitneho' hlukomera, ked ze sa vypisuju zle hodnoty na displej | |||
|                                            // tak musime menit prave tuto hodnotu, aby nulovy hluk zodpovedal 'nule' na displeji) | |||
|         int db = log10(value/3.3); | |||
|           sprintf(riadok,"%d",db); | |||
| 	  int i = (value/12); | |||
| 	  int o = 16-i;                  // tu sme pocitame nase "stvorceky" pre stupnicu | |||
| 	  if (pocitadlo == 5)            // pocitadlo na vypisovanie dB jeden krat za 5 cyklusov programu,  aby bolo to prehliadne | |||
| 	  { | |||
| 	   lcd_puts(riadok);             // dB | |||
| 	   lcd_data(0x10);               // put space key | |||
| 	  pocitadlo =0; | |||
| 	   }  | |||
| 	   pocitadlo++;	   | |||
| 	   lcd_command(0xC0);            // prestup do noveho riadka | |||
| 	   for(i;i>0;i--)                // stupnica | |||
| 	   { | |||
| 		  lcd_data(0xFF);        // put ■ | |||
| 	    }		   | |||
| 		for(o;o>0;o--) | |||
| 	   { | |||
| 		  lcd_data(0x10);        // put space key | |||
| 	    }		  | |||
| 	  lcd_command(0x70);             // 0x10 (Cursor/display shift) + 0x20 (Function set) + 0x40 (Set CGRAM address) | |||
|       lcd_command(1<<LCD_HOME);  /* Set cursor to home position */ | |||
|    } |    } | ||
|    return(0); |    return(0); | ||
| } | } | ||
| </source></tab> | |||
| <tab name="adc.h"><source lang="c++" style="background: LightYellow;"> | |||
| <tab name=" | |||
| #include <avr/io.h> | #include <avr/io.h> | ||
| Riadok 80: | Riadok 187: | ||
| unsigned int adc_read(char a_pin); | unsigned int adc_read(char a_pin); | ||
| </source></tab> | </source></tab> | ||
| <tab name="adc.c"><source lang="c++" style="background: LightYellow;"> | |||
| #include <avr/io.h> | |||
| void adc_init (void){ | |||
| 	ADMUX = (1<<REFS0);	 | |||
| 	ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); | |||
| } | |||
| unsigned int adc_read(char a_pin){ | |||
| 	a_pin &= 0x07; | |||
| 	ADMUX = (ADMUX & 0xF8)|a_pin; | |||
| 	ADCSRA |= (1<< ADSC); | |||
| 	while ( ADCSRA & (1<< ADSC)); | |||
| 		return (ADC); | |||
| } | |||
| </source></tab> | |||
| <tab name="lcd_ch.h"><source lang="c++" style="background: LightYellow;"> | |||
| /* | |||
|  * lcd_ch.h | |||
|  * | |||
|  * Created: 3/10/2021 7:05:39 PM | |||
|  *  Author: Admin | |||
|  */  | |||
| #ifndef F_CPU | |||
|  #define F_CPU 16000000UL	/* Define CPU frequency here 16MHz */ | |||
| #endif | |||
| #ifndef LCD_CH_H_ | |||
|  #define LCD_CH_H_ | |||
| #include <avr/io.h> | |||
| #include <util/delay.h> | |||
| /* Nasledovne define rozhodne ktora cast programu sa prelozi:  | |||
|    LCD Shiled (WR ma pripojene na GND) a | |||
|    priradenie pinov je dane napr.: | |||
|    "zamrzne" | |||
|    -    https://www.14core.com/wiring-the-lcd-16x2-keypad-shield-on-arduino/ | |||
|    -	https://wiki.dfrobot.com/LCD_KeyPad_Shield_For_Arduino_SKU__DFR0009 | |||
|    resp.  | |||
|    LCD, zapojenie vid. stranka MIPS | |||
|    "zamrzne" | |||
|    - http://senzor.robotika.sk/sensorwiki/index.php/LCD_displej_s_radi%C4%8Dom_HD44780 | |||
|    , ktore ma pripojene aj pin WR | |||
|    t.j. moze sa testovat aj pin BF | |||
| */ | |||
|  /* !!!!!!!  | |||
|     #define _Shield_LCD | |||
|     !!!!!!! */ | |||
| extern unsigned char kon_vyp; | |||
| #ifdef _Shield_LCD | |||
| 	#define LCD_CTRL_DDR DDRB | |||
| 	#define LCD_CTRL_PORT PORTB | |||
| 	#define LCD_DATA_DDR DDRD | |||
| 	#define LCD_DATA_PORT PORTD | |||
| 	// Riadiaca zbernica display-a | |||
| 	#define LCD_RS_pin 0 | |||
| 	//#define LCD_RW_pin = 0 | |||
| 	#define LCD_EN_pin 1 | |||
| 	// Datova zbernica | |||
| 	#define LCD_D4_pin 4 | |||
| 	#define LCD_D5_pin 5 | |||
| 	#define LCD_D6_pin 6 | |||
| 	#define LCD_D7_pin 7 | |||
| #else | |||
| 	// LCD  klasik yapojenie vid. MIPS | |||
| 	#define LCD_CTRL_DDR DDRD | |||
| 	#define LCD_CTRL_PORT PORTD | |||
| 	#define LCD_DATA_DDR DDRB | |||
| 	#define LCD_DATA_PORT PORTB | |||
| 	#define LCD_DATA_PIN PINB | |||
| 	#define LCD_RS_pin 2 | |||
| 	#define LCD_RW_pin 3 | |||
| 	#define LCD_EN_pin 4 | |||
| 	#define LCD_D4_pin 1 | |||
| 	#define LCD_D5_pin 2 | |||
| 	#define LCD_D6_pin 3 | |||
| 	#define LCD_D7_pin 4 | |||
| #endif | |||
| // Oneskorenie 6 SC | |||
| #define NOP() asm("nop")	 | |||
| #define LCD_DELAY	NOP();NOP();NOP();NOP();NOP();NOP(); | |||
| #ifdef _Shield_LCD | |||
| // formatovanie dat | |||
| #define PORT_DATA_WR_H(x) LCD_DATA_PORT &=0b00001111; LCD_DATA_PORT |= (x & 0xF0 ) | |||
| #define PORT_DATA_WR_L(x) LCD_DATA_PORT &=0b00001111; LCD_DATA_PORT |= (x & 0x0F )<<4 | |||
| #else | |||
| #define PORT_DATA_WR_H(x) LCD_DATA_PORT &=0b11100001; LCD_DATA_PORT |= (x & 0xF0 )>>3 | |||
| #define PORT_DATA_WR_L(x) LCD_DATA_PORT &=0b11100001; LCD_DATA_PORT |= (x & 0x0F )<<1 | |||
| #define PORT_DATA_RD_H ((LCD_DATA_PIN & ((1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin)))<<3) | |||
| #define PORT_DATA_RD_L ((LCD_DATA_PIN & ((1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin)))>>1) | |||
| #endif | |||
| /* Public functions for your use */ | |||
| #ifndef _Shield_LCD | |||
| int8_t lcd_read_AC(void);    | |||
| void def_spec_znaky_AC(void); | |||
| #endif | |||
| void lcd_init(void); | |||
| void lcd_data(unsigned char ); | |||
| void lcd_command(unsigned char ); | |||
| // void lcd_puts(const char *s);  /* deklaracia funkcie  */ | |||
| void ini_ports(void); | |||
| void En_imp(void); | |||
| void wr_data (unsigned char ); | |||
| unsigned char busy_flag(void); | |||
| void zob_text(char *); | |||
| void def_Clear_spec_znaky(void); | |||
| void def_znak(unsigned char *,unsigned char ); | |||
| void def_spec_znaky(void); | |||
| #endif /* LCD_CH_H_ */ | |||
| </source></tab> | |||
| <tab name="lcd_ch.c"><source lang="c++" style="background: LightYellow;"> | |||
| #include "lcd_ch.h" | |||
| unsigned char Znak_OO[8]= {0x00,0x00,0x00,0x00,0x00,0x00,0x15,0};// Prazdny znak	dole su tri bodky | |||
| unsigned char Znak_SC[8]= {0x1A,0x1D,0x04,0x04,0x04,0x05,0x02,0};// st.C	 | |||
| unsigned char Znak_SM[8]= {0x0A,0x04,0x0E,0x10,0x0E,0x01,0x1E,0};//  s + mekcen	 | |||
| unsigned char Znak_CM[8]= {0x0A,0x04,0x0E,0x10,0x10,0x11,0x0C,0};//  c + mekcen | |||
| // Vynulovanie CGRAM | |||
| void def_Clear_spec_znaky(void){ | |||
| 	// zapis specialneho znaku do CGRAM  na poziciu 0, a 7 | |||
| 	for(char i = 0; i < 8; i++) def_znak( Znak_OO,i); | |||
| 	lcd_command(0x80); | |||
| }  | |||
| void def_spec_znaky(void){ | |||
| // zapis vlastnych znakkov do CGRAM  na poziciu 4, a 0 (8)  | |||
|  def_znak( Znak_SC,4);// stupen Celzia | |||
|  def_znak( Znak_SM,0);// s + makcen | |||
|  // obnovenie obsahu AC. AC nastvime na 1. riadok, 1. znak | |||
|  lcd_command(0x80); | |||
| }		 | |||
| #ifndef _Shield_LCD | |||
| void def_spec_znaky_AC(void){ | |||
| // zapis specialneho znaku do CGRAM  na poziciu 7 | |||
| unsigned char obsah_AC = 0; | |||
|  obsah_AC = lcd_read_AC(); //      | |||
|  // kon_vyp = obsah_AC; | |||
|  // sem dame nove vlastne znaky | |||
|  def_znak( Znak_CM,7);// c + makcen | |||
|  // obnovenie obsahu AC. AC  | |||
| lcd_command(0x80|obsah_AC); | |||
| }		 | |||
| #endif | |||
| void ini_ports(void){	 	 | |||
| /* inicializacia portov - vstupy / vystupy  | |||
| oba typy displaja */ | |||
| // nasledovna # riadky su spolocne pre oba typy LCD | |||
| LCD_CTRL_DDR |= (1<<LCD_EN_pin);	//  (Enable)    output   | |||
| LCD_CTRL_DDR |= (1<<LCD_RS_pin);	//  (RS)        output  	 | |||
| LCD_DATA_DDR |= (1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin);	// Datove piny ako Output (Data pre display) | |||
| #ifndef _Shield_LCD | |||
| // klasicky LCD vyuziva aj RW pin | |||
| LCD_CTRL_DDR |= (1<<LCD_RW_pin);	//	(RW)        output   | |||
| #endif | |||
| }	 | |||
| void En_imp(void) { | |||
| 	LCD_CTRL_PORT |= (1<<LCD_EN_pin);	// -> "log.1" | |||
| 	LCD_DELAY;							// cca 400 ns | |||
| 	LCD_CTRL_PORT &= ~(1<<LCD_EN_pin);	// -> "log.0"  spolu cca 500 ns | |||
| } | |||
| void lcd_init(void) | |||
| {   // 4 bitove pripojenie display-a | |||
| 	ini_ports(); // inicializacia porov | |||
| 	 _delay_ms(15); | |||
| 	// 1. ------------------- | |||
| 	LCD_CTRL_PORT &= ~(1 << LCD_RS_pin);		// set RS  = to "log. 0"  Instruction Register (IR) | |||
| #ifndef _Shield_LCD | |||
| 	LCD_CTRL_PORT &= ~(1 << LCD_RW_pin)	;		// set R/W = to "log. 0" - Write | |||
| #endif | |||
| 	// RS R/W   DB7 DB6 DB5 DB4   DB3 DB2 DB1 DB0 | |||
| 	// 0  0     0   0   1   1     x   x   x   x     = 0x30 | |||
| 	PORT_DATA_WR_H(0x30);	// 8-bitove pripojenie | |||
| 	En_imp(); | |||
| 	// 2. ------------------- | |||
|     // zopakujem  8-bitove pripojenie | |||
| 	_delay_ms(5); En_imp(); | |||
| 	// 3. ------------------- | |||
| 	// zopakujem  8-bitove pripojenie | |||
|     _delay_ms(1); En_imp(); // -  stacilo by delay 0.1ms, momentalne najkratsie nastavitelne je 1ms | |||
| 	// 4. ------------------- | |||
| 	// zmenim na 4-bitove pripojenie | |||
| 	// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0 | |||
| 	// 0  0      0   0   1   0      x   x   x   x    = 0x20 | |||
| 	PORT_DATA_WR_H(0x20);	// 4-bitove pripojenie | |||
| 	_delay_ms(1); En_imp(); // -  stacilo by delay 0.04ms | |||
| 	// -------------------		 | |||
| 	// LCD function set      mod: DL = 0 - 4-bitove data, N = 1 - 2 riadky, F = 0 - 5x7 dots  | |||
| 	// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0 | |||
| 	// 0  0      0   0   1   DL     N   F   x   x     = 0x28 | |||
| 	// Mozeme nasledujuci prikaz pre LCD vynechat? | |||
| 	_delay_ms(2); | |||
| 	lcd_command(0x28); | |||
| 	// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0 | |||
| 	// 0  0      0   0   0   0	    0   0   0   1     = 0x01 , Display clear | |||
| 	// Mozeme nasledujuci prikaz pre LCD vynechat? | |||
| 	_delay_ms(2); | |||
| 	lcd_command(0x01); | |||
| 	// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0 | |||
| 	// 0  0      0   0   0   0	    0   1   I/D S      = 0x06, I/D = 1 - inkrement | |||
| 	// Mozeme nasledujuci prikaz pre LCD vynechat? | |||
| 	_delay_ms(2); | |||
| 	lcd_command(0x02); | |||
| 	// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0 | |||
| 	// 0  0      0   0   0   0	    1   D   C   B      = 0x0E, D = C = 1 - Display a kurzor zapnute | |||
| 	// Mozeme nasledujuci prikaz pre LCD vynechat? | |||
| 	_delay_ms(2); | |||
| 	lcd_command(0x0E);								// B = 0 - blikanie vypnute | |||
| } | |||
| //zapis data do Data Register | |||
| void lcd_data(unsigned char data){	 | |||
| 	while(busy_flag() & 0x80); | |||
| 	//while(rd_BF()); // test BF sa da realizovat pre klasicky LCD, nie Shield | |||
| 	LCD_CTRL_PORT |= (1<<LCD_RS_pin);		//    (RS = High)   | |||
| #ifndef _Shield_LCD | |||
| 	LCD_CTRL_PORT &= ~(1<<LCD_RW_pin);		//    (RW = Low, write)  | |||
| #endif | |||
| 	wr_data (data);	 | |||
| } | |||
| // zapis commandu do Instruction Register | |||
| void lcd_command(unsigned char command){  | |||
| 	while(busy_flag() & 0x80); | |||
| 	//while(rd_BF()); // test BF sa da realizovat pre klasicky LCD, nie Shield | |||
| 	LCD_CTRL_PORT &= ~(1<<LCD_RS_pin);		//   (RS = Low)   | |||
| #ifndef _Shield_LCD | |||
| 	LCD_CTRL_PORT &= ~(1<<LCD_RW_pin);		//   (RW = Low, write)  | |||
| #endif | |||
| 	wr_data (command);	 | |||
| } | |||
| void wr_data(unsigned char data) {  | |||
| 	PORT_DATA_WR_H(data);		// data High nibble | |||
| 	En_imp(); | |||
| 	PORT_DATA_WR_L(data);		// data Low nibble | |||
| 	En_imp(); | |||
| } | |||
| #ifdef _Shield_LCD | |||
| // namiesto testu BF "pockam".  | |||
| // LCD typu Shield ma WR pripojene na GND		 | |||
| unsigned char busy_flag(void){ | |||
| 	_delay_ms(2);	 | |||
| 	return(0); | |||
| }	 | |||
| #else | |||
| // namiesto testu BF "pockam". Vacsine prikazov tento cas vyhovuje		 | |||
| /*int busy_flag(void){ | |||
| 	_delay_ms(2);	 | |||
| 	return(0); | |||
| } | |||
| */ | |||
| // klasicke pripojenie LCD umozni aj test BF | |||
| unsigned char busy_flag(void){ //  rd_BF    | |||
| 	unsigned char pom = 0; | |||
| 	LCD_CTRL_PORT &= ~(1<<LCD_RS_pin);	//   (RS = Low)   | |||
| 	LCD_CTRL_PORT |= (1<<LCD_RW_pin);	//    (RW = High, read)  | |||
|     // port B, datove bity budu teraz input | |||
| 	LCD_DATA_DDR &= ~((1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin));	//  Datove piny nastavime  na input, (Data pre disp) | |||
| 	// Spravne by sa malo vycitavaj pred dobeznou hranou EN impulzu. Je tam urcity presah. Mozeme vycitat aj po dobeznej hrane. | |||
| 	En_imp(); | |||
| 	pom = PORT_DATA_RD_H; // vycitam High nibble AC | |||
| 	En_imp(); | |||
| 	pom |= PORT_DATA_RD_L; // vycitam Low nibble AC | |||
| 	// datove bity zase output | |||
| 	LCD_DATA_DDR |= (1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin);	// Datove piny nastavime na output (Data pre disp)  | |||
| 	//if(pom & 0x80) return 1;	// display je busy | |||
| 	//else  | |||
| 	return pom;					// display je not busy | |||
| } | |||
| #endif | |||
| void zob_text(char *s){ | |||
| 	register unsigned char c; | |||
| 	while((c = *s++))	lcd_data(c); // retazec konci "nulou" | |||
| } | |||
| void def_znak(unsigned char *ZnakArray,unsigned char kam) {	 | |||
| 	lcd_command(0x40|(kam << 3)); //nastavenie adresy znaku v CGRAM | |||
| 	for(unsigned char i = 0; i < 8; i++) lcd_data( *(ZnakArray + i));		 | |||
| } | |||
| /* ********************************************************	*/ | |||
| /* vypis retazca na poziciu, resp. podla nasledovnych 		*/ | |||
| /* formatovacich prikazov                                       */ | |||
| /*   : \r - prechod na novy riadok                              */ | |||
| /*   : \f - prechod na zaciatok displeja                        */ | |||
| /* ********************************************************     */ | |||
|  void lcd_puts(  const char *s)   /* definicia funkcie		*/ | |||
| { | |||
|   // sem pride vas vlastny kod...   | |||
| } | |||
| #ifndef _Shield_LCD | |||
| int8_t lcd_read_AC(void){ //  rd_BF    | |||
| 	char pom_AC ; | |||
| 	while((pom_AC = busy_flag( )) & 0x80); | |||
| 	// kedze po BF = 0 este cca 4us sa nezmenil obsah AC | |||
| 	// treba vycitat este raz   | |||
| 	pom_AC = busy_flag( ); | |||
| 	return pom_AC;					// display not busy | |||
| } | |||
| #endif | |||
| </source></tab> | |||
| <tab name="uart.h"><source lang="c++" style="background: LightYellow;"> | |||
| /* | |||
|  * uart.h | |||
|  * | |||
|  * Created: 4/6/2022 11:26:15 AM | |||
|  *  Author: Admin | |||
|  */  | |||
| #ifndef UART_H_ | |||
| #define UART_H_ 1 | |||
| #include <avr/io.h> | |||
| #define F_CPU 16000000UL | |||
| #define B_R_9600 | |||
| #ifdef B_R_9600 | |||
| #define BAUDRATE       9600 | |||
| #define BAUD_PRESCALE ((F_CPU + BAUDRATE * 4UL) / (BAUDRATE * 8UL) - 1UL) | |||
| #else | |||
| #define BAUDRATE       9600 | |||
| #define BAUD_PRESCALE  (((F_CPU / (BAUDRATE * 16UL))) - 1)  // vzorcek z datasheetu | |||
| #endif | |||
| void uart_init( void ); | |||
| extern  int uart_putchar(const char c); | |||
| char uart_getc( void ); | |||
| #endif /* UART_H_ */ | |||
| </source></tab> | |||
| <tab name="uart.c"><source lang="c++" style="background: LightYellow;"> | |||
| /* | |||
|  * uart.c | |||
|  * | |||
|  * Created: 4/6/2022 11:25:56 AM | |||
|  *  Author: Admin | |||
|  */  | |||
| #include "uart.h" | |||
| //#include "p_f.h" | |||
| void uart_init( void ){ | |||
| 	#ifdef B_R_115200 | |||
| 	UCSR0A |= (1<<U2X0); | |||
| 	#endif | |||
|    // 0.1. UBRR0 = (unsigned char)BAUD_PRESCALE;         // Set baud rate: Load the UBRR register | |||
|    UBRR0 = (unsigned int)BAUD_PRESCALE;                 // Set baud rate: Load the UBRR register | |||
|    UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);                     // Set format: 8data, 1stop bit  | |||
|    UCSR0B = (1 << RXEN0) | (1 << TXEN0);                 // Enable receiver and transmitter | |||
| }; | |||
|  int uart_putchar( const char c){ | |||
|    if (c == '\n'){ | |||
| 	  uart_putchar( '\r' ); | |||
| 	  while ( !( UCSR0A & (1<<UDRE0)) ); | |||
| 	/* Put data into buffer, sends the data */ | |||
| 	UDR0 = c; | |||
|    return 0; | |||
|   } | |||
|    while ( !( UCSR0A & (1<<UDRE0)) );                  // Wait for empty transmit buffer  | |||
| 	   // Do nothing until UDR is ready for more data to be written to it | |||
|       UDR0 = c;                             // Echo back the modified received byte  | |||
| return 0; | |||
| }; | |||
| void uart_puts( const char *s ); | |||
| // treba dorobit | |||
| char uart_getc( void ){ | |||
| 	while (!(UCSR0A & (1 << RXC0)) );              // Wait for data to be received  | |||
| 	    // Do nothing until data have been recieved and is ready to be read from UDR | |||
|       return(UDR0);                               // Fetch the recieved byte  | |||
| }; | |||
| </source></tab> | |||
| </tabs> | </tabs> | ||
| Zdrojový kód: [ | Zbalený kompletný projekt | ||
| Zdrojový kód: [https://senzor.robotika.sk/sensorwiki/index.php/S%C3%BAbor:HlukomerMykytaSabadash.zip Hlukomer.zip] | |||
| === Overenie === | === Overenie === | ||
| Vytvorime hluk a uvidime "reakciu" hlukomeru, na LCD mame vypisane "hodnoty hluku" v cislach a pomocou stupnice. | |||
| Tak isto vidime na konci videa to ze hodnoty idu do minusu a ne mame stupnicu, co znamena ze hlukomer nam ustalil na hodnote mensej ako 350, ktoru sme pouzili v kode, a musime sme ju zmensit, aby minimalnym/ustalenym vypisom bola nula, a potom znov zacat meranie. | |||
| '''Video:''' | '''Video:''' | ||
| <center><youtube> | <center><youtube>1nKjUhUQs04</youtube></center> | ||
| [[Category:AVR]] [[Category:MIPS]] | [[Category:AVR]] [[Category:MIPS]] | ||
Aktuálna revízia z 10:32, 8. jún 2023
Záverečný projekt predmetu MIPS / LS2023 - Mykyta Sabadash
Zadanie
Hlukomer: - naprogramujte zariadenie na meranie úrovne hluku so zobrazením na LCD displej. Zobrazenie v dB a pomocou stupnice.

Literatúra: 
Analýza a opis riešenia
Zapojenie nasho Hlukomeru bolo urobene strucne podla cviceni, kde nas senzor zvuku je A/D prevodnikom (cvicenie 9) a LCD displej z cvicenia 4
Prikladam schemy zapojenia z cviceni



Algoritmus a program
Sme inicializujeme A/D prevodnik, inicializujeme LCD displej a overujeme spravnost ho zapojenia, ked je vsetko v pohode tak displej sa zapne a sa zacnu ukazovat tam data ktore sme tam posleme (ked ze sme tam nieco posleme).
Dalej, zadefinujeme "lcd_puts" (funkcia na vypis veci na displej), zoberieme nase vstupne data z funkcie "adc_read()", a vyskusame ich v Serial Plot-e. Tu sme overime ci je nas senzor zvuku funkcny/zapojeny, lebo priebeh data ktore on nam posiela vidime na diagrame.
Teraz, zadefinujeme riadok, "vypocitame" hodnotu ktoru chceme vidiet na displeji, a vypiseme to pomocou funkcie "sprintf()".
A vypocitame nase Db
dB = 20 * log10(napatie_senzora / referencne_napatie)
Kde:
* dB je vysledná hodnota v decibeloch * log10 je desiatkovy logaritmus * napatie_senzora je vstupne napätie senzora zvuku (value) * referencne_napatie je referencne napatie senzora (~3.3v)
A, pre lepsi vyhlad nasho hlukomeru pridame mu stupnicu hluku, ktoru vytvorime z ciernych stvorcekov a "pustych miest" (space key)
Kedy nam to vsetko vypise, dostaneme vypis na LCD ktory bude vyzerat priblizne takto:
Db --> 25
■■
Alebo napriklad takto
Db --> 100
■■■■■■■■
Potom, sme vratime kurzor na zaciatok, a urobime meranie a vypis znova
#include <avr/io.h>
#include "adc.h"
#include "uart.h"
#include "lcd_ch.h"
#include <stdio.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define LCD_CTRL_PORT DDRD
#define LCD_DATA_PORT DDRB
#define LCD_CLR               0      /* DB0: clear display                  */
#define LCD_HOME              1      /* DB1: return to home position        */
#define LCD_RS_pin 2
#define LCD_RW_pin 3
#define LCD_EN_pin 4
#define LCD_D4_pin 1
#define LCD_D5_pin 2
#define LCD_D6_pin 3
#define LCD_D7_pin 4
FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
int main(void)
{
	
 int pocitadlo =0;
	
 
 /* inicializacia a/d prevodnika*/
  unsigned int measuredValue;
  adc_init();                                          // Init A/D converter
  uart_init(); 
  stdout =  &uart_stream;
  
  /* inicializacia portov - vstupy / vystupy */
	
	DDRD |= (1<<LCD_EN_pin);	// Pin D4 (Enable)  PORTD  output  
	DDRD |= (1<<LCD_RW_pin);	// Pin D3 (RW)      PORTD  output  
	DDRD |= (1<<LCD_RS_pin);	// Pin D2 (RS)      PORTD  output  
  
	LCD_DATA_PORT |= (1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin);	// Piny 1,2,3,4, PORTB ako output (Data pre display)
	
	/* displej je spravne pripojeny, mozeme zacat inicializaciu podla datasheetu */
	
	lcd_init();  // definiciu pozri v -> lcd_ch.h resp. lcd_ch.c
	/* po ukonceni inicializacie je displej zapnuty a ak posleme nejake data, tak 
	   sa zacnu zobrazovat od prvej pozicie (riadok 0, stlpec 0)               */
  
  
  void lcd_puts(const char *s)
	{
	register unsigned char c;
	while((c = *s++))	lcd_data(c); // retazec konci "nulou"
    }
  while (1)
  {
     
	  lcd_puts("Db  -->  ");                        // vystup co sa vypise na displeji
    measuredValue = adc_read(4);                        // hodnota ktoru nam 'hovori' a/d prevodnik (mikrofon)
    printf("%u\n",measuredValue);			// pre serial plot  
 _delay_ms(100);
 
      lcd_command(0x0C);                   // schovat kurzor
	  
	  char riadok[]= {"                "};	
        int value = measuredValue - 350;   // premenna, ktorej hodnotu by sme chceli zobrazit na LCD (350 podla toho ze
	                                   // je to akoby nulova velicina nasho 'kvalitneho' hlukomera, ked ze sa vypisuju zle hodnoty na displej
                                           // tak musime menit prave tuto hodnotu, aby nulovy hluk zodpovedal 'nule' na displeji)
        int db = log10(value/3.3);
          sprintf(riadok,"%d",db);
          
    
	  int i = (value/12);
	  int o = 16-i;                  // tu sme pocitame nase "stvorceky" pre stupnicu
	  
	  if (pocitadlo == 5)            // pocitadlo na vypisovanie dB jeden krat za 5 cyklusov programu,  aby bolo to prehliadne
	  {
	   lcd_puts(riadok);             // dB
	   lcd_data(0x10);               // put space key
	   
	  pocitadlo =0;
	   } 
	   pocitadlo++;	  
	   
	   lcd_command(0xC0);            // prestup do noveho riadka
	   
	   for(i;i>0;i--)                // stupnica
	   {
		  lcd_data(0xFF);        // put ■
	    }		  
		for(o;o>0;o--)
	   {
		  lcd_data(0x10);        // put space key
	    }		 
	  lcd_command(0x70);             // 0x10 (Cursor/display shift) + 0x20 (Function set) + 0x40 (Set CGRAM address)
	  
      lcd_command(1<<LCD_HOME);  /* Set cursor to home position */
  }
  return(0);
}
#include <avr/io.h>
void adc_init(void);                                   // A/D converter initialization
unsigned int adc_read(char a_pin);
#include <avr/io.h>
void adc_init (void){
	
	ADMUX = (1<<REFS0);	
	ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
}
unsigned int adc_read(char a_pin){
	a_pin &= 0x07;
	ADMUX = (ADMUX & 0xF8)|a_pin;
	ADCSRA |= (1<< ADSC);
	while ( ADCSRA & (1<< ADSC));
		return (ADC);
}
/*
 * lcd_ch.h
 *
 * Created: 3/10/2021 7:05:39 PM
 *  Author: Admin
 */ 
#ifndef F_CPU
 #define F_CPU 16000000UL	/* Define CPU frequency here 16MHz */
#endif
#ifndef LCD_CH_H_
 #define LCD_CH_H_
#include <avr/io.h>
#include <util/delay.h>
/* Nasledovne define rozhodne ktora cast programu sa prelozi: 
   LCD Shiled (WR ma pripojene na GND) a
   priradenie pinov je dane napr.:
   "zamrzne"
   -    https://www.14core.com/wiring-the-lcd-16x2-keypad-shield-on-arduino/
   -	https://wiki.dfrobot.com/LCD_KeyPad_Shield_For_Arduino_SKU__DFR0009
   resp. 
   LCD, zapojenie vid. stranka MIPS
   "zamrzne"
   - http://senzor.robotika.sk/sensorwiki/index.php/LCD_displej_s_radi%C4%8Dom_HD44780
   , ktore ma pripojene aj pin WR
   t.j. moze sa testovat aj pin BF
*/
 /* !!!!!!! 
    #define _Shield_LCD
    !!!!!!! */
extern unsigned char kon_vyp;
#ifdef _Shield_LCD
	#define LCD_CTRL_DDR DDRB
	#define LCD_CTRL_PORT PORTB
	#define LCD_DATA_DDR DDRD
	#define LCD_DATA_PORT PORTD
	// Riadiaca zbernica display-a
	#define LCD_RS_pin 0
	//#define LCD_RW_pin = 0
	#define LCD_EN_pin 1
	// Datova zbernica
	#define LCD_D4_pin 4
	#define LCD_D5_pin 5
	#define LCD_D6_pin 6
	#define LCD_D7_pin 7
#else
	// LCD  klasik yapojenie vid. MIPS
	#define LCD_CTRL_DDR DDRD
	#define LCD_CTRL_PORT PORTD
	#define LCD_DATA_DDR DDRB
	#define LCD_DATA_PORT PORTB
	#define LCD_DATA_PIN PINB
	#define LCD_RS_pin 2
	#define LCD_RW_pin 3
	#define LCD_EN_pin 4
	#define LCD_D4_pin 1
	#define LCD_D5_pin 2
	#define LCD_D6_pin 3
	#define LCD_D7_pin 4
#endif
 
// Oneskorenie 6 SC
#define NOP() asm("nop")	
#define LCD_DELAY	NOP();NOP();NOP();NOP();NOP();NOP();
#ifdef _Shield_LCD
// formatovanie dat
#define PORT_DATA_WR_H(x) LCD_DATA_PORT &=0b00001111; LCD_DATA_PORT |= (x & 0xF0 )
#define PORT_DATA_WR_L(x) LCD_DATA_PORT &=0b00001111; LCD_DATA_PORT |= (x & 0x0F )<<4
#else
#define PORT_DATA_WR_H(x) LCD_DATA_PORT &=0b11100001; LCD_DATA_PORT |= (x & 0xF0 )>>3
#define PORT_DATA_WR_L(x) LCD_DATA_PORT &=0b11100001; LCD_DATA_PORT |= (x & 0x0F )<<1
#define PORT_DATA_RD_H ((LCD_DATA_PIN & ((1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin)))<<3)
#define PORT_DATA_RD_L ((LCD_DATA_PIN & ((1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin)))>>1)
#endif
/* Public functions for your use */
#ifndef _Shield_LCD
int8_t lcd_read_AC(void);   
void def_spec_znaky_AC(void);
#endif
	
void lcd_init(void);
void lcd_data(unsigned char );
void lcd_command(unsigned char );
// void lcd_puts(const char *s);  /* deklaracia funkcie  */
void ini_ports(void);
void En_imp(void);
void wr_data (unsigned char );
unsigned char busy_flag(void);
void zob_text(char *);
void def_Clear_spec_znaky(void);
void def_znak(unsigned char *,unsigned char );
void def_spec_znaky(void);
#endif /* LCD_CH_H_ */
#include "lcd_ch.h"
unsigned char Znak_OO[8]= {0x00,0x00,0x00,0x00,0x00,0x00,0x15,0};// Prazdny znak	dole su tri bodky
unsigned char Znak_SC[8]= {0x1A,0x1D,0x04,0x04,0x04,0x05,0x02,0};// st.C	
unsigned char Znak_SM[8]= {0x0A,0x04,0x0E,0x10,0x0E,0x01,0x1E,0};//  s + mekcen	
unsigned char Znak_CM[8]= {0x0A,0x04,0x0E,0x10,0x10,0x11,0x0C,0};//  c + mekcen
// Vynulovanie CGRAM
void def_Clear_spec_znaky(void){
	// zapis specialneho znaku do CGRAM  na poziciu 0, a 7
	for(char i = 0; i < 8; i++) def_znak( Znak_OO,i);
	lcd_command(0x80);
} 
 
void def_spec_znaky(void){
// zapis vlastnych znakkov do CGRAM  na poziciu 4, a 0 (8) 
 def_znak( Znak_SC,4);// stupen Celzia
 def_znak( Znak_SM,0);// s + makcen
 // obnovenie obsahu AC. AC nastvime na 1. riadok, 1. znak
 lcd_command(0x80);
}		
#ifndef _Shield_LCD
void def_spec_znaky_AC(void){
// zapis specialneho znaku do CGRAM  na poziciu 7
unsigned char obsah_AC = 0;
 obsah_AC = lcd_read_AC(); //     
 // kon_vyp = obsah_AC;
 // sem dame nove vlastne znaky
 def_znak( Znak_CM,7);// c + makcen
 // obnovenie obsahu AC. AC 
lcd_command(0x80|obsah_AC);
}		
#endif
	 
void ini_ports(void){	 	
	
/* inicializacia portov - vstupy / vystupy 
oba typy displaja */
// nasledovna # riadky su spolocne pre oba typy LCD
LCD_CTRL_DDR |= (1<<LCD_EN_pin);	//  (Enable)    output  
LCD_CTRL_DDR |= (1<<LCD_RS_pin);	//  (RS)        output  	
LCD_DATA_DDR |= (1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin);	// Datove piny ako Output (Data pre display)
#ifndef _Shield_LCD
// klasicky LCD vyuziva aj RW pin
LCD_CTRL_DDR |= (1<<LCD_RW_pin);	//	(RW)        output  
	
#endif
}	
void En_imp(void) {
	LCD_CTRL_PORT |= (1<<LCD_EN_pin);	// -> "log.1"
	LCD_DELAY;							// cca 400 ns
	LCD_CTRL_PORT &= ~(1<<LCD_EN_pin);	// -> "log.0"  spolu cca 500 ns
}
void lcd_init(void)
{   // 4 bitove pripojenie display-a
	ini_ports(); // inicializacia porov
	 _delay_ms(15);
	// 1. -------------------
	LCD_CTRL_PORT &= ~(1 << LCD_RS_pin);		// set RS  = to "log. 0"  Instruction Register (IR)
#ifndef _Shield_LCD
	LCD_CTRL_PORT &= ~(1 << LCD_RW_pin)	;		// set R/W = to "log. 0" - Write
#endif
	// RS R/W   DB7 DB6 DB5 DB4   DB3 DB2 DB1 DB0
	// 0  0     0   0   1   1     x   x   x   x     = 0x30
	PORT_DATA_WR_H(0x30);	// 8-bitove pripojenie
	En_imp();
	// 2. -------------------
    // zopakujem  8-bitove pripojenie
	_delay_ms(5); En_imp();
	// 3. -------------------
	// zopakujem  8-bitove pripojenie
    _delay_ms(1); En_imp(); // -  stacilo by delay 0.1ms, momentalne najkratsie nastavitelne je 1ms
	// 4. -------------------
	// zmenim na 4-bitove pripojenie
	// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0
	// 0  0      0   0   1   0      x   x   x   x    = 0x20
	PORT_DATA_WR_H(0x20);	// 4-bitove pripojenie
	_delay_ms(1); En_imp(); // -  stacilo by delay 0.04ms
	// -------------------		
	// LCD function set      mod: DL = 0 - 4-bitove data, N = 1 - 2 riadky, F = 0 - 5x7 dots 
	// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0
	// 0  0      0   0   1   DL     N   F   x   x     = 0x28
	// Mozeme nasledujuci prikaz pre LCD vynechat?
	_delay_ms(2);
	lcd_command(0x28);
	// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0
	// 0  0      0   0   0   0	    0   0   0   1     = 0x01 , Display clear
	// Mozeme nasledujuci prikaz pre LCD vynechat?
	_delay_ms(2);
	lcd_command(0x01);
	// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0
	// 0  0      0   0   0   0	    0   1   I/D S      = 0x06, I/D = 1 - inkrement
	// Mozeme nasledujuci prikaz pre LCD vynechat?
	_delay_ms(2);
	lcd_command(0x02);
	// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0
	// 0  0      0   0   0   0	    1   D   C   B      = 0x0E, D = C = 1 - Display a kurzor zapnute
	// Mozeme nasledujuci prikaz pre LCD vynechat?
	_delay_ms(2);
	lcd_command(0x0E);								// B = 0 - blikanie vypnute
}
//zapis data do Data Register
void lcd_data(unsigned char data){	
	while(busy_flag() & 0x80);
	//while(rd_BF()); // test BF sa da realizovat pre klasicky LCD, nie Shield
	LCD_CTRL_PORT |= (1<<LCD_RS_pin);		//    (RS = High)  
#ifndef _Shield_LCD
	LCD_CTRL_PORT &= ~(1<<LCD_RW_pin);		//    (RW = Low, write) 
#endif
	wr_data (data);	
}
// zapis commandu do Instruction Register
void lcd_command(unsigned char command){ 
	while(busy_flag() & 0x80);
	//while(rd_BF()); // test BF sa da realizovat pre klasicky LCD, nie Shield
	LCD_CTRL_PORT &= ~(1<<LCD_RS_pin);		//   (RS = Low)  
#ifndef _Shield_LCD
	LCD_CTRL_PORT &= ~(1<<LCD_RW_pin);		//   (RW = Low, write) 
#endif
	wr_data (command);	
}
void wr_data(unsigned char data) { 
	PORT_DATA_WR_H(data);		// data High nibble
	En_imp();
			
	PORT_DATA_WR_L(data);		// data Low nibble
	En_imp();
}
#ifdef _Shield_LCD
// namiesto testu BF "pockam". 
// LCD typu Shield ma WR pripojene na GND		
unsigned char busy_flag(void){
	_delay_ms(2);	
	return(0);
}	
#else
// namiesto testu BF "pockam". Vacsine prikazov tento cas vyhovuje		
/*int busy_flag(void){
	_delay_ms(2);	
	return(0);
}
*/
// klasicke pripojenie LCD umozni aj test BF
unsigned char busy_flag(void){ //  rd_BF   
	unsigned char pom = 0;
	LCD_CTRL_PORT &= ~(1<<LCD_RS_pin);	//   (RS = Low)  
	LCD_CTRL_PORT |= (1<<LCD_RW_pin);	//    (RW = High, read) 
    // port B, datove bity budu teraz input
	LCD_DATA_DDR &= ~((1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin));	//  Datove piny nastavime  na input, (Data pre disp)
	
	// Spravne by sa malo vycitavaj pred dobeznou hranou EN impulzu. Je tam urcity presah. Mozeme vycitat aj po dobeznej hrane.
	En_imp();
	pom = PORT_DATA_RD_H; // vycitam High nibble AC
	En_imp();
	pom |= PORT_DATA_RD_L; // vycitam Low nibble AC
	// datove bity zase output
	LCD_DATA_DDR |= (1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin);	// Datove piny nastavime na output (Data pre disp) 
	//if(pom & 0x80) return 1;	// display je busy
	//else 
	return pom;					// display je not busy
}
#endif
	
void zob_text(char *s){
	register unsigned char c;
	while((c = *s++))	lcd_data(c); // retazec konci "nulou"
}
void def_znak(unsigned char *ZnakArray,unsigned char kam) {	
	lcd_command(0x40|(kam << 3)); //nastavenie adresy znaku v CGRAM
	for(unsigned char i = 0; i < 8; i++) lcd_data( *(ZnakArray + i));		
}
/* ********************************************************	*/
/* vypis retazca na poziciu, resp. podla nasledovnych 		*/
/* formatovacich prikazov                                       */
/*   : \r - prechod na novy riadok                              */
/*   : \f - prechod na zaciatok displeja                        */
/* ********************************************************     */
 void lcd_puts(  const char *s)   /* definicia funkcie		*/
{
  // sem pride vas vlastny kod...  
}
#ifndef _Shield_LCD
int8_t lcd_read_AC(void){ //  rd_BF   
	char pom_AC ;
	
	while((pom_AC = busy_flag( )) & 0x80);
	// kedze po BF = 0 este cca 4us sa nezmenil obsah AC
	// treba vycitat este raz  
	pom_AC = busy_flag( );
	return pom_AC;					// display not busy
	
}
#endif
/*
 * uart.h
 *
 * Created: 4/6/2022 11:26:15 AM
 *  Author: Admin
 */ 
#ifndef UART_H_
#define UART_H_ 1
#include <avr/io.h>
#define F_CPU 16000000UL
#define B_R_9600
#ifdef B_R_9600
#define BAUDRATE       9600
#define BAUD_PRESCALE ((F_CPU + BAUDRATE * 4UL) / (BAUDRATE * 8UL) - 1UL)
#else
#define BAUDRATE       9600
#define BAUD_PRESCALE  (((F_CPU / (BAUDRATE * 16UL))) - 1)  // vzorcek z datasheetu
#endif
void uart_init( void );
     
extern  int uart_putchar(const char c);
char uart_getc( void );
#endif /* UART_H_ */
/*
 * uart.c
 *
 * Created: 4/6/2022 11:25:56 AM
 *  Author: Admin
 */ 
#include "uart.h"
//#include "p_f.h"
void uart_init( void ){
	#ifdef B_R_115200
	UCSR0A |= (1<<U2X0);
	#endif
   // 0.1. UBRR0 = (unsigned char)BAUD_PRESCALE;         // Set baud rate: Load the UBRR register
   UBRR0 = (unsigned int)BAUD_PRESCALE;                 // Set baud rate: Load the UBRR register
   UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);                     // Set format: 8data, 1stop bit 
   UCSR0B = (1 << RXEN0) | (1 << TXEN0);                 // Enable receiver and transmitter
};
     
 int uart_putchar( const char c){
   if (c == '\n'){
	  uart_putchar( '\r' );
	  while ( !( UCSR0A & (1<<UDRE0)) );
	/* Put data into buffer, sends the data */
	UDR0 = c;
   return 0;
  }
   while ( !( UCSR0A & (1<<UDRE0)) );                  // Wait for empty transmit buffer 
	   // Do nothing until UDR is ready for more data to be written to it
      UDR0 = c;                             // Echo back the modified received byte 
return 0;
};
void uart_puts( const char *s );
// treba dorobit
char uart_getc( void ){
	while (!(UCSR0A & (1 << RXC0)) );              // Wait for data to be received 
	    // Do nothing until data have been recieved and is ready to be read from UDR
      return(UDR0);                               // Fetch the recieved byte 
};
Zbalený kompletný projekt
Zdrojový kód: Hlukomer.zip
Overenie
Vytvorime hluk a uvidime "reakciu" hlukomeru, na LCD mame vypisane "hodnoty hluku" v cislach a pomocou stupnice.
Tak isto vidime na konci videa to ze hodnoty idu do minusu a ne mame stupnicu, co znamena ze hlukomer nam ustalil na hodnote mensej ako 350, ktoru sme pouzili v kode, a musime sme ju zmensit, aby minimalnym/ustalenym vypisom bola nula, a potom znov zacat meranie.
Video: