Individální projekty MPOA

Mikroprocesory s architekturou ARM

Uživatelské nástroje

Nástroje pro tento web


2017:envi-logger

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);
 
}

SHT21, HP03M a ADC

Nastavenie IIC periférie a GPIO pre ovládanie XCLR - reset signálu pre HP03M.

void Init_iic(void) {
	BOARD_I2C_ConfigurePins();
	gpio_pin_config_t xclr = { kGPIO_DigitalOutput, 0, };
	GPIO_PinInit(GPIOB, 10U, &xclr);
 
	I2C_MasterGetDefaultConfig(&masterConfig);
	masterConfig.baudRate_Bps = I2C_BAUDRATE;
 
	sourceClock = I2C_MASTER_CLK_FREQ;
 
	I2C_MasterInit(I2C0, &masterConfig, sourceClock);
 
}

Komunikácia s SHT21. Funkcie pre čítanie teploty a vlhkosti a ich prepočet na °C a %RH:

float read_temp() {
 
	uint8_t data[5];
	uint16_t itemp;
	float ftemp;
 
	data[0] = (uint8_t) SHT21_TRIG_TEMP_HM;
	while (kStatus_Success
			!= I2C_MasterStart(I2C0, SHT21_I2C_ADDRESS, kI2C_Write))
		;
 
	while (kStatus_Success
			!= I2C_MasterWriteBlocking(I2C0, data, 1, kI2C_TransferNoStopFlag))
		;
 
	while (kStatus_Success
			!= I2C_MasterRepeatedStart(I2C0, SHT21_I2C_ADDRESS, kI2C_Read))
		;
 
	while (kStatus_Success
			!= I2C_MasterReadBlocking(I2C0, data, 3, kI2C_TransferCompleteFlag))
		;
	itemp = data[0];
	itemp = itemp << 8;
	itemp |= data[1];
	itemp &= 0xFFFC;
	ftemp = -48.85 + (175.72 * ((float) itemp)) / 65536.0;
 
	return (ftemp);
}
 
float read_hum() {
 
	uint8_t data[5];
	uint16_t ihum;
	float fhum;
 
	data[0] = (uint8_t) SHT21_TRIG_HUMIDITY_HM;
	while (kStatus_Success
			!= I2C_MasterStart(I2C0, SHT21_I2C_ADDRESS, kI2C_Write))
		;
	while (kStatus_Success
			!= I2C_MasterWriteBlocking(I2C0, data, 1, kI2C_TransferNoStopFlag))
		;
	while (kStatus_Success
			!= I2C_MasterRepeatedStart(I2C0, SHT21_I2C_ADDRESS, kI2C_Read))
		;
 
	while (kStatus_Success
			!= I2C_MasterReadBlocking(I2C0, data, 3, kI2C_TransferCompleteFlag))
		;
	ihum = data[0];
	ihum = ihum << 8;
	ihum |= data[1];
	ihum &= 0xFFFC;
	fhum = -6.0 + 125.0 * ((float) ihum) / 65536.0;
	return (fhum);
}

Komunikácia s HP03M a výpočet barometrického tlaku, je zaujímavé, že tento senzor obsahuje 2 obvody, v jednom sú kalibračné a kompenzačné údaje, druhý je AD prevodník s meraním teploty pre kompenzáciu a tlaku. Každý z týchto obvodov má inú adresu a iný spôsob ich čítania:

