6.3.2 Adding String Markers

It is time to implement the mode switch. To check that the switch is actually working and switching at the right threshold, the string marker feature of the Graph module is useful. By setting up the CDC USART interface of the ATmega256RFR2 Xplained Pro to send a string each time the mode is switched. These messages can then be shown in the graph as string markers. First, extend the code as shown below.
Important: The code will only work if the target CPU is running at 8 MHz. Use the Atmel Studio Programming dialog to set the fuses correctly (Tools → Device Programming). The clock should be set to internal RC oscillator and the CKDIV8 fuse should not be set.
#include <avr/io.h>
#include <avr/interrupt.h>
const char* message_on = "NIGHT MODE ON";
const char* message_off = "NIGHT MODE OFF";
uint16_t adc_value = 0;
uint8_t nightmode_threshold = 40;
uint8_t nightmode_active = 0;
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();
	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 night mode inactive to active
				nightmode_active = 0x01;
				send_message(message_on);
			}
			} else {
			if (0x01 == nightmode_active){
				// Changing from night mode active to inactive
				nightmode_active = 0x00;
				send_message(message_off);
			}
		}
	}
}
Todo:
  • Build the project, program and run the application by simply selecting Continue (F5) in the Debug menu of Atmel Studio