AC himmennys arduino serial

tervehdys

olen tässä tuskaillut ja yrittänyt saada valojen himmennyksen toimimaan arduinon sarjaporttia (serial 9600) käyttäen, ja siis useampaa kuin yhtä.

olen tehnyt TRIAC-himmentimen näiden ohjeiden mukaan:

http://www.instructables.com/id/Arduino-controlled-light-dimmer-The-circuit/

tarkoituksena on käyttää tuon mallin rinnalla saman ohjeen mukaisia himmentimiä, pois lukien zero cross osio; teen sen vain yhdesti jota käytän muissa himmentimissä.

saan edellä mainitun ohjeen mukaisesti yhtä valoa ohjattua oikein mainiosti, mutta oma äly ei riitä muokkaamaan koodia siten että saisin useampaa “kanavaa” ohjattua.

olen yrittänyt penkoa internettiä ja vaivannut omaa päätä, mutta tuloksetta.

tässä on lupaavin koodi mitä olen löytänyt, mutta siinäkin arduino valittaa jotain mitä en täysin ymmärrä ja se jää lataamatta error viestin takia.

[code]/*
DIMMERS 120V 60Hz (8-channel Possibly more)

by Gromain59
Translated By Mike Deuschle
mike.dausch@gmail.com

Material part:

  • Triac driven by a digital output via an optocoupler
  • AC opto-coupler for detecting the zero crossing of phase

Software part:

  • A hardware interrupt input 2 at the zero crossing of phase
  • A software interrupt that occurs between 100us and 1400us.
    => Interrupt interval is variable to obtain a light curve by linear orders, because of the shape of the sinusoidal signal.
    we have:
  1. Detection of the transition to zero on input 2
  2. execution of detection_zero (): processing channel with a setpoint of 0% and 100%
  3. deactivating hardware interrupt, enabling the software interrupt on the basis of delay [0]
  4. interrupt after delay [c2] ?s (c2 = 0)
  5. execution of controle_canaux ()
    => Index increment c2
    and if c2 is greater than 49, then this is the last cycle
    => Turn OFF of all channels
    => Activate the hardware interrupt
    otherwise:
    => Activation of output channels with 98% to record (either a 469?s delay) or if
    => Interrupt reconfiguration of time with another delay, delay [c2]

To change the setpoint of a channel, you must send via the serial monitor a frame of the form:
" D/0/45/F"
=> Space
=> “D” to indicate the start of the frame
=> “/” As separator
=> The affected channel (0 to 7 here)
=> “/” As separator
=> The desired level (from 0% to 100%)
=> “/” As separator
=> “F” to indicate the end of the frame

  Once the frame received, the function sscanf is responsible for retrieving data.
  It converts the received record levels (0 to 50 levels)

Resources:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230333861/30 for first test
http://www.hoelscher-hi.de/hendrik/english/dimmer.htm for electronics
http://www.abcelectronique.com/bigonoff/domocan.php?par=3efd4 for electronics and soft (PIC)
arduino forum

*/

#include <TimerOne.h> // for the interruption time http://www.arduino.cc/playground/Code/Timer1
#include <stdio.h> // for the treatment of the frame containing the change orders

                  // timeout value for the reception of the frame

int tps_max_lecture = 200; // reading code, counter max between all the characters of a code
int tps_max_carte = 1000; // max meter between reception of a character

