提示:下面只贴出部分代码,后续开发完后会提供完整代码。
一、前言
在上周,收到了MM32F5270开发板,多余的介绍就不说了(官网比较详细)。板子上集成了音频功放,可用IIS驱动音频芯片或者直接使用单片机的DAC输出音频,有SD卡可以存储数据,正好家里又有2.8寸的液晶屏,那就组合一下做个音乐播放器吧。
二、硬件接口
2.8寸屏幕: 使用SPI1驱动(不使用PA4和PA5引脚,可复用为其它引脚)
电阻触摸: 使用软件模拟SPI驱动
音频: 使用芯片内置DAC驱动,因为通用性强(不考虑音质)。
SD卡: 使用SPI3驱动(开发板连接好)
三、屏幕驱动
屏幕使用SPI1进行驱动,关于这一部分可以参考官方给的例程,这里只贴出SPI部分,关于屏幕其他部分都是一样的,此处省略。
void bsp_spi1_config(void)
{
SPI_Master_Init_Type SPI_InitStructure;
GPIO_Init_Type GPIO_InitStructure;
RCC_EnableAHB1Periphs(BSP_SPI1_GPIO_RCU, true);
RCC_EnableAPB2Periphs(BSP_SPI1_RCU, true);
#if USB_SPI1_CS
/* CS */
GPIO_InitStructure.Pins = BSP_SPI1_CS_PIN;
GPIO_InitStructure.Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.PinMode = GPIO_PinMode_Out_PushPull;
GPIO_Init(BSP_SPI1_CS_PORT, &GPIO_InitStructure);
GPIO_PinAFConf(BSP_SPI1_CS_PORT, BSP_SPI1_CS_PIN, GPIO_AF_5);
#endif
/* SCK */
GPIO_InitStructure.Pins = BSP_SPI1_SCK_PIN;
GPIO_InitStructure.Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.PinMode = GPIO_PinMode_AF_PushPull;
GPIO_Init(BSP_SPI1_SCK_PORT, &GPIO_InitStructure);
GPIO_PinAFConf(BSP_SPI1_SCK_PORT, BSP_SPI1_SCK_PIN, GPIO_AF_5);
#if USB_SPI1_READ
/* MISO */
GPIO_InitStructure.Pins = BSP_SPI1_MISO_PIN;
GPIO_InitStructure.PinMode = GPIO_PinMode_In_Floating;
GPIO_Init(BSP_SPI1_MISO_PORT, &GPIO_InitStructure);
GPIO_PinAFConf(BSP_SPI1_MISO_PORT, BSP_SPI1_MISO_PIN, GPIO_AF_5);
#endif
/* MOSI */
GPIO_InitStructure.Pins = BSP_SPI1_MOSI_PIN;
GPIO_InitStructure.PinMode = GPIO_PinMode_AF_PushPull;
GPIO_Init(BSP_SPI1_MOSI_PORT, &GPIO_InitStructure);
GPIO_PinAFConf(BSP_SPI1_MOSI_PORT, BSP_SPI1_MOSI_PIN, GPIO_AF_5);
/* Setup SPI Master. */
SPI_InitStructure.ClockFreqHz = CLOCK_APB2_FREQ;
SPI_InitStructure.BaudRate = 40000000u; /* 40Mhz. */
SPI_InitStructure.XferMode = SPI_XferMode_TxRx;
SPI_InitStructure.PolPha = SPI_PolPha_Alt2; // CPOL = 1, CPHA = 1,
SPI_InitStructure.DataWidth = SPI_DataWidth_8b;
SPI_InitStructure.LSB = false;
SPI_InitStructure.AutoCS = false; /* if set false, need SPI_EnableCS after spi enable. */
SPI_InitMaster(USB_SPI1, &SPI_InitStructure);
/* Enable SPI Master. */
SPI_Enable(USB_SPI1, true);
}
发送和接收数据部分:
uint8_t spi1_send_byte(uint8_t byte)
{
/* Tx. */
while ( SPI_STATUS_TX_FULL & SPI_GetStatus(USB_SPI1) )
{}
SPI_PutData(USB_SPI1, byte);
/* Rx. */
while (0u == (SPI_STATUS_RX_DONE & SPI_GetStatus(USB_SPI1)) )
{}
return SPI_GetData(USB_SPI1);
}
完成上面两部分之后,SPI就初始化好了。
四、触摸驱动
这里也是使用SPI驱动,大家可以使用硬件SPI,这里我就省事就直接用软件的了。
void bsp_software_spi_config(void)
{
GPIO_Init_Type GPIO_InitStructure;
RCC_EnableAHB1Periphs(BSP_SOFTWARE_SPI_SCK_RCU|BSP_SOFTWARE_SPI_MOSI_RCU, true);
#if USB_SOFTWARE_SPI_READ
RCC_EnableAHB1Periphs(BSP_SOFTWARE_SPI_MISO_RCU, true);
#endif
/* SCK */
GPIO_InitStructure.Pins = BSP_SOFTWARE_SPI_SCK_PIN;
GPIO_InitStructure.Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.PinMode = GPIO_PinMode_Out_PushPull;
GPIO_Init(BSP_SOFTWARE_SPI_SCK_PORT, &GPIO_InitStructure);
#if USB_SOFTWARE_SPI_READ
/* MISO */
GPIO_InitStructure.Pins = BSP_SOFTWARE_SPI_MISO_PIN;
GPIO_InitStructure.Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.PinMode = GPIO_PinMode_In_PullUp; // 输入上拉
GPIO_Init(BSP_SOFTWARE_SPI_MISO_PORT, &GPIO_InitStructure);
#endif
/* MOSI */
GPIO_InitStructure.Pins = BSP_SOFTWARE_SPI_MOSI_PIN;
GPIO_InitStructure.Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.PinMode = GPIO_PinMode_Out_PushPull;
GPIO_Init(BSP_SOFTWARE_SPI_MOSI_PORT, &GPIO_InitStructure);
}
/********************************************
@功能:软件SPI写入一个字节
@日期:2022-08-14 09:03
@作者:lengyuefeng
@说明:
@参数: 无
@返回值: 无
*********************************************/
static void software_spi_write_byte(uint8_t byte)
{
uint8_t i = 0;
for(i = 0; i < 8; i++)
{
if(byte&0x80)
BSP_SOFTWARE_SPI_MOSI_WRITE(1);
else
BSP_SOFTWARE_SPI_MOSI_WRITE(0);
byte <<= 1;
BSP_SOFTWARE_SPI_SCK_WRITE(0);
BSP_SOFTWARE_SPI_SCK_WRITE(1); //上升沿有效
}
}
/********************************************
@功能:软件SPI写入一个字节
@日期:2022-08-14 09:03
@作者:lengyuefeng
@说明:
@参数: 无
@返回值: 无
*********************************************/
static uint16_t software_spi_read_byte(void)
{
uint8_t i = 0;
uint16_t byte = 0;
BSP_SOFTWARE_SPI_SCK_WRITE(0);
BSP_SOFTWARE_SPI_DELAY_US(6);
BSP_SOFTWARE_SPI_SCK_WRITE(1); //给1个时钟,清除BUSY
BSP_SOFTWARE_SPI_SCK_WRITE(0);
for(i = 0; i < 12; i++)
{
byte <<= 1;
BSP_SOFTWARE_SPI_SCK_WRITE(0); //下降沿有效
BSP_SOFTWARE_SPI_SCK_WRITE(1);
if(BSP_SOFTWARE_SPI_MISO_READ())
byte ++;
}
return byte;
}
/********************************************
@功能:uint8_t software_spi_send_byte(uint8_t byte)
@日期:2022-08-14 09:03
@作者:lengyuefeng
@说明:
@参数: 无
@返回值: 无
*********************************************/
uint16_t software_spi_send_byte(uint8_t byte)
{
BSP_SOFTWARE_SPI_SCK_WRITE(0); //先拉低时钟
BSP_SOFTWARE_SPI_MOSI_WRITE(0); //拉低数据线
software_spi_write_byte(byte);
BSP_SOFTWARE_SPI_DELAY_US(1);
return software_spi_read_byte();
}
五、测试
完成屏幕移植和触摸移植之后,可以测试一下功能。这里屏幕就简单显示一下,然后触摸呢,写了一个测试矫正函数。
显示部分:
ScreenGUI_DrawFontGBK32((OLED_W-32*5)/2,30,BLACK,WHITE,"音乐播放器");
ScreenGUI_ShowPicture(30,OLED_H-50-30,50,50,gImage_pic_music);
ScreenGUI_ShowPicture(OLED_W / 2 - 25,OLED_H-50-30,50,50,gImage_pic_video);
ScreenGUI_ShowPicture(OLED_W-30-50,OLED_H-50-30,50,50,gImage_pic_setting);
测试效果:
触摸部分:
用触摸测试函数,首先会在左上角出现字符,点击之后消失,然后出现在右上角,以此类推,会出现在四个角。
测试效果:
六、后续
音乐播放器在开发中,一切从简(没有使用lvgl等图形库,纯贴图),不做太复杂的界面,也没有特别多的功能,只有音乐播放这一个功能。