6.3.3 Using Horizontal Cursor Code
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);
}
}
}
}
- Build the project, program and run the application by simply selecting Continue (F5) in the Debug menu of Atmel Studio