long curve[] = {
1469 , // 98 % 1 225,3V retard / zéro = 1469 ms
287 , // 96 % 2 222,7V retard / zéro = 1867 ms
234 , // 94 % 3 220,6V retard / zéro = 2154 ms
201 , // 92 % 4 218,2V retard / zéro = 2388 ms
180 , // 90 % 5 215,4V retard / zéro = 2589 ms
164 , // 88 % 6 213,3V retard / zéro = 2769 ms
152 , // 86 % 7 210,8V retard / zéro = 2933 ms
143 , // 84 % 8 208V retard / zéro = 3085 ms
135 , // 82 % 9 205,7V retard / zéro = 3228 ms
129 , // 80 % 10 202,8V retard / zéro = 3363 ms
124 , // 78 % 11 200,5V retard / zéro = 3492 ms
120 , // 76 % 12 197,6V retard / zéro = 3616 ms
116 , // 74 % 13 195,2V retard / zéro = 3736 ms
112 , // 72 % 14 192,4V retard / zéro = 3852 ms
110 , // 70 % 15 189,6V retard / zéro = 3964 ms
108 , // 68 % 16 186,8V retard / zéro = 4074 ms
106 , // 66 % 17 184V retard / zéro = 4182 ms
105 , // 64 % 18 180,9V retard / zéro = 4288 ms
103 , // 62 % 19 178,1V retard / zéro = 4393 ms
102 , // 60 % 20 175,1V retard / zéro = 4496 ms
101 , // 58 % 21 172,1V retard / zéro = 4598 ms
101 , // 56 % 22 168,9V retard / zéro = 4699 ms
100 , // 54 % 23 166,2V retard / zéro = 4800 ms
100 , // 52 % 24 162,6V retard / zéro = 4900 ms
100 , // 50 % 25 159,3V retard / zéro = 5000 ms
101 , // 48 % 26 155,8V retard / zéro = 5100 ms
100 , // 46 % 27 152,6V retard / zéro = 5201 ms
101 , // 44 % 28 149,1V retard / zéro = 5301 ms
102 , // 42 % 29 145,3V retard / zéro = 5402 ms
103 , // 40 % 30 141,8V retard / zéro = 5504 ms
105 , // 38 % 31 138V retard / zéro = 5607 ms
106 , // 36 % 32 133,8V retard / zéro = 5712 ms
108 , // 34 % 33 130V retard / zéro = 5818 ms
110 , // 32 % 34 126V retard / zéro = 5926 ms
112 , // 30 % 35 121,7V retard / zéro = 6036 ms
116 , // 28 % 36 117,1V retard / zéro = 6148 ms
120 , // 26 % 37 112,6V retard / zéro = 6264 ms
124 , // 24 % 38 107,7V retard / zéro = 6384 ms
129 , // 22 % 39 102,4V retard / zéro = 6508 ms
135 , // 20 % 40 97,2V retard / zéro = 6637 ms
143 , // 18 % 41 92V retard / zéro = 6772 ms
152 , // 16 % 42 85,7V retard / zéro = 6915 ms
164 , // 14 % 43 79,4V retard / zéro = 7067 ms
180 , // 12 % 44 72,8V retard / zéro = 7231 ms
201 , // 10 % 45 64,8V retard / zéro = 7411 ms
234 , // 8 % 46 56,4V retard / zéro = 7612 ms
286 , // 6 % 47 46V retard / zéro = 7846 ms
399 , // 4 % 48 32,4V retard / zéro = 8132 ms
500 , //
1469 // 2 % 49 0V retard / zéro = 8531 ms
};

int set[] = { // set channel level (0 = 100%, 50 = 0%)
0, // Output 0
0, // output 1
0, // output 2
0, // output 3
0, // output 4
0, // output 5
0, // output 6
0, // output 7
};

int output [] = { // assign a pin for each channel.
4, // Output 0
3, // output 1
5, // output 2
0, // output 3
0, // output 4
0, // output 5
0, // output 6
0, // output 7
};

volatile int c1 = 0; // index c1 for reading data from each channel (No pin, luggage)
volatile int c2 = 0; // c2 index number passing through the loop control phase delay (49 passages)

// Definition of macros to drive the output
#define lightON(index) (digitalWrite(output[index], HIGH))
#define lightOFF(index) (digitalWrite(output[index], LOW))

void setup () {// Start of setup

// Initialize the serial
Serial.begin (9600);

// Initialize the channel outputs (triacs)
for (c1 = 0; c1 <= 7; c1++) {// we traverse the 8 channels to configure
pinMode(output[c1], OUTPUT); // we associate each channel has a pin, which sets the output digital
lightOFF(output[c1]); // and we switch off the output
}

  Serial.println( "Gromain 8-CHANNEL DIMMER v0.2");
  Serial.println( "FRAME EXPECTED: <space> 'D' / 'Output Port' / 'Value of DIM' / 'F'");

// Initialize the interruption time Timer1
Timer1.initialize(); // Initialize TimerOne library for the freq we need

// Attach the interrupt 0 to pin 2 for the detection of zero crossing (Zero Cross Detection)
attachInterrupt(0, detection_zero, FALLING); // Attach an Interrupt to Pin 2 (Interrupt 0) for Zero Cross Detection

} // End of setup

void detection_zero() {// function associated with the interrupt 0

  detachInterrupt(0); // disables the interrupt on zero crossing

  c2 = 0;
 
  for (c1 = 0; c1 <= 7; c1++) {// we scan the 8 outputs to check their orders
          if (set[c1] >= 49 ) {// if set 0%
              lightOFF(c1); // then we switch off
          }
       
        if (set[c1]<= 0){// if set 100%
              lightON(c1); // then we light
        }
       
  }

  Timer1.attachInterrupt(controle_canaux, curve[c2]); // we attach the interruption time

} // End of detection_zero