float read_pressure() {
 
	uint8_t eeprom_data[18];
	uint16_t iPressure;
	uint16_t iTemperature;
	uint8_t data_index;
	uint16_t C[7];
	uint8_t coef_A;
	uint8_t coef_B;
	uint8_t coef_C;
	uint8_t coef_D;
	float fTemp;
	float fPressure;
	float dut;
	float offset;
	float sensitivity;
	float xpress;
 
	GPIO_PinWrite(GPIOB, 10U, 1);
 
 
	eeprom_data[0] = 0x10;
 
	while (kStatus_Success != I2C_MasterStop(I2C0))
		;
 
 
	while (kStatus_Success
			!= I2C_MasterStart(I2C0, HP03_I2C_EEPROM_ADDRESS, kI2C_Write))
		;
 
	while (kStatus_Success
			!= I2C_MasterWriteBlocking(I2C0, eeprom_data, 1,
					kI2C_TransferNoStopFlag))
		;
 
	while (kStatus_Success
			!= I2C_MasterRepeatedStart(I2C0, HP03_I2C_EEPROM_ADDRESS, kI2C_Read))
		;
 
	while (kStatus_Success
			!= I2C_MasterReadBlocking(I2C0, eeprom_data, 18,
					kI2C_TransferCompleteFlag))
		;
 
	for (data_index = 0; data_index <= 6; data_index++) {
		C[data_index] = eeprom_data[data_index * 2];
		C[data_index] = C[data_index] << 8;
		C[data_index] |= eeprom_data[(data_index * 2) + 1];
	}
 
	coef_A = eeprom_data[14];
	coef_B = eeprom_data[15];
	coef_C = eeprom_data[16];
	coef_D = eeprom_data[17];
 
 
	while (kStatus_Success
			!= I2C_MasterStart(I2C0, HP03_I2C_AD_ADDRESS, kI2C_Write))
		;
 
	eeprom_data[0] = 0xFF;
	eeprom_data[1] = 0xF0;
 
	while (kStatus_Success
			!= I2C_MasterWriteBlocking(I2C0, eeprom_data, 2,
					kI2C_TransferCompleteFlag))
		;
 
 
	while (kStatus_Success
			!= I2C_MasterStart(I2C0, HP03_I2C_AD_ADDRESS, kI2C_Write))
		;
	eeprom_data[0] = 0xFD;
 
	while (kStatus_Success
			!= I2C_MasterWriteBlocking(I2C0, eeprom_data, 1,
					kI2C_TransferNoStopFlag))
		;
 
	while (kStatus_Success
			!= I2C_MasterRepeatedStart(I2C0, HP03_I2C_AD_ADDRESS, kI2C_Read))
		;
 
	while (kStatus_Success
			!= I2C_MasterReadBlocking(I2C0, eeprom_data, 2,
					kI2C_TransferCompleteFlag))
		;
 
	iPressure = eeprom_data[0];
	iPressure = iPressure << 8;
	iPressure |= eeprom_data[1];
 
 
	while (kStatus_Success
			!= I2C_MasterStart(I2C0, HP03_I2C_AD_ADDRESS, kI2C_Write))
		;
 
	eeprom_data[0] = 0xFF;
	eeprom_data[1] = 0xE8;
 
	while (kStatus_Success
			!= I2C_MasterWriteBlocking(I2C0, eeprom_data, 2,
					kI2C_TransferCompleteFlag))
		;
 
 
	while (kStatus_Success
			!= I2C_MasterStart(I2C0, HP03_I2C_AD_ADDRESS, kI2C_Write))
		;
	eeprom_data[0] = 0xFD;
 
	while (kStatus_Success
			!= I2C_MasterWriteBlocking(I2C0, eeprom_data, 1,
					kI2C_TransferNoStopFlag))
		;
 
	while (kStatus_Success
			!= I2C_MasterRepeatedStart(I2C0, HP03_I2C_AD_ADDRESS, kI2C_Read))
		;
 
	while (kStatus_Success
			!= I2C_MasterReadBlocking(I2C0, eeprom_data, 2,
					kI2C_TransferCompleteFlag))
		;
 
	iTemperature = eeprom_data[0];
	iTemperature = iTemperature << 8;
	iTemperature |= eeprom_data[1];
	GPIO_PinWrite(GPIOB, 10U, 0);
 
	fTemp = (float)iTemperature;
 
	if(iTemperature >= C[4]){
		dut = fTemp - (float)C[4] - ((fTemp-(float)C[4])/128.0) * ((fTemp-(float)C[4])/128.0) * (float)coef_A / (float)(2^coef_C);
	}else{
		dut = fTemp - (float)C[4] - ((fTemp-(float)C[4])/128.0) * ((fTemp-(float)C[4])/128.0) * (float)coef_B / (float)(2^coef_C);
	}
 
	offset = ((float)C[1]+((float)C[3]-1024.0)*dut/16384.0)*4.0;
	sensitivity = (float)C[0]+ (float)C[2]*dut/1024.0;
	xpress = sensitivity * ((float)iPressure-7168.0)/16384.0 - offset;
	fPressure = xpress*10.0/32.0+(float)C[6] + 253.0;
	return (fPressure/10.0);
}

