Aquarium-Steuerung

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

von Sascha focus

Hallo zusammen,

momentan versuche ich mich an einer Aquarium-Steuerung. Als Controller fungiert ein PIC18F47J53. Dieser besitzt unter anderem 128kB Flash, 12 Bit A/D Wandler, USB. Zum Einstellen der Parameter wird dieser per USB mit einem PC verbunden.

Momentaner Stand:

  • LCD-Ausgabe
  • Temperaturmessung mittels DS18B20
  • Berechnung von Sonnenauf- und -untergang
  • Berechnen der Mondphase

LCD-Steuerung

Hier eine Ansteuerung im 4Bit-Mode. Die Pins können beliebig gewählt werden

Source File lcd.c

#include "p18cxxx.h"
#include "lcd.h"
#include <delays.h>        


static void lcd_nibble( unsigned char d )
{
  LCD_D4 = 0; if( d & 1<<4 ) LCD_D4 = 1;
  LCD_D5 = 0; if( d & 1<<5 ) LCD_D5 = 1;
  LCD_D6 = 0; if( d & 1<<6 ) LCD_D6 = 1;
  LCD_D7 = 0; if( d & 1<<7 ) LCD_D7 = 1;

  LCD_E0 = 1;
  _delay_us( 1 );			// 1us
  LCD_E0 = 0;
}


static void lcd_byte( unsigned char d )
{
  lcd_nibble( d );
  lcd_nibble( d<<4 );
  _delay_us( 45 );			// 45µs
}


void lcd_command( unsigned char d )     //Kommando senden
{
  LCD_RS = 0;
  lcd_byte( d );
  switch( d ){
    case 1:
    case 2:
    case 3: _delay_ms( 2 );		// warte 2ms
  }
}


void lcd_data( unsigned char d )        //Daten senden
{
  LCD_RS = 1;
  lcd_byte( d );
}


void lcd_text(unsigned char *string)
{
while(*string != 0){ //Text aus Ram senden
lcd_data(*string++); 
}
}

void lcd_text_rom(unsigned rom char *string){
while(*string != 0){ //Text aus Rom senden
lcd_data(*string++);
}
}

void lcd_init( void )
{
  LCD_DDR_D4 = 0;
  LCD_DDR_D5 = 0;
  LCD_DDR_D6 = 0;
  LCD_DDR_D7 = 0;
  LCD_DDR_RS = 0;
  LCD_DDR_E0 = 0;

  LCD_E0 = 0;
  LCD_RS = 0;				// send commands
  _delay_ms( 15 );			// warte 15ms

  lcd_nibble( 0x30 );
  _delay_ms( 5 );			// warte >4.1ms

  lcd_nibble( 0x30 );
  _delay_us( 100 );			// warte >100æs

  lcd_nibble( 0x30 );			// 8 bit mode
  _delay_us( 100 );			// warte >100µs

  lcd_nibble( 0x20 );			// 4 bit mode
  _delay_us( 100 );			// warte >100µs

  lcd_command( 0x28 );			// 2 lines 5*7
  lcd_command( 0x08 );			// display off
  lcd_command( 0x01 );			// display clear
  lcd_command( 0x06 );                  // cursor increment
  lcd_command( 0x0C );			// on, no cursor, no blink
}


void lcd_pos( unsigned char line, unsigned char column )
{
  if( line & 1 )                        // LCD Position setzen
    column += 0x40;

  lcd_command( 0x80 + column );
}

void print5(unsigned int x)             // 5 stellige Dezimalzahl ausg.
	{
  unsigned int y;
  		y=x/10000;
		lcd_data(y+0x30);
		x-=(y*10000);
		y=x/1000;
		lcd_data(y+0x30);
		x-=(y*1000);
		y=x/100;
		lcd_data(y+0x30);
		x-=(y*100);
		y=x/10;
		lcd_data(y+0x30);
		x-=(y*10);
		lcd_data(x+0x30);
	}
void print2(unsigned char x)             // 2 stellige Dezimalzahl ausg.
{
  unsigned char y;
		y=x/10;
		lcd_data(y+0x30);
		x-=(y*10);
		lcd_data(x+0x30);
}

void delay_1us()
{
unsigned int i;
	for (i=0;i<12;i++)
		{
		Delay1TCY();
		}
}

