Forum: Mikrocontroller und Digitale Elektronik RGB Matrix mit I2C


von Pascal C. (pascal01)


Lesenswert?

Hallo Former,

ich habe mir ein kleines Projekt aufgesetzt und möchte eine RGB LED über 
I2C  Bus und Sensor(is471) ansteuern. Alles ist eigentlich soweit fertig 
und bereit. (Hardware). Die Software ist "eigentlich" fertig, wenn da 
nicht  ein kleines Problem wäre.

Ich sollte hier vielleicht noch sagen dass meine letzte Berührung mit 
AVR schon viele, viele Jahre zurück liegt. Es hat mich einfach wieder 
gepackt und möchte da wieder einsteigen. Also habt bitte etwas 
Nachsicht, jedoch konstruktive Kritik muss sein.

Kurz zu dem wie die LED reagieren soll.
Ich sende per I2C einen Wert, welcher die Farbe sowohl auch die 
Lichtstärke definiert.

Hierzu benutze ich ein Arduino als Master.
1
#include <Wire.h>
2
3
byte rgb[3] = {0,0,0};
4
5
void setup()
6
{
7
  TWBR=50000L;  // set SCL Clock to 50kHz für ATtiny2313 1MHz clock
8
  Wire.begin(); // join i2c bus (address optional for master) 
9
  Serial.begin(9600);  // start serial for output
10
  Serial.println("OK>");
11
}
12
13
void loop()
14
{
15
    // begin transmission to device 1    
16
    Wire.beginTransmission(5);
17
    // send
18
    rgb[0] = 0;
19
    rgb[1] = 0;
20
    rgb[2] = 110;
21
    Wire.write(rgb,3);
22
    // done
23
    Wire.endTransmission();  
24
  
25
    Wire.requestFrom(5,1);    // request 1 bytes from slave device #5
26
    while (Wire.available())  // slave may send less than requested
27
    {
28
      byte c = Wire.read();
29
      Serial.println(c);
30
    }
31
}

Auf dem Slave liegt nun mein Problem.
Sobald ich die Hand vom Sensor weg nehme, dimmt die LED mit Weiss aus 
und der I2C ist tot. Soweit ich diese vom Oszilloskop sehen kann. Danach 
geht nix mehr.

Wenn ich das Delay (_delay_ms(5)) in der Schleife zum Dimmen 
auskommentiere, funktioniert alles bestens, nur dimmen dann die LED eben 
nicht mehr. Gut sie dimmen schon, aber einfach zu schnell :)

