pwcdecode

annotate pwcdecode.c @ 1:4ea5d2920f89

made the timing more accurate
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 01 Nov 2013 21:33:14 +0200
parents 050c04723d37
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@0 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 3: RS
nuclear@0 13 * bit 4: R/W
nuclear@0 14 * bit 5: E
nuclear@0 15 */
nuclear@0 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 lcd_init(void);
nuclear@0 43 void lcd_clear(void);
nuclear@0 44 void lcd_set_cursor_addr(unsigned int addr);
nuclear@0 45 void lcd_putchar(char c);
nuclear@0 46 void lcd_putstr(const char *str);
nuclear@0 47 int lcd_stream_write(char c, FILE *fp);
nuclear@0 48 void lcd_wait_busy(void);
nuclear@0 49 static void enable(void);
nuclear@0 50 static void set_bit(int bit);
nuclear@0 51 static void clear_bit(int bit);
nuclear@0 52 void delay(int x);
nuclear@0 53
nuclear@0 54 #define NSDELAY() asm volatile ("nop")
nuclear@0 55 #define DEBUG(i) (PORTB = (1 << (i)))
nuclear@0 56
nuclear@0 57 FILE stream_lcd = FDEV_SETUP_STREAM(lcd_stream_write, NULL, _FDEV_SETUP_WRITE);
nuclear@0 58
nuclear@0 59 unsigned int pulse_time;
nuclear@0 60
nuclear@0 61 int main(void)
nuclear@0 62 {
nuclear@0 63 stdout = stderr = &stream_lcd;
nuclear@0 64
nuclear@0 65 DDRB = 0; /* set port B as input (bit 0 is used to measure pulse width) */
nuclear@0 66 PORTB = 0; /* disable pullups */
nuclear@0 67
nuclear@0 68 DDRD = 0xff;
nuclear@0 69 DDRC = 0xfe;
nuclear@0 70 PORTC = 0; /* disable pullups */
nuclear@0 71
nuclear@0 72 lcd_init();
nuclear@0 73 lcd_clear();
nuclear@0 74
nuclear@0 75 printf("initializing...");
nuclear@0 76
nuclear@0 77 TCCR1B |= (1 << ICES1); /* set first capture to occur on a rising edge */
nuclear@1 78 TCCR1B = (TCCR1B & 0xf8) | 2; /* /8 prescaling */
nuclear@0 79 TIMSK1 |= (1 << ICIE1); /* enable timer1 input capture interrupt */
nuclear@0 80 sei();
nuclear@0 81
nuclear@0 82 for(;;) {
nuclear@0 83 lcd_set_cursor_addr(0);
nuclear@0 84 printf("pulse time: %u us ", pulse_time);
nuclear@0 85 lcd_set_cursor_addr(64);
nuclear@1 86 printf("pos: %u %% ", (pulse_time - 1000) / 10);
nuclear@0 87 _delay_ms(100);
nuclear@0 88 }
nuclear@0 89 return 0;
nuclear@0 90 }
nuclear@0 91
nuclear@0 92 ISR(TIMER1_CAPT_vect)
nuclear@0 93 {
nuclear@0 94 static int rising;
nuclear@1 95 static unsigned int start_time;
nuclear@0 96
nuclear@0 97 rising = !rising;
nuclear@0 98 if(rising) {
nuclear@1 99 /* start counting ... */
nuclear@1 100 start_time = ICR1;
nuclear@0 101 /* and set a falling edge trigger */
nuclear@0 102 TCCR1B &= ~(1 << ICES1);
nuclear@0 103 } else {
nuclear@0 104 /* falling edge: calculate the time since the last rise */
nuclear@1 105 pulse_time = (ICR1 - start_time) * 8; /* 8x to cancel out prescaling */
nuclear@0 106 /* and set a rising edge trigger */
nuclear@0 107 TCCR1B |= 1 << ICES1;
nuclear@1 108
nuclear@1 109 /* also clear the timer so it won't overflow */
nuclear@1 110 TCNT1 = 0;
nuclear@0 111 }
nuclear@0 112 }
nuclear@0 113
nuclear@0 114 void lcd_write_byte(unsigned char byte)
nuclear@0 115 {
nuclear@0 116 #if LCD_BUS_WIDTH == 8
nuclear@0 117 DDRD = 0xff;
nuclear@0 118 PORTD = byte;
nuclear@0 119 #else
nuclear@0 120 DDRD = (DDRD & 0xf0) | 0xf;
nuclear@0 121
nuclear@0 122 PORTD = (PORTD & 0xf0) | ((byte >> 4) & 0xf);
nuclear@0 123 PORTD = (PORTD & 0xf0) | (byte & 0xf);
nuclear@0 124 #endif
nuclear@0 125 }
nuclear@0 126
nuclear@0 127 unsigned char lcd_read_byte(void)
nuclear@0 128 {
nuclear@0 129 #if LCD_BUS_WIDTH == 8
nuclear@0 130 DDRD = 0;
nuclear@0 131 PORTD = 0; /* disable pull-ups */
nuclear@0 132
nuclear@0 133 return PIND;
nuclear@0 134 #else
nuclear@0 135 unsigned char byte;
nuclear@0 136
nuclear@0 137 DDRD = DDRD & 0xf0;
nuclear@0 138 PORTD &= 0xf0; /* disable pull-ups */
nuclear@0 139
nuclear@0 140 byte = (PIND & 0xf) << 4;
nuclear@0 141 return byte | (PIND & 0xf);
nuclear@0 142 #endif
nuclear@0 143 }
nuclear@0 144
nuclear@0 145 void lcd_init(void)
nuclear@0 146 {
nuclear@0 147 /* make sure the display has time to boot up */
nuclear@0 148 _delay_ms(20);
nuclear@0 149
nuclear@0 150 clear_bit(BIT_RW);
nuclear@0 151
nuclear@0 152 clear_bit(BIT_E);
nuclear@0 153 clear_bit(BIT_RS);
nuclear@0 154 #if LCD_BUS_WIDTH == 8
nuclear@0 155 lcd_write_byte(CMD_FUNC | FUNC_BUS_8BIT | FUNC_LINES_2 | FUNC_FONT_5x8);
nuclear@0 156 #else
nuclear@0 157 lcd_write_byte(CMD_FUNC | FUNC_BUS_4BIT | FUNC_LINES_2 | FUNC_FONT_5x8);
nuclear@0 158 #endif
nuclear@0 159 enable();
nuclear@0 160 lcd_wait_busy();
nuclear@0 161
nuclear@0 162 clear_bit(BIT_RS);
nuclear@0 163 lcd_write_byte(CMD_ONOFF | ONOFF_DISP);
nuclear@0 164 enable();
nuclear@0 165 lcd_wait_busy();
nuclear@0 166
nuclear@0 167 clear_bit(BIT_RS);
nuclear@0 168 lcd_write_byte(CMD_ENTRY_MODE | (1 << 1));
nuclear@0 169 enable();
nuclear@0 170 lcd_wait_busy();
nuclear@0 171 }
nuclear@0 172
nuclear@0 173 void lcd_clear(void)
nuclear@0 174 {
nuclear@0 175 clear_bit(BIT_RW);
nuclear@0 176
nuclear@0 177 clear_bit(BIT_E);
nuclear@0 178 clear_bit(BIT_RS);
nuclear@0 179 lcd_write_byte(CMD_CLEAR);
nuclear@0 180 enable();
nuclear@0 181 lcd_wait_busy();
nuclear@0 182 }
nuclear@0 183
nuclear@0 184 void lcd_set_cursor_addr(unsigned int addr)
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@0 190 lcd_write_byte(CMD_DDRAM_ADDR | addr);
nuclear@0 191 enable();
nuclear@0 192 lcd_wait_busy();
nuclear@0 193 }
nuclear@0 194
nuclear@0 195 void lcd_putchar(char c)
nuclear@0 196 {
nuclear@0 197 clear_bit(BIT_RW);
nuclear@0 198
nuclear@0 199 set_bit(BIT_RS);
nuclear@0 200 lcd_write_byte(c);
nuclear@0 201 enable();
nuclear@0 202 lcd_wait_busy();
nuclear@0 203 }
nuclear@0 204
nuclear@0 205 void lcd_putstr(const char *str)
nuclear@0 206 {
nuclear@0 207 while(*str) {
nuclear@0 208 lcd_putchar(*str++);
nuclear@0 209 }
nuclear@0 210 }
nuclear@0 211
nuclear@0 212 int lcd_stream_write(char c, FILE *fp)
nuclear@0 213 {
nuclear@0 214 /* TODO terminal shit handling */
nuclear@0 215 lcd_putchar(c);
nuclear@0 216 return 0;
nuclear@0 217 }
nuclear@0 218
nuclear@0 219 void lcd_wait_busy(void)
nuclear@0 220 {
nuclear@0 221 unsigned char data;
nuclear@0 222
nuclear@0 223 do {
nuclear@0 224 NSDELAY();
nuclear@0 225 clear_bit(BIT_E);
nuclear@0 226 clear_bit(BIT_RS);
nuclear@0 227 set_bit(BIT_RW);
nuclear@0 228 /*PIND = 0xff;*/
nuclear@0 229
nuclear@0 230 NSDELAY();
nuclear@0 231 set_bit(BIT_E);
nuclear@0 232 NSDELAY();
nuclear@0 233 data = lcd_read_byte();
nuclear@0 234 clear_bit(BIT_E);
nuclear@0 235 clear_bit(BIT_RW);
nuclear@0 236
nuclear@0 237 } while(data & (1 << 7));
nuclear@0 238 }
nuclear@0 239
nuclear@0 240 static void enable(void)
nuclear@0 241 {
nuclear@0 242 NSDELAY();
nuclear@0 243 set_bit(BIT_E);
nuclear@0 244 NSDELAY();
nuclear@0 245 clear_bit(BIT_E);
nuclear@0 246 NSDELAY();
nuclear@0 247 }
nuclear@0 248
nuclear@0 249 static void set_bit(int bit)
nuclear@0 250 {
nuclear@0 251 PORTC |= 1 << bit;
nuclear@0 252 }
nuclear@0 253
nuclear@0 254 static void clear_bit(int bit)
nuclear@0 255 {
nuclear@0 256 PORTC &= ~(1 << bit);
nuclear@0 257 }
nuclear@0 258
nuclear@0 259
nuclear@0 260 void delay(int x)
nuclear@0 261 {
nuclear@0 262 int i, j;
nuclear@0 263
nuclear@0 264 while(x-- > 0) {
nuclear@0 265 for(i=0; i<90; i++) {
nuclear@0 266 for(j=0; j<6; j++) {
nuclear@0 267 asm volatile("nop");
nuclear@0 268 }
nuclear@0 269 }
nuclear@0 270 }
nuclear@0 271 }