void controle_canaux() {// here we verified whether the triac must be initiated

 c2=c2++;
 
  attachInterrupt(0, detection_zero, FALLING); // we attach an interrupt on pin 2 (interrupt 0)
  Timer1.detachInterrupt(); // we detach the interruption time

  if (c2 >= 41) {// If last cycle then (best at 41 for 60Hz)

  for (c1 = 0; c1 <= 7; c1++) {// we scan the 8 outputs
        lightOFF(c1);  // and we put out the channel for the next cycle
  }

 
  }

else { // else

  Timer1.attachInterrupt(controle_canaux, curve[c2]); // we attach a break time

  for (c1 = 0; c1 <= 7; c1++) { // we scan the 8 outputs to check their orders
          if (set[c1] == c2) // if is set equal to the processed (no change in the loop)
        {lightON(c1);} // then we light the channel
  }

} // End function controle_canaux

}
void loop() {// Main Loop

  int n = 0;
 
  if (Serial.available ()> 0) {
        n = lecture();
  }

}

int lecture() { // read a frame type: "D / aaa / bbb / F
// Or “D” starting character frame
// Or “yyyy” No output which is set to modify
// Or “bbbb” new set of output (between 0 and 100%)

  char buf[15] = "              ";
  int timeout = 0;
  int i = 0;
  int n1 = 0;
  int n2 = 0;
  char c1, c2;
 
  while (Serial.available() > 0) {
        if(i!=14){
        buf = Serial.read ();
        i++;
        }

  timeout++;
 
  if (timeout>tps_max_lecture)
        {Serial.println("T1");
        return -1;
        }
  if (timeout> tps_max_lecture)
        {Serial.println("T2");
        return -2;
        }
    }
  sscanf(buf, "%c/%d/%d/%c", &c1, &n1, &n2, &c2); // decoding frame
 
  if (c1 == 'D' && c2 == 'F') {// Check if the plot starts out by D and ending in F
       
        int nouv_cons = n2;  // we store the new value for the work then
       
        nouv_cons = constrain(nouv_cons, 0, 100); // on the new terminal value between 0 and 100%


             
        Serial.print("Output ");
        Serial.print(n1);
        Serial.print(" , new value of: ");
        Serial.print(nouv_cons);
        Serial.print(" % index, delay: ");
             
        set[n1] = (50 - (nouv_cons / 2)); // it converts the value 0-100% in no phase delay
             
        Serial.println (set[n1]);
  }
  else // if character from the beginning or end of frame not recognized
  {Serial.println("Code Unknown");}
 
  return i;

}
[/code]

toinen koodi mikä vaikutti jo joltain oli tämä:

[code]/*
AC dual dimmer Control
adapted from sketch by Robert Twomey rtwomey@u.washington.edu
http://wiki.dxarts.washington.edu/groups/general/wiki/4dd69/
*/

#include <TimerOne.h> // Avaiable from http://www.arduino.cc/playground/Code/Timer1

volatile int i=0; // Variable to use as a counter
int AC_pin1 = 4; // Output to Opto Triac load#1
int AC_pin2 = 5; // Output to Triac load #2
int dim1 = 0;
int dim2 = 0; // Dimming level (0-128) 0 = on, 128 = 0ff
int inc=1;

int freqStep = 65; // This is the delay-per-brightness step in microseconds.
// It is calculated based on the frequency of your voltage supply (50Hz or 60Hz)
// and the number of brightness steps you want.
//
// 1000000 us / 120 Hz = 8333 uS, length of one half-wave.
// 8333 uS / 128 steps = 65 uS / step
//

void setup() {
// Begin setup
//Serial.begin(9600);
pinMode(AC_pin1, OUTPUT); // Set the Triac pin as output
pinMode(AC_pin2, OUTPUT);
attachInterrupt(0, zero_cross_detect, RISING); // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
Timer1.initialize(freqStep); // Initialize TimerOne library for the freq we need
Timer1.attachInterrupt(dim_check, freqStep);
// Use the TimerOne Library to attach an interrupt
// to the function we use to check to see if it is
// the right time to fire the triac. This function
// will now run every freqStep (65 uS for a 60Hz sinewave).
}

void zero_cross_detect() {
i=0;
// since the control pin stays high, the TRIAC won’t ‘unlatch’
// when zero-crossing, so I need to put the pins to LOW
digitalWrite(AC_pin1, LOW);
digitalWrite(AC_pin2, LOW);
// writing pins is like 10 times faster if
// we write the register directly
// instead of using ‘digitalWrite’
}

// Turn on the TRIAC at the appropriate time
void dim_check() {
if(i>=dim1) {
digitalWrite(AC_pin1, HIGH); // turn on triac #1
}
if (i>=dim2) {
digitalWrite(AC_pin2, HIGH); // turn on triac #2
}
i++; // increment time step counter
}