Ich bin da etwas ratlos....
1
/**
2
* I2C.c
3
*
4
* Created: 19.02.2015 22:39:00
5
*  Author: Pascal
6
*
7
* Pin definition on ATtiny2313
8
*                         --------
9
*        (RESET/dW) PA2  1|°     |20  VCC
10
*             (RXD) PD0  2|      |19  PB7 (UCSK/SCL/PCINT7)
11
*             (TXD) PD1  3|      |18  PB6 (MISO/DO/PCINT6)
12
*           (XTAL2) PA1  4|      |17  PB5 (MOSI/DI/SDA/PCINT5)
13
*           (XTAL1) PA0  5|      |16  PB4 (OC1B/PCINT4)
14
*  (CKOUT/XCK/INT0) PD2  6|      |15  PB3 (OC1A/PCINT3)
15
*            (INT1) PD3  7|      |14  PB2 (OC0A/PCINT2)
16
*              (T0) PD4  8|      |13  PB1 (AIN1/PCINT1)
17
*         (OC0B/T1) PD5  9|      |12  PB0 (AIN0/PCINT0)
18
*                   GND 10|      |11  PD6 (ICP)
19
*                         --------
20
*/
21
22
23
#define F_CPU 1000000UL
24
25
#include <avr/io.h>
26
#include <util/delay.h>
27
#include <avr/interrupt.h>
28
#include <usiTwiSlave.h> // Don Blake's library
29
30
// The TWI address for this slave device
31
const uint8_t TWI_SLAVE_ADDRESS = 0x05;
32
33
// init array for RGB
34
uint8_t data[3];  
35
36
#define pwm1 OCR0A
37
#define pwm2 OCR0B
38
#define pwm3 OCR1A
39
//#define pwm4 OCR1B
40
41
int main(void)
42
{
43
  
44
  // Timer 0 PWM Init (fast PWM)
45
  TCCR0A = (1 << WGM00)
46
  | (1 << WGM01)
47
  | (1 << COM0A1)
48
  | (1 << COM0B1);
49
  TCCR0B = (0 << WGM02) 
50
  | (0 << CS00)
51
  | (1 << CS01)
52
  | (0 << CS02);  
53
  /**
54
  * CS02  CS01  CS00  Description
55
  * ---------------------------------------------------------------
56
  * 0    0    0    No clock source (Timer/Counter stopped)
57
  * 0    0    1    clkI/O/(No prescaling)
58
  * 0    1    0    clkI/O/8 (From prescaler)
59
  * 0    1    1    clkI/O/64 (From prescaler)
60
  * 1    0    0    clkI/O/256 (From prescaler)
61
  * 1    0    1    clkI/O/1024 (From prescaler)
62
  * 1    1    0    External clock source on T0 pin. Clock on falling edge.
63
  * 1    1    1    External clock source on T0 pin. Clock on rising edge.  
64
  * ---------------------------------------------------------------
65
  */
66
  
67
68
  // Timer 1 PWM Init (fast PWM)
69
  TCCR1A = (1 << WGM10)
70
  | (0 << WGM11)
71
  | (1 << COM1A1)
72
  | (1 << COM1B1);
73
  TCCR1B = (1 << WGM12)
74
  | (0 << WGM13)
75
  | (0 << CS10)
76
  | (1 << CS11)
77
  | (0 << CS12);
78
  
79
  /**
80
  * CS12  CS11  CS10  Description
81
  * ---------------------------------------------------------------
82
  * 0    0    0    No clock source (Timer/Counter stopped).
83
  * 0    0    1    clkI/O/1 (No prescaling)
84
  * 0    1    0    clkI/O/8 (From prescaler)
85
  * 0    1    1    clkI/O/64 (From prescaler)
86
  * 1    0    0    clkI/O/256 (From prescaler)
87
  * 1    0    1    clkI/O/1024 (From prescaler)
88
  * 1    1    0    External clock source on T1 pin. Clock on falling edge.
89
  * 1    1    1    External clock source on T1 pin. Clock on rising edge.
90
  * ---------------------------------------------------------------
91
  */
92
  
93
  
94
  
95
  /**
96
   * OC0A on pin 14 (PB2)
97
   * OC1A on pin 15 (PB3)
98
   * OC0B on pin  9 (PD5)
99
   * OC1B on pin 16 (PB4)
100
   */
101
  DDRB |= (1 << PB2);   // PWM output on PB2 - OC0A
102
  DDRB |= (1 << PB3);   // PWM output on PB3 - OC1A
103
  DDRD |= (1 << PD5);   // PWM output on PD5 - OC0B
104
  //DDRB |= (1 << PB4);   // PWM output on PB4 - OC1B
105
  
106
  OCR0A = 0;
107
  OCR0B = 0;
108
  OCR1A = 0;
109
//  OCR1B = 0;
110
111
  // set port to input (for Sensor)
112
  DDRB &= ~(1 << PINB0); // data direction register set as input PINB1
113
  PORTB |= 1 << PINB0; // set PINB1 to a "high" reading
114
115
  // Initialise the I2C interface
116
  usiTwiSlaveInit(TWI_SLAVE_ADDRESS);
117
118
  // Start interrupts
119
  sei();
120
  
121
  // set variable for sensor status
122
  bool sensor_is_clear = false;
123
124
125
  /**
126
   * pwm1 = R
127
   * pwm2 = G
128
   * pwm3 = B
129
   */
130
  while (1)
131
  {
132
    // check sensor input
133
    if(bit_is_clear(PINB, 0))
134
    {
135
      sensor_is_clear = true;
136
      // set color white
137
      pwm1 = 255;
138
      pwm2 = 255;
139
      pwm3 = 255;
140
141
      // send value 1 to master if sensor is covered
142
      usiTwiTransmitByte(1);
143
    }
144
    else
145
    {
146
      if( sensor_is_clear )
147
      {
148
        // if sensor is free fade out white color
149
        for (int i=255; i>0; i--)
150
        {
151
          pwm1 = i; // R
152
          pwm2 = i; // G
153
          pwm3 = i; // B
154
          //_delay_ms(5);
155
        }
156
        sensor_is_clear = false;
157
      }
158
      else
159
      {
160
        // check if data is in the i2c receive buffer
161
        if(usiTwiDataInReceiveBuffer())
162
        {
163
          // get some bytes
164
          for (int i=0; i<3; i++)
165
          {
166
            data[i] = usiTwiReceiveByte();
167
          }
168
169
          pwm1 = data[0];  // R
170
          pwm2 = data[1];  // G
171
          pwm3 = data[2];  // B
172
        }
173
        
174
        // send 0 if sensor is clear
175
        usiTwiTransmitByte(0);        
176
      }
177
    }
178
  }
179
}

