SD kártyára mentés és LCD-re kiírás egyben

Avatar
Robert
Elektronbűvölő
Hozzászólások: 10191
Csatlakozott: 2005. december 9. péntek, 7:00

Hozzászólás Szerző: Robert »

Kódot kéne látni.
SD írás: 1 flash cella (blokk) 2...5 msec!
De bekavar más INT is:
Delay() van?

Igaz sehol nem használsz delayMicroseconds() utasítást? Az 8 usecenként INT-ezik!
Memória mennyire szabad? Igaz nem M168-as ICben vagy, hanem 328-as vagy nagyobban?
ChipSelect jól kezelődik? A kártyát időnként ugye újrainicializálod?
Avatar
yflk32
DrótVégénSzéndarab
Hozzászólások: 27
Csatlakozott: 2012. január 6. péntek, 7:00

Hozzászólás Szerző: yflk32 »

Robert írta:Kódot kéne látni.
SD írás: 1 flash cella (blokk) 2...5 msec!
De bekavar más INT is:
Delay() van?

Igaz sehol nem használsz delayMicroseconds() utasítást? Az 8 usecenként INT-ezik!
Memória mennyire szabad? Igaz nem M168-as ICben vagy, hanem 328-as vagy nagyobban?
ChipSelect jól kezelődik? A kártyát időnként ugye újrainicializálod?
Ok. Köszönöm! Kódot ma feltöltöm, miután hazaértem.
Avatar
yflk32
DrótVégénSzéndarab
Hozzászólások: 27
Csatlakozott: 2012. január 6. péntek, 7:00

Hozzászólás Szerző: yflk32 »

ATMega328-ra.

Ez az eddigi kód:

/*
BOYLER TERMOSZTAT v1.5
2012-10-03

Periferiak:
- LM35 tempsensor
- Nokia5110 LCD
- SD module
- RTC module (meg nincs)

NOKIA LCD PINS (SPI) definied in nokia_3310_lcd.h:
---(D6 -> CE/CS)
---(D8 -> DC)
---(D9 -> RESET)
---(D11 -> MOSI)
---(D13 -> CLK)

SD MODULE PINS (SPI):
---(D10 -> CS)
---(D11 -> MOSI)
---(D12 -> MISO)
---(D13 -> CLK)
*/
#include <nokia_3310_lcd.h>


#include "Andrew.h"
#include <SdFat.h>
//#include "pacman.h"
//#include <TimerOne.h>
// Specify data and clock connections and instantiate SHT1x object
#define SENSORPIN 5 // what pin we're connected to LM35
//int sensorPin = 5;
int SD_CS = 10;
//int cardError = 0;
SdFat sd;
SdFile myFile;


//keypad debounce parameter
#define DEBOUNCE_MAX 15
#define DEBOUNCE_ON 10
#define DEBOUNCE_OFF 3

#define NUM_KEYS 5 //count of buttons
#define NUM_MENU_ITEM 5 //count of menus

// joystick numbers
#define UP_KEY 1
#define LEFT_KEY 3
#define CENTER_KEY 4
#define DOWN_KEY 2
#define RIGHT_KEY 0

// Pin used by Backlight, so we can turn it on and off. Pin setup in LCD init function
#define BL_PIN 7 //---(D7 -> Backlight)---

// menu starting points
#define MENU_X 5 // 0-83
#define MENU_Y 1 // 0-5

// adc preset value, represent top value,incl. noise & margin,that the adc reads, when a key is pressed
// set noise & margin = 30 (0.15V@5V)
int adc_key_val[5] ={
30, 150, 360, 535, 760 };

float tempc = 0.00; //,tempf=0; // temperature variables
float tempb = 0.00; //,tempf=0; // temperature variables
float samples[8]; // variables to make a better precision
float maxi = -100.00, mini = 100.00;

unsigned long millisTimer;
unsigned long start_time;
unsigned char ora=22;
unsigned char perc=54;
unsigned char mp=10;
unsigned int ev=2012;
unsigned char ho=10;
unsigned char nap=2;

int myseconds = 0;
// debounce counters
byte button_count[NUM_KEYS];
// button status - pressed/released
byte button_status[NUM_KEYS];
// button on flags for user program
byte button_flag[NUM_KEYS];

// menu definition
char menu_items[NUM_MENU_ITEM][14]={
"1.HOMERO",
"2.PARATART.",
"3.HATTERFENY",
"4.DEMO",
"5.INFO"
};

void (*menu_funcs[NUM_MENU_ITEM])(void) = {
temperature,
humidity,
backlight,
demo,
about
};

char current_menu_item;
int blflag = 0; // Backlight initially ON
char degree = 0x7b; // Degree symbol


Nokia_3310_lcd lcd=Nokia_3310_lcd();

