Individální projekty MPOA

Mikroprocesory s architekturou ARM

Uživatelské nástroje

Nástroje pro tento web


2017:envi-logger

Toto je starší verze dokumentu!


Zadání

Navrhnete zařízení pro sběr a záznam environmentálních veličin: teplota okolí, barometrický tlak, vlhkost vzduchu a koncentrace CO2. Tyto údaje zaznamenejte na vhodné paměťové medium. Veličiny vzorkujte s periodou alespoň 1min a zobrazte na grafickém displeji. Vyřešte přenos naměřených údajů do počítače.

Úvod

Úlohou v tejto práci, je navrhnúť a postaviť zariadenie pre zber údajov environmentálnych veličín. Celý projekt môžeme rozdeliť do niekoľkých podskupín:

  1. Hardware
    1. Senzor teploty
    2. Senzor vlhkosti
    3. Senzor tlaku
    4. Senzor koncentrácie CO2
    5. Grafický displej
    6. uSD karta
  2. Software

Spracovanie údajov zo senzorov, riadenie display-a bude prebiehať na vývojovej doske NXP FRDM-K64. https://www.nxp.com/products/processors-and-microcontrollers/arm-based-processors-and-mcus/kinetis-cortex-m-mcus/k-seriesperformancem4/k2x-usb/freedom-development-platform-for-kinetis-k64-k63-and-k24-mcus:FRDM-K64F, ktorú bude potrebné patrične upraviť.

Obvody senzorov

Pre zber údajov o prostredí som navrhol dosku, ktorá obsahuje všetky potrebné senzory. Výber jednotlivých senzorov bol viacmenej priamočiary a výchádzal som z dostupných obvodov, ktoré už boli zakúpené. Pre meranie teploty a tlaku je použítý obvod SHT21 firmy Sensirion. https://www.sensirion.com/en/environmental-sensors/humidity-sensors/humidity-temperature-sensor-sht2x-digital-i2c-accurate/. Ide o obvod, ktorý komunikuje sériovou zbernicou I2C. Obvod vyžaduje len málo externých komponentov, blokovací kondenzátor a štandardné pull-up rezistory na vodičoch zbernice. Pre meranie tlaku je použitý obvod HOPE RF, HP03M. http://www.hoperf.de/sensor/barometer_16/HP03M.htm. Tento obvod taktiež komunikuje po zbernici I2C s inými adresami zariadenia ako SHT21, preto možu byť bezproblémov zapojené na jednej zbernici. Riadenie je skomplikované tým, že A/D prevodník v senzore nemá vlastný oscilátor a je nutné mu hodinový signál priviesť externe - signál MCLK, ďalej je odporúčané uviesť prevodník do stavu reset, pri čítaní nameraných údajov, k tomu je pripojený ďalší signál XCLR.
 Pripojenie senzorov SHT21 a HP03M Posledným zo senzorov je senzor koncentrácie CO2. Dostupný bol analógový senzor FIGARO TGS4161 https://cdn.sos.sk/productdata/62/d9/f2bb36a6/tgs-4161.pdf. K tomuto bolo nutné navrhnúť obvod, pre spracovanie signálu, ktorý by bolo možné merať A/D prevodníkom. Senzor generuje malé elektromotorické napätie, ktorého veľkosť zmeny exponenciálne závisí od koncentrácie CO2. Výstupná impedancia tohto senzoru je veľmi veľká, z čoho plynie požiadavka pre spracovanie obvodom s veľmi veľkou vstupnou impedanciou. Odporúčaná impedancia je >100G. Tomu vyhovuje obvod TLC271. ďalšie spracovanie je už iba odcítanie a zosilnenie meraného napätia 5x prístrojovým zosilňovačom.  Spracovanie elektromotorického napätia generovaného TGS4161 a zmeraná prevodová charakteristika: Prevodová charakteristika TGS4161. Celý obvod je kompletne dizajnovaný ako jeden modul. Kompletna schema a PCB  PCB senzorov

Rozširovacia doska a displej

