Week 10: Interface and Application Programming

This week the assignment was to create interfaces between our microcontroller board, a computer, and a user. I decided to program my board to output a color on the RGB LED corresponding to a hex code sent to the microcontroller from the computer. I programmed my attiny44 with C to read serial data from the ftdi cable and adjust the pwm duty cycle to reflect those values. I made a user interface with the python PyQt package to allow a user to input a number between 0 and 255 (the decimal representation of the hex value) for red, green, and blue to specify which color they wanted. Then I used the pyserial package to transmit data over the ftdi cable to the microcontroller. Below is my C code for the microcontroller and then my python code for the computer end. I'm still working out the bugs in the code that implements the sending of serial data when the button is pressed.

//
//
// application.c
// programs the attiny44 board to read serial data
// and output color on RGB to match received hex code
//
//

#include 
#include 

#define output(directions,pin) (directions |= pin) // set port direction for output
#define input(directions,pin) (directions &= ~pin)
#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 PWM_delay() _delay_us(25) // PWM delay
#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 red_port PORTB
#define green_port PORTA
#define blue_port PORTA
#define led_direction DDRB
#define red (1 << PB2)
#define green (1 << PA7)
#define blue (1 << PA3)

#define button_pin PINA
#define button (1 << PA2)

#define serial_port PORTA
#define serial_direction DDRA
#define serial_pins PINA
#define serial_pin_in (1 << PA0)
#define serial_pin_out (1 << PA1)

#define prefix0 'A'
#define prefix1 'B'

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();
   }

int main(void) {
   //
   // main
   //
   unsigned char count, pwm;
   static char chr;
   static char red_code;
   static char green_code;
   static char blue_code;
   int red_count = 0;
   int green_count = 0;
   int blue_count = 0;
 
   //
   // set clock divider to /1
   //
   CLKPR = (1 << CLKPCE);
   CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
   //
   // initialize LED pins
   //
   set(red_port, red);
   output(DDRB, red);
   set(green_port, green);
   output(DDRA, green);
   set(blue_port, blue);
   output(DDRA, blue);
   input(DDRA,button);
   set(button_pin,button);

   set(serial_port,serial_pin_out);
   input(DDRA,serial_pin_out);


while(1) {
    //read char and check for prefix
    get_char(&serial_pins, serial_pin_in, &chr);
    if (chr == prefix0){
        get_char(&serial_pins, serial_pin_in, &chr);
        if (chr == prefix1){
            //if prefix received, read data
            get_char(&serial_pins, serial_pin_in, &red_code);
            red_count = (int) red_code;
            get_char(&serial_pins, serial_pin_in, &green_code);
            green_count = (int) green_code;
            get_char(&serial_pins, serial_pin_in, &blue_code);
            blue_count = (int) blue_code;
            }
        }

    clear(red_port,red);
    clear(green_port,green);
    clear(blue_port,blue);
    //set each led on for length of appropriate duty cycle
    for (pwm = 0; pwm < 255; ++count) {
        if (pwm >= red_count)
            set(red_port,red);
        if (pwm >= blue_count)
            set(blue_port,blue);
        if (pwm >= green_count)
            set(green_port,green);
            PWM_delay();
            }
    }
  }

This is the python code for the computer side. It implements the user interface and the serial data transfer.

import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import serial



def main():
        #initialize window
        app = QApplication(sys.argv)
    win = QWidget()
    flo = QFormLayout()

        #add line of input for each RGB
    red = QLineEdit()
        #check for 3 digit ints
    red.setValidator(QIntValidator())
    red.setMaxLength(3)
    flo.addRow("Red Value (0-255):", red)

    green = QLineEdit()
    green.setValidator(QIntValidator())
    green.setMaxLength(3)
    flo.addRow("Green Value (0-255):", green)

    blue = QLineEdit()
    blue.setValidator(QIntValidator())
    blue.setMaxLength(3)
    flo.addRow("Blue Value (0-255):", blue)

        #make button
    button = QPushButton('Send')
    flo.addRow(button)

    win.setLayout(flo)
    win.show()

        #create serial channel
    out = serial.Serial("/dev/ttyUSB1", 9600)

        sys.exit(app.exec_())


if __name__ == '__main__':
        main()
        while True:
        if button.clicked==1:
        red_value = red.text()
        green_value = green.text()
        blue_value = blue.text()
                out.write("A")
                out.write("B")
        out.write(chr(red_value))
        out.write(chr(green_value))
        out.write(chr(blue_value))
                break