voltmeter
annotate voltmeter.c @ 1:40b150fedb0e
foo
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 28 Jan 2013 09:52:15 +0200 |
parents | d26d73ef2db7 |
children |
rev | line source |
---|---|
nuclear@0 | 1 #define F_CLK 1000000 |
nuclear@0 | 2 #define F_CPU 1000000 |
nuclear@0 | 3 |
nuclear@0 | 4 #include <stdio.h> |
nuclear@0 | 5 #include <avr/io.h> |
nuclear@1 | 6 #include <avr/interrupt.h> |
nuclear@0 | 7 #include <util/delay.h> |
nuclear@0 | 8 |
nuclear@0 | 9 /* hardware setup |
nuclear@0 | 10 * - PORT D: data bits |
nuclear@0 | 11 * - PORT C |
nuclear@0 | 12 * bit 0: RS |
nuclear@0 | 13 * bit 1: R/W |
nuclear@0 | 14 * bit 2: E |
nuclear@0 | 15 */ |
nuclear@1 | 16 #define LCD_BUS_WIDTH 8 |
nuclear@0 | 17 |
nuclear@0 | 18 #define BIT_RS 3 |
nuclear@0 | 19 #define BIT_RW 4 |
nuclear@0 | 20 #define BIT_E 5 |
nuclear@0 | 21 |
nuclear@0 | 22 #define CMD_CLEAR 1 |
nuclear@0 | 23 #define CMD_RET (1 << 1) |
nuclear@0 | 24 #define CMD_ENTRY_MODE (1 << 2) |
nuclear@0 | 25 #define CMD_ONOFF (1 << 3) |
nuclear@0 | 26 #define CMD_SHIFT (1 << 4) |
nuclear@0 | 27 #define CMD_FUNC (1 << 5) |
nuclear@0 | 28 #define CMD_CGRAM_ADDR (1 << 6) |
nuclear@0 | 29 #define CMD_DDRAM_ADDR (1 << 7) |
nuclear@0 | 30 |
nuclear@0 | 31 #define FUNC_BUS_4BIT 0 |
nuclear@0 | 32 #define FUNC_BUS_8BIT (1 << 4) |
nuclear@0 | 33 #define FUNC_LINES_1 0 |
nuclear@0 | 34 #define FUNC_LINES_2 (1 << 3) |
nuclear@0 | 35 #define FUNC_FONT_5x8 0 |
nuclear@0 | 36 #define FUNC_FONT_5x11 (1 << 2) |
nuclear@0 | 37 |
nuclear@0 | 38 #define ONOFF_DISP (1 << 2) |
nuclear@0 | 39 #define ONOFF_CURSOR (1 << 1) |
nuclear@0 | 40 #define ONOFF_CURSOR_POS 1 |
nuclear@0 | 41 |
nuclear@0 | 42 void setup_adc(void); |
nuclear@0 | 43 long read_adc(void); |
nuclear@0 | 44 |
nuclear@0 | 45 void lcd_init(void); |
nuclear@0 | 46 void lcd_clear(void); |
nuclear@0 | 47 void lcd_set_cursor_addr(unsigned int addr); |
nuclear@0 | 48 void lcd_putchar(char c); |
nuclear@0 | 49 void lcd_putstr(const char *str); |
nuclear@0 | 50 int lcd_stream_write(char c, FILE *fp); |
nuclear@0 | 51 void lcd_wait_busy(void); |
nuclear@0 | 52 static void enable(void); |
nuclear@0 | 53 static void set_bit(int bit); |
nuclear@0 | 54 static void clear_bit(int bit); |
nuclear@0 | 55 void delay(int x); |
nuclear@0 | 56 |
nuclear@0 | 57 #define NSDELAY() asm volatile ("nop") |
nuclear@0 | 58 #define DEBUG(i) (PORTB = (1 << (i))) |
nuclear@0 | 59 |
nuclear@0 | 60 FILE stream_lcd = FDEV_SETUP_STREAM(lcd_stream_write, NULL, _FDEV_SETUP_WRITE); |
nuclear@0 | 61 |
nuclear@1 | 62 int bn_pressed; |
nuclear@1 | 63 unsigned char foo; |
nuclear@1 | 64 |
nuclear@0 | 65 int main(void) |
nuclear@0 | 66 { |
nuclear@0 | 67 stdout = stderr = &stream_lcd; |
nuclear@0 | 68 |
nuclear@1 | 69 /* port B[0] out -> backlight |
nuclear@1 | 70 * port B[1] in <- backlight switch |
nuclear@1 | 71 */ |
nuclear@1 | 72 DDRB = 1; |
nuclear@1 | 73 PORTB = 0xfe; /* enable all pullups, leave bit0 -> 0 (backlight) */ |
nuclear@1 | 74 /* enable PIN B1 interrupt */ |
nuclear@1 | 75 PCMSK0 = 2; |
nuclear@1 | 76 PCICR = 1; |
nuclear@1 | 77 sei(); /* enable interrupts */ |
nuclear@1 | 78 |
nuclear@0 | 79 DDRC = 0xfe; |
nuclear@0 | 80 PORTC = 0; /* disable pullups */ |
nuclear@0 | 81 |
nuclear@0 | 82 lcd_init(); |
nuclear@0 | 83 lcd_clear(); |
nuclear@0 | 84 |
nuclear@0 | 85 printf("initializing..."); |
nuclear@0 | 86 setup_adc(); |
nuclear@0 | 87 |
nuclear@0 | 88 for(;;) { |
nuclear@0 | 89 long val = read_adc(); |
nuclear@0 | 90 double ref = 1.08 * 1.47 / 0.47; |
nuclear@0 | 91 double voltage = ref * (double)val / (double)1024; |
nuclear@1 | 92 |
nuclear@0 | 93 lcd_clear(); |
nuclear@0 | 94 |
nuclear@0 | 95 if(val == 1023) { |
nuclear@1 | 96 printf("*** RANGE ***"); |
nuclear@0 | 97 } else { |
nuclear@1 | 98 printf("%.2f volts", voltage); |
nuclear@1 | 99 } |
nuclear@1 | 100 |
nuclear@1 | 101 /* check if the backlight button was pressed */ |
nuclear@1 | 102 if(bn_pressed & 1) { |
nuclear@1 | 103 if(PORTB & 1) { |
nuclear@1 | 104 PORTB &= 0xfe; |
nuclear@1 | 105 } else { |
nuclear@1 | 106 PORTB |= 1; |
nuclear@1 | 107 } |
nuclear@1 | 108 bn_pressed = 0; |
nuclear@0 | 109 } |
nuclear@0 | 110 _delay_ms(500); |
nuclear@0 | 111 } |
nuclear@0 | 112 return 0; |
nuclear@0 | 113 } |
nuclear@0 | 114 |
nuclear@1 | 115 |
nuclear@1 | 116 ISR(PCINT0_vect) { |
nuclear@1 | 117 if((PINB & 2) == 0) { |
nuclear@1 | 118 bn_pressed = 1; |
nuclear@1 | 119 } |
nuclear@1 | 120 } |
nuclear@1 | 121 |
nuclear@0 | 122 void setup_adc(void) |
nuclear@0 | 123 { |
nuclear@0 | 124 /* disable digital input buffer on ADC0 pin */ |
nuclear@0 | 125 DIDR0 = 1; |
nuclear@0 | 126 |
nuclear@0 | 127 /* use the internal bandgap as a reference */ |
nuclear@0 | 128 ADMUX = 3 << REFS0; |
nuclear@0 | 129 |
nuclear@0 | 130 /* - enable ADC |
nuclear@0 | 131 * - set ADC clock prescaler to clock / 8 |
nuclear@0 | 132 */ |
nuclear@0 | 133 ADCSRA = (1 << ADEN) | (3 << ADPS0); |
nuclear@0 | 134 } |
nuclear@0 | 135 |
nuclear@0 | 136 long read_adc(void) |
nuclear@0 | 137 { |
nuclear@0 | 138 long low; |
nuclear@0 | 139 |
nuclear@0 | 140 /* start conversion */ |
nuclear@0 | 141 ADCSRA |= (1 << ADSC); |
nuclear@0 | 142 |
nuclear@0 | 143 /* wait while converting */ |
nuclear@0 | 144 while(ADCSRA & (1 << ADSC)); |
nuclear@0 | 145 |
nuclear@0 | 146 low = ADCL; |
nuclear@0 | 147 return low | ((long)ADCH << 8); |
nuclear@0 | 148 } |
nuclear@0 | 149 |
nuclear@1 | 150 void lcd_write_byte(unsigned char byte) |
nuclear@1 | 151 { |
nuclear@1 | 152 #if LCD_BUS_WIDTH == 8 |
nuclear@1 | 153 DDRD = 0xff; |
nuclear@1 | 154 PORTD = byte; |
nuclear@1 | 155 #else |
nuclear@1 | 156 DDRD = (DDRD & 0xf0) | 0xf; |
nuclear@1 | 157 |
nuclear@1 | 158 PORTD = (PORTD & 0xf0) | ((byte >> 4) & 0xf); |
nuclear@1 | 159 PORTD = (PORTD & 0xf0) | (byte & 0xf); |
nuclear@1 | 160 #endif |
nuclear@1 | 161 } |
nuclear@1 | 162 |
nuclear@1 | 163 unsigned char lcd_read_byte(void) |
nuclear@1 | 164 { |
nuclear@1 | 165 #if LCD_BUS_WIDTH == 8 |
nuclear@1 | 166 DDRD = 0; |
nuclear@1 | 167 PORTD = 0; /* disable pull-ups */ |
nuclear@1 | 168 |
nuclear@1 | 169 return PIND; |
nuclear@1 | 170 #else |
nuclear@1 | 171 unsigned char byte; |
nuclear@1 | 172 |
nuclear@1 | 173 DDRD = DDRD & 0xf0; |
nuclear@1 | 174 PORTD &= 0xf0; /* disable pull-ups */ |
nuclear@1 | 175 |
nuclear@1 | 176 byte = (PIND & 0xf) << 4; |
nuclear@1 | 177 return byte | (PIND & 0xf); |
nuclear@1 | 178 #endif |
nuclear@1 | 179 } |
nuclear@1 | 180 |
nuclear@0 | 181 void lcd_init(void) |
nuclear@0 | 182 { |
nuclear@0 | 183 /* make sure the display has time to boot up */ |
nuclear@0 | 184 _delay_ms(20); |
nuclear@0 | 185 |
nuclear@0 | 186 clear_bit(BIT_RW); |
nuclear@0 | 187 |
nuclear@0 | 188 clear_bit(BIT_E); |
nuclear@0 | 189 clear_bit(BIT_RS); |
nuclear@1 | 190 #if LCD_BUS_WIDTH == 8 |
nuclear@1 | 191 lcd_write_byte(CMD_FUNC | FUNC_BUS_8BIT | FUNC_LINES_2 | FUNC_FONT_5x8); |
nuclear@1 | 192 #else |
nuclear@1 | 193 lcd_write_byte(CMD_FUNC | FUNC_BUS_4BIT | FUNC_LINES_2 | FUNC_FONT_5x8); |
nuclear@1 | 194 #endif |
nuclear@0 | 195 enable(); |
nuclear@0 | 196 lcd_wait_busy(); |
nuclear@0 | 197 |
nuclear@0 | 198 clear_bit(BIT_RS); |
nuclear@1 | 199 lcd_write_byte(CMD_ONOFF | ONOFF_DISP); |
nuclear@0 | 200 enable(); |
nuclear@0 | 201 lcd_wait_busy(); |
nuclear@0 | 202 |
nuclear@0 | 203 clear_bit(BIT_RS); |
nuclear@1 | 204 lcd_write_byte(CMD_ENTRY_MODE | (1 << 1)); |
nuclear@0 | 205 enable(); |
nuclear@0 | 206 lcd_wait_busy(); |
nuclear@0 | 207 } |
nuclear@0 | 208 |
nuclear@0 | 209 void lcd_clear(void) |
nuclear@0 | 210 { |
nuclear@0 | 211 clear_bit(BIT_RW); |
nuclear@0 | 212 |
nuclear@0 | 213 clear_bit(BIT_E); |
nuclear@0 | 214 clear_bit(BIT_RS); |
nuclear@1 | 215 lcd_write_byte(CMD_CLEAR); |
nuclear@0 | 216 enable(); |
nuclear@0 | 217 lcd_wait_busy(); |
nuclear@0 | 218 } |
nuclear@0 | 219 |
nuclear@0 | 220 void lcd_set_cursor_addr(unsigned int addr) |
nuclear@0 | 221 { |
nuclear@0 | 222 clear_bit(BIT_RW); |
nuclear@0 | 223 |
nuclear@0 | 224 clear_bit(BIT_E); |
nuclear@0 | 225 clear_bit(BIT_RS); |
nuclear@1 | 226 lcd_write_byte(CMD_DDRAM_ADDR | addr); |
nuclear@0 | 227 enable(); |
nuclear@0 | 228 lcd_wait_busy(); |
nuclear@0 | 229 } |
nuclear@0 | 230 |
nuclear@0 | 231 void lcd_putchar(char c) |
nuclear@0 | 232 { |
nuclear@0 | 233 clear_bit(BIT_RW); |
nuclear@0 | 234 |
nuclear@0 | 235 set_bit(BIT_RS); |
nuclear@1 | 236 lcd_write_byte(c); |
nuclear@0 | 237 enable(); |
nuclear@0 | 238 lcd_wait_busy(); |
nuclear@0 | 239 } |
nuclear@0 | 240 |
nuclear@0 | 241 void lcd_putstr(const char *str) |
nuclear@0 | 242 { |
nuclear@0 | 243 while(*str) { |
nuclear@0 | 244 lcd_putchar(*str++); |
nuclear@0 | 245 } |
nuclear@0 | 246 } |
nuclear@0 | 247 |
nuclear@0 | 248 int lcd_stream_write(char c, FILE *fp) |
nuclear@0 | 249 { |
nuclear@0 | 250 /* TODO terminal shit handling */ |
nuclear@0 | 251 lcd_putchar(c); |
nuclear@0 | 252 return 0; |
nuclear@0 | 253 } |
nuclear@0 | 254 |
nuclear@0 | 255 void lcd_wait_busy(void) |
nuclear@0 | 256 { |
nuclear@0 | 257 unsigned char data; |
nuclear@0 | 258 |
nuclear@0 | 259 do { |
nuclear@0 | 260 NSDELAY(); |
nuclear@0 | 261 clear_bit(BIT_E); |
nuclear@0 | 262 clear_bit(BIT_RS); |
nuclear@0 | 263 set_bit(BIT_RW); |
nuclear@0 | 264 /*PIND = 0xff;*/ |
nuclear@0 | 265 |
nuclear@0 | 266 NSDELAY(); |
nuclear@0 | 267 set_bit(BIT_E); |
nuclear@0 | 268 NSDELAY(); |
nuclear@1 | 269 data = lcd_read_byte(); |
nuclear@0 | 270 clear_bit(BIT_E); |
nuclear@0 | 271 clear_bit(BIT_RW); |
nuclear@0 | 272 |
nuclear@0 | 273 } while(data & (1 << 7)); |
nuclear@0 | 274 } |
nuclear@0 | 275 |
nuclear@0 | 276 static void enable(void) |
nuclear@0 | 277 { |
nuclear@0 | 278 NSDELAY(); |
nuclear@0 | 279 set_bit(BIT_E); |
nuclear@0 | 280 NSDELAY(); |
nuclear@0 | 281 clear_bit(BIT_E); |
nuclear@0 | 282 NSDELAY(); |
nuclear@0 | 283 } |
nuclear@0 | 284 |
nuclear@0 | 285 static void set_bit(int bit) |
nuclear@0 | 286 { |
nuclear@0 | 287 PORTC |= 1 << bit; |
nuclear@0 | 288 } |
nuclear@0 | 289 |
nuclear@0 | 290 static void clear_bit(int bit) |
nuclear@0 | 291 { |
nuclear@0 | 292 PORTC &= ~(1 << bit); |
nuclear@0 | 293 } |
nuclear@0 | 294 |
nuclear@0 | 295 |
nuclear@0 | 296 void delay(int x) |
nuclear@0 | 297 { |
nuclear@0 | 298 int i, j; |
nuclear@0 | 299 |
nuclear@0 | 300 while(x-- > 0) { |
nuclear@0 | 301 for(i=0; i<90; i++) { |
nuclear@0 | 302 for(j=0; j<6; j++) { |
nuclear@0 | 303 asm volatile("nop"); |
nuclear@0 | 304 } |
nuclear@0 | 305 } |
nuclear@0 | 306 } |
nuclear@0 | 307 } |