void setup()
{
Serial.begin(9600);
pinMode(4, OUTPUT); //SD WRITE LED
pinMode(SD_CS, OUTPUT);
pinMode(BL_PIN, OUTPUT); //Backlight
pinMode(6, OUTPUT); //LCD CS
digitalWrite(6, HIGH); //LCD DISABLE
// setup interrupt-driven keypad arrays
// reset button arrays
for(byte i=0; i<NUM_KEYS; i++){
button_count=0;
button_status=0;
button_flag=0;
}

digitalWrite(6, HIGH); //LCD DISABLE
digitalWrite(SD_CS, LOW); //SD ENABLE
// Initialize SdFat or print a detailed error message and halt
// Use half speed like the native library.
// change to SPI_FULL_SPEED for more performance. //SPI_FULL_SPEED / SPI_HALF_SPEED
if (!sd.begin(SD_CS, SPI_HALF_SPEED)) {
sd.initErrorHalt();
//cardError = 1;
digitalWrite(SD_CS, HIGH); //SD DISABLE
digitalWrite(6, LOW); //LCD ENABLE
} /*else { //ha ez a rész aktív, akkor nem megy
cardError = 0;
// open the file for write at end like the Native SD library
if (!myFile.open("test.txt", O_RDWR | O_CREAT | O_AT_END)) {
sd.errorHalt("opening test.txt for write failed");
cardError = 1;
} else {
cardError = 0;
//dataString += (millis()/1000);
//dataString += ","; // add a comma

// if the file opened okay, write to it:
Serial.println("RESTART SD CARD...");
myFile.println("- RESTART -");
myFile.println("-----------");
myFile.print("millis()/1000");
myFile.print(", ");
myFile.print("tempb");
myFile.print(", ");
myFile.print("maxi");
myFile.print(", ");
myFile.print("mini");
myFile.println(", ");
Serial.println("Write header to card:");
Serial.print("millis()/1000");
Serial.print(", ");
Serial.print("tempb");
Serial.print(", ");
Serial.print("maxi");
Serial.print(", ");
Serial.print("mini");
Serial.println(", ");
//Serial.println("dataString");
// close the file:
myFile.close();
//Serial.println("done.");
}
}
/**/
digitalWrite(SD_CS, HIGH); //SD DISABLE
digitalWrite( BL_PIN, LOW );
// Setup timer2 -- Prescaler/256
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
TCCR2B = (1<<CS22)|(1<<CS21);

ASSR |=(0<<AS2);

// Use normal mode
TCCR2A =0;
//Timer2 Overflow Interrupt Enable
TIMSK2 |= (0<<OCIE2A);
TCNT2=0x6; // counting starts from 6;
TIMSK2 = (1<<TOIE2);

SREG|=1<<SREG_I;
/**/
/*
// interrupt interval in uSec
// this determines how long to keep each row turned on
// so if we have 5 rows, we redraw the whole screen
// once every 5 rows * 3 cycles per row * 1000 usec = .015 sec -> 66.67Hz
// if you perceive flickering you can decrease to 500 for a 133.33Hz rate

Timer1.initialize(100000);
Timer1.attachInterrupt(display); // ISR
/**/

start_time = millis();
lcd.init();
lcd.clear();
(*menu_funcs[0])();
lcd.clear();
//menu initialization
init_MENU();
current_menu_item = 0;
}



void loop() {

byte i;
for(i=0; i<NUM_KEYS; i++) {
if(button_flag !=0) {

button_flag=0; // reset button flag
switch(i){
case UP_KEY:
// current item to normal display
lcd.writeString(MENU_X, MENU_Y + current_menu_item, menu_items[current_menu_item], MENU_NORMAL );
current_menu_item -=1;
if(current_menu_item <0) current_menu_item = NUM_MENU_ITEM -1;
// next item to highlight display
lcd.writeString(MENU_X, MENU_Y + current_menu_item, menu_items[current_menu_item], MENU_HIGHLIGHT );
lcd.update();
lcd.writeString(MENU_X, MENU_Y + current_menu_item, menu_items[current_menu_item], MENU_HIGHLIGHT );
break;

case DOWN_KEY:
// current item to normal display
lcd.writeString(MENU_X, MENU_Y + current_menu_item, menu_items[current_menu_item], MENU_NORMAL );
current_menu_item +=1;
if(current_menu_item >(NUM_MENU_ITEM-1)) current_menu_item = 0;
// next item to highlight display
lcd.writeString(MENU_X, MENU_Y + current_menu_item, menu_items[current_menu_item], MENU_HIGHLIGHT );
lcd.update();
lcd.writeString(MENU_X, MENU_Y + current_menu_item, menu_items[current_menu_item], MENU_HIGHLIGHT );
break;

case LEFT_KEY:
init_MENU();
current_menu_item = 0;
break;

case RIGHT_KEY:
lcd.clear();
(*menu_funcs[current_menu_item])();
lcd.clear();
init_MENU();
current_menu_item = 0;
break;
}
}
}
}




/* menu functions */
void init_MENU(void) {

byte i;
lcd.clear();
lcd.writeString(0, 0, "--= FOMENU =--", MENU_NORMAL);
lcd.writeString(MENU_X, MENU_Y, menu_items[0], MENU_HIGHLIGHT );

for (i=1; i<NUM_MENU_ITEM; i++) {
lcd.writeString(MENU_X, MENU_Y+i, menu_items, MENU_NORMAL);
}
}




// waiting for center key press
void waitfor_OKkey() {
byte i;
byte key = 0xFF;
while (key!= CENTER_KEY){
for(i=0; i<NUM_KEYS; i++){
if(button_flag !=0){
button_flag=0; // reset button flag
if(i== CENTER_KEY) key=CENTER_KEY;
}
}
}
}





// Check if joystick is moved or pressed
byte checkKeypressed() {
byte key = 0xFF;

for(int i=0; i<NUM_KEYS; i++){
if(button_flag !=0){
button_flag=0; // reset button flag
if(i== CENTER_KEY) key=CENTER_KEY;
}
}
return key;
}


char rtcStr[8];
// Format a number to string
void formatStr( int dnum ) {
// First part before decimalpoint
itoa( dnum, rtcStr, 10 );
int pos = strlen(rtcStr);

if( dnum > 9 ) {
itoa( dnum, rtcStr, 10 );
} else {
rtcStr[pos++] = '0';
itoa( dnum, rtcStr, 10 );
}

}


char numStr[8];

// Format a number to 2 decimal places
void formatNum( int num ) {
// First part before decimalpoint
itoa( num / 100, numStr, 10 );
int pos = strlen( numStr );
numStr[pos++] = '.';
int decimal = num % 10;
itoa( decimal, &numStr[pos], 10 );

}


