这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 【STM32WBA55CG开发板】使用arm-2d制作电子书界面

共3条 1/1 1 跳转至

【STM32WBA55CG开发板】使用arm-2d制作电子书界面

菜鸟
2024-12-27 10:52:43     打赏

上一篇我们移植了arm公司开源的arm-2d,这一篇就讲一下怎么使用arm-2d的api来制作电子书的界面。

界面效果如下图

129x134_cp1.gif

这次一共制作4个界面(图标选择界面、电子书目录、电子书阅读界面和单词卡界面)

硬件接线

好,首先我们先看一下这次的硬件连接。这次需要一张micro SD卡来保存txt文件和屏幕显示需要的字库文件,

所以硬件链接如下图

01.png


其中SD卡是接到板子的spi1接口,共4根线,如下

PB4      ------> SPI1_SCK

PB3      ------> SPI1_MISO

PA15    ------> SPI1_MOSI

PA12    ------> SPI1_CS

屏幕还是gpio模拟iic,第一篇文章已经介绍过了,这里就不在介绍了。

驱动SD卡

接线已经讲完了,就来看看SD卡的驱动程序。首先用stm32cubeMX生成spi1的驱动代码,

由于不太会用这个软件,所以生成后的代码还需要简单修改一下,修改好的代码如下

SPI_HandleTypeDef hspi1;
static void MX_SPI1_Init(void)
{

  SPI_AutonomousModeConfTypeDef HAL_SPI_AutonomousMode_Cfg_Struct = {0};

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;//工作模式为全双工模式
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;//设置SPI的数据大小:SPI发送接收8位帧结构
  hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;//选择了串行时钟的稳态:时钟悬空高
  hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;//数据捕获于第二个时钟沿
  hspi1.Init.NSS = SPI_NSS_SOFT;//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;//定义波特率预分频的值:波特率预分频值为256
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;//指定数据传输从MSB位2还是LSB位开始:数据传输从MSB位开始
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;//具体来说是禁用TI模式
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 0x7;//CRC值计算的多项式
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;//启用NSS脉冲模式
  hspi1.Init.NSSPolarity = SPI_NSS_POLARITY_HIGH;//具体来说是将NSS信号的空闲状态设置为高电平
  hspi1.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;//具体来说是将FIFO阈值设置为1个数据。
  hspi1.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;//具体来说是将片选空闲周期设置为0个时钟周期。
  hspi1.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;//具体来说是将帧间空闲周期设置为0个时钟周期。
  hspi1.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;//STM32微控制器中SPI接口的自动接收暂停功能(Master Receiver Auto-Suspend),具体来说是禁用该功能。
  hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;//这行代码用于配置STM32微控制器中SPI接口的I/O状态保持功能(Master Keep IO State),具体来说是禁用该功能
  hspi1.Init.IOSwap = SPI_IO_SWAP_DISABLE;//这行代码用于配置STM32微控制器中SPI接口的I/O引脚交换功能(IO Swap),具体来说是禁用该功能。
  hspi1.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;//具体来说是将就绪信号的管理设置为内部管理(Internally)。
  hspi1.Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH;//具体来说是将就绪信号的空闲状态设置为高电平。
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    //Error_Handler();
  }
  HAL_SPI_AutonomousMode_Cfg_Struct.TriggerState = SPI_AUTO_MODE_DISABLE;//具体来说是将自主模式触发状态设置为禁用。
  if (HAL_SPIEx_SetConfigAutonomousMode(&hspi1, &HAL_SPI_AutonomousMode_Cfg_Struct) != HAL_OK)
  {
    //Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */

}

其他sd卡的程序我们就不多讲了,到时候会上传到附件。

简单测试一下SD卡,看看是否连接正确,测试程序如下

 SD_HW_Config();
 int result = SD_Init();
	
 if(result){
        draw_string_fast_EN(0,16,12,"01");
  }else{
        draw_string_fast_EN(0,16,12,"ok");
  }

如果屏幕中显示OK,则sd卡连接正确

挂载fatfs文件系统

sd卡驱动没问题后,接下来就是挂载fatfs文件系统,具体移植就不做介绍了,简单的测试程序如下

#define MUSIC_PATH_NEWFILE_TXT  "/大学.txt"
void test_read_file_fatfs(){
    FIL file;  // 文件对象
    FRESULT res;  // FatFs返回结果
    char out_buff[128];
    uint32_t rd_len;
    //res = f_open(&file,  MUSIC_PATH_NEWFILE_TXT, FA_READ);//FA_CREATE_ALWAYS | FA_WRITE
    res = f_open(&file,  MUSIC_PATH_NEWFILE_TXT, FA_CREATE_ALWAYS | FA_WRITE);//FA_CREATE_ALWAYS | FA_WRITE
    if (res == FR_OK) {
        for(int i = 0; i < 4;i++){
            res = f_lseek(&file, (2+i)*128);
            if(res == FR_OK){
                res = f_read(&file, out_buff, 128, &rd_len);
                draw_string_fast_EN(16,16*i ,16,out_buff);
            }
        }
        draw_string_fast_EN(0,16,12," fatfs ok");
    }
    f_close(&file) ;
}

