Home
Weekly Assignments
Final Project

13. Networking and communications

I2C [TWI]

The incubator will consist of different modules that can be connected to add features. To achieve that goal I implemented the I2C protocol with one master device and several slaves. Therefore, the master device will communicate with the tilting bed module, the temperature module, etc. through the "two wire" communication protocol.

This protocol requires two pulled-up wires (using a 10kΩ resistor), one for the clock (SCL) and other for the data (SCA). That wiring process was made using a breadboard.

Pull

The first attempt to communicate two devices was done by pulling information from the master device.

In this example I implemented a Master-transmitter and a Slave-receiver architecture. The master device sends numbers to the slave with the number of times it led has to blink. That number increases each time it is sent until it reaches a value of 10.

Master

  1. /********************************************************
  2. *
  3. * i2cmaster.fabduino.c
  4. *
  5. * Alejandro Escario Méndez
  6. * 03/05/2015
  7. *
  8. * MIT license
  9. *********************************************************/
  10.  
  11. #include <avr/io.h>
  12. #include <util/delay.h>
  13.  
  14. #define output(directions,pin) (directions |= pin) // set port direction for output
  15. #define input(directions,pin) (directions &= (~pin)) // set port direction for input
  16. #define set(port,pin) (port |= pin) // set port pin
  17. #define clear(port,pin) (port &= (~pin)) // clear port pin
  18. #define pin_test(pins,pin) (pins & pin) // test for port pin
  19. #define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
  20.  
  21. #define LED_DIRECTION DDRB
  22. #define LED_PORT PORTB
  23. #define LED_PIN (1 << PB5)
  24.  
  25. unsigned char recipient = 0x28;
  26. unsigned char data = 1;
  27.  
  28. void i2c_init_master(){
  29. // SCL freq = F_CPU/(16+2(TWBR)*prescalerValue)
  30. TWBR = 32; // Bit rate
  31. TWSR = (0 << TWPS1) | (0 << TWPS0); // Setting prescalar bits
  32. }
  33.  
  34. void i2c_start(){
  35. TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); // put start condition
  36. while(!(TWCR & (1 << TWINT))); // wait until start condition is transmitted
  37. while((TWSR & 0xF8)!= 0x08); // wait for ACK
  38. }
  39.  
  40. void i2c_repeated_start(){
  41. TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); // put start condition
  42. while(!(TWCR & (1 << TWINT))); // wait until start condition is transmitted
  43. while((TWSR & 0xF8)!= 0x10); // wait for ACK
  44. }
  45.  
  46. void i2c_stop(){
  47. TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); // put stop condition
  48. while(!(TWCR & (1<<TWSTO))); // wait until stop condition is transmitted
  49. }
  50.  
  51. void i2c_write_address(unsigned char addr)
  52. {
  53. TWDR = addr; // write addr to "call"
  54. TWCR = (1 << TWINT) | (1 << TWEN); // Enable TWI and clear interrupt flag
  55. while(!(TWCR & (1 << TWINT))); // Wait until TWDR byte is transmitted
  56. while((TWSR & 0xF8)!= 0x18); // Check for the acknowledgement
  57. }
  58.  
  59. void i2c_write_data(unsigned char data)
  60. {
  61. TWDR = data; // write data in TWDR
  62. TWCR = (1 << TWINT) | (1 << TWEN); // Clear TWI interrupt flag,Enable TWI
  63. while (!(TWCR & (1 << TWINT))); // Wait till complete TWDR byte transmitted
  64. while((TWSR & 0xF8) != 0x28); // Check for the acknowledgement
  65. }
  66.  
  67. int main() {
  68. output(LED_DIRECTION, LED_PIN);
  69.  
  70. i2c_init_master();
  71.  
  72. while (1) {
  73. set(LED_PORT,LED_PIN);
  74. _delay_ms(100);
  75. clear(LED_PORT,LED_PIN);
  76.  
  77. i2c_start();
  78. i2c_write_address(recipient);
  79. i2c_write_data(data);
  80. i2c_stop();
  81.  
  82. _delay_ms(1000);
  83.  
  84. data ++;
  85. data %= 10;
  86. }
  87. }

