// // // phil_LCD_WiFi.c // // 115200 baud: period = 8.68 micros = 8681 ns // // 1 instruction at 20 MHz = 50 ns // ~173 instructions per communication period. // // // set lfuse to 0x5E for 20 MHz xtal. This divides clock by 8, giving 2.5 MHz clock frequency. // The divider is set to /1 in the main program, running the chip at 20 MHz, just at the top // of the specified range. The chip should receive 4.5-5.5 V in order to operate above 10 MHz. //F. Phil Brooks III // 10/23/19 // Harvard Chemistry and Chemical Biology // Based on code by // Neil Gershenfeld // 12/8/10 // (c) Massachusetts Institute of Technology 2010 // This work may be reproduced, modified, distributed, // performed, and displayed for any purpose. Copyright is // retained and must be preserved. The work is provided // as is; no warranty is provided, and users accept all // liability. //--------------------------------------------------------------------------------------------------- //#include #include #include #include #include #include #include #include #define bit_delay_time 8.2//8.5 // bit delay for 115200 with overhead 8.5 too large for joined bytes #define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay #define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay /* #define serial_pin_in (1 << PA7) #define serial_pin_out (1 << PA6) #define serial_interrupt (1 << PCIE0) #define serial_interrupt_pin (1 << PCINT7) #define serial_interrupt_flag (1 << PCIF0) //needed to clear flag */ #define W_serial_pin_in (1 << PA1) #define W_serial_pin_out (1 << PA0) //switched for esp8266 #define W_serial_interrupt (1 << PCIE0) #define W_serial_interrupt_pin (1 << PCINT1) #define W_serial_interrupt_flag (1 << PCIF0) //needed to clear flag #define DB7 (1 << PA7) #define DB6 (1 << PA6) #define DB5 (1 << PA5) #define DB4 (1 << PA4) #define E (1 << PA3) #define RS (1 << PA2) #define lcd_delay() _delay_ms(5) //delay between LCD commands #define strobe_delay() _delay_us(1) //delay for strobe #define button_pin (1 << PB2) #define max_buffer 200 volatile char update = 0; volatile int cmd_index = 0; volatile char message[max_buffer] = {0}; volatile int message_index = 0; volatile char my_msg_flag = 0; const char command_0[] PROGMEM="AT+CWMODE=1\r\n"; const char command_1[] PROGMEM="AT+CWJAP=\"PHILPRINCETONPC 8765\",\"xxxxxxxx\"\r\n"; const char command_2[] PROGMEM="AT+CIPSTART=\"TCP\",\"fab.cba.mit.edu\",80\r\n"; const char command_3[] PROGMEM="AT+CIPSEND=93\r\n"; const char command_4[] PROGMEM="GET /classes/863.19/Harvard/people/Phil/week_10/test.html HTTP/1.1\r\n"; const char command_5[] PROGMEM="HOST: fab.cba.mit.edu\r\n\r\n"; PGM_P const commands[] PROGMEM = {command_0,command_1,command_2,command_3,command_4,command_5}; // // lcd_putchar // put character in lcdbyte // void lcd_putchar(char lcdbyte) { // // set RS for data // PORTA |= RS; // // output high nibble // if (lcdbyte & (1 << 7)) PORTA |= DB7; else PORTA &= ~DB7; if (lcdbyte & (1 << 6)) PORTA |= DB6; else PORTA &= ~DB6; if (lcdbyte & (1 << 5)) PORTA |= DB5; else PORTA &= ~DB5; if (lcdbyte & (1 << 4)) PORTA |= DB4; else PORTA &= ~DB4; // // strobe E // strobe_delay(); PORTA |= E; strobe_delay(); PORTA &= (~E); // // wait // lcd_delay(); // // output low nibble // if (lcdbyte & (1 << 3)) PORTA |= DB7; else PORTA &= ~DB7; if (lcdbyte & (1 << 2)) PORTA |= DB6; else PORTA &= ~DB6; if (lcdbyte & (1 << 1)) PORTA |= DB5; else PORTA &= ~DB5; if (lcdbyte & (1 << 0)) PORTA |= DB4; else PORTA &= ~DB4; // // strobe E // strobe_delay(); PORTA |= E; strobe_delay(); PORTA &= (~E); // // wait and return // lcd_delay(); } // // lcd_putcmd // put command in lcdbyte // void lcd_putcmd(char lcdbyte) { // // clear RS for command // PORTA &= ~RS; // // output command bits // Set relevant PORTA bits, clear unset bits, and leave non-LCD bits alone PORTA &= (~(DB4 | DB5 | DB6 | DB7 | E | RS)); PORTA |= ((DB4 | DB5 | DB6 | DB7 | E | RS) & lcdbyte); // // strobe E // strobe_delay(); PORTA |= E; strobe_delay(); PORTA &= (~E); // // wait and return // lcd_delay(); } // // lcd_putstring // put a null-terminated string // void lcd_putstring(char *msg) { // // print a null-terminated string static uint8_t index; static char chr; index = 0; while (1) { chr = msg[index++]; if (chr > 31) { lcd_putchar(chr); } else if ((chr == 0)) { return; } else if (chr == 10) { lcd_putcmd(DB7+DB6); //set DDRAM address to 64 (start of 2nd line) lcd_putcmd(0); } } } // // lcd_init // initialize the LCD // void lcd_init() { // // power-up delay // lcd_delay(); // // initialization sequence // lcd_putcmd(DB5+DB4); //8 bit one line 5x8 lcd_putcmd(DB5+DB4); //repeat (see datasheet) lcd_putcmd(DB5+DB4); //repeat (see datasheet) // // 4-bit interface // lcd_putcmd(DB5); //4 bit interface one line 5x8 (all following instructions are in 4-bit mode) // // two lines, 5x7 font // lcd_putcmd(DB5); //high lcd_putcmd(DB7); //low // // display on with cursor on // lcd_putcmd(0); lcd_putcmd(DB7+DB6+DB5); // // entry mode // lcd_putcmd(0); lcd_putcmd(DB6+DB5); } void get_char(volatile unsigned char *pins, unsigned char pin, char *rxbyte) { // read character into rxbyte on pins pin // assumes line driver (inverts bits) *rxbyte = 0; /*while (*pins & pin) { ;// wait for start bit }*/ // delay to middle of first data bit //half_bit_delay(); //causes problems receiving o, w with fixed code. May have been legacy of bug. bit_delay(); // unrolled loop to read data bits if (*pins & pin) *rxbyte |= (1 << 0); else *rxbyte |= (0 << 0); bit_delay(); if (*pins & pin) *rxbyte |= (1 << 1); else *rxbyte |= (0 << 1); bit_delay(); if (*pins & pin) *rxbyte |= (1 << 2); else *rxbyte |= (0 << 2); bit_delay(); if (*pins & pin) *rxbyte |= (1 << 3); else *rxbyte |= (0 << 3); bit_delay(); if (*pins & pin) *rxbyte |= (1 << 4); else *rxbyte |= (0 << 4); bit_delay(); if (*pins & pin) *rxbyte |= (1 << 5); else *rxbyte |= (0 << 5); bit_delay(); if (*pins & pin) *rxbyte |= (1 << 6); else *rxbyte |= (0 << 6); bit_delay(); if (*pins & pin) *rxbyte |= (1 << 7); else *rxbyte |= (0 << 7); // wait for stop bit bit_delay(); half_bit_delay(); } void put_char(volatile unsigned char *port, unsigned char pin, char txchar) { // send character in txchar on port pin // assumes line driver (inverts bits) // start bit *port &= (~pin); bit_delay(); // // unrolled loop to write data bits if (txchar & (1<<0)) *port |= pin; else *port &= (~pin); bit_delay(); if (txchar & (1<<1)) *port |= pin; else *port &= (~pin); bit_delay(); if (txchar & (1<<2)) *port |= pin; else *port &= (~pin); bit_delay(); if (txchar & (1<<3)) *port |= pin; else *port &= (~pin); bit_delay(); if (txchar & (1<<4)) *port |= pin; else *port &= (~pin); bit_delay(); if (txchar & (1<<5)) *port |= pin; else *port &= (~pin); bit_delay(); if (txchar & (1<<6)) *port |= pin; else *port &= (~pin); bit_delay(); if (txchar & (1<<7)) *port |= pin; else *port &= (~pin); bit_delay(); // // stop bit *port |= pin; bit_delay(); } void put_string_P(volatile unsigned char *port, unsigned char pin, PGM_P str) { // // print a null-terminated string static int index; static char chr; index = 0; while (1) { chr = pgm_read_byte(&(str[index])); if (chr==0) { return; } put_char(port, pin, chr); ++index; } } ISR(PCINT0_vect) { // // pin change interrupt handler // if (~(PINA & W_serial_pin_in)) { static char chr; get_char(&PINA, W_serial_pin_in, &chr); GIFR = W_serial_interrupt_flag; //clear pending serial interrupts caused by data transmission. if (chr=='#') { if (my_msg_flag == 0) { message_index = max_buffer-2; } my_msg_flag = 1; } message[message_index++] = chr; if (message_index == (max_buffer-1)) { //last char is always null (necessary for put_string). message_index = 0; } } //update = 1; } ISR(INT0_vect) { update = 1; for ( ; message_index > 0; --message_index) { message[message_index-1] = 0; } //Talk to ESP8266 put_string_P(&PORTA, W_serial_pin_out, (PGM_P)pgm_read_word(&(commands[cmd_index++]))); if (cmd_index == 6) { cmd_index = 0; } GIFR = W_serial_interrupt_flag; GIFR = (1 << INTF0); //clear button interrupt flag //(catches bouncing, but not release of button, since // user release of button is much slower than this interrupt handler. } int main(void) { // // main // // set clock divider to /1: Operate at 20 MHz // CLKPR = (1 << CLKPCE); CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0); // // initialize output pins // //PORTA |= serial_pin_out; //DDRA |= serial_pin_out; PORTA |= W_serial_pin_out; DDRA |= W_serial_pin_out; //Initialize LCD pins DDRA |= (DB7 | DB6 | DB5 | DB4 | RS | E); PORTA &= (~(DB7 | DB6 | DB5 | DB4 | RS | E)); // // set up pin change interrupt on input pin // GIMSK |= W_serial_interrupt; GIMSK |= (1 << INT0); //enable INT0 external interrupts PCMSK0 |= W_serial_interrupt_pin; MCUCR |= (1 << ISC01); //set external interrupt for falling edge on INT0 pin PORTB |= (1 << PB2); //turn on pull-up resistor PORTA |= W_serial_pin_in; //OPTIONAL? //Initialize LCD lcd_init(); _delay_ms(1500);//wait for ESP8266 initialization sei(); while (1) { if (update == 1) { update = 0; _delay_ms(10); // // clear display // lcd_putcmd(0); lcd_putcmd(DB4); // // go to zero position // lcd_putcmd(0); lcd_putcmd(DB5); // // print first line // if (my_msg_flag) { lcd_putstring((char *)message); } else { lcd_putstring((char *)message); } } } }