int main(void)
{
    ...//
    f_mount(&fatfs,"",1);//挂载文件系统
    test_read_file_fatfs();
    ...
}

如果屏幕中显示fatfs ok,则文件系统挂载成功。


好了,接下来,就进入今天的主题,编写一个电子书的界面。

scene简介

在arm-2d中,每一个scene就相当于一个界面,所以我们需要几个界面就在rte中生成几个scene就可以了,如下图

02.png

直接输入4,点击确定就会出现4个scene,如下图

03.png

我们做的电子书需要4个界面,其效果如上面的gif所示。

图标界面

下面就开始制作第一个图标界面,如下图

04.png

此界面也很简单,一共有3个图标(分别是  电子书、单词卡和音乐),

按下板子上的按键1,3个图标会左右切换,并且在中间的图标处于选中状态,他的图标是反色绘制的。

中间图标的下面也会显示对应的汉字。

好了,这个界面的需求知道了,我们就开始制作吧。

图标界面布局

首先我们用arm-2d的布局小工具dock对此界面进行布局。

布局小工具dock简介

你可能还不知道什么是dock小工具,那我们就先简单介绍一下。

比如,你要获取屏幕上方高度为30的区域,如下图所示

07.png

此时,就可这样写

arm_2d_canvas(ptTile, _canvas) {
    arm_2d_dock_top( _canvas,  30 ) {
            __top_region
    }
}

arm_2d_canvas是用来获取屏幕大小的

arm_2d_dock_top就是用来获取屏幕上方的区域,此时生成的区域名称就叫__top_region(也就是说它的名字是固定的)

同样的,Arm-2D还提供了获取屏幕左边、右边和下方区域的小工具,如下表所示

工具名称对应区域名称
arm_2d_dock_bottom(__region, __height)__bottom_region
arm_2d_dock_left(__region, __width) __left_region
arm_2d_dock_right(__region, __width) __right_region

那我想获取屏幕中间的区域呢,比如高度为30,宽度为屏幕宽度的区域(如下图所示)该怎么办呢?

08.png

哈哈,这个也简单,贴心的官方也给我们提供了工具,如下

arm_2d_canvas(ptTile, _canvas) {
    arm_2d_dock_vertical( _canvas,  30 ) {
            __vertical_region    
    }
}

  • __vertical_region就是我们想要的区域了

同样的,获取屏幕中间竖条区域的小工具也有,如下

arm_2d_dock_horizontal(__region, __width)

它对应的区域名称为__horizontal_region

当然了,除了dock小工具,arm-2d还有其他的布局小工具,比如在区域中央可以用arm_2d_align_centre

arm_2d_canvas(ptTile, _canvas) {
    arm_2d_align_centre(_canvas, 100,100 ) {
        __centre_region
    }
}

好了,布局小工具就先介绍到这里。

其他布局工具可以看这篇文章:     https://mp.weixin.qq.com/s/m8Cvi--nl9I700kpskqqmg


接着就该今天的图标界面布局了。

首先,

此界面分为上下两个部分,如下图

05.png

对应的代码就可以这样写

arm_2d_dock_top( my_region,  50 ) {

}
arm_2d_dock_bottom(my_region,  20){
}

而上面的图标区域又分为3个,如下图

06.png

此时代码就可以这样写

arm_2d_dock_top( my_region,  50 ) {
    //__top_region   
  arm_2d_dock_vertical( __top_region,  40 ) {
        arm_2d_align_centre(__vertical_region, 40,40 ) {
      //中间的区域
    }
    arm_2d_dock_left(__vertical_region, 40){ 
      //左边的区域
    }
    arm_2d_dock_right(__vertical_region, 40){
      //右边的区域
    }
  }
}

下边区域的汉字也是在屏幕中间,所以代码就可以这样写

arm_2d_dock_bottom(my_region,  20){
    arm_2d_align_centre(__bottom_region, 16*3,16 ) {
        
  }
}

到此,图标界面的布局就完成了。

接着在这几个区域中绘制图标就可以了。

图标的绘制

要绘制图标,首先讲几个绘制函数。

由于我们使用的是单色屏幕,所以可以直接用A1的素材来绘制,其函数如下

arm_2d_fill_colour_with_a1_mask(ptTile, 
        &my_region, 
        &c_tileCar24A1Mask, 
        (__arm_2d_color_t){GLCD_COLOR_WHITE});

其中,my_region就是我们要在屏幕的哪个区域绘制

c_tileCar24A1Mask就是我们的图片素材

GLCD_COLOR_WHITE就是素材填充的颜色

由于我们使用的是arm-2d的8bit模式驱动oled的,所以也可以直接使用A8素材来填充,其函数如下

arm_2d_fill_colour_with_a8_mask(ptTile, 
       &my_region, 
       &c_tileCar24A8Mask, 
       (__arm_2d_color_t){GLCD_COLOR_WHITE});


那你这个A1mask和A8 mask是怎么制作的呢?

