/** * \brief Display text on OLED screen. * \param string String to display. */ void ssd1306_write_text(uint8_t * string) { uint8_t *char_ptr; uint8_t i; while (*string != 0) { char_ptr = font_table[(*string - 32) & 0x7F]; for (i = 1; i <= char_ptr[0]; i++) { ssd1306_write_data(char_ptr[i]); } ssd1306_write_data(0x00); string++; } }
int main(void) { uint8_t page_address; uint8_t column_address; uint8_t start_line_address = 0; volatile uint16_t delay = 10000; board_init(); sysclk_init(); // Initialize SPI and SSD1306 controller ssd1306_init(); // set addresses at beginning of display ssd1306_set_page_address(0); ssd1306_set_column_address(0); // fill display with lines for (page_address = 0; page_address <= 4; page_address++) { ssd1306_set_page_address(page_address); for (column_address = 0; column_address < 128; column_address++) { ssd1306_set_column_address(column_address); /* fill every other pixel in the display. This will produce horizontal lines on the display. */ ssd1306_write_data(0x6F); } } // scroll the display using hardware support in the LCD controller while (true) { ssd1306_set_display_start_line_address(start_line_address++); clock_delay_msec(250); } }
/** * \brief Draw graph on the OLED screen using the provided point array. * \param col X coordinate. * \param page Y coordinate (please refer to OLED datasheet for page * description). * \param width Graph width(columns). * \param height Graph height(pages, 1~3). * \param tab Data to draw. Must contain width elements. */ static void ssd1306_draw_graph(uint8_t col, uint8_t page, uint8_t width, uint8_t height, uint8_t *tab) { uint8_t i, j; uint8_t page_start, scale, bit_length, page_data[3]; uint32_t bit_data; for (i = col; i < width; ++i) { scale = 8 * height; bit_length = tab[i] * scale / 24; for (bit_data = 0; bit_length > 0; --bit_length) { bit_data = (bit_data << 1) + 1; } page_data[0] = bit_reverse8(bit_data & 0xFF); page_data[1] = bit_reverse8((bit_data >> 8) & 0xFF); page_data[2] = bit_reverse8((bit_data >> 16) & 0xFF); j = height - 1; for (page_start = page; page_start < (page + height); ++page_start) { ssd1306_write_command(SSD1306_CMD_SET_PAGE_START_ADDRESS( page_start)); ssd1306_set_column_address(i); ssd1306_write_data(page_data[j]); --j; } } }
/** * \brief Display text on OLED screen. * \param string String to display. */ void ssd1306_write_text(const char *string) { uint8_t *char_ptr; uint8_t i; while (*string != 0) { if (*string < 0x7F) { char_ptr = font_table[*string - 32]; for (i = 1; i <= char_ptr[0]; i++) { ssd1306_write_data(char_ptr[i]); } ssd1306_write_data(0x00); } string++; } }
/** * \brief Draw graph on the OLED screen using the provided point array. * \param col X coordinate. * \param page Y coordinate (please refer to OLED datasheet for page description). * \param width Graph width. * \param height Graph height. * \param tab Data to draw. Must contain width elements. */ static void ssd1306_draw_graph(uint8_t col, uint8_t page, uint8_t width, uint8_t height, uint8_t *tab) { volatile register uint8_t page_start; volatile register uint8_t i, j, k, s; uint8_t scale; for (i = 0; i < width; ++i) { for (page_start = page; page_start <= height; ++page_start) { ssd1306_write_command(SSD1306_CMD_SET_PAGE_START_ADDRESS(page_start)); ssd1306_set_column_address(i); j = tab[i]; scale = 8 * (height - page_start + 1); if (j > scale) j = 8; else j -= (scale - 8); for (k = 0, s = j; j > 0; --j) k = (k << 1) + 1; for (s = 8 - s; s > 0; --s) k <<= 1; ssd1306_write_data(k); } } }
/** * \brief Put a page from RAM to display controller. * * If the controller is accessed by the SPI interface, we can not read * back data from the LCD controller RAM. Because of this all data that is * written to the LCD controller in this mode is also written to a framebuffer * in MCU RAM. * * \param data Pointer to data to be written * \param page Page address * \param column Offset into page (x coordinate) * \param width Number of bytes to be written. * * The following example will write 32 bytes from data_buf to the page 0, * column 10. This will place data_buf in the rectangle x1=10,y1=0,x2=42,y2=8 * (10 pixels from the upper left corner of the screen): * \code * gfx_mono_ssd1306_put_page(data_buf, 0, 10, 32); * \endcode */ void gfx_mono_ssd1306_put_page(gfx_mono_color_t *data, gfx_coord_t page, gfx_coord_t column, gfx_coord_t width) { #ifdef CONFIG_SSD1306_FRAMEBUFFER gfx_mono_framebuffer_put_page(data, page, column, width); #endif ssd1306_set_page_address(page); ssd1306_set_column_address(column); do { ssd1306_write_data(*data++); } while (--width); }
/** * \brief Clear one character at the cursor current position on the OLED * screen. */ static void ssd1306_clear_char(void) { ssd1306_write_data(0x00); ssd1306_write_data(0x00); ssd1306_write_data(0x00); ssd1306_write_data(0x00); ssd1306_write_data(0x00); ssd1306_write_data(0x00); }
/** * \brief Put a byte to the display controller RAM * * If the LCD controller is accessed by the SPI interface we will also put the * data to the local framebuffer. * * \param page Page address * \param column Page offset (x coordinate) * \param data Data to be written * * This example will put the value 0xFF to the first byte in the display memory * setting a 8 pixel high column of pixels in the upper left corner of the * display. * \code * gfx_mono_ssd1306_put_byte(0, 0, 0xFF, false); * \endcode */ void gfx_mono_ssd1306_put_byte(gfx_coord_t page, gfx_coord_t column, uint8_t data, bool force) { #ifdef CONFIG_SSD1306_FRAMEBUFFER if (!force && data == gfx_mono_framebuffer_get_byte(page, column)) { return; } gfx_mono_framebuffer_put_byte(page, column, data); #endif ssd1306_set_page_address(page); ssd1306_set_column_address(column); ssd1306_write_data(data); }
int main(void) { //! the page address to write to uint8_t page_address; //! the column address, or the X pixel. uint8_t column_address; //! store the LCD controller start draw line uint8_t start_line_address = 0; board_init(); sysclk_init(); // Initialize SPI and SSD1306 controller ssd1306_init(); // set addresses at beginning of display ssd1306_set_page_address(0); ssd1306_set_column_address(0); // fill display with lines for (page_address = 0; page_address <= 7; page_address++) { ssd1306_set_page_address(page_address); for (column_address = 0; column_address < 128; column_address++) { ssd1306_set_column_address(column_address); /* fill every other pixel in the display. This will produce horizontal lines on the display. */ ssd1306_write_data(0x6F); } } // scroll the display using hardware support in the LCD controller while (true) { ssd1306_set_display_start_line_address(start_line_address++); delay_ms(250); } }
/** * \brief The main application. */ int main(void) { uint8_t i; uint8_t temperature[BUFFER_SIZE]; uint8_t light[BUFFER_SIZE]; char value_disp[5]; uint32_t adc_value; uint32_t light_value; double temp; /* Initialize clocks. */ sysclk_init(); /* Initialize GPIO states. */ board_init(); /* Configure ADC for light sensor. */ configure_adc(); /* Initialize at30tse. */ at30tse_init(); /* Configure IO1 buttons. */ configure_buttons(); /* Initialize SPI and SSD1306 controller. */ ssd1306_init(); ssd1306_clear(); /* Clear internal buffers. */ for (i = 0; i < BUFFER_SIZE; ++i) { temperature[i] = 0; light[i] = 0; } /* Show the start info. */ multi_language_show_start_info(); /* Wait 3 seconds to show the above message. */ delay_s(3); /* Check for valid firmware in SD card. */ check_valid_firmware(); while (true) { /* Set the trigger and jump to bootloader */ if (reset_flag) { jump_to_bootloader(); } /* Refresh page title only if necessary. */ if (app_mode_switch > 0) { app_mode = (app_mode + 1) % 3; /* Clear screen. */ ssd1306_clear(); ssd1306_set_page_address(0); ssd1306_set_column_address(0); if (app_mode == 0) { /* Temperature mode. */ ioport_set_pin_level(OLED1_LED1_PIN, OLED1_LED1_ACTIVE); ioport_set_pin_level(OLED1_LED2_PIN, !OLED1_LED2_ACTIVE); ioport_set_pin_level(OLED1_LED3_PIN, !OLED1_LED3_ACTIVE); multi_language_show_temperature_info(); } else if (app_mode == 1) { /* Light mode. */ ioport_set_pin_level(OLED1_LED2_PIN, OLED1_LED2_ACTIVE); ioport_set_pin_level(OLED1_LED1_PIN, !OLED1_LED1_ACTIVE); ioport_set_pin_level(OLED1_LED3_PIN, !OLED1_LED3_ACTIVE); multi_language_show_light_info(); } else { /* SD mode. */ ioport_set_pin_level(OLED1_LED3_PIN, OLED1_LED3_ACTIVE); ioport_set_pin_level(OLED1_LED1_PIN, !OLED1_LED1_ACTIVE); ioport_set_pin_level(OLED1_LED2_PIN, !OLED1_LED2_ACTIVE); sd_listing_pos = 0; /* Show SD card info. */ display_sd_info(); } app_mode_switch = 0; } /* Shift graph buffers. */ for (i = 0; i < (BUFFER_SIZE - 1); ++i) { temperature[i] = temperature[i + 1]; light[i] = light[i + 1]; } /* Get temperature. */ if (at30tse_read_temperature(&temp) == TWI_SUCCESS) { /* Don't care about negative temperature. */ if (temp < 0) { temp = 0; } /* Update temperature for display. */ /* Note: rescale to 0~24 for better rendering. */ if (temp > 40) { temperature[BUFFER_SIZE - 1] = 24; } else { temperature[BUFFER_SIZE - 1] = (uint8_t)temp * 24 / 40; } } else { /* Error print zero values. */ temperature[BUFFER_SIZE - 1] = 0; } /* Get light sensor information. */ /* Rescale to 0~24 for better rendering. */ adc_start_software_conversion(ADC); adc_value = adc_channel_get_value(ADC, ADC_CHANNEL_0); light[BUFFER_SIZE - 1] = 24 - adc_value * 24 / 1024; if (app_mode == 0) { /* Display temperature in text format. */ sprintf(value_disp, "%d", (uint8_t)temp); ssd1306_set_column_address(98); ssd1306_write_command(SSD1306_CMD_SET_PAGE_START_ADDRESS(0)); ssd1306_write_text(" "); /* Avoid character overlapping. */ if (temp < 10) { ssd1306_clear_char(); } ssd1306_write_text(value_disp); /* Display degree symbol. */ ssd1306_write_data(0x06); ssd1306_write_data(0x06); ssd1306_write_text("c"); /* Refresh graph. */ ssd1306_draw_graph(0, 2, BUFFER_SIZE, 2, temperature); } else if (app_mode == 1) { light_value = 100 - (adc_value * 100 / 1024); sprintf(value_disp, "%lu", light_value); ssd1306_set_column_address(98); ssd1306_write_command(SSD1306_CMD_SET_PAGE_START_ADDRESS(0)); ssd1306_write_text(" "); /* Avoid character overlapping. */ if (light_value < 10) { ssd1306_clear_char(); } ssd1306_write_text(value_disp); ssd1306_write_text("%"); /* Avoid character overlapping. */ if (light_value < 100) { ssd1306_clear_char(); } /* Refresh graph. */ ssd1306_draw_graph(0, 2, BUFFER_SIZE, 2, light); } else { /** * Refresh screen if card was inserted/removed or * browsing content. */ if (sd_update == 1) { /* Clear screen. */ ssd1306_clear(); ssd1306_set_page_address(0); ssd1306_set_column_address(0); if (sd_listing_pos == 0) { /* Show SD card info. */ display_sd_info(); } else { /* List SD card files. */ display_sd_files_unicode(); } sd_update = 0; } } /* Wait and stop screen flickers. */ delay_ms(150); if (app_mode_switch == 0) { pio_enable_interrupt(OLED1_PIN_PUSHBUTTON_1_PIO, OLED1_PIN_PUSHBUTTON_1_MASK); } if (sd_update == 0) { pio_enable_interrupt(OLED1_PIN_PUSHBUTTON_2_PIO, OLED1_PIN_PUSHBUTTON_2_MASK); pio_enable_interrupt(OLED1_PIN_PUSHBUTTON_3_PIO, OLED1_PIN_PUSHBUTTON_3_MASK); } } }
int main(void) { uint8_t i; uint8_t temperature[BUFFER_SIZE]; uint8_t light[BUFFER_SIZE]; uint8_t value_disp[5]; uint32_t adc_value; double temp; // Initialize clocks. sysclk_init(); // Initialize GPIO states. board_init(); // Configure ADC for light sensor. configure_adc(); // Initialize at30tse. at30tse_init(); // Configure IO1 buttons. configure_buttons(); // Initialize SPI and SSD1306 controller. ssd1306_init(); ssd1306_clear(); // Clear internal buffers. for (i = 0; i < BUFFER_SIZE; ++i) { temperature[i] = 0; light[i] = 0; } while (true) { /* Refresh page title only if necessary. */ if (app_mode_switch > 0) { app_mode = app_mode_switch - 1; // Clear screen. ssd1306_clear(); ssd1306_set_page_address(0); ssd1306_set_column_address(0); /* Temperature mode. */ if (app_mode == 0) { ioport_set_pin_level(IO1_LED1_PIN, IO1_LED1_ACTIVE); ioport_set_pin_level(IO1_LED2_PIN, !IO1_LED2_ACTIVE); ioport_set_pin_level(IO1_LED3_PIN, !IO1_LED3_ACTIVE); ssd1306_write_text("Temperature sensor:"); } /* Light mode. */ else if (app_mode == 1) { ioport_set_pin_level(IO1_LED2_PIN, IO1_LED2_ACTIVE); ioport_set_pin_level(IO1_LED1_PIN, !IO1_LED1_ACTIVE); ioport_set_pin_level(IO1_LED3_PIN, !IO1_LED3_ACTIVE); ssd1306_write_text("Light sensor:"); } /* SD mode. */ else { ioport_set_pin_level(IO1_LED3_PIN, IO1_LED3_ACTIVE); ioport_set_pin_level(IO1_LED1_PIN, !IO1_LED1_ACTIVE); ioport_set_pin_level(IO1_LED2_PIN, !IO1_LED2_ACTIVE); display_sd_info(); } app_mode_switch = 0; } // Shift graph buffers. for (i = 0; i < BUFFER_SIZE - 1; ++i) { temperature[i] = temperature[i + 1]; light[i] = light[i + 1]; } // Get temperature in a range from 0 to 40 degrees. if (at30tse_read_temperature(&temp) == TWI_SUCCESS) { // Don't care about negative temperature. if (temp < 0) temp = 0; // Update temperature for display. // Note: -12 in order to rescale for better rendering. if (temp < 12) temperature[BUFFER_SIZE - 1] = 0; else temperature[BUFFER_SIZE - 1] = temp - 12; } else { // Error print zero values. temperature[BUFFER_SIZE - 1] = 0; } // Get light sensor information. // Rescale for better rendering. adc_start(ADC); adc_value = adc_get_channel_value(ADC, ADC_CHANNEL_4); light[BUFFER_SIZE - 1] = 24 - adc_value * 24 / 4096; // Print temperature in text format. if (app_mode == 0) { sprintf(value_disp, "%d", (uint8_t)temp); ssd1306_set_column_address(95); ssd1306_write_command(SSD1306_CMD_SET_PAGE_START_ADDRESS(0)); ssd1306_write_text(" "); ssd1306_write_text(value_disp); // Display degree symbol. ssd1306_write_data(0x06); ssd1306_write_data(0x06); ssd1306_write_text("c"); // Refresh graph. ssd1306_draw_graph(0, 1, BUFFER_SIZE, 3, temperature); } else if (app_mode == 1) { sprintf(value_disp, "%lu", 100 - (adc_value * 100 / 4096)); ssd1306_set_column_address(98); ssd1306_write_command(SSD1306_CMD_SET_PAGE_START_ADDRESS(0)); ssd1306_write_text(" "); ssd1306_write_text(value_disp); ssd1306_write_text("%"); // Refresh graph. ssd1306_draw_graph(0, 1, BUFFER_SIZE, 3, light); } else { // Is card has been inserted or removed? if (sd_status_update == 1) { // Clear screen. ssd1306_clear(); ssd1306_set_page_address(0); ssd1306_set_column_address(0); // Show SD card info. display_sd_info(); sd_status_update = 0; } } /* Wait and stop screen flickers. */ delay_ms(50); } }