User Tools

Site Tools


Arduino UNO/AVR pure C sample

Sample for Arduino interactive “application”. I wrote for the weekend from chip datasheet and examples.

In general, I bought a kit of manipulator for my youngest son, but once I got a micro controller … I could not miss this chance and “remember all” =)

Into the sample release:

  1. FIFO buffers for input and input/output to serial line
  2. Redirect standard input/output to FIFOs
  3. 2 PWN output
  4. Watchdog and timer interrupts (I hooked FIFO in/out to the interrupts)
  5. Some own data manipulation function
  6. … What yet?

The microprocessor is very modest for 2017 but I liked simplicity (relative) of its programming.

Output

# cu -s 38400 -l /dev/ttyU0
Connected
#########################
### UNIX7.ORG ##############
READY>23
OK 23   
READY>
Makefile
#
# $Id$
#
.SECONDARY:
 
all: main.hex
 
CFLAGS= -I. -Os -DF_CPU=16000000UL -mmcu=atmega328p
LDFLAGS= -s -Os -DF_CPU=16000000UL -mmcu=atmega328p
 
main.elf: main.o fifo.o tools.o
	avr-gcc $(LDFLAGS) -o $@ main.o fifo.o tools.o
 
%.o: %.c
	avr-gcc $(CFLAGS) -c -o $@ $<
 
%.elf: %.o
	avr-gcc $(LDFLAGS) -o $@ $<
 
%.hex: %.elf
	avr-objcopy --strip-unneeded -g -O ihex -R .eeprom $< $@
 
upload: main.hex
	avrdude -qq -c arduino -p ATMEGA328P -P /dev/ttyU0 -b 115200 -U flash:w:main.hex
 
backup:
	avrdude -F -V -c arduino -p ATMEGA328P -P /dev/ttyU0 -b 115200 -U flash:r:backup.hex:i
 
clean:
	rm -f *.i *.o *.elf *~
 
#EOF

fifo.c

fifo.c
/* $Id$ */
 
#include <ctype.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
 
#include <fifo.h>
 
void fifo_init(FIFO * b, uint8_t * buffer, uint8_t buffer_len) {
    if (b && buffer) {
        memset((void **)buffer, 0, buffer_len);
        b->buffer_len = buffer_len;
        b->buffer = buffer;
        b->head = 0;
        b->tail = 0;
    }
    return;
}
 
uint8_t fifo_count(const FIFO * b) {
    if (b) {
        return (b->head - b->tail);
    }
    return 0;
}
 
static bool fifo_full(const FIFO * b) {
    if (b) {
        return (fifo_count(b) == b->buffer_len);
    }
    return true;
}
 
bool fifo_empty(const FIFO * b) {
    if (b) {
        return (fifo_count(b) == 0);
    }
    return true;
}
 
uint8_t fifo_peek(const FIFO * b) {
    if (b) {
        return (b->buffer[b->tail % b->buffer_len]);
    }
    return 0;
}
 
uint8_t fifo_getc(FIFO * b) {
    uint8_t data = 0;
 
    if (!fifo_empty(b)) {
        data = b->buffer[b->tail % b->buffer_len];
        b->tail++;
    }
    return data;
}
 
bool fifo_putc(FIFO * b, uint8_t data) {
    bool status = false;
 
    if (b) {
        if (!fifo_full(b)) {
            b->buffer[b->head % b->buffer_len] = data;
            b->head++;
            status = true;
        }
    }
    return status;
}
 
uint8_t fifo_puts(FIFO * b, char *string) {
    if (b) {
        for (uint8_t i = 0; i < strlen(string); i++) {
            if (!fifo_putc(b, string[i]))
                return i;
        }
    }
}
 
bool fifo_scanc(FIFO * b, uint8_t c) {
    if (b) {
        if (!fifo_empty(b)) {
            uint8_t tail = b->tail;
 
            for (uint8_t i = 0; i < fifo_count(b); i++) {
                uint8_t data = b->buffer[tail % b->buffer_len];
 
                if (data == c) {
                    return true;
                }
                tail++;
            }
        }
        return false;
    }
}
 