TFT display a FlexBus

Pre riadenie TFT display-u som využil hotovú knižnicu: https://www.element14.com/community/groups/development-tools/blog/2012/05/26/stm32f4-discovery-hy32d-tft-lcd Tú som však musel naportovať pre K64 procesor a zbernicu FluxBus: Inicializácia:

void Init_FlexBus(void){
	flexbus_config_t flexbusUserConfig;
 
	FLEXBUS_GetDefaultConfig(&flexbusUserConfig);
 
	flexbusUserConfig.waitStates = 2U;
	flexbusUserConfig.portSize = kFLEXBUS_2Bytes;
	flexbusUserConfig.chipBaseAddress = (uint32_t)TFT_DC_ADDRESS;
	flexbusUserConfig.chipBaseAddressMask = 1U;
	flexbusUserConfig.byteLaneShift = kFLEXBUS_Shifted;
	flexbusUserConfig.autoAcknowledge = true;
 
	FLEXBUS_Init(FB, &flexbusUserConfig);
 }

Zápis dát do pamäte a do registrov:

void vfnSendDataWord(unsigned short value)
  {
    *((unsigned short*)TFT_BASE_ADDRESS) = value;
  }
 
void vfnSendCmdWord(unsigned short cmd)
  {
    *((unsigned short*)TFT_DC_ADDRESS) = cmd;
  }

RTC

Inicializácia a nastavenie hodín reálneho času:

void Init_rtc(void){
 
	 rtc_config_t rtcConfig;
 
	 RTC_GetDefaultConfig(&rtcConfig);
	 RTC_Init(RTC, &rtcConfig);
	    /* Select RTC clock source */
	 RTC_SetClockSource(RTC);
}
 
void rtc_settime(rtc_datetime_t date){
 
	  RTC_StopTimer(RTC);
	  RTC_SetDatetime(RTC, &date);
	  RTC_StartTimer(RTC);
}
 
rtc_datetime_t rtc_gettime(void){
 
	rtc_datetime_t date;
 
	RTC_GetDatetime(RTC, &date);
	return(date);
}

Hlavná slučka a Fat FS

Kinetis software development kit obsahuje okrem štandardných ovládačov periférií aj middleware pre prácu s USB a SD kartami s podporou Fat FS, ktorý som použil. Tým, že zapisujem namerané údaje v textovom formáte, tieto sú po pripojeni SD karty do počítača bezproblémov spracovateľné. V hlavnej slučke sa periodicky vyčítavajú údaje, ktoré sa okamžite zobrazujú na display-i a každých 10s sa otvorí súbor pre zápis a udaje sa zapíšu vo formáte dátum, čas, koncentrácia CO2, teplota, vlhkosť a tlak. Po zápise sa súbor okamžite uzavrie.

while (1) {
 
		date = rtc_gettime();
		sprintf(str, "%02hd-%02hd-%04hd %02hd:%02hd:%02hd     ", date.day,
				date.month, date.year, date.hour, date.minute, date.second);
 
		LCD_SetTextColor(ASSEMBLE_RGB(0, 0, 0));
		LCD_CharSize(16);
		LCD_StringLine(1, 1, (uint8_t*) str);
		co_value = get_concentration();
		sprintf(str, "CO2:%d ppm", co_value);
		LCD_SetTextColor(ASSEMBLE_RGB(0, 0, 0xFF));
		LCD_CharSize(24);
		LCD_StringLine(1, 16, (uint8_t*) str);
 
		temperature = read_temp();
		humidity = read_hum();
		LCD_SetTextColor(ASSEMBLE_RGB(0xFF, 0, 0));
		sprintf(str, "T:   %2.2f C", temperature);
		LCD_StringLine(1, 40, (uint8_t*) str);
		LCD_SetTextColor(ASSEMBLE_RGB(0, 0, 0xFF));
		sprintf(str, "RH:  %2.2f %%", humidity);
		LCD_StringLine(1, 64, (uint8_t*) str);
		LCD_SetTextColor(ASSEMBLE_RGB(0xFF, 0, 0));
		pressure = read_pressure();
		sprintf(str, "P:%6.2fhPa", pressure);
		LCD_StringLine(1, 88, (uint8_t*) str);
		Delay(10);
 
		if(card_ok && prev_second != date.second && !(date.second % 10)){
			sprintf(g_bufferWrite, "%02hd-%02hd-%04hd %02hd:%02hd:%02hd %d %2.2f %2.2f %6.2f \r\n", date.day,
				date.month, date.year, date.hour, date.minute, date.second, co_value, temperature, humidity, pressure);
			f_open(&g_fileObject, _T("/data.dat"), (FA_WRITE | FA_READ | FA_OPEN_APPEND));
 
			error = f_write(&g_fileObject, g_bufferWrite, strlen(g_bufferWrite), &bytesWritten);
			 f_close(&g_fileObject);
			 prev_second = date.second;
		}
	}

