Skip to content

Commit f8cc4b8

Browse files
committed
Fixed everything
I was just about to discard the project, when I gave it a last chance and suddenly all worked just as I wished it should. Except for the I2C, which is a bit unreliable.
1 parent c0aad15 commit f8cc4b8

11 files changed

+1604
-179
lines changed

I2C_Slave_Tiny.ino

-179
This file was deleted.

I2C_Slave_Tiny/I2C_Slave_Tiny.ino

+212
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
2+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
#include "TinyWireS.h"
5+
6+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7+
8+
#define I2C_SLAVE_ADDR 0x2F
9+
10+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11+
12+
uint8_t u8Pwm0 = 0;
13+
uint8_t u8Pwm1 = 0;
14+
uint8_t u8Command = 0;
15+
16+
const uint8_t adc_is_freerunning = 0; // don't use freerunning when using multiple adc's
17+
// changing ADMUX while freerunning may make things difficult
18+
// and single conversion seems to work just fine.
19+
20+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21+
22+
void initADC() {
23+
24+
ADCSRA = (1 << ADPS2) | // set prescaler to 64, bit 2 ~~ for 8MHz below is valid
25+
(1 << ADPS1) | // set prescaler to 64, bit 1 ~~ 1 1 0 = ps64 = 125kHz
26+
(0 << ADPS0); // set prescaler to 64, bit 0 ~~ 1 1 1 = ps128 = 62.5kHz
27+
28+
ADCSRA |= (adc_is_freerunning << ADATE); // set auto trigger enable
29+
ADCSRA |= (0 << ADTS2) | // set free running mode, bit 2
30+
(0 << ADTS1) | // set free running mode, bit 1
31+
(0 << ADTS0); // set free running mode, bit 0
32+
33+
34+
ADMUX = (1 << REFS2) | // Sets ref. voltage to VCC, bit 3 ~~ i2c makes use of ADREF pin, only internal vref can be used
35+
(1 << REFS1) | // Sets ref. voltage to VCC, bit 1 ~~ 0 1 0 Internal 1.1V Voltage Reference.
36+
(0 << REFS0); // Sets ref. voltage to VCC, bit 0 ~~ 1 1 0 Internal 2.56V Voltage Reference without external bypass capacitor, disconnected from PB0 (AREF)
37+
38+
ADMUX = (0 << MUX3) | // MUX bit 3 ~~ 0 0 0 0 = ADC0 --> PB4 | Pin3, needs RESET fuse disabled, mcu can then not be reprogrammed.
39+
(0 << MUX2) | // MUX bit 2 ~~ 0 0 0 1 = ADC1 --> PB2 | Pin7
40+
(1 << MUX1) | // MUX bit 1 ~~ 0 0 1 0 = ADC2 --> PB4 | Pin3
41+
(1 << MUX0); // MUX bit 0 ~~ 0 0 1 1 = ADC3 --> PB3 | Pin2
42+
43+
ADCSRA |= (1 << ADEN); // Enable ADC
44+
45+
ADCSRA |= (1 << ADSC); // Start ADC measurement
46+
ADCL; ADCH; // "The first ADC conversion result after switching voltage reference source may be inaccurate, and the user is advised to discard this result."
47+
}
48+
49+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
50+
51+
void initPWM() {
52+
53+
DDRB |= (1 << PB1) | (1 << PB4);
54+
55+
// Buzzer is on Counter 0 ( OC0B ) PB1 = pin 6
56+
// LED is on Counter 1 ( OC1B compl. ) PB1 = pin 6
57+
// OC0A cannot be used, because PB0 = pin 5 is used by I2C (SDA), this frees up OCR0A which we will use as TOP for Counter 0 (via WGM0x) to get a variable frequency for the Buzzer
58+
// OC1A might have been used on PB1 = pin 6 for the Buzzer, but luckily OC0B did the job just fine so that this didn't get tested.
59+
// I guess that using OC1A wouldn't work, as we then couldn't use OCR1A as TOP for itself, since OCRA's are the only TOP that can be used in WGM0x. But it's just a guess.
60+
61+
TCCR0A = // ------------ Timer/Counter Control Register A ------------
62+
(0 << COM0A1) | // Normal port operation, OC0A disconnected. | OC0A Pin is used by I2C and we will use OC0A's register as the top value
63+
(0 << COM0A0) | // .. | for the Counter 0 to set the pitch of PWM OC0B
64+
(1 << COM0B1) | // Clear OC0B on Compare Match when up-counting. Set OC0B on Compare Match when down-counting. <----
65+
(0 << COM0B0) | // .. <----
66+
//(-)
67+
//(-)
68+
(0 << WGM01) | // (1) 0 1 = PWM, Phase Correct with -->OCR0A<-- as TOP (1/3) <----
69+
(1 << WGM00); // (1) 0 1 = PWM, Phase Correct with -->OCR0A<-- as TOP (2/3) <----
70+
71+
TCCR0B = // ------------ Timer/Counter Control Register B ------------
72+
(0 << FOC0A) |
73+
(0 << FOC0B) |
74+
//(-)
75+
//(-)
76+
(1 << WGM02) | // 1 (0 1) = PWM, Phase Correct with -->OCR0A<-- as TOP (3/3) <----
77+
(1 << CS02) | // Prescaler used to pick the base frequency <---
78+
(0 << CS01) | // of the OC0B. <---
79+
(0 << CS00); // <---
80+
// 2/1/0
81+
// 0 0 1 No prescaling - ok
82+
// 0 1 0 8 (From prescaler) - not ok
83+
// 0 1 1 64 (From prescaler) - ok
84+
// 1 0 0 256 (From prescaler) - ok
85+
// 1 0 1 1024 (From prescaler) - ok
86+
87+
TCCR1 = // ------------ Timer/Counter1 Control Register ------------
88+
(0 << CTC1) |
89+
(0 << PWM1A) |
90+
(0 << COM1A1) |
91+
(0 << COM1A0) |
92+
(1 << CS13) | // Prescaler used to pick the fixed <----
93+
(0 << CS12) | // frequency of the OCR1B PWM <----
94+
(0 << CS11) | // <----
95+
(1 << CS10); // <----
96+
// 3/2/1/0
97+
// 0 0 0 0 T/C1 stopped T/C1 stopped
98+
// 0 0 0 1 P
99+
// 0 0 1 0 2
100+
// 0 0 1 1 4
101+
// 0 1 0 0 8s
102+
// 0 1 0 1 16
103+
// 0 1 1 0 32
104+
// 0 1 1 1 64 <---- more limited 'dynamic range'
105+
// 1 0 0 1 256 <---- limited 'dynamic range'
106+
// 1 0 0 1 256 <---- no flickering on LED, good 'dynamic range'
107+
// 1 0 1 0 512 <---- noticeable flickering
108+
// 1 0 1 1 1024 <---- more noticeable flickering
109+
// 1 1 0 0 2048
110+
// 1 1 0 1 4096
111+
// 1 1 1 0 8192
112+
// 1 1 1 1 16384
113+
114+
GTCCR = // ------------ General Timer/Counter1 Control Register ------------
115+
(0 << TSM) |
116+
(1 << PWM1B) |
117+
(1 << COM1B1) | // 0 1 - PB4 (pin3) - COM1B 0=0V
118+
(0 << COM1B0) | // 1 0 - PB3 (pin2) - COM1B complementary 0=5V <----
119+
(0 << FOC1B) |
120+
(0 << FOC1A) |
121+
(0 << PSR1) |
122+
(0 << PSR0);
123+
}
124+
125+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
126+
127+
void setup(){
128+
initADC();
129+
initPWM();
130+
TinyWireS.begin(I2C_SLAVE_ADDR);
131+
}
132+
133+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
134+
135+
void loop() {
136+
if (TinyWireS.available()) {
137+
138+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
139+
u8Command = TinyWireS.receive();
140+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
141+
if (u8Command == 0x00) {} // Nothing done here, maybe implemet a reset ?
142+
else if (u8Command == 0x01) {} // Nothing done here...
143+
else if (u8Command == 0x02) { // Write to PWM0 = OCR1B, which is the PWM of the LED
144+
u8Pwm0 = TinyWireS.receive();
145+
OCR1B = u8Pwm0;
146+
return;
147+
}
148+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
149+
else if (u8Command == 0x03) { // Read from PWM0 = OCR1B, which is the PWM of the LED
150+
TinyWireS.send(u8Pwm0);
151+
return;
152+
}
153+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
154+
else if (u8Command == 0x04) { // Write to PWM1 = OCR0B and OCR0A, which is the PWM and looping point of the Buzzer
155+
// OCR0A sets looping point on the counter: frequency
156+
// OCR0B sets the pulse width, = OCR0A / 2 obviously.
157+
u8Pwm1 = TinyWireS.receive();
158+
if (!u8Pwm1) {
159+
OCR0B = 0;
160+
OCR0A = 1; // just in case, force this to 1, may not be neccesary
161+
}
162+
else {
163+
OCR0B = u8Pwm1 * 0.5;
164+
OCR0A = u8Pwm1;
165+
}
166+
return;
167+
}
168+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169+
else if (u8Command == 0x05) { // Read from PWM1 = OCR0B and OCR0A, which is the PWM and looping point of the Buzzer
170+
TinyWireS.send(u8Pwm1);
171+
return;
172+
}
173+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
174+
else if (u8Command == 0x06) { // Read from ADC2 (PB4 | Pin3)
175+
if (!adc_is_freerunning) { // ADC 2, single conversion
176+
ADMUX = (0 << MUX3) | // MUX bit 3 ~~ 0 0 0 0 = ADC0 --> PB4 | Pin3, needs RESET fuse disabled, mcu can then not be reprogrammed.
177+
(0 << MUX2) | // MUX bit 2 ~~ 0 0 0 1 = ADC1 --> PB2 | Pin7
178+
(1 << MUX1) | // MUX bit 1 ~~ 0 0 1 0 = ADC2 --> PB4 | Pin3
179+
(1 << MUX0); // MUX bit 0 ~~ 0 0 1 1 = ADC3 --> PB3 | Pin2
180+
ADCSRA |= (1 << ADSC); // start ADC measurement, needed when auto trigger enable is 0 (= single conversion)
181+
while (ADCSRA & (1 << ADSC)); // wait until conversion is done
182+
}
183+
TinyWireS.send(ADCL);
184+
TinyWireS.send(ADCH);
185+
return;
186+
}
187+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
188+
else if (u8Command == 0x07) {
189+
// Apparently the only free ADC is ADC0 | PB4 | Pin3, but in order to use it, the RESET fuse needs to get disabled.
190+
// This will most probably result in the inability to reprogram this chip, but if you know that you won't need to do
191+
// that again, you gain one ADC channel. You won't be able to change the I2C_SLAVE_ADDR then, so keep that in mind.
192+
// But I2C_SLAVE_ADDR could be written to EEPROM and be writable by the host...
193+
/*
194+
if (!adc_is_freerunning) { // ADC 0, single conversion
195+
ADMUX = (0 << MUX3) | // MUX bit 3 ~~ 0 0 0 0 = ADC0 --> PB4 | Pin3, needs RESET fuse disabled, mcu can then not be reprogrammed.
196+
(0 << MUX2) | // MUX bit 2 ~~ 0 0 0 1 = ADC1 --> PB2 | Pin7
197+
(0 << MUX1) | // MUX bit 1 ~~ 0 0 1 0 = ADC2 --> PB4 | Pin3
198+
(0 << MUX0); // MUX bit 0 ~~ 0 0 1 1 = ADC3 --> PB3 | Pin2
199+
ADCSRA |= (1 << ADSC); // start ADC measurement, needed when auto trigger enable is 0 (= single conversion)
200+
while (ADCSRA & (1 << ADSC)); // wait until conversion is done
201+
}
202+
TinyWireS.send(ADCL);
203+
TinyWireS.send(ADCH);
204+
*/
205+
TinyWireS.send(0); // Not implemented, return 0
206+
TinyWireS.send(0); // Not implemented, return 0
207+
return;
208+
}
209+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
210+
211+
}
212+
}

0 commit comments

Comments
 (0)