So far, the Graph module of the Data Visualizer has been used to show the data generated by the light sensor and to show when the Night mode switch toggles between the two modes. The Graph module can also be used to interact with the target application while it is running. In this example, the Night mode threshold can be adjusted dynamically by using a horizontal cursor.
First, the code must be extended to accept incoming data on the CDC USART. The output of the horizontal cursor is a 4-byte float value and will be sent over the CDC interface to the target application. This float value will be used as the threshold for the Night mode switch.
#include <avr/io.h> #include <avr/interrupt.h> const char* message_on = "NIGHT MODE ON"; const char* message_off = "NIGHT MODE OFF"; union u_float{ float flt; char data[4]; }; uint16_t adc_value = 0; uint8_t nightmode_threshold; uint8_t nightmode_active = 0; union u_float cdc_received_data; uint8_t cdc_read_index=0; ISR (USART1_RX_vect){ // A byte is received on the CDC UART, MSB first cdc_received_data.data[cdc_read_index] = UDR1 & 0xFF; if (3 == cdc_read_index){ // A complete float value is received nightmode_threshold = (uint8_t) cdc_received_data.flt; cdc_read_index = 0; } else { cdc_read_index++; } } void adc_init(void){ // Internal 1.5V reference, ADC0 as single ended input ADMUX = (1 << REFS1); // Enable the ADC, ADCSRA |= (1<<ADEN); // Check that the reference is OK while (0x00 == (ADCSRB & (1 << REFOK))); } uint16_t adc_sample(void){ // Trigger an ADC conversion ADCSRA |= (1<<ADSC); // Wait for conversion to finish while (0x00 == (ADCSRA & (1 << ADIF))); // Clear the interrupt flag ADCSRA |= (1 << ADIF); return (ADC); } void spi_init(void){ // Slave select (PB0), MOSI (PB2) and SCK (PB1) as output DDRB |= (1<<PINB0) | (1<<PINB2) | (1<<PINB1); //Slave select high (inactive) PORTB |= (1<<PINB0); // Master mode, enable SPI module. // Clock polarity and phase is kept at default (sample on rising edge) SPCR = (1<<SPE) | (1<<MSTR); } void spi_send(uint8_t data){ // Slave select low PORTB &= ~(1<<PINB0); // Write data to shift register SPDR = data; // Wait for the transmission to complete while (0x00 == (SPSR & (1<<SPIF))); // Slave select high PORTB |= (1<<PINB0); } void cdc_init(void){ // Baud rate 9600 based on 8 MHz CPU clock UBRR1 = 51; // Enable the transmitter and receiver, 8 bit character size, // receive interrupts enabled UCSR1B = (1<<RXEN1) | (1<<TXEN1) | (1<<RXCIE1); } void cdc_send(const char data){ // Wait for transmitter to be ready for more data while (0x00 == (UCSR1A & (1<<UDRE1))); // Send the data UDR1 = data; } void send_message(const char* message){ while (*message) cdc_send(*message++); // String markers requires Null-termination cdc_send(0); } int main(void){ adc_init(); spi_init(); cdc_init(); // Interrupts on sei(); while (1){ adc_value = adc_sample(); // Send the ADC value over SPI to the host // Only the 8 lower bits contain useful data spi_send(adc_value & 0xFF); // higher adc value == less light if (adc_value > nightmode_threshold){ if (0x00 == nightmode_active){ // Changing from nightmode inactive to active nightmode_active = 0x01; send_message(message_on); } } else { if (0x01 == nightmode_active){ // Changing from nightmode active to inactive nightmode_active = 0x00; send_message(message_off); } } } }