void loop() {
dim1+=inc;
if (dim1>=127 | dim1<=0){
inc*=-1;
}

dim2=127-dim1;
digitalWrite(13,HIGH);
delay(30);
digitalWrite(13,LOW);
delay(30);

}[/code]

tuolla koodilla kaksi kanavaa toimii itsenäisesti, mutta silti en saa siitä tehtyä sellaista että se minun serial monitor kutsuihin vastaisi.
tuo on siis alkuperäinen koodi, joten siksi siellä on serial kommentoituna.

mutta yhteenvetona, olisin suuresti kiitollinen jos joku voisi minua tässä auttaa.

sähköiset kiitokseni jo valmiiksi

eikö kukaan osaa kertoa ratkaisua pulmaani

Tuossa ensimmäisessa koodissa lienee virhe tuon lecture funktion alkupaassä.
Siellä lukee jotta
buf=Serial.read();
oletan että pitäisi olla
buf[i] = Serial.read ();

Tuo aiheuttaa virheilmon "incompatible types in assingment of ‘int’ to ‘char[15]’

Sitä toimiiko koodi muilta osin haluamallasi tavalla, en tosiaankaan tiedä.

Tuohon kakkoskoodiin on paha sanoa mitään sarjaliikenteen osalta. Eihän siinä ole mitään koodia joka lukisi sarjaporttia/kirjoittaisi sarjaporttiin?

Tuossa ykköskoodissa on jotain hämärää tuon sarjaliikenteen lukemisen kanssa. Kokeilin tuota ja kuinka ollakaan , en keksinyt tapaa miten se lukisi tiedot oikein noihin muuttujiin.
Näyttäisi siltä että koodi käsittelee vain osan lähetetystä datasta kerrallaan. Ja silloinhan D ja F ei osu oikeisiin lokeroihin.
En epäile etteikö koodaaja olisi osannut, minä en vain ymmärrä.

Tarvitset sen nollapisteen tiedon. Tiacia potkaistaessa, triac johtaa kunnes virta katkeaa. Kuormasta riippuen tämä tapahtuu jännitteen noin nollakohdalla. Mikäli et tahdistu tähän, himmennys toimii hassusti, huojuu ja on epäillyttävä.

Ja anteeksi. En edelleenkään ole ottanut vakavasti opeteltavakseni arduinoa.

Itse tekisin jotain tän tapaista. Kello sitten sopivaksi. 16M kiteellä, 8 esijakajalla COMPA keskeytysten välillä on vissiin 244 kellojaksoa. 2e6/100 = 2e4, koska nollakohtakeskeytys tulee verkkojännitteestä. Tämän jälkeen tarvitsee tehdä 256 tasoa ja tästä jää noin 78 COMP_A:lle. COMP_A:n tulon välillä on siis 624 käskyä. ja siinä ajassa täytyy lähinnä kanavat_ funktiot suorittaa. Tai sitten pitää main()issa ajaa jotain jatkuvasti portteihin kirjoittajaa. Tämä myös auttaisi suoritukseen, ettei oltaisi pitkään keskeytyksessä blokkaamassa muita keskeytyksiä.

Itse saattaisin pienentää kirkkauksien resoluutiota ja laskennallisesti virittäisin COMP_B vectorin ajamaan kanavat kiinni ennen nollakohtaa. Asetus voisi olla vaikkaa OCR1B = TCNT1 & 0xfff0;

[code]#include <inttypes.h>

volatile unsigned char aikaolo[KANAVA_MAARA];
//Jotain tän tapaista
struct mappaus{
uint8_t * portti;
uint8_t pinni;
};
//tän vois laittaa progmemiin
struct mappaus kanava_kytkenta[KANAVA_MAARA] = { {PORTB,3},{PORTB, 4}};

void kanavat_auki(uint8_t aika){
for(uint8_t i = 0; i < KANAVA_MAARA; ++i){
if(aikaolo[i]&&aikaolo[i] < aika){
*(kanava_kytkenta[i].portti) |= (1 << kanava_kytkenta[i].pinni);
}
}
}

void kanavat_kiinni(void){
for(uint8_t i = 0; i < KANAVA_MAARA; ++i){
if(aikaolo[i] != 0xff){
*(kanava_kytkenta[i].portti) &= ~(1 << kanava_kytkenta[i].pinni);
}
}
}

volatile uint8_t nyt;

ISR(TIMER1_COMPA_vect){
kanavat_auki(nyt++);
}

ISR(INT0_vect){
uint16_t kierros = TCNT1;
kanavat_kiinni();
OCR1A = (kierros >> 8);
TCNT1 = 0;
nyt = 0;
}[/code]