-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathi2cScan.ino
251 lines (215 loc) · 6.37 KB
/
i2cScan.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/****************************************************
https://github.com/swellhunter/i2cScan
i2cScan - Ripped off from Arduino Playground
Adapted for ATTiny85 with RayLid UART LCD.
___ +---v---+
RST 1|o |8 VCC
XTAL 2| |7 SCL * two wire serial clock
XTAL 3| |6 TX * UART serial out
GND 4| |5 SDA * two wire serial data
+-------+
Requires :
https://github.com/nickgammon/SendOnlySoftwareSerial
https://github.com/SpenceKonde/ATTinyCore
Raylid RSI1602***-00 16*02 UART LCD display.
(from Ebay user surenoo)
2 x 4.7KΩ pull up resistors for IIC lines.
Physical switch for power on and off.
******************************************************/
/* Includes */
// ATTiny85 will require pull-up resistors,
// but said resistors will cause issues after
// programming. Device needs to be reset
// or cycled after programming to run
// with disconnected programmer.
#include <Wire.h>
#include <avr/wdt.h>
#include <SendOnlySoftwareSerial.h>
/* Globals - well "ours" anyway */
SendOnlySoftwareSerial serLCD(1); // Tx pin
unsigned short line1 = 0;
unsigned short line2 = 1;
unsigned int baud = 9600;
unsigned short intensity = 63;
unsigned short loopcount = 0;
// This is the ubiquitous Arduino setup function
// It is called once per reboot.
void setup() {
wdt_reset();
MCUSR &= ~(1 << WDRF); // Spence Konde recommends, could save first.
wdt_disable();
serLCD.begin(baud);
brightness_LCD(intensity);
Wire.begin();
delay(1000);
preamble();
}
// And this is the main Arduino loop that is
// executed indefinitely, the stack is already
// down about 8 bytes when we get in here.
void loop() {
byte error, address;
int nDevices;
char all[17] = ""; // one whole line, right ?
char buff[3] = ""; // holds two hex characters.
loopcount++; // do it here, not miles away.
// In theory we have a spare PortB pin to run
// a piezo buzzer to remind people to switch
// off after 4 cycles, ala fridge door and
// then reset after a delay.
if (loopcount > 4) {
reboot();
}
clear_LCD();
beginLCDWrite(line1, 0);
serLCD.print(F("Scanning... "));
endLCDWrite();
nDevices = 0;
// Most of this loop ripped off from Arduino Playground.
for (address = 0; address < 128; address++) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) { // knock was answered
if (nDevices) { // separate with commas
strcat(all, ",");
}
else {
strcat(all, "0x");
}
sprintf(buff, "%02X", address);
strcat(all, buff);
beginLCDWrite(line2, 0);
serLCD.print(F("Found 0x"));
if (address < 16) {
serLCD.print(F("0"));
}
serLCD.print(address, HEX);
endLCDWrite();
nDevices++;
delay(1500);
clear_LCD_line2();
}
else if (error == 4) { // not good
beginLCDWrite(line2, 0);
serLCD.print(F("Error at : 0x"));
if (address < 16) {
serLCD.print(F("0"));
}
serLCD.print(address, HEX);
endLCDWrite();
delay(4000);
clear_LCD_line2();
}
}
if (nDevices == 0) {
clear_LCD();
beginLCDWrite(line1, 0);
serLCD.print(F("No I2C devices!!"));
endLCDWrite();
}
else {
delay(1000);
clear_LCD();
beginLCDWrite(line1, 0);
serLCD.print(all);
endLCDWrite();
beginLCDWrite(1, 0);
serLCD.print(F("Done. "));
serLCD.print(nDevices);
serLCD.print(F(" hit"));
if (nDevices > 1) {
serLCD.print(F("s"));
}
serLCD.print(F("."));
endLCDWrite();
}
delay(8000);
clear_LCD();
delay(200);
}
//---------------------------------------------------
// functions and subroutines follow...
//----------------------------------------------------
// Things in setup() best abstracted to declutter the
// code there and make it more readable.
void preamble(void) {
id_LCD();
clear_LCD();
beginLCDWrite(line1, 0);
serLCD.print(F("*** I2C Scan ***"));
endLCDWrite();
delay(1000);
beginLCDWrite(line2, 0);
serLCD.print(F("... stand by ..."));
endLCDWrite();
delay(2000);
}
// Supposedly the definitive way to reboot an ATTiny85.
// Cleaner than SP=RAMEND;SREG=0;MCUSR=0;asm("rjmp 0")
// Not really essential, but revisits startup routines
// and causes initial information to redisplay.
// Could also tie a spare output pin to reset....
// Also could just trap the sparks and have a button for the user?
void reboot(void) {
wdt_enable(WDTO_1S);
while (true);
}
//---------------------------------------------------
// LCD functions, specific to RayLid, these are
// few enough to not need a library or separate
// file. Anyway we are using our instance explicitly.
//----------------------------------------------------
// This sets the brightness of the LCD. Note that the
// relationship is not that linear. You should test
// for fixed values on the scale that are useful.
void brightness_LCD(unsigned short x) {
serLCD.write(0xAA);
serLCD.write(0x13);
serLCD.write(x);
}
// This clears the whole LCD display.
void clear_LCD(void) {
serLCD.write(0xAA);
serLCD.write(0x10);
}
// These are the control characters for the UART display
// to specify that characters for writing to a particular
// location are to follow. Note order of r,c as may not
// follow the usual convention for LCD displays? (reversed?).
// Also it is not that unusual for serial communication to
// have beginTransmission..endTransmission anyway?
void beginLCDWrite(uint8_t r, uint8_t c) {
serLCD.write(0xAA);
serLCD.write(0x20);
serLCD.write(r);
serLCD.write(c);
serLCD.write(0xAA);
serLCD.write(0x25);
}
// This terminates the character stream written to the
// UART LCD. There should not have been any \n in that
// stream either.
void endLCDWrite(void) {
serLCD.write(0x0D);
}
// LCD displays perform at their best when blanked
// between "shifting in" writes of large clumps of
// text. This clears the 2nd of 2 lines.
void clear_LCD_line2(void) {
unsigned short i;
beginLCDWrite(line2, 0);
for (i = 0; i < 16; i++) {
serLCD.print(F(" "));
}
endLCDWrite();
delay(500);
}
// Dump model and version (if any) of the LCD
// display. Obviously we can see the colour,
// and we know it is UART. The "K" means the
// keyboard/pad inputs will work (wasted here).
void id_LCD(void) {
serLCD.write(0xAA);
serLCD.write((uint8_t)0); // note the "cast".
delay(2000);
}