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:
The control panel will consist of:
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.
- /********************************************************
- *
- * controlpanel.fabduino.c
- *
- * 9600 baud FTDI interface
- *
- * Alejandro Escario Méndez
- * 15/04/2015
- *
- * MIT license
- *********************************************************/
- #include <avr/io.h>
- #include <util/delay.h>
- #include <stdio.h>
- #include <avr/pgmspace.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 RGB_PORT PORTB
- #define RGB_DIRECTION DDRB
- #define RGB_PIN PINB
- #define RGB_RED PB1
- #define RGB_GREEN PB0
- #define RGB_BLUE PB2
- #define BUZZER_PORT PORTD
- #define BUZZER_DIRECTION DDRD
- #define BUZZER_PIN PIND
- #define BUZZER_I PD7
- #define BUTTON_PORT PORTD
- #define BUTTON_DIRECTION DDRD
- #define BUTTON_PIN PIND
- #define BUTTON_I PD2
- #define lcd_delay() _delay_ms(10) // delay between commands
- #define strobe_delay() _delay_us(1) // delay for strobe
- #define LCD_PORT PORTC
- #define LCD_DIRECTION DDRC
- #define LCD_DB7 (1 << PC0)
- #define LCD_DB6 (1 << PC1)
- #define LCD_DB5 (1 << PC2)
- #define LCD_DB4 (1 << PC3)
- #define LCD_E (1 << PC4)
- #define LCD_RS (1 << PC5)
- #define JOY_X 7
- #define JOY_Y 6
- void button_init(){
- set(BUTTON_PORT, (1 << BUTTON_I)); // turn on pull-up
- input(BUTTON_DIRECTION, (1 << BUTTON_I));
- }
- void button_on_click(void (*fn)()){
- if (0 == pin_test(BUTTON_PIN, (1 << BUTTON_I))){
- (*fn)();
- }
- }
- void buzzer_init(){
- clear(BUZZER_PORT, (1 << BUZZER_I));
- output(BUZZER_DIRECTION, (1 << BUZZER_I));
- }
- void buzzer_beep(){
- set(BUZZER_PORT, (1 << BUZZER_I));
- _delay_ms(10);
- clear(BUZZER_PORT, (1 << BUZZER_I));
- }
- void rgb_init(){
- clear(RGB_PORT, (1 << RGB_RED));
- output(RGB_DIRECTION, (1 << RGB_RED));
- clear(RGB_PORT, (1 << RGB_GREEN));
- output(RGB_DIRECTION, (1 << RGB_GREEN));
- clear(RGB_PORT, (1 << RGB_BLUE));
- output(RGB_DIRECTION, (1 << RGB_BLUE));
- }
- void rgb_green(){
- clear(PORTB, (1 << RGB_GREEN));
- set(PORTB, (1 << RGB_RED));
- set(PORTB, (1 << RGB_BLUE));
- }
- void rgb_red(){
- clear(PORTB, (1 << RGB_RED));
- set(PORTB, (1 << RGB_GREEN));
- set(PORTB, (1 << RGB_BLUE));
- }
- void rgb_blue(){
- set(PORTB, (1 << RGB_RED));
- set(PORTB, (1 << RGB_GREEN));
- clear(PORTB, (1 << RGB_BLUE));
- }
- void rgb_yellow(){
- clear(PORTB, (1 << RGB_GREEN));
- clear(PORTB, (1 << RGB_RED));
- set(PORTB, (1 << RGB_BLUE));
- }
- void rgb_white(){
- clear(PORTB, (1 << RGB_GREEN));
- clear(PORTB, (1 << RGB_RED));
- clear(PORTB, (1 << RGB_BLUE));
- }
- void joystick_init(){
- ADCSRA = (1 << ADEN) // enable
- | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // prescaler /128
- }
- void joystick_change_port(volatile uint8_t pc){
- ADMUX = (0 << REFS1) | (0 << REFS0) // VCC ref
- | (0 << ADLAR) // right adjust for 10bit precision
- | pc;
- }
- int joystick_read_x(){
- joystick_change_port(JOY_X);
- return read_adc();
- }
- int joystick_read_y(){
- joystick_change_port(JOY_Y);
- return read_adc();
- }
- int read_adc(){
- ADCSRA |= (1 << ADSC); // conversion init
- while (ADCSRA & (1 << ADSC)); // wait for completion
- return ADC; // return value
- }
- //
- // lcd_putchar
- // put character in lcdbyte
- //
- void lcd_putchar(char lcdbyte) {
- //
- // set RS for data
- //
- set(LCD_PORT, LCD_RS);
- //
- // output high nibble
- //
- if bit_test(lcdbyte, 7)
- set(LCD_PORT, LCD_DB7);
- else
- clear(LCD_PORT, LCD_DB7);
- if bit_test(lcdbyte, 6)
- set(LCD_PORT, LCD_DB6);
- else
- clear(LCD_PORT, LCD_DB6);
- if bit_test(lcdbyte, 5)
- set(LCD_PORT, LCD_DB5);
- else
- clear(LCD_PORT, LCD_DB5);
- if bit_test(lcdbyte, 4)
- set(LCD_PORT, LCD_DB4);
- else
- clear(LCD_PORT, LCD_DB4);
- //
- // strobe E
- //
- strobe_delay();
- set(LCD_PORT, LCD_E);
- strobe_delay();
- clear(LCD_PORT, LCD_E);
- //
- // wait
- //
- lcd_delay();
- //
- // output low nibble
- //
- if bit_test(lcdbyte, 3)
- set(LCD_PORT, LCD_DB7);
- else
- clear(LCD_PORT, LCD_DB7);
- if bit_test(lcdbyte, 2)
- set(LCD_PORT, LCD_DB6);
- else
- clear(LCD_PORT, LCD_DB6);
- if bit_test(lcdbyte, 1)
- set(LCD_PORT, LCD_DB5);
- else
- clear(LCD_PORT, LCD_DB5);
- if bit_test(lcdbyte, 0)
- set(LCD_PORT, LCD_DB4);
- else
- clear(LCD_PORT, LCD_DB4);
- //
- // strobe E
- //
- strobe_delay();
- set(LCD_PORT, LCD_E);
- strobe_delay();
- clear(LCD_PORT, LCD_E);
- //
- // wait and return
- //
- lcd_delay();
- }
- //
- // lcd_putcmd
- // put command in lcdbyte
- //
- void lcd_putcmd(char lcdbyte) {
- //
- // clear RS for command
- //
- clear(LCD_PORT, LCD_RS);
- //
- // output command bits
- //
- PORTC = lcdbyte;
- //
- // strobe E
- //
- strobe_delay();
- set(LCD_PORT, LCD_E);
- strobe_delay();
- clear(LCD_PORT, LCD_E);
- //
- // wait and return
- //
- lcd_delay();
- }
- //
- // lcd_putstring
- // put a null-terminated string in flash
- //
- void lcd_putstring(char* message) {
- static uint8_t i;
- static char chr;
- i = 0;
- while (1) {
- chr = message[i];
- if (chr == 0)
- return;
- lcd_putchar(chr);
- ++i;
- }
- }
- void lcd_putline(char* message, int line){
- if(line == 1){
- lcd_putcmd(0);
- lcd_putcmd(LCD_DB5);
- }else if(line == 2){
- lcd_putcmd(LCD_DB7+LCD_DB6);
- lcd_putcmd(0);
- }
- lcd_putstring(message);
- }
- void lcd_clear(){
- lcd_putcmd(0);
- lcd_putcmd(LCD_DB4);
- }
- void lcd_cursor_off(){
- lcd_putcmd(0);
- lcd_putcmd(LCD_DB7+LCD_DB6);
- }
- //
- // lcd_init
- // initialize the LCD
- //
- void lcd_init() {
- //
- // initialize LCD pins
- //
- clear(LCD_PORT, LCD_DB7);
- output(LCD_DIRECTION, LCD_DB7);
- clear(LCD_PORT, LCD_DB6);
- output(LCD_DIRECTION, LCD_DB6);
- clear(LCD_PORT, LCD_DB5);
- output(LCD_DIRECTION, LCD_DB5);
- clear(LCD_PORT, LCD_DB4);
- output(LCD_DIRECTION, LCD_DB4);
- clear(LCD_PORT, LCD_E);
- output(LCD_DIRECTION, LCD_E);
- clear(LCD_PORT, LCD_RS);
- output(LCD_DIRECTION, LCD_RS);
- //
- // power-up delay
- //
- lcd_delay();
- //
- // initialization sequence
- //
- lcd_putcmd(LCD_DB5+LCD_DB4);
- lcd_putcmd(LCD_DB5+LCD_DB4);
- lcd_putcmd(LCD_DB5+LCD_DB4);
- //
- // 4-bit interface
- //
- lcd_putcmd(LCD_DB5);
- //
- // two lines, 5x7 font
- //
- lcd_putcmd(LCD_DB5);
- lcd_putcmd(LCD_DB7);
- //
- // display on
- //
- lcd_putcmd(0);
- lcd_putcmd(LCD_DB7+LCD_DB6+LCD_DB5);
- //
- // entry mode
- //
- lcd_putcmd(0);
- lcd_putcmd(LCD_DB6+LCD_DB5);
- }
- int main(void) {
- char line[16];
- int x, y;
- buzzer_init();
- rgb_init();
- lcd_init();
- button_init();
- joystick_init();
- lcd_clear();
- lcd_cursor_off();
- while (1) {
- x = joystick_read_x();
- sprintf(line, "%4i", x);
- lcd_putline(line,1);
- button_on_click(&buzzer_beep);
- y = joystick_read_y();
- sprintf(line, "%4i", y);
- lcd_putline(line,2);
- if(x > 450 && x < 550 && y > 450 && y < 550){
- rgb_green();
- }else if(x > 200 && x < 800 && y > 200 && y < 800){
- rgb_yellow();
- }else{
- rgb_red();
- }
- }
- }
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.
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.
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):
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.