voltmeter

annotate 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
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@0 6 #include <util/delay.h>
nuclear@0 7
nuclear@0 8 /* hardware setup
nuclear@0 9 * - PORT D: data bits
nuclear@0 10 * - PORT C
nuclear@0 11 * bit 0: RS
nuclear@0 12 * bit 1: R/W
nuclear@0 13 * bit 2: E
nuclear@0 14 */
nuclear@0 15
nuclear@0 16 #define BIT_RS 3
nuclear@0 17 #define BIT_RW 4
nuclear@0 18 #define BIT_E 5
nuclear@0 19
nuclear@0 20 #define CMD_CLEAR 1
nuclear@0 21 #define CMD_RET (1 << 1)
nuclear@0 22 #define CMD_ENTRY_MODE (1 << 2)
nuclear@0 23 #define CMD_ONOFF (1 << 3)
nuclear@0 24 #define CMD_SHIFT (1 << 4)
nuclear@0 25 #define CMD_FUNC (1 << 5)
nuclear@0 26 #define CMD_CGRAM_ADDR (1 << 6)
nuclear@0 27 #define CMD_DDRAM_ADDR (1 << 7)
nuclear@0 28
nuclear@0 29 #define FUNC_BUS_4BIT 0
nuclear@0 30 #define FUNC_BUS_8BIT (1 << 4)
nuclear@0 31 #define FUNC_LINES_1 0
nuclear@0 32 #define FUNC_LINES_2 (1 << 3)
nuclear@0 33 #define FUNC_FONT_5x8 0
nuclear@0 34 #define FUNC_FONT_5x11 (1 << 2)
nuclear@0 35
nuclear@0 36 #define ONOFF_DISP (1 << 2)
nuclear@0 37 #define ONOFF_CURSOR (1 << 1)
nuclear@0 38 #define ONOFF_CURSOR_POS 1
nuclear@0 39
nuclear@0 40 void setup_adc(void);
nuclear@0 41 long read_adc(void);
nuclear@0 42
nuclear@0 43 void lcd_init(void);
nuclear@0 44 void lcd_clear(void);
nuclear@0 45 void lcd_set_cursor_addr(unsigned int addr);
nuclear@0 46 void lcd_putchar(char c);
nuclear@0 47 void lcd_putstr(const char *str);
nuclear@0 48 int lcd_stream_write(char c, FILE *fp);
nuclear@0 49 void lcd_wait_busy(void);
nuclear@0 50 static void enable(void);
nuclear@0 51 static void set_bit(int bit);
nuclear@0 52 static void clear_bit(int bit);
nuclear@0 53 void delay(int x);
nuclear@0 54
nuclear@0 55 #define NSDELAY() asm volatile ("nop")
nuclear@0 56 #define DEBUG(i) (PORTB = (1 << (i)))
nuclear@0 57
nuclear@0 58 FILE stream_lcd = FDEV_SETUP_STREAM(lcd_stream_write, NULL, _FDEV_SETUP_WRITE);
nuclear@0 59
nuclear@0 60 int main(void)
nuclear@0 61 {
nuclear@0 62 stdout = stderr = &stream_lcd;
nuclear@0 63
nuclear@0 64 DDRC = 0xfe;
nuclear@0 65 PORTC = 0; /* disable pullups */
nuclear@0 66
nuclear@0 67 lcd_init();
nuclear@0 68 lcd_clear();
nuclear@0 69
nuclear@0 70 printf("initializing...");
nuclear@0 71 setup_adc();
nuclear@0 72
nuclear@0 73 for(;;) {
nuclear@0 74 long val = read_adc();
nuclear@0 75 double ref = 1.08 * 1.47 / 0.47;
nuclear@0 76 double voltage = ref * (double)val / (double)1024;
nuclear@0 77 lcd_clear();
nuclear@0 78
nuclear@0 79 if(val == 1023) {
nuclear@0 80 printf("*** RANGE *** ");
nuclear@0 81 } else {
nuclear@0 82 printf("%.2f volts ", voltage);
nuclear@0 83 }
nuclear@0 84 _delay_ms(500);
nuclear@0 85 }
nuclear@0 86 return 0;
nuclear@0 87 }
nuclear@0 88
nuclear@0 89 void setup_adc(void)
nuclear@0 90 {
nuclear@0 91 /* disable digital input buffer on ADC0 pin */
nuclear@0 92 DIDR0 = 1;
nuclear@0 93
nuclear@0 94 /* use the internal bandgap as a reference */
nuclear@0 95 ADMUX = 3 << REFS0;
nuclear@0 96
nuclear@0 97 /* - enable ADC
nuclear@0 98 * - set ADC clock prescaler to clock / 8
nuclear@0 99 */
nuclear@0 100 ADCSRA = (1 << ADEN) | (3 << ADPS0);
nuclear@0 101 }
nuclear@0 102
nuclear@0 103 long read_adc(void)
nuclear@0 104 {
nuclear@0 105 long low;
nuclear@0 106
nuclear@0 107 /* start conversion */
nuclear@0 108 ADCSRA |= (1 << ADSC);
nuclear@0 109
nuclear@0 110 /* wait while converting */
nuclear@0 111 while(ADCSRA & (1 << ADSC));
nuclear@0 112
nuclear@0 113 low = ADCL;
nuclear@0 114 return low | ((long)ADCH << 8);
nuclear@0 115 }
nuclear@0 116
nuclear@0 117 void lcd_init(void)
nuclear@0 118 {
nuclear@0 119 DDRD = 0x0f; /* port d[0, 3] -> output */
nuclear@0 120
nuclear@0 121 /* make sure the display has time to boot up */
nuclear@0 122 _delay_ms(20);
nuclear@0 123
nuclear@0 124 clear_bit(BIT_RW);
nuclear@0 125
nuclear@0 126 clear_bit(BIT_E);
nuclear@0 127 clear_bit(BIT_RS);
nuclear@0 128 PORTD = CMD_FUNC | FUNC_BUS_8BIT | FUNC_LINES_2 | FUNC_FONT_5x8;
nuclear@0 129 enable();
nuclear@0 130 lcd_wait_busy();
nuclear@0 131
nuclear@0 132 clear_bit(BIT_RS);
nuclear@0 133 PORTD = CMD_ONOFF | ONOFF_DISP | ONOFF_CURSOR;
nuclear@0 134 enable();
nuclear@0 135 lcd_wait_busy();
nuclear@0 136
nuclear@0 137 clear_bit(BIT_RS);
nuclear@0 138 PORTD = CMD_ENTRY_MODE | (1 << 1);
nuclear@0 139 enable();
nuclear@0 140 lcd_wait_busy();
nuclear@0 141 }
nuclear@0 142
nuclear@0 143 void lcd_clear(void)
nuclear@0 144 {
nuclear@0 145 DDRD = 0xff; /* port d -> output */
nuclear@0 146
nuclear@0 147 clear_bit(BIT_RW);
nuclear@0 148
nuclear@0 149 clear_bit(BIT_E);
nuclear@0 150 clear_bit(BIT_RS);
nuclear@0 151 PORTD = CMD_CLEAR;
nuclear@0 152 enable();
nuclear@0 153 lcd_wait_busy();
nuclear@0 154 }
nuclear@0 155
nuclear@0 156 void lcd_set_cursor_addr(unsigned int addr)
nuclear@0 157 {
nuclear@0 158 DDRD = 0xff; /* port d -> output */
nuclear@0 159
nuclear@0 160 clear_bit(BIT_RW);
nuclear@0 161
nuclear@0 162 clear_bit(BIT_E);
nuclear@0 163 clear_bit(BIT_RS);
nuclear@0 164 PORTD = CMD_DDRAM_ADDR | addr;
nuclear@0 165 enable();
nuclear@0 166 lcd_wait_busy();
nuclear@0 167 }
nuclear@0 168
nuclear@0 169 void lcd_putchar(char c)
nuclear@0 170 {
nuclear@0 171 DDRD = 0xff; /* port d -> output */
nuclear@0 172
nuclear@0 173 clear_bit(BIT_RW);
nuclear@0 174
nuclear@0 175 set_bit(BIT_RS);
nuclear@0 176 PORTD = c;
nuclear@0 177 enable();
nuclear@0 178 lcd_wait_busy();
nuclear@0 179 }
nuclear@0 180
nuclear@0 181 void lcd_putstr(const char *str)
nuclear@0 182 {
nuclear@0 183 while(*str) {
nuclear@0 184 lcd_putchar(*str++);
nuclear@0 185 }
nuclear@0 186 }
nuclear@0 187
nuclear@0 188 int lcd_stream_write(char c, FILE *fp)
nuclear@0 189 {
nuclear@0 190 /* TODO terminal shit handling */
nuclear@0 191 lcd_putchar(c);
nuclear@0 192 return 0;
nuclear@0 193 }
nuclear@0 194
nuclear@0 195 void lcd_wait_busy(void)
nuclear@0 196 {
nuclear@0 197 unsigned char data;
nuclear@0 198
nuclear@0 199 DDRD = 0; /* port d -> input */
nuclear@0 200 PORTD = 0; /* disable pull-ups */
nuclear@0 201
nuclear@0 202 do {
nuclear@0 203 NSDELAY();
nuclear@0 204 clear_bit(BIT_E);
nuclear@0 205 clear_bit(BIT_RS);
nuclear@0 206 set_bit(BIT_RW);
nuclear@0 207 /*PIND = 0xff;*/
nuclear@0 208
nuclear@0 209 NSDELAY();
nuclear@0 210 set_bit(BIT_E);
nuclear@0 211 NSDELAY();
nuclear@0 212 data = PIND;
nuclear@0 213 clear_bit(BIT_E);
nuclear@0 214 clear_bit(BIT_RW);
nuclear@0 215
nuclear@0 216 } while(data & (1 << 7));
nuclear@0 217
nuclear@0 218 DDRD = 0xff; /* port d -> output */
nuclear@0 219 }
nuclear@0 220
nuclear@0 221 static void enable(void)
nuclear@0 222 {
nuclear@0 223 NSDELAY();
nuclear@0 224 set_bit(BIT_E);
nuclear@0 225 NSDELAY();
nuclear@0 226 clear_bit(BIT_E);
nuclear@0 227 NSDELAY();
nuclear@0 228 }
nuclear@0 229
nuclear@0 230 static void set_bit(int bit)
nuclear@0 231 {
nuclear@0 232 PORTC |= 1 << bit;
nuclear@0 233 }
nuclear@0 234
nuclear@0 235 static void clear_bit(int bit)
nuclear@0 236 {
nuclear@0 237 PORTC &= ~(1 << bit);
nuclear@0 238 }
nuclear@0 239
nuclear@0 240
nuclear@0 241 void delay(int x)
nuclear@0 242 {
nuclear@0 243 int i, j;
nuclear@0 244
nuclear@0 245 while(x-- > 0) {
nuclear@0 246 for(i=0; i<90; i++) {
nuclear@0 247 for(j=0; j<6; j++) {
nuclear@0 248 asm volatile("nop");
nuclear@0 249 }
nuclear@0 250 }
nuclear@0 251 }
nuclear@0 252 }