// Display temperature
void temperature() {
int temp1, tempmaxi, tempmini;

//lcd.writeString(10, 0, "HOMERSEKLET", MENU_NORMAL );
lcd.writeString(23, 5, "VISSZA", MENU_HIGHLIGHT );
lcd.writeString(0, 5, "<C", MENU_HIGHLIGHT );
//lcd.drawLine(0,7,83,7, PIXEL_ON); //felso vizsz.vonal (opcio: vizsz.kezdo, fugg.kezdo, vizsz.veg, fugg.veg)
//lcd.drawLine(0,39,83,39, PIXEL_ON); //also vizsz.vonal
lcd.drawLine(71,10,83,10, PIXEL_ON); //felso vizsz.vonal
lcd.drawLine(71,36,83,36, PIXEL_ON); //also vizsz.vonal
lcd.drawLine(71,10,71,36, PIXEL_ON); //elso fugg.vonal
lcd.drawLine(83,10,83,36, PIXEL_ON); //utolso fugg.vonal
//lcd.drawLine(0,7,0,39, PIXEL_ON); //elso fugg.vonal
lcd.drawLine(71,23,83,23, PIXEL_ON); //kozepso vizsz.vonal
// Display non changing text, there is a slight delay while first reading is taken
lcd.gotoXY( 51,2 );
lcd.print( degree );
lcd.print( "C" );

long lastUpdate = 0; // Force update
byte i;
byte key = 0xFF;
long ccount = 0;
long ccount2 = 0;
// Loop to display temperaure/humidity with check for key press to exit
while (key!= CENTER_KEY) {

ccount++;
ccount2++;
if (ccount2 == 14000){
ccount2 = 0;
lcd.gotoXY(10,0);
formatStr(ora);
//lcd.writeString(0, 2, rtcStr, MENU_NORMAL);
lcd.print(ora);
lcd.print(":");
formatStr(perc);
//lcd.writeString(0, 3, rtcStr, MENU_NORMAL);
lcd.print(perc);
lcd.print(":");
formatStr(mp);
//lcd.writeString(0, 4, rtcStr, MENU_NORMAL);
lcd.print(mp);
}

if (ccount == 300000 && tempb > 0 && mini < 100) {
ccount = 0;
digitalWrite(6, HIGH); //LCD DISABLE
delayMicroseconds(100);
digitalWrite(SD_CS, LOW); //SD ENABLE
SDWrite();
delayMicroseconds(100);
digitalWrite(SD_CS, HIGH); //SD DISABLE
delayMicroseconds(100);
digitalWrite(6, LOW); //LCD ENABLE
}

// Update temp
if( millis() > lastUpdate + 1000) {

temp1 = (tempb * 100);
tempmaxi = (maxi * 100);
tempmini = (mini * 100);

// Display temp
//lcd.writeString(0, 0, "-LM35 sensor-", MENU_NORMAL); //ez nem fer ki
formatNum( temp1 );
lcd.writeStringBig(1, 1, numStr, MENU_NORMAL);
lcd.writeString(45, 3, "/50", MENU_NORMAL);
if(maxi != -100 || mini != 100) {
formatNum( tempmaxi );
lcd.writeString(5, 4, numStr, MENU_NORMAL);
formatNum( tempmini );
//lcd.print( degree );
lcd.print( "/" );
lcd.writeString(35, 4, numStr, MENU_NORMAL);
lcd.print( degree );
lcd.print( "C" );
}

lastUpdate = millis();

}

for(i=0; i<NUM_KEYS; i++) {
if(button_flag[i] !=0) {

button_flag[i]=0; // reset button flag

switch(i){

case LEFT_KEY:
maxi = -100;
mini = 100;
//button_flag[i]=0; // reset button flag
lcd.update();
lcd.writeString(23, 5, "VISSZA", MENU_HIGHLIGHT );
lcd.writeString(0, 5, "<C", MENU_HIGHLIGHT );
current_menu_item = 0;
break;

/*case RIGHT_KEY:

//button_flag[i]=0; // reset button flag
current_menu_item = 0;
break;
*/
case CENTER_KEY:
if(i== CENTER_KEY) key=CENTER_KEY;
break;
}
}
}

// key = checkKeypressed();
}
}



// Display humidity in big digits, temperature in small digits underneath
void humidity() {


lcd.writeString(23, 5, "VISSZA", MENU_HIGHLIGHT );

long lastUpdate = 0; // Force update

byte key = 0xFF;
// Loop to display temperaure with check for key press to exit

while (key!= CENTER_KEY){
// Update temp
if( millis() > lastUpdate + 1000) {

// Display temperature
// Display Date/Time
formatStr(ho);
lcd.writeString(0, 0, rtcStr, MENU_NORMAL);

formatStr(nap);
lcd.writeString(0, 1, rtcStr, MENU_NORMAL);

formatStr(ora);
lcd.writeString(0, 2, rtcStr, MENU_NORMAL);

formatStr(perc);
lcd.writeString(0, 3, rtcStr, MENU_NORMAL);

formatStr(mp);
lcd.writeString(0, 4, rtcStr, MENU_NORMAL);

lastUpdate = millis();
}
key = checkKeypressed();
}
}





// Display the about information
void about(){

lcd.gotoXY( 0, 1 );
lcd.print("Temp/RTC/SD" );
lcd.gotoXY( 0, 2 );
lcd.print( "Nokia 5110 LCD" );
lcd.gotoXY( 0, 3 );
lcd.print( "v1.5" );
lcd.writeString(38, 5, "OK", MENU_HIGHLIGHT );
waitfor_OKkey();
}