Besten Dank für einen Eat, denn ich weiss hier nicht mehr weiter.

Gruss
Pascal

: Verschoben durch User
von Frank L. (frank_l)


Lesenswert?

Hallo Pascal,

statt einem delay, solltest Du das Dimmen in einen eigenen Timer 
verlagern. Das Delay sperrt alles!

Eventuell auch die Sende und Empfangsroutine auf Interrupt gesteuert 
umstellen, dann wird auch alles andere klappen.

Gruß
Frank

von Pascal C. (pascal01)


Lesenswert?

Hallo Frank,

danke für deine Info.
Dass mit den Timern habe ich noch nicht so im Griff. Der tiny2313 hat 
zwei Timers welche ich für die PWM der LED brauche. Da habe ich doch 
keinen Timer mehr frei, oder? Da muss ich mich wohl noch tiefer in die 
Materie graben.

Mit Interrupts habe ich bis jetzt noch nichts gemacht.
Naja, eines nach dem andren....

Gruss
Pascal

von J. T. (chaoskind)


Lesenswert?

Mit einem Timer kannst du mehrere PWMs erzeugen. Erstens haben die Timer 
teilweise 2 outpout compare register. Du kannst aber auch einfach einen 
Timer laufen lassen und im Interrupt die Differenz zum nächsten 
"PWM-Umschalten" ins OCR laden. Ich versuch mal nen Beitrag rauszusuchen 
da hatte ich ein ähnliches Problem. Wenn ich ihn finde, meld ich mich 
nochmal.

MfG Chaos

von Pascal C. (pascal01)


Lesenswert?

Danke Chaos das wäre sehr hilfreich, da ich mich in diesem Bereich noch 
gar nicht gut auskenne. Ich werde mich in den nächsten Tagen Mal über 
das ganze Datenblatt des 2313 hermachen. Werde dann sehen was ich alles 
verstanden habe und was nicht :)
...

von J. T. (chaoskind)


Lesenswert?

Beitrag "Musikalisches Diskettenlaufwerk"

da musste dich mal durchwühlen. Es geht zwar um das parallele Erzeugen 
von mehreren Frequenzen, aber das sollte sich auch auf PWM adaptieren 
lassen.

Edit: Irgendwo in der 2ten Hälfte gehts zum entscheidenden Teil

: Bearbeitet durch User
von Pascal C. (pascal01)


Lesenswert?

kurze Zwischenfrage,

ich bin gerade am umbauen des codes auf Interrupt Steuerung.
Bei INT0 und INT1 kann ich das Register MCUCR benutzen um auf eine 
poitive oder negative Flanke zu triggern. Das gleiche möchte ich nun 
auch auf PCINT0 machen. Ich habe da aber kein Eintrag gefunden.

Kann ich dass überhaupt?

Ich habe das mit INT0 auf PD2 gemacht was auch funktioniert hat. Jedoch 
ist dies ja nur ein Interrupt und ich möchte anschliessend mit 
bit_is_clear prüfen ob der Sensor immer noch ein Signal liefert wenn die 
Hand drauf ist.

vielen Dank für eure bisherigen Hilfestellung.

von Falk B. (falk)


Lesenswert?

@ Pascal Clément (pascal01)

>Kann ich dass überhaupt?

Nein. Der Interrupt reagiert auf jede Flanke. Welche dann real 
vorliegt, muss man durch Auslesen den PINx Registers rausfinden.

von Pascal C. (pascal01)


Lesenswert?

habe es gerade bemerkt. Ich habe es nun doch mit INT0 gelöst.

Jetzt muss ich nur noch den TWI Teil wieder einbauen....

von Pascal C. (pascal01)


Lesenswert?

...nun ist die Software grundsätzlich Fertig. Es fehlt mir eigentlich 
nur noch einen kleinen Teil wo ich dem Master mitteile dass der Sensor 
bedeckt ist.

Es ist vielleicht noch etwas viel Beschreibung im Code, jedoch ist diese 
für mich noch recht hilfreich um mich zurecht zu finden.

Wie gesagt, möchte ich dem Master mitteilen dass der Sensor bedeckt ist.
Dies mit "usiTwiTransmitByte(1);" funktioniert grundsätzlich. Da aber 
der Interrrupt durch bedecken das Sensors ausgelöst wird, wird auch die 
Kommunikation unterbrochen. Dies kann ich an meinem Oszilloskop sehen.