uint8_t fifo_gett(FIFO * b, uint8_t * str, uint8_t len, uint8_t term) {
    if (b) {
        memset((void *)str, 0, len);
 
        if (fifo_scanc(b, term) && str) {
            uint8_t i = 0, c = 0;
 
            while ((c = fifo_getc(b)) != 0 && c != term && i < len) {
                str[i] = c;
                i++;
            }
            return i;
        }
        return 0;
    }
}
/* EOF */

fifo.h

fifo.h
/* $Id$ */
 
#ifndef UARTH_IUI
#define UARTH_IUI
 
struct fifo_t {
    volatile unsigned head;
    volatile unsigned tail;
    volatile uint8_t *buffer;
    unsigned buffer_len;
};
 
typedef struct fifo_t FIFO;
 
void fifo_init(FIFO * b, uint8_t * buffer, uint8_t buffer_len);
uint8_t fifo_count(const FIFO * b);
static bool fifo_full(const FIFO * b);
bool fifo_empty(const FIFO * b);
uint8_t fifo_peek(const FIFO * b);
uint8_t fifo_getc(FIFO * b);
bool fifo_putc(FIFO * b, uint8_t data);
uint8_t fifo_puts(FIFO * b, char *string);
bool fifo_scanc(FIFO * b, uint8_t c);
uint8_t fifo_gett(FIFO * b, uint8_t * str, uint8_t len, uint8_t);
 
#endif
/* EOF */

main.c

main.c
/* $Id$ */
 
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
 
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
 
 
#define BAUD 38400
#include <util/setbaud.h>
 
#include <fifo.h>
#include <tools.h>
 
inline void init_uart(void) {
    /* UBRR - USART Baud Rate Register */
    UBRR0H = UBRRH_VALUE;
    UBRR0L = UBRRL_VALUE;
    /* UCSR  - USART Control and Status Register */
    /* U2X - Double Speed Operation */
    UCSR0A &= ~(1 << U2X0);
    /* UCSZ - USART Character Size, 8 bit */
    UCSR0B &= ~(1 << UCSZ02);
    UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00);
    /* USBS - USART Stop Bit Select */
    /* UPM - USART Parity Mode */
    UCSR0C &= ~(1 << USBS0) & ~(1 << UPM00) & ~(1 << UPM01);
    UCSR0B |= (1 << TXEN0) | (1 << RXEN0);
    UCSR0B |= (1 << RXCIE0);    /* Enable Receive Interrupt */
    UCSR0B &= ~(1 << UDRIE0);   /* Disabale Transmit Interrupt */
}
 
void wdt_init(void) {
    wdt_enable(WDTO_30MS);
    WDTCSR = (1 << WDIE);
}
 
#define FIFO_BUFFER_SIZE 255
 
FIFO fifo_in, fifo_out;
FIFO* in;
FIFO* out;
 
ISR(USART_RX_vect) {
    uint8_t c = UDR0;
    if (c == '\r') {
        fifo_puts(in, "\n");
        fifo_puts(out, "\n");
    }
    fifo_putc(in, c);
    fifo_putc(out, c);
}
 
//ISR(USART_UDRE_vect) {
//}
 
ISR(WDT_vect) {
    wdt_reset();
    uint8_t c;
    while ((c = fifo_getc(out)) > 0) {
        while (!(UCSR0A & (1 << UDRE0)));
            UDR0 = c;
    }
    WDTCSR = (1 << WDIE);
}
 
#define CLKD1    (1<<CS20)      /* CLK/8 */
#define CLKD8    (1<<CS21)      /* CLK/8 */
#define CLKD32   (1<<CS20)|(1<<CS21)    /* CLK/32 */
#define CLKD64   (1<<CS22);     /* CLK/64 */
#define CLKD128  (1<<CS20)|(1<<CS22)    /* CLK/128 */
#define CLKD256  (1<<CS21)|(1<<CS22)    /* CLK/256 */
#define CLKD1024 (1<<CS20)|(1<<CS21)|(1<<CS22)  /* CLK/1024 */
 
void timer_init(void) {
    TCCR2A = 0;
    TCCR2B = 0;
    TCCR2B = CLKD256;
    TIMSK2 |= (1 << TOIE2);
}
 