Slave

  1. /********************************************************
  2. *
  3. * i2cslave.fabduino.c
  4. *
  5. * Alejandro Escario Méndez
  6. * 03/05/2015
  7. *
  8. * MIT license
  9. *********************************************************/
  10.  
  11. #include <avr/io.h>
  12. #include <util/delay.h>
  13.  
  14. #define output(directions,pin) (directions |= pin) // set port direction for output
  15. #define input(directions,pin) (directions &= (~pin)) // set port direction for input
  16. #define set(port,pin) (port |= pin) // set port pin
  17. #define clear(port,pin) (port &= (~pin)) // clear port pin
  18. #define pin_test(pins,pin) (pins & pin) // test for port pin
  19. #define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
  20.  
  21. #define LED_DIRECTION DDRB
  22. #define LED_PORT PORTB
  23. #define LED_PIN (1 << PB5)
  24.  
  25. unsigned char my_addr = 0x28;
  26.  
  27. void i2c_init_slave(){
  28. TWAR = my_addr;
  29. }
  30.  
  31. void i2c_match_read_slave(){
  32. while((TWSR & 0xF8)!= 0x60) { // wait for ACK
  33. TWCR=(1<<TWEA)|(1<<TWEN)|(1<<TWINT); // get ACK, en TWI, clear int flag
  34. while (!(TWCR & (1<<TWINT))); // Wait for TWINT flag
  35. }
  36. }
  37.  
  38. unsigned char i2c_read_slave(){
  39. TWCR=(1<<TWEA)|(1<<TWEN)|(1<<TWINT); // get ACK, en TWI, clear int flag
  40. while (!(TWCR & (1<<TWINT))); // Wait for TWINT flag
  41. while((TWSR & 0xF8)!=0x80); // Wait for acknowledgement
  42. return TWDR; // return received value
  43. }
  44.  
  45. int main() {
  46. output(LED_DIRECTION, LED_PIN);
  47.  
  48. i2c_init_slave();
  49.  
  50. while (1) {
  51. i2c_match_read_slave();
  52.  
  53. unsigned char data = i2c_read_slave();
  54. int i;
  55. for(i = 0; i < data; i++){
  56. _delay_ms(25);
  57. set(LED_PORT,LED_PIN);
  58. _delay_ms(25);
  59. clear(LED_PORT, LED_PIN);
  60. }
  61. }
  62. }

Interrupt

The preceding code is not implementing the best approach. Meanwhile the master device can divide its time between communication time and self-executing time because it decides when to communicate; the slave device has to be wasting CPU time waiting for the master device to start the communication. In order to fix that issue I decided to use interruptions in the slave device, so it can process information when not transmitting or receiving.

The incubator brain will need to send and retrieve information from the external modules. This new code enables two ways communication:

  • Master-transmitter/Slave-receiver
  • Master-receiver/Slave-transmitter

The implemented program sends a number (x) from the master device to the slave. The slave blinks the led 'x' times. The slave subtract the received number to 10 and sends it back to the master device. The master device blinks the led 10-x times. Increments the number to be sent to the slave and starts again.