Wie kann ich also Daten senden bevor die Kommunikation unterbrochen 
wird? Oder ist die ISR Routine falsch?

Der Rest funktioniert soweit eigentlich recht gut. Zurzeit sind auch 
gerade alle OCRnx definiert obwohl ich nur drei brauche. Ist aber für 
mich im Moment nicht so wichtig.

Hier Mal was ich habe.
1
/**
2
 * I2C.c
3
 *
4
 * Created: 19.02.2015 22:39:00
5
 * Author: Pascal
6
 *
7
 * Pin definition on ATtiny2313
8
 *                         --------
9
 *        (RESET/dW) PA2  1|°     |20  VCC
10
 *             (RXD) PD0  2|      |19  PB7 (UCSK/SCL/PCINT7)
11
 *             (TXD) PD1  3|      |18  PB6 (MISO/DO/PCINT6)
12
 *           (XTAL2) PA1  4|      |17  PB5 (MOSI/DI/SDA/PCINT5)
13
 *           (XTAL1) PA0  5|      |16  PB4 (OC1B/PCINT4)
14
 *  (CKOUT/XCK/INT0) PD2  6|      |15  PB3 (OC1A/PCINT3)
15
 *            (INT1) PD3  7|      |14  PB2 (OC0A/PCINT2)
16
 *              (T0) PD4  8|      |13  PB1 (AIN1/PCINT1)
17
 *         (OC0B/T1) PD5  9|      |12  PB0 (AIN0/PCINT0)
18
 *                   GND 10|      |11  PD6 (ICP)
19
 *                         --------
20
 */
21
22
#define F_CPU 1000000UL
23
#include <avr/io.h>
24
#include <util/delay.h>
25
#include <avr/interrupt.h>
26
#include <usiTwiSlave.h> // Don Blake's library
27
28
/**
29
 * The TWI address for this slave device
30
 */
31
const uint8_t TWI_SLAVE_ADDRESS = 0x05;
32
33
/**
34
 * init array for RGB
35
 */
36
uint8_t data[3];  
37
38
/**
39
 * define pwm[x] for Port B and D
40
 */