Pre zobrazovanie meraných údajov je použitý TFT grafický displej Sainsmart https://www.sainsmart.com/products/3-2-tft-lcd-touch-screen-with-sd-slot s radičom SSD1289, ktorý komunikuje po paralelnej zbernici kompatibilnej s motorola 6800 štandardom. Najlepší spôsob, ako komunikovať po tejto zbernici, je použiť na to určenú perifériu mikrokontroléra K64 Flexbus. SSD1289 vyžaduje 16 dátových signálov, 1 RW, 1 CS, 1 D/S a 1 RST signál. Nie všetky tieto signály sú prístupné na konektoroch vývojovej dosky. Obsahuje ale neobsadené piny na konektoroch, ku ktorým je možné tieto signály priviesť. Pre pripojenie displeju a modulu so senzormi k vývojovej doske som navrhol a vyrobil ďalšiu dosku preto určenú.  Schéma rozširovacej dosky.  Doska rozširovacej dosky Upravená vývojová doska FRDM-K64 s privedenými chýbajúcimi signálmi zbernice Flexbus: Upravená doska FRDM-K64. Schéma a PCB rozširovacej dosky

uSD karta a ďlašie periférie

Poslednou z nutných periférií pre Datalogger je pamäťové médium. Z výhodou som mohol použiť integrovanú perifériu pre komuniáciu s SDHC kartou. Ďalšie z periférií, ktoré sú prístupné sú LAN, USB a UART pre rozšírenia v budúcnosti. Zostavený dataloger: Zostavený datalogger.

Software

Software je zložený s niekoľkých modulov.

  1. Konfigurácia pinov
  2. Konfigurácia hodinových domén
  3. Kofigurácia periférií a komunikácia
  4. Správa displeja
  5. Ukladanie údajov

Konfigurácia pinov

Pre správnu činnosť periférií je dôležité nastavenie konfigurácií pinov. Každý pin procesora obsahuje multiplexor s privedenými signálmi s rôznych periférií.

  CLOCK_EnableClock(kCLOCK_PortC);                          
  CLOCK_EnableClock(kCLOCK_PortB);
  CLOCK_EnableClock(kCLOCK_PortE);
 
// Set UART
 
  PORT_SetPinMux(PORTC, PIN14_IDX, kPORT_MuxAlt3);           /* PORTB16 (pin 62) is configured as UART0_RX */
  PORT_SetPinMux(PORTC, PIN15_IDX, kPORT_MuxAlt3);           /* PORTB17 (pin 63) is configured as UART0_TX */
  SIM->SCGC1 = (SIM->SCGC1 | SIM_SCGC1_UART4_MASK);
 
  PORT_SetPinMux(PORTB, PIN20_IDX, kPORT_MuxAsGpio);		 // GPIO Heater TGS 4146 1->ON
  PORT_SetPinMux(PORTB, PIN10_IDX, kPORT_MuxAsGpio);
 
