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 }