Master

  1. /********************************************************
  2. *
  3. * i2cmaster.fabduino.c
  4. *
  5. * Alejandro Escario Méndez
  6. * 03/05/2015
  7. * MIT license
  8. *********************************************************/
  9.  
  10. #include <avr/io.h>
  11. #include <util/delay.h>
  12. #include <util/twi.h>
  13.  
  14. #define output(directions,pin) (directions |= pin) // set port direction for output
  15. #define input(directions,pin) (directions &= (~pin)) // set port direction for input
  16. #define set(port,pin) (port |= pin) // set port pin
  17. #define clear(port,pin) (port &= (~pin)) // clear port pin
  18. #define pin_test(pins,pin) (pins & pin) // test for port pin
  19. #define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
  20.  
  21. #define LED_DIRECTION DDRB
  22. #define LED_PORT PORTB
  23. #define LED_PIN (1 << PB5)
  24.  
  25. unsigned char recipient = 0x28;
  26. unsigned char data = 1;
  27.  
  28. void i2c_init_master(){
  29. // SCL freq = F_CPU/(16+2(TWBR)*prescalerValue)
  30. TWBR = 32; // Bit rate
  31. TWSR = (0 << TWPS1) | (0 << TWPS0); // Setting prescalar bits
  32. }
  33.  
  34. void i2c_start(){
  35. TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); // put start condition
  36. while(!(TWCR & (1 << TWINT))); // wait until start condition is transmitted
  37. while((TWSR & 0xF8)!= TW_START); // wait for ACK
  38. }
  39.  
  40. void i2c_repeated_start(){
  41. TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); // put start condition
  42. while(!(TWCR & (1 << TWINT))); // wait until start condition is transmitted
  43. while((TWSR & 0xF8)!= TW_REP_START); // wait for ACK
  44. }
  45.  
  46. void i2c_stop(){
  47. TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); // put stop condition
  48. while(!(TWCR & (1<<TWSTO))); // wait until stop condition is transmitted
  49. }
  50.  
  51. void i2c_write_address(unsigned char addr)
  52. {
  53. TWDR = addr; // write addr to "call"
  54. TWCR = (1 << TWINT) | (1 << TWEN); // Enable TWI and clear interrupt flag
  55. while(!(TWCR & (1 << TWINT))); // Wait until TWDR byte is transmitted
  56. while((TWSR & 0xF8)!= TW_MT_SLA_ACK); // Check for the acknowledgement
  57. }
  58.  
  59. void i2c_write_data(unsigned char data)
  60. {
  61. TWDR = data; // write data in TWDR
  62. TWCR = (1 << TWINT) | (1 << TWEN); // clc TWI interrupt flag,En TWI
  63. while (!(TWCR & (1 << TWINT))); // Wait until TWDR byte transmitted
  64. while((TWSR & 0xF8) != TW_MT_DATA_ACK); // Check for the acknowledgement
  65. }
  66.  
  67. void i2c_read_address(unsigned char data)
  68. {
  69. TWDR=data; // Address and read instruction
  70. TWCR=(1<<TWINT)|(1<<TWEN); // clc TWI interrupt flag,En TWI
  71. while (!(TWCR & (1<<TWINT))); // Wait until TWDR byte transmitted
  72. while((TWSR & 0xF8)!= TW_MR_SLA_ACK); // Check for the acknowledgement
  73. }
  74.  
  75.  
  76. void i2c_read_data()
  77. {
  78. TWCR=(1<<TWINT)|(1<<TWEN); // clc TWI interrupt flag,En TWI
  79. while (!(TWCR & (1<<TWINT))); // Wait until TWDR byte transmitted
  80. while((TWSR & 0xF8) != TW_MR_DATA_NACK); // Check for the acknowledgement
  81. blink(TWDR);
  82. }
  83.  
  84. void blink(unsigned char num){
  85. int i;
  86. for(i = 0; i < num; i++){
  87. _delay_ms(50);
  88. set(LED_PORT,LED_PIN);
  89. _delay_ms(50);
  90. clear(LED_PORT, LED_PIN);
  91. }
  92. }
  93.  
  94. int main() {
  95. output(LED_DIRECTION, LED_PIN);
  96.  
  97. i2c_init_master();
  98.  
  99. while (1) {
  100.  
  101. i2c_start();
  102. i2c_write_address(recipient);
  103. i2c_write_data(data);
  104. i2c_stop();
  105.  
  106. _delay_ms(1000);
  107. i2c_start();
  108. i2c_read_address(recipient+1);
  109. i2c_read_data();
  110. i2c_stop();
  111. _delay_ms(1000);
  112.  
  113. data ++;
  114. data %= 10;
  115. }
  116. }