// Display the simple graphics demo
void demo(){
lcd.writeString( 0, 1, "Text Demo", MENU_NORMAL);
lcd.writeString(24, 5, "START", MENU_HIGHLIGHT );
waitfor_OKkey();
lcd.clear();

lcd.writeStringBig( 0, 0, "123456", MENU_NORMAL );
lcd.writeStringBig( 0, 3, "7890+-.", MENU_NORMAL );
delay(3000);

lcd.writeStringBig( 0, 0, "987654", MENU_HIGHLIGHT );
lcd.writeStringBig( 0, 3, "3210+-.", MENU_HIGHLIGHT );
delay(3000);

lcd.clear();

lcd.writeString( 0, 1, "Graphic Demo", MENU_NORMAL);
//lcd.writeString(24, 5, "START", MENU_HIGHLIGHT );
delay(3000);
//waitfor_OKkey();
lcd.clear();
// Draw some circles pulsing in and out
for(int a=0; a< 4; a++) {
for( int r = 1; r < 49; r+=1 ) {
lcd.drawCircle(42, 24, r, PIXEL_ON );
delay(10);
}
delay(10);
for( int r = 48; r >0; r-=1 ) {
delay(10);
lcd.drawCircle(42, 24, r, PIXEL_OFF );
}
}

delay( 2000 );

// Draw bitmap image
lcd.drawBitmapP( 0,0, &Andrew[0],84,48);
delay(3000);
lcd.clear();
lcd.writeString( 0, 1, "Graphic Demo", MENU_NORMAL);
lcd.writeString( 0, 3, "The End!!", MENU_NORMAL);
lcd.writeString(38, 5, "OK", MENU_HIGHLIGHT );
waitfor_OKkey();
}






// Allow backlight to be turned on and off
void backlight() {

//lcd.writeString( 0, 1, "Atvalt", MENU_NORMAL);
lcd.writeString( 0, 2, "Hatterfeny:", MENU_NORMAL);
lcd.writeString(23, 5, "VISSZA", MENU_HIGHLIGHT );


if( blflag != 0 ) {
lcd.writeString( 65, 2, "KI", MENU_HIGHLIGHT);
}
else {
lcd.writeString( 65, 2, "BE", MENU_HIGHLIGHT);
}


byte key = 0xFF;
while (key!= CENTER_KEY){

byte i;
for(i=0; i<NUM_KEYS; i++) {
if(button_flag[i] !=0) {

button_flag[i]=0; // reset button flag

switch(i){

case LEFT_KEY:
if( blflag == 0 ) {
lcd.writeString( 65, 2, "KI", MENU_HIGHLIGHT);
lcd.update();
lcd.writeString( 65, 2, "KI", MENU_HIGHLIGHT);
lcd.writeString(23, 5, "VISSZA", MENU_HIGHLIGHT );
blflag = 1;
digitalWrite( BL_PIN, HIGH );
}
//button_flag[i]=0; // reset button flag
current_menu_item = 0;
break;

case RIGHT_KEY:
if( blflag == 1 ) {
lcd.writeString( 65, 2, "BE", MENU_HIGHLIGHT);
lcd.update();
lcd.writeString( 65, 2, "BE", MENU_HIGHLIGHT);
lcd.writeString(23, 5, "VISSZA", MENU_HIGHLIGHT );
blflag=0;
digitalWrite( BL_PIN, LOW );
}
//button_flag[i]=0; // reset button flag
current_menu_item = 0;
break;

case CENTER_KEY:
if(i== CENTER_KEY) key=CENTER_KEY;
break;
}
}
}


//waitfor_OKkey();
}



}


// The following are interrupt-driven keypad reading functions
// which includes DEBOUNCE ON/OFF mechanism, and continuous pressing detection


// Convert ADC value to key number
char get_key(unsigned int input) {
char k;

for (k = 0; k < NUM_KEYS; k++) {
if (input < adc_key_val[k]) {
return k;
}
}

if (k >= NUM_KEYS)
k = -1; // No valid key pressed

return k;
}






void update_adc_key() {
int adc_key_in;
char key_in;
byte i;

adc_key_in = analogRead(0);
key_in = get_key(adc_key_in);
for(i=0; i<NUM_KEYS; i++) {
if(key_in==i) { //one key is pressed
if(button_count[i]<DEBOUNCE_MAX) {
button_count[i]++;
if(button_count[i]>DEBOUNCE_ON) {
if(button_status[i] == 0) {
button_flag[i] = 1;
button_status[i] = 1; //button debounced to 'pressed' status
}
}
}
} else { // no button pressed
if (button_count[i] >0) {
button_flag[i] = 0;
button_count[i]--;
if(button_count[i]<DEBOUNCE_OFF) {
button_status[i]=0; //button debounced to 'released' status
}
}
}
}
}





// Timer2 interrupt routine -
// 1/(160000000/256/(256-6)) = 4ms interval

ISR(TIMER2_OVF_vect) {
TCNT2 = 6;
update_adc_key();
myseconds++;
if(millis()-start_time>1000) {
mp++;
kiiras();
start_time+=1000;
}

if (myseconds == 500)
{
myseconds = 0;
tempSensor();
}

}