Video datalogger

Výpis dát

V tomto bolku je príklad zmeraných dát, potom ako som začal vetrať. Je vidieť, ako klesá koncentrácia CO2, ale zároveň aj s teplotou…

14-01-2018 17:20:10 1052 21.98 27.91 1017.92 
14-01-2018 17:20:20 1021 21.99 27.36 1017.80 
14-01-2018 17:20:30 971 21.93 26.92 1017.80 
14-01-2018 17:20:40 955 21.92 26.60 1017.67 
14-01-2018 17:20:50 939 21.87 25.60 1017.90 
14-01-2018 17:21:00 920 21.83 24.97 1017.95 
14-01-2018 17:21:10 909 21.79 24.63 1017.90 
14-01-2018 17:21:20 884 21.73 24.27 1017.90 
14-01-2018 17:21:30 898 21.64 24.33 1017.95 
14-01-2018 17:21:40 883 21.58 23.90 1017.99 
14-01-2018 17:21:50 917 21.50 24.53 1017.89 
14-01-2018 17:22:00 905 21.41 24.16 1018.08 
14-01-2018 17:22:10 872 21.35 23.40 1017.94 
14-01-2018 17:22:20 862 21.24 23.51 1017.98 
14-01-2018 17:22:30 909 21.13 23.87 1017.94 
14-01-2018 17:22:40 861 21.13 22.79 1017.95 
14-01-2018 17:22:50 833 21.12 22.56 1017.95 
14-01-2018 17:23:00 841 21.11 22.62 1018.04 
14-01-2018 17:23:10 821 21.02 22.26 1017.94 
14-01-2018 17:23:20 814 20.96 22.06 1018.06 
14-01-2018 17:23:30 803 20.91 21.89 1018.05 
14-01-2018 17:23:40 819 20.86 21.93 1017.82 
14-01-2018 17:23:50 864 20.76 23.28 1018.07 
14-01-2018 17:24:00 841 20.71 22.27 1017.97 
14-01-2018 17:24:10 799 20.64 21.51 1018.00 
14-01-2018 17:24:20 794 20.58 21.94 1018.07 

Záver

Tento projekt je prototyp, na ktorom som si overil rôzne senzory, vyskúšal som prostredie MCUXpresso firmy NXP a ich software-ové knižnice pre prácu s ARM procesormi Kinetis KSDK verzie 2.3. K tomu, aby to bol plnohodnotný projekt je nutné prerobiť a dorobiť niekoľko vecí. Najmä radiče pre komunikáciu prerobiť z blokovacieho na neblokovací režim, veľa času stráca procesor tým, že čaká, kým periféria zmeria a odpovie. Ďalej je nutné prerobiť HW vývojovej dosky na zálohovanie z batérie pre kalibračné dáta a hodiny reálneho času. Takisto ovládanie z konzoly a prekopírovávanie uložených dát. Z užívateľského rozhrania je vhodné dorobiť grafické zobrazenie údajov v čase. Debug sériový port, ktorý je teraz použitý previesť na USB com port, a tento sériový port priviesť na malý WiFi modul so serverom, na ktorom budú prístupné namerané údaje z lokálnej siete. Za úvahu stojí aj zmena senzora koncentrácie CO2, keďže je to už pomerne obsolete senzor, ktorý je náchylný na všetky parametre ako napájacie napätie, ktoré v tomto prípade nie je vôbec stabilné, nepresnosť, stále je nutné ho kalibrovať a náročný prepočet.

Zdroje: Zdrojové súbory

2017/envi-logger.txt · Poslední úprava: 2018/01/22 06:23 autor: Miroslav Waldecker