41
#define pwm1 OCR0A
42
#define pwm2 OCR0B
43
#define pwm3 OCR1A
44
#define pwm4 OCR1B
45
46
void initPWMChanels(void);
47
void initInterrupt0(void);
48
void initInputSensor(void);
49
void initTWISlave(void);
50
51
int main(void)
52
{
53
  initPWMChanels();
54
  initInterrupt0();
55
  initInputSensor();
56
  initTWISlave();
57
58
  /**
59
   * pwm1 = R
60
   * pwm2 = G
61
   * pwm3 = B
62
   */
63
  while (1)
64
  {
65
    // check if data is in the TWI receive buffer
66
    if(usiTwiDataInReceiveBuffer())
67
    {
68
      // get some bytes
69
      for (int i=0; i<3; i++)
70
      {
71
        data[i] = usiTwiReceiveByte();
72
      }
73
74
      pwm1 = data[0];  // R
75
      pwm2 = data[1];  // G
76
      pwm3 = data[2];  // B
77
    }
78
79
    // send 0 if sensor is clear
80
    usiTwiTransmitByte(0);        
81
  }
82
}
83
84
85
void initTWISlave()
86
{
87
  usiTwiSlaveInit(TWI_SLAVE_ADDRESS);
88
}
89
90
void initInputSensor()
91
{
92
  DDRD &= ~(1 << PD2);  // data direction register set as input PIND2
93
  PORTD |= 1 << PD2;  // set PIND2 to "high"
94
}
95
96
void initPWMChanels()
97
{
98
  /**
99
   * set outputs
100
   */  
101
  DDRB |= 1 << PB2; // OC0A
102
  DDRD |= 1 << PD5; // OC0B
103
  DDRB |= 1 << PB3; // OC1A
104
  DDRB |= 1 << PB4; // OC1B
105
106
  /**
107
  * Timer/Counter0
108
  * set as FAST PWM
109
  *
110
  * Bit    Register  Value
111
  * -----------------------------
112
  * Bits 7    COM0A1      1
113
  * Bits 6    COM0A0
114
  * Bits 5    COM0B1    1
115
  * Bits 4    COM0B0
116
  * Bits 3    -
117
  * Bits 2    -
118
  * Bits 1    WGM01       1
119
  * Bits 0    WGM00       1
120
  *
121
  */
122
  TCCR0A = (1 << WGM00) 
123
           | (1 << WGM01)
124
           | (1 << COM0A1)
125
       | (1 << COM0B1);
126
127
  /**
128
  * Timer/Counter0
129
  * set as FAST PWM
130
  *
131
  * Bit    Register  Value
132
  * -----------------------------
133
  * Bits 7    FOC0A
134
  * Bits 6    FOC0B
135
  * Bits 5    -
136
  * Bits 4    -
137
  * Bits 3    WGM02
138
  * Bits 2    CS02
139
  * Bits 1    CS01        1
140
  * Bits 0    CS00        1
141
  *
142
  */
143
  TCCR0B = (1 << CS01);
144
145
  /**
146
  * Timer/Counter1
147
  * set as FAST PWM
148
  *
149
  * Bit    Register  Value
150
  * -----------------------------
151
  * Bits 7    COM1A1      1
152
  * Bits 6    COM1A0
153
  * Bits 5    COM1B1    1
154
  * Bits 4    COM1B0
155
  * Bits 3    -
156
  * Bits 2    -
157
  * Bits 1    WGM11       
158
  * Bits 0    WGM10       1
159
  *
160
  */
161
  TCCR1A = (1 << WGM10)
162
           | (1 << COM1A1)
163
       | (1 << COM1B1);     
164
165
  /**
166
  * Timer/Counter1
167
  * set as FAST PWM
168
  *
169
  * Bit    Register  Value
170
  * -----------------------------
171
  * Bits 7    ICNC1
172
  * Bits 6    ICES1
173
  * Bits 5    -
174
  * Bits 4    WGM13
175
  * Bits 3    WGM12    1
176
  * Bits 2    CS12
177
  * Bits 1    CS11    1
178
  * Bits 0    CS10
179
  *
180
  */
181
  TCCR1B = (1 << WGM12)
182
           | (1 << CS11);
183
}
184
185
void initInterrupt0()
186
{
187
  /**
188
  * Mask Register
189
  * Bit    Register  Value
190
  * -----------------------------
191
  * Bits 7    INT1
192
  * Bits 6    INT0
193
  * Bits 5    PCIE    1
194
  * Bits 4    -
195
  * Bits 3    -
196
  * Bits 2    -
197
  * Bits 1    -
198
  * Bits 0    -
199
  *
200
  */
201
  GIMSK  |= (1 << INT0);  // Enable PCINT0
202
  
203
  /**
204
  * Pin Change Mask Register
205
  * Bit    Register  Value
206
  * -----------------------------
207
  * Bits 7    PCINT7
208
  * Bits 6    PCINT6
209
  * Bits 5    PCINT5
210
  * Bits 4    PCINT4
211
  * Bits 3    PCINT3
212
  * Bits 2    PCINT2
213
  * Bits 1    PCINT1
214
  * Bits 0    PCINT0    1
215
  *
216
  */
217
  //PCMSK |= (1 << PCINT0);
218
  
219
  /**
220
  * extern INT0
221
  * MCU Control Register
222
  * Bit    Register  Value
223
  * -----------------------------
224
  * Bits 7    PUD
225
  * Bits 6    SM1
226
  * Bits 5    SE
227
  * Bits 4    SM0
228
  * Bits 3    ISC11
229
  * Bits 2    ISC10
230
  * Bits 1    ISC01    1
231
  * Bits 0    ISC00
232
  *
233
  */
234
  MCUCR = (1 << ISC01);  // Trigger INT0 on falling edge
235
236
  /**
237
   * Start global interrupts
238
   */
239
  sei();  
240
}
241
242
ISR(INT0_vect)
243
{
244
  /**
245
   * Meanwhile the sensor is covered , the color white is output.
246
   * if the sensor is free, fadeout from white color
247
   */
248
  while (1)
249
  {
250
    /**
251
     * check sensor input
252
     */
253
    if(bit_is_clear(PIND, 2))
254
    {
255
      pwm1 = 255;
256
      pwm2 = 255;
257
      pwm3 = 255;
258
      
259
      /**
260
       * send value 1 to master if sensor is covered
261
       */
262
      //usiTwiTransmitByte(1);
263
    }
264
    else
265
    {
266
      for (int i=255; i>0; i--)
267
      {
268
        pwm1 = i; // R
269
        pwm2 = i; // G
270
        pwm3 = i; // B
271
        _delay_ms(5);
272
      }
273
      return 1;
274
    }
275
  }
276
  reti();  // Exit of an interrupt handler
277
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.