void kiiras() {
unsigned char honaphossz;
if(mp>59)
{
mp=0;
perc++;
//ebresztes_gomb=0;
//csak akkor torolheto az ebresztesnyugtazas, ha percet ugrott!
if(perc>59)
{
ora++;
perc=0;
if(ora>23)
{
ora=0;
nap++;
switch (ho) {
case 1:
honaphossz = 31;
break;
case 2:
// szokoev van?
honaphossz = 28;
if( (ev%4)==0 )
// neggyel oszthato ev
{
if( (ev%100)!=0 ) {

//nem oszthato 100-zal: szokoev
honaphossz = 29;
} else {
if( (ev%400)==0 ) {

//ha 400-zal oszthato: szokoev
honaphossz=29;
}
}
}
case 3:
honaphossz = 31;
break;
case 4:
honaphossz = 30;
break;
case 5:
honaphossz = 31;
break;
case 6:
honaphossz = 30;
break;
case 7:
honaphossz = 31;
break;
case 8:
honaphossz = 31;
break;
case 9:
honaphossz = 30;
break;
case 10:
honaphossz = 31;
break;
case 11:
honaphossz = 30;
break;
case 12:
honaphossz = 31;
break;
}
if(nap>honaphossz) {
ho++;
nap=1;
if(ho>12){
ho = 1;
ev++;
}
}
}
}
}

Serial.print(ora,DEC);
Serial.print(':');
Serial.print(perc,DEC);
Serial.print(':');
Serial.println(mp,DEC);

}



void tempSensor() {

for(int i = 0; i <= 7; i++){ // gets 8 samples of temperature
samples[i] = ( 5.0 * analogRead(SENSORPIN) * 100.0) / 1024.0;
tempc = tempc + samples[i];
}

tempc = tempc/8.0; // better precision

if(tempc > maxi) {maxi = tempc;} // set max temperature
if(tempc < mini) {mini = tempc;} // set min temperature

tempb = tempc;
tempc = 0;

}

void SDWrite() {

//SD card read/write

// open the file for write at end like the Native SD library
if (!myFile.open("test.txt", O_RDWR | O_CREAT | O_AT_END)) {
//Serial.println("opening test.txt for write failed...");

sd.errorHalt("opening test.txt for write failed");
//cardError = 1;
//return;
} else {
//dataString += (millis()/1000);
//dataString += ","; // add a comma
digitalWrite(4, HIGH); //LED ON
//cardError = 0;
// if the file opened okay, write to it:
//Serial.println("Writing to test.txt...");
myFile.print(ev);
myFile.print(", ");
myFile.print(ho);
myFile.print(", ");
myFile.print(nap);
myFile.print(", ");
myFile.print(ora);
myFile.print(", ");
myFile.print(perc);
myFile.print(", ");
myFile.print(tempb);
myFile.print(", ");
myFile.print(maxi);
myFile.print(", ");
myFile.print(mini);
myFile.println(", ");

Serial.print(millis()/1000);
Serial.print(", ");
Serial.print(tempb);
Serial.print(", ");
Serial.print(maxi);
Serial.print(", ");
Serial.print(mini);
Serial.println(", ");

// close the file:
myFile.close();
//Serial.println("done.");
digitalWrite(4, LOW); //LED OFF

}
}
Avatar
Robert
Elektronbűvölő
Hozzászólások: 10191
Csatlakozott: 2005. december 9. péntek, 7:00

Hozzászólás Szerző: Robert »

SDkiírás befejezése _után_ matass csak a sorosporton...
Ez a setup timer2-es rész nem tetszik arduino szemmel. Regiszterírás? Felsőszintű programból?
Timer1 belepiszkálás? Nem kéne...

Nem használja valamelyik függvény/eljáráskönyvtár duplán esetleg?
Avatar
yflk32
DrótVégénSzéndarab
Hozzászólások: 27
Csatlakozott: 2012. január 6. péntek, 7:00

Hozzászólás Szerző: yflk32 »

Robert írta:SDkiírás befejezése _után_ matass csak a sorosporton...
Ez a setup timer2-es rész nem tetszik arduino szemmel. Regiszterírás? Felsőszintű programból?
Timer1 belepiszkálás? Nem kéne...

Nem használja valamelyik függvény/eljáráskönyvtár duplán esetleg?
A Timer1 kommentelve van, csak a korábbi próba miatt maradt bent.
Maradtam még az SD piszkálás körül és megpróbáltam az írás előtt letiltani az interrupt-okat is:
if (ccount == 500000 && tempb > 0 && mini < 100) {

noInterrupts();
// critical, time-sensitive code here

ccount = 0;
digitalWrite(6, HIGH); //LCD DISABLE
delayMicroseconds(100);
digitalWrite(SD_CS, LOW); //SD ENABLE
SDWrite();
delayMicroseconds(100);
digitalWrite(SD_CS, HIGH); //SD DISABLE
delayMicroseconds(100);
digitalWrite(6, LOW); //LCD ENABLE

interrupts();

}

Így most stabilnak tűnik. Az SD írás alatt így nincs ADC és lehet, hogy ez volt a fő baj. Köszi GPetinek is az interrupt-os javaslatért!
A delayMicroseconds(100); sornak egyébként van létjogosultsága vagy felesleges? Ezt én tettem bele eredetileg.

Éjszaka tesztüzem...
Avatar
Robert
Elektronbűvölő
Hozzászólások: 10191
Csatlakozott: 2005. december 9. péntek, 7:00

Hozzászólás Szerző: Robert »

Delaymicrosec - szerintem - felesleges.
Egy helyen hagynám:

Kód: Egész kijelölése

ccount = 0; 
digitalWrite(6, HIGH); //LCD DISABLE 
// delayMicroseconds(100); 
digitalWrite(SD_CS, LOW); //SD ENABLE 
delayMicroseconds(100); 

SDWrite(); 
//delayMicroseconds(100); 
digitalWrite(SD_CS, HIGH); //SD DISABLE 
//delayMicroseconds(100); 
digitalWrite(6, LOW); //LCD ENABLE 

interrupts(); 

} 
Avatar
yflk32
DrótVégénSzéndarab
Hozzászólások: 27
Csatlakozott: 2012. január 6. péntek, 7:00

Hozzászólás Szerző: yflk32 »

Mostanában nem közöltem a fejleményeket, de tudatom, hogy nem hagytam abba és nem adtam fel a tárgyban szereplő probléma megoldásának keresését.