void _delay_us( unsigned int us)
{
unsigned int i;
	for (i=0;i<us;i++)
		{
		delay_1us();
		}
}

void _delay_ms( unsigned int ms)
{
unsigned int i;
	for (i=0;i<ms;i++)
		{
  		Delay1KTCYx(12);
		}
}

Header-File lcd.h

void lcd_command( unsigned char d );
void lcd_data( unsigned char d );
void lcd_text(unsigned char *string);
void lcd_text_rom(unsigned rom char *string);
void lcd_init( void );
void lcd_pos( unsigned char line, unsigned char column );
void delay_1us();
void _delay_us( unsigned int us);
void _delay_ms( unsigned int ms);
void print5(unsigned int x);
void print2(unsigned char x);

 
#define	LCD_D4		LATDbits.LATD4
#define	LCD_DDR_D4	TRISDbits.TRISD4

#define	LCD_D5		LATDbits.LATD5
#define	LCD_DDR_D5	TRISDbits.TRISD5

#define	LCD_D6		LATDbits.LATD6
#define	LCD_DDR_D6	TRISDbits.TRISD6

#define	LCD_D7		LATDbits.LATD7
#define	LCD_DDR_D7	TRISDbits.TRISD7

#define	LCD_RS		LATDbits.LATD2
#define	LCD_DDR_RS	TRISDbits.TRISD2

#define	LCD_E0		LATDbits.LATD3
#define	LCD_DDR_E0	TRISDbits.TRISD3

Berechnung Sonnenaufgang/Untergang und Mondphase

Dies stammt natürlich nicht aus meinen Federn. Die Berechnung findet man hier im Forum oder aber auch im Internet.

Für die Berechnung des Sonnenaufgangs/-untergangs benötigt man das Datum und die Längen- und Breitengrade des Ortes. Nach Aufruf von

sun (date_t datum, lonlat_t koord, UINT8 rise, INT8 localOffset, time_t* zeit);

findet man in de Strukturen rise_time und fall_time die Uhrzeiten.

Für die Mondphase benötigt man das Datum. Als Rückgabewert erhält man:

  • 0 = Neumond
  • 1 = Viertelmond (zunehmend, Sichel nach links)
  • 2 = Halbmond (zunehmend, Sichel nach links)
  • 3 = 3/4 Mond (zunehmend, Sichel nach links)
  • 4 = Vollmond
  • 5 = 3/4 Mond (abnehmend, Sichel nach rechts)
  • 6 = Halbmond (abnehmend, Sichel nach rechts)
  • 7 = Viertelmond (abnehmend, Sichel nach rechts)


Source-File sun.c

#include <stdlib.h>
#include "GenericTypeDefs.h"
#include <string.h>
#include <math.h>
#include <stdio.h>
#include "sun.h"
#include "HardwareProfile.h"

#define M_PI   3.14159265358979323846
#define Pi M_PI
#define ZPi 2*M_PI
#define PY 0.0174532925199432957692369076848861
#define Pi2 1.5707963267948966192313216916398
#define frac(x) ((x)-floor(x))
#define int(x)  ((x)<0? -ceil(-x):floor(x))


