【前言】
在古代,有一个词为学富五车(指读书很多,学问渊博。喻书多)为啥书那么多呢?原因就是古代的书是竹子做的竹简。哈哈,现在想想实在太不可思议了。随着技术的发展,我们现在似乎纸质的书都不怎么看了,取而代之的是电子书。以前的五车书现在一本电子书就搞定了
然而,由于现在的LCD显示屏幕,有背光灯,看的时间长了眼睛会不舒服。所以,为了解决这个问题,又研发了一种不带背光的墨水屏,这不,我们今天就用墨水屏来制作一个电子书。入下图所示
【墨水屏显示原理】
墨水屏采用的是“微胶囊电泳显示”技术进行图像显示,它的基本原理是悬浮在液体中的带电纳米粒子受到电场作用而产生迁移(所以使用时间长了切换会有残影)。墨水屏是靠反射环境光来显示图案的,所以不需要背光,在环境光下,墨水屏清晰可见,可视角度几乎达到了 180°。因此,墨水屏非常适合做电子书进行阅读。
不过,墨水屏也是有缺点的,首先它的刷新率不是很高,刷一屏的时间差不多是2秒,其次是它的显示颜色少,基本就是黑白两色。
好了,下面我们就看看怎么把墨水屏驱动起来。
【墨水屏驱动程序】
首先,墨水屏的接口为spi串行接口,所以直接接到单片机的spi1的管脚,如下图
spi的驱动程序如下
static void epaper_spi1_init(void)
{
spi_parameter_struct spi_init_struct;
/* enable the gpio clock */
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_SPI1);
rcu_periph_clock_enable(RCU_DMA0);
/* GPIOB config, PB13(SPI1_SCK), PB14(SPI1_MISO), PB15(LCD_SPI1_MOSI) */
gpio_af_set(GPIOB, GPIO_AF_5, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
/* GPIOB config */
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_12);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_12);
/* GPIOB11 config */
gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN_11);
//gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_12);
/* SPI1 parameter config */
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init_struct.device_mode = SPI_MASTER;
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;//SPI_CK_PL_HIGH_PH_1EDGE;
spi_init_struct.nss = SPI_NSS_SOFT;
spi_init_struct.prescale = SPI_PSC_32;
spi_init_struct.endian = SPI_ENDIAN_MSB;
spi_init(SPI1, &spi_init_struct);
/* set crc polynomial */
spi_enable(SPI1);
//spi_dma_enable(SPI1, SPI_DMA_TRANSMIT);
}
其他墨水屏的驱动函数(比如画点函数,打印字符函数等)我们就不具体贴了,大家一般买屏幕卖家都会送的。
接下来我们就看看具体的电子书程序是怎么写的。
首先对墨水屏进行初始化
如下所示
int EPD_test_elink_book2(void)
{
page_turn_flag = 0;
book_num = 0;
DEV_Module_Init();
EPD_2IN9_Init(EPD_2IN9_FULL);
DEV_Delay_ms(500);
Paint_NewImage(BlackImage, EPD_2IN9_WIDTH, EPD_2IN9_HEIGHT, 270, WHITE);
然后显示一张开机图片
程序如下
Paint_SelectImage(BlackImage);
Paint_Clear(WHITE);
Paint_DrawBitMap(gImage_dzs);
EPD_2IN9_Display(BlackImage);
DEV_Delay_ms(10000);
接下来就是电子书显示
程序如下
Paint_SelectImage(BlackImage);
Paint_Clear(WHITE);
read_book(str_book);
DEV_Delay_ms(2000);
- 我们封装了一个函数read_book来显示电子书
- 它的参数只有一个,就是字符串指针
函数read_book原型
read_book函数如下
void read_book(const char *str2){
char flag = 1;
while(1){
flag = my_lcd_puts(str2);
EPD_2IN9_Display(BlackImage);
DEV_Delay_ms(20000);
if(0 == flag){
book_num = 0;
return;
}
set_page_turn();
Paint_SelectImage(BlackImage);
Paint_Clear(WHITE);
}
}
其中,最主要的函数为 my_lcd_puts,他是用来显示传人的字符串到墨水屏的
my_lcd_puts函数如下
char my_lcd_puts(const char *str2) { char *str = str2 + book_num; page_turn_flag = 0; while(*str) { //处理特殊字符 if (*str == '\r') { s_tLCDTextControl_su.tTextLocation.chX = 0; } else if (*str == '\n') { s_tLCDTextControl_su.tTextLocation.chX = 0; s_tLCDTextControl_su.tTextLocation.chY++; } else if (*str == '\t') { s_tLCDTextControl_su.tTextLocation.chX += 8; s_tLCDTextControl_su.tTextLocation.chX &= ~(_BV(3)-1); if ( s_tLCDTextControl_su.tTextLocation.chX * Font16.Width >= s_tLCDTextControl_su.tRegion.tSize.iWidth ) { s_tLCDTextControl_su.tTextLocation.chX = 0; s_tLCDTextControl_su.tTextLocation.chY++; } }else if (*str == '\b') { if (s_tLCDTextControl_su.tTextLocation.chX) { s_tLCDTextControl_su.tTextLocation.chX--; } } else { //计算字符显示坐标 int16_t iX = s_tLCDTextControl_su.tTextLocation.chX * Font16.Width; int16_t iY = s_tLCDTextControl_su.tTextLocation.chY * Font16.Height; if ( iY > (s_tLCDTextControl_su.tRegion.tSize.iHeight-Font16.Height) ) { //显示完一页 s_tLCDTextControl_su.tTextLocation.chY = 0; s_tLCDTextControl_su.tTextLocation.chX = 0; page_turn_flag = 1; return 1; } //显示一个字符 my_lcd_draw_char( s_tLCDTextControl_su.tRegion.tLocation.iX + iX, iY, *str); //右移一个字符的坐标,方便下个字符显示 s_tLCDTextControl_su.tTextLocation.chX++; //判断是否显示到屏幕外面 if ( s_tLCDTextControl_su.tTextLocation.chX * Font16.Width >= s_tLCDTextControl_su.tRegion.tSize.iWidth ) { s_tLCDTextControl_su.tTextLocation.chX = 0; //显示到一行的末尾后换行 s_tLCDTextControl_su.tTextLocation.chY++; if ( s_tLCDTextControl_su.tTextLocation.chY * Font16.Height >= s_tLCDTextControl_su.tRegion.tSize.iHeight) { //显示完一页 s_tLCDTextControl_su.tTextLocation.chY = 0; s_tLCDTextControl_su.tTextLocation.chX = 0; page_turn_flag = 1; return 1; } } } //显示完一个字符,指向下一个字符 if(0 == page_turn_flag){ book_num++; str = str2 + book_num; } } return 0; }
- 此程序我们参考了下面这篇文章,大家感兴趣也可以取看看原文
活字印刷术之字符串显示
电子书演示视频如下
https://www.bilibili.com/vide...