# HG changeset patch # User John Tsiombikas # Date 1359274300 -7200 # Node ID d26d73ef2db7394fda0904d5dd40c6cca0cd6bb3 initial commit diff -r 000000000000 -r d26d73ef2db7 Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Sun Jan 27 10:11:40 2013 +0200 @@ -0,0 +1,34 @@ +src = $(wildcard *.c) +obj = $(src:.c=.o) +bin = voltmeter +hex = $(bin).hex +eep = $(bin).eep + +mcu_gcc = atmega168 +mcu_dude = m168 + +CC = avr-gcc +OBJCOPY = avr-objcopy + +CFLAGS = -O2 -pedantic -Wall -mmcu=$(mcu_gcc) +LDFLAGS = -Wl,-Map,$(bin).map -mmcu=$(mcu_gcc) -Wl,-u,vfprintf -lprintf_flt -lm + +.PHONY: all +all: $(hex) $(eep) + +$(bin): $(obj) + $(CC) -o $@ $(obj) $(LDFLAGS) + +$(hex): $(bin) + $(OBJCOPY) -j .text -j .data -O ihex -R .eeprom $< $@ + +$(eep): $(bin) + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ + +.PHONY: program +program: $(hex) + avrdude -c usbtiny -p $(mcu_dude) -e -U flash:w:$(hex) + +.PHONY: clean +clean: + rm -f $(bin) $(obj) $(hex) $(eep) $(bin).map diff -r 000000000000 -r d26d73ef2db7 voltmeter.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/voltmeter.c Sun Jan 27 10:11:40 2013 +0200 @@ -0,0 +1,252 @@ +#define F_CLK 1000000 +#define F_CPU 1000000 + +#include +#include +#include + +/* hardware setup + * - PORT D: data bits + * - PORT C + * bit 0: RS + * bit 1: R/W + * bit 2: E + */ + +#define BIT_RS 3 +#define BIT_RW 4 +#define BIT_E 5 + +#define CMD_CLEAR 1 +#define CMD_RET (1 << 1) +#define CMD_ENTRY_MODE (1 << 2) +#define CMD_ONOFF (1 << 3) +#define CMD_SHIFT (1 << 4) +#define CMD_FUNC (1 << 5) +#define CMD_CGRAM_ADDR (1 << 6) +#define CMD_DDRAM_ADDR (1 << 7) + +#define FUNC_BUS_4BIT 0 +#define FUNC_BUS_8BIT (1 << 4) +#define FUNC_LINES_1 0 +#define FUNC_LINES_2 (1 << 3) +#define FUNC_FONT_5x8 0 +#define FUNC_FONT_5x11 (1 << 2) + +#define ONOFF_DISP (1 << 2) +#define ONOFF_CURSOR (1 << 1) +#define ONOFF_CURSOR_POS 1 + +void setup_adc(void); +long read_adc(void); + +void lcd_init(void); +void lcd_clear(void); +void lcd_set_cursor_addr(unsigned int addr); +void lcd_putchar(char c); +void lcd_putstr(const char *str); +int lcd_stream_write(char c, FILE *fp); +void lcd_wait_busy(void); +static void enable(void); +static void set_bit(int bit); +static void clear_bit(int bit); +void delay(int x); + +#define NSDELAY() asm volatile ("nop") +#define DEBUG(i) (PORTB = (1 << (i))) + +FILE stream_lcd = FDEV_SETUP_STREAM(lcd_stream_write, NULL, _FDEV_SETUP_WRITE); + +int main(void) +{ + stdout = stderr = &stream_lcd; + + DDRC = 0xfe; + PORTC = 0; /* disable pullups */ + + lcd_init(); + lcd_clear(); + + printf("initializing..."); + setup_adc(); + + for(;;) { + long val = read_adc(); + double ref = 1.08 * 1.47 / 0.47; + double voltage = ref * (double)val / (double)1024; + lcd_clear(); + + if(val == 1023) { + printf("*** RANGE *** "); + } else { + printf("%.2f volts ", voltage); + } + _delay_ms(500); + } + return 0; +} + +void setup_adc(void) +{ + /* disable digital input buffer on ADC0 pin */ + DIDR0 = 1; + + /* use the internal bandgap as a reference */ + ADMUX = 3 << REFS0; + + /* - enable ADC + * - set ADC clock prescaler to clock / 8 + */ + ADCSRA = (1 << ADEN) | (3 << ADPS0); +} + +long read_adc(void) +{ + long low; + + /* start conversion */ + ADCSRA |= (1 << ADSC); + + /* wait while converting */ + while(ADCSRA & (1 << ADSC)); + + low = ADCL; + return low | ((long)ADCH << 8); +} + +void lcd_init(void) +{ + DDRD = 0x0f; /* port d[0, 3] -> output */ + + /* make sure the display has time to boot up */ + _delay_ms(20); + + clear_bit(BIT_RW); + + clear_bit(BIT_E); + clear_bit(BIT_RS); + PORTD = CMD_FUNC | FUNC_BUS_8BIT | FUNC_LINES_2 | FUNC_FONT_5x8; + enable(); + lcd_wait_busy(); + + clear_bit(BIT_RS); + PORTD = CMD_ONOFF | ONOFF_DISP | ONOFF_CURSOR; + enable(); + lcd_wait_busy(); + + clear_bit(BIT_RS); + PORTD = CMD_ENTRY_MODE | (1 << 1); + enable(); + lcd_wait_busy(); +} + +void lcd_clear(void) +{ + DDRD = 0xff; /* port d -> output */ + + clear_bit(BIT_RW); + + clear_bit(BIT_E); + clear_bit(BIT_RS); + PORTD = CMD_CLEAR; + enable(); + lcd_wait_busy(); +} + +void lcd_set_cursor_addr(unsigned int addr) +{ + DDRD = 0xff; /* port d -> output */ + + clear_bit(BIT_RW); + + clear_bit(BIT_E); + clear_bit(BIT_RS); + PORTD = CMD_DDRAM_ADDR | addr; + enable(); + lcd_wait_busy(); +} + +void lcd_putchar(char c) +{ + DDRD = 0xff; /* port d -> output */ + + clear_bit(BIT_RW); + + set_bit(BIT_RS); + PORTD = c; + enable(); + lcd_wait_busy(); +} + +void lcd_putstr(const char *str) +{ + while(*str) { + lcd_putchar(*str++); + } +} + +int lcd_stream_write(char c, FILE *fp) +{ + /* TODO terminal shit handling */ + lcd_putchar(c); + return 0; +} + +void lcd_wait_busy(void) +{ + unsigned char data; + + DDRD = 0; /* port d -> input */ + PORTD = 0; /* disable pull-ups */ + + do { + NSDELAY(); + clear_bit(BIT_E); + clear_bit(BIT_RS); + set_bit(BIT_RW); + /*PIND = 0xff;*/ + + NSDELAY(); + set_bit(BIT_E); + NSDELAY(); + data = PIND; + clear_bit(BIT_E); + clear_bit(BIT_RW); + + } while(data & (1 << 7)); + + DDRD = 0xff; /* port d -> output */ +} + +static void enable(void) +{ + NSDELAY(); + set_bit(BIT_E); + NSDELAY(); + clear_bit(BIT_E); + NSDELAY(); +} + +static void set_bit(int bit) +{ + PORTC |= 1 << bit; +} + +static void clear_bit(int bit) +{ + PORTC &= ~(1 << bit); +} + + +void delay(int x) +{ + int i, j; + + while(x-- > 0) { + for(i=0; i<90; i++) { + for(j=0; j<6; j++) { + asm volatile("nop"); + } + } + } +}