STM32HAL库使用SPI驱动1.44寸TFTLCD

  关于STM32F4单片机,使用HAL库自带的SPI,驱动TFTLCD屏幕的资料网上好像不太多,正好最近我做了这项工作,把成果分享给大家。我的代码实现了这些功能:任意坐标画点,指定首尾坐标画线,画方框,指定区域显示彩图,显示16* 16或者12* 12的汉字、ASCII码,并附带ASCII码表与少量的汉字字库。

硬件设计

  屏幕选择:使用了一款低成本十六位彩屏,只要十块钱。链接
在这里插入图片描述
  厂家看到文章请联系我打广告费,哈哈。
  虽然用这个屏幕的可能不多,但我了解到,只要其控制芯片是ST7735S,那么程序就应该差不多。不同的地方在于,厂家的封装与玻璃不太一样,玻璃有个伽马值不同,会导致颜色看上去不太一样。

  屏幕的引脚信息
在这里插入图片描述
  我的原理图设计:使用了STM32F405RG芯片的SPI1,屏幕没有MISO。
在这里插入图片描述
在这里插入图片描述

cubeMX中SPI的配置大致如下:
在这里插入图片描述在这里插入图片描述
  其实SPI的速度我选的是21MBITS/s,可能再快一点也行,没有测试。
  其它引脚比较散,都是当做IO来用,CubeMX中的配置过程就不说了,汇总如下

名称 引脚 功能
LCD_RST PC5 屏幕复位
LCD_CD PB0 0数据1指令
SPI_MOSI PB5 数据线
SPI_CLK PB3 时钟线
LCD_CS PB1 片选,低电平有效
LCD_LED PB2 背光,高电平有效

发送数据与指令的基本函数

  在引脚初始化以后,我定义了几个位带操作,方便操作引脚

#define LCD_RST   PCout(5)
#define LCD_CD    PBout(0)
#define LCD_CS    PBout(1)
#define LCD_LED   PBout(2)

   
   
   
  • 1
  • 2
  • 3
  • 4

  不论是发送数据还是引脚,我都采用了HAL库提供的现成的SPI发送函数:

HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

   
   
   
  • 1

  很多人在使用STM32的SPI时都用模拟SPI,说STM32的硬件SPI有问题,我暂时没有发现硬件SPI的问题。不过模拟SPI很容易讲清楚原理,按位发送数据,一般写法是这样的:

      for(i=0;i<8;i++)
      {
     
     
          if(dat&0x80)
      {
     
     
      SDA=1;

   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5

  如果你没有使用HAL库,可以把HAL_SPI_Transmit替换掉。
  发送数据与指令的区别就在于LCD_CD引脚的电平状态,两个函数如下:

/**
  * @brief 向LCD屏幕写一个字节的命令
  * @param 命令内容,具体命令可以参照手册
  * @retval None
  */
static void LCD_WriteCommand(uint8_t temp)
{
     
     
	LCD_CD = 0;
	LCD_CS = 0;
	HAL_SPI_Transmit(&hspi1,&temp, 1, 0xffff);
	LCD_CS = 1;
}
/**
  * @brief 向LCD屏幕写一个字节的数据
  * @param 数据
  * @retval None
  */	
static void LCD_WriteData(uint8_t temp)
{
     
     
	LCD_CD = 1;
	LCD_CS = 0;
	HAL_SPI_Transmit(&hspi1,&temp, 1, 0xffff);
	LCD_CS = 1;
}

   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

  可以看出来,除了LCD_CD引脚用于切换命令,也需要操作LCD_CS来选中屏幕。个人认为操作过多操作引脚会影响效率,而发送数据的函数应用的十分频繁,特别是对于我们选用的十六位屏幕,每个像素都需要十六位的数据,所以,我们经常用到的功能是发送个十六位的数据。代码可以这么写,调用两次发送8位数据的函数:

static void LCD_WD_U16(u16 temp)
{
     
     
    LCD_WriteData(temp>>8);
    LCD_WriteData(temp);
}

   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5

  由于要操作两次IO,所以我稍微做了一点优化:

/**
  * @brief 向LCD屏幕写两个字节的数据
  * @param 16位的数据
	* @note  此函数可以直接调用LCD_WriteData两次,但是IO的操作是多余的
  *        由于每个图片的数据都是16位的,所以此函数很常用,因此稍作优化,减少操作IO
  * @retval None
  */	
static void LCD_WD_U16(u16 temp)
{
     
     
	u8 tempBuf[2];
	tempBuf[0] = temp>>8;
	tempBuf[1] = temp;
	LCD_CD = 1;
	LCD_CS = 0;
	HAL_SPI_Transmit(&hspi1,tempBuf, 2, 0xffff);
	LCD_CS = 1;
}

   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

  同理写了一个函数,用于发送数组。彩图数组动辄都是上万位的,并且是连续发送数据,所以也不需要操作多次IO。

/**
  * @brief 向LCD屏幕写一个数组的长度
  * @param 数组地址与长度
	* @note  此函数可以直接调用LCD_WriteData若干次,但是IO的操作是多余的
  *        由于每个图片的数据都是16位的很长的数组,所以此函数很常用,因此稍作优化,减少操作IO,一个图片的数组值操作一次IO
  * @retval None
  */	
static void LCD_WD_buf(uint8_t *pData, uint16_t Size)
{
     
     
	LCD_CD = 1;
	LCD_CS = 0;
	HAL_SPI_Transmit(&hspi1,pData, Size, 0xffff);
	LCD_CS = 1;
}

   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

初始化与定位

  初始化代码太长,就不放了。其实初始化代码是厂家提供的,只不过原来是51程序,我移植了下。
  屏幕的显示需要坐标系,定位操作其实就是发个特定的命令,表示设置x/y轴,在发送特定的数据,表示具体位置。操作思路在《ST7735S手册》中都有体现,例如设置列地址:
在这里插入图片描述
  我们找到了设置列地址的命令,再把自己需要的坐标计算出来,假如全屏显示:

/**
  * @brief 设置显示区域为全屏
  * @param None
  * @retval None
  */	
static void Full_Screen(void)
{
     
     
	LCD_WriteCommand(0x2A);	    //设置列地址
	LCD_WriteData(0x00);
	LCD_WriteData(0x02);
	LCD_WriteData(0x00);
	LCD_WriteData(0x81);
<span class="toke
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值