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