nuclear@0: #define F_CLK 1000000 nuclear@0: #define F_CPU 1000000 nuclear@0: nuclear@0: #include nuclear@0: #include nuclear@1: #include nuclear@0: #include nuclear@0: nuclear@0: /* hardware setup nuclear@0: * - PORT D: data bits nuclear@0: * - PORT C nuclear@0: * bit 0: RS nuclear@0: * bit 1: R/W nuclear@0: * bit 2: E nuclear@0: */ nuclear@1: #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 setup_adc(void); nuclear@0: long read_adc(void); 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@1: int bn_pressed; nuclear@1: unsigned char foo; nuclear@1: nuclear@0: int main(void) nuclear@0: { nuclear@0: stdout = stderr = &stream_lcd; nuclear@0: nuclear@1: /* port B[0] out -> backlight nuclear@1: * port B[1] in <- backlight switch nuclear@1: */ nuclear@1: DDRB = 1; nuclear@1: PORTB = 0xfe; /* enable all pullups, leave bit0 -> 0 (backlight) */ nuclear@1: /* enable PIN B1 interrupt */ nuclear@1: PCMSK0 = 2; nuclear@1: PCICR = 1; nuclear@1: sei(); /* enable interrupts */ nuclear@1: 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: setup_adc(); nuclear@0: nuclear@0: for(;;) { nuclear@0: long val = read_adc(); nuclear@0: double ref = 1.08 * 1.47 / 0.47; nuclear@0: double voltage = ref * (double)val / (double)1024; nuclear@1: nuclear@0: lcd_clear(); nuclear@0: nuclear@0: if(val == 1023) { nuclear@1: printf("*** RANGE ***"); nuclear@0: } else { nuclear@1: printf("%.2f volts", voltage); nuclear@1: } nuclear@1: nuclear@1: /* check if the backlight button was pressed */ nuclear@1: if(bn_pressed & 1) { nuclear@1: if(PORTB & 1) { nuclear@1: PORTB &= 0xfe; nuclear@1: } else { nuclear@1: PORTB |= 1; nuclear@1: } nuclear@1: bn_pressed = 0; nuclear@0: } nuclear@0: _delay_ms(500); nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@1: nuclear@1: ISR(PCINT0_vect) { nuclear@1: if((PINB & 2) == 0) { nuclear@1: bn_pressed = 1; nuclear@1: } nuclear@1: } nuclear@1: nuclear@0: void setup_adc(void) nuclear@0: { nuclear@0: /* disable digital input buffer on ADC0 pin */ nuclear@0: DIDR0 = 1; nuclear@0: nuclear@0: /* use the internal bandgap as a reference */ nuclear@0: ADMUX = 3 << REFS0; nuclear@0: nuclear@0: /* - enable ADC nuclear@0: * - set ADC clock prescaler to clock / 8 nuclear@0: */ nuclear@0: ADCSRA = (1 << ADEN) | (3 << ADPS0); nuclear@0: } nuclear@0: nuclear@0: long read_adc(void) nuclear@0: { nuclear@0: long low; nuclear@0: nuclear@0: /* start conversion */ nuclear@0: ADCSRA |= (1 << ADSC); nuclear@0: nuclear@0: /* wait while converting */ nuclear@0: while(ADCSRA & (1 << ADSC)); nuclear@0: nuclear@0: low = ADCL; nuclear@0: return low | ((long)ADCH << 8); nuclear@0: } nuclear@0: nuclear@1: void lcd_write_byte(unsigned char byte) nuclear@1: { nuclear@1: #if LCD_BUS_WIDTH == 8 nuclear@1: DDRD = 0xff; nuclear@1: PORTD = byte; nuclear@1: #else nuclear@1: DDRD = (DDRD & 0xf0) | 0xf; nuclear@1: nuclear@1: PORTD = (PORTD & 0xf0) | ((byte >> 4) & 0xf); nuclear@1: PORTD = (PORTD & 0xf0) | (byte & 0xf); nuclear@1: #endif nuclear@1: } nuclear@1: nuclear@1: unsigned char lcd_read_byte(void) nuclear@1: { nuclear@1: #if LCD_BUS_WIDTH == 8 nuclear@1: DDRD = 0; nuclear@1: PORTD = 0; /* disable pull-ups */ nuclear@1: nuclear@1: return PIND; nuclear@1: #else nuclear@1: unsigned char byte; nuclear@1: nuclear@1: DDRD = DDRD & 0xf0; nuclear@1: PORTD &= 0xf0; /* disable pull-ups */ nuclear@1: nuclear@1: byte = (PIND & 0xf) << 4; nuclear@1: return byte | (PIND & 0xf); nuclear@1: #endif nuclear@1: } nuclear@1: 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@1: #if LCD_BUS_WIDTH == 8 nuclear@1: lcd_write_byte(CMD_FUNC | FUNC_BUS_8BIT | FUNC_LINES_2 | FUNC_FONT_5x8); nuclear@1: #else nuclear@1: lcd_write_byte(CMD_FUNC | FUNC_BUS_4BIT | FUNC_LINES_2 | FUNC_FONT_5x8); nuclear@1: #endif nuclear@0: enable(); nuclear@0: lcd_wait_busy(); nuclear@0: nuclear@0: clear_bit(BIT_RS); nuclear@1: lcd_write_byte(CMD_ONOFF | ONOFF_DISP); nuclear@0: enable(); nuclear@0: lcd_wait_busy(); nuclear@0: nuclear@0: clear_bit(BIT_RS); nuclear@1: 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@1: 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@1: 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@1: 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@1: 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: }