//Set SDHC interface
 
  const port_pin_config_t porte0_pin1_config = {
     kPORT_PullUp,                                            /* Internal pull-up resistor is enabled */
     kPORT_FastSlewRate,                                      /* Fast slew rate is configured */
     kPORT_PassiveFilterDisable,                              /* Passive filter is disabled */
     kPORT_OpenDrainDisable,                                  /* Open drain is disabled */
     kPORT_HighDriveStrength,                                 /* High drive strength is configured */
     kPORT_MuxAlt4,                                           /* Pin is configured as SDHC0_D1 */
     kPORT_UnlockRegister                                     /* Pin Control Register fields [15:0] are not locked */
   };
   PORT_SetPinConfig(PORTE, PIN0_IDX, &porte0_pin1_config);   /* PORTE0 (pin 1) is configured as SDHC0_D1 */
   const port_pin_config_t porte1_pin2_config = {
     kPORT_PullUp,                                            /* Internal pull-up resistor is enabled */
     kPORT_FastSlewRate,                                      /* Fast slew rate is configured */
     kPORT_PassiveFilterDisable,                              /* Passive filter is disabled */
     kPORT_OpenDrainDisable,                                  /* Open drain is disabled */
     kPORT_HighDriveStrength,                                 /* High drive strength is configured */
     kPORT_MuxAlt4,                                           /* Pin is configured as SDHC0_D0 */
     kPORT_UnlockRegister                                     /* Pin Control Register fields [15:0] are not locked */
   };
   PORT_SetPinConfig(PORTE, PIN1_IDX, &porte1_pin2_config);   /* PORTE1 (pin 2) is configured as SDHC0_D0 */
   const port_pin_config_t porte2_pin3_config = {
     kPORT_PullUp,                                            /* Internal pull-up resistor is enabled */
     kPORT_FastSlewRate,                                      /* Fast slew rate is configured */
     kPORT_PassiveFilterDisable,                              /* Passive filter is disabled */
     kPORT_OpenDrainDisable,                                  /* Open drain is disabled */
     kPORT_HighDriveStrength,                                 /* High drive strength is configured */
     kPORT_MuxAlt4,                                           /* Pin is configured as SDHC0_DCLK */
     kPORT_UnlockRegister                                     /* Pin Control Register fields [15:0] are not locked */
   };
   PORT_SetPinConfig(PORTE, PIN2_IDX, &porte2_pin3_config);   /* PORTE2 (pin 3) is configured as SDHC0_DCLK */
   const port_pin_config_t porte3_pin4_config = {
     kPORT_PullUp,                                            /* Internal pull-up resistor is enabled */
     kPORT_FastSlewRate,                                      /* Fast slew rate is configured */
     kPORT_PassiveFilterDisable,                              /* Passive filter is disabled */
     kPORT_OpenDrainDisable,                                  /* Open drain is disabled */
     kPORT_HighDriveStrength,                                 /* High drive strength is configured */
     kPORT_MuxAlt4,                                           /* Pin is configured as SDHC0_CMD */
     kPORT_UnlockRegister                                     /* Pin Control Register fields [15:0] are not locked */
   };
   PORT_SetPinConfig(PORTE, PIN3_IDX, &porte3_pin4_config);   /* PORTE3 (pin 4) is configured as SDHC0_CMD */
   const port_pin_config_t porte4_pin5_config = {
     kPORT_PullUp,                                            /* Internal pull-up resistor is enabled */
     kPORT_FastSlewRate,                                      /* Fast slew rate is configured */
     kPORT_PassiveFilterDisable,                              /* Passive filter is disabled */
     kPORT_OpenDrainDisable,                                  /* Open drain is disabled */
     kPORT_HighDriveStrength,                                 /* High drive strength is configured */
     kPORT_MuxAlt4,                                           /* Pin is configured as SDHC0_D3 */
     kPORT_UnlockRegister                                     /* Pin Control Register fields [15:0] are not locked */
   };
   PORT_SetPinConfig(PORTE, PIN4_IDX, &porte4_pin5_config);   /* PORTE4 (pin 5) is configured as SDHC0_D3 */
   const port_pin_config_t porte5_pin6_config = {
     kPORT_PullUp,                                            /* Internal pull-up resistor is enabled */
     kPORT_FastSlewRate,                                      /* Fast slew rate is configured */
     kPORT_PassiveFilterDisable,                              /* Passive filter is disabled */
     kPORT_OpenDrainDisable,                                  /* Open drain is disabled */
     kPORT_HighDriveStrength,                                 /* High drive strength is configured */
     kPORT_MuxAlt4,                                           /* Pin is configured as SDHC0_D2 */
     kPORT_UnlockRegister                                     /* Pin Control Register fields [15:0] are not locked */
   };
   PORT_SetPinConfig(PORTE, PIN5_IDX, &porte5_pin6_config);   /* PORTE5 (pin 6) is configured as SDHC0_D2 */
   const port_pin_config_t porte6_pin7_config = {
     kPORT_PullDown,                                          /* Internal pull-down resistor is enabled */
     kPORT_FastSlewRate,                                      /* Fast slew rate is configured */
     kPORT_PassiveFilterDisable,                              /* Passive filter is disabled */
     kPORT_OpenDrainDisable,                                  /* Open drain is disabled */
     kPORT_LowDriveStrength,                                  /* Low drive strength is configured */
     kPORT_MuxAsGpio,                                         /* Pin is configured as PTE6 */
     kPORT_UnlockRegister                                     /* Pin Control Register fields [15:0] are not locked */
   };
   PORT_SetPinConfig(PORTE, PIN6_IDX, &porte6_pin7_config);   /* PORTE6 (pin 7) is configured as PTE6 */
}
 
