Home
Weekly Assignments
Final Project

11. Output devices

This week's assignment is similar to the input devices one, but instead of designing a board to receive data from the outside, a board with output devices must be built. Some examples are: screens, buzzers, RGB leds, engines, etc. must be designed.

The first prototype of the incubator will include two boards that match with this assignment:

Control panel

The control panel will consist of:

  • Joystick + button: this input device will allows the doctor/nurse to interact with the incubator. For example, changing the temperature.
  • RGB led: output device to tell if everything is OK (green), may be checked (yellow) or if attention is needed (red).
  • LCD screen: will display the incubator status.
  • Buzzer: output device to improve the user experience. For example, if a button is clicked, the incubator will "buzz", indicating that the action has been read.

Continuing with last week's strategy, I designed a new shield for my modified version of the FabKit board.

Once cut and welded is ready to be programed.

The code below is a demo which displays [using the LCD display] the position of the joystick (0-1023) for the x and y axes, buzzes when the button is pressed and changes the RGB led color depending on the position of the joystick.

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

Building FabKit shields is great for testing and learning how to program each device, but I am not sure if it is the best approach for the incubator. For example: this board requires almost every pin of the ATmega168A. Therefore, I wont be able to manage a NTC thermistor, a humidity sensor, water sensor and an engine. Probably, the final prototype will consist of several independent circuits (each one with its own microcontroller) communicating through serial port, I2C or any other protocol.

Power supply

The incubator will be able to tilt the bed using one or two stepper motors and its corresponding gears. I'd also like a first prototype pluggable to a 12V car battery. This means that the final circuit of the incubator will need middleware circuit to prepare the input voltage to feed the electronics (5V) and the stepper motors (12V).

I decided to design an independent board that, given a 12V power source, it can feed 12V and 5V systems.

As seen, it has 2 pin input for GND and VCC, 3 pair of 5V+GND, and 3 pair of 12V+GND pins.

24th June. 2015

In3

The incubator has several output devices.

The ones we are most used to deal with are the LCD display and the RGB led. Both of them have already been described. This devices are placed in the control panel board.

The temperature board is a little bit more tricky. It has 2 different types of output devices(in fact it has 3, but only 2 of them working right now):

  • Relays to turn on and of the Peltier module.
  • Fans to dissipate the cool or heat produced by the Peltier module.

The third output module is a pump to increase the humidity inside the incubator.

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

Files

Circuits

Codes

Control panel