voltmeter
diff voltmeter.c @ 0:d26d73ef2db7
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 27 Jan 2013 10:11:40 +0200 |
parents | |
children | 40b150fedb0e |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/voltmeter.c Sun Jan 27 10:11:40 2013 +0200 1.3 @@ -0,0 +1,252 @@ 1.4 +#define F_CLK 1000000 1.5 +#define F_CPU 1000000 1.6 + 1.7 +#include <stdio.h> 1.8 +#include <avr/io.h> 1.9 +#include <util/delay.h> 1.10 + 1.11 +/* hardware setup 1.12 + * - PORT D: data bits 1.13 + * - PORT C 1.14 + * bit 0: RS 1.15 + * bit 1: R/W 1.16 + * bit 2: E 1.17 + */ 1.18 + 1.19 +#define BIT_RS 3 1.20 +#define BIT_RW 4 1.21 +#define BIT_E 5 1.22 + 1.23 +#define CMD_CLEAR 1 1.24 +#define CMD_RET (1 << 1) 1.25 +#define CMD_ENTRY_MODE (1 << 2) 1.26 +#define CMD_ONOFF (1 << 3) 1.27 +#define CMD_SHIFT (1 << 4) 1.28 +#define CMD_FUNC (1 << 5) 1.29 +#define CMD_CGRAM_ADDR (1 << 6) 1.30 +#define CMD_DDRAM_ADDR (1 << 7) 1.31 + 1.32 +#define FUNC_BUS_4BIT 0 1.33 +#define FUNC_BUS_8BIT (1 << 4) 1.34 +#define FUNC_LINES_1 0 1.35 +#define FUNC_LINES_2 (1 << 3) 1.36 +#define FUNC_FONT_5x8 0 1.37 +#define FUNC_FONT_5x11 (1 << 2) 1.38 + 1.39 +#define ONOFF_DISP (1 << 2) 1.40 +#define ONOFF_CURSOR (1 << 1) 1.41 +#define ONOFF_CURSOR_POS 1 1.42 + 1.43 +void setup_adc(void); 1.44 +long read_adc(void); 1.45 + 1.46 +void lcd_init(void); 1.47 +void lcd_clear(void); 1.48 +void lcd_set_cursor_addr(unsigned int addr); 1.49 +void lcd_putchar(char c); 1.50 +void lcd_putstr(const char *str); 1.51 +int lcd_stream_write(char c, FILE *fp); 1.52 +void lcd_wait_busy(void); 1.53 +static void enable(void); 1.54 +static void set_bit(int bit); 1.55 +static void clear_bit(int bit); 1.56 +void delay(int x); 1.57 + 1.58 +#define NSDELAY() asm volatile ("nop") 1.59 +#define DEBUG(i) (PORTB = (1 << (i))) 1.60 + 1.61 +FILE stream_lcd = FDEV_SETUP_STREAM(lcd_stream_write, NULL, _FDEV_SETUP_WRITE); 1.62 + 1.63 +int main(void) 1.64 +{ 1.65 + stdout = stderr = &stream_lcd; 1.66 + 1.67 + DDRC = 0xfe; 1.68 + PORTC = 0; /* disable pullups */ 1.69 + 1.70 + lcd_init(); 1.71 + lcd_clear(); 1.72 + 1.73 + printf("initializing..."); 1.74 + setup_adc(); 1.75 + 1.76 + for(;;) { 1.77 + long val = read_adc(); 1.78 + double ref = 1.08 * 1.47 / 0.47; 1.79 + double voltage = ref * (double)val / (double)1024; 1.80 + lcd_clear(); 1.81 + 1.82 + if(val == 1023) { 1.83 + printf("*** RANGE *** "); 1.84 + } else { 1.85 + printf("%.2f volts ", voltage); 1.86 + } 1.87 + _delay_ms(500); 1.88 + } 1.89 + return 0; 1.90 +} 1.91 + 1.92 +void setup_adc(void) 1.93 +{ 1.94 + /* disable digital input buffer on ADC0 pin */ 1.95 + DIDR0 = 1; 1.96 + 1.97 + /* use the internal bandgap as a reference */ 1.98 + ADMUX = 3 << REFS0; 1.99 + 1.100 + /* - enable ADC 1.101 + * - set ADC clock prescaler to clock / 8 1.102 + */ 1.103 + ADCSRA = (1 << ADEN) | (3 << ADPS0); 1.104 +} 1.105 + 1.106 +long read_adc(void) 1.107 +{ 1.108 + long low; 1.109 + 1.110 + /* start conversion */ 1.111 + ADCSRA |= (1 << ADSC); 1.112 + 1.113 + /* wait while converting */ 1.114 + while(ADCSRA & (1 << ADSC)); 1.115 + 1.116 + low = ADCL; 1.117 + return low | ((long)ADCH << 8); 1.118 +} 1.119 + 1.120 +void lcd_init(void) 1.121 +{ 1.122 + DDRD = 0x0f; /* port d[0, 3] -> output */ 1.123 + 1.124 + /* make sure the display has time to boot up */ 1.125 + _delay_ms(20); 1.126 + 1.127 + clear_bit(BIT_RW); 1.128 + 1.129 + clear_bit(BIT_E); 1.130 + clear_bit(BIT_RS); 1.131 + PORTD = CMD_FUNC | FUNC_BUS_8BIT | FUNC_LINES_2 | FUNC_FONT_5x8; 1.132 + enable(); 1.133 + lcd_wait_busy(); 1.134 + 1.135 + clear_bit(BIT_RS); 1.136 + PORTD = CMD_ONOFF | ONOFF_DISP | ONOFF_CURSOR; 1.137 + enable(); 1.138 + lcd_wait_busy(); 1.139 + 1.140 + clear_bit(BIT_RS); 1.141 + PORTD = CMD_ENTRY_MODE | (1 << 1); 1.142 + enable(); 1.143 + lcd_wait_busy(); 1.144 +} 1.145 + 1.146 +void lcd_clear(void) 1.147 +{ 1.148 + DDRD = 0xff; /* port d -> output */ 1.149 + 1.150 + clear_bit(BIT_RW); 1.151 + 1.152 + clear_bit(BIT_E); 1.153 + clear_bit(BIT_RS); 1.154 + PORTD = CMD_CLEAR; 1.155 + enable(); 1.156 + lcd_wait_busy(); 1.157 +} 1.158 + 1.159 +void lcd_set_cursor_addr(unsigned int addr) 1.160 +{ 1.161 + DDRD = 0xff; /* port d -> output */ 1.162 + 1.163 + clear_bit(BIT_RW); 1.164 + 1.165 + clear_bit(BIT_E); 1.166 + clear_bit(BIT_RS); 1.167 + PORTD = CMD_DDRAM_ADDR | addr; 1.168 + enable(); 1.169 + lcd_wait_busy(); 1.170 +} 1.171 + 1.172 +void lcd_putchar(char c) 1.173 +{ 1.174 + DDRD = 0xff; /* port d -> output */ 1.175 + 1.176 + clear_bit(BIT_RW); 1.177 + 1.178 + set_bit(BIT_RS); 1.179 + PORTD = c; 1.180 + enable(); 1.181 + lcd_wait_busy(); 1.182 +} 1.183 + 1.184 +void lcd_putstr(const char *str) 1.185 +{ 1.186 + while(*str) { 1.187 + lcd_putchar(*str++); 1.188 + } 1.189 +} 1.190 + 1.191 +int lcd_stream_write(char c, FILE *fp) 1.192 +{ 1.193 + /* TODO terminal shit handling */ 1.194 + lcd_putchar(c); 1.195 + return 0; 1.196 +} 1.197 + 1.198 +void lcd_wait_busy(void) 1.199 +{ 1.200 + unsigned char data; 1.201 + 1.202 + DDRD = 0; /* port d -> input */ 1.203 + PORTD = 0; /* disable pull-ups */ 1.204 + 1.205 + do { 1.206 + NSDELAY(); 1.207 + clear_bit(BIT_E); 1.208 + clear_bit(BIT_RS); 1.209 + set_bit(BIT_RW); 1.210 + /*PIND = 0xff;*/ 1.211 + 1.212 + NSDELAY(); 1.213 + set_bit(BIT_E); 1.214 + NSDELAY(); 1.215 + data = PIND; 1.216 + clear_bit(BIT_E); 1.217 + clear_bit(BIT_RW); 1.218 + 1.219 + } while(data & (1 << 7)); 1.220 + 1.221 + DDRD = 0xff; /* port d -> output */ 1.222 +} 1.223 + 1.224 +static void enable(void) 1.225 +{ 1.226 + NSDELAY(); 1.227 + set_bit(BIT_E); 1.228 + NSDELAY(); 1.229 + clear_bit(BIT_E); 1.230 + NSDELAY(); 1.231 +} 1.232 + 1.233 +static void set_bit(int bit) 1.234 +{ 1.235 + PORTC |= 1 << bit; 1.236 +} 1.237 + 1.238 +static void clear_bit(int bit) 1.239 +{ 1.240 + PORTC &= ~(1 << bit); 1.241 +} 1.242 + 1.243 + 1.244 +void delay(int x) 1.245 +{ 1.246 + int i, j; 1.247 + 1.248 + while(x-- > 0) { 1.249 + for(i=0; i<90; i++) { 1.250 + for(j=0; j<6; j++) { 1.251 + asm volatile("nop"); 1.252 + } 1.253 + } 1.254 + } 1.255 +}