Slave

  1. /********************************************************
  2. *
  3. * i2cslave.fabduino.c
  4. *
  5. * Alejandro Escario Méndez
  6. * 03/05/2015
  7. *
  8. * (c) Massachusetts Institute of Technology 2015
  9. * Permission granted for experimental and personal use;
  10. * license for commercial sale available from MIT.
  11. *********************************************************/
  12.  
  13. #include <avr/io.h>
  14. #include <util/delay.h>
  15. #include <util/twi.h>
  16. #include <avr/interrupt.h>
  17.  
  18. #define output(directions,pin) (directions |= pin) // set port direction for output
  19. #define input(directions,pin) (directions &= (~pin)) // set port direction for input
  20. #define set(port,pin) (port |= pin) // set port pin
  21. #define clear(port,pin) (port &= (~pin)) // clear port pin
  22. #define pin_test(pins,pin) (pins & pin) // test for port pin
  23. #define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
  24.  
  25. #define LED_DIRECTION DDRB
  26. #define LED_PORT PORTB
  27. #define LED_PIN (1 << PB5)
  28.  
  29. unsigned char my_addr = 0x28;
  30. unsigned char regaddr, regdata;
  31.  
  32. void i2c_init_slave(){
  33. TWAR = my_addr;
  34. TWDR = 0x00;
  35. // SCL freq = F_CPU/(16+2(TWBR)*prescalerValue)
  36. TWBR = 32; // Bit rate
  37. TWSR = (0 << TWPS1) | (0 << TWPS0); // Setting prescalar bits
  38. TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE); // get ACK, en TWI, clear int flag
  39. }
  40.  
  41. void blink(unsigned char num){
  42. int i;
  43. for(i = 0; i < num; i++){
  44. _delay_ms(50);
  45. set(LED_PORT,LED_PIN);
  46. _delay_ms(50);
  47. clear(LED_PORT, LED_PIN);
  48. }
  49. }
  50.  
  51. ISR(TWI_vect){
  52. static unsigned char last_val = 1;
  53. // Disable Global Interrupt
  54. cli();
  55. switch(TW_STATUS){
  56. case TW_START: // 0x08
  57. case TW_REP_START: // 0x10
  58. case TW_MT_SLA_ACK: // 0x18
  59. case TW_MT_SLA_NACK: // 0x20
  60. case TW_MT_DATA_ACK: // 0x28
  61. case TW_MT_DATA_NACK: // 0x30
  62. case TW_MR_SLA_ACK: // 0x40
  63. case TW_MR_SLA_NACK: // 0x48
  64. case TW_MR_DATA_ACK: // 0x50
  65. case TW_MR_DATA_NACK: // 0x58
  66. case TW_ST_ARB_LOST_SLA_ACK: // 0xB0
  67. case TW_SR_ARB_LOST_SLA_ACK: // 0x68
  68. case TW_SR_GCALL_ACK: //0x70
  69. case TW_SR_ARB_LOST_GCALL_ACK: // 0x78
  70. case TW_SR_GCALL_DATA_ACK: // 0x90
  71. case TW_SR_GCALL_DATA_NACK: // 0x98
  72. case TW_NO_INFO: // 0xF8
  73. TWCR |= (1<<TWINT); // Clear TWINT Flag
  74. break;
  75. case TW_SR_SLA_ACK: // 0x60: SLA+W received, ACK returned
  76. TWCR |= (1<<TWINT); // Clear TWINT Flag
  77. break;
  78. case TW_SR_DATA_ACK: // data received
  79. last_val = TWDR;
  80. blink(last_val);
  81. TWCR |= (1<<TWINT); // Clear TWINT Flag
  82. break;
  83. case TW_SR_STOP: // 0xA0: stop or repeated start condition received while selected
  84. TWCR |= (1<<TWINT); // Clear TWINT Flag
  85. break;
  86. case TW_ST_SLA_ACK: // 0xA8: SLA+R received, ACK returned
  87. TWDR= 10-last_val; // Fill TWDR register whith the data to be sent
  88. TWCR = ((1 << TWEA) | (1 << TWINT) | (1 << TWEN) | (1 << TWIE)); // Enable TWI, Clear TWI interrupt flag
  89. break;
  90. case TW_ST_DATA_ACK: // 0xB8: data transmitted, ACK received
  91. TWCR |= (1<<TWINT); // Clear TWINT Flag
  92. break;
  93. case TW_ST_DATA_NACK: // 0xC0: data transmitted, NACK received
  94. TWCR |= (1<<TWINT); // Clear TWINT Flag
  95. break;
  96. case TW_ST_LAST_DATA: // 0xC8: last data byte transmitted, ACK received
  97. case TW_BUS_ERROR: // 0x00: illegal start or stop condition
  98. default:
  99. TWCR |= (1<<TWINT); // Clear TWINT Flag
  100. break;
  101. }
  102.  
  103. sei();
  104. }
  105.  
  106. int main() {
  107. output(LED_DIRECTION, LED_PIN);
  108.  
  109. i2c_init_slave();
  110. sei();
  111.  
  112. while (1);
  113. }

