Sunteți pe pagina 1din 13

Ministerul Educației, Culturii și Cercetarilor al Republicii Moldova

Universitatea Tehnica a Moldovei


Facultatea de Calculatoare Informatică și Microelectronică
Departamentul Microelectronică şi Inginerie Biomedicală

Raport
Lucrare de laborator nr.3
Disciplina: SEI
Tema: Achiziții de date. Senzori

A efectuat: st.gr.IBM-172 , Rotari Nicu


A verificat: asistent univ., Verjbiţki Valeri

Chișinău 2020
Scopul lucrării:

- Să se definească o funcție de prelucrare a datelor primite de pe senzor;


- Să se afișeze datele pe afișor 16x2.

Sarcina:

Să se scrie un program pentru MCU care va colecta datele de la senzorul de temperatură LM20. Să se
definească funcția de conversie ADC – temperatură, utilizând ecuația dreptei. Să se afișeze datele colectate
prin interfața stdio, serial sau pe LCD16x2.

Date teoretice:
LM20 este o ieșire analogică precisă CMOS, senzor de temperatură integrat în circuit care operează în
intervalul -55°C ÷ 130°C. Gama de operare de alimentare este de 2,4 V÷5,5 V. Funcția de transfer a LM20
este predominant liniară, are totuși o ușoară curbură parabolică previzibilă. Precizia LM20 atunci când este
specificat la o funcție de transfer parabolică este ±1,5°C, la o temperatură ambiantă de 30°C .Eroare de
temperatură crește liniar și atinge un maxim de ± 2,5°C la o gamă extremă de temperatură. Domeniul de
temperatură este afectată de tensiunea de alimentare. La o tensiune de alimentare de 2,7 V la 5,5 V
domeniile de temperatură extreme sunt de 130°C și -55°C. Reducerea tensiunii de alimentare la 2,4 V se
schimbă extrem de negativ la -30°C, în timp ce rămâne pozitivă la 130°C. La LM20 curentul de repaus este
mai mic de 10 mA. De aceea, auto-încălzirea este mai mică de 0,02°C în atmosferă.

Fig. 1 – Diagrama de conexiuni a LM20

Fig. 2 – Dependența tensiunii de ieșire de temperatură


Scheme bloc:
lcd.c utils1.h
lcd.h

main lcd.h
thermometer.h
my_stdio.c

my_stdio.h avr_adc.c
thermometer.h

my_stdio.h avr_adc.h
thermometer.c

avr_adc.h
lm20.c
lm20.h utils.h
lm20.h
Fig. 3.3 – Schema bloc a bibliotecilor
MAIN

Thermometer_Init

_delay_ms(1000);

While(1)

Thermometer_Init

Thermometer_App
SerialStdioInit();

_delay_ms(2000); LM20_Init();

END END
lcd_writeCommand

SET_1(LCD_CONT_POR
T, LCD_EN)

lcd_init SET_0(LCD_CONT_POR
T, LCD_RS)

Thermometer_App LCD_DATA_DDR=0xFF
MyStdioInit LCD_DATA_PORT=command

LCD_CONT_DDR|=M(LC
temperature=0; D_RS, LCD_RW,
lcd_init _delay_ms(1)
LCD_EN)

lcd_clear(); stdout=&my_stdio SET_0(LCD_CONT_PORT,


SET_1(LCD_CONT_DDR) LCD_EN)

temperature=LM20_GetTemp(); stdin=&my_stdio lcd_writeCommand(..) _delay_ms(1)

END END END END

lcd_writeData

SET_1(LCD_CONT_POR
T, LCD_EN)

SET_1(LCD_CONT_POR
T, LCD_RS)
ADC_Enable
lcd_writeNumber lcd_writeString
LCD_DATA_PORT=data ADCSRA|=1<<ADEN

*number_string=´ 00000 ³
_delay_ms(1) END
*string
itoa(number,
True
SET_0(LCD_CONT_PORT, number_string, radix)
LCD_EN)
ADC_InitDefault
lcd_writeData(*string++)
False
_delay_ms(1) lcd_writeString(number_string)
ADC_Init(0);

END END END


END
ADC_SetReference
Suource

ADC_Init

(ref<0) ||
True
(ref>3)

return -1; !context True


False

ADMUX=(ADMUX& ADC_Enable(0);
~((1<<REFS1)|(1<<RE
ADC_Disable FS0)))|(ref<<REFS0);
False
ADC_SetReferenceSource(ADC_
ADCSRA&=~(1<<ADEN) return 0; REF_SRC_AVCC);

END
END END

LM20_DiagStatus

return(LM20_DiagSta
tus&(1<<diag_item))
ADC_GetData

adcData=0; END

