// // // hello.button.45mod.c // // button hello-world // 9600 baud FTDI interface // // Christian Teissl, modified from Neil Gershenfeld // Nov. 2014 // Does ADC when pressing a button and sends serial to the computer when button is released // #include <avr/io.h> #include <util/delay.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 102 // 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 input_port PORTB #define input_direction DDRB #define input_pin1 (1 << PB3) // switch (switch ON = VCC) #define input_pin2 (1 << PB4) // analog voltage in #define input_pins PINB #define serial_port PORTB #define serial_direction DDRB #define serial_pin_out (1 << PB2) 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(); } int main(void) { // declarations char adc_result; // // main // // // initialize pins // set(serial_port, serial_pin_out); output(serial_direction, serial_pin_out); set(input_port, input_pin1); // turn on pull-up set(input_port, input_pin2); // turn on pull-up input(input_direction, input_pin1); input(input_direction, input_pin2); // // main loop // while (1) { // // wait for button down - triggers a single ADC conversion // while (0 == pin_test(input_pins,input_pin1)) ; // // ***initialize ADC*** // // *ADMUX Register* // // SET 8 bits only (ADCH)! ADLAR = 1 // SET reference voltage // voltage reference (rem: init. value of REFS[2:0]=0; // REFS1=0, REFS2=0; VCC used as Voltage Reference // SET analog input channel (and differential gain if required) // SET PB4 as single analog input: MUX[3:0] = 0010 (0 as default) ADMUX = (1 << ADLAR) | (0 << REFS1) | (0 << REFS0) | (0 << MUX3) | (0 << MUX2) | (1 << MUX1) | (0 << MUX0); // *ADCSRA – Register* // ADC Control and Status Register A // // SET ADC enabled via ADEN // SET prescale 8000kHz/64=125kHz via ADP[2:0}]=(110) ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0); // SET ADC Start Conversion bit (ADSC) - start measurement ADCSRA |= (1 << ADSC); // When conversion is complete, the result is written to the ADC Data Registers, and ADIF is set // In single Conversion mode, ADSC is cleared simultaneously while (ADCSRA & (1 << ADSC) ); // conversation is completed // read result from the ADC Result Register (ADCH if 8bit only!). adc_result = ADCH; // // wait for button up // while (0 != pin_test(input_pins,input_pin1)) ; // set clock divider back to /1 CLKPR = (1 << CLKPCE); CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0); put_char(&serial_port, serial_pin_out, 'r'); put_char(&serial_port, serial_pin_out, adc_result); } }