void sun( date_t datum, lonlat_t koord, UINT8 rise, INT8 localOffset, time_t* zeit  ){

/*!
 * Source:
 *	Almanac for Computers, 1990
 *	published by Nautical Almanac Office
 *	United States Naval Observatory
 *	Washington, DC 20392
 *
 * http://www.best.com/~williams/sunrise_sunset_algorithm.htm
 *
 * Inputs:
 * - datum:      date of sunrise/sunset
 * - koord:   location for sunrise/sunset
 * - zenith:                Sun's zenith for sunrise/sunset defined as macro
 * 	- offical      = 90 degrees 50'  == Aufgang
 * 	- civil        = 96 degrees
 * 	- nautical     = 102 degrees   == Daemmerung
 * 	- astronomical = 108 degrees
 *
 * - rise: 1 for calculating sunrise, 0 for calculating sunset
 * - localOffset: offset to UTC. 1 for MEZ, 2 for MESZ
 * Output:
 * - zeit: structure for rise/set-time 
 *	NOTE: longitude is positive for East and negative for West

 * Beispiel: Berechnet die Auf- und Untergangszeiten, wie sie im 'Himmelsjahr' angegeben sind
 * =========
date_t datum;
lonlat_t koord;
time_t rise_time;
time_t fall_time;
	koord.longitude=10.0;
	koord.latitude=50.0;
	datum.year=2008;
	datum.month=1;
	datum.day=19;
	sun(datum,koord,1,1,&rise_time);
	sun(datum,koord,0,1,&fall_time);


 */

#define zenith 90.833333333333

UINT16 N1, N3, N;
float lngHour, t;
float M, L, RA;
float SinDec, CosDec, CosH;
float H, T, UT, localT;

/* 1. first calculate the day of the year */

	N1 = (275 * datum.month) / 9;
//0-1 1-2 2-2 3-2
	N3 = (datum.year & 3) ? 2:1;
	N = N1 +datum.day - 30;
	if( datum.month>2 ) N-=N3;

/* 2. convert the longitude to hour value and calculate an approximate time */

	lngHour = koord.longitude / 15;

	t = rise ? 6:18;
	t = N + ((t - lngHour) / 24);

/* 3. calculate the Sun's mean anomaly */

	M = (0.017201965 * t) - 0.057403879;

/* 4. calculate the Sun's true longitude */

	L = M + ((0.033440508 * sin(M)) + (0.0003490658504 * sin(2 * M)) + 4.932893878);
	if( L>=ZPi ) L-=ZPi;
	if( L<0 )    L+=ZPi;	// NOTE: L potentially needs to be adjusted into the range [0,360) by adding/subtracting 360

/* 5a. calculate the Sun's right ascension */

	RA = atan(0.91764 * tan(L));
	if( RA>ZPi ) RA-=ZPi;
	if( RA<0 )   RA+=ZPi;	// NOTE: RA potentially needs to be adjusted into the range [0,360) by adding/subtracting 360

/* 5b. right ascension value needs to be in the same quadrant as L */

	RA = RA/PY + ( (floor( L/Pi2)) - (floor(RA/Pi2)) )* 90.0;

/* 5c. right ascension value needs to be converted into hours */

	RA /= 15;

/* 6. calculate the Sun's declination */

	SinDec = 0.39782 * sin(L);
	CosDec = cos(asin(SinDec));

/* 7a. calculate the Sun's local hour angle */

	CosH = (cos(zenith*PY) - (SinDec * sin(koord.latitude*PY))) / (CosDec * cos(koord.latitude*PY));

//	if (CosH >  1) document.write("Die Sonne geht hier heute nicht auf");
//	if (CosH < -1) document.write("Die Sonne geht hier heute nicht unter");

/* 7b. finish calculating H and convert into hours */

	H = acos(CosH)/PY;
	if( rise )  H = 360.0 - H;
	H /= 15.0;

/* 8. calculate local mean time of rising/setting */
	T = H + RA - (0.06571 * t) - 6.622;

/* 9. adjust back to UTC */

	UT = T - lngHour;
	if( UT<0 )		UT += 24;
	if( UT>=24 ) 	UT -= 24;	// NOTE: UT potentially needs to be adjusted into the range [0,24) by adding/subtracting 24

/* 10. convert UT value to local time zone of latitude/longitude */

	localT = UT + localOffset;

	zeit->h = floor( localT );
	zeit->m = floor( 60 * ( localT - zeit->h ));
}

long Moon_phase(long year,long month,long day)
{
    /*k
      Calculates the moon phase (0-7), accurate to 1 segment.
      0 = > new moon.
      4 => Full moon.
    */
   
    long g;
	long e;

    if (month == 1) --day;
    else if (month == 2) day += 30;
    else // m >= 3
    {
        day += 28 + (month-2)*3059/100;

        // adjust for leap years
        if (!(year & 3)) ++day;
        if ((year%100) == 0) --day;
    }
   
    g = (year-1900)%19 + 1;
    e = (11*g + 18) % 30;
    if ((e == 25 && g > 11) || e == 24) e++;
    return ((((e + day)*6+11)%177)/22 & 7);
}

Header File sun.h

typedef struct
	{	UINT8 h;
		UINT8 m;
	} time_t;

typedef struct
	{	UINT16 year;
		UINT8 month;
		UINT8 day;
	} date_t;

typedef struct
	{	float longitude;
		float latitude;
	} lonlat_t;

void sun( date_t datum, lonlat_t koord, UINT8 rise, INT8 localOffset, time_t* zeit );
long Moon_phase(long year,long month,long day);

Links