The interaction between both FabKits can be seen in the next video.

9th May 2015

For this example I used a breadboard to do the SDA and SCL pull-up circuit. Now that everything is working as expected, I decided to create a small PCB circuit that allows connecting 4 I2C devices. The master or any slave can be connected to any port, But I suggest connecting the master device in the independent connection.

Once welded the result should look like this:

Bluetooth

Despite of the low cost nature of the incubator I am designing, I decided to add an "optional" module to control wirelessly the machine. In order to do that I connected a HC-05 Bluetooth module to my FabKit through the USART port and tried to send and receive/send information from/to a cellphone.

To achieve that goal I recycled the code and the design of the control panel shield but, instead of connecting the FabKit to the computer using the FTDI cable, I fed the circuit using the power supply built a few weeks ago. Doing that I could use the TX and RX ports of the FabKit to communicate with the bluetooth module at 9600 bauds.

I also had to design a board to connect the HC-05 to the FabKit (using for example a breadboard).

Once welded it looks like this:

This board has a button to pair the device, a led that indicates whether is powered on or not and a second led that blinks depending on the state of the bluetooth module. It has 6 output pins, but just 4 of them are mandatory: GND, 5V, Tx & Rx.

Learning how to communicate using a bluetooth interface, I modified the control panel code. It shows the position of the joystick in the first line of the screen and sends that information through the bluetooth as a string. If the connected device sends information to the AVR, it will be displayed in the second line of the LCD display.