void BOARD_I2C_ConfigurePins(void) {
  CLOCK_EnableClock(kCLOCK_PortE);                           /* Port E Clock Gate Control: Clock enabled */
 
//Set IIC
  const port_pin_config_t porte24_pin31_config = {
    kPORT_PullUp,                                            /* Internal pull-up resistor is enabled */
    kPORT_FastSlewRate,                                      /* Fast slew rate is configured */
    kPORT_PassiveFilterDisable,                              /* Passive filter is disabled */
    kPORT_OpenDrainEnable,                                   /* Open drain is enabled */
    kPORT_LowDriveStrength,                                  /* Low drive strength is configured */
    kPORT_MuxAlt5,                                           /* Pin is configured as I2C0_SCL */
    kPORT_UnlockRegister                                     /* Pin Control Register fields [15:0] are not locked */
  };
  PORT_SetPinConfig(PORTE, PIN24_IDX, &porte24_pin31_config); /* PORTE24 (pin 31) is configured as I2C0_SCL */
  const port_pin_config_t porte25_pin32_config = {
    kPORT_PullUp,                                            /* Internal pull-up resistor is enabled */
    kPORT_FastSlewRate,                                      /* Fast slew rate is configured */
    kPORT_PassiveFilterDisable,                              /* Passive filter is disabled */
    kPORT_OpenDrainEnable,                                   /* Open drain is enabled */
    kPORT_LowDriveStrength,                                  /* Low drive strength is configured */
    kPORT_MuxAlt5,                                           /* Pin is configured as I2C0_SDA */
    kPORT_UnlockRegister                                     /* Pin Control Register fields [15:0] are not locked */
  };
  PORT_SetPinConfig(PORTE, PIN25_IDX, &porte25_pin32_config); /* PORTE25 (pin 32) is configured as I2C0_SDA */
}
 
void BOARD_InitFlexbus(void){
	CLOCK_EnableClock(kCLOCK_PortB);                           /* Port B Clock Gate Control: Clock enabled */
	CLOCK_EnableClock(kCLOCK_PortC);                           /* Port C Clock Gate Control: Clock enabled */
	CLOCK_EnableClock(kCLOCK_PortD);                           /* Port D Clock Gate Control: Clock enabled */
// Set Flexbus
	PORT_SetPinMux(PORTD, PIN6_IDX, kPORT_MuxAlt5);            /* PORTD6 (pin A2) is configured as FB_AD0 */
	PORT_SetPinMux(PORTD, PIN5_IDX, kPORT_MuxAlt5);            /* PORTD5 (pin A3) is configured as FB_AD1 */
	PORT_SetPinMux(PORTD, PIN4_IDX, kPORT_MuxAlt5);            /* PORTD4 (pin A4) is configured as FB_AD2 */
	PORT_SetPinMux(PORTD, PIN3_IDX, kPORT_MuxAlt5);            /* PORTD3 (pin B4) is configured as FB_AD3 */
	PORT_SetPinMux(PORTD, PIN2_IDX, kPORT_MuxAlt5);            /* PORTD2 (pin C4) is configured as FB_AD4 */
	PORT_SetPinMux(PORTC, PIN10_IDX, kPORT_MuxAlt5);           /* PORTC10 (pin C7) is configured as FB_AD5 */
	PORT_SetPinMux(PORTC, PIN9_IDX, kPORT_MuxAlt5);            /* PORTC9 (pin D7) is configured as FB_AD6 */
	PORT_SetPinMux(PORTC, PIN8_IDX, kPORT_MuxAlt5);            /* PORTC8 (pin A8) is configured as FB_AD7 */
	PORT_SetPinMux(PORTC, PIN7_IDX, kPORT_MuxAlt5);            /* PORTC7 (pin B8) is configured as FB_AD8 */
	PORT_SetPinMux(PORTC, PIN6_IDX, kPORT_MuxAlt5);            /* PORTC6 (pin C8) is configured as FB_AD9 */
	PORT_SetPinMux(PORTC, PIN5_IDX, kPORT_MuxAlt5);            /* PORTC5 (pin D8) is configured as FB_AD10 */
	PORT_SetPinMux(PORTC, PIN4_IDX, kPORT_MuxAlt5);            /* PORTC4 (pin A9) is configured as FB_AD11 */
	PORT_SetPinMux(PORTC, PIN2_IDX, kPORT_MuxAlt5);            /* PORTC2 (pin A12) is configured as FB_AD12 */
	PORT_SetPinMux(PORTC, PIN1_IDX, kPORT_MuxAlt5);            /* PORTC1 (pin B11) is configured as FB_AD13 */
	PORT_SetPinMux(PORTC, PIN0_IDX, kPORT_MuxAlt5);            /* PORTC0 (pin B12) is configured as FB_AD14 */
	PORT_SetPinMux(PORTB, PIN18_IDX, kPORT_MuxAlt5);           /* PORTB18 (pin D12) is configured as FB_AD15 */
	PORT_SetPinMux(PORTB, PIN17_IDX, kPORT_MuxAlt5);           /* PORTB17 (pin E9) is configured as FB_AD16 */
 
	PORT_SetPinMux(PORTC, PIN11_IDX, kPORT_MuxAlt5);           /* PORTC11 (pin B7) is configured as FB_RW_b */
	PORT_SetPinMux(PORTB, PIN19_IDX, kPORT_MuxAlt5);           /* PORTB19 (pin D11) is configured as FB_OE_b */
	PORT_SetPinMux(PORTC, PIN3_IDX, kPORT_MuxAlt5);            /* PORTC3 (pin A11) is configured as FB_CLKOUT */
	PORT_SetPinMux(PORTD, PIN1_IDX, kPORT_MuxAlt5);            /* PORTD1 (pin D4) is configured as FB_CS0_b */
}
 