LM20_SetDiagStatus
ADCSRA
&(1<<A True
DSC) channel&=0x07; LM20_DiagStatus|=1<<diag_item;

False
END
ADMUX=(ADMUX&
~(0x07))|channel;
LM20_ClearDiagStatus
ADCSRA|=(1<<ADSC);

diag_item
ADCSRA False ==Diag_
ALL True
&(1<<A True
DSC)
adcData=ADC;
LM20_DiagStatus&=1<<diag_item LM20_DiagStatus=0
False

return adcData;

END
END
LM20_ADC_ToTemperature

v_in=LineConversion(AD
Cvalues, ADC_MIN,
ADC_MAX,
ADC_VI_MIN, ADC);

grdC=LookUpConversion(
v_in, lm20_votable, LM20_Init
lm20_temp_table,
LM20_TEMP_TABLE_SI
ZE); ADC_InitDefault();

END END
Codul sursă:

/*
* main.c
*/
#include <util/delay.h>
#include "thermometer.h"

int main(void){
Thermometer_Init();
_delay_ms(1000);
while(1){
Thermometer_App();
_delay_ms(2000);
}
}
/*
* thermometer.c
*/
#include "my_stdio.h"
#include "lm20.h"
#include "util/delay.h"
#include "thermometer.h"

void Thermometer_Init(void){
SerialStdioInit();
LM20_init();
printf("App. Started");
}

void Thermometer_App(void){
int temperature = 0;
lcd_clear();
printf("Temp:");
temperature = LM20_GetTemp();
printf("%d", temperature);
}

/*
* thermometer.h
*/
#ifndef THERMOMETER_H_
#define THERMOMETER_H_
void Thermometer_Init(void);
void Thermometer_App(void);
#endif /* THERMOMETER_H_ */

/*
* my_stdio.c
*/
#include "my_stdio.h"
#include "lcd.h"

static FILE my_stdio = FDEV_SETUP_STREAM(lcd_writeData, NULL, _FDEV_SETUP_RW);

void SerialStdioInit(void){
lcd_init();
stdout = &my_stdio;
stdin = &my_stdio;
}
/*
* my_stdio.h
*/
#ifndef MY_STDIO_H_
#define MY_STDIO_H_
#include "stdio.h"
void SerialStdioInit(void);
#endif /* MY_STDIO_H_ */

/*
* avr_adc.c
*/
#include <avr/io.h>
#include "avr_adc.h"

adc_err_type ADC_InitDefault(void) {
return ADC_Init(0); //initializare ADC = pornirea ADC si setare sursa de ref
}

adc_err_type ADC_Init(void* context) {


if (!context) {

ADC_Enable(); //pornire adc


ADC_SetReferenceSource(ADC_REF_SRC_AVCC); //setarea sursei de referinta
}
return ADC_E_OK;
}

void ADC_Enable(void) {
//ADCSRA - ADC cntrl & status reg [ADEN ADSC ADATE ADIF ADPS2-0]
ADCSRA |= 1 << ADEN;
}

void ADC_Disable(void) {
ADCSRA &= ~(1 << ADEN);
}

adc_err_type ADC_SetReferenceSource(adc_ref_type ref) {


if (ref < 0 || ref > 3)
return -1;
//ADMUX - ADC MULTIPLEXER SELECT [REFS1 REFS0 ADLAR MUX 4-0]
ADMUX = (ADMUX & ~((1 << REFS1) | (1 << REFS0))) | (ref << REFS0) ;

return 0;
}

int ADC_GetData(char channel){


int adcData = 0;

while(ADCSRA & 1 << ADSC); //wait until ADC is busy


channel &= 0x07; //normalize the channel, leave last 3 bits LSB; 7=0111
//channel=00000xxx
ADMUX = (ADMUX & ~(0x07)) | channel; //apply the channel to the ADMUX with protection of configuration bits
//ADMUX=xxxxx111 | channel = xxxxx111
ADCSRA |= (1<<ADSC); //start conversion
while (ADCSRA & (1<<ADSC)); //wait until conversion is complete
adcData = ADC;//ADC=_SFR_IO16(0x04)
/* The Analog to Digital Converter registers are defined like so:
#define ADC _SFR_IO16(0x04)
#define ADCL _SFR_IO8(0x04)
#define ADCH _SFR_IO8(0x05)*/
return adcData;
}

/*
* avr_adc.h
*/
#ifndef AVR_ADC_H_
#define AVR_ADC_H_

typedef enum adc_err_enum {ADC_E_OK = 0, ADC_E_NOT_OK} adc_err_type;


typedef enum adc_ref_enum {ADC_REF_SRC_AVCC = 0, ADC_REF_SRC_AREF=1,ADC_REF_SRC_2_56 = 3} adc_ref_type;
typedef struct ADC_Context{
char admux_mode:5;
char refs:2;
char adlar:1;
char enable:1;
} context_type;