In order to compile and load this code into an AVR the libraries serial.h and defitions.h must be located in the folder ../lib/. Those can be downloaded from the input devices page.
  1. /********************************************************
  2. *
  3. * bluetooth.fabduino.c
  4. *
  5. * 9600 baud FTDI interface
  6. *
  7. * Alejandro Escario Méndez
  8. * 29/04/2015
  9. *
  10. * MIT license
  11. *********************************************************/
  12.  
  13. #include <avr/io.h>
  14. #include <util/delay.h>
  15. #include <stdio.h>
  16. #include <avr/pgmspace.h>
  17. #include <avr/interrupt.h>
  18.  
  19. #include "../lib/definitions.h"
  20. #include "../lib/serial.h"
  21.  
  22. #define output(directions,pin) (directions |= pin) // set port direction for output
  23. #define input(directions,pin) (directions &= (~pin)) // set port direction for input
  24. #define set(port,pin) (port |= pin) // set port pin
  25. #define clear(port,pin) (port &= (~pin)) // clear port pin
  26. #define pin_test(pins,pin) (pins & pin) // test for port pin
  27. #define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
  28.  
  29. #define RGB_PORT PORTB
  30. #define RGB_DIRECTION DDRB
  31. #define RGB_PIN PINB
  32. #define RGB_RED PB1
  33. #define RGB_GREEN PB0
  34. #define RGB_BLUE PB2
  35.  
  36. #define BUZZER_PORT PORTD
  37. #define BUZZER_DIRECTION DDRD
  38. #define BUZZER_PIN PIND
  39. #define BUZZER_I PD7
  40.  
  41. #define BUTTON_PORT PORTD
  42. #define BUTTON_DIRECTION DDRD
  43. #define BUTTON_PIN PIND
  44. #define BUTTON_I PD2
  45.  
  46. #define lcd_delay() _delay_ms(10) // delay between commands
  47. #define strobe_delay() _delay_us(1) // delay for strobe
  48. #define LCD_PORT PORTC
  49. #define LCD_DIRECTION DDRC
  50. #define LCD_DB7 (1 << PC0)
  51. #define LCD_DB6 (1 << PC1)
  52. #define LCD_DB5 (1 << PC2)
  53. #define LCD_DB4 (1 << PC3)
  54. #define LCD_E (1 << PC4)
  55. #define LCD_RS (1 << PC5)
  56.  
  57. #define JOY_X 7
  58. #define JOY_Y 6
  59.  
  60. volatile int x = 0, y = 0, buff_idx;
  61. volatile char buff[16];
  62.  
  63. void button_init(){
  64. set(BUTTON_PORT, (1 << BUTTON_I)); // turn on pull-up
  65. input(BUTTON_DIRECTION, (1 << BUTTON_I));
  66. }
  67.  
  68. void button_on_click(void (*fn)()){
  69. if (0 == pin_test(BUTTON_PIN, (1 << BUTTON_I))){
  70. (*fn)();
  71. }
  72. }
  73.  
  74. void buzzer_init(){
  75. clear(BUZZER_PORT, (1 << BUZZER_I));
  76. output(BUZZER_DIRECTION, (1 << BUZZER_I));
  77. }
  78.  
  79. void buzzer_beep(){
  80. set(BUZZER_PORT, (1 << BUZZER_I));
  81. _delay_ms(10);
  82. clear(BUZZER_PORT, (1 << BUZZER_I));
  83. }
  84.  
  85. void rgb_init(){
  86. clear(RGB_PORT, (1 << RGB_RED));
  87. output(RGB_DIRECTION, (1 << RGB_RED));
  88. clear(RGB_PORT, (1 << RGB_GREEN));
  89. output(RGB_DIRECTION, (1 << RGB_GREEN));
  90. clear(RGB_PORT, (1 << RGB_BLUE));
  91. output(RGB_DIRECTION, (1 << RGB_BLUE));
  92.  
  93. rgb_off();
  94. }
  95.  
  96. void rgb_green(){
  97. clear(PORTB, (1 << RGB_GREEN));
  98. set(PORTB, (1 << RGB_RED));
  99. set(PORTB, (1 << RGB_BLUE));
  100. }
  101.  
  102. void rgb_off(){
  103. set(PORTB, (1 << RGB_GREEN));
  104. set(PORTB, (1 << RGB_RED));
  105. set(PORTB, (1 << RGB_BLUE));
  106. }
  107.  
  108. void rgb_red(){
  109. clear(PORTB, (1 << RGB_RED));
  110. set(PORTB, (1 << RGB_GREEN));
  111. set(PORTB, (1 << RGB_BLUE));
  112. }
  113.  
  114. void rgb_blue(){
  115. set(PORTB, (1 << RGB_RED));
  116. set(PORTB, (1 << RGB_GREEN));
  117. clear(PORTB, (1 << RGB_BLUE));
  118. }
  119.  
  120. void rgb_yellow(){
  121. clear(PORTB, (1 << RGB_GREEN));
  122. clear(PORTB, (1 << RGB_RED));
  123. set(PORTB, (1 << RGB_BLUE));
  124. }
  125.  
  126. void rgb_white(){
  127. clear(PORTB, (1 << RGB_GREEN));
  128. clear(PORTB, (1 << RGB_RED));
  129. clear(PORTB, (1 << RGB_BLUE));
  130. }
  131.  
  132. void joystick_init(){
  133. ADCSRA = (1 << ADEN) // enable
  134. | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // prescaler /128
  135. }
  136.  
  137. void joystick_change_port(volatile uint8_t pc){
  138. ADMUX = (0 << REFS1) | (0 << REFS0) // VCC ref
  139. | (0 << ADLAR) // right adjust for 10bit precision
  140. | pc;
  141. }
  142.  
  143. int joystick_read_x(){
  144. joystick_change_port(JOY_X);
  145. return read_adc();
  146. }
  147.  
  148. int joystick_read_y(){
  149. joystick_change_port(JOY_Y);
  150. return read_adc();
  151. }
  152.  
  153. int read_adc(){
  154. ADCSRA |= (1 << ADSC); // conversion init
  155. while (ADCSRA & (1 << ADSC)); // wait for completion
  156. return ADC; // return value
  157. }
  158.  
  159. //
  160. // lcd_putchar
  161. // put character in lcdbyte
  162. //
  163. void lcd_putchar(char lcdbyte) {
  164. //
  165. // set RS for data
  166. //
  167. set(LCD_PORT, LCD_RS);
  168. //
  169. // output high nibble
  170. //
  171. if bit_test(lcdbyte, 7)
  172. set(LCD_PORT, LCD_DB7);
  173. else
  174. clear(LCD_PORT, LCD_DB7);
  175. if bit_test(lcdbyte, 6)
  176. set(LCD_PORT, LCD_DB6);
  177. else
  178. clear(LCD_PORT, LCD_DB6);
  179. if bit_test(lcdbyte, 5)
  180. set(LCD_PORT, LCD_DB5);
  181. else
  182. clear(LCD_PORT, LCD_DB5);
  183. if bit_test(lcdbyte, 4)
  184. set(LCD_PORT, LCD_DB4);
  185. else
  186. clear(LCD_PORT, LCD_DB4);
  187. //
  188. // strobe E
  189. //
  190. strobe_delay();
  191. set(LCD_PORT, LCD_E);
  192. strobe_delay();
  193. clear(LCD_PORT, LCD_E);
  194. //
  195. // wait
  196. //
  197. lcd_delay();
  198. //
  199. // output low nibble
  200. //
  201. if bit_test(lcdbyte, 3)
  202. set(LCD_PORT, LCD_DB7);
  203. else
  204. clear(LCD_PORT, LCD_DB7);
  205. if bit_test(lcdbyte, 2)
  206. set(LCD_PORT, LCD_DB6);
  207. else
  208. clear(LCD_PORT, LCD_DB6);
  209. if bit_test(lcdbyte, 1)
  210. set(LCD_PORT, LCD_DB5);
  211. else
  212. clear(LCD_PORT, LCD_DB5);
  213. if bit_test(lcdbyte, 0)
  214. set(LCD_PORT, LCD_DB4);
  215. else
  216. clear(LCD_PORT, LCD_DB4);
  217. //
  218. // strobe E
  219. //
  220. strobe_delay();
  221. set(LCD_PORT, LCD_E);
  222. strobe_delay();
  223. clear(LCD_PORT, LCD_E);
  224. //
  225. // wait and return
  226. //
  227. lcd_delay();
  228. }
  229. //
  230. // lcd_putcmd
  231. // put command in lcdbyte
  232. //
  233. void lcd_putcmd(char lcdbyte) {
  234. //
  235. // clear RS for command
  236. //
  237. clear(LCD_PORT, LCD_RS);
  238. //
  239. // output command bits
  240. //
  241. PORTC = lcdbyte;
  242. //
  243. // strobe E
  244. //
  245. strobe_delay();
  246. set(LCD_PORT, LCD_E);
  247. strobe_delay();
  248. clear(LCD_PORT, LCD_E);
  249. //
  250. // wait and return
  251. //
  252. lcd_delay();
  253. }
  254. //
  255. // lcd_putstring
  256. // put a null-terminated string in flash
  257. //
  258. void lcd_putstring(char* message) {
  259. static uint8_t i;
  260. static char chr;
  261. i = 0;
  262. while (1) {
  263. chr = message[i];
  264. if (chr == 0)
  265. return;
  266. lcd_putchar(chr);
  267. ++i;
  268. }
  269. }
  270.  
  271. void lcd_putline(char* message, int line){
  272. if(line == 1){
  273. lcd_putcmd(0);
  274. lcd_putcmd(LCD_DB5);
  275. }else if(line == 2){
  276. lcd_putcmd(LCD_DB7+LCD_DB6);
  277. lcd_putcmd(0);
  278. }
  279. lcd_putstring(message);
  280. }
  281.  
  282. void lcd_clear(){
  283. lcd_putcmd(0);
  284. lcd_putcmd(LCD_DB4);
  285. }
  286.  
  287. void lcd_cursor_off(){
  288. lcd_putcmd(0);
  289. lcd_putcmd(LCD_DB7+LCD_DB6);
  290. }
  291. //
  292. // lcd_init
  293. // initialize the LCD
  294. //
  295. void lcd_init() {
  296. //
  297. // initialize LCD pins
  298. //
  299. clear(LCD_PORT, LCD_DB7);
  300. output(LCD_DIRECTION, LCD_DB7);
  301. clear(LCD_PORT, LCD_DB6);
  302. output(LCD_DIRECTION, LCD_DB6);
  303. clear(LCD_PORT, LCD_DB5);
  304. output(LCD_DIRECTION, LCD_DB5);
  305. clear(LCD_PORT, LCD_DB4);
  306. output(LCD_DIRECTION, LCD_DB4);
  307. clear(LCD_PORT, LCD_E);
  308. output(LCD_DIRECTION, LCD_E);
  309. clear(LCD_PORT, LCD_RS);
  310. output(LCD_DIRECTION, LCD_RS);
  311. //
  312. // power-up delay
  313. //
  314. lcd_delay();
  315. //
  316. // initialization sequence
  317. //
  318. lcd_putcmd(LCD_DB5+LCD_DB4);
  319. lcd_putcmd(LCD_DB5+LCD_DB4);
  320. lcd_putcmd(LCD_DB5+LCD_DB4);
  321. //
  322. // 4-bit interface
  323. //
  324. lcd_putcmd(LCD_DB5);
  325. //
  326. // two lines, 5x7 font
  327. //
  328. lcd_putcmd(LCD_DB5);
  329. lcd_putcmd(LCD_DB7);
  330. //
  331. // display on
  332. //
  333. lcd_putcmd(0);
  334. lcd_putcmd(LCD_DB7+LCD_DB6+LCD_DB5);
  335. //
  336. // entry mode
  337. //
  338. lcd_putcmd(0);
  339. lcd_putcmd(LCD_DB6+LCD_DB5);
  340. }
  341.  
  342. ISR (USART_RX_vect) {
  343. char line[16];
  344. buff[buff_idx] = UDR0;
  345. if(buff_idx >= 16 || buff[buff_idx] == 0){
  346. buff_idx = 0;
  347. }else{
  348. buff_idx++;
  349. }
  350. }
  351.  
  352. int main(void) {
  353. char line[16];
  354. int x, y, i = 0;
  355.  
  356. buzzer_init();
  357. rgb_init();
  358. lcd_init();
  359. button_init();
  360. joystick_init();
  361. lcd_init();
  362. lcd_clear();
  363. lcd_cursor_off();
  364.  
  365. usart_init(R_UBRR);
  366. sei();
  367.  
  368. while(1){
  369. x = joystick_read_x();
  370. y = joystick_read_y();
  371. sprintf(line, "x=%4i - y=%4i", x, y);
  372. printf("%s\n", line);
  373. lcd_putline(line, 1);
  374. lcd_putline(buff,2);
  375.  
  376. button_on_click(&buzzer_beep);
  377.  
  378. if(x > 450 && x < 550 && y > 450 && y < 550){
  379. rgb_green();
  380. }else if(x > 200 && x < 800 && y > 200 && y < 800){
  381. rgb_yellow();
  382. }else{
  383. rgb_red();
  384. }
  385. }
  386. }
24th June. 2015

In3

The incubator has 3 different boards. This approach might seem unnecessary at first glance, but the goal of the project is building a low cost incubator and, in order to achieve that goal, I designed it as modular as possible. Therefore If you want to build your incubator without the control panel board and controle it using the bluetooth connection, you can do it.

There are 3 types of networking communication:

  • I2C protocol to interact between boards.
  • Bluetooth through the ATmega168A serial port.
  • Serial full-duplex communication to interact with the DHT11 sensor module.

The boards and code of this two input devices can be found in the final project page.

Files

I2C [TWI]

Pull

Interrupt

Circuit

Bluetooth

Circuit

Code