Olyannyira, hogy sikerrel számolhatok be arról, hogy működik! Igaz a végére majdnem sikerült mind a 32kByte programmemóriát kihasználni.

Jelenleg még nem teljesen élesben, de tesztelem. Leginkább a memóriakártyára írással voltak problémák feltehetően a puffer használat miatt.

Elkészítettem (95%-os szinten áll körülbelül) a kapcsolási és NYÁK rajz, továbbá csináltam hozzá egy blokkvázlatot is, mivel a gombmátrix, az LCD, az RTC, az SD és a relé külön modulként kapcsolódik a mikrovezérlő áramköréhez.

Ha teljesen készen leszek szívesen megosztom majd az érdeklődőkkel.

A kapcsolás blokkvázlata - kép

Röviden, hogy végülis miről van szó:

- A kapcsolást a villanyboyler vezérlésére és működésének monitorozása miatt terveztem. Így egyszerűbben követhető egyrészt az állapota (vízkövesség mértéke), másrészt az egyes időszakok melegvízfogyasztása és a boyler energiaigénye is. Másrészt választ lehet kapni olyan kérdésekre, hogy melyik a jobb, ha magasabb hőfokú vízből fogyasztunk kevesebbet vagy alacsonyabból - nyilván többet, de melyik kerül többe?

- A vezérlés termosztátként fogható fel. Beállítható a kívánt hőfok 50...80°C között és a kapcsolási hiszterézis 1...5°C között.

- Figyeli, hogy az éjszakai áram (vezérelt) rendelkezésre áll-e? Ez csak azért lényeges, mert ha nincs áram, de fűteni kellene, ne legyen behúzva a relé, illetve ez bekerül a log fájlba is, amiből látni lehet, hogy napi hány óra a rendelkezésre állás.

- Az LCD (Nokia kijelző) szinte minden fontos infót egyszerre ki tud jelezni. Nagy karakterekkel jelzi a pillanatnyi mért hőfokot, mellette a beállításokat (hőfok, hiszterézis), a pontos időt, ikonokkal (összesen 17db saját tervezésű ikon van) az SD kártya állapotát (van, nincs), a fűtés állapotát (fűt, nem fűt, fűtene, de nincs áram), a hálózati feszültség meglétét, stb. Az alsó sorban egy sávban grafikusan van megjelenítve a mért hőfok változása, az indítástól mért minimum és maximum hőfok.

- Menükön keresztül lehet a hőfokokat, időt, dátumot programozni. A joystick-al lehet a menüben navigálni, illetve a háttérvilágítást BE vagy AUTO-ra változtatni. Van még 'SD kártya törlés következő resetnél' funkció is és működés közben is biztonságosan kivehető a kártya, ha az adatokat kellene leolvasni.

- Az SD kártyára minden funkcióváltáskor történik mentés, más esetben a beállított időközönként rendszeresen. A hónap, nap, óra, perc, beállított hőfok, beállított hiszterézis, mért hőfok, fűtés be/ki állapot, áram van/nincs állapot kerül mentésre minden egyes alkalommal. Kártya eltávolításakor pedig egy külön sorként (LOG END) dátum és idő mentődik el.

- LED-eken keresztül jelenleg csak a fűtés és az SD kártyára írás/SD hibajelzés van megjelenítve. Minden más az LCD-re íródik ki, aminek a kék háttérvilágítását minden funkcióváltáskor bekapcsolom 5mp-re.

- A hőmérsékletszenzor egy LM35. A pontosabb mérés érdekében osztott feszültségreferenciáról megy. A kijelzés 1 tizedesre kerekített.

- A beállított hőfok, hiszterézis, SD kártya törlési kérelem elmentésre kerül a belső EEPROM-ba is.

- Az EAGLE-ben a blokkvázlathoz és későbbi felhasználásra megterveztem a modulokat külön alkatrészként, méretarányosan.

Nagyjából ennyi, ahol most tartok. Ami még hátravan, az az áramköri terv véglegesítése és elkészítése és az éles teszt, ami után a program is módosulhat még.

Köszi mindenkinek, aki itt a fórumon segített a kezdeti botladozásokon túllépni!

Üdv.: yflk32
Avatar
winnerbt
Elektronbűvölő
Hozzászólások: 907
Csatlakozott: 2007. március 25. vasárnap, 6:00

Hozzászólás Szerző: winnerbt »

Szia!
Ha nem hadititok:
1. Az LM35-t hova tetted?
2. A joystick az analóg jelet ad vagy hogyan működik?
JAni
Avatar
yflk32
DrótVégénSzéndarab
Hozzászólások: 27
Csatlakozott: 2012. január 6. péntek, 7:00

Hozzászólás Szerző: yflk32 »

winnerbt írta:Szia!
Ha nem hadititok:
1. Az LM35-t hova tetted?
2. A joystick az analóg jelet ad vagy hogyan működik?
JAni
Hello! Nincs itt titok... :)

Az LM35 kimenete egy analog bemenetre van kötve. A tápja 5V-os. A felbontása 10mV/°C az adatlapja szerint, azaz 0.01V/°C. Ha nincs külön meghatározva, akkor az A/D átalakító 5V-os referenciával dolgozik. Ez azt jelenti, hogy a bemeneti mért feszültségérték legkisebb egysége 5/1024, mert a 0V = 0 egység, az 5V-os szint pedig 1023-at ad vissza az analog-digital átalakítás után.

