Objective
The aim of this week is to get an understanding on how to communicate between board/nodes. It is similar to speaking. We will learn how to talk with other devices like computers, controllers etc. Here I will make at-least 2 controller boards to communicate.
The plan
- Take some board which I have already made for this week. I am getting pissed off by the amount of boards i have in my hand by now. Have to learn how to reuse stuff from now on.
- As a start I will look into wired communication and then move on to wireless.
Learning
Listening to this weeks lecture could give you the idea of what we will be dealing with. I will use simple softwareSerial
to communicate between two boards forst. then move on to making a serial bus, connecting n-number of devices and then give address to each and call them individually.
softwareSerial
I always look up arduino analogies initially, as they are plenty and easy to find. So here is the official page on serial comm. in an arduino board which has dedicated UART/USART port. But with our custom boards we should look further. The serialSoftware library is the need of the hour. Simply saying it helps to have any i/o port to be Tx/Rx pins.
And there is always Neils examples to learn from.
My assignments
First step- wired c using arduino IDE
Ttook the board i made from week 6 for using the push button and the board from week 13 for the LED on it. The idea is to switch on the LED in week13 by pushing the button in the week6 board.
Programing
I used arduino IDE for programming the boards and connected them using wire but nothing was happening as planned.
Debugging
The board with the push button also had an LED. So changed the code to make that also blink when the button is engaged. This way I can make sure the board i working.
Next i took the LED board and connected the Rx pin to an FTDI cable and manually send the keyword for turning on the LED, which worked fine.
So went back to the first board and checked what it is transmitting using the FTDI cable and a PC to collect the serial data. When the button is pushed instead of the keyword something gibberish is send. I tried varying the baudrate, double checking my logic and ten tried even changing the keyword. Finally our remote instructor frac pointed out it might be because of wrong timing as I was using the internal clock, which is not reliable. I switched to the external 20 MHz and reprogrammed the board, which actually solved the issue. Franc to my rescue again!!
What we did is a simple serial communication with the help of softwareSerial
library. This library essentially handles all the challenges of serial communication like having the clock, interrupts and protocol for sending and receiving data. Some other libraries which can be used are wire.h which enables to communicate in the SPI bus. This is an synchronous serial communication interface. Most of the boards nowadays have SPI for programming. The board i have in hand have an ATtiny45 which unfortunately dont have SPI pull up registers for taking advantage of the SPI pins. wire.h
enables to have SPI communication on standard Arduino boards by assigning general registers as SPI registers for the timebeing. But our ATtiny is not supported by wire too(sigh!). So finally i decided to have Neils code which uses bit banging for serial communication to communicate serially with addresses assigned to each connected boards.
Serial Communication with addresses
Here i need to have a board with provision to access the Tx and Rx pins from two sets of pins, one for connecting to the computer for debugging and the other pair for connecting to the serial bus. So I made the bridge
board in Neils serial communication example. example, and named it node 1
. I took the temp sensor board from week 13 and named it node 2
and the ambient light sensing board from week 11 as node 3
. I modified Neils code for serial communication and programmed it into all the 3 boards. The changes I made are
- in node 1, I defined the
node_id
as1
. - in node 2, defined
node_id
as2
and I had the LED connected toPB0
. So i changed the line defining theled_pin
accordingly. - in node 3 defined
node_id
as3
similar changes like the LED is connected to pin PB3 so i changedled_pin
to the same. Also the LED is notset
as in the other boards. so it only blinks when the command addressing this board is received - In all the above cases, since I am reusing the board, I have only the SPI pins taken out so I changed the Tx and Rx pins in
serial_pin_in
andserial_pin_out
as PB2 and PB1.
The following is the code for node 1
.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//
//
// hello.bus.45.c
//
// 9600 baud serial bus hello-world
//
// Neil Gershenfeld
// 11/24/10
//
//Modified by Vishnu Easwaran on Fab Academy 2016
//
// (c) Massachusetts Institute of Technology 2010
// Permission granted for experimental and personal use;
// license for commercial sale available from MIT.
//
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <string.h>
#define output(directions,pin) (directions |= pin) // set port direction for output
#define input(directions,pin) (directions &= (~pin)) // set port direction for input
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define pin_test(pins,pin) (pins & pin) // test for port pin
#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
#define bit_delay_time 100 // bit delay for 9600 with overhead
#define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay
#define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay
#define led_delay() _delay_ms(100) // LED flash delay
#define led_port PORTB
#define led_direction DDRB
#define led_pin (1 << PB3) //the LED in the branch board, changedfor each node
#define serial_port PORTB
#define serial_direction DDRB
#define serial_pins PINB
#define serial_pin_in (1 << PB2) //changed
#define serial_pin_out (1 << PB1) //changed
#define node_id '1'
void get_char(volatile unsigned char *pins, unsigned char pin, char *rxbyte) {
//
// read character into rxbyte on pins pin
// assumes line driver (inverts bits)
//
*rxbyte = 0;
while (pin_test(*pins,pin))
//
// wait for start bit
//
;
//
// delay to middle of first data bit
//
half_bit_delay();
bit_delay();
//
// unrolled loop to read data bits
//
if pin_test(*pins,pin)
*rxbyte |= (1 << 0);
else
*rxbyte |= (0 << 0);
bit_delay();
if pin_test(*pins,pin)
*rxbyte |= (1 << 1);
else
*rxbyte |= (0 << 1);
bit_delay();
if pin_test(*pins,pin)
*rxbyte |= (1 << 2);
else
*rxbyte |= (0 << 2);
bit_delay();
if pin_test(*pins,pin)
*rxbyte |= (1 << 3);
else
*rxbyte |= (0 << 3);
bit_delay();
if pin_test(*pins,pin)
*rxbyte |= (1 << 4);
else
*rxbyte |= (0 << 4);
bit_delay();
if pin_test(*pins,pin)
*rxbyte |= (1 << 5);
else
*rxbyte |= (0 << 5);
bit_delay();
if pin_test(*pins,pin)
*rxbyte |= (1 << 6);
else
*rxbyte |= (0 << 6);
bit_delay();
if pin_test(*pins,pin)
*rxbyte |= (1 << 7);
else
*rxbyte |= (0 << 7);
//
// wait for stop bit
//
bit_delay();
half_bit_delay();
}
void put_char(volatile unsigned char *port, unsigned char pin, char txchar) {
//
// send character in txchar on port pin
// assumes line driver (inverts bits)
//
// start bit
//
clear(*port,pin);
bit_delay();
//
// unrolled loop to write data bits
//
if bit_test(txchar,0)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,1)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,2)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,3)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,4)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,5)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,6)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,7)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
//
// stop bit
//
set(*port,pin);
bit_delay();
//
// char delay
//
bit_delay();
}
void put_string(volatile unsigned char *port, unsigned char pin, PGM_P str) {
//
// send character in txchar on port pin
// assumes line driver (inverts bits)
//
static char chr;
static int index;
index = 0;
do {
chr = pgm_read_byte(&(str[index]));
put_char(&serial_port, serial_pin_out, chr);
++index;
} while (chr != 0);
}
void flash() {
//
// LED flash delay
//
clear(led_port, led_pin);
led_delay();
set(led_port, led_pin);
}
int main(void) {
//
// main
//
static char chr;
//
// set clock divider to /1
//
CLKPR = (1 << CLKPCE);
CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
//
// initialize output pins
//
set(serial_port, serial_pin_out);
input(serial_direction, serial_pin_out);
set(led_port, led_pin);
output(led_direction, led_pin);
//
// main loop
//
while (1) {
get_char(&serial_pins, serial_pin_in, &chr);
flash();
if (chr == node_id) {
output(serial_direction, serial_pin_out);
static const char message[] PROGMEM = "node ";
put_string(&serial_port, serial_pin_out, (PGM_P) message);
put_char(&serial_port, serial_pin_out, chr);
led_delay();
flash();
input(serial_direction, serial_pin_out);
}
}
}
After programming the board and connecting them properly, I connected node 1
to my PC and opened it up in a serial monitor. Now when I send the integer 1
node 1 will respond by blinking twice and the same happens when we send 2
and 3
the corresponding boards responds.
The same exercise done with code in Arduino IDE is as follows. here also i named the same nodes with node names 1, 2 and 3. All of them will blink only when it is addressed. By default for node 1 and node 2 the LED will be ON but it will be OFF for node 3.
1 | /* |