Aquarium-Steuerung
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);