其实他就是一个取模软件,不过arm-2d也提供了一个python工具,如下

09.png

他的使用如下

10.png

这样,就可以生成40*40的图标素材了。

绘制界面

好,接下来就把图标界面绘制一下,程序如下

void  draw_icon(void *pTarget,                                  
                                const arm_2d_tile_t *ptTile,
                                arm_2d_region_t my_region,    
                                bool bIsNewFrame){
    arm_2d_dock_top( my_region,  50 ) {
        //__top_region   
        arm_2d_dock_vertical( __top_region,  40 ) {
            //__vertical_region   
            arm_2d_align_centre(__vertical_region, 40,40 ) { 
                arm_2d_fill_colour_with_a8_mask(ptTile, 
                                        &__centre_region, 
                                        my_icon[my_icon_list.current_entry], 
                                        (__arm_2d_color_t){GLCD_COLOR_WHITE}); 
                __centre_region.tLocation.iX -= 1;   
                __centre_region.tLocation.iY -= 1; 
                __centre_region.tSize.iHeight += 2;
                __centre_region.tSize.iWidth += 2;                            
                arm_2d_filter_reverse_colour(ptTile, 
                                        &__centre_region);                        
            }
            arm_2d_dock_left(__vertical_region, 40){
                char num;
                __left_region.tLocation.iX -= 10;
                if(0 == my_icon_list.current_entry){
                    num = my_icon_list.total_entries_num;
                }else{
                    num = my_icon_list.current_entry;
                }
                arm_2d_fill_colour_with_a8_mask(ptTile, 
                                        &__left_region, 
                                        my_icon[num - 1], 
                                        (__arm_2d_color_t){GLCD_COLOR_WHITE}); 
            }
            arm_2d_dock_right(__vertical_region, 40){
                __right_region.tLocation.iX += 10;
                arm_2d_fill_colour_with_a8_mask(ptTile, 
                                        &__right_region, 
                                        my_icon[(my_icon_list.current_entry + 1) % my_icon_list.total_entries_num ], 
                                        (__arm_2d_color_t){GLCD_COLOR_WHITE}); 
            }
        }                
    }
    arm_2d_dock_bottom(my_region,  20){
        arm_2d_align_centre(__bottom_region, 16*3,16 ) { 
            draw_string_2d(__centre_region.tLocation.iX,
            __centre_region.tLocation.iY,
            16,my_icon_string[my_icon_list.current_entry],  pTarget,  ptTile);
        }
        
    
    }
                                    
}

我们还使用了一个颜色反转的函数

arm_2d_filter_reverse_colour(ptTile,&__centre_region); 

这个函数就是把__centre_region区域的数据进行反色显示,这样就相当于我们选中了图标

好了,这个界面就先讲到这里

电子书阅读界面

接下来在制作一个电子书阅读界面,如下图

11.png

这个界面布局也很简单,也就左右两个部分,所以他的布局如下

arm_2d_dock_left(my_region, 120){
        
} 
arm_2d_dock_right(my_region, 11){
        
}

左边用来显示4行文字,也很简单,如下

arm_2d_dock_left(my_region, 120){
        write_line(  __left_region,out_buff,16); 
        draw_string_2d(0, 16 * 0, 16,&my_book.lines[0][0],  pTarget,  ptTile);     
        draw_string_2d(0, 16 * 1, 16,&my_book.lines[1][0],  pTarget,  ptTile);  
        draw_string_2d(0, 16 * 2, 16,&my_book.lines[2][0],  pTarget,  ptTile);
        draw_string_2d(0, 16 * 3, 16,&my_book.lines[3][0],  pTarget,  ptTile); 

    }

右边绘制了一个进度条,程序如下

arm_2d_dock_right(my_region, 11){
        arm_2d_dock_horizontal(__right_region, 2){
            arm_2d_fill_colour(ptTile, &__horizontal_region, GLCD_COLOR_WHITE);
            __horizontal_region.tLocation.iX -= 2;
            __horizontal_region.tLocation.iY =  128 * my_book.current_lseek / my_book.book_size;
            if(__horizontal_region.tLocation.iY >  125){
                __horizontal_region.tLocation.iY = 125;
            }
            __horizontal_region.tSize.iWidth = 6;
            __horizontal_region.tSize.iHeight = 3;
            arm_2d_fill_colour(ptTile, &__horizontal_region, GLCD_COLOR_WHITE);
        }
    }

首先我们现在右边区域绘制一个竖线,其函数为

arm_2d_fill_colour(ptTile, &__horizontal_region, GLCD_COLOR_WHITE);

这个函数就是把__horizontal_region区域中填充颜色(也就是绘制一个矩形)

同样的,根据进度在绘制一个小的矩形就可以了,是不是很简单

好了,其他界面我们就不介绍了,我把程序放到了附件,感兴趣的可以下载看看。

test_spi.zip

下一篇:实现蓝牙传书





关键词: oled     arm-2d     fatfs     sd    

专家
2024-12-27 22:02:47     打赏
2楼

感谢分享


专家
2024-12-27 22:09:14     打赏
3楼

感谢分享


共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]