Vegyük példának a 25°C-os hőmérséklet mérés folyamatát: Az LM35 kimenete ekkor 0.25V-os szinten áll. Ezt az A/D átalakító egy számértékké konvertálja. Ha 1024/5V=204.8 --> 1V-os szintnél, akkor a 0,25V-nál ez 51.2-t ad vissza. Ez a szám az analogRead(LM35_bemenet) utasítás visszaadott értéke, ha 25°C-ot mérünk. Ahhoz, hogy ebből a programban megkapjuk a 25-öt, egy számítást kell végezni ebből az értékből.
Az analog bemeneten mért értéket szorozni kell 5/1024-el és ezt még szorozni 100-al (mert az LM35 kimenete 0.01V/°C felbontású), hogy megkapd az LM35 által mért hőfokot °C-ban. Képlettel leírva áttekinthetőbb:
mért hőmérséklet = (5 * analogRead(LM35_bemenet) * 100) / 1024.0;

A pontosabb mérési eredmény érdekében én még két dolgot tettem:
1.) amikor a hőmérsékletmérés rutint meghívom, akkor nem 1db mérés történik, hanem egymás után 8x mérek, majd elosztom 8-al, így átlagolva 8 mérés eredményét és ezután végeztetem el a képlet szerinti visszaalakítást.
2.) nem 5V-os analog referenciával dolgozik a kontroller, hanem 2.5V-al. Így az egységnyi érték nem 5/1024, hanem 2.5/1024, ami pontosabb értéket ad vissza, mert feleakkora értéket osztunk fel 1024 részre.
Ehhez annyit kell tenni, hogy az AREF lábra két db ellenállással (de számos más módszerrel is lehet, pl. zenerrel) leosztom felére az 5V-os tápfeszt (pl. 2db 330Ohm-al) és a void setup() részben ezt jelzem az IC és a fordító számára az analogReference(EXTERNAL); utasítással. Innentől kezdve nem az alapértelmezett 5V lesz az A/D átalakító referencia feszültsége (azaz 1023-hoz nem az 5V-os szint fog tartozni), hanem az AREF lábon levő feszültség, ami persze lehetne 5V is, de akkor felesleges az utasítás, illetve lehetne kisebb is, mint 2.5V, de arra figyelni kell, hogy ez lesz minden más analog bemenet referenciája is. (Ez természetesen NEM érinti az LM35 tápfeszültségét, azaz marad továbbra is 5V!)

Ez számomra akkor lett lényeges, amikor a gombmátrix ellenállásértékei az 5V-os szinthez lettek beállítva, illetve a gombokhoz tartozó analog értékek a programban hozzá lettek rendelve egy-egy gombhoz. Miután a fele lett a referencia, meg kellett ezeket az értékeket is változtatnom.

Ebből már ki is derült, hogy a gombok is analog bemenetre lettek kötve. Így én jelen programban 6db nyomógombot kezelek 1db bemeneten.
Egy korábbi programból itt egy példa a bekötésre: Gombmátrix (link)
Az An(0) jelzi az analog bemenetre kötött pontot.

A gombokhoz a programban társítva lettek az értékek.
char uzenet[5][16] = {"Jobbra", "Felfele", "Lefele", "Balra", "OK" };
int analog_gomb_ertek[5] ={30, 150, 360, 535, 760 };



Szóval így működik. :)
Ha nem kellett volna ilyen részletekig menően leírni, akkor elnézést, de másnak még jól jöhet... :)

Üdv.: yflk32
Avatar
kapu48
Elektronbűvölő
Hozzászólások: 3375
Csatlakozott: 2008. augusztus 29. péntek, 6:00

Hozzászólás Szerző: kapu48 »

Ez tényleg érdekes kérdés!
Fizikailag hova tetted a hőmérőt a bojlerben?

Megbontottad a hőszigetelést?

Mert a kialakítása szerint rétegződik benne a meleg víz.
Alul ahol az eredeti termosztát van, a leghidegebb.
És felül ahol a kiömlő cső vége van a legmelegebb.

Hogy közte milyen hőfokok vannak, csak saccolni lehet.
És a kifolyó víz hőmérsékletét csak meleg víz kivételkór tudod mérni, mert közben az is kihűl.

:?:
És az egyértelmű, hogy a nagyobb tömegű és kisseb hő különbségen, kevesebb a hő vesztesség.
8)
Más.: Eredetileg 2*es hő kapcsoló védelem van minden bojlerben, hogy fel ne robbanj, ha az 1ik meghibásodik.
Szóval nem gyerekjáték. Veszélyes üzem a forró gőz.
8O
Avatar
winnerbt
Elektronbűvölő
Hozzászólások: 907
Csatlakozott: 2007. március 25. vasárnap, 6:00

Hozzászólás Szerző: winnerbt »

Igen, én is arra lennék kíváncsi, hogy fúrva/törve/ragasztva stb... kapja meg a meleget a hőérzékelő?
JAni
Avatar
yflk32
DrótVégénSzéndarab
Hozzászólások: 27
Csatlakozott: 2012. január 6. péntek, 7:00

Hozzászólás Szerző: yflk32 »

kapu48 írta:Ez tényleg érdekes kérdés!
Fizikailag hova tetted a hőmérőt a bojlerben?

Megbontottad a hőszigetelést?

Mert a kialakítása szerint rétegződik benne a meleg víz.
Alul ahol az eredeti termosztát van, a leghidegebb.
És felül ahol a kiömlő cső vége van a legmelegebb.

Hogy közte milyen hőfokok vannak, csak saccolni lehet.
És a kifolyó víz hőmérsékletét csak meleg víz kivételkór tudod mérni, mert közben az is kihűl.

