nuclear@0: #define F_CLK 1000000 nuclear@0: #define F_CPU 1000000 nuclear@0: nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@0: /* hardware setup nuclear@0: * - PORT D: data bits nuclear@0: * - PORT C nuclear@0: * bit 3: RS nuclear@0: * bit 4: R/W nuclear@0: * bit 5: E nuclear@0: */ nuclear@0: #define LCD_BUS_WIDTH 8 nuclear@0: nuclear@0: #define BIT_RS 3 nuclear@0: #define BIT_RW 4 nuclear@0: #define BIT_E 5 nuclear@0: nuclear@0: #define CMD_CLEAR 1 nuclear@0: #define CMD_RET (1 << 1) nuclear@0: #define CMD_ENTRY_MODE (1 << 2) nuclear@0: #define CMD_ONOFF (1 << 3) nuclear@0: #define CMD_SHIFT (1 << 4) nuclear@0: #define CMD_FUNC (1 << 5) nuclear@0: #define CMD_CGRAM_ADDR (1 << 6) nuclear@0: #define CMD_DDRAM_ADDR (1 << 7) nuclear@0: nuclear@0: #define FUNC_BUS_4BIT 0 nuclear@0: #define FUNC_BUS_8BIT (1 << 4) nuclear@0: #define FUNC_LINES_1 0 nuclear@0: #define FUNC_LINES_2 (1 << 3) nuclear@0: #define FUNC_FONT_5x8 0 nuclear@0: #define FUNC_FONT_5x11 (1 << 2) nuclear@0: nuclear@0: #define ONOFF_DISP (1 << 2) nuclear@0: #define ONOFF_CURSOR (1 << 1) nuclear@0: #define ONOFF_CURSOR_POS 1 nuclear@0: nuclear@0: void lcd_init(void); nuclear@0: void lcd_clear(void); nuclear@0: void lcd_set_cursor_addr(unsigned int addr); nuclear@0: void lcd_putchar(char c); nuclear@0: void lcd_putstr(const char *str); nuclear@0: int lcd_stream_write(char c, FILE *fp); nuclear@0: void lcd_wait_busy(void); nuclear@0: static void enable(void); nuclear@0: static void set_bit(int bit); nuclear@0: static void clear_bit(int bit); nuclear@0: void delay(int x); nuclear@0: nuclear@0: #define NSDELAY() asm volatile ("nop") nuclear@0: #define DEBUG(i) (PORTB = (1 << (i))) nuclear@0: nuclear@0: FILE stream_lcd = FDEV_SETUP_STREAM(lcd_stream_write, NULL, _FDEV_SETUP_WRITE); nuclear@0: nuclear@0: unsigned int pulse_time; nuclear@0: nuclear@0: int main(void) nuclear@0: { nuclear@0: stdout = stderr = &stream_lcd; nuclear@0: nuclear@0: DDRB = 0; /* set port B as input (bit 0 is used to measure pulse width) */ nuclear@0: PORTB = 0; /* disable pullups */ nuclear@0: nuclear@0: DDRD = 0xff; nuclear@0: DDRC = 0xfe; nuclear@0: PORTC = 0; /* disable pullups */ nuclear@0: nuclear@0: lcd_init(); nuclear@0: lcd_clear(); nuclear@0: nuclear@0: printf("initializing..."); nuclear@0: nuclear@0: TCCR1B |= (1 << ICES1); /* set first capture to occur on a rising edge */ nuclear@0: TCCR1B = (TCCR1B & 0xf8) | 1; /* no prescaling */ nuclear@0: TIMSK1 |= (1 << ICIE1); /* enable timer1 input capture interrupt */ nuclear@0: sei(); nuclear@0: nuclear@0: for(;;) { nuclear@0: static int blink = 0; nuclear@0: nuclear@0: PORTB = blink ? 1 : 0; nuclear@0: blink = (blink + 1) & 1; nuclear@0: nuclear@0: lcd_set_cursor_addr(0); nuclear@0: printf("pulse time: %u us ", pulse_time); nuclear@0: lcd_set_cursor_addr(64); nuclear@0: printf("pos: %u%% ", (pulse_time - 1000) / 10); nuclear@0: _delay_ms(100); nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: ISR(TIMER1_CAPT_vect) nuclear@0: { nuclear@0: static int rising; nuclear@0: nuclear@0: rising = !rising; nuclear@0: if(rising) { nuclear@0: /* rising edge: reset the timer */ nuclear@0: TCNT1 = 0; nuclear@0: /* and set a falling edge trigger */ nuclear@0: TCCR1B &= ~(1 << ICES1); nuclear@0: } else { nuclear@0: /* falling edge: calculate the time since the last rise */ nuclear@0: pulse_time = ICR1; nuclear@0: /* and set a rising edge trigger */ nuclear@0: TCCR1B |= 1 << ICES1; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void lcd_write_byte(unsigned char byte) nuclear@0: { nuclear@0: #if LCD_BUS_WIDTH == 8 nuclear@0: DDRD = 0xff; nuclear@0: PORTD = byte; nuclear@0: #else nuclear@0: DDRD = (DDRD & 0xf0) | 0xf; nuclear@0: nuclear@0: PORTD = (PORTD & 0xf0) | ((byte >> 4) & 0xf); nuclear@0: PORTD = (PORTD & 0xf0) | (byte & 0xf); nuclear@0: #endif nuclear@0: } nuclear@0: nuclear@0: unsigned char lcd_read_byte(void) nuclear@0: { nuclear@0: #if LCD_BUS_WIDTH == 8 nuclear@0: DDRD = 0; nuclear@0: PORTD = 0; /* disable pull-ups */ nuclear@0: nuclear@0: return PIND; nuclear@0: #else nuclear@0: unsigned char byte; nuclear@0: nuclear@0: DDRD = DDRD & 0xf0; nuclear@0: PORTD &= 0xf0; /* disable pull-ups */ nuclear@0: nuclear@0: byte = (PIND & 0xf) << 4; nuclear@0: return byte | (PIND & 0xf); nuclear@0: #endif nuclear@0: } nuclear@0: nuclear@0: void lcd_init(void) nuclear@0: { nuclear@0: /* make sure the display has time to boot up */ nuclear@0: _delay_ms(20); nuclear@0: nuclear@0: clear_bit(BIT_RW); nuclear@0: nuclear@0: clear_bit(BIT_E); nuclear@0: clear_bit(BIT_RS); nuclear@0: #if LCD_BUS_WIDTH == 8 nuclear@0: lcd_write_byte(CMD_FUNC | FUNC_BUS_8BIT | FUNC_LINES_2 | FUNC_FONT_5x8); nuclear@0: #else nuclear@0: lcd_write_byte(CMD_FUNC | FUNC_BUS_4BIT | FUNC_LINES_2 | FUNC_FONT_5x8); nuclear@0: #endif nuclear@0: enable(); nuclear@0: lcd_wait_busy(); nuclear@0: nuclear@0: clear_bit(BIT_RS); nuclear@0: lcd_write_byte(CMD_ONOFF | ONOFF_DISP); nuclear@0: enable(); nuclear@0: lcd_wait_busy(); nuclear@0: nuclear@0: clear_bit(BIT_RS); nuclear@0: lcd_write_byte(CMD_ENTRY_MODE | (1 << 1)); nuclear@0: enable(); nuclear@0: lcd_wait_busy(); nuclear@0: } nuclear@0: nuclear@0: void lcd_clear(void) nuclear@0: { nuclear@0: clear_bit(BIT_RW); nuclear@0: nuclear@0: clear_bit(BIT_E); nuclear@0: clear_bit(BIT_RS); nuclear@0: lcd_write_byte(CMD_CLEAR); nuclear@0: enable(); nuclear@0: lcd_wait_busy(); nuclear@0: } nuclear@0: nuclear@0: void lcd_set_cursor_addr(unsigned int addr) nuclear@0: { nuclear@0: clear_bit(BIT_RW); nuclear@0: nuclear@0: clear_bit(BIT_E); nuclear@0: clear_bit(BIT_RS); nuclear@0: lcd_write_byte(CMD_DDRAM_ADDR | addr); nuclear@0: enable(); nuclear@0: lcd_wait_busy(); nuclear@0: } nuclear@0: nuclear@0: void lcd_putchar(char c) nuclear@0: { nuclear@0: clear_bit(BIT_RW); nuclear@0: nuclear@0: set_bit(BIT_RS); nuclear@0: lcd_write_byte(c); nuclear@0: enable(); nuclear@0: lcd_wait_busy(); nuclear@0: } nuclear@0: nuclear@0: void lcd_putstr(const char *str) nuclear@0: { nuclear@0: while(*str) { nuclear@0: lcd_putchar(*str++); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: int lcd_stream_write(char c, FILE *fp) nuclear@0: { nuclear@0: /* TODO terminal shit handling */ nuclear@0: lcd_putchar(c); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: void lcd_wait_busy(void) nuclear@0: { nuclear@0: unsigned char data; nuclear@0: nuclear@0: do { nuclear@0: NSDELAY(); nuclear@0: clear_bit(BIT_E); nuclear@0: clear_bit(BIT_RS); nuclear@0: set_bit(BIT_RW); nuclear@0: /*PIND = 0xff;*/ nuclear@0: nuclear@0: NSDELAY(); nuclear@0: set_bit(BIT_E); nuclear@0: NSDELAY(); nuclear@0: data = lcd_read_byte(); nuclear@0: clear_bit(BIT_E); nuclear@0: clear_bit(BIT_RW); nuclear@0: nuclear@0: } while(data & (1 << 7)); nuclear@0: } nuclear@0: nuclear@0: static void enable(void) nuclear@0: { nuclear@0: NSDELAY(); nuclear@0: set_bit(BIT_E); nuclear@0: NSDELAY(); nuclear@0: clear_bit(BIT_E); nuclear@0: NSDELAY(); nuclear@0: } nuclear@0: nuclear@0: static void set_bit(int bit) nuclear@0: { nuclear@0: PORTC |= 1 << bit; nuclear@0: } nuclear@0: nuclear@0: static void clear_bit(int bit) nuclear@0: { nuclear@0: PORTC &= ~(1 << bit); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: void delay(int x) nuclear@0: { nuclear@0: int i, j; nuclear@0: nuclear@0: while(x-- > 0) { nuclear@0: for(i=0; i<90; i++) { nuclear@0: for(j=0; j<6; j++) { nuclear@0: asm volatile("nop"); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: }