void pwm_init(void) {
    TCCR0A |= _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00) | _BV(WGM01); 
    TCCR0B = CLKD128;
    OCR0A = 0;
    OCR0B = 0;
    DDRB |= (1 << PORTB3) ;
    DDRD |= (1 << PORTD3) | (1 << PORTD6) | (1 << PORTD5) ;
}
 
ISR(TIMER2_OVF_vect) {
}
 
int uart_putchar(char c, FILE *stream) {
    return fifo_putc(&fifo_out, c);
}
 
int uart_getchar(FILE *stream) {
    return (int)fifo_getc(&fifo_out);
}
 
FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
 
int main() {
 
    uint8_t inbuf[FIFO_BUFFER_SIZE];
    uint8_t outbuf[FIFO_BUFFER_SIZE];
 
    stdout = stdin = stderr = &uart_str;
 
    in = &fifo_in;
    out = &fifo_out;
 
    fifo_init(in, inbuf, FIFO_BUFFER_SIZE);
    fifo_init(out, outbuf, FIFO_BUFFER_SIZE);
 
    init_uart();
    wdt_init();
    timer_init();
    pwm_init();
    sei();
 
    _delay_ms(1000);
 
    fifo_puts(out, "############################\r\n");
    fifo_puts(out, "### UNIX7.ORG ##############\r\n");
 
    fifo_puts(out, "READY>");
 
#define STR_LEN 64
    uint8_t str[STR_LEN];
    memset(str, 0, STR_LEN);
 
    while (1) {
        uint8_t *s;
        s = str;
 
        while(fifo_gett(in, str, STR_LEN, '\r') > 0) {
 
            s = str_trim(str, ' ');
            int16_t i = str_geti(s);
            int_gets(i, s, STR_LEN, 10);
 
            if (i >= 10 && i <= 38) {
                OCR0A = i;
                OCR0B = i;
                fifo_puts(out, "OK ");
                fifo_puts(out, s);
            } else {
                fifo_puts(out, "OUT OF RANGE 10-38");
            }
 
            fifo_puts(out, "\n\rREADY>");
 
        }
        _delay_ms(100);
 
    }
}

tools.c

tools.c
/* $Id$ */
 
#include <stdint.h>
#include <tools.h>
 
uint16_t str_len(uint8_t * str) {
    uint16_t i = 0;
    while (str[i] != 0 && i < MAX_LINE_LEN)
        i++;
    return i;
}
 
uint8_t *str_trim(uint8_t * str, uint8_t c) {
    while (str[0] == c && str[0] != 0) str++;
 
    uint8_t i = str_len(str) - 1;
    while (str[i] == c && i > 0) {
        i--;
    }
    str[++i] = 0;
    return str;
}
 
int32_t int_power(uint8_t n, uint8_t s) {
    int64_t i = 1;
    while (s--) {
        i = i * n;
    }
    return i;
}
 
int32_t str_geti(uint8_t * str) {
    uint8_t l = str_len(str);
    uint8_t i = l - 1;
    int16_t n = 0;
    while (i--) {
        if (str[i] <= '9' && str[i] >= '0')
            n += (str[i] - '0') * int_power(10, l - i - 2);
    }
    if (str[0] == '-') n = -n;
    return n;
}
 
uint8_t int_gets(int32_t num, uint8_t *str, uint8_t str_len, int16_t base) {
    static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
    uint8_t i = 0, sign = 0;
    if (num < 0) {
        sign = '-';
        num = -num;
    }
    do {
        str[i++] = digits[num % base];
    } while ((num /= base) > 0 && i < str_len);
 
    if (sign) str[i++] = '-';
    str[i] = 0;
 
    uint8_t len = i - 1;
    uint8_t c, b = 0;
 
    while(i-- && b < i) {
        c = str[b];
        str[b] = str[i];
        str[i] = c;
        b++;
    }
    return len;
}
 
/* EOF */

tools.h

tools.h
/* $Id$ */
 
#define MAX_LINE_LEN 1024
 
uint16_t str_len(uint8_t * str);
uint8_t * str_trim(uint8_t * str, uint8_t c);
 
int32_t int_power(uint8_t n, uint8_t s);
int32_t str_geti(uint8_t * str);
uint8_t int_gets(int32_t num, uint8_t *str, uint8_t str_len, int16_t base);
 
/* EOF */