:?:
És az egyértelmű, hogy a nagyobb tömegű és kisseb hő különbségen, kevesebb a hő vesztesség.
8)
Más.: Eredetileg 2*es hő kapcsoló védelem van minden bojlerben, hogy fel ne robbanj, ha az 1ik meghibásodik.
Szóval nem gyerekjáték. Veszélyes üzem a forró gőz.
8O
Na akkor eredetileg félreértettem a kérdést, már hogy hova kerül az LM35... :)
Ezen gondolkoztam a legkevesebbet, ezért nem volt nagyon kérdés számomra.
Az eszem sem ment el, hogy kiiktassam az eredeti hővédelmet...
A jelenleg működő bimetálos hőkapcsolónak a szondája egy csőben van és ez körülbelül a tartály fele környékén méri a hőmérsékletet. A hővédelem (a felforrás megakadályozására) a tartály alsó részén van, gyakorlatilag a fűtőszállal körülvett víz közvetlen hőmérsékletét érzékeli.

Igen, rétegződik a vízhőfok, de csak nyugalmi helyzetben. Más, amikor fűtés van és más vízkivételkor. Ezért kell kb. középen lennie az érzékelőnek. Fűtéskor pedig áramlás indul meg, így a víz keveredik.
Az LM35 az eredeti szonda mellett/felett kap helyet, azzal érintkezve (hővezető pad+öntapadós rézfólia rögzítéssel). Hiszen az eredetit kell kiváltani, ezért ugyanazt a hőt kell érzékelni is. Semmi sem lesz kikötve az eredeti (gyári) megoldáshoz képest, a gyári termosztátot maximumra állítom (80°C), az áramkör ez alá lesz maximalizálva. Azaz, ha bármi gond van, akkor még mindig lekapcsolhatja a fűtést vagy az eredeti termosztát vagy a hővédelem. A vezérelt relé záróérintkezője SOROSAN lesz kötve, így a legrosszabb esetben nem lesz melegvíz, ha gond van és nem a hővédelemnek kell beavatkoznia.

Az pedig lehet, hogy egyértelmű, hogy kisebb hőmérsékleten kisebb a hőveszteség, viszont arra vonatkozóan már senki sem lehet elég okos, hogy hol van az optimális beállítás? Annyi a változó az egyenletben, hogy ezt pontosan kiszámolni nem lehet, hiszen a konkrét vízmelegítő pontos jellemzői szükségesek hozzá. Viszont a mérés-adatgyűjtés utáni kiértékelés már pontosabb képet mutathat.
Egyik kollégám, aki hasonlóan kiváltotta a gyári termosztátot, még időszakokra is bontotta, hogy a nap mely szakában hány fokig fűthet maximum a boyler. Annyi különbséggel, hogy neki állandóan van áram, nem vezérelt óráról megy.

Üdv.:yflk32
Avatar
kapu48
Elektronbűvölő
Hozzászólások: 3375
Csatlakozott: 2008. augusztus 29. péntek, 6:00

Hozzászólás Szerző: kapu48 »

Érdekes lenne a kétféle rendszert összehasonlítani!
1.:
Ha van állandóan (drágábban) áramunk, nem érdemes tárolni a meleg vizet.
Mert csak veszteséges. Ilyenkór csak akkor és annyit melegítünk fel, amennyire szükségünk van.
2.:
Ha kapcsolt (olcsóbb) áramunk van?
Kénytelenek vagyunk, akkor fűteni mikor van mivel.
Ilyenkor viszont veszteséges a hőtárolás.

Kérdés, melyik a jobb nekünk? Illetve mik az igényeink?
Avatar
yflk32
DrótVégénSzéndarab
Hozzászólások: 27
Csatlakozott: 2012. január 6. péntek, 7:00

Hozzászólás Szerző: yflk32 »

kapu48 írta:Érdekes lenne a kétféle rendszert összehasonlítani!
1.:
Ha van állandóan (drágábban) áramunk, nem érdemes tárolni a meleg vizet.
Mert csak veszteséges. Ilyenkór csak akkor és annyit melegítünk fel, amennyire szükségünk van.
2.:
Ha kapcsolt (olcsóbb) áramunk van?
Kénytelenek vagyunk, akkor fűteni mikor van mivel.
Ilyenkor viszont veszteséges a hőtárolás.

Kérdés, melyik a jobb nekünk? Illetve mik az igényeink?
Először is azt kellene tudni, hogy kompenzálja-e az olcsóbb (vezérelt esetben) áram a tárolás közbeni veszteségeket. Remélhetőleg igen és nem csak a veszteségek esetén, de a fűtés közbeni energia is olcsóbb, mint az állandó rendelkezésre állás esetén.

Ha állandó árammal kalkulálunk, akkor valamilyen átfolyós melegítő jöhet szóba. Nem sok embert ismerek, aki az ilyen módú vízmelegítést ne gázzal oldaná meg. De most mi maradjunk az elektromos megoldásoknál. Nem hiszem, hogy megéri akkor melegíteni árammal vizet amikor éppen szükség van rá, még úgy sem, ha nem kell tárolnunk sem és ezzel együtt hőn tartani egy puffer mennyiséget. Már csak azért sem, mert akkor ez a megoldás nyilván sokkal elterjedtebb lenne.

Azt viszont érdemes lenne kipróbálni, hogy hogy jönnénk ki akkor áramszámla és melegvíz rendelkezésre állás szempontjából, ha például úgy használnánk ki az olcsóbb áramot, hogy amikor van (vezérelt időszak) ÉS megnyitjuk a csapot, akkor átfolyós rendszerben kapcsolódna be egy vízmelegítő, egyébként a boylert melegíti, ha szükséges, mert amikor majd kikapcsolják a vezérlést, akkor a boylerből vehetjük ki a melegvizet. Ennek talán egyedül akkor és úgy van értelme, ha csak nagyon kicsi a boyler, pl. 80 literes. De még így is érdemes lenne számolgatni.

Remélem én okosabb leszek, amikor majd a log fájlokat kiértékelem, mert nekünk 200 literes a villanyboylerünk. :)

Üdv.: yflk32
Válasz küldése