adc_err_type ADC_InitDefault(void);
adc_err_type ADC_Init(void* context);
void ADC_Enable(void);
void ADC_Disable(void);
adc_err_type ADC_SetReferenceSource(adc_ref_type ref);
int ADC_GetData(char channel);

#endif /* AVR_ADC_H_ */

/*
* lm20.c
*/
#include "lm20.h"
#include "avr_adc.h"
#include "utils.h"

//Temperature (T) Typical VO


// 130°C 303 mV
// 100°C 675 mV
// 80°C 919 mV
// 30°C 1515 mV
// 25°C 1574 mV
// 0°C 1863.9 mV
// -30°C 2205 mV
// -40°C 2318 mV
// -55°C 2485 mV

//definire pe baza datelor din tab


#define LM_20_TEMP_MIN (-55)
#define LM_20_TEMP_MAX 130
#define LM_20_VO_T_MIN 2485
#define LM_20_VO_T_MAX 303
#define ADC_MIN 0
#define ADC_MAX 1023
#define ADC_VI_MIN 0
#define ADC_VI_MAX 5000
#define LM20_TEMP_TABLE_SIZE 9 //in total avem 9 rinduri in tab
int lm20_temp_table[LM20_TEMP_TABLE_SIZE] ={ //date din datasheet: temperatura C
130,
100,
80,
30,
25,
0,
-30,
-40,
-55
};

int lm20_vo_table[LM20_TEMP_TABLE_SIZE] ={//date din datasheet: Vo mV


303,
675,
919,
1515,
1574,
1864,
2205,
2318,
2485
};

void LM20_init(){
ADC_InitDefault();
}

enum LM20_DiagType{
OORH = 0,
OORL = 1,
UNDERT = 2,
OVERT = 4,
Diag_ALL = 255
};

int LM20_OORH_Limit = 0;
int LM20_OORL_Limit = 1;
int LM20_UNDERT_Limit = 2;
int LM20_OVERT_Limit = 4;

int LM20_DiagStatus;

int LM20_GetDiagStatus(int diag_item) {


return (LM20_DiagStatus & (1 << diag_item));
}

int LM20_ClearDiagStatus(int diag_item) {


if (diag_item == Diag_ALL)
LM20_DiagStatus = 0;
else
LM20_DiagStatus &= 1 << diag_item;
return LM20_DiagStatus;
}

int LM20_SetDiagStatus(int diag_item) {


LM20_DiagStatus |= 1 << diag_item;
return LM20_DiagStatus;
}

int LM20_ADC_ToTemperature(int ADCvalue){


// line equation conversion
// (x-x0)/(x1-x0) = (y-y0)/(y1-y0);
/* int LineConversion(int x, int x0, int x1, int y0, int y1){
* int y = ((((long)x-x0)*((long)y1-y0))/(x1-x0)) + y0;
* return y;
*/
int v_in = LineConversion(ADCvalue,ADC_MIN,ADC_MAX,ADC_VI_MIN,ADC_VI_MAX);
int grdC = LookUpConversion(v_in,lm20_vo_table,lm20_temp_table,LM20_TEMP_TABLE_SIZE);
return grdC;
}

int LM20_GetTemp(){

int ADCvalue = ADC_GetData(LM20_ADC_CHANNEL);

int v_in = LineConversion(ADCvalue,ADC_MIN,ADC_MAX,ADC_VI_MIN,ADC_VI_MAX);


int grdC = LookUpConversion(v_in,lm20_vo_table,lm20_temp_table,LM20_TEMP_TABLE_SIZE);

LM20_ClearDiagStatus(Diag_ALL);

if(v_in > LM20_OORH_Limit){


LM20_SetDiagStatus(OORH);
}else if(v_in < LM20_OORL_Limit){
LM20_SetDiagStatus(OORL);
}else if(grdC > LM20_OVERT_Limit){
LM20_SetDiagStatus(OVERT);
}else if(grdC < LM20_UNDERT_Limit){
LM20_SetDiagStatus(UNDERT);
}

return grdC;

}
/*
* lm20.h
*/

#ifndef BSW_DRIVER_LM20_H_
#define BSW_DRIVER_LM20_H_
#define LM20_ADC_CHANNEL 0
void LM20_init();
int LM20_GetTemp();
#endif /* BSW_DRIVER_LM20_H_ */
Concluzii:

La efectuarea acestei lucrari de laboratorator ” Achiziții de date. Senzori’’ am studiat un


program pentru MCU care colectază datele de la senzorul de temperatură LM20. Dupa
care am facut un program pentru MCU, care afișeze datele pe un afișor 16x2.

S-ar putea să vă placă și