Konfigurácia hodín

Ďalšou z esenciálnych konfigurácií, je nastavenie hodín pre periférie. Hlavným zdrojom je oscilátor v periférii pre fyzickú vrstvu ethernetu 50MHz. Z nej potom PLL blokom generujem hodiny pre jadro 120MHz, pre pamäť 60MHz, Flexbus (Vzhľadom na obmedzenie SSD1289 radiča 25MHz) 15MHz. Zdrojom hodín pre RTC časovač a prevodník snímača tlaku je použitý oscilátor s kryštálom 32,768kHz. Ten funguje aj po vypnutá napájania. Výstup z neho je smerovaný na výstupný pin procesora CLKOUT.

Kofigurácia periférií a komunikácia

TGS4161 a ADC

Pre zber údajov zo senzoru koncentrácie j epoužitý interný prevodník ADC v single ended móde a internou referenciou. Funkcia pre nastavenie periférií:

void Init_CO(void) {
//Set GPIO for heater control
	gpio_pin_config_t heater = { kGPIO_DigitalOutput, 0, };
	GPIO_PinInit(GPIOB, 20U, &heater);
//Get ADC default config
	ADC16_GetDefaultConfig(&adc16ConfigStruct);
 
	adc16ConfigStruct.resolution = kADC16_ResolutionSE16Bit;
	ADC16_Init(DEMO_ADC16_BASE, &adc16ConfigStruct);
	ADC16_EnableHardwareTrigger(DEMO_ADC16_BASE, false);
	if (kStatus_Success == ADC16_DoAutoCalibration(DEMO_ADC16_BASE)) {
		PRINTF("ADC16_DoAutoCalibration() Done.\r\n");
	} else {
		PRINTF("ADC16_DoAutoCalibration() Failed.\r\n");
	}
 
	adc16ChannelConfigStruct.channelNumber = DEMO_ADC16_USER_CHANNEL;
	adc16ChannelConfigStruct.enableInterruptOnConversionCompleted = false;
}
//Set heater on
void Start_sensor(void) {
	GPIO_SetPinsOutput(GPIOB, 1U << 20U);
}
//Reset heater
void Stop_sensor(void) {
	GPIO_ClearPinsOutput(GPIOB, 1U << 20U);
}

Funkcia pre čitanie vzorky vzčítanej prevodníkom - ADC0 kanál 0 single ended:

int32_t get_adc(void) {
 
	ADC16_SetChannelConfig(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP,
			&adc16ChannelConfigStruct);
	while (0U
			== (kADC16_ChannelConversionDoneFlag
					& ADC16_GetChannelStatusFlags(DEMO_ADC16_BASE,
							DEMO_ADC16_CHANNEL_GROUP)))
		;
	return (ADC16_GetChannelConversionValue(DEMO_ADC16_BASE,
			DEMO_ADC16_CHANNEL_GROUP));
}

Prepočet hodnoty zmeranej AD prevodníkom na koncentráciu ppm CO2:

int32_t get_concentration(void){
	float adc_mv;
	float sens_mv;
	float adc_mv_min;
	float sens_mv_min;
	float delta_emf;
	int32_t co2ppm;
 
//Prepocet na rozsah + kalibracia
	adc_mv_min = 5.03321924e-5 * (float)adc_val_min;
	adc_mv = 5.03321924e-5 * (float)get_adc();
//Prepocet prevodová charakteristika
	sens_mv_min = (0.39 - 0.2*adc_mv_min)*1000.0;
	sens_mv = (0.39 - 0.2*adc_mv)*1000.0;
//Prepocet na ppm zo semilox charakteristiky v datasheet-e
	delta_emf = sens_mv_min - sens_mv;
	sens_mv = powf(10.0,(0.0161*delta_emf + 2.5441));
 
	co2ppm = (int32_t)sens_mv;
	return(co2ppm);
 
}
2017/envi-logger.1516594757.txt.gz · Poslední úprava: 2018/01/22 05:19 autor: Miroslav Waldecker