In this article I will show you how to use the ATTINY817 XPLAINED to communicate via UART using PuTTY software. This is very useful when you want to debug your hardware using your PC. This comes in handy if your hardware have no display and other means for human interface.
Setting up
When you connect your xplained kit, a new hardware is being added into your system. You will find it under “Device Manager -> Ports(COM & LPT) -> COMxx” where xx is the number of the device. It is different on every system so take note of it. On my machine it is COM10, this might be different on your machine.
Open PuTTY and click on “serial” and then Type the COMxx number on the text box. In this example it is COM10. Leave other settings as is and click ok.
About the Program
The program is written in C and fairly simple. It make use of the ISR or Interrupt Service Routine for executing program when a UART activity is detected. When you type any character on the PuTTY terminal, your PC will send UART data to your device and the device will receive the data and send it back to the PC for display. The microcontroller now search and evaluates the commands it received, if found valid, it will execute the command request.
Full Code:
/* * UART_simple.c * Author : tataylino.com */ #define F_CPU 20000000UL // 20 MHz #define NEWLINE_ON 1 #define NEWLINE_OFF 0 #define ENABLE 1 #define DISABLE 0 #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #include #include #include #include char msg_tx[] = "tataylino.com UART Utility v1.0 \n\rCommands: \ \n\r h - help \ \n\r a - read ADC \ \n\r d xx - set DAC \ \n\r c xx - set PortC \ \n\r Notes\n xx- 8bit hex value"; int x = 0; char msg_rx[]; char msg_tx[]; char param1[5]; uint16_t hex_value; void dac_init() { DAC0_CTRLA = 0xC1; // enable DAC } void adc_init (void) { ADC0_CTRLA = (0<<ADC_RUNSTBY_bp)|(0<<ADC_RESSEL_10BIT_gc)|(1<<ADC_ENABLE_bp); //Disabled run in standby, enabled ADC & full 10-bit resolution VREF_CTRLA = (1<<VREF_ADC0REFSEL0_bp)|(VREF_DAC0REFSEL_1V1_gc); //ADC voltage reference = 1.1V (0x1), DAC to 1.1V ADC0_CTRLC = (1<<ADC_SAMPCAP_bp)|(0<<ADC_REFSEL_gp); //Set Internal reference, set reduced size of sampling capacitance, set prescaler to CLK_PER/4 ADC0_CTRLD = (1<<ADC_INITDLY1_bp)|(0<<ADC_ASDV_bp)|(0<<ADC_SAMPDLY0_bp); //These bits define the delay when initializing the ADC or changing the source of the reference voltage. ADC0_SAMPCTRL = (1<<ADC_SAMPLEN4_bp); //0x10, These bits control the ADC sampling time in number of CLK_ADC cycles, ADC0_MUXPOS = ADC_MUXPOS_TEMPSENSE_gc; //0x1E Temperature sensor - Single ended analog input connected to ADC ADC0_CTRLB = 0x06; // 32 samples } void set_dac(uint16_t val) { DAC0_DATA = val; } void read_adc(char ch) { // Read ADC char buffer[6]; //Array with three elements, 8-bits in each element uint16_t adc_val = 0; double adc_ave = 0; double adc_v = 0; char run = 0; run = 0; ADC0_MUXPOS = ch; // channel select _delay_ms(1); start_conversion: ADC0_COMMAND = (1<<ADC_STCONV_bp); // Start conversion//Writing a '1' to this bit in single-shot mode starts one conversion. while (ADC0_COMMAND & (1<<ADC_STCONV_bp)); // while conversion is on-going _delay_ms(10); if (run < 5) // discard 5 adc readings { run++; adc_val = ((ADC0_RESH << 8) | ADC0_RESL); //ADC conversion result to make sure adc reading is good goto start_conversion; } else { adc_val = ((ADC0_RESH << 8) | ADC0_RESL); //ADC conversion result with 1.1 V internal reference adc_ave = adc_val/64; // Average from 64 samples adc_v = (adc_ave/1024)*1.1; // 1.1 is VREF, 1024 is the adc resolution(10bit) dtostrf(adc_v, 6, 3, buffer); //double to string conversion send_msg(buffer, NEWLINE_OFF); } } ISR(USART0_RXC_vect) { // When any key is pressed char value = 0; value = USART0_RXDATAL; if(value != "") { msg_rx[x] = value; USART_SendByte(msg_rx[x]); //send back the character typed to display if(value != 8 && value != 127) // if backspace/delete is pressed, { x++; } else { x--; } if(value == '\r') //if enter is pressed, process command { USART_SendByte('\n'); // new line check_cmd(msg_rx); // check for command request x = 0; } } } void check_param(char msg[]) { // read param param1[0] = msg[2]; param1[1] = msg[3]; param1[2] = '\0'; // add null character } void convert_to_int() { // ASCII to integer conversion hex_value = (uint8_t)(strtol(param1, NULL, 16)); } void check_cmd(char msg[]) { char cmd; char chk_space; cmd = msg[0]; // get first character chk_space = msg[1]; // get second character -should be space if(chk_space == ' ' || cmd == 'h' || cmd == 't') { switch(cmd) { case 'h': // Help send_msg(msg_tx, NEWLINE_ON); break; case 'a': // ADC read send_msg("ADC reading: ", NEWLINE_OFF); check_param(msg); convert_to_int(); read_adc(hex_value); send_msg("V", NEWLINE_ON); //Display Unit break; case 'd': // DAC set send_msg("DAC SET: ", NEWLINE_OFF); check_param(msg); convert_to_int(); if(hex_value > 0xFF) { send_msg("Out of range ", NEWLINE_ON); } set_dac(hex_value); read_adc(0x1C); // Read actual DAC voltage send_msg("V ", NEWLINE_ON); // Display unit V break; case 'c': // GPIO Set port C send_msg("PORT C set: ", NEWLINE_OFF); check_param(msg); convert_to_int(); gpio_on(hex_value); send_msg(param1, NEWLINE_ON); break; default: send_msg("Unknown Command! Type h to get list of commands!"); } } else{ send_msg("Invalid Command!"); } } void USART_Init(void) { USART0_CTRLB = USART_RXEN_bm | USART_TXEN_bm | USART_RXCIE_bm; USART0_CTRLC = USART_CMODE_ASYNCHRONOUS_gc | USART_PMODE_DISABLED_gc | USART_CHSIZE_8BIT_gc; USART0_CTRLA = (1<<USART_RXCIE_bp)|(0<<USART_TXCIE_bp); PORTB_DIRSET = (0<<PIN3_bp) | (1<<PIN2_bp); USART0_BAUD = 1388; //Calculate baud rate setting, Industrial, BAUD = 64*CLK_PER/S*fBAUD = 64*3.33MHz/16*9600 = 1388 USART0_STATUS = USART_RXCIF_bm | USART_TXCIF_bm; } void USART_SendByte(uint8_t u8Data) { // Send Character USART0_TXDATAL = u8Data; while((USART0_STATUS &(1<<USART_TXCIF_bp)) == 0); USART0_STATUS = (1<<USART_TXCIF_bp); // clear flag } void send_msg(char msg[], char new_line) { // send message to UART int i = 0; for(i = 0; i < strlen(msg); i++) { USART_SendByte(msg[i]); // send value } if(new_line == ENABLE) { USART_SendByte('\n'); // new line USART_SendByte('\r'); // return } } void gpio_on(char val) { PORTC_OUT = val; // PORT C output } int main(void) { PORTA_DIR = 0x40; // SET PA6 as output PORTC_DIR = 0xff; // Set PORT C as output PORTC_OUT = 0x00; // initial value USART_Init(); // Initialize USART adc_init(); //Calling ADC init dac_init(); // initialize DAC sei(); // enable all interrupts send_msg(msg_tx, NEWLINE_ON); while (1) { } }
This should be the